1 #include "host_pdr_handler.hpp"
2 
3 #include <assert.h>
4 #include <libpldm/pldm.h>
5 
6 #include <nlohmann/json.hpp>
7 #include <phosphor-logging/lg2.hpp>
8 #include <sdeventplus/clock.hpp>
9 #include <sdeventplus/exception.hpp>
10 #include <sdeventplus/source/io.hpp>
11 #include <sdeventplus/source/time.hpp>
12 
13 #include <fstream>
14 
15 PHOSPHOR_LOG2_USING;
16 
17 namespace pldm
18 {
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,
51     pldm::InstanceIdDb& instanceIdDb,
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), instanceIdDb(instanceIdDb), 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                 error("Parsing Host FRU json file failed");
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             error("Parsing Host FRU json file failed, exception = {ERR_EXCEP}",
88                   "ERR_EXCEP", e.what());
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 = instanceIdDb.next(mctp_eid);
174 
175     auto rc = encode_get_pdr_req(instanceId, recordHandle, 0,
176                                  PLDM_GET_FIRSTPART, UINT16_MAX, 0, request,
177                                  PLDM_GET_PDR_REQ_BYTES);
178     if (rc != PLDM_SUCCESS)
179     {
180         instanceIdDb.free(mctp_eid, instanceId);
181         error("Failed to encode_get_pdr_req, rc = {RC}", "RC", rc);
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         error("Failed to send the GetPDR request to Host");
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         error("Failed to fetch and update D-bus property, rc = {RC}", "RC", rc);
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             error("could not find referrence of the entity in the tree");
253         }
254         else
255         {
256             int rc = pldm_entity_association_pdr_add_from_node_check(
257                 node, repo, &entities, numEntities, true, TERMINUS_HANDLE);
258             if (rc)
259             {
260                 error(
261                     "Failed to add entity association PDR from node: {LIBPLDM_ERROR}",
262                     "LIBPLDM_ERROR", rc);
263             }
264         }
265     }
266     free(entities);
267 }
268 
269 void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes,
270                                                uint8_t eventDataFormat)
271 {
272     assert(eventDataFormat == FORMAT_IS_PDR_HANDLES);
273 
274     // Extract from the PDR repo record handles of PDRs we want the host
275     // to pull up.
276     std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED};
277     std::vector<uint8_t> numsOfChangeEntries(1);
278     std::vector<std::vector<ChangeEntry>> changeEntries(
279         numsOfChangeEntries.size());
280     for (auto pdrType : pdrTypes)
281     {
282         const pldm_pdr_record* record{};
283         do
284         {
285             record = pldm_pdr_find_record_by_type(repo, pdrType, record,
286                                                   nullptr, nullptr);
287             if (record && pldm_pdr_record_is_remote(record))
288             {
289                 changeEntries[0].push_back(
290                     pldm_pdr_get_record_handle(repo, record));
291             }
292         } while (record);
293     }
294     if (changeEntries.empty())
295     {
296         return;
297     }
298     numsOfChangeEntries[0] = changeEntries[0].size();
299 
300     // Encode PLDM platform event msg to indicate a PDR repo change.
301     size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
302                      PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
303                      changeEntries[0].size() * sizeof(uint32_t);
304     std::vector<uint8_t> eventDataVec{};
305     eventDataVec.resize(maxSize);
306     auto eventData =
307         reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
308             eventDataVec.data());
309     size_t actualSize{};
310     auto firstEntry = changeEntries[0].data();
311     auto rc = encode_pldm_pdr_repository_chg_event_data(
312         eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(),
313         &firstEntry, eventData, &actualSize, maxSize);
314     if (rc != PLDM_SUCCESS)
315     {
316         error("Failed to encode_pldm_pdr_repository_chg_event_data, rc = {RC}",
317               "RC", rc);
318         return;
319     }
320     auto instanceId = instanceIdDb.next(mctp_eid);
321     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
322                                     PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
323                                     actualSize);
324     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
325     rc = encode_platform_event_message_req(
326         instanceId, 1, TERMINUS_ID, PLDM_PDR_REPOSITORY_CHG_EVENT,
327         eventDataVec.data(), actualSize, request,
328         actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
329     if (rc != PLDM_SUCCESS)
330     {
331         instanceIdDb.free(mctp_eid, instanceId);
332         error("Failed to encode_platform_event_message_req, rc = {RC}", "RC",
333               rc);
334         return;
335     }
336 
337     auto platformEventMessageResponseHandler =
338         [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
339         if (response == nullptr || !respMsgLen)
340         {
341             error(
342                 "Failed to receive response for the PDR repository changed event");
343             return;
344         }
345 
346         uint8_t completionCode{};
347         uint8_t status{};
348         auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response);
349         auto rc = decode_platform_event_message_resp(responsePtr, respMsgLen,
350                                                      &completionCode, &status);
351         if (rc || completionCode)
352         {
353             error(
354                 "Failed to decode_platform_event_message_resp: {RC}, cc = {CC}",
355                 "RC", rc, "CC", static_cast<unsigned>(completionCode));
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         error("Failed to send the PDR repository changed event request");
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         error("Failed to receive response for the GetPDR command");
412         return;
413     }
414 
415     auto rc = decode_get_pdr_resp(
416         response, respMsgLen /*- sizeof(pldm_msg_hdr)*/, &completionCode,
417         &nextRecordHandle, &nextDataTransferHandle, &transferFlag, &respCount,
418         nullptr, 0, &transferCRC);
419     std::vector<uint8_t> responsePDRMsg;
420     responsePDRMsg.resize(respMsgLen + sizeof(pldm_msg_hdr));
421     memcpy(responsePDRMsg.data(), response, respMsgLen + sizeof(pldm_msg_hdr));
422     if (rc != PLDM_SUCCESS)
423     {
424         error("Failed to decode_get_pdr_resp, rc = {RC}", "RC", rc);
425         return;
426     }
427     else
428     {
429         std::vector<uint8_t> pdr(respCount, 0);
430         rc = decode_get_pdr_resp(response, respMsgLen, &completionCode,
431                                  &nextRecordHandle, &nextDataTransferHandle,
432                                  &transferFlag, &respCount, pdr.data(),
433                                  respCount, &transferCRC);
434         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
435         {
436             error("Failed to decode_get_pdr_resp: rc = {RC}, cc = {CC}", "RC",
437                   rc, "CC", static_cast<unsigned>(completionCode));
438             return;
439         }
440         else
441         {
442             // when nextRecordHandle is 0, we need the recordHandle of the last
443             // PDR and not 0-1.
444             if (!nextRecordHandle)
445             {
446                 rh = nextRecordHandle;
447             }
448             else
449             {
450                 rh = nextRecordHandle - 1;
451             }
452 
453             auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
454             if (!rh)
455             {
456                 rh = pdrHdr->record_handle;
457             }
458 
459             if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
460             {
461                 this->mergeEntityAssociations(pdr);
462                 merged = true;
463             }
464             else
465             {
466                 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR)
467                 {
468                     pdrTerminusHandle =
469                         extractTerminusHandle<pldm_terminus_locator_pdr>(pdr);
470                     auto tlpdr =
471                         reinterpret_cast<const pldm_terminus_locator_pdr*>(
472                             pdr.data());
473 
474                     terminusHandle = tlpdr->terminus_handle;
475                     tid = tlpdr->tid;
476                     auto terminus_locator_type = tlpdr->terminus_locator_type;
477                     if (terminus_locator_type ==
478                         PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID)
479                     {
480                         auto locatorValue = reinterpret_cast<
481                             const pldm_terminus_locator_type_mctp_eid*>(
482                             tlpdr->terminus_locator_value);
483                         tlEid = static_cast<uint8_t>(locatorValue->eid);
484                     }
485                     if (tlpdr->validity == 0)
486                     {
487                         tlValid = false;
488                     }
489                     for (const auto& terminusMap : tlPDRInfo)
490                     {
491                         if ((terminusHandle == (terminusMap.first)) &&
492                             (get<1>(terminusMap.second) == tlEid) &&
493                             (get<2>(terminusMap.second) == tlpdr->validity))
494                         {
495                             // TL PDR already present with same validity don't
496                             // add the PDR to the repo just return
497                             return;
498                         }
499                     }
500                     tlPDRInfo.insert_or_assign(
501                         tlpdr->terminus_handle,
502                         std::make_tuple(tlpdr->tid, tlEid, tlpdr->validity));
503                 }
504                 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
505                 {
506                     pdrTerminusHandle =
507                         extractTerminusHandle<pldm_state_sensor_pdr>(pdr);
508                     stateSensorPDRs.emplace_back(pdr);
509                 }
510                 else if (pdrHdr->type == PLDM_PDR_FRU_RECORD_SET)
511                 {
512                     pdrTerminusHandle =
513                         extractTerminusHandle<pldm_pdr_fru_record_set>(pdr);
514                 }
515                 else if (pdrHdr->type == PLDM_STATE_EFFECTER_PDR)
516                 {
517                     pdrTerminusHandle =
518                         extractTerminusHandle<pldm_state_effecter_pdr>(pdr);
519                 }
520                 else if (pdrHdr->type == PLDM_NUMERIC_EFFECTER_PDR)
521                 {
522                     pdrTerminusHandle =
523                         extractTerminusHandle<pldm_numeric_effecter_value_pdr>(
524                             pdr);
525                 }
526                 // if the TLPDR is invalid update the repo accordingly
527                 if (!tlValid)
528                 {
529                     pldm_pdr_update_TL_pdr(repo, terminusHandle, tid, tlEid,
530                                            tlValid);
531                 }
532                 else
533                 {
534                     rc = pldm_pdr_add_check(repo, pdr.data(), respCount, true,
535                                             pdrTerminusHandle, &rh);
536                     if (rc)
537                     {
538                         // pldm_pdr_add() assert()ed on failure to add a PDR.
539                         throw std::runtime_error("Failed to add PDR");
540                     }
541                 }
542             }
543         }
544     }
545     if (!nextRecordHandle)
546     {
547         /*received last record*/
548         this->parseStateSensorPDRs(stateSensorPDRs);
549         if (isHostUp())
550         {
551             this->setHostSensorState(stateSensorPDRs);
552         }
553         stateSensorPDRs.clear();
554         if (merged)
555         {
556             merged = false;
557             deferredPDRRepoChgEvent =
558                 std::make_unique<sdeventplus::source::Defer>(
559                     event,
560                     std::bind(
561                         std::mem_fn((&HostPDRHandler::_processPDRRepoChgEvent)),
562                         this, std::placeholders::_1));
563         }
564     }
565     else
566     {
567         if (modifiedPDRRecordHandles.empty() && isHostPdrModified)
568         {
569             isHostPdrModified = false;
570         }
571         else
572         {
573             deferredFetchPDREvent =
574                 std::make_unique<sdeventplus::source::Defer>(
575                     event,
576                     std::bind(
577                         std::mem_fn((&HostPDRHandler::_processFetchPDREvent)),
578                         this, nextRecordHandle, std::placeholders::_1));
579         }
580     }
581 }
582 
583 void HostPDRHandler::_processPDRRepoChgEvent(
584     sdeventplus::source::EventBase& /*source */)
585 {
586     deferredPDRRepoChgEvent.reset();
587     this->sendPDRRepositoryChgEvent(
588         std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
589         FORMAT_IS_PDR_HANDLES);
590 }
591 
592 void HostPDRHandler::_processFetchPDREvent(
593     uint32_t nextRecordHandle, sdeventplus::source::EventBase& /*source */)
594 {
595     deferredFetchPDREvent.reset();
596     if (!this->pdrRecordHandles.empty())
597     {
598         nextRecordHandle = this->pdrRecordHandles.front();
599         this->pdrRecordHandles.pop_front();
600     }
601     if (isHostPdrModified && (!this->modifiedPDRRecordHandles.empty()))
602     {
603         nextRecordHandle = this->modifiedPDRRecordHandles.front();
604         this->modifiedPDRRecordHandles.pop_front();
605     }
606     this->getHostPDR(nextRecordHandle);
607 }
608 
609 void HostPDRHandler::setHostFirmwareCondition()
610 {
611     responseReceived = false;
612     auto instanceId = instanceIdDb.next(mctp_eid);
613     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
614                                     PLDM_GET_VERSION_REQ_BYTES);
615     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
616     auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART,
617                                      PLDM_BASE, request);
618     if (rc != PLDM_SUCCESS)
619     {
620         error("GetPLDMVersion encode failure. PLDM error code = {RC}", "RC",
621               lg2::hex, rc);
622         instanceIdDb.free(mctp_eid, instanceId);
623         return;
624     }
625 
626     auto getPLDMVersionHandler = [this](mctp_eid_t /*eid*/,
627                                         const pldm_msg* response,
628                                         size_t respMsgLen) {
629         if (response == nullptr || !respMsgLen)
630         {
631             error(
632                 "Failed to receive response for getPLDMVersion command, Host seems to be off");
633             return;
634         }
635         info("Getting the response. PLDM RC = {RC}", "RC", lg2::hex,
636              static_cast<uint16_t>(response->payload[0]));
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         error("Failed to discover Host state. Assuming Host as off");
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             error("Failed to get State sensor PDR");
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 = instanceIdDb.next(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                     instanceIdDb.free(mctp_eid, instanceId);
695                     error(
696                         "Failed to encode_get_state_sensor_readings_req, rc = {RC}",
697                         "RC", rc);
698                     pldm::utils::reportError(
699                         "xyz.openbmc_project.bmc.pldm.InternalFailure");
700                     return;
701                 }
702 
703                 auto getStateSensorReadingRespHandler =
704                     [=, this](mctp_eid_t /*eid*/, const pldm_msg* response,
705                               size_t respMsgLen) {
706                     if (response == nullptr || !respMsgLen)
707                     {
708                         error(
709                             "Failed to receive response for getStateSensorReading command");
710                         return;
711                     }
712                     std::array<get_sensor_state_field, 8> stateField{};
713                     uint8_t completionCode = 0;
714                     uint8_t comp_sensor_count = 0;
715 
716                     auto rc = decode_get_state_sensor_readings_resp(
717                         response, respMsgLen, &completionCode,
718                         &comp_sensor_count, stateField.data());
719 
720                     if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
721                     {
722                         error(
723                             "Failed to decode_get_state_sensor_readings_resp, rc = {RC} cc = {CC}",
724                             "RC", rc, "CC",
725                             static_cast<unsigned>(completionCode));
726                         pldm::utils::reportError(
727                             "xyz.openbmc_project.bmc.pldm.InternalFailure");
728                     }
729 
730                     uint8_t eventState;
731                     uint8_t previousEventState;
732 
733                     for (uint8_t sensorOffset = 0;
734                          sensorOffset < comp_sensor_count; sensorOffset++)
735                     {
736                         eventState = stateField[sensorOffset].present_state;
737                         previousEventState =
738                             stateField[sensorOffset].previous_state;
739 
740                         emitStateSensorEventSignal(tid, sensorId, sensorOffset,
741                                                    eventState,
742                                                    previousEventState);
743 
744                         SensorEntry sensorEntry{tid, sensorId};
745 
746                         pldm::pdr::EntityInfo entityInfo{};
747                         pldm::pdr::CompositeSensorStates
748                             compositeSensorStates{};
749 
750                         try
751                         {
752                             std::tie(entityInfo, compositeSensorStates) =
753                                 lookupSensorInfo(sensorEntry);
754                         }
755                         catch (const std::out_of_range& e)
756                         {
757                             try
758                             {
759                                 sensorEntry.terminusID = PLDM_TID_RESERVED;
760                                 std::tie(entityInfo, compositeSensorStates) =
761                                     lookupSensorInfo(sensorEntry);
762                             }
763                             catch (const std::out_of_range& e)
764                             {
765                                 error("No mapping for the events");
766                             }
767                         }
768 
769                         if (sensorOffset > compositeSensorStates.size())
770                         {
771                             error("Error Invalid data, Invalid sensor offset");
772                             return;
773                         }
774 
775                         const auto& possibleStates =
776                             compositeSensorStates[sensorOffset];
777                         if (possibleStates.find(eventState) ==
778                             possibleStates.end())
779                         {
780                             error("Error invalid_data, Invalid event state");
781                             return;
782                         }
783                         const auto& [containerId, entityType,
784                                      entityInstance] = entityInfo;
785                         pldm::responder::events::StateSensorEntry
786                             stateSensorEntry{containerId, entityType,
787                                              entityInstance, sensorOffset};
788                         handleStateSensorEvent(stateSensorEntry, eventState);
789                     }
790                 };
791 
792                 rc = handler->registerRequest(
793                     mctp_eid, instanceId, PLDM_PLATFORM,
794                     PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg),
795                     std::move(getStateSensorReadingRespHandler));
796 
797                 if (rc != PLDM_SUCCESS)
798                 {
799                     error(
800                         "Failed to send request to get State sensor reading on Host");
801                 }
802             }
803         }
804     }
805 }
806 } // namespace pldm
807