1 #include "config.h"
2 
3 #include "host_pdr_handler.hpp"
4 
5 #include <assert.h>
6 #include <libpldm/pldm.h>
7 
8 #include <nlohmann/json.hpp>
9 #include <phosphor-logging/lg2.hpp>
10 #include <sdeventplus/clock.hpp>
11 #include <sdeventplus/exception.hpp>
12 #include <sdeventplus/source/io.hpp>
13 #include <sdeventplus/source/time.hpp>
14 
15 #include <fstream>
16 
17 PHOSPHOR_LOG2_USING;
18 
19 namespace pldm
20 {
21 using namespace pldm::dbus_api;
22 using namespace pldm::responder::events;
23 using namespace pldm::utils;
24 using namespace sdbusplus::bus::match::rules;
25 using Json = nlohmann::json;
26 namespace fs = std::filesystem;
27 constexpr auto fruJson = "host_frus.json";
28 const Json emptyJson{};
29 const std::vector<Json> emptyJsonList{};
30 
31 template <typename T>
32 uint16_t extractTerminusHandle(std::vector<uint8_t>& pdr)
33 {
34     T* var = nullptr;
35     if (std::is_same<T, pldm_pdr_fru_record_set>::value)
36     {
37         var = (T*)(pdr.data() + sizeof(pldm_pdr_hdr));
38     }
39     else
40     {
41         var = (T*)(pdr.data());
42     }
43     if (var != nullptr)
44     {
45         return var->terminus_handle;
46     }
47     return TERMINUS_HANDLE;
48 }
49 
50 HostPDRHandler::HostPDRHandler(
51     int mctp_fd, uint8_t mctp_eid, sdeventplus::Event& event, pldm_pdr* repo,
52     const std::string& eventsJsonsDir, pldm_entity_association_tree* entityTree,
53     pldm_entity_association_tree* bmcEntityTree, Requester& requester,
54     pldm::requester::Handler<pldm::requester::Request>* handler) :
55     mctp_fd(mctp_fd),
56     mctp_eid(mctp_eid), event(event), repo(repo),
57     stateSensorHandler(eventsJsonsDir), entityTree(entityTree),
58     bmcEntityTree(bmcEntityTree), requester(requester), handler(handler)
59 {
60     fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson);
61     if (fs::exists(hostFruJson))
62     {
63         // Note parent entities for entities sent down by the host firmware.
64         // This will enable a merge of entity associations.
65         try
66         {
67             std::ifstream jsonFile(hostFruJson);
68             auto data = Json::parse(jsonFile, nullptr, false);
69             if (data.is_discarded())
70             {
71                 error("Parsing Host FRU json file failed");
72             }
73             else
74             {
75                 auto entities = data.value("entities", emptyJsonList);
76                 for (auto& entity : entities)
77                 {
78                     EntityType entityType = entity.value("entity_type", 0);
79                     auto parent = entity.value("parent", emptyJson);
80                     pldm_entity p{};
81                     p.entity_type = parent.value("entity_type", 0);
82                     p.entity_instance_num = parent.value("entity_instance", 0);
83                     parents.emplace(entityType, std::move(p));
84                 }
85             }
86         }
87         catch (const std::exception& e)
88         {
89             error("Parsing Host FRU json file failed, exception = {ERR_EXCEP}",
90                   "ERR_EXCEP", e.what());
91         }
92     }
93 
94     hostOffMatch = std::make_unique<sdbusplus::bus::match_t>(
95         pldm::utils::DBusHandler::getBus(),
96         propertiesChanged("/xyz/openbmc_project/state/host0",
97                           "xyz.openbmc_project.State.Host"),
98         [this, repo, entityTree, bmcEntityTree](sdbusplus::message_t& msg) {
99             DbusChangedProps props{};
100             std::string intf;
101             msg.read(intf, props);
102             const auto itr = props.find("CurrentHostState");
103             if (itr != props.end())
104             {
105                 PropertyValue value = itr->second;
106                 auto propVal = std::get<std::string>(value);
107                 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
108                 {
109                     // Delete all the remote terminus information
110                     std::erase_if(tlPDRInfo, [](const auto& item) {
111                         auto const& [key, value] = item;
112                         return key != TERMINUS_HANDLE;
113                     });
114                     pldm_pdr_remove_remote_pdrs(repo);
115                     pldm_entity_association_tree_destroy_root(entityTree);
116                     pldm_entity_association_tree_copy_root(bmcEntityTree,
117                                                            entityTree);
118                     this->sensorMap.clear();
119                     this->responseReceived = false;
120                 }
121             }
122         });
123 }
124 
125 void HostPDRHandler::fetchPDR(PDRRecordHandles&& recordHandles)
126 {
127     pdrRecordHandles.clear();
128     modifiedPDRRecordHandles.clear();
129 
130     if (isHostPdrModified)
131     {
132         modifiedPDRRecordHandles = std::move(recordHandles);
133     }
134     else
135     {
136         pdrRecordHandles = std::move(recordHandles);
137     }
138 
139     // Defer the actual fetch of PDRs from the host (by queuing the call on the
140     // main event loop). That way, we can respond to the platform event msg from
141     // the host firmware.
142     pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>(
143         event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this,
144                          std::placeholders::_1));
145 }
146 
147 void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/)
148 {
149     getHostPDR();
150 }
151 
152 void HostPDRHandler::getHostPDR(uint32_t nextRecordHandle)
153 {
154     pdrFetchEvent.reset();
155 
156     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
157                                     PLDM_GET_PDR_REQ_BYTES);
158     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
159     uint32_t recordHandle{};
160     if (!nextRecordHandle && (!modifiedPDRRecordHandles.empty()) &&
161         isHostPdrModified)
162     {
163         recordHandle = modifiedPDRRecordHandles.front();
164         modifiedPDRRecordHandles.pop_front();
165     }
166     else if (!nextRecordHandle && (!pdrRecordHandles.empty()))
167     {
168         recordHandle = pdrRecordHandles.front();
169         pdrRecordHandles.pop_front();
170     }
171     else
172     {
173         recordHandle = nextRecordHandle;
174     }
175     auto instanceId = requester.getInstanceId(mctp_eid);
176 
177     auto rc =
178         encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART,
179                            UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES);
180     if (rc != PLDM_SUCCESS)
181     {
182         requester.markFree(mctp_eid, instanceId);
183         error("Failed to encode_get_pdr_req, rc = {RC}", "RC", rc);
184         return;
185     }
186 
187     rc = handler->registerRequest(
188         mctp_eid, instanceId, PLDM_PLATFORM, PLDM_GET_PDR,
189         std::move(requestMsg),
190         std::move(std::bind_front(&HostPDRHandler::processHostPDRs, this)));
191     if (rc)
192     {
193         error("Failed to send the GetPDR request to Host");
194     }
195 }
196 
197 int HostPDRHandler::handleStateSensorEvent(const StateSensorEntry& entry,
198                                            pdr::EventState state)
199 {
200     auto rc = stateSensorHandler.eventAction(entry, state);
201     if (rc != PLDM_SUCCESS)
202     {
203         error("Failed to fetch and update D-bus property, rc = {RC}", "RC", rc);
204         return rc;
205     }
206     return PLDM_SUCCESS;
207 }
208 bool HostPDRHandler::getParent(EntityType type, pldm_entity& parent)
209 {
210     auto found = parents.find(type);
211     if (found != parents.end())
212     {
213         parent.entity_type = found->second.entity_type;
214         parent.entity_instance_num = found->second.entity_instance_num;
215         return true;
216     }
217 
218     return false;
219 }
220 
221 void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr)
222 {
223     size_t numEntities{};
224     pldm_entity* entities = nullptr;
225     bool merged = false;
226     auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>(
227         const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr));
228 
229     pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities,
230                                         &entities);
231     for (size_t i = 0; i < numEntities; ++i)
232     {
233         pldm_entity parent{};
234         if (getParent(entities[i].entity_type, parent))
235         {
236             auto node = pldm_entity_association_tree_find(entityTree, &parent);
237             if (node)
238             {
239                 pldm_entity_association_tree_add(entityTree, &entities[i],
240                                                  0xFFFF, node,
241                                                  entityPdr->association_type);
242                 merged = true;
243             }
244         }
245     }
246 
247     if (merged)
248     {
249         // Update our PDR repo with the merged entity association PDRs
250         pldm_entity_node* node = nullptr;
251         pldm_find_entity_ref_in_tree(entityTree, entities[0], &node);
252         if (node == nullptr)
253         {
254             error("could not find referrence of the entity in the tree");
255         }
256         else
257         {
258             pldm_entity_association_pdr_add_from_node(
259                 node, repo, &entities, numEntities, true, TERMINUS_HANDLE);
260         }
261     }
262     free(entities);
263 }
264 
265 void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes,
266                                                uint8_t eventDataFormat)
267 {
268     assert(eventDataFormat == FORMAT_IS_PDR_HANDLES);
269 
270     // Extract from the PDR repo record handles of PDRs we want the host
271     // to pull up.
272     std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED};
273     std::vector<uint8_t> numsOfChangeEntries(1);
274     std::vector<std::vector<ChangeEntry>> changeEntries(
275         numsOfChangeEntries.size());
276     for (auto pdrType : pdrTypes)
277     {
278         const pldm_pdr_record* record{};
279         do
280         {
281             record = pldm_pdr_find_record_by_type(repo, pdrType, record,
282                                                   nullptr, nullptr);
283             if (record && pldm_pdr_record_is_remote(record))
284             {
285                 changeEntries[0].push_back(
286                     pldm_pdr_get_record_handle(repo, record));
287             }
288         } while (record);
289     }
290     if (changeEntries.empty())
291     {
292         return;
293     }
294     numsOfChangeEntries[0] = changeEntries[0].size();
295 
296     // Encode PLDM platform event msg to indicate a PDR repo change.
297     size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
298                      PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
299                      changeEntries[0].size() * sizeof(uint32_t);
300     std::vector<uint8_t> eventDataVec{};
301     eventDataVec.resize(maxSize);
302     auto eventData =
303         reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
304             eventDataVec.data());
305     size_t actualSize{};
306     auto firstEntry = changeEntries[0].data();
307     auto rc = encode_pldm_pdr_repository_chg_event_data(
308         eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(),
309         &firstEntry, eventData, &actualSize, maxSize);
310     if (rc != PLDM_SUCCESS)
311     {
312         error("Failed to encode_pldm_pdr_repository_chg_event_data, rc = {RC}",
313               "RC", rc);
314         return;
315     }
316     auto instanceId = requester.getInstanceId(mctp_eid);
317     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
318                                     PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
319                                     actualSize);
320     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
321     rc = encode_platform_event_message_req(
322         instanceId, 1, TERMINUS_ID, PLDM_PDR_REPOSITORY_CHG_EVENT,
323         eventDataVec.data(), actualSize, request,
324         actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
325     if (rc != PLDM_SUCCESS)
326     {
327         requester.markFree(mctp_eid, instanceId);
328         error("Failed to encode_platform_event_message_req, rc = {RC}", "RC",
329               rc);
330         return;
331     }
332 
333     auto platformEventMessageResponseHandler = [](mctp_eid_t /*eid*/,
334                                                   const pldm_msg* response,
335                                                   size_t respMsgLen) {
336         if (response == nullptr || !respMsgLen)
337         {
338             error(
339                 "Failed to receive response for the PDR repository changed event");
340             return;
341         }
342 
343         uint8_t completionCode{};
344         uint8_t status{};
345         auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response);
346         auto rc = decode_platform_event_message_resp(responsePtr, respMsgLen,
347                                                      &completionCode, &status);
348         if (rc || completionCode)
349         {
350             error(
351                 "Failed to decode_platform_event_message_resp: {RC}, cc = {CC}",
352                 "RC", rc, "CC", static_cast<unsigned>(completionCode));
353         }
354     };
355 
356     rc = handler->registerRequest(
357         mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE,
358         std::move(requestMsg), std::move(platformEventMessageResponseHandler));
359     if (rc)
360     {
361         error("Failed to send the PDR repository changed event request");
362     }
363 }
364 
365 void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs)
366 {
367     for (const auto& pdr : stateSensorPDRs)
368     {
369         SensorEntry sensorEntry{};
370         const auto& [terminusHandle, sensorID, sensorInfo] =
371             responder::pdr_utils::parseStateSensorPDR(pdr);
372         sensorEntry.sensorID = sensorID;
373         try
374         {
375             sensorEntry.terminusID = std::get<0>(tlPDRInfo.at(terminusHandle));
376         }
377         // If there is no mapping for terminusHandle assign the reserved TID
378         // value of 0xFF to indicate that.
379         catch (const std::out_of_range& e)
380         {
381             sensorEntry.terminusID = PLDM_TID_RESERVED;
382         }
383         sensorMap.emplace(sensorEntry, std::move(sensorInfo));
384     }
385 }
386 
387 void HostPDRHandler::processHostPDRs(mctp_eid_t /*eid*/,
388                                      const pldm_msg* response,
389                                      size_t respMsgLen)
390 {
391     static bool merged = false;
392     static PDRList stateSensorPDRs{};
393     uint32_t nextRecordHandle{};
394     uint8_t tlEid = 0;
395     bool tlValid = true;
396     uint32_t rh = 0;
397     uint16_t terminusHandle = 0;
398     uint16_t pdrTerminusHandle = 0;
399     uint8_t tid = 0;
400 
401     uint8_t completionCode{};
402     uint32_t nextDataTransferHandle{};
403     uint8_t transferFlag{};
404     uint16_t respCount{};
405     uint8_t transferCRC{};
406     if (response == nullptr || !respMsgLen)
407     {
408         error("Failed to receive response for the GetPDR command");
409         return;
410     }
411 
412     auto rc = decode_get_pdr_resp(
413         response, respMsgLen /*- sizeof(pldm_msg_hdr)*/, &completionCode,
414         &nextRecordHandle, &nextDataTransferHandle, &transferFlag, &respCount,
415         nullptr, 0, &transferCRC);
416     std::vector<uint8_t> responsePDRMsg;
417     responsePDRMsg.resize(respMsgLen + sizeof(pldm_msg_hdr));
418     memcpy(responsePDRMsg.data(), response, respMsgLen + sizeof(pldm_msg_hdr));
419     if (rc != PLDM_SUCCESS)
420     {
421         error("Failed to decode_get_pdr_resp, rc = {RC}", "RC", rc);
422         return;
423     }
424     else
425     {
426         std::vector<uint8_t> pdr(respCount, 0);
427         rc = decode_get_pdr_resp(response, respMsgLen, &completionCode,
428                                  &nextRecordHandle, &nextDataTransferHandle,
429                                  &transferFlag, &respCount, pdr.data(),
430                                  respCount, &transferCRC);
431         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
432         {
433             error("Failed to decode_get_pdr_resp: rc = {RC}, cc = {CC}", "RC",
434                   rc, "CC", static_cast<unsigned>(completionCode));
435             return;
436         }
437         else
438         {
439             // when nextRecordHandle is 0, we need the recordHandle of the last
440             // PDR and not 0-1.
441             if (!nextRecordHandle)
442             {
443                 rh = nextRecordHandle;
444             }
445             else
446             {
447                 rh = nextRecordHandle - 1;
448             }
449 
450             auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
451             if (!rh)
452             {
453                 rh = pdrHdr->record_handle;
454             }
455 
456             if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
457             {
458                 this->mergeEntityAssociations(pdr);
459                 merged = true;
460             }
461             else
462             {
463                 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR)
464                 {
465                     pdrTerminusHandle =
466                         extractTerminusHandle<pldm_terminus_locator_pdr>(pdr);
467                     auto tlpdr =
468                         reinterpret_cast<const pldm_terminus_locator_pdr*>(
469                             pdr.data());
470 
471                     terminusHandle = tlpdr->terminus_handle;
472                     tid = tlpdr->tid;
473                     auto terminus_locator_type = tlpdr->terminus_locator_type;
474                     if (terminus_locator_type ==
475                         PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID)
476                     {
477                         auto locatorValue = reinterpret_cast<
478                             const pldm_terminus_locator_type_mctp_eid*>(
479                             tlpdr->terminus_locator_value);
480                         tlEid = static_cast<uint8_t>(locatorValue->eid);
481                     }
482                     if (tlpdr->validity == 0)
483                     {
484                         tlValid = false;
485                     }
486                     for (const auto& terminusMap : tlPDRInfo)
487                     {
488                         if ((terminusHandle == (terminusMap.first)) &&
489                             (get<1>(terminusMap.second) == tlEid) &&
490                             (get<2>(terminusMap.second) == tlpdr->validity))
491                         {
492                             // TL PDR already present with same validity don't
493                             // add the PDR to the repo just return
494                             return;
495                         }
496                     }
497                     tlPDRInfo.insert_or_assign(
498                         tlpdr->terminus_handle,
499                         std::make_tuple(tlpdr->tid, tlEid, tlpdr->validity));
500                 }
501                 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
502                 {
503                     pdrTerminusHandle =
504                         extractTerminusHandle<pldm_state_sensor_pdr>(pdr);
505                     stateSensorPDRs.emplace_back(pdr);
506                 }
507                 else if (pdrHdr->type == PLDM_PDR_FRU_RECORD_SET)
508                 {
509                     pdrTerminusHandle =
510                         extractTerminusHandle<pldm_pdr_fru_record_set>(pdr);
511                 }
512                 else if (pdrHdr->type == PLDM_STATE_EFFECTER_PDR)
513                 {
514                     pdrTerminusHandle =
515                         extractTerminusHandle<pldm_state_effecter_pdr>(pdr);
516                 }
517                 else if (pdrHdr->type == PLDM_NUMERIC_EFFECTER_PDR)
518                 {
519                     pdrTerminusHandle =
520                         extractTerminusHandle<pldm_numeric_effecter_value_pdr>(
521                             pdr);
522                 }
523                 // if the TLPDR is invalid update the repo accordingly
524                 if (!tlValid)
525                 {
526                     pldm_pdr_update_TL_pdr(repo, terminusHandle, tid, tlEid,
527                                            tlValid);
528                 }
529                 else
530                 {
531                     pldm_pdr_add(repo, pdr.data(), respCount, rh, true,
532                                  pdrTerminusHandle);
533                 }
534             }
535         }
536     }
537     if (!nextRecordHandle)
538     {
539         /*received last record*/
540         this->parseStateSensorPDRs(stateSensorPDRs);
541         if (isHostUp())
542         {
543             this->setHostSensorState(stateSensorPDRs);
544         }
545         stateSensorPDRs.clear();
546         if (merged)
547         {
548             merged = false;
549             deferredPDRRepoChgEvent =
550                 std::make_unique<sdeventplus::source::Defer>(
551                     event,
552                     std::bind(
553                         std::mem_fn((&HostPDRHandler::_processPDRRepoChgEvent)),
554                         this, std::placeholders::_1));
555         }
556     }
557     else
558     {
559         if (modifiedPDRRecordHandles.empty() && isHostPdrModified)
560         {
561             isHostPdrModified = false;
562         }
563         else
564         {
565             deferredFetchPDREvent =
566                 std::make_unique<sdeventplus::source::Defer>(
567                     event,
568                     std::bind(
569                         std::mem_fn((&HostPDRHandler::_processFetchPDREvent)),
570                         this, nextRecordHandle, std::placeholders::_1));
571         }
572     }
573 }
574 
575 void HostPDRHandler::_processPDRRepoChgEvent(
576     sdeventplus::source::EventBase& /*source */)
577 {
578     deferredPDRRepoChgEvent.reset();
579     this->sendPDRRepositoryChgEvent(
580         std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
581         FORMAT_IS_PDR_HANDLES);
582 }
583 
584 void HostPDRHandler::_processFetchPDREvent(
585     uint32_t nextRecordHandle, sdeventplus::source::EventBase& /*source */)
586 {
587     deferredFetchPDREvent.reset();
588     if (!this->pdrRecordHandles.empty())
589     {
590         nextRecordHandle = this->pdrRecordHandles.front();
591         this->pdrRecordHandles.pop_front();
592     }
593     if (isHostPdrModified && (!this->modifiedPDRRecordHandles.empty()))
594     {
595         nextRecordHandle = this->modifiedPDRRecordHandles.front();
596         this->modifiedPDRRecordHandles.pop_front();
597     }
598     this->getHostPDR(nextRecordHandle);
599 }
600 
601 void HostPDRHandler::setHostFirmwareCondition()
602 {
603     responseReceived = false;
604     auto instanceId = requester.getInstanceId(mctp_eid);
605     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
606                                     PLDM_GET_VERSION_REQ_BYTES);
607     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
608     auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART,
609                                      PLDM_BASE, request);
610     if (rc != PLDM_SUCCESS)
611     {
612         error("GetPLDMVersion encode failure. PLDM error code = {RC}", "RC",
613               lg2::hex, rc);
614         requester.markFree(mctp_eid, instanceId);
615         return;
616     }
617 
618     auto getPLDMVersionHandler = [this](mctp_eid_t /*eid*/,
619                                         const pldm_msg* response,
620                                         size_t respMsgLen) {
621         if (response == nullptr || !respMsgLen)
622         {
623             error(
624                 "Failed to receive response for getPLDMVersion command, Host seems to be off");
625             return;
626         }
627         info("Getting the response. PLDM RC = {RC}", "RC", lg2::hex,
628              static_cast<uint16_t>(response->payload[0]));
629         this->responseReceived = true;
630         getHostPDR();
631     };
632     rc = handler->registerRequest(mctp_eid, instanceId, PLDM_BASE,
633                                   PLDM_GET_PLDM_VERSION, std::move(requestMsg),
634                                   std::move(getPLDMVersionHandler));
635     if (rc)
636     {
637         error("Failed to discover Host state. Assuming Host as off");
638     }
639 }
640 
641 bool HostPDRHandler::isHostUp()
642 {
643     return responseReceived;
644 }
645 
646 void HostPDRHandler::setHostSensorState(const PDRList& stateSensorPDRs)
647 {
648     for (const auto& stateSensorPDR : stateSensorPDRs)
649     {
650         auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>(
651             stateSensorPDR.data());
652 
653         if (!pdr)
654         {
655             error("Failed to get State sensor PDR");
656             pldm::utils::reportError(
657                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
658             return;
659         }
660 
661         uint16_t sensorId = pdr->sensor_id;
662 
663         for (const auto& [terminusHandle, terminusInfo] : tlPDRInfo)
664         {
665             if (terminusHandle == pdr->terminus_handle)
666             {
667                 if (std::get<2>(terminusInfo) == PLDM_TL_PDR_VALID)
668                 {
669                     mctp_eid = std::get<1>(terminusInfo);
670                 }
671 
672                 bitfield8_t sensorRearm;
673                 sensorRearm.byte = 0;
674                 uint8_t tid = std::get<0>(terminusInfo);
675 
676                 auto instanceId = requester.getInstanceId(mctp_eid);
677                 std::vector<uint8_t> requestMsg(
678                     sizeof(pldm_msg_hdr) +
679                     PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES);
680                 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
681                 auto rc = encode_get_state_sensor_readings_req(
682                     instanceId, sensorId, sensorRearm, 0, request);
683 
684                 if (rc != PLDM_SUCCESS)
685                 {
686                     requester.markFree(mctp_eid, instanceId);
687                     error(
688                         "Failed to encode_get_state_sensor_readings_req, rc = {RC}",
689                         "RC", rc);
690                     pldm::utils::reportError(
691                         "xyz.openbmc_project.bmc.pldm.InternalFailure");
692                     return;
693                 }
694 
695                 auto getStateSensorReadingRespHandler = [=, this](
696                                                             mctp_eid_t /*eid*/,
697                                                             const pldm_msg*
698                                                                 response,
699                                                             size_t respMsgLen) {
700                     if (response == nullptr || !respMsgLen)
701                     {
702                         error(
703                             "Failed to receive response for getStateSensorReading command");
704                         return;
705                     }
706                     std::array<get_sensor_state_field, 8> stateField{};
707                     uint8_t completionCode = 0;
708                     uint8_t comp_sensor_count = 0;
709 
710                     auto rc = decode_get_state_sensor_readings_resp(
711                         response, respMsgLen, &completionCode,
712                         &comp_sensor_count, stateField.data());
713 
714                     if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
715                     {
716                         error(
717                             "Failed to decode_get_state_sensor_readings_resp, rc = {RC} cc = {CC}",
718                             "RC", rc, "CC",
719                             static_cast<unsigned>(completionCode));
720                         pldm::utils::reportError(
721                             "xyz.openbmc_project.bmc.pldm.InternalFailure");
722                     }
723 
724                     uint8_t eventState;
725                     uint8_t previousEventState;
726 
727                     for (uint8_t sensorOffset = 0;
728                          sensorOffset < comp_sensor_count; sensorOffset++)
729                     {
730                         eventState = stateField[sensorOffset].present_state;
731                         previousEventState =
732                             stateField[sensorOffset].previous_state;
733 
734                         emitStateSensorEventSignal(tid, sensorId, sensorOffset,
735                                                    eventState,
736                                                    previousEventState);
737 
738                         SensorEntry sensorEntry{tid, sensorId};
739 
740                         pldm::pdr::EntityInfo entityInfo{};
741                         pldm::pdr::CompositeSensorStates
742                             compositeSensorStates{};
743 
744                         try
745                         {
746                             std::tie(entityInfo, compositeSensorStates) =
747                                 lookupSensorInfo(sensorEntry);
748                         }
749                         catch (const std::out_of_range& e)
750                         {
751                             try
752                             {
753                                 sensorEntry.terminusID = PLDM_TID_RESERVED;
754                                 std::tie(entityInfo, compositeSensorStates) =
755                                     lookupSensorInfo(sensorEntry);
756                             }
757                             catch (const std::out_of_range& e)
758                             {
759                                 error("No mapping for the events");
760                             }
761                         }
762 
763                         if (sensorOffset > compositeSensorStates.size())
764                         {
765                             error("Error Invalid data, Invalid sensor offset");
766                             return;
767                         }
768 
769                         const auto& possibleStates =
770                             compositeSensorStates[sensorOffset];
771                         if (possibleStates.find(eventState) ==
772                             possibleStates.end())
773                         {
774                             error("Error invalid_data, Invalid event state");
775                             return;
776                         }
777                         const auto& [containerId, entityType, entityInstance] =
778                             entityInfo;
779                         pldm::responder::events::StateSensorEntry
780                             stateSensorEntry{containerId, entityType,
781                                              entityInstance, sensorOffset};
782                         handleStateSensorEvent(stateSensorEntry, eventState);
783                     }
784                 };
785 
786                 rc = handler->registerRequest(
787                     mctp_eid, instanceId, PLDM_PLATFORM,
788                     PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg),
789                     std::move(getStateSensorReadingRespHandler));
790 
791                 if (rc != PLDM_SUCCESS)
792                 {
793                     error(
794                         "Failed to send request to get State sensor reading on Host");
795                 }
796             }
797         }
798     }
799 }
800 } // namespace pldm
801