1 #include "platform.hpp"
2 
3 #include "common/types.hpp"
4 #include "common/utils.hpp"
5 #include "event_parser.hpp"
6 #include "pdr.hpp"
7 #include "pdr_numeric_effecter.hpp"
8 #include "pdr_state_effecter.hpp"
9 #include "pdr_state_sensor.hpp"
10 #include "pdr_utils.hpp"
11 #include "platform_numeric_effecter.hpp"
12 #include "platform_state_effecter.hpp"
13 #include "platform_state_sensor.hpp"
14 
15 #include <config.h>
16 #include <libpldm/entity.h>
17 #include <libpldm/state_set.h>
18 
19 #include <phosphor-logging/lg2.hpp>
20 
21 PHOSPHOR_LOG2_USING;
22 
23 using namespace pldm::utils;
24 using namespace pldm::responder::pdr;
25 using namespace pldm::responder::pdr_utils;
26 
27 namespace pldm
28 {
29 namespace responder
30 {
31 namespace platform
32 {
33 using InternalFailure =
34     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
35 
36 static const Json empty{};
37 
38 void Handler::addDbusObjMaps(
39     uint16_t id,
40     std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj,
41     TypeId typeId)
42 {
43     if (typeId == TypeId::PLDM_SENSOR_ID)
44     {
45         sensorDbusObjMaps.emplace(id, dbusObj);
46     }
47     else
48     {
49         effecterDbusObjMaps.emplace(id, dbusObj);
50     }
51 }
52 
53 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>&
54     Handler::getDbusObjMaps(uint16_t id, TypeId typeId) const
55 {
56     if (typeId == TypeId::PLDM_SENSOR_ID)
57     {
58         return sensorDbusObjMaps.at(id);
59     }
60     else
61     {
62         return effecterDbusObjMaps.at(id);
63     }
64 }
65 
66 void Handler::generate(const pldm::utils::DBusHandler& dBusIntf,
67                        const std::string& dir, Repo& repo)
68 {
69     if (!fs::exists(dir))
70     {
71         return;
72     }
73 
74     // A map of PDR type to a lambda that handles creation of that PDR type.
75     // The lambda essentially would parse the platform specific PDR JSONs to
76     // generate the PDR structures. This function iterates through the map to
77     // invoke all lambdas, so that all PDR types can be created.
78 
79     const std::map<Type, generatePDR>
80         generateHandlers = {{PLDM_STATE_EFFECTER_PDR,
81                              [this](const DBusHandler& dBusIntf,
82                                     const auto& json, RepoInterface& repo) {
83         pdr_state_effecter::generateStateEffecterPDR<pldm::utils::DBusHandler,
84                                                      Handler>(dBusIntf, json,
85                                                               *this, repo);
86                              }},
87                             {PLDM_NUMERIC_EFFECTER_PDR,
88                              [this](const DBusHandler& dBusIntf,
89                                     const auto& json, RepoInterface& repo) {
90         pdr_numeric_effecter::generateNumericEffecterPDR<
91             pldm::utils::DBusHandler, Handler>(dBusIntf, json, *this, repo);
92                              }},
93         {PLDM_STATE_SENSOR_PDR, [this](const DBusHandler& dBusIntf,
94                                        const auto& json, RepoInterface& repo) {
95              pdr_state_sensor::generateStateSensorPDR<pldm::utils::DBusHandler,
96                                                       Handler>(dBusIntf, json,
97                                                                *this, repo);
98          }}};
99 
100     Type pdrType{};
101     for (const auto& dirEntry : fs::directory_iterator(dir))
102     {
103         try
104         {
105             auto json = readJson(dirEntry.path().string());
106             if (!json.empty())
107             {
108                 auto effecterPDRs = json.value("effecterPDRs", empty);
109                 for (const auto& effecter : effecterPDRs)
110                 {
111                     pdrType = effecter.value("pdrType", 0);
112                     generateHandlers.at(pdrType)(dBusIntf, effecter, repo);
113                 }
114 
115                 auto sensorPDRs = json.value("sensorPDRs", empty);
116                 for (const auto& sensor : sensorPDRs)
117                 {
118                     pdrType = sensor.value("pdrType", 0);
119                     generateHandlers.at(pdrType)(dBusIntf, sensor, repo);
120                 }
121             }
122         }
123         catch (const InternalFailure& e)
124         {
125             error(
126                 "PDR config directory does not exist or empty, TYPE= {PDR_TYPE} PATH={DIR_PATH} ERROR={ERR_EXCEP}",
127                 "PDR_TYPE", pdrType, "DIR_PATH", dirEntry.path().string(),
128                 "ERR_EXCEP", e.what());
129         }
130         catch (const Json::exception& e)
131         {
132             error(
133                 "Failed parsing PDR JSON file, TYPE={PDR_TYPE} ERROR={ERR_EXCEP}",
134                 "PDR_TYPE", pdrType, "ERR_EXCEP", e.what());
135             pldm::utils::reportError(
136                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
137         }
138         catch (const std::exception& e)
139         {
140             error(
141                 "Failed parsing PDR JSON file, TYPE= {PDR_TYPE} ERROR={ERR_EXCEP}",
142                 "PDR_TYPE", pdrType, "ERR_EXCEP", e.what());
143             pldm::utils::reportError(
144                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
145         }
146     }
147 }
148 
149 Response Handler::getPDR(const pldm_msg* request, size_t payloadLength)
150 {
151     if (hostPDRHandler)
152     {
153         if (hostPDRHandler->isHostUp() && oemPlatformHandler != nullptr)
154         {
155             auto rc = oemPlatformHandler->checkBMCState();
156             if (rc != PLDM_SUCCESS)
157             {
158                 return ccOnlyResponse(request, PLDM_ERROR_NOT_READY);
159             }
160         }
161     }
162 
163     // Build FRU table if not built, since entity association PDR's
164     // are built when the FRU table is constructed.
165     if (fruHandler)
166     {
167         fruHandler->buildFRUTable();
168     }
169 
170     if (!pdrCreated)
171     {
172         generateTerminusLocatorPDR(pdrRepo);
173         generate(*dBusIntf, pdrJsonsDir, pdrRepo);
174         if (oemPlatformHandler != nullptr)
175         {
176             oemPlatformHandler->buildOEMPDR(pdrRepo);
177         }
178 
179         pdrCreated = true;
180 
181         if (dbusToPLDMEventHandler)
182         {
183             deferredGetPDREvent = std::make_unique<sdeventplus::source::Defer>(
184                 event,
185                 std::bind(std::mem_fn(&pldm::responder::platform::Handler::
186                                           _processPostGetPDRActions),
187                           this, std::placeholders::_1));
188         }
189     }
190 
191     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0);
192 
193     if (payloadLength != PLDM_GET_PDR_REQ_BYTES)
194     {
195         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
196     }
197 
198     uint32_t recordHandle{};
199     uint32_t dataTransferHandle{};
200     uint8_t transferOpFlag{};
201     uint16_t reqSizeBytes{};
202     uint16_t recordChangeNum{};
203 
204     auto rc = decode_get_pdr_req(request, payloadLength, &recordHandle,
205                                  &dataTransferHandle, &transferOpFlag,
206                                  &reqSizeBytes, &recordChangeNum);
207     if (rc != PLDM_SUCCESS)
208     {
209         return CmdHandler::ccOnlyResponse(request, rc);
210     }
211 
212     uint16_t respSizeBytes{};
213     uint8_t* recordData = nullptr;
214     try
215     {
216         pdr_utils::PdrEntry e;
217         auto record = pdr::getRecordByHandle(pdrRepo, recordHandle, e);
218         if (record == NULL)
219         {
220             return CmdHandler::ccOnlyResponse(
221                 request, PLDM_PLATFORM_INVALID_RECORD_HANDLE);
222         }
223 
224         if (reqSizeBytes)
225         {
226             respSizeBytes = e.size;
227             if (respSizeBytes > reqSizeBytes)
228             {
229                 respSizeBytes = reqSizeBytes;
230             }
231             recordData = e.data;
232         }
233         response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES +
234                             respSizeBytes,
235                         0);
236         auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
237         rc = encode_get_pdr_resp(
238             request->hdr.instance_id, PLDM_SUCCESS, e.handle.nextRecordHandle,
239             0, PLDM_START_AND_END, respSizeBytes, recordData, 0, responsePtr);
240         if (rc != PLDM_SUCCESS)
241         {
242             return ccOnlyResponse(request, rc);
243         }
244     }
245     catch (const std::exception& e)
246     {
247         error("Error accessing PDR, HANDLE={REC_HANDLE} ERROR={ERR_EXCEP}",
248               "REC_HANDLE", recordHandle, "ERR_EXCEP", e.what());
249         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR);
250     }
251     return response;
252 }
253 
254 Response Handler::setStateEffecterStates(const pldm_msg* request,
255                                          size_t payloadLength)
256 {
257     Response response(
258         sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0);
259     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
260     uint16_t effecterId;
261     uint8_t compEffecterCnt;
262     constexpr auto maxCompositeEffecterCnt = 8;
263     std::vector<set_effecter_state_field> stateField(maxCompositeEffecterCnt,
264                                                      {0, 0});
265 
266     if ((payloadLength > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) ||
267         (payloadLength < sizeof(effecterId) + sizeof(compEffecterCnt) +
268                              sizeof(set_effecter_state_field)))
269     {
270         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
271     }
272 
273     int rc = decode_set_state_effecter_states_req(request, payloadLength,
274                                                   &effecterId, &compEffecterCnt,
275                                                   stateField.data());
276 
277     if (rc != PLDM_SUCCESS)
278     {
279         return CmdHandler::ccOnlyResponse(request, rc);
280     }
281 
282     stateField.resize(compEffecterCnt);
283     const pldm::utils::DBusHandler dBusIntf;
284     uint16_t entityType{};
285     uint16_t entityInstance{};
286     uint16_t stateSetId{};
287 
288     if (isOemStateEffecter(*this, effecterId, compEffecterCnt, entityType,
289                            entityInstance, stateSetId) &&
290         oemPlatformHandler != nullptr &&
291         !effecterDbusObjMaps.contains(effecterId))
292     {
293         rc = oemPlatformHandler->oemSetStateEffecterStatesHandler(
294             entityType, entityInstance, stateSetId, compEffecterCnt, stateField,
295             effecterId);
296     }
297     else
298     {
299         rc = platform_state_effecter::setStateEffecterStatesHandler<
300             pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId,
301                                                stateField);
302     }
303     if (rc != PLDM_SUCCESS)
304     {
305         return CmdHandler::ccOnlyResponse(request, rc);
306     }
307 
308     rc = encode_set_state_effecter_states_resp(request->hdr.instance_id, rc,
309                                                responsePtr);
310     if (rc != PLDM_SUCCESS)
311     {
312         return ccOnlyResponse(request, rc);
313     }
314 
315     return response;
316 }
317 
318 Response Handler::platformEventMessage(const pldm_msg* request,
319                                        size_t payloadLength)
320 {
321     uint8_t formatVersion{};
322     uint8_t tid{};
323     uint8_t eventClass{};
324     size_t offset{};
325 
326     auto rc = decode_platform_event_message_req(
327         request, payloadLength, &formatVersion, &tid, &eventClass, &offset);
328     if (rc != PLDM_SUCCESS)
329     {
330         return CmdHandler::ccOnlyResponse(request, rc);
331     }
332 
333     if (eventClass == PLDM_HEARTBEAT_TIMER_ELAPSED_EVENT)
334     {
335         rc = PLDM_SUCCESS;
336         if (oemPlatformHandler)
337         {
338             oemPlatformHandler->resetWatchDogTimer();
339         }
340     }
341     else
342     {
343         try
344         {
345             const auto& handlers = eventHandlers.at(eventClass);
346             for (const auto& handler : handlers)
347             {
348                 auto rc = handler(request, payloadLength, formatVersion, tid,
349                                   offset);
350                 if (rc != PLDM_SUCCESS)
351                 {
352                     return CmdHandler::ccOnlyResponse(request, rc);
353                 }
354             }
355         }
356         catch (const std::out_of_range& e)
357         {
358             return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA);
359         }
360     }
361     Response response(
362         sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES, 0);
363     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
364 
365     rc = encode_platform_event_message_resp(request->hdr.instance_id, rc,
366                                             PLDM_EVENT_NO_LOGGING, responsePtr);
367     if (rc != PLDM_SUCCESS)
368     {
369         return ccOnlyResponse(request, rc);
370     }
371 
372     return response;
373 }
374 
375 int Handler::sensorEvent(const pldm_msg* request, size_t payloadLength,
376                          uint8_t /*formatVersion*/, uint8_t tid,
377                          size_t eventDataOffset)
378 {
379     uint16_t sensorId{};
380     uint8_t eventClass{};
381     size_t eventClassDataOffset{};
382     auto eventData = reinterpret_cast<const uint8_t*>(request->payload) +
383                      eventDataOffset;
384     auto eventDataSize = payloadLength - eventDataOffset;
385 
386     auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId,
387                                        &eventClass, &eventClassDataOffset);
388     if (rc != PLDM_SUCCESS)
389     {
390         return rc;
391     }
392 
393     auto eventClassData = reinterpret_cast<const uint8_t*>(request->payload) +
394                           eventDataOffset + eventClassDataOffset;
395     auto eventClassDataSize = payloadLength - eventDataOffset -
396                               eventClassDataOffset;
397 
398     if (eventClass == PLDM_STATE_SENSOR_STATE)
399     {
400         uint8_t sensorOffset{};
401         uint8_t eventState{};
402         uint8_t previousEventState{};
403 
404         rc = decode_state_sensor_data(eventClassData, eventClassDataSize,
405                                       &sensorOffset, &eventState,
406                                       &previousEventState);
407         if (rc != PLDM_SUCCESS)
408         {
409             return PLDM_ERROR;
410         }
411 
412         // Emitting state sensor event signal
413         emitStateSensorEventSignal(tid, sensorId, sensorOffset, eventState,
414                                    previousEventState);
415 
416         // If there are no HOST PDR's, there is no further action
417         if (hostPDRHandler == NULL)
418         {
419             return PLDM_SUCCESS;
420         }
421 
422         // Handle PLDM events for which PDR is available
423         SensorEntry sensorEntry{tid, sensorId};
424 
425         pldm::pdr::EntityInfo entityInfo{};
426         pldm::pdr::CompositeSensorStates compositeSensorStates{};
427 
428         try
429         {
430             std::tie(entityInfo, compositeSensorStates) =
431                 hostPDRHandler->lookupSensorInfo(sensorEntry);
432         }
433         catch (const std::out_of_range& e)
434         {
435             // If there is no mapping for tid, sensorId combination, try
436             // PLDM_TID_RESERVED, sensorId for terminus that is yet to
437             // implement TL PDR.
438             try
439             {
440                 sensorEntry.terminusID = PLDM_TID_RESERVED;
441                 std::tie(entityInfo, compositeSensorStates) =
442                     hostPDRHandler->lookupSensorInfo(sensorEntry);
443             }
444             // If there is no mapping for events return PLDM_SUCCESS
445             catch (const std::out_of_range& e)
446             {
447                 return PLDM_SUCCESS;
448             }
449         }
450 
451         if (sensorOffset >= compositeSensorStates.size())
452         {
453             return PLDM_ERROR_INVALID_DATA;
454         }
455 
456         const auto& possibleStates = compositeSensorStates[sensorOffset];
457         if (possibleStates.find(eventState) == possibleStates.end())
458         {
459             return PLDM_ERROR_INVALID_DATA;
460         }
461 
462         const auto& [containerId, entityType, entityInstance] = entityInfo;
463         events::StateSensorEntry stateSensorEntry{containerId, entityType,
464                                                   entityInstance, sensorOffset};
465         return hostPDRHandler->handleStateSensorEvent(stateSensorEntry,
466                                                       eventState);
467     }
468     else
469     {
470         return PLDM_ERROR_INVALID_DATA;
471     }
472 
473     return PLDM_SUCCESS;
474 }
475 
476 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request,
477                                        size_t payloadLength,
478                                        uint8_t /*formatVersion*/, uint8_t tid,
479                                        size_t eventDataOffset)
480 {
481     uint8_t eventDataFormat{};
482     uint8_t numberOfChangeRecords{};
483     size_t dataOffset{};
484 
485     auto eventData = reinterpret_cast<const uint8_t*>(request->payload) +
486                      eventDataOffset;
487     auto eventDataSize = payloadLength - eventDataOffset;
488 
489     auto rc = decode_pldm_pdr_repository_chg_event_data(
490         eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords,
491         &dataOffset);
492     if (rc != PLDM_SUCCESS)
493     {
494         return rc;
495     }
496 
497     PDRRecordHandles pdrRecordHandles;
498 
499     if (eventDataFormat == FORMAT_IS_PDR_TYPES)
500     {
501         return PLDM_ERROR_INVALID_DATA;
502     }
503 
504     if (eventDataFormat == FORMAT_IS_PDR_HANDLES)
505     {
506         uint8_t eventDataOperation{};
507         uint8_t numberOfChangeEntries{};
508 
509         auto changeRecordData = eventData + dataOffset;
510         auto changeRecordDataSize = eventDataSize - dataOffset;
511 
512         while (changeRecordDataSize)
513         {
514             rc = decode_pldm_pdr_repository_change_record_data(
515                 changeRecordData, changeRecordDataSize, &eventDataOperation,
516                 &numberOfChangeEntries, &dataOffset);
517 
518             if (rc != PLDM_SUCCESS)
519             {
520                 return rc;
521             }
522 
523             if (eventDataOperation == PLDM_RECORDS_ADDED ||
524                 eventDataOperation == PLDM_RECORDS_MODIFIED)
525             {
526                 if (eventDataOperation == PLDM_RECORDS_MODIFIED)
527                 {
528                     hostPDRHandler->isHostPdrModified = true;
529                 }
530 
531                 rc = getPDRRecordHandles(
532                     reinterpret_cast<const ChangeEntry*>(changeRecordData +
533                                                          dataOffset),
534                     changeRecordDataSize - dataOffset,
535                     static_cast<size_t>(numberOfChangeEntries),
536                     pdrRecordHandles);
537 
538                 if (rc != PLDM_SUCCESS)
539                 {
540                     return rc;
541                 }
542             }
543 
544             changeRecordData += dataOffset +
545                                 (numberOfChangeEntries * sizeof(ChangeEntry));
546             changeRecordDataSize -=
547                 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry));
548         }
549     }
550     if (hostPDRHandler)
551     {
552         // if we get a Repository change event with the eventDataFormat
553         // as REFRESH_ENTIRE_REPOSITORY, then delete all the PDR's that
554         // have the matched Terminus handle
555         if (eventDataFormat == REFRESH_ENTIRE_REPOSITORY)
556         {
557             // We cannot get the Repo change event from the Terminus
558             // that is not already added to the BMC repository
559 
560             for (auto it = hostPDRHandler->tlPDRInfo.cbegin();
561                  it != hostPDRHandler->tlPDRInfo.cend();)
562             {
563                 if (std::get<0>(it->second) == tid)
564                 {
565                     pldm_pdr_remove_pdrs_by_terminus_handle(pdrRepo.getPdr(),
566                                                             it->first);
567                     hostPDRHandler->tlPDRInfo.erase(it++);
568                 }
569                 else
570                 {
571                     ++it;
572                 }
573             }
574         }
575         hostPDRHandler->fetchPDR(std::move(pdrRecordHandles));
576     }
577 
578     return PLDM_SUCCESS;
579 }
580 
581 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData,
582                                  size_t changeEntryDataSize,
583                                  size_t numberOfChangeEntries,
584                                  PDRRecordHandles& pdrRecordHandles)
585 {
586     if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry)))
587     {
588         return PLDM_ERROR_INVALID_DATA;
589     }
590     for (size_t i = 0; i < numberOfChangeEntries; i++)
591     {
592         pdrRecordHandles.push_back(changeEntryData[i]);
593     }
594     return PLDM_SUCCESS;
595 }
596 
597 Response Handler::setNumericEffecterValue(const pldm_msg* request,
598                                           size_t payloadLength)
599 {
600     Response response(sizeof(pldm_msg_hdr) +
601                       PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES);
602     uint16_t effecterId{};
603     uint8_t effecterDataSize{};
604     uint8_t effecterValue[4] = {};
605 
606     if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) +
607                              sizeof(union_effecter_data_size)) ||
608         (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1))
609     {
610         return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
611     }
612 
613     int rc = decode_set_numeric_effecter_value_req(
614         request, payloadLength, &effecterId, &effecterDataSize, effecterValue);
615 
616     if (rc == PLDM_SUCCESS)
617     {
618         const pldm::utils::DBusHandler dBusIntf;
619         rc = platform_numeric_effecter::setNumericEffecterValueHandler<
620             pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId,
621                                                effecterDataSize, effecterValue,
622                                                sizeof(effecterValue));
623     }
624 
625     return ccOnlyResponse(request, rc);
626 }
627 
628 void Handler::generateTerminusLocatorPDR(Repo& repo)
629 {
630     std::vector<uint8_t> pdrBuffer(sizeof(pldm_terminus_locator_pdr));
631 
632     auto pdr = reinterpret_cast<pldm_terminus_locator_pdr*>(pdrBuffer.data());
633 
634     pdr->hdr.record_handle = 0;
635     pdr->hdr.version = 1;
636     pdr->hdr.type = PLDM_TERMINUS_LOCATOR_PDR;
637     pdr->hdr.record_change_num = 0;
638     pdr->hdr.length = sizeof(pldm_terminus_locator_pdr) - sizeof(pldm_pdr_hdr);
639     pdr->terminus_handle = TERMINUS_HANDLE;
640     pdr->validity = PLDM_TL_PDR_VALID;
641     pdr->tid = TERMINUS_ID;
642     pdr->container_id = 0x0;
643     pdr->terminus_locator_type = PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID;
644     pdr->terminus_locator_value_size =
645         sizeof(pldm_terminus_locator_type_mctp_eid);
646     auto locatorValue = reinterpret_cast<pldm_terminus_locator_type_mctp_eid*>(
647         pdr->terminus_locator_value);
648     locatorValue->eid = BmcMctpEid;
649 
650     PdrEntry pdrEntry{};
651     pdrEntry.data = pdrBuffer.data();
652     pdrEntry.size = pdrBuffer.size();
653     repo.addRecord(pdrEntry);
654     if (hostPDRHandler)
655     {
656         hostPDRHandler->tlPDRInfo.insert_or_assign(
657             pdr->terminus_handle,
658             std::make_tuple(pdr->tid, locatorValue->eid, pdr->validity));
659     }
660 }
661 
662 Response Handler::getStateSensorReadings(const pldm_msg* request,
663                                          size_t payloadLength)
664 {
665     uint16_t sensorId{};
666     bitfield8_t sensorRearm{};
667     uint8_t reserved{};
668 
669     if (payloadLength != PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES)
670     {
671         return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
672     }
673 
674     int rc = decode_get_state_sensor_readings_req(
675         request, payloadLength, &sensorId, &sensorRearm, &reserved);
676 
677     if (rc != PLDM_SUCCESS)
678     {
679         return ccOnlyResponse(request, rc);
680     }
681 
682     // 0x01 to 0x08
683     uint8_t sensorRearmCount = std::popcount(sensorRearm.byte);
684     std::vector<get_sensor_state_field> stateField(sensorRearmCount);
685     uint8_t comSensorCnt{};
686     const pldm::utils::DBusHandler dBusIntf;
687 
688     uint16_t entityType{};
689     uint16_t entityInstance{};
690     uint16_t stateSetId{};
691 
692     if (isOemStateSensor(*this, sensorId, sensorRearmCount, comSensorCnt,
693                          entityType, entityInstance, stateSetId) &&
694         oemPlatformHandler != nullptr && !sensorDbusObjMaps.contains(sensorId))
695     {
696         rc = oemPlatformHandler->getOemStateSensorReadingsHandler(
697             entityType, entityInstance, stateSetId, comSensorCnt, stateField);
698     }
699     else
700     {
701         rc = platform_state_sensor::getStateSensorReadingsHandler<
702             pldm::utils::DBusHandler, Handler>(dBusIntf, *this, sensorId,
703                                                sensorRearmCount, comSensorCnt,
704                                                stateField);
705     }
706 
707     if (rc != PLDM_SUCCESS)
708     {
709         return ccOnlyResponse(request, rc);
710     }
711 
712     Response response(sizeof(pldm_msg_hdr) +
713                       PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES +
714                       sizeof(get_sensor_state_field) * comSensorCnt);
715     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
716     rc = encode_get_state_sensor_readings_resp(request->hdr.instance_id, rc,
717                                                comSensorCnt, stateField.data(),
718                                                responsePtr);
719     if (rc != PLDM_SUCCESS)
720     {
721         return ccOnlyResponse(request, rc);
722     }
723 
724     return response;
725 }
726 
727 void Handler::_processPostGetPDRActions(sdeventplus::source::EventBase&
728                                         /*source */)
729 {
730     deferredGetPDREvent.reset();
731     dbusToPLDMEventHandler->listenSensorEvent(pdrRepo, sensorDbusObjMaps);
732 }
733 
734 bool isOemStateSensor(Handler& handler, uint16_t sensorId,
735                       uint8_t sensorRearmCount, uint8_t& compSensorCnt,
736                       uint16_t& entityType, uint16_t& entityInstance,
737                       uint16_t& stateSetId)
738 {
739     pldm_state_sensor_pdr* pdr = nullptr;
740 
741     std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateSensorPdrRepo(
742         pldm_pdr_init(), pldm_pdr_destroy);
743     Repo stateSensorPDRs(stateSensorPdrRepo.get());
744     getRepoByType(handler.getRepo(), stateSensorPDRs, PLDM_STATE_SENSOR_PDR);
745     if (stateSensorPDRs.empty())
746     {
747         error("Failed to get record by PDR type");
748         return false;
749     }
750 
751     PdrEntry pdrEntry{};
752     auto pdrRecord = stateSensorPDRs.getFirstRecord(pdrEntry);
753     while (pdrRecord)
754     {
755         pdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdrEntry.data);
756         assert(pdr != NULL);
757         if (pdr->sensor_id != sensorId)
758         {
759             pdr = nullptr;
760             pdrRecord = stateSensorPDRs.getNextRecord(pdrRecord, pdrEntry);
761             continue;
762         }
763         auto tmpEntityType = pdr->entity_type;
764         auto tmpEntityInstance = pdr->entity_instance;
765         auto tmpCompSensorCnt = pdr->composite_sensor_count;
766         auto tmpPossibleStates =
767             reinterpret_cast<state_sensor_possible_states*>(
768                 pdr->possible_states);
769         auto tmpStateSetId = tmpPossibleStates->state_set_id;
770 
771         if (sensorRearmCount > tmpCompSensorCnt)
772         {
773             error(
774                 "The requester sent wrong sensorRearm count for the sensor, SENSOR_ID={SENSOR_ID} SENSOR_REARM_COUNT={SENSOR_REARM_CNT}",
775                 "SENSOR_ID", sensorId, "SENSOR_REARM_CNT",
776                 (uint16_t)sensorRearmCount);
777             break;
778         }
779 
780         if ((tmpEntityType >= PLDM_OEM_ENTITY_TYPE_START &&
781              tmpEntityType <= PLDM_OEM_ENTITY_TYPE_END) ||
782             (tmpStateSetId >= PLDM_OEM_STATE_SET_ID_START &&
783              tmpStateSetId < PLDM_OEM_STATE_SET_ID_END))
784         {
785             entityType = tmpEntityType;
786             entityInstance = tmpEntityInstance;
787             stateSetId = tmpStateSetId;
788             compSensorCnt = tmpCompSensorCnt;
789             return true;
790         }
791         else
792         {
793             return false;
794         }
795     }
796     return false;
797 }
798 
799 bool isOemStateEffecter(Handler& handler, uint16_t effecterId,
800                         uint8_t compEffecterCnt, uint16_t& entityType,
801                         uint16_t& entityInstance, uint16_t& stateSetId)
802 {
803     pldm_state_effecter_pdr* pdr = nullptr;
804 
805     std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateEffecterPdrRepo(
806         pldm_pdr_init(), pldm_pdr_destroy);
807     Repo stateEffecterPDRs(stateEffecterPdrRepo.get());
808     getRepoByType(handler.getRepo(), stateEffecterPDRs,
809                   PLDM_STATE_EFFECTER_PDR);
810     if (stateEffecterPDRs.empty())
811     {
812         error("Failed to get record by PDR type");
813         return false;
814     }
815 
816     PdrEntry pdrEntry{};
817     auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry);
818     while (pdrRecord)
819     {
820         pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data);
821         assert(pdr != NULL);
822         if (pdr->effecter_id != effecterId)
823         {
824             pdr = nullptr;
825             pdrRecord = stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry);
826             continue;
827         }
828 
829         auto tmpEntityType = pdr->entity_type;
830         auto tmpEntityInstance = pdr->entity_instance;
831         auto tmpPossibleStates =
832             reinterpret_cast<state_effecter_possible_states*>(
833                 pdr->possible_states);
834         auto tmpStateSetId = tmpPossibleStates->state_set_id;
835 
836         if (compEffecterCnt > pdr->composite_effecter_count)
837         {
838             error(
839                 "The requester sent wrong composite effecter count for the effecter, EFFECTER_ID={EFFECTER_ID} COMP_EFF_CNT={COMP_EFF_CNT}",
840                 "EFFECTER_ID", effecterId, "COMP_EFF_CNT",
841                 (uint16_t)compEffecterCnt);
842             return false;
843         }
844 
845         if ((tmpEntityType >= PLDM_OEM_ENTITY_TYPE_START &&
846              tmpEntityType <= PLDM_OEM_ENTITY_TYPE_END) ||
847             (tmpStateSetId >= PLDM_OEM_STATE_SET_ID_START &&
848              tmpStateSetId < PLDM_OEM_STATE_SET_ID_END))
849         {
850             entityType = tmpEntityType;
851             entityInstance = tmpEntityInstance;
852             stateSetId = tmpStateSetId;
853             return true;
854         }
855         else
856         {
857             return false;
858         }
859     }
860     return false;
861 }
862 
863 } // namespace platform
864 } // namespace responder
865 } // namespace pldm
866