1 #include "host_pdr_handler.hpp"
2 
3 #include "libpldm/fru.h"
4 #ifdef OEM_IBM
5 #include "libpldm/fru_oem_ibm.h"
6 #endif
7 
8 #include "custom_dbus.hpp"
9 
10 #include <assert.h>
11 
12 #include <nlohmann/json.hpp>
13 #include <phosphor-logging/lg2.hpp>
14 #include <sdeventplus/clock.hpp>
15 #include <sdeventplus/exception.hpp>
16 #include <sdeventplus/source/io.hpp>
17 #include <sdeventplus/source/time.hpp>
18 
19 #include <fstream>
20 #include <type_traits>
21 
22 PHOSPHOR_LOG2_USING;
23 
24 namespace pldm
25 {
26 using namespace pldm::responder::events;
27 using namespace pldm::utils;
28 using namespace sdbusplus::bus::match::rules;
29 using Json = nlohmann::json;
30 namespace fs = std::filesystem;
31 using namespace pldm::dbus;
32 constexpr auto fruJson = "host_frus.json";
33 const Json emptyJson{};
34 const std::vector<Json> emptyJsonList{};
35 
36 template <typename T>
37 uint16_t extractTerminusHandle(std::vector<uint8_t>& pdr)
38 {
39     T* var = nullptr;
40     if (std::is_same<T, pldm_pdr_fru_record_set>::value)
41     {
42         var = (T*)(pdr.data() + sizeof(pldm_pdr_hdr));
43     }
44     else
45     {
46         var = (T*)(pdr.data());
47     }
48     if (var != nullptr)
49     {
50         return var->terminus_handle;
51     }
52     return TERMINUS_HANDLE;
53 }
54 
55 template <typename T>
56 void updateContainerId(pldm_entity_association_tree* entityTree,
57                        std::vector<uint8_t>& pdr)
58 {
59     T* t = nullptr;
60     if (entityTree == nullptr)
61     {
62         return;
63     }
64     if (std::is_same<T, pldm_pdr_fru_record_set>::value)
65     {
66         t = (T*)(pdr.data() + sizeof(pldm_pdr_hdr));
67     }
68     else
69     {
70         t = (T*)(pdr.data());
71     }
72     if (t == nullptr)
73     {
74         return;
75     }
76 
77     pldm_entity entity{t->entity_type, t->entity_instance, t->container_id};
78     auto node = pldm_entity_association_tree_find_with_locality(entityTree,
79                                                                 &entity, true);
80     if (node)
81     {
82         pldm_entity e = pldm_entity_extract(node);
83         t->container_id = e.entity_container_id;
84     }
85 }
86 
87 HostPDRHandler::HostPDRHandler(
88     int mctp_fd, uint8_t mctp_eid, sdeventplus::Event& event, pldm_pdr* repo,
89     const std::string& eventsJsonsDir, pldm_entity_association_tree* entityTree,
90     pldm_entity_association_tree* bmcEntityTree,
91     pldm::InstanceIdDb& instanceIdDb,
92     pldm::requester::Handler<pldm::requester::Request>* handler) :
93     mctp_fd(mctp_fd),
94     mctp_eid(mctp_eid), event(event), repo(repo),
95     stateSensorHandler(eventsJsonsDir), entityTree(entityTree),
96     bmcEntityTree(bmcEntityTree), instanceIdDb(instanceIdDb), handler(handler)
97 {
98     mergedHostParents = false;
99     fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson);
100     if (fs::exists(hostFruJson))
101     {
102         // Note parent entities for entities sent down by the host firmware.
103         // This will enable a merge of entity associations.
104         try
105         {
106             std::ifstream jsonFile(hostFruJson);
107             auto data = Json::parse(jsonFile, nullptr, false);
108             if (data.is_discarded())
109             {
110                 error("Parsing Host FRU json file failed");
111             }
112             else
113             {
114                 auto entities = data.value("entities", emptyJsonList);
115                 for (auto& entity : entities)
116                 {
117                     EntityType entityType = entity.value("entity_type", 0);
118                     auto parent = entity.value("parent", emptyJson);
119                     pldm_entity p{};
120                     p.entity_type = parent.value("entity_type", 0);
121                     p.entity_instance_num = parent.value("entity_instance", 0);
122                     parents.emplace(entityType, std::move(p));
123                 }
124             }
125         }
126         catch (const std::exception& e)
127         {
128             error("Parsing Host FRU json file failed, exception = {ERR_EXCEP}",
129                   "ERR_EXCEP", e.what());
130         }
131     }
132 
133     hostOffMatch = std::make_unique<sdbusplus::bus::match_t>(
134         pldm::utils::DBusHandler::getBus(),
135         propertiesChanged("/xyz/openbmc_project/state/host0",
136                           "xyz.openbmc_project.State.Host"),
137         [this, repo, entityTree, bmcEntityTree](sdbusplus::message_t& msg) {
138         DbusChangedProps props{};
139         std::string intf;
140         msg.read(intf, props);
141         const auto itr = props.find("CurrentHostState");
142         if (itr != props.end())
143         {
144             PropertyValue value = itr->second;
145             auto propVal = std::get<std::string>(value);
146             if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
147             {
148                 // Delete all the remote terminus information
149                 std::erase_if(tlPDRInfo, [](const auto& item) {
150                     auto const& [key, value] = item;
151                     return key != TERMINUS_HANDLE;
152                 });
153                 pldm_pdr_remove_remote_pdrs(repo);
154                 pldm_entity_association_tree_destroy_root(entityTree);
155                 pldm_entity_association_tree_copy_root(bmcEntityTree,
156                                                        entityTree);
157                 this->sensorMap.clear();
158                 this->responseReceived = false;
159                 this->mergedHostParents = false;
160             }
161         }
162     });
163 }
164 
165 void HostPDRHandler::fetchPDR(PDRRecordHandles&& recordHandles)
166 {
167     pdrRecordHandles.clear();
168     modifiedPDRRecordHandles.clear();
169 
170     if (isHostPdrModified)
171     {
172         modifiedPDRRecordHandles = std::move(recordHandles);
173     }
174     else
175     {
176         pdrRecordHandles = std::move(recordHandles);
177     }
178 
179     // Defer the actual fetch of PDRs from the host (by queuing the call on the
180     // main event loop). That way, we can respond to the platform event msg from
181     // the host firmware.
182     pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>(
183         event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this,
184                          std::placeholders::_1));
185 }
186 
187 void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/)
188 {
189     getHostPDR();
190 }
191 
192 void HostPDRHandler::getHostPDR(uint32_t nextRecordHandle)
193 {
194     pdrFetchEvent.reset();
195 
196     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
197                                     PLDM_GET_PDR_REQ_BYTES);
198     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
199     uint32_t recordHandle{};
200     if (!nextRecordHandle && (!modifiedPDRRecordHandles.empty()) &&
201         isHostPdrModified)
202     {
203         recordHandle = modifiedPDRRecordHandles.front();
204         modifiedPDRRecordHandles.pop_front();
205     }
206     else if (!nextRecordHandle && (!pdrRecordHandles.empty()))
207     {
208         recordHandle = pdrRecordHandles.front();
209         pdrRecordHandles.pop_front();
210     }
211     else
212     {
213         recordHandle = nextRecordHandle;
214     }
215     auto instanceId = instanceIdDb.next(mctp_eid);
216 
217     auto rc = encode_get_pdr_req(instanceId, recordHandle, 0,
218                                  PLDM_GET_FIRSTPART, UINT16_MAX, 0, request,
219                                  PLDM_GET_PDR_REQ_BYTES);
220     if (rc != PLDM_SUCCESS)
221     {
222         instanceIdDb.free(mctp_eid, instanceId);
223         error("Failed to encode_get_pdr_req, rc = {RC}", "RC", rc);
224         return;
225     }
226 
227     rc = handler->registerRequest(
228         mctp_eid, instanceId, PLDM_PLATFORM, PLDM_GET_PDR,
229         std::move(requestMsg),
230         std::move(std::bind_front(&HostPDRHandler::processHostPDRs, this)));
231     if (rc)
232     {
233         error("Failed to send the GetPDR request to Host");
234     }
235 }
236 
237 int HostPDRHandler::handleStateSensorEvent(const StateSensorEntry& entry,
238                                            pdr::EventState state)
239 {
240     auto rc = stateSensorHandler.eventAction(entry, state);
241     if (rc != PLDM_SUCCESS)
242     {
243         error("Failed to fetch and update D-bus property, rc = {RC}", "RC", rc);
244         return rc;
245     }
246     return PLDM_SUCCESS;
247 }
248 
249 void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr)
250 {
251     size_t numEntities{};
252     pldm_entity* entities = nullptr;
253     bool merged = false;
254     auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>(
255         const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr));
256 
257     pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities,
258                                         &entities);
259     if (numEntities > 0)
260     {
261         pldm_entity_node* pNode = nullptr;
262         if (!mergedHostParents)
263         {
264             pNode = pldm_entity_association_tree_find_with_locality(
265                 entityTree, &entities[0], false);
266         }
267         else
268         {
269             pNode = pldm_entity_association_tree_find_with_locality(
270                 entityTree, &entities[0], true);
271         }
272         if (!pNode)
273         {
274             return;
275         }
276 
277         Entities entityAssoc;
278         entityAssoc.push_back(pNode);
279         for (size_t i = 1; i < numEntities; ++i)
280         {
281             auto node = pldm_entity_association_tree_add_entity(
282                 entityTree, &entities[i], entities[i].entity_instance_num,
283                 pNode, entityPdr->association_type, true, true, 0xFFFF);
284             merged = true;
285             entityAssoc.push_back(node);
286         }
287 
288         mergedHostParents = true;
289         if (merged)
290         {
291             entityAssociations.push_back(entityAssoc);
292         }
293     }
294 
295     if (merged)
296     {
297         // Update our PDR repo with the merged entity association PDRs
298         pldm_entity_node* node = nullptr;
299         pldm_find_entity_ref_in_tree(entityTree, entities[0], &node);
300         if (node == nullptr)
301         {
302             error("could not find referrence of the entity in the tree");
303         }
304         else
305         {
306             int rc = pldm_entity_association_pdr_add_from_node_check(
307                 node, repo, &entities, numEntities, true, TERMINUS_HANDLE);
308             if (rc)
309             {
310                 error(
311                     "Failed to add entity association PDR from node: {LIBPLDM_ERROR}",
312                     "LIBPLDM_ERROR", rc);
313             }
314         }
315     }
316     free(entities);
317 }
318 
319 void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes,
320                                                uint8_t eventDataFormat)
321 {
322     assert(eventDataFormat == FORMAT_IS_PDR_HANDLES);
323 
324     // Extract from the PDR repo record handles of PDRs we want the host
325     // to pull up.
326     std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED};
327     std::vector<uint8_t> numsOfChangeEntries(1);
328     std::vector<std::vector<ChangeEntry>> changeEntries(
329         numsOfChangeEntries.size());
330     for (auto pdrType : pdrTypes)
331     {
332         const pldm_pdr_record* record{};
333         do
334         {
335             record = pldm_pdr_find_record_by_type(repo, pdrType, record,
336                                                   nullptr, nullptr);
337             if (record && pldm_pdr_record_is_remote(record))
338             {
339                 changeEntries[0].push_back(
340                     pldm_pdr_get_record_handle(repo, record));
341             }
342         } while (record);
343     }
344     if (changeEntries.empty())
345     {
346         return;
347     }
348     numsOfChangeEntries[0] = changeEntries[0].size();
349 
350     // Encode PLDM platform event msg to indicate a PDR repo change.
351     size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
352                      PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
353                      changeEntries[0].size() * sizeof(uint32_t);
354     std::vector<uint8_t> eventDataVec{};
355     eventDataVec.resize(maxSize);
356     auto eventData =
357         reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
358             eventDataVec.data());
359     size_t actualSize{};
360     auto firstEntry = changeEntries[0].data();
361     auto rc = encode_pldm_pdr_repository_chg_event_data(
362         eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(),
363         &firstEntry, eventData, &actualSize, maxSize);
364     if (rc != PLDM_SUCCESS)
365     {
366         error("Failed to encode_pldm_pdr_repository_chg_event_data, rc = {RC}",
367               "RC", rc);
368         return;
369     }
370     auto instanceId = instanceIdDb.next(mctp_eid);
371     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
372                                     PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
373                                     actualSize);
374     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
375     rc = encode_platform_event_message_req(
376         instanceId, 1, TERMINUS_ID, PLDM_PDR_REPOSITORY_CHG_EVENT,
377         eventDataVec.data(), actualSize, request,
378         actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
379     if (rc != PLDM_SUCCESS)
380     {
381         instanceIdDb.free(mctp_eid, instanceId);
382         error("Failed to encode_platform_event_message_req, rc = {RC}", "RC",
383               rc);
384         return;
385     }
386 
387     auto platformEventMessageResponseHandler =
388         [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
389         if (response == nullptr || !respMsgLen)
390         {
391             error(
392                 "Failed to receive response for the PDR repository changed event");
393             return;
394         }
395 
396         uint8_t completionCode{};
397         uint8_t status{};
398         auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response);
399         auto rc = decode_platform_event_message_resp(responsePtr, respMsgLen,
400                                                      &completionCode, &status);
401         if (rc || completionCode)
402         {
403             error(
404                 "Failed to decode_platform_event_message_resp: {RC}, cc = {CC}",
405                 "RC", rc, "CC", static_cast<unsigned>(completionCode));
406         }
407     };
408 
409     rc = handler->registerRequest(
410         mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE,
411         std::move(requestMsg), std::move(platformEventMessageResponseHandler));
412     if (rc)
413     {
414         error("Failed to send the PDR repository changed event request");
415     }
416 }
417 
418 void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs)
419 {
420     for (const auto& pdr : stateSensorPDRs)
421     {
422         SensorEntry sensorEntry{};
423         const auto& [terminusHandle, sensorID, sensorInfo] =
424             responder::pdr_utils::parseStateSensorPDR(pdr);
425         sensorEntry.sensorID = sensorID;
426         try
427         {
428             sensorEntry.terminusID = std::get<0>(tlPDRInfo.at(terminusHandle));
429         }
430         // If there is no mapping for terminusHandle assign the reserved TID
431         // value of 0xFF to indicate that.
432         catch (const std::out_of_range& e)
433         {
434             sensorEntry.terminusID = PLDM_TID_RESERVED;
435         }
436         sensorMap.emplace(sensorEntry, std::move(sensorInfo));
437     }
438 }
439 
440 void HostPDRHandler::processHostPDRs(mctp_eid_t /*eid*/,
441                                      const pldm_msg* response,
442                                      size_t respMsgLen)
443 {
444     static bool merged = false;
445     static PDRList stateSensorPDRs{};
446     static PDRList fruRecordSetPDRs{};
447     uint32_t nextRecordHandle{};
448     uint8_t tlEid = 0;
449     bool tlValid = true;
450     uint32_t rh = 0;
451     uint16_t terminusHandle = 0;
452     uint16_t pdrTerminusHandle = 0;
453     uint8_t tid = 0;
454 
455     uint8_t completionCode{};
456     uint32_t nextDataTransferHandle{};
457     uint8_t transferFlag{};
458     uint16_t respCount{};
459     uint8_t transferCRC{};
460     if (response == nullptr || !respMsgLen)
461     {
462         error("Failed to receive response for the GetPDR command");
463         return;
464     }
465 
466     auto rc = decode_get_pdr_resp(
467         response, respMsgLen /*- sizeof(pldm_msg_hdr)*/, &completionCode,
468         &nextRecordHandle, &nextDataTransferHandle, &transferFlag, &respCount,
469         nullptr, 0, &transferCRC);
470     std::vector<uint8_t> responsePDRMsg;
471     responsePDRMsg.resize(respMsgLen + sizeof(pldm_msg_hdr));
472     memcpy(responsePDRMsg.data(), response, respMsgLen + sizeof(pldm_msg_hdr));
473     if (rc != PLDM_SUCCESS)
474     {
475         error("Failed to decode_get_pdr_resp, rc = {RC}", "RC", rc);
476         return;
477     }
478     else
479     {
480         std::vector<uint8_t> pdr(respCount, 0);
481         rc = decode_get_pdr_resp(response, respMsgLen, &completionCode,
482                                  &nextRecordHandle, &nextDataTransferHandle,
483                                  &transferFlag, &respCount, pdr.data(),
484                                  respCount, &transferCRC);
485         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
486         {
487             error("Failed to decode_get_pdr_resp: rc = {RC}, cc = {CC}", "RC",
488                   rc, "CC", static_cast<unsigned>(completionCode));
489             return;
490         }
491         else
492         {
493             // when nextRecordHandle is 0, we need the recordHandle of the last
494             // PDR and not 0-1.
495             if (!nextRecordHandle)
496             {
497                 rh = nextRecordHandle;
498             }
499             else
500             {
501                 rh = nextRecordHandle - 1;
502             }
503 
504             auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
505             if (!rh)
506             {
507                 rh = pdrHdr->record_handle;
508             }
509 
510             if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
511             {
512                 this->mergeEntityAssociations(pdr);
513                 merged = true;
514             }
515             else
516             {
517                 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR)
518                 {
519                     pdrTerminusHandle =
520                         extractTerminusHandle<pldm_terminus_locator_pdr>(pdr);
521                     auto tlpdr =
522                         reinterpret_cast<const pldm_terminus_locator_pdr*>(
523                             pdr.data());
524 
525                     terminusHandle = tlpdr->terminus_handle;
526                     tid = tlpdr->tid;
527                     auto terminus_locator_type = tlpdr->terminus_locator_type;
528                     if (terminus_locator_type ==
529                         PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID)
530                     {
531                         auto locatorValue = reinterpret_cast<
532                             const pldm_terminus_locator_type_mctp_eid*>(
533                             tlpdr->terminus_locator_value);
534                         tlEid = static_cast<uint8_t>(locatorValue->eid);
535                     }
536                     if (tlpdr->validity == 0)
537                     {
538                         tlValid = false;
539                     }
540                     for (const auto& terminusMap : tlPDRInfo)
541                     {
542                         if ((terminusHandle == (terminusMap.first)) &&
543                             (get<1>(terminusMap.second) == tlEid) &&
544                             (get<2>(terminusMap.second) == tlpdr->validity))
545                         {
546                             // TL PDR already present with same validity don't
547                             // add the PDR to the repo just return
548                             return;
549                         }
550                     }
551                     tlPDRInfo.insert_or_assign(
552                         tlpdr->terminus_handle,
553                         std::make_tuple(tlpdr->tid, tlEid, tlpdr->validity));
554                 }
555                 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
556                 {
557                     pdrTerminusHandle =
558                         extractTerminusHandle<pldm_state_sensor_pdr>(pdr);
559                     updateContainerId<pldm_state_sensor_pdr>(entityTree, pdr);
560                     stateSensorPDRs.emplace_back(pdr);
561                 }
562                 else if (pdrHdr->type == PLDM_PDR_FRU_RECORD_SET)
563                 {
564                     pdrTerminusHandle =
565                         extractTerminusHandle<pldm_pdr_fru_record_set>(pdr);
566                     updateContainerId<pldm_pdr_fru_record_set>(entityTree, pdr);
567                     fruRecordSetPDRs.emplace_back(pdr);
568                 }
569                 else if (pdrHdr->type == PLDM_STATE_EFFECTER_PDR)
570                 {
571                     pdrTerminusHandle =
572                         extractTerminusHandle<pldm_state_effecter_pdr>(pdr);
573                     updateContainerId<pldm_state_effecter_pdr>(entityTree, pdr);
574                 }
575                 else if (pdrHdr->type == PLDM_NUMERIC_EFFECTER_PDR)
576                 {
577                     pdrTerminusHandle =
578                         extractTerminusHandle<pldm_numeric_effecter_value_pdr>(
579                             pdr);
580                     updateContainerId<pldm_numeric_effecter_value_pdr>(
581                         entityTree, pdr);
582                 }
583                 // if the TLPDR is invalid update the repo accordingly
584                 if (!tlValid)
585                 {
586                     pldm_pdr_update_TL_pdr(repo, terminusHandle, tid, tlEid,
587                                            tlValid);
588                 }
589                 else
590                 {
591                     rc = pldm_pdr_add_check(repo, pdr.data(), respCount, true,
592                                             pdrTerminusHandle, &rh);
593                     if (rc)
594                     {
595                         // pldm_pdr_add() assert()ed on failure to add a PDR.
596                         throw std::runtime_error("Failed to add PDR");
597                     }
598                 }
599             }
600         }
601     }
602     if (!nextRecordHandle)
603     {
604         updateEntityAssociation(entityAssociations, entityTree, objPathMap);
605 
606         /*received last record*/
607         this->parseStateSensorPDRs(stateSensorPDRs);
608         this->createDbusObjects(fruRecordSetPDRs);
609         if (isHostUp())
610         {
611             this->setHostSensorState(stateSensorPDRs);
612         }
613         stateSensorPDRs.clear();
614         fruRecordSetPDRs.clear();
615         entityAssociations.clear();
616 
617         if (merged)
618         {
619             merged = false;
620             deferredPDRRepoChgEvent =
621                 std::make_unique<sdeventplus::source::Defer>(
622                     event,
623                     std::bind(
624                         std::mem_fn((&HostPDRHandler::_processPDRRepoChgEvent)),
625                         this, std::placeholders::_1));
626         }
627     }
628     else
629     {
630         if (modifiedPDRRecordHandles.empty() && isHostPdrModified)
631         {
632             isHostPdrModified = false;
633         }
634         else
635         {
636             deferredFetchPDREvent =
637                 std::make_unique<sdeventplus::source::Defer>(
638                     event,
639                     std::bind(
640                         std::mem_fn((&HostPDRHandler::_processFetchPDREvent)),
641                         this, nextRecordHandle, std::placeholders::_1));
642         }
643     }
644 }
645 
646 void HostPDRHandler::_processPDRRepoChgEvent(
647     sdeventplus::source::EventBase& /*source */)
648 {
649     deferredPDRRepoChgEvent.reset();
650     this->sendPDRRepositoryChgEvent(
651         std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
652         FORMAT_IS_PDR_HANDLES);
653 }
654 
655 void HostPDRHandler::_processFetchPDREvent(
656     uint32_t nextRecordHandle, sdeventplus::source::EventBase& /*source */)
657 {
658     deferredFetchPDREvent.reset();
659     if (!this->pdrRecordHandles.empty())
660     {
661         nextRecordHandle = this->pdrRecordHandles.front();
662         this->pdrRecordHandles.pop_front();
663     }
664     if (isHostPdrModified && (!this->modifiedPDRRecordHandles.empty()))
665     {
666         nextRecordHandle = this->modifiedPDRRecordHandles.front();
667         this->modifiedPDRRecordHandles.pop_front();
668     }
669     this->getHostPDR(nextRecordHandle);
670 }
671 
672 void HostPDRHandler::setHostFirmwareCondition()
673 {
674     responseReceived = false;
675     auto instanceId = instanceIdDb.next(mctp_eid);
676     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
677                                     PLDM_GET_VERSION_REQ_BYTES);
678     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
679     auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART,
680                                      PLDM_BASE, request);
681     if (rc != PLDM_SUCCESS)
682     {
683         error("GetPLDMVersion encode failure. PLDM error code = {RC}", "RC",
684               lg2::hex, rc);
685         instanceIdDb.free(mctp_eid, instanceId);
686         return;
687     }
688 
689     auto getPLDMVersionHandler = [this](mctp_eid_t /*eid*/,
690                                         const pldm_msg* response,
691                                         size_t respMsgLen) {
692         if (response == nullptr || !respMsgLen)
693         {
694             error(
695                 "Failed to receive response for getPLDMVersion command, Host seems to be off");
696             return;
697         }
698         info("Getting the response. PLDM RC = {RC}", "RC", lg2::hex,
699              static_cast<uint16_t>(response->payload[0]));
700         this->responseReceived = true;
701         getHostPDR();
702     };
703     rc = handler->registerRequest(mctp_eid, instanceId, PLDM_BASE,
704                                   PLDM_GET_PLDM_VERSION, std::move(requestMsg),
705                                   std::move(getPLDMVersionHandler));
706     if (rc)
707     {
708         error("Failed to discover Host state. Assuming Host as off");
709     }
710 }
711 
712 bool HostPDRHandler::isHostUp()
713 {
714     return responseReceived;
715 }
716 
717 void HostPDRHandler::setHostSensorState(const PDRList& stateSensorPDRs)
718 {
719     for (const auto& stateSensorPDR : stateSensorPDRs)
720     {
721         auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>(
722             stateSensorPDR.data());
723 
724         if (!pdr)
725         {
726             error("Failed to get State sensor PDR");
727             pldm::utils::reportError(
728                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
729             return;
730         }
731 
732         uint16_t sensorId = pdr->sensor_id;
733 
734         for (const auto& [terminusHandle, terminusInfo] : tlPDRInfo)
735         {
736             if (terminusHandle == pdr->terminus_handle)
737             {
738                 if (std::get<2>(terminusInfo) == PLDM_TL_PDR_VALID)
739                 {
740                     mctp_eid = std::get<1>(terminusInfo);
741                 }
742 
743                 bitfield8_t sensorRearm;
744                 sensorRearm.byte = 0;
745                 uint8_t tid = std::get<0>(terminusInfo);
746 
747                 auto instanceId = instanceIdDb.next(mctp_eid);
748                 std::vector<uint8_t> requestMsg(
749                     sizeof(pldm_msg_hdr) +
750                     PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES);
751                 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
752                 auto rc = encode_get_state_sensor_readings_req(
753                     instanceId, sensorId, sensorRearm, 0, request);
754 
755                 if (rc != PLDM_SUCCESS)
756                 {
757                     instanceIdDb.free(mctp_eid, instanceId);
758                     error(
759                         "Failed to encode_get_state_sensor_readings_req, rc = {RC}",
760                         "RC", rc);
761                     pldm::utils::reportError(
762                         "xyz.openbmc_project.bmc.pldm.InternalFailure");
763                     return;
764                 }
765 
766                 auto getStateSensorReadingRespHandler =
767                     [=, this](mctp_eid_t /*eid*/, const pldm_msg* response,
768                               size_t respMsgLen) {
769                     if (response == nullptr || !respMsgLen)
770                     {
771                         error(
772                             "Failed to receive response for getStateSensorReading command");
773                         return;
774                     }
775                     std::array<get_sensor_state_field, 8> stateField{};
776                     uint8_t completionCode = 0;
777                     uint8_t comp_sensor_count = 0;
778 
779                     auto rc = decode_get_state_sensor_readings_resp(
780                         response, respMsgLen, &completionCode,
781                         &comp_sensor_count, stateField.data());
782 
783                     if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
784                     {
785                         error(
786                             "Failed to decode_get_state_sensor_readings_resp, rc = {RC} cc = {CC}",
787                             "RC", rc, "CC",
788                             static_cast<unsigned>(completionCode));
789                         pldm::utils::reportError(
790                             "xyz.openbmc_project.bmc.pldm.InternalFailure");
791                     }
792 
793                     uint8_t eventState;
794                     uint8_t previousEventState;
795 
796                     for (uint8_t sensorOffset = 0;
797                          sensorOffset < comp_sensor_count; sensorOffset++)
798                     {
799                         eventState = stateField[sensorOffset].present_state;
800                         previousEventState =
801                             stateField[sensorOffset].previous_state;
802 
803                         emitStateSensorEventSignal(tid, sensorId, sensorOffset,
804                                                    eventState,
805                                                    previousEventState);
806 
807                         SensorEntry sensorEntry{tid, sensorId};
808 
809                         pldm::pdr::EntityInfo entityInfo{};
810                         pldm::pdr::CompositeSensorStates
811                             compositeSensorStates{};
812 
813                         try
814                         {
815                             std::tie(entityInfo, compositeSensorStates) =
816                                 lookupSensorInfo(sensorEntry);
817                         }
818                         catch (const std::out_of_range& e)
819                         {
820                             try
821                             {
822                                 sensorEntry.terminusID = PLDM_TID_RESERVED;
823                                 std::tie(entityInfo, compositeSensorStates) =
824                                     lookupSensorInfo(sensorEntry);
825                             }
826                             catch (const std::out_of_range& e)
827                             {
828                                 error("No mapping for the events");
829                             }
830                         }
831 
832                         if (sensorOffset > compositeSensorStates.size())
833                         {
834                             error("Error Invalid data, Invalid sensor offset");
835                             return;
836                         }
837 
838                         const auto& possibleStates =
839                             compositeSensorStates[sensorOffset];
840                         if (possibleStates.find(eventState) ==
841                             possibleStates.end())
842                         {
843                             error("Error invalid_data, Invalid event state");
844                             return;
845                         }
846                         const auto& [containerId, entityType,
847                                      entityInstance] = entityInfo;
848                         pldm::responder::events::StateSensorEntry
849                             stateSensorEntry{containerId, entityType,
850                                              entityInstance, sensorOffset};
851                         handleStateSensorEvent(stateSensorEntry, eventState);
852                     }
853                 };
854 
855                 rc = handler->registerRequest(
856                     mctp_eid, instanceId, PLDM_PLATFORM,
857                     PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg),
858                     std::move(getStateSensorReadingRespHandler));
859 
860                 if (rc != PLDM_SUCCESS)
861                 {
862                     error(
863                         "Failed to send request to get State sensor reading on Host");
864                 }
865             }
866         }
867     }
868 }
869 
870 void HostPDRHandler::getFRURecordTableMetadataByRemote(
871     const PDRList& fruRecordSetPDRs)
872 {
873     auto instanceId = instanceIdDb.next(mctp_eid);
874     std::vector<uint8_t> requestMsg(
875         sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES);
876 
877     // GetFruRecordTableMetadata
878     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
879     auto rc = encode_get_fru_record_table_metadata_req(
880         instanceId, request, requestMsg.size() - sizeof(pldm_msg_hdr));
881     if (rc != PLDM_SUCCESS)
882     {
883         instanceIdDb.free(mctp_eid, instanceId);
884         lg2::error(
885             "Failed to encode_get_fru_record_table_metadata_req, rc = {RC}",
886             "RC", lg2::hex, rc);
887         return;
888     }
889 
890     auto getFruRecordTableMetadataResponseHandler =
891         [this, fruRecordSetPDRs](mctp_eid_t /*eid*/, const pldm_msg* response,
892                                  size_t respMsgLen) {
893         if (response == nullptr || !respMsgLen)
894         {
895             lg2::error(
896                 "Failed to receive response for the Get FRU Record Table Metadata");
897             return;
898         }
899 
900         uint8_t cc = 0;
901         uint8_t fru_data_major_version, fru_data_minor_version;
902         uint32_t fru_table_maximum_size, fru_table_length;
903         uint16_t total_record_set_identifiers;
904         uint16_t total;
905         uint32_t checksum;
906 
907         auto rc = decode_get_fru_record_table_metadata_resp(
908             response, respMsgLen, &cc, &fru_data_major_version,
909             &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length,
910             &total_record_set_identifiers, &total, &checksum);
911 
912         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
913         {
914             lg2::error(
915                 "Faile to decode get fru record table metadata resp, Message Error: {RC}, cc: {CC}",
916                 "RC", lg2::hex, rc, "CC", cc);
917             return;
918         }
919 
920         // pass total to getFRURecordTableByRemote
921         this->getFRURecordTableByRemote(fruRecordSetPDRs, total);
922     };
923 
924     rc = handler->registerRequest(
925         mctp_eid, instanceId, PLDM_FRU, PLDM_GET_FRU_RECORD_TABLE_METADATA,
926         std::move(requestMsg),
927         std::move(getFruRecordTableMetadataResponseHandler));
928     if (rc != PLDM_SUCCESS)
929     {
930         lg2::error("Failed to send the the Set State Effecter States request");
931     }
932 
933     return;
934 }
935 
936 void HostPDRHandler::getFRURecordTableByRemote(const PDRList& fruRecordSetPDRs,
937                                                uint16_t totalTableRecords)
938 {
939     fruRecordData.clear();
940 
941     if (!totalTableRecords)
942     {
943         lg2::error("Failed to get fru record table");
944         return;
945     }
946 
947     auto instanceId = instanceIdDb.next(mctp_eid);
948     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
949                                     PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES);
950 
951     // send the getFruRecordTable command
952     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
953     auto rc = encode_get_fru_record_table_req(
954         instanceId, 0, PLDM_GET_FIRSTPART, request,
955         requestMsg.size() - sizeof(pldm_msg_hdr));
956     if (rc != PLDM_SUCCESS)
957     {
958         instanceIdDb.free(mctp_eid, instanceId);
959         lg2::error("Failed to encode_get_fru_record_table_req, rc = {RC}", "RC",
960                    lg2::hex, rc);
961         return;
962     }
963 
964     auto getFruRecordTableResponseHandler =
965         [totalTableRecords, this, fruRecordSetPDRs](
966             mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
967         if (response == nullptr || !respMsgLen)
968         {
969             lg2::error(
970                 "Failed to receive response for the Get FRU Record Table");
971             return;
972         }
973 
974         uint8_t cc = 0;
975         uint32_t next_data_transfer_handle = 0;
976         uint8_t transfer_flag = 0;
977         size_t fru_record_table_length = 0;
978         std::vector<uint8_t> fru_record_table_data(respMsgLen -
979                                                    sizeof(pldm_msg_hdr));
980         auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response);
981         auto rc = decode_get_fru_record_table_resp(
982             responsePtr, respMsgLen - sizeof(pldm_msg_hdr), &cc,
983             &next_data_transfer_handle, &transfer_flag,
984             fru_record_table_data.data(), &fru_record_table_length);
985 
986         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
987         {
988             lg2::error(
989                 "Failed to decode get fru record table resp, Message Error: {RC}, cc: {CC}",
990                 "RC", lg2::hex, rc, "CC", cc);
991             return;
992         }
993 
994         fruRecordData = responder::pdr_utils::parseFruRecordTable(
995             fru_record_table_data.data(), fru_record_table_length);
996 
997         if (totalTableRecords != fruRecordData.size())
998         {
999             fruRecordData.clear();
1000 
1001             lg2::error("failed to parse fru recrod data format.");
1002             return;
1003         }
1004 
1005         this->setFRUDataOnDBus(fruRecordSetPDRs, fruRecordData);
1006     };
1007 
1008     rc = handler->registerRequest(
1009         mctp_eid, instanceId, PLDM_FRU, PLDM_GET_FRU_RECORD_TABLE,
1010         std::move(requestMsg), std::move(getFruRecordTableResponseHandler));
1011     if (rc != PLDM_SUCCESS)
1012     {
1013         lg2::error("Failed to send the the Set State Effecter States request");
1014     }
1015 }
1016 
1017 std::optional<uint16_t> HostPDRHandler::getRSI(const PDRList& fruRecordSetPDRs,
1018                                                const pldm_entity& entity)
1019 {
1020     for (const auto& pdr : fruRecordSetPDRs)
1021     {
1022         auto fruPdr = reinterpret_cast<const pldm_pdr_fru_record_set*>(
1023             const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr));
1024 
1025         if (fruPdr->entity_type == entity.entity_type &&
1026             fruPdr->entity_instance == entity.entity_instance_num &&
1027             fruPdr->container_id == entity.entity_container_id)
1028         {
1029             return fruPdr->fru_rsi;
1030         }
1031     }
1032 
1033     return std::nullopt;
1034 }
1035 
1036 void HostPDRHandler::setFRUDataOnDBus(
1037     [[maybe_unused]] const PDRList& fruRecordSetPDRs,
1038     [[maybe_unused]] const std::vector<
1039         responder::pdr_utils::FruRecordDataFormat>& fruRecordData)
1040 {
1041 #ifdef OEM_IBM
1042     for (const auto& entity : objPathMap)
1043     {
1044         pldm_entity node = pldm_entity_extract(entity.second);
1045         auto fruRSI = getRSI(fruRecordSetPDRs, node);
1046 
1047         for (const auto& data : fruRecordData)
1048         {
1049             if (!fruRSI || *fruRSI != data.fruRSI)
1050             {
1051                 continue;
1052             }
1053 
1054             if (data.fruRecType == PLDM_FRU_RECORD_TYPE_OEM)
1055             {
1056                 for (const auto& tlv : data.fruTLV)
1057                 {
1058                     if (tlv.fruFieldType ==
1059                         PLDM_OEM_FRU_FIELD_TYPE_LOCATION_CODE)
1060                     {
1061                         CustomDBus::getCustomDBus().setLocationCode(
1062                             entity.first,
1063                             std::string(reinterpret_cast<const char*>(
1064                                             tlv.fruFieldValue.data()),
1065                                         tlv.fruFieldLen));
1066                     }
1067                 }
1068             }
1069         }
1070     }
1071 #endif
1072 }
1073 void HostPDRHandler::createDbusObjects(const PDRList& fruRecordSetPDRs)
1074 {
1075     // TODO: Creating and Refreshing dbus hosted by remote PLDM entity Fru PDRs
1076 
1077     getFRURecordTableMetadataByRemote(fruRecordSetPDRs);
1078 }
1079 
1080 } // namespace pldm
1081