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