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::setHostState()
548 {
549     using namespace sdeventplus;
550     using namespace sdeventplus::source;
551     constexpr auto clockId = sdeventplus::ClockId::RealTime;
552     using Clock = Clock<clockId>;
553     using Timer = Time<clockId>;
554 
555     auto event1 = sdeventplus::Event::get_default();
556     auto& bus = pldm::utils::DBusHandler::getBus();
557     bus.attach_event(event1.get(), SD_EVENT_PRIORITY_NORMAL);
558 
559     responseReceived = false;
560     timeOut = false;
561 
562     int fd = pldm_open();
563     if (-1 == fd)
564     {
565         std::cerr << "Failed to connect to mctp demux daemon \n";
566         return;
567     }
568 
569     auto timerCallback = [=, this](Timer& /*source*/,
570                                    Timer::TimePoint /*time*/) {
571         timeOut = true;
572         if (!responseReceived)
573         {
574             std::cout << "PLDM did not get a response from Host"
575                          " Host seems to be off \n";
576         }
577         return;
578     };
579 
580     Timer time(event1, (Clock(event1).now() + std::chrono::seconds{3}),
581                std::chrono::seconds{1}, std::move(timerCallback));
582 
583     auto callback = [=, this](IO& /*io*/, int fd, uint32_t revents) {
584         if (!(revents & EPOLLIN))
585         {
586             return;
587         }
588         uint8_t* responseMsg = nullptr;
589         size_t responseMsgSize{};
590         auto rc =
591             pldm_recv(mctp_eid, fd, insId, &responseMsg, &responseMsgSize);
592         if (rc != PLDM_REQUESTER_SUCCESS)
593         {
594             return;
595         }
596         std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
597             responseMsg, std::free};
598         auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
599         std::cout << "Getting the response. PLDM RC = " << std::hex
600                   << std::showbase
601                   << static_cast<uint16_t>(response->payload[0]) << "\n";
602         responseReceived = true;
603         return;
604     };
605     IO io(event1, fd, EPOLLIN, std::move(callback));
606     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
607                                     PLDM_GET_PDR_REQ_BYTES);
608     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
609     uint32_t recordHandle{};
610     insId = requester.getInstanceId(mctp_eid);
611     auto rc =
612         encode_get_pdr_req(insId, recordHandle, 0, PLDM_GET_FIRSTPART,
613                            UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES);
614     if (rc != PLDM_SUCCESS)
615     {
616         requester.markFree(mctp_eid, insId);
617         std::cerr << "Failed to encode_get_pdr_req, rc = " << rc << std::endl;
618         return;
619     }
620     rc = pldm_send(mctp_eid, fd, requestMsg.data(), requestMsg.size());
621     if (0 > rc)
622     {
623         std::cerr << "Failed to send message RC = " << rc
624                   << ", errno = " << errno << "\n";
625         return;
626     }
627     while (1)
628     {
629         if (responseReceived)
630         {
631             requester.markFree(mctp_eid, insId);
632             break;
633         }
634         if (timeOut)
635         {
636             requester.markFree(mctp_eid, insId);
637             break;
638         }
639         try
640         {
641             event1.run(std::nullopt);
642         }
643         catch (const sdeventplus::SdEventError& e)
644         {
645             std::cerr << "Failure in processing request.ERROR= " << e.what()
646                       << "\n";
647             return;
648         }
649     }
650 }
651 
652 bool HostPDRHandler::isHostUp()
653 {
654     return responseReceived;
655 }
656 
657 void HostPDRHandler::setHostSensorState(const PDRList& stateSensorPDRs,
658                                         const std::vector<TlInfo>& tlinfo)
659 {
660     for (const auto& stateSensorPDR : stateSensorPDRs)
661     {
662         auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>(
663             stateSensorPDR.data());
664 
665         if (!pdr)
666         {
667             std::cerr << "Failed to get State sensor PDR" << std::endl;
668             pldm::utils::reportError(
669                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
670             return;
671         }
672 
673         uint16_t sensorId = pdr->sensor_id;
674 
675         for (auto info : tlinfo)
676         {
677             if (info.terminusHandle == pdr->terminus_handle)
678             {
679                 if (info.valid == PLDM_TL_PDR_VALID)
680                 {
681                     mctp_eid = info.eid;
682                 }
683 
684                 bitfield8_t sensorRearm;
685                 sensorRearm.byte = 0;
686                 uint8_t tid = info.tid;
687 
688                 auto instanceId = requester.getInstanceId(mctp_eid);
689                 std::vector<uint8_t> requestMsg(
690                     sizeof(pldm_msg_hdr) +
691                     PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES);
692                 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
693                 auto rc = encode_get_state_sensor_readings_req(
694                     instanceId, sensorId, sensorRearm, 0, request);
695 
696                 if (rc != PLDM_SUCCESS)
697                 {
698                     requester.markFree(mctp_eid, instanceId);
699                     std::cerr << "Failed to "
700                                  "encode_get_state_sensor_readings_req, rc = "
701                               << rc << std::endl;
702                     pldm::utils::reportError(
703                         "xyz.openbmc_project.bmc.pldm.InternalFailure");
704                     return;
705                 }
706 
707                 auto getStateSensorReadingRespHandler = [=, this](
708                                                             mctp_eid_t /*eid*/,
709                                                             const pldm_msg*
710                                                                 response,
711                                                             size_t respMsgLen) {
712                     if (response == nullptr || !respMsgLen)
713                     {
714                         std::cerr << "Failed to receive response for "
715                                      "getStateSensorReading command \n";
716                         return;
717                     }
718                     std::array<get_sensor_state_field, 8> stateField{};
719                     uint8_t completionCode = 0;
720                     uint8_t comp_sensor_count = 0;
721 
722                     auto rc = decode_get_state_sensor_readings_resp(
723                         response, respMsgLen, &completionCode,
724                         &comp_sensor_count, stateField.data());
725 
726                     if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
727                     {
728                         std::cerr
729                             << "Failed to "
730                                "decode_get_state_sensor_readings_resp, rc = "
731                             << rc
732                             << " cc=" << static_cast<unsigned>(completionCode)
733                             << std::endl;
734                         pldm::utils::reportError(
735                             "xyz.openbmc_project.bmc.pldm.InternalFailure");
736                     }
737 
738                     uint8_t eventState;
739                     uint8_t previousEventState;
740                     uint8_t sensorOffset = comp_sensor_count - 1;
741 
742                     for (size_t i = 0; i < comp_sensor_count; i++)
743                     {
744                         eventState = stateField[i].present_state;
745                         previousEventState = stateField[i].previous_state;
746 
747                         emitStateSensorEventSignal(tid, sensorId, sensorOffset,
748                                                    eventState,
749                                                    previousEventState);
750 
751                         SensorEntry sensorEntry{tid, sensorId};
752 
753                         pldm::pdr::EntityInfo entityInfo{};
754                         pldm::pdr::CompositeSensorStates
755                             compositeSensorStates{};
756 
757                         try
758                         {
759                             std::tie(entityInfo, compositeSensorStates) =
760                                 lookupSensorInfo(sensorEntry);
761                         }
762                         catch (const std::out_of_range& e)
763                         {
764                             try
765                             {
766                                 sensorEntry.terminusID = PLDM_TID_RESERVED;
767                                 std::tie(entityInfo, compositeSensorStates) =
768                                     lookupSensorInfo(sensorEntry);
769                             }
770                             catch (const std::out_of_range& e)
771                             {
772                                 std::cerr << "No mapping for the events"
773                                           << std::endl;
774                             }
775                         }
776 
777                         if (sensorOffset > compositeSensorStates.size())
778                         {
779                             std::cerr
780                                 << " Error Invalid data, Invalid sensor offset"
781                                 << std::endl;
782                             return;
783                         }
784 
785                         const auto& possibleStates =
786                             compositeSensorStates[sensorOffset];
787                         if (possibleStates.find(eventState) ==
788                             possibleStates.end())
789                         {
790                             std::cerr
791                                 << " Error invalid_data, Invalid event state"
792                                 << std::endl;
793                             return;
794                         }
795                         const auto& [containerId, entityType, entityInstance] =
796                             entityInfo;
797                         pldm::responder::events::StateSensorEntry
798                             stateSensorEntry{containerId, entityType,
799                                              entityInstance, sensorOffset};
800                         handleStateSensorEvent(stateSensorEntry, eventState);
801                     }
802                 };
803 
804                 rc = handler->registerRequest(
805                     mctp_eid, instanceId, PLDM_PLATFORM,
806                     PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg),
807                     std::move(getStateSensorReadingRespHandler));
808 
809                 if (rc != PLDM_SUCCESS)
810                 {
811                     std::cerr << " Failed to send request to get State sensor "
812                                  "reading on Host "
813                               << std::endl;
814                 }
815             }
816         }
817     }
818 }
819 } // namespace pldm
820