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 = encode_get_pdr_req(instanceId, recordHandle, 0,
178                                  PLDM_GET_FIRSTPART, UINT16_MAX, 0, request,
179                                  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 =
334         [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
335         if (response == nullptr || !respMsgLen)
336         {
337             error(
338                 "Failed to receive response for the PDR repository changed event");
339             return;
340         }
341 
342         uint8_t completionCode{};
343         uint8_t status{};
344         auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response);
345         auto rc = decode_platform_event_message_resp(responsePtr, respMsgLen,
346                                                      &completionCode, &status);
347         if (rc || completionCode)
348         {
349             error(
350                 "Failed to decode_platform_event_message_resp: {RC}, cc = {CC}",
351                 "RC", rc, "CC", static_cast<unsigned>(completionCode));
352         }
353     };
354 
355     rc = handler->registerRequest(
356         mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE,
357         std::move(requestMsg), std::move(platformEventMessageResponseHandler));
358     if (rc)
359     {
360         error("Failed to send the PDR repository changed event request");
361     }
362 }
363 
364 void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs)
365 {
366     for (const auto& pdr : stateSensorPDRs)
367     {
368         SensorEntry sensorEntry{};
369         const auto& [terminusHandle, sensorID, sensorInfo] =
370             responder::pdr_utils::parseStateSensorPDR(pdr);
371         sensorEntry.sensorID = sensorID;
372         try
373         {
374             sensorEntry.terminusID = std::get<0>(tlPDRInfo.at(terminusHandle));
375         }
376         // If there is no mapping for terminusHandle assign the reserved TID
377         // value of 0xFF to indicate that.
378         catch (const std::out_of_range& e)
379         {
380             sensorEntry.terminusID = PLDM_TID_RESERVED;
381         }
382         sensorMap.emplace(sensorEntry, std::move(sensorInfo));
383     }
384 }
385 
386 void HostPDRHandler::processHostPDRs(mctp_eid_t /*eid*/,
387                                      const pldm_msg* response,
388                                      size_t respMsgLen)
389 {
390     static bool merged = false;
391     static PDRList stateSensorPDRs{};
392     uint32_t nextRecordHandle{};
393     uint8_t tlEid = 0;
394     bool tlValid = true;
395     uint32_t rh = 0;
396     uint16_t terminusHandle = 0;
397     uint16_t pdrTerminusHandle = 0;
398     uint8_t tid = 0;
399 
400     uint8_t completionCode{};
401     uint32_t nextDataTransferHandle{};
402     uint8_t transferFlag{};
403     uint16_t respCount{};
404     uint8_t transferCRC{};
405     if (response == nullptr || !respMsgLen)
406     {
407         error("Failed to receive response for the GetPDR command");
408         return;
409     }
410 
411     auto rc = decode_get_pdr_resp(
412         response, respMsgLen /*- sizeof(pldm_msg_hdr)*/, &completionCode,
413         &nextRecordHandle, &nextDataTransferHandle, &transferFlag, &respCount,
414         nullptr, 0, &transferCRC);
415     std::vector<uint8_t> responsePDRMsg;
416     responsePDRMsg.resize(respMsgLen + sizeof(pldm_msg_hdr));
417     memcpy(responsePDRMsg.data(), response, respMsgLen + sizeof(pldm_msg_hdr));
418     if (rc != PLDM_SUCCESS)
419     {
420         error("Failed to decode_get_pdr_resp, rc = {RC}", "RC", rc);
421         return;
422     }
423     else
424     {
425         std::vector<uint8_t> pdr(respCount, 0);
426         rc = decode_get_pdr_resp(response, respMsgLen, &completionCode,
427                                  &nextRecordHandle, &nextDataTransferHandle,
428                                  &transferFlag, &respCount, pdr.data(),
429                                  respCount, &transferCRC);
430         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
431         {
432             error("Failed to decode_get_pdr_resp: rc = {RC}, cc = {CC}", "RC",
433                   rc, "CC", static_cast<unsigned>(completionCode));
434             return;
435         }
436         else
437         {
438             // when nextRecordHandle is 0, we need the recordHandle of the last
439             // PDR and not 0-1.
440             if (!nextRecordHandle)
441             {
442                 rh = nextRecordHandle;
443             }
444             else
445             {
446                 rh = nextRecordHandle - 1;
447             }
448 
449             auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
450             if (!rh)
451             {
452                 rh = pdrHdr->record_handle;
453             }
454 
455             if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
456             {
457                 this->mergeEntityAssociations(pdr);
458                 merged = true;
459             }
460             else
461             {
462                 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR)
463                 {
464                     pdrTerminusHandle =
465                         extractTerminusHandle<pldm_terminus_locator_pdr>(pdr);
466                     auto tlpdr =
467                         reinterpret_cast<const pldm_terminus_locator_pdr*>(
468                             pdr.data());
469 
470                     terminusHandle = tlpdr->terminus_handle;
471                     tid = tlpdr->tid;
472                     auto terminus_locator_type = tlpdr->terminus_locator_type;
473                     if (terminus_locator_type ==
474                         PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID)
475                     {
476                         auto locatorValue = reinterpret_cast<
477                             const pldm_terminus_locator_type_mctp_eid*>(
478                             tlpdr->terminus_locator_value);
479                         tlEid = static_cast<uint8_t>(locatorValue->eid);
480                     }
481                     if (tlpdr->validity == 0)
482                     {
483                         tlValid = false;
484                     }
485                     for (const auto& terminusMap : tlPDRInfo)
486                     {
487                         if ((terminusHandle == (terminusMap.first)) &&
488                             (get<1>(terminusMap.second) == tlEid) &&
489                             (get<2>(terminusMap.second) == tlpdr->validity))
490                         {
491                             // TL PDR already present with same validity don't
492                             // add the PDR to the repo just return
493                             return;
494                         }
495                     }
496                     tlPDRInfo.insert_or_assign(
497                         tlpdr->terminus_handle,
498                         std::make_tuple(tlpdr->tid, tlEid, tlpdr->validity));
499                 }
500                 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
501                 {
502                     pdrTerminusHandle =
503                         extractTerminusHandle<pldm_state_sensor_pdr>(pdr);
504                     stateSensorPDRs.emplace_back(pdr);
505                 }
506                 else if (pdrHdr->type == PLDM_PDR_FRU_RECORD_SET)
507                 {
508                     pdrTerminusHandle =
509                         extractTerminusHandle<pldm_pdr_fru_record_set>(pdr);
510                 }
511                 else if (pdrHdr->type == PLDM_STATE_EFFECTER_PDR)
512                 {
513                     pdrTerminusHandle =
514                         extractTerminusHandle<pldm_state_effecter_pdr>(pdr);
515                 }
516                 else if (pdrHdr->type == PLDM_NUMERIC_EFFECTER_PDR)
517                 {
518                     pdrTerminusHandle =
519                         extractTerminusHandle<pldm_numeric_effecter_value_pdr>(
520                             pdr);
521                 }
522                 // if the TLPDR is invalid update the repo accordingly
523                 if (!tlValid)
524                 {
525                     pldm_pdr_update_TL_pdr(repo, terminusHandle, tid, tlEid,
526                                            tlValid);
527                 }
528                 else
529                 {
530                     pldm_pdr_add(repo, pdr.data(), respCount, rh, true,
531                                  pdrTerminusHandle);
532                 }
533             }
534         }
535     }
536     if (!nextRecordHandle)
537     {
538         /*received last record*/
539         this->parseStateSensorPDRs(stateSensorPDRs);
540         if (isHostUp())
541         {
542             this->setHostSensorState(stateSensorPDRs);
543         }
544         stateSensorPDRs.clear();
545         if (merged)
546         {
547             merged = false;
548             deferredPDRRepoChgEvent =
549                 std::make_unique<sdeventplus::source::Defer>(
550                     event,
551                     std::bind(
552                         std::mem_fn((&HostPDRHandler::_processPDRRepoChgEvent)),
553                         this, std::placeholders::_1));
554         }
555     }
556     else
557     {
558         if (modifiedPDRRecordHandles.empty() && isHostPdrModified)
559         {
560             isHostPdrModified = false;
561         }
562         else
563         {
564             deferredFetchPDREvent =
565                 std::make_unique<sdeventplus::source::Defer>(
566                     event,
567                     std::bind(
568                         std::mem_fn((&HostPDRHandler::_processFetchPDREvent)),
569                         this, nextRecordHandle, std::placeholders::_1));
570         }
571     }
572 }
573 
574 void HostPDRHandler::_processPDRRepoChgEvent(
575     sdeventplus::source::EventBase& /*source */)
576 {
577     deferredPDRRepoChgEvent.reset();
578     this->sendPDRRepositoryChgEvent(
579         std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
580         FORMAT_IS_PDR_HANDLES);
581 }
582 
583 void HostPDRHandler::_processFetchPDREvent(
584     uint32_t nextRecordHandle, sdeventplus::source::EventBase& /*source */)
585 {
586     deferredFetchPDREvent.reset();
587     if (!this->pdrRecordHandles.empty())
588     {
589         nextRecordHandle = this->pdrRecordHandles.front();
590         this->pdrRecordHandles.pop_front();
591     }
592     if (isHostPdrModified && (!this->modifiedPDRRecordHandles.empty()))
593     {
594         nextRecordHandle = this->modifiedPDRRecordHandles.front();
595         this->modifiedPDRRecordHandles.pop_front();
596     }
597     this->getHostPDR(nextRecordHandle);
598 }
599 
600 void HostPDRHandler::setHostFirmwareCondition()
601 {
602     responseReceived = false;
603     auto instanceId = requester.getInstanceId(mctp_eid);
604     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
605                                     PLDM_GET_VERSION_REQ_BYTES);
606     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
607     auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART,
608                                      PLDM_BASE, request);
609     if (rc != PLDM_SUCCESS)
610     {
611         error("GetPLDMVersion encode failure. PLDM error code = {RC}", "RC",
612               lg2::hex, rc);
613         requester.markFree(mctp_eid, instanceId);
614         return;
615     }
616 
617     auto getPLDMVersionHandler = [this](mctp_eid_t /*eid*/,
618                                         const pldm_msg* response,
619                                         size_t respMsgLen) {
620         if (response == nullptr || !respMsgLen)
621         {
622             error(
623                 "Failed to receive response for getPLDMVersion command, Host seems to be off");
624             return;
625         }
626         info("Getting the response. PLDM RC = {RC}", "RC", lg2::hex,
627              static_cast<uint16_t>(response->payload[0]));
628         this->responseReceived = true;
629         getHostPDR();
630     };
631     rc = handler->registerRequest(mctp_eid, instanceId, PLDM_BASE,
632                                   PLDM_GET_PLDM_VERSION, std::move(requestMsg),
633                                   std::move(getPLDMVersionHandler));
634     if (rc)
635     {
636         error("Failed to discover Host state. Assuming Host as off");
637     }
638 }
639 
640 bool HostPDRHandler::isHostUp()
641 {
642     return responseReceived;
643 }
644 
645 void HostPDRHandler::setHostSensorState(const PDRList& stateSensorPDRs)
646 {
647     for (const auto& stateSensorPDR : stateSensorPDRs)
648     {
649         auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>(
650             stateSensorPDR.data());
651 
652         if (!pdr)
653         {
654             error("Failed to get State sensor PDR");
655             pldm::utils::reportError(
656                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
657             return;
658         }
659 
660         uint16_t sensorId = pdr->sensor_id;
661 
662         for (const auto& [terminusHandle, terminusInfo] : tlPDRInfo)
663         {
664             if (terminusHandle == pdr->terminus_handle)
665             {
666                 if (std::get<2>(terminusInfo) == PLDM_TL_PDR_VALID)
667                 {
668                     mctp_eid = std::get<1>(terminusInfo);
669                 }
670 
671                 bitfield8_t sensorRearm;
672                 sensorRearm.byte = 0;
673                 uint8_t tid = std::get<0>(terminusInfo);
674 
675                 auto instanceId = requester.getInstanceId(mctp_eid);
676                 std::vector<uint8_t> requestMsg(
677                     sizeof(pldm_msg_hdr) +
678                     PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES);
679                 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
680                 auto rc = encode_get_state_sensor_readings_req(
681                     instanceId, sensorId, sensorRearm, 0, request);
682 
683                 if (rc != PLDM_SUCCESS)
684                 {
685                     requester.markFree(mctp_eid, instanceId);
686                     error(
687                         "Failed to encode_get_state_sensor_readings_req, rc = {RC}",
688                         "RC", rc);
689                     pldm::utils::reportError(
690                         "xyz.openbmc_project.bmc.pldm.InternalFailure");
691                     return;
692                 }
693 
694                 auto getStateSensorReadingRespHandler =
695                     [=, this](mctp_eid_t /*eid*/, const pldm_msg* response,
696                               size_t respMsgLen) {
697                     if (response == nullptr || !respMsgLen)
698                     {
699                         error(
700                             "Failed to receive response for getStateSensorReading command");
701                         return;
702                     }
703                     std::array<get_sensor_state_field, 8> stateField{};
704                     uint8_t completionCode = 0;
705                     uint8_t comp_sensor_count = 0;
706 
707                     auto rc = decode_get_state_sensor_readings_resp(
708                         response, respMsgLen, &completionCode,
709                         &comp_sensor_count, stateField.data());
710 
711                     if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
712                     {
713                         error(
714                             "Failed to decode_get_state_sensor_readings_resp, rc = {RC} cc = {CC}",
715                             "RC", rc, "CC",
716                             static_cast<unsigned>(completionCode));
717                         pldm::utils::reportError(
718                             "xyz.openbmc_project.bmc.pldm.InternalFailure");
719                     }
720 
721                     uint8_t eventState;
722                     uint8_t previousEventState;
723 
724                     for (uint8_t sensorOffset = 0;
725                          sensorOffset < comp_sensor_count; sensorOffset++)
726                     {
727                         eventState = stateField[sensorOffset].present_state;
728                         previousEventState =
729                             stateField[sensorOffset].previous_state;
730 
731                         emitStateSensorEventSignal(tid, sensorId, sensorOffset,
732                                                    eventState,
733                                                    previousEventState);
734 
735                         SensorEntry sensorEntry{tid, sensorId};
736 
737                         pldm::pdr::EntityInfo entityInfo{};
738                         pldm::pdr::CompositeSensorStates
739                             compositeSensorStates{};
740 
741                         try
742                         {
743                             std::tie(entityInfo, compositeSensorStates) =
744                                 lookupSensorInfo(sensorEntry);
745                         }
746                         catch (const std::out_of_range& e)
747                         {
748                             try
749                             {
750                                 sensorEntry.terminusID = PLDM_TID_RESERVED;
751                                 std::tie(entityInfo, compositeSensorStates) =
752                                     lookupSensorInfo(sensorEntry);
753                             }
754                             catch (const std::out_of_range& e)
755                             {
756                                 error("No mapping for the events");
757                             }
758                         }
759 
760                         if (sensorOffset > compositeSensorStates.size())
761                         {
762                             error("Error Invalid data, Invalid sensor offset");
763                             return;
764                         }
765 
766                         const auto& possibleStates =
767                             compositeSensorStates[sensorOffset];
768                         if (possibleStates.find(eventState) ==
769                             possibleStates.end())
770                         {
771                             error("Error invalid_data, Invalid event state");
772                             return;
773                         }
774                         const auto& [containerId, entityType,
775                                      entityInstance] = entityInfo;
776                         pldm::responder::events::StateSensorEntry
777                             stateSensorEntry{containerId, entityType,
778                                              entityInstance, sensorOffset};
779                         handleStateSensorEvent(stateSensorEntry, eventState);
780                     }
781                 };
782 
783                 rc = handler->registerRequest(
784                     mctp_eid, instanceId, PLDM_PLATFORM,
785                     PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg),
786                     std::move(getStateSensorReadingRespHandler));
787 
788                 if (rc != PLDM_SUCCESS)
789                 {
790                     error(
791                         "Failed to send request to get State sensor reading on Host");
792                 }
793             }
794         }
795     }
796 }
797 } // namespace pldm
798