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