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