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