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