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