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