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 
454         try
455         {
456             std::tie(entityInfo, compositeSensorStates) =
457                 hostPDRHandler->lookupSensorInfo(sensorEntry);
458         }
459         catch (const std::out_of_range&)
460         {
461             // If there is no mapping for tid, sensorId combination, try
462             // PLDM_TID_RESERVED, sensorId for terminus that is yet to
463             // implement TL PDR.
464             try
465             {
466                 sensorEntry.terminusID = PLDM_TID_RESERVED;
467                 std::tie(entityInfo, compositeSensorStates) =
468                     hostPDRHandler->lookupSensorInfo(sensorEntry);
469             }
470             // If there is no mapping for events return PLDM_SUCCESS
471             catch (const std::out_of_range&)
472             {
473                 return PLDM_SUCCESS;
474             }
475         }
476 
477         if (sensorOffset >= compositeSensorStates.size())
478         {
479             return PLDM_ERROR_INVALID_DATA;
480         }
481 
482         const auto& possibleStates = compositeSensorStates[sensorOffset];
483         if (possibleStates.find(eventState) == possibleStates.end())
484         {
485             return PLDM_ERROR_INVALID_DATA;
486         }
487 
488         const auto& [containerId, entityType, entityInstance] = entityInfo;
489         events::StateSensorEntry stateSensorEntry{containerId, entityType,
490                                                   entityInstance, sensorOffset};
491         return hostPDRHandler->handleStateSensorEvent(stateSensorEntry,
492                                                       eventState);
493     }
494     else
495     {
496         return PLDM_ERROR_INVALID_DATA;
497     }
498 
499     return PLDM_SUCCESS;
500 }
501 
502 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request,
503                                        size_t payloadLength,
504                                        uint8_t /*formatVersion*/, uint8_t tid,
505                                        size_t eventDataOffset)
506 {
507     uint8_t eventDataFormat{};
508     uint8_t numberOfChangeRecords{};
509     size_t dataOffset{};
510 
511     auto eventData = reinterpret_cast<const uint8_t*>(request->payload) +
512                      eventDataOffset;
513     auto eventDataSize = payloadLength - eventDataOffset;
514 
515     auto rc = decode_pldm_pdr_repository_chg_event_data(
516         eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords,
517         &dataOffset);
518     if (rc != PLDM_SUCCESS)
519     {
520         return rc;
521     }
522 
523     PDRRecordHandles pdrRecordHandles;
524 
525     if (eventDataFormat == FORMAT_IS_PDR_TYPES)
526     {
527         return PLDM_ERROR_INVALID_DATA;
528     }
529 
530     if (eventDataFormat == FORMAT_IS_PDR_HANDLES)
531     {
532         uint8_t eventDataOperation{};
533         uint8_t numberOfChangeEntries{};
534 
535         auto changeRecordData = eventData + dataOffset;
536         auto changeRecordDataSize = eventDataSize - dataOffset;
537 
538         while (changeRecordDataSize)
539         {
540             rc = decode_pldm_pdr_repository_change_record_data(
541                 changeRecordData, changeRecordDataSize, &eventDataOperation,
542                 &numberOfChangeEntries, &dataOffset);
543 
544             if (rc != PLDM_SUCCESS)
545             {
546                 return rc;
547             }
548 
549             if (eventDataOperation == PLDM_RECORDS_ADDED ||
550                 eventDataOperation == PLDM_RECORDS_MODIFIED)
551             {
552                 if (eventDataOperation == PLDM_RECORDS_MODIFIED)
553                 {
554                     hostPDRHandler->isHostPdrModified = true;
555                 }
556 
557                 rc = getPDRRecordHandles(
558                     reinterpret_cast<const ChangeEntry*>(changeRecordData +
559                                                          dataOffset),
560                     changeRecordDataSize - dataOffset,
561                     static_cast<size_t>(numberOfChangeEntries),
562                     pdrRecordHandles);
563 
564                 if (rc != PLDM_SUCCESS)
565                 {
566                     return rc;
567                 }
568             }
569 
570             changeRecordData += dataOffset +
571                                 (numberOfChangeEntries * sizeof(ChangeEntry));
572             changeRecordDataSize -=
573                 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry));
574         }
575     }
576     if (hostPDRHandler)
577     {
578         // if we get a Repository change event with the eventDataFormat
579         // as REFRESH_ENTIRE_REPOSITORY, then delete all the PDR's that
580         // have the matched Terminus handle
581         if (eventDataFormat == REFRESH_ENTIRE_REPOSITORY)
582         {
583             // We cannot get the Repo change event from the Terminus
584             // that is not already added to the BMC repository
585 
586             for (auto it = hostPDRHandler->tlPDRInfo.cbegin();
587                  it != hostPDRHandler->tlPDRInfo.cend();)
588             {
589                 if (std::get<0>(it->second) == tid)
590                 {
591                     pldm_pdr_remove_pdrs_by_terminus_handle(pdrRepo.getPdr(),
592                                                             it->first);
593                     hostPDRHandler->tlPDRInfo.erase(it++);
594                 }
595                 else
596                 {
597                     ++it;
598                 }
599             }
600         }
601         hostPDRHandler->fetchPDR(std::move(pdrRecordHandles));
602     }
603 
604     return PLDM_SUCCESS;
605 }
606 
607 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData,
608                                  size_t changeEntryDataSize,
609                                  size_t numberOfChangeEntries,
610                                  PDRRecordHandles& pdrRecordHandles)
611 {
612     if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry)))
613     {
614         return PLDM_ERROR_INVALID_DATA;
615     }
616     for (size_t i = 0; i < numberOfChangeEntries; i++)
617     {
618         pdrRecordHandles.push_back(changeEntryData[i]);
619     }
620     return PLDM_SUCCESS;
621 }
622 
623 Response Handler::getNumericEffecterValue(const pldm_msg* request,
624                                           size_t payloadLength)
625 {
626     if (payloadLength != PLDM_GET_NUMERIC_EFFECTER_VALUE_REQ_BYTES)
627     {
628         return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
629     }
630 
631     uint16_t effecterId{};
632     auto rc = decode_get_numeric_effecter_value_req(request, payloadLength,
633                                                     &effecterId);
634     if (rc != PLDM_SUCCESS)
635     {
636         return ccOnlyResponse(request, rc);
637     }
638 
639     const pldm::utils::DBusHandler dBusIntf;
640     uint8_t effecterDataSize{};
641     pldm::utils::PropertyValue dbusValue;
642     std::string propertyType;
643     using effecterOperationalState = uint8_t;
644     using completionCode = uint8_t;
645 
646     rc = platform_numeric_effecter::getNumericEffecterData<
647         pldm::utils::DBusHandler, Handler>(
648         dBusIntf, *this, effecterId, effecterDataSize, propertyType, dbusValue);
649 
650     if (rc != PLDM_SUCCESS)
651     {
652         return ccOnlyResponse(request, rc);
653     }
654 
655     // Refer DSP0248_1.2.0.pdf (section 22.3, Table 48)
656     // Completion Code (uint8), Effecter Data Size(uint8), Effecter Operational
657     // State(uint8), PendingValue (uint8|sint8|uint16|sint16|uint32|sint32 )
658     // PresentValue (uint8|sint8|uint16|sint16|uint32|sint32 )
659     // Size of PendingValue and PresentValue calculated based on size is
660     // provided in effecter data size
661     size_t responsePayloadLength = sizeof(completionCode) +
662                                    sizeof(effecterDataSize) +
663                                    sizeof(effecterOperationalState) +
664                                    getEffecterDataSize(effecterDataSize) +
665                                    getEffecterDataSize(effecterDataSize);
666 
667     Response response(responsePayloadLength + sizeof(pldm_msg_hdr));
668     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
669 
670     rc = platform_numeric_effecter::getNumericEffecterValueHandler(
671         propertyType, dbusValue, effecterDataSize, responsePtr,
672         responsePayloadLength, request->hdr.instance_id);
673 
674     if (rc != PLDM_SUCCESS)
675     {
676         error(
677             "Reponse to GetNumericEffecterValue failed RC={RC} for EffectorId={EFFECTER_ID} ",
678             "RC", rc, "EFFECTER_ID", effecterId);
679         return ccOnlyResponse(request, rc);
680     }
681     return response;
682 }
683 
684 Response Handler::setNumericEffecterValue(const pldm_msg* request,
685                                           size_t payloadLength)
686 {
687     Response response(sizeof(pldm_msg_hdr) +
688                       PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES);
689     uint16_t effecterId{};
690     uint8_t effecterDataSize{};
691     uint8_t effecterValue[4] = {};
692 
693     if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) +
694                              sizeof(union_effecter_data_size)) ||
695         (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1))
696     {
697         return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
698     }
699 
700     int rc = decode_set_numeric_effecter_value_req(
701         request, payloadLength, &effecterId, &effecterDataSize, effecterValue);
702 
703     if (rc == PLDM_SUCCESS)
704     {
705         const pldm::utils::DBusHandler dBusIntf;
706         rc = platform_numeric_effecter::setNumericEffecterValueHandler<
707             pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId,
708                                                effecterDataSize, effecterValue,
709                                                sizeof(effecterValue));
710     }
711 
712     return ccOnlyResponse(request, rc);
713 }
714 
715 void Handler::generateTerminusLocatorPDR(Repo& repo)
716 {
717     std::vector<uint8_t> pdrBuffer(sizeof(pldm_terminus_locator_pdr));
718 
719     auto pdr = reinterpret_cast<pldm_terminus_locator_pdr*>(pdrBuffer.data());
720 
721     pdr->hdr.record_handle = 0;
722     pdr->hdr.version = 1;
723     pdr->hdr.type = PLDM_TERMINUS_LOCATOR_PDR;
724     pdr->hdr.record_change_num = 0;
725     pdr->hdr.length = sizeof(pldm_terminus_locator_pdr) - sizeof(pldm_pdr_hdr);
726     pdr->terminus_handle = TERMINUS_HANDLE;
727     pdr->validity = PLDM_TL_PDR_VALID;
728     pdr->tid = TERMINUS_ID;
729     pdr->container_id = 0x0;
730     pdr->terminus_locator_type = PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID;
731     pdr->terminus_locator_value_size =
732         sizeof(pldm_terminus_locator_type_mctp_eid);
733     auto locatorValue = reinterpret_cast<pldm_terminus_locator_type_mctp_eid*>(
734         pdr->terminus_locator_value);
735     locatorValue->eid = BmcMctpEid;
736 
737     PdrEntry pdrEntry{};
738     pdrEntry.data = pdrBuffer.data();
739     pdrEntry.size = pdrBuffer.size();
740     repo.addRecord(pdrEntry);
741     if (hostPDRHandler)
742     {
743         hostPDRHandler->tlPDRInfo.insert_or_assign(
744             pdr->terminus_handle,
745             std::make_tuple(pdr->tid, locatorValue->eid, pdr->validity));
746     }
747 }
748 
749 Response Handler::getStateSensorReadings(const pldm_msg* request,
750                                          size_t payloadLength)
751 {
752     uint16_t sensorId{};
753     bitfield8_t sensorRearm{};
754     uint8_t reserved{};
755 
756     if (payloadLength != PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES)
757     {
758         return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
759     }
760 
761     int rc = decode_get_state_sensor_readings_req(
762         request, payloadLength, &sensorId, &sensorRearm, &reserved);
763 
764     if (rc != PLDM_SUCCESS)
765     {
766         return ccOnlyResponse(request, rc);
767     }
768 
769     // 0x01 to 0x08
770     uint8_t sensorRearmCount = std::popcount(sensorRearm.byte);
771     std::vector<get_sensor_state_field> stateField(sensorRearmCount);
772     uint8_t comSensorCnt{};
773     const pldm::utils::DBusHandler dBusIntf;
774 
775     uint16_t entityType{};
776     uint16_t entityInstance{};
777     uint16_t stateSetId{};
778 
779     if (isOemStateSensor(*this, sensorId, sensorRearmCount, comSensorCnt,
780                          entityType, entityInstance, stateSetId) &&
781         oemPlatformHandler != nullptr && !sensorDbusObjMaps.contains(sensorId))
782     {
783         rc = oemPlatformHandler->getOemStateSensorReadingsHandler(
784             entityType, entityInstance, stateSetId, comSensorCnt, stateField);
785     }
786     else
787     {
788         rc = platform_state_sensor::getStateSensorReadingsHandler<
789             pldm::utils::DBusHandler, Handler>(dBusIntf, *this, sensorId,
790                                                sensorRearmCount, comSensorCnt,
791                                                stateField);
792     }
793 
794     if (rc != PLDM_SUCCESS)
795     {
796         return ccOnlyResponse(request, rc);
797     }
798 
799     Response response(sizeof(pldm_msg_hdr) +
800                       PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES +
801                       sizeof(get_sensor_state_field) * comSensorCnt);
802     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
803     rc = encode_get_state_sensor_readings_resp(request->hdr.instance_id, rc,
804                                                comSensorCnt, stateField.data(),
805                                                responsePtr);
806     if (rc != PLDM_SUCCESS)
807     {
808         return ccOnlyResponse(request, rc);
809     }
810 
811     return response;
812 }
813 
814 void Handler::_processPostGetPDRActions(sdeventplus::source::EventBase&
815                                         /*source */)
816 {
817     deferredGetPDREvent.reset();
818     dbusToPLDMEventHandler->listenSensorEvent(pdrRepo, sensorDbusObjMaps);
819 }
820 
821 bool isOemStateSensor(Handler& handler, uint16_t sensorId,
822                       uint8_t sensorRearmCount, uint8_t& compSensorCnt,
823                       uint16_t& entityType, uint16_t& entityInstance,
824                       uint16_t& stateSetId)
825 {
826     pldm_state_sensor_pdr* pdr = nullptr;
827 
828     std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateSensorPdrRepo(
829         pldm_pdr_init(), pldm_pdr_destroy);
830     if (!stateSensorPdrRepo)
831     {
832         error("Failed to instantiate state sensor PDR repository");
833         return false;
834     }
835     Repo stateSensorPDRs(stateSensorPdrRepo.get());
836     getRepoByType(handler.getRepo(), stateSensorPDRs, PLDM_STATE_SENSOR_PDR);
837     if (stateSensorPDRs.empty())
838     {
839         error("Failed to get record by PDR type");
840         return false;
841     }
842 
843     PdrEntry pdrEntry{};
844     auto pdrRecord = stateSensorPDRs.getFirstRecord(pdrEntry);
845     while (pdrRecord)
846     {
847         pdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdrEntry.data);
848         assert(pdr != NULL);
849         if (pdr->sensor_id != sensorId)
850         {
851             pdr = nullptr;
852             pdrRecord = stateSensorPDRs.getNextRecord(pdrRecord, pdrEntry);
853             continue;
854         }
855         auto tmpEntityType = pdr->entity_type;
856         auto tmpEntityInstance = pdr->entity_instance;
857         auto tmpCompSensorCnt = pdr->composite_sensor_count;
858         auto tmpPossibleStates =
859             reinterpret_cast<state_sensor_possible_states*>(
860                 pdr->possible_states);
861         auto tmpStateSetId = tmpPossibleStates->state_set_id;
862 
863         if (sensorRearmCount > tmpCompSensorCnt)
864         {
865             error(
866                 "The requester sent wrong sensorRearm count for the sensor, SENSOR_ID={SENSOR_ID} SENSOR_REARM_COUNT={SENSOR_REARM_CNT}",
867                 "SENSOR_ID", sensorId, "SENSOR_REARM_CNT",
868                 (uint16_t)sensorRearmCount);
869             break;
870         }
871 
872         if ((tmpEntityType >= PLDM_OEM_ENTITY_TYPE_START &&
873              tmpEntityType <= PLDM_OEM_ENTITY_TYPE_END) ||
874             (tmpStateSetId >= PLDM_OEM_STATE_SET_ID_START &&
875              tmpStateSetId < PLDM_OEM_STATE_SET_ID_END))
876         {
877             entityType = tmpEntityType;
878             entityInstance = tmpEntityInstance;
879             stateSetId = tmpStateSetId;
880             compSensorCnt = tmpCompSensorCnt;
881             return true;
882         }
883         else
884         {
885             return false;
886         }
887     }
888     return false;
889 }
890 
891 bool isOemStateEffecter(Handler& handler, uint16_t effecterId,
892                         uint8_t compEffecterCnt, uint16_t& entityType,
893                         uint16_t& entityInstance, uint16_t& stateSetId)
894 {
895     pldm_state_effecter_pdr* pdr = nullptr;
896 
897     std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateEffecterPdrRepo(
898         pldm_pdr_init(), pldm_pdr_destroy);
899     if (!stateEffecterPdrRepo)
900     {
901         error("Failed to instantiate state effecter PDR repository");
902         return false;
903     }
904     Repo stateEffecterPDRs(stateEffecterPdrRepo.get());
905     getRepoByType(handler.getRepo(), stateEffecterPDRs,
906                   PLDM_STATE_EFFECTER_PDR);
907     if (stateEffecterPDRs.empty())
908     {
909         error("Failed to get record by PDR type");
910         return false;
911     }
912 
913     PdrEntry pdrEntry{};
914     auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry);
915     while (pdrRecord)
916     {
917         pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data);
918         assert(pdr != NULL);
919         if (pdr->effecter_id != effecterId)
920         {
921             pdr = nullptr;
922             pdrRecord = stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry);
923             continue;
924         }
925 
926         auto tmpEntityType = pdr->entity_type;
927         auto tmpEntityInstance = pdr->entity_instance;
928         auto tmpPossibleStates =
929             reinterpret_cast<state_effecter_possible_states*>(
930                 pdr->possible_states);
931         auto tmpStateSetId = tmpPossibleStates->state_set_id;
932 
933         if (compEffecterCnt > pdr->composite_effecter_count)
934         {
935             error(
936                 "The requester sent wrong composite effecter count for the effecter, EFFECTER_ID={EFFECTER_ID} COMP_EFF_CNT={COMP_EFF_CNT}",
937                 "EFFECTER_ID", effecterId, "COMP_EFF_CNT",
938                 (uint16_t)compEffecterCnt);
939             return false;
940         }
941 
942         if ((tmpEntityType >= PLDM_OEM_ENTITY_TYPE_START &&
943              tmpEntityType <= PLDM_OEM_ENTITY_TYPE_END) ||
944             (tmpStateSetId >= PLDM_OEM_STATE_SET_ID_START &&
945              tmpStateSetId < PLDM_OEM_STATE_SET_ID_END))
946         {
947             entityType = tmpEntityType;
948             entityInstance = tmpEntityInstance;
949             stateSetId = tmpStateSetId;
950             return true;
951         }
952         else
953         {
954             return false;
955         }
956     }
957     return false;
958 }
959 
960 void Handler::setEventReceiver()
961 {
962     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
963                                     PLDM_SET_EVENT_RECEIVER_REQ_BYTES);
964     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
965     auto instanceId = instanceIdDb->next(eid);
966     uint8_t eventMessageGlobalEnable =
967         PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE;
968     uint8_t transportProtocolType = PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP;
969     uint8_t eventReceiverAddressInfo = pldm::responder::pdr::BmcMctpEid;
970     uint16_t heartbeatTimer = HEARTBEAT_TIMEOUT;
971 
972     auto rc = encode_set_event_receiver_req(
973         instanceId, eventMessageGlobalEnable, transportProtocolType,
974         eventReceiverAddressInfo, heartbeatTimer, request);
975     if (rc != PLDM_SUCCESS)
976     {
977         instanceIdDb->free(eid, instanceId);
978         error("Failed to encode_set_event_receiver_req, rc = {RC}", "RC",
979               lg2::hex, rc);
980         return;
981     }
982 
983     auto processSetEventReceiverResponse =
984         [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
985         if (response == nullptr || !respMsgLen)
986         {
987             error("Failed to receive response for setEventReceiver command");
988             return;
989         }
990 
991         uint8_t completionCode{};
992         auto rc = decode_set_event_receiver_resp(response, respMsgLen,
993                                                  &completionCode);
994         if (rc || completionCode)
995         {
996             error(
997                 "Failed to decode setEventReceiver command response, rc = {RC}, cc = {CC}",
998                 "RC", rc, "CC", (unsigned)completionCode);
999             pldm::utils::reportError(
1000                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
1001         }
1002     };
1003     rc = handler->registerRequest(
1004         eid, instanceId, PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER,
1005         std::move(requestMsg), std::move(processSetEventReceiverResponse));
1006 
1007     if (rc != PLDM_SUCCESS)
1008     {
1009         error("Failed to send the setEventReceiver request");
1010     }
1011 
1012     if (oemPlatformHandler)
1013     {
1014         oemPlatformHandler->countSetEventReceiver();
1015         oemPlatformHandler->checkAndDisableWatchDog();
1016     }
1017 }
1018 
1019 } // namespace platform
1020 } // namespace responder
1021 } // namespace pldm
1022