1 #include "platform.hpp"
2 
3 #include "common/types.hpp"
4 #include "common/utils.hpp"
5 #include "event_parser.hpp"
6 #include "pdr.hpp"
7 #include "pdr_numeric_effecter.hpp"
8 #include "pdr_state_effecter.hpp"
9 #include "pdr_state_sensor.hpp"
10 #include "pdr_utils.hpp"
11 #include "platform_numeric_effecter.hpp"
12 #include "platform_state_effecter.hpp"
13 #include "platform_state_sensor.hpp"
14 #include "pldmd/dbus_impl_requester.hpp"
15 #include "pldmd/handler.hpp"
16 #include "requester/handler.hpp"
17 
18 #include <libpldm/entity.h>
19 #include <libpldm/state_set.h>
20 
21 #include <phosphor-logging/lg2.hpp>
22 
23 PHOSPHOR_LOG2_USING;
24 
25 using namespace pldm::utils;
26 using namespace pldm::responder::pdr;
27 using namespace pldm::responder::pdr_utils;
28 
29 namespace pldm
30 {
31 namespace responder
32 {
33 namespace platform
34 {
35 using InternalFailure =
36     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
37 
38 static const Json empty{};
39 
40 void Handler::addDbusObjMaps(
41     uint16_t id,
42     std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj,
43     TypeId typeId)
44 {
45     if (typeId == TypeId::PLDM_SENSOR_ID)
46     {
47         sensorDbusObjMaps.emplace(id, dbusObj);
48     }
49     else
50     {
51         effecterDbusObjMaps.emplace(id, dbusObj);
52     }
53 }
54 
55 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>&
56     Handler::getDbusObjMaps(uint16_t id, TypeId typeId) const
57 {
58     if (typeId == TypeId::PLDM_SENSOR_ID)
59     {
60         return sensorDbusObjMaps.at(id);
61     }
62     else
63     {
64         return effecterDbusObjMaps.at(id);
65     }
66 }
67 
68 void Handler::generate(const pldm::utils::DBusHandler& dBusIntf,
69                        const std::string& dir, Repo& repo)
70 {
71     if (!fs::exists(dir))
72     {
73         return;
74     }
75 
76     // A map of PDR type to a lambda that handles creation of that PDR type.
77     // The lambda essentially would parse the platform specific PDR JSONs to
78     // generate the PDR structures. This function iterates through the map to
79     // invoke all lambdas, so that all PDR types can be created.
80 
81     const std::map<Type, generatePDR> generateHandlers = {
82         {PLDM_STATE_EFFECTER_PDR,
83          [this](const DBusHandler& dBusIntf, const auto& json,
84                 RepoInterface& repo) {
85         pdr_state_effecter::generateStateEffecterPDR<pldm::utils::DBusHandler,
86                                                      Handler>(dBusIntf, json,
87                                                               *this, repo);
88     }},
89         {PLDM_NUMERIC_EFFECTER_PDR,
90          [this](const DBusHandler& dBusIntf, const auto& json,
91                 RepoInterface& repo) {
92         pdr_numeric_effecter::generateNumericEffecterPDR<
93             pldm::utils::DBusHandler, Handler>(dBusIntf, json, *this, repo);
94     }},
95         {PLDM_STATE_SENSOR_PDR, [this](const DBusHandler& dBusIntf,
96                                        const auto& json, RepoInterface& repo) {
97         pdr_state_sensor::generateStateSensorPDR<pldm::utils::DBusHandler,
98                                                  Handler>(dBusIntf, json, *this,
99                                                           repo);
100     }}};
101 
102     Type pdrType{};
103     for (const auto& dirEntry : fs::directory_iterator(dir))
104     {
105         try
106         {
107             auto json = readJson(dirEntry.path().string());
108             if (!json.empty())
109             {
110                 auto effecterPDRs = json.value("effecterPDRs", empty);
111                 for (const auto& effecter : effecterPDRs)
112                 {
113                     pdrType = effecter.value("pdrType", 0);
114                     generateHandlers.at(pdrType)(dBusIntf, effecter, repo);
115                 }
116 
117                 auto sensorPDRs = json.value("sensorPDRs", empty);
118                 for (const auto& sensor : sensorPDRs)
119                 {
120                     pdrType = sensor.value("pdrType", 0);
121                     generateHandlers.at(pdrType)(dBusIntf, sensor, repo);
122                 }
123             }
124         }
125         catch (const InternalFailure& e)
126         {
127             error(
128                 "PDR config directory does not exist or empty, TYPE= {PDR_TYPE} PATH={DIR_PATH} ERROR={ERR_EXCEP}",
129                 "PDR_TYPE", pdrType, "DIR_PATH", dirEntry.path().string(),
130                 "ERR_EXCEP", e.what());
131         }
132         catch (const Json::exception& e)
133         {
134             error(
135                 "Failed parsing PDR JSON file, TYPE={PDR_TYPE} ERROR={ERR_EXCEP}",
136                 "PDR_TYPE", pdrType, "ERR_EXCEP", e.what());
137             pldm::utils::reportError(
138                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
139         }
140         catch (const std::exception& e)
141         {
142             error(
143                 "Failed parsing PDR JSON file, TYPE= {PDR_TYPE} ERROR={ERR_EXCEP}",
144                 "PDR_TYPE", pdrType, "ERR_EXCEP", e.what());
145             pldm::utils::reportError(
146                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
147         }
148     }
149 }
150 
151 Response Handler::getPDR(const pldm_msg* request, size_t payloadLength)
152 {
153     if (hostPDRHandler)
154     {
155         if (hostPDRHandler->isHostUp() && oemPlatformHandler != nullptr)
156         {
157             auto rc = oemPlatformHandler->checkBMCState();
158             if (rc != PLDM_SUCCESS)
159             {
160                 return ccOnlyResponse(request, PLDM_ERROR_NOT_READY);
161             }
162         }
163     }
164 
165     // Build FRU table if not built, since entity association PDR's
166     // are built when the FRU table is constructed.
167     if (fruHandler)
168     {
169         fruHandler->buildFRUTable();
170     }
171 
172     if (!pdrCreated)
173     {
174         generateTerminusLocatorPDR(pdrRepo);
175         generate(*dBusIntf, pdrJsonsDir, pdrRepo);
176         if (oemPlatformHandler != nullptr)
177         {
178             oemPlatformHandler->buildOEMPDR(pdrRepo);
179         }
180 
181         pdrCreated = true;
182 
183         if (dbusToPLDMEventHandler)
184         {
185             deferredGetPDREvent = std::make_unique<sdeventplus::source::Defer>(
186                 event,
187                 std::bind(std::mem_fn(&pldm::responder::platform::Handler::
188                                           _processPostGetPDRActions),
189                           this, std::placeholders::_1));
190         }
191     }
192 
193     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0);
194 
195     if (payloadLength != PLDM_GET_PDR_REQ_BYTES)
196     {
197         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
198     }
199 
200     uint32_t recordHandle{};
201     uint32_t dataTransferHandle{};
202     uint8_t transferOpFlag{};
203     uint16_t reqSizeBytes{};
204     uint16_t recordChangeNum{};
205 
206     auto rc = decode_get_pdr_req(request, payloadLength, &recordHandle,
207                                  &dataTransferHandle, &transferOpFlag,
208                                  &reqSizeBytes, &recordChangeNum);
209     if (rc != PLDM_SUCCESS)
210     {
211         return CmdHandler::ccOnlyResponse(request, rc);
212     }
213 
214     uint16_t respSizeBytes{};
215     uint8_t* recordData = nullptr;
216     try
217     {
218         pdr_utils::PdrEntry e;
219         auto record = pdr::getRecordByHandle(pdrRepo, recordHandle, e);
220         if (record == NULL)
221         {
222             return CmdHandler::ccOnlyResponse(
223                 request, PLDM_PLATFORM_INVALID_RECORD_HANDLE);
224         }
225 
226         if (reqSizeBytes)
227         {
228             respSizeBytes = e.size;
229             if (respSizeBytes > reqSizeBytes)
230             {
231                 respSizeBytes = reqSizeBytes;
232             }
233             recordData = e.data;
234         }
235         response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES +
236                             respSizeBytes,
237                         0);
238         auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
239         rc = encode_get_pdr_resp(
240             request->hdr.instance_id, PLDM_SUCCESS, e.handle.nextRecordHandle,
241             0, PLDM_START_AND_END, respSizeBytes, recordData, 0, responsePtr);
242         if (rc != PLDM_SUCCESS)
243         {
244             return ccOnlyResponse(request, rc);
245         }
246     }
247     catch (const std::exception& e)
248     {
249         error("Error accessing PDR, HANDLE={REC_HANDLE} ERROR={ERR_EXCEP}",
250               "REC_HANDLE", recordHandle, "ERR_EXCEP", e.what());
251         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR);
252     }
253     return response;
254 }
255 
256 Response Handler::setStateEffecterStates(const pldm_msg* request,
257                                          size_t payloadLength)
258 {
259     Response response(
260         sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0);
261     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
262     uint16_t effecterId;
263     uint8_t compEffecterCnt;
264     constexpr auto maxCompositeEffecterCnt = 8;
265     std::vector<set_effecter_state_field> stateField(maxCompositeEffecterCnt,
266                                                      {0, 0});
267 
268     if ((payloadLength > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) ||
269         (payloadLength < sizeof(effecterId) + sizeof(compEffecterCnt) +
270                              sizeof(set_effecter_state_field)))
271     {
272         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
273     }
274 
275     int rc = decode_set_state_effecter_states_req(request, payloadLength,
276                                                   &effecterId, &compEffecterCnt,
277                                                   stateField.data());
278 
279     if (rc != PLDM_SUCCESS)
280     {
281         return CmdHandler::ccOnlyResponse(request, rc);
282     }
283 
284     stateField.resize(compEffecterCnt);
285     const pldm::utils::DBusHandler dBusIntf;
286     uint16_t entityType{};
287     uint16_t entityInstance{};
288     uint16_t stateSetId{};
289 
290     if (isOemStateEffecter(*this, effecterId, compEffecterCnt, entityType,
291                            entityInstance, stateSetId) &&
292         oemPlatformHandler != nullptr &&
293         !effecterDbusObjMaps.contains(effecterId))
294     {
295         rc = oemPlatformHandler->oemSetStateEffecterStatesHandler(
296             entityType, entityInstance, stateSetId, compEffecterCnt, stateField,
297             effecterId);
298     }
299     else
300     {
301         rc = platform_state_effecter::setStateEffecterStatesHandler<
302             pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId,
303                                                stateField);
304     }
305     if (rc != PLDM_SUCCESS)
306     {
307         return CmdHandler::ccOnlyResponse(request, rc);
308     }
309 
310     rc = encode_set_state_effecter_states_resp(request->hdr.instance_id, rc,
311                                                responsePtr);
312     if (rc != PLDM_SUCCESS)
313     {
314         return ccOnlyResponse(request, rc);
315     }
316 
317     return response;
318 }
319 
320 Response Handler::platformEventMessage(const pldm_msg* request,
321                                        size_t payloadLength)
322 {
323     uint8_t formatVersion{};
324     uint8_t tid{};
325     uint8_t eventClass{};
326     size_t offset{};
327 
328     auto rc = decode_platform_event_message_req(
329         request, payloadLength, &formatVersion, &tid, &eventClass, &offset);
330     if (rc != PLDM_SUCCESS)
331     {
332         return CmdHandler::ccOnlyResponse(request, rc);
333     }
334 
335     if (eventClass == PLDM_HEARTBEAT_TIMER_ELAPSED_EVENT)
336     {
337         rc = PLDM_SUCCESS;
338         if (oemPlatformHandler)
339         {
340             oemPlatformHandler->resetWatchDogTimer();
341         }
342     }
343     else
344     {
345         try
346         {
347             const auto& handlers = eventHandlers.at(eventClass);
348             for (const auto& handler : handlers)
349             {
350                 auto rc = handler(request, payloadLength, formatVersion, tid,
351                                   offset);
352                 if (rc != PLDM_SUCCESS)
353                 {
354                     return CmdHandler::ccOnlyResponse(request, rc);
355                 }
356             }
357         }
358         catch (const std::out_of_range& e)
359         {
360             return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA);
361         }
362     }
363     Response response(
364         sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES, 0);
365     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
366 
367     rc = encode_platform_event_message_resp(request->hdr.instance_id, rc,
368                                             PLDM_EVENT_NO_LOGGING, responsePtr);
369     if (rc != PLDM_SUCCESS)
370     {
371         return ccOnlyResponse(request, rc);
372     }
373 
374     return response;
375 }
376 
377 int Handler::sensorEvent(const pldm_msg* request, size_t payloadLength,
378                          uint8_t /*formatVersion*/, uint8_t tid,
379                          size_t eventDataOffset)
380 {
381     uint16_t sensorId{};
382     uint8_t eventClass{};
383     size_t eventClassDataOffset{};
384     auto eventData = reinterpret_cast<const uint8_t*>(request->payload) +
385                      eventDataOffset;
386     auto eventDataSize = payloadLength - eventDataOffset;
387 
388     auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId,
389                                        &eventClass, &eventClassDataOffset);
390     if (rc != PLDM_SUCCESS)
391     {
392         return rc;
393     }
394 
395     auto eventClassData = reinterpret_cast<const uint8_t*>(request->payload) +
396                           eventDataOffset + eventClassDataOffset;
397     auto eventClassDataSize = payloadLength - eventDataOffset -
398                               eventClassDataOffset;
399 
400     if (eventClass == PLDM_STATE_SENSOR_STATE)
401     {
402         uint8_t sensorOffset{};
403         uint8_t eventState{};
404         uint8_t previousEventState{};
405 
406         rc = decode_state_sensor_data(eventClassData, eventClassDataSize,
407                                       &sensorOffset, &eventState,
408                                       &previousEventState);
409         if (rc != PLDM_SUCCESS)
410         {
411             return PLDM_ERROR;
412         }
413 
414         // Emitting state sensor event signal
415         emitStateSensorEventSignal(tid, sensorId, sensorOffset, eventState,
416                                    previousEventState);
417 
418         // If there are no HOST PDR's, there is no further action
419         if (hostPDRHandler == NULL)
420         {
421             return PLDM_SUCCESS;
422         }
423 
424         // Handle PLDM events for which PDR is available
425         SensorEntry sensorEntry{tid, sensorId};
426 
427         pldm::pdr::EntityInfo entityInfo{};
428         pldm::pdr::CompositeSensorStates compositeSensorStates{};
429 
430         try
431         {
432             std::tie(entityInfo, compositeSensorStates) =
433                 hostPDRHandler->lookupSensorInfo(sensorEntry);
434         }
435         catch (const std::out_of_range& e)
436         {
437             // If there is no mapping for tid, sensorId combination, try
438             // PLDM_TID_RESERVED, sensorId for terminus that is yet to
439             // implement TL PDR.
440             try
441             {
442                 sensorEntry.terminusID = PLDM_TID_RESERVED;
443                 std::tie(entityInfo, compositeSensorStates) =
444                     hostPDRHandler->lookupSensorInfo(sensorEntry);
445             }
446             // If there is no mapping for events return PLDM_SUCCESS
447             catch (const std::out_of_range& e)
448             {
449                 return PLDM_SUCCESS;
450             }
451         }
452 
453         if (sensorOffset >= compositeSensorStates.size())
454         {
455             return PLDM_ERROR_INVALID_DATA;
456         }
457 
458         const auto& possibleStates = compositeSensorStates[sensorOffset];
459         if (possibleStates.find(eventState) == possibleStates.end())
460         {
461             return PLDM_ERROR_INVALID_DATA;
462         }
463 
464         const auto& [containerId, entityType, entityInstance] = entityInfo;
465         events::StateSensorEntry stateSensorEntry{containerId, entityType,
466                                                   entityInstance, sensorOffset};
467         return hostPDRHandler->handleStateSensorEvent(stateSensorEntry,
468                                                       eventState);
469     }
470     else
471     {
472         return PLDM_ERROR_INVALID_DATA;
473     }
474 
475     return PLDM_SUCCESS;
476 }
477 
478 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request,
479                                        size_t payloadLength,
480                                        uint8_t /*formatVersion*/, uint8_t tid,
481                                        size_t eventDataOffset)
482 {
483     uint8_t eventDataFormat{};
484     uint8_t numberOfChangeRecords{};
485     size_t dataOffset{};
486 
487     auto eventData = reinterpret_cast<const uint8_t*>(request->payload) +
488                      eventDataOffset;
489     auto eventDataSize = payloadLength - eventDataOffset;
490 
491     auto rc = decode_pldm_pdr_repository_chg_event_data(
492         eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords,
493         &dataOffset);
494     if (rc != PLDM_SUCCESS)
495     {
496         return rc;
497     }
498 
499     PDRRecordHandles pdrRecordHandles;
500 
501     if (eventDataFormat == FORMAT_IS_PDR_TYPES)
502     {
503         return PLDM_ERROR_INVALID_DATA;
504     }
505 
506     if (eventDataFormat == FORMAT_IS_PDR_HANDLES)
507     {
508         uint8_t eventDataOperation{};
509         uint8_t numberOfChangeEntries{};
510 
511         auto changeRecordData = eventData + dataOffset;
512         auto changeRecordDataSize = eventDataSize - dataOffset;
513 
514         while (changeRecordDataSize)
515         {
516             rc = decode_pldm_pdr_repository_change_record_data(
517                 changeRecordData, changeRecordDataSize, &eventDataOperation,
518                 &numberOfChangeEntries, &dataOffset);
519 
520             if (rc != PLDM_SUCCESS)
521             {
522                 return rc;
523             }
524 
525             if (eventDataOperation == PLDM_RECORDS_ADDED ||
526                 eventDataOperation == PLDM_RECORDS_MODIFIED)
527             {
528                 if (eventDataOperation == PLDM_RECORDS_MODIFIED)
529                 {
530                     hostPDRHandler->isHostPdrModified = true;
531                 }
532 
533                 rc = getPDRRecordHandles(
534                     reinterpret_cast<const ChangeEntry*>(changeRecordData +
535                                                          dataOffset),
536                     changeRecordDataSize - dataOffset,
537                     static_cast<size_t>(numberOfChangeEntries),
538                     pdrRecordHandles);
539 
540                 if (rc != PLDM_SUCCESS)
541                 {
542                     return rc;
543                 }
544             }
545 
546             changeRecordData += dataOffset +
547                                 (numberOfChangeEntries * sizeof(ChangeEntry));
548             changeRecordDataSize -=
549                 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry));
550         }
551     }
552     if (hostPDRHandler)
553     {
554         // if we get a Repository change event with the eventDataFormat
555         // as REFRESH_ENTIRE_REPOSITORY, then delete all the PDR's that
556         // have the matched Terminus handle
557         if (eventDataFormat == REFRESH_ENTIRE_REPOSITORY)
558         {
559             // We cannot get the Repo change event from the Terminus
560             // that is not already added to the BMC repository
561 
562             for (auto it = hostPDRHandler->tlPDRInfo.cbegin();
563                  it != hostPDRHandler->tlPDRInfo.cend();)
564             {
565                 if (std::get<0>(it->second) == tid)
566                 {
567                     pldm_pdr_remove_pdrs_by_terminus_handle(pdrRepo.getPdr(),
568                                                             it->first);
569                     hostPDRHandler->tlPDRInfo.erase(it++);
570                 }
571                 else
572                 {
573                     ++it;
574                 }
575             }
576         }
577         hostPDRHandler->fetchPDR(std::move(pdrRecordHandles));
578     }
579 
580     return PLDM_SUCCESS;
581 }
582 
583 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData,
584                                  size_t changeEntryDataSize,
585                                  size_t numberOfChangeEntries,
586                                  PDRRecordHandles& pdrRecordHandles)
587 {
588     if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry)))
589     {
590         return PLDM_ERROR_INVALID_DATA;
591     }
592     for (size_t i = 0; i < numberOfChangeEntries; i++)
593     {
594         pdrRecordHandles.push_back(changeEntryData[i]);
595     }
596     return PLDM_SUCCESS;
597 }
598 
599 Response Handler::getNumericEffecterValue(const pldm_msg* request,
600                                           size_t payloadLength)
601 {
602     if (payloadLength != PLDM_GET_NUMERIC_EFFECTER_VALUE_REQ_BYTES)
603     {
604         return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
605     }
606 
607     uint16_t effecterId{};
608     auto rc = decode_get_numeric_effecter_value_req(request, payloadLength,
609                                                     &effecterId);
610     if (rc != PLDM_SUCCESS)
611     {
612         return ccOnlyResponse(request, rc);
613     }
614 
615     const pldm::utils::DBusHandler dBusIntf;
616     uint8_t effecterDataSize{};
617     pldm::utils::PropertyValue dbusValue;
618     std::string propertyType;
619     using effecterOperationalState = uint8_t;
620     using completionCode = uint8_t;
621 
622     rc = platform_numeric_effecter::getNumericEffecterData<
623         pldm::utils::DBusHandler, Handler>(
624         dBusIntf, *this, effecterId, effecterDataSize, propertyType, dbusValue);
625 
626     if (rc != PLDM_SUCCESS)
627     {
628         return ccOnlyResponse(request, rc);
629     }
630 
631     // Refer DSP0248_1.2.0.pdf (section 22.3, Table 48)
632     // Completion Code (uint8), Effecter Data Size(uint8), Effecter Operational
633     // State(uint8), PendingValue (uint8|sint8|uint16|sint16|uint32|sint32 )
634     // PresentValue (uint8|sint8|uint16|sint16|uint32|sint32 )
635     // Size of PendingValue and PresentValue calculated based on size is
636     // provided in effecter data size
637     size_t responsePayloadLength = sizeof(completionCode) +
638                                    sizeof(effecterDataSize) +
639                                    sizeof(effecterOperationalState) +
640                                    getEffecterDataSize(effecterDataSize) +
641                                    getEffecterDataSize(effecterDataSize);
642 
643     Response response(responsePayloadLength + sizeof(pldm_msg_hdr));
644     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
645 
646     rc = platform_numeric_effecter::getNumericEffecterValueHandler(
647         propertyType, dbusValue, effecterDataSize, responsePtr,
648         responsePayloadLength, request->hdr.instance_id);
649 
650     if (rc != PLDM_SUCCESS)
651     {
652         error(
653             "Reponse to GetNumericEffecterValue failed RC={RC} for EffectorId={EFFECTER_ID} ",
654             "RC", rc, "EFFECTER_ID", effecterId);
655         return ccOnlyResponse(request, rc);
656     }
657     return response;
658 }
659 
660 Response Handler::setNumericEffecterValue(const pldm_msg* request,
661                                           size_t payloadLength)
662 {
663     Response response(sizeof(pldm_msg_hdr) +
664                       PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES);
665     uint16_t effecterId{};
666     uint8_t effecterDataSize{};
667     uint8_t effecterValue[4] = {};
668 
669     if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) +
670                              sizeof(union_effecter_data_size)) ||
671         (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1))
672     {
673         return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
674     }
675 
676     int rc = decode_set_numeric_effecter_value_req(
677         request, payloadLength, &effecterId, &effecterDataSize, effecterValue);
678 
679     if (rc == PLDM_SUCCESS)
680     {
681         const pldm::utils::DBusHandler dBusIntf;
682         rc = platform_numeric_effecter::setNumericEffecterValueHandler<
683             pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId,
684                                                effecterDataSize, effecterValue,
685                                                sizeof(effecterValue));
686     }
687 
688     return ccOnlyResponse(request, rc);
689 }
690 
691 void Handler::generateTerminusLocatorPDR(Repo& repo)
692 {
693     std::vector<uint8_t> pdrBuffer(sizeof(pldm_terminus_locator_pdr));
694 
695     auto pdr = reinterpret_cast<pldm_terminus_locator_pdr*>(pdrBuffer.data());
696 
697     pdr->hdr.record_handle = 0;
698     pdr->hdr.version = 1;
699     pdr->hdr.type = PLDM_TERMINUS_LOCATOR_PDR;
700     pdr->hdr.record_change_num = 0;
701     pdr->hdr.length = sizeof(pldm_terminus_locator_pdr) - sizeof(pldm_pdr_hdr);
702     pdr->terminus_handle = TERMINUS_HANDLE;
703     pdr->validity = PLDM_TL_PDR_VALID;
704     pdr->tid = TERMINUS_ID;
705     pdr->container_id = 0x0;
706     pdr->terminus_locator_type = PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID;
707     pdr->terminus_locator_value_size =
708         sizeof(pldm_terminus_locator_type_mctp_eid);
709     auto locatorValue = reinterpret_cast<pldm_terminus_locator_type_mctp_eid*>(
710         pdr->terminus_locator_value);
711     locatorValue->eid = BmcMctpEid;
712 
713     PdrEntry pdrEntry{};
714     pdrEntry.data = pdrBuffer.data();
715     pdrEntry.size = pdrBuffer.size();
716     repo.addRecord(pdrEntry);
717     if (hostPDRHandler)
718     {
719         hostPDRHandler->tlPDRInfo.insert_or_assign(
720             pdr->terminus_handle,
721             std::make_tuple(pdr->tid, locatorValue->eid, pdr->validity));
722     }
723 }
724 
725 Response Handler::getStateSensorReadings(const pldm_msg* request,
726                                          size_t payloadLength)
727 {
728     uint16_t sensorId{};
729     bitfield8_t sensorRearm{};
730     uint8_t reserved{};
731 
732     if (payloadLength != PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES)
733     {
734         return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
735     }
736 
737     int rc = decode_get_state_sensor_readings_req(
738         request, payloadLength, &sensorId, &sensorRearm, &reserved);
739 
740     if (rc != PLDM_SUCCESS)
741     {
742         return ccOnlyResponse(request, rc);
743     }
744 
745     // 0x01 to 0x08
746     uint8_t sensorRearmCount = std::popcount(sensorRearm.byte);
747     std::vector<get_sensor_state_field> stateField(sensorRearmCount);
748     uint8_t comSensorCnt{};
749     const pldm::utils::DBusHandler dBusIntf;
750 
751     uint16_t entityType{};
752     uint16_t entityInstance{};
753     uint16_t stateSetId{};
754 
755     if (isOemStateSensor(*this, sensorId, sensorRearmCount, comSensorCnt,
756                          entityType, entityInstance, stateSetId) &&
757         oemPlatformHandler != nullptr && !sensorDbusObjMaps.contains(sensorId))
758     {
759         rc = oemPlatformHandler->getOemStateSensorReadingsHandler(
760             entityType, entityInstance, stateSetId, comSensorCnt, stateField);
761     }
762     else
763     {
764         rc = platform_state_sensor::getStateSensorReadingsHandler<
765             pldm::utils::DBusHandler, Handler>(dBusIntf, *this, sensorId,
766                                                sensorRearmCount, comSensorCnt,
767                                                stateField);
768     }
769 
770     if (rc != PLDM_SUCCESS)
771     {
772         return ccOnlyResponse(request, rc);
773     }
774 
775     Response response(sizeof(pldm_msg_hdr) +
776                       PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES +
777                       sizeof(get_sensor_state_field) * comSensorCnt);
778     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
779     rc = encode_get_state_sensor_readings_resp(request->hdr.instance_id, rc,
780                                                comSensorCnt, stateField.data(),
781                                                responsePtr);
782     if (rc != PLDM_SUCCESS)
783     {
784         return ccOnlyResponse(request, rc);
785     }
786 
787     return response;
788 }
789 
790 void Handler::_processPostGetPDRActions(sdeventplus::source::EventBase&
791                                         /*source */)
792 {
793     deferredGetPDREvent.reset();
794     dbusToPLDMEventHandler->listenSensorEvent(pdrRepo, sensorDbusObjMaps);
795 }
796 
797 bool isOemStateSensor(Handler& handler, uint16_t sensorId,
798                       uint8_t sensorRearmCount, uint8_t& compSensorCnt,
799                       uint16_t& entityType, uint16_t& entityInstance,
800                       uint16_t& stateSetId)
801 {
802     pldm_state_sensor_pdr* pdr = nullptr;
803 
804     std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateSensorPdrRepo(
805         pldm_pdr_init(), pldm_pdr_destroy);
806     if (!stateSensorPdrRepo)
807     {
808         error("Failed to instantiate state sensor PDR repository");
809         return false;
810     }
811     Repo stateSensorPDRs(stateSensorPdrRepo.get());
812     getRepoByType(handler.getRepo(), stateSensorPDRs, PLDM_STATE_SENSOR_PDR);
813     if (stateSensorPDRs.empty())
814     {
815         error("Failed to get record by PDR type");
816         return false;
817     }
818 
819     PdrEntry pdrEntry{};
820     auto pdrRecord = stateSensorPDRs.getFirstRecord(pdrEntry);
821     while (pdrRecord)
822     {
823         pdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdrEntry.data);
824         assert(pdr != NULL);
825         if (pdr->sensor_id != sensorId)
826         {
827             pdr = nullptr;
828             pdrRecord = stateSensorPDRs.getNextRecord(pdrRecord, pdrEntry);
829             continue;
830         }
831         auto tmpEntityType = pdr->entity_type;
832         auto tmpEntityInstance = pdr->entity_instance;
833         auto tmpCompSensorCnt = pdr->composite_sensor_count;
834         auto tmpPossibleStates =
835             reinterpret_cast<state_sensor_possible_states*>(
836                 pdr->possible_states);
837         auto tmpStateSetId = tmpPossibleStates->state_set_id;
838 
839         if (sensorRearmCount > tmpCompSensorCnt)
840         {
841             error(
842                 "The requester sent wrong sensorRearm count for the sensor, SENSOR_ID={SENSOR_ID} SENSOR_REARM_COUNT={SENSOR_REARM_CNT}",
843                 "SENSOR_ID", sensorId, "SENSOR_REARM_CNT",
844                 (uint16_t)sensorRearmCount);
845             break;
846         }
847 
848         if ((tmpEntityType >= PLDM_OEM_ENTITY_TYPE_START &&
849              tmpEntityType <= PLDM_OEM_ENTITY_TYPE_END) ||
850             (tmpStateSetId >= PLDM_OEM_STATE_SET_ID_START &&
851              tmpStateSetId < PLDM_OEM_STATE_SET_ID_END))
852         {
853             entityType = tmpEntityType;
854             entityInstance = tmpEntityInstance;
855             stateSetId = tmpStateSetId;
856             compSensorCnt = tmpCompSensorCnt;
857             return true;
858         }
859         else
860         {
861             return false;
862         }
863     }
864     return false;
865 }
866 
867 bool isOemStateEffecter(Handler& handler, uint16_t effecterId,
868                         uint8_t compEffecterCnt, uint16_t& entityType,
869                         uint16_t& entityInstance, uint16_t& stateSetId)
870 {
871     pldm_state_effecter_pdr* pdr = nullptr;
872 
873     std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateEffecterPdrRepo(
874         pldm_pdr_init(), pldm_pdr_destroy);
875     if (!stateEffecterPdrRepo)
876     {
877         error("Failed to instantiate state effecter PDR repository");
878         return false;
879     }
880     Repo stateEffecterPDRs(stateEffecterPdrRepo.get());
881     getRepoByType(handler.getRepo(), stateEffecterPDRs,
882                   PLDM_STATE_EFFECTER_PDR);
883     if (stateEffecterPDRs.empty())
884     {
885         error("Failed to get record by PDR type");
886         return false;
887     }
888 
889     PdrEntry pdrEntry{};
890     auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry);
891     while (pdrRecord)
892     {
893         pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data);
894         assert(pdr != NULL);
895         if (pdr->effecter_id != effecterId)
896         {
897             pdr = nullptr;
898             pdrRecord = stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry);
899             continue;
900         }
901 
902         auto tmpEntityType = pdr->entity_type;
903         auto tmpEntityInstance = pdr->entity_instance;
904         auto tmpPossibleStates =
905             reinterpret_cast<state_effecter_possible_states*>(
906                 pdr->possible_states);
907         auto tmpStateSetId = tmpPossibleStates->state_set_id;
908 
909         if (compEffecterCnt > pdr->composite_effecter_count)
910         {
911             error(
912                 "The requester sent wrong composite effecter count for the effecter, EFFECTER_ID={EFFECTER_ID} COMP_EFF_CNT={COMP_EFF_CNT}",
913                 "EFFECTER_ID", effecterId, "COMP_EFF_CNT",
914                 (uint16_t)compEffecterCnt);
915             return false;
916         }
917 
918         if ((tmpEntityType >= PLDM_OEM_ENTITY_TYPE_START &&
919              tmpEntityType <= PLDM_OEM_ENTITY_TYPE_END) ||
920             (tmpStateSetId >= PLDM_OEM_STATE_SET_ID_START &&
921              tmpStateSetId < PLDM_OEM_STATE_SET_ID_END))
922         {
923             entityType = tmpEntityType;
924             entityInstance = tmpEntityInstance;
925             stateSetId = tmpStateSetId;
926             return true;
927         }
928         else
929         {
930             return false;
931         }
932     }
933     return false;
934 }
935 
936 void Handler::setEventReceiver()
937 {
938     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
939                                     PLDM_SET_EVENT_RECEIVER_REQ_BYTES);
940     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
941     auto instanceId = instanceIdDb->next(eid);
942     uint8_t eventMessageGlobalEnable =
943         PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE;
944     uint8_t transportProtocolType = PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP;
945     uint8_t eventReceiverAddressInfo = pldm::responder::pdr::BmcMctpEid;
946     uint16_t heartbeatTimer = HEARTBEAT_TIMEOUT;
947 
948     auto rc = encode_set_event_receiver_req(
949         instanceId, eventMessageGlobalEnable, transportProtocolType,
950         eventReceiverAddressInfo, heartbeatTimer, request);
951     if (rc != PLDM_SUCCESS)
952     {
953         instanceIdDb->free(eid, instanceId);
954         error("Failed to encode_set_event_receiver_req, rc = {RC}", "RC",
955               lg2::hex, rc);
956         return;
957     }
958 
959     auto processSetEventReceiverResponse =
960         [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
961         if (response == nullptr || !respMsgLen)
962         {
963             error("Failed to receive response for setEventReceiver command");
964             return;
965         }
966 
967         uint8_t completionCode{};
968         auto rc = decode_set_event_receiver_resp(response, respMsgLen,
969                                                  &completionCode);
970         if (rc || completionCode)
971         {
972             error(
973                 "Failed to decode setEventReceiver command response, rc = {RC}, cc = {CC}",
974                 "RC", rc, "CC", (unsigned)completionCode);
975             pldm::utils::reportError(
976                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
977         }
978     };
979     rc = handler->registerRequest(
980         eid, instanceId, PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER,
981         std::move(requestMsg), std::move(processSetEventReceiverResponse));
982 
983     if (rc != PLDM_SUCCESS)
984     {
985         error("Failed to send the setEventReceiver request");
986     }
987 
988     if (oemPlatformHandler)
989     {
990         oemPlatformHandler->countSetEventReceiver();
991         oemPlatformHandler->checkAndDisableWatchDog();
992     }
993 }
994 
995 } // namespace platform
996 } // namespace responder
997 } // namespace pldm
998