1 #pragma once
2 
3 #include "config.h"
4 
5 #include "libpldm/pdr.h"
6 #include "libpldm/platform.h"
7 #include "libpldm/states.h"
8 
9 #include "common/utils.hpp"
10 #include "event_parser.hpp"
11 #include "fru.hpp"
12 #include "host-bmc/dbus_to_event_handler.hpp"
13 #include "host-bmc/host_pdr_handler.hpp"
14 #include "libpldmresponder/pdr.hpp"
15 #include "libpldmresponder/pdr_utils.hpp"
16 #include "pldmd/handler.hpp"
17 
18 #include <stdint.h>
19 
20 #include <map>
21 
22 namespace pldm
23 {
24 namespace responder
25 {
26 namespace platform
27 {
28 
29 using namespace pldm::utils;
30 using namespace pldm::responder::pdr_utils;
31 using namespace pldm::state_sensor;
32 
33 using generatePDR =
34     std::function<void(const pldm::utils::DBusHandler& dBusIntf,
35                        const Json& json, pdr_utils::RepoInterface& repo)>;
36 
37 using EffecterId = uint16_t;
38 using DbusObjMaps =
39     std::map<EffecterId,
40              std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>>;
41 using DbusPath = std::string;
42 using EffecterObjs = std::vector<DbusPath>;
43 using EventType = uint8_t;
44 using EventHandler = std::function<int(
45     const pldm_msg* request, size_t payloadLength, uint8_t formatVersion,
46     uint8_t tid, size_t eventDataOffset)>;
47 using EventHandlers = std::vector<EventHandler>;
48 using EventMap = std::map<EventType, EventHandlers>;
49 
50 // EventEntry = <uint8_t> - EventState <uint8_t> - SensorOffset <uint16_t> -
51 // SensorID
52 using EventEntry = uint32_t;
53 struct DBusInfo
54 {
55     pldm::utils::DBusMapping dBusValues;
56     pldm::utils::PropertyValue dBusPropertyValue;
57 };
58 
59 class Handler : public CmdHandler
60 {
61   public:
62     Handler(const pldm::utils::DBusHandler* dBusIntf,
63             const std::string& pdrJsonsDir, const std::string& eventsJsonsDir,
64             pldm_pdr* repo, HostPDRHandler* hostPDRHandler,
65             DbusToPLDMEvent* dbusToPLDMEventHandler, fru::Handler* fruHandler,
66             bool buildPDRLazily = false,
67             const std::optional<EventMap>& addOnHandlersMap = std::nullopt) :
68         pdrRepo(repo),
69         hostPDRHandler(hostPDRHandler), stateSensorHandler(eventsJsonsDir),
70         dbusToPLDMEventHandler(dbusToPLDMEventHandler), fruHandler(fruHandler),
71         dBusIntf(dBusIntf), pdrJsonsDir(pdrJsonsDir), pdrCreated(false)
72     {
73         if (!buildPDRLazily)
74         {
75             generateTerminusLocatorPDR(pdrRepo);
76             generate(*dBusIntf, pdrJsonsDir, pdrRepo);
77             pdrCreated = true;
78         }
79 
80         handlers.emplace(PLDM_GET_PDR,
81                          [this](const pldm_msg* request, size_t payloadLength) {
82                              return this->getPDR(request, payloadLength);
83                          });
84         handlers.emplace(PLDM_SET_NUMERIC_EFFECTER_VALUE,
85                          [this](const pldm_msg* request, size_t payloadLength) {
86                              return this->setNumericEffecterValue(
87                                  request, payloadLength);
88                          });
89         handlers.emplace(PLDM_SET_STATE_EFFECTER_STATES,
90                          [this](const pldm_msg* request, size_t payloadLength) {
91                              return this->setStateEffecterStates(request,
92                                                                  payloadLength);
93                          });
94         handlers.emplace(PLDM_PLATFORM_EVENT_MESSAGE,
95                          [this](const pldm_msg* request, size_t payloadLength) {
96                              return this->platformEventMessage(request,
97                                                                payloadLength);
98                          });
99         handlers.emplace(PLDM_GET_STATE_SENSOR_READINGS,
100                          [this](const pldm_msg* request, size_t payloadLength) {
101                              return this->getStateSensorReadings(request,
102                                                                  payloadLength);
103                          });
104 
105         // Default handler for PLDM Events
106         eventHandlers[PLDM_SENSOR_EVENT].emplace_back(
107             [this](const pldm_msg* request, size_t payloadLength,
108                    uint8_t formatVersion, uint8_t tid, size_t eventDataOffset) {
109                 return this->sensorEvent(request, payloadLength, formatVersion,
110                                          tid, eventDataOffset);
111             });
112         eventHandlers[PLDM_PDR_REPOSITORY_CHG_EVENT].emplace_back(
113             [this](const pldm_msg* request, size_t payloadLength,
114                    uint8_t formatVersion, uint8_t tid, size_t eventDataOffset) {
115                 return this->pldmPDRRepositoryChgEvent(request, payloadLength,
116                                                        formatVersion, tid,
117                                                        eventDataOffset);
118             });
119 
120         // Additional OEM event handlers for PLDM events, append it to the
121         // standard handlers
122         if (addOnHandlersMap)
123         {
124             auto addOnHandlers = addOnHandlersMap.value();
125             for (EventMap::iterator iter = addOnHandlers.begin();
126                  iter != addOnHandlers.end(); ++iter)
127             {
128                 auto search = eventHandlers.find(iter->first);
129                 if (search != eventHandlers.end())
130                 {
131                     search->second.insert(std::end(search->second),
132                                           std::begin(iter->second),
133                                           std::end(iter->second));
134                 }
135                 else
136                 {
137                     eventHandlers.emplace(iter->first, iter->second);
138                 }
139             }
140         }
141     }
142 
143     pdr_utils::Repo& getRepo()
144     {
145         return this->pdrRepo;
146     }
147 
148     /** @brief Add D-Bus mapping and value mapping(stateId to D-Bus) for the
149      *         Id. If the same id is added, the previous dbusObjs will
150      *         be "over-written".
151      *
152      *  @param[in] Id - effecter/sensor id
153      *  @param[in] dbusObj - list of D-Bus object structure and list of D-Bus
154      *                       property value to attribute value
155      *  @param[in] typeId - the type id of enum
156      */
157     void addDbusObjMaps(
158         uint16_t id,
159         std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj,
160         TypeId typeId = TypeId::PLDM_EFFECTER_ID);
161 
162     /** @brief Retrieve an id -> D-Bus objects mapping
163      *
164      *  @param[in] Id - id
165      *  @param[in] typeId - the type id of enum
166      *
167      *  @return std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> -
168      *          list of D-Bus object structure and list of D-Bus property value
169      *          to attribute value
170      */
171     const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>&
172         getDbusObjMaps(uint16_t id,
173                        TypeId typeId = TypeId::PLDM_EFFECTER_ID) const;
174 
175     uint16_t getNextEffecterId()
176     {
177         return ++nextEffecterId;
178     }
179 
180     uint16_t getNextSensorId()
181     {
182         return ++nextSensorId;
183     }
184 
185     /** @brief Parse PDR JSONs and build PDR repository
186      *
187      *  @param[in] dBusIntf - The interface object
188      *  @param[in] dir - directory housing platform specific PDR JSON files
189      *  @param[in] repo - instance of concrete implementation of Repo
190      */
191     void generate(const pldm::utils::DBusHandler& dBusIntf,
192                   const std::string& dir, Repo& repo);
193 
194     /** @brief Parse PDR JSONs and build state effecter PDR repository
195      *
196      *  @param[in] json - platform specific PDR JSON files
197      *  @param[in] repo - instance of state effecter implementation of Repo
198      */
199     void generateStateEffecterRepo(const Json& json, Repo& repo);
200 
201     /** @brief map of PLDM event type to EventHandlers
202      *
203      */
204     EventMap eventHandlers;
205 
206     /** @brief Handler for GetPDR
207      *
208      *  @param[in] request - Request message payload
209      *  @param[in] payloadLength - Request payload length
210      *  @param[out] Response - Response message written here
211      */
212     Response getPDR(const pldm_msg* request, size_t payloadLength);
213 
214     /** @brief Handler for setNumericEffecterValue
215      *
216      *  @param[in] request - Request message
217      *  @param[in] payloadLength - Request payload length
218      *  @return Response - PLDM Response message
219      */
220     Response setNumericEffecterValue(const pldm_msg* request,
221                                      size_t payloadLength);
222 
223     /** @brief Handler for getStateSensorReadings
224      *
225      *  @param[in] request - Request message
226      *  @param[in] payloadLength - Request payload length
227      *  @return Response - PLDM Response message
228      */
229     Response getStateSensorReadings(const pldm_msg* request,
230                                     size_t payloadLength);
231 
232     /** @brief Handler for setStateEffecterStates
233      *
234      *  @param[in] request - Request message
235      *  @param[in] payloadLength - Request payload length
236      *  @return Response - PLDM Response message
237      */
238     Response setStateEffecterStates(const pldm_msg* request,
239                                     size_t payloadLength);
240 
241     /** @brief Handler for PlatformEventMessage
242      *
243      *  @param[in] request - Request message
244      *  @param[in] payloadLength - Request payload length
245      *  @return Response - PLDM Response message
246      */
247     Response platformEventMessage(const pldm_msg* request,
248                                   size_t payloadLength);
249 
250     /** @brief Handler for event class Sensor event
251      *
252      *  @param[in] request - Request message
253      *  @param[in] payloadLength - Request payload length
254      *  @param[in] formatVersion - Version of the event format
255      *  @param[in] tid - Terminus ID of the event's originator
256      *  @param[in] eventDataOffset - Offset of the event data in the request
257      *                               message
258      *  @return PLDM completion code
259      */
260     int sensorEvent(const pldm_msg* request, size_t payloadLength,
261                     uint8_t formatVersion, uint8_t tid, size_t eventDataOffset);
262 
263     /** @brief Handler for pldmPDRRepositoryChgEvent
264      *
265      *  @param[in] request - Request message
266      *  @param[in] payloadLength - Request payload length
267      *  @param[in] formatVersion - Version of the event format
268      *  @param[in] tid - Terminus ID of the event's originator
269      *  @param[in] eventDataOffset - Offset of the event data in the request
270      *                               message
271      *  @return PLDM completion code
272      */
273     int pldmPDRRepositoryChgEvent(const pldm_msg* request, size_t payloadLength,
274                                   uint8_t formatVersion, uint8_t tid,
275                                   size_t eventDataOffset);
276 
277     /** @brief Handler for extracting the PDR handles from changeEntries
278      *
279      *  @param[in] changeEntryData - ChangeEntry data from changeRecord
280      *  @param[in] changeEntryDataSize - total size of changeEntryData
281      *  @param[in] numberOfChangeEntries - total number of changeEntries to
282      *                                     extract
283      *  @param[out] pdrRecordHandles - std::vector where the extracted PDR
284      *                                 handles are placed
285      *  @return PLDM completion code
286      */
287     int getPDRRecordHandles(const ChangeEntry* changeEntryData,
288                             size_t changeEntryDataSize,
289                             size_t numberOfChangeEntries,
290                             PDRRecordHandles& pdrRecordHandles);
291 
292     /** @brief Handler for setting Sensor event data
293      *
294      *  @param[in] sensorId - sensorID value of the sensor
295      *  @param[in] sensorOffset - Identifies which state sensor within a
296      * composite state sensor the event is being returned for
297      *  @param[in] eventState - The event state value from the state change that
298      * triggered the event message
299      *  @return PLDM completion code
300      */
301     int setSensorEventData(uint16_t sensorId, uint8_t sensorOffset,
302                            uint8_t eventState);
303 
304     /** @brief Function to set the effecter requested by pldm requester
305      *  @param[in] dBusIntf - The interface object
306      *  @param[in] effecterId - Effecter ID sent by the requester to act on
307      *  @param[in] stateField - The state field data for each of the states,
308      * equal to composite effecter count in number
309      *  @return - Success or failure in setting the states. Returns failure in
310      * terms of PLDM completion codes if atleast one state fails to be set
311      */
312     template <class DBusInterface>
313     int setStateEffecterStatesHandler(
314         const DBusInterface& dBusIntf, uint16_t effecterId,
315         const std::vector<set_effecter_state_field>& stateField)
316     {
317         using namespace pldm::responder::pdr;
318         using namespace pldm::utils;
319         using StateSetNum = uint8_t;
320 
321         state_effecter_possible_states* states = nullptr;
322         pldm_state_effecter_pdr* pdr = nullptr;
323         uint8_t compEffecterCnt = stateField.size();
324 
325         std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)>
326             stateEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy);
327         Repo stateEffecterPDRs(stateEffecterPdrRepo.get());
328         getRepoByType(pdrRepo, stateEffecterPDRs, PLDM_STATE_EFFECTER_PDR);
329         if (stateEffecterPDRs.empty())
330         {
331             std::cerr << "Failed to get record by PDR type\n";
332             return PLDM_PLATFORM_INVALID_EFFECTER_ID;
333         }
334 
335         PdrEntry pdrEntry{};
336         auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry);
337         while (pdrRecord)
338         {
339             pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data);
340             if (pdr->effecter_id != effecterId)
341             {
342                 pdr = nullptr;
343                 pdrRecord =
344                     stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry);
345                 continue;
346             }
347 
348             states = reinterpret_cast<state_effecter_possible_states*>(
349                 pdr->possible_states);
350             if (compEffecterCnt > pdr->composite_effecter_count)
351             {
352                 std::cerr << "The requester sent wrong composite effecter"
353                           << " count for the effecter, EFFECTER_ID="
354                           << effecterId << "COMP_EFF_CNT=" << compEffecterCnt
355                           << "\n";
356                 return PLDM_ERROR_INVALID_DATA;
357             }
358             break;
359         }
360 
361         if (!pdr)
362         {
363             return PLDM_PLATFORM_INVALID_EFFECTER_ID;
364         }
365 
366         int rc = PLDM_SUCCESS;
367         try
368         {
369             const auto& [dbusMappings, dbusValMaps] =
370                 effecterDbusObjMaps.at(effecterId);
371             for (uint8_t currState = 0; currState < compEffecterCnt;
372                  ++currState)
373             {
374                 std::vector<StateSetNum> allowed{};
375                 // computation is based on table 79 from DSP0248 v1.1.1
376                 uint8_t bitfieldIndex =
377                     stateField[currState].effecter_state / 8;
378                 uint8_t bit =
379                     stateField[currState].effecter_state - (8 * bitfieldIndex);
380                 if (states->possible_states_size < bitfieldIndex ||
381                     !(states->states[bitfieldIndex].byte & (1 << bit)))
382                 {
383                     std::cerr
384                         << "Invalid state set value, EFFECTER_ID=" << effecterId
385                         << " VALUE=" << stateField[currState].effecter_state
386                         << " COMPOSITE_EFFECTER_ID=" << currState
387                         << " DBUS_PATH=" << dbusMappings[currState].objectPath
388                         << "\n";
389                     rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
390                     break;
391                 }
392                 const DBusMapping& dbusMapping = dbusMappings[currState];
393                 const StatestoDbusVal& dbusValToMap = dbusValMaps[currState];
394 
395                 if (stateField[currState].set_request == PLDM_REQUEST_SET)
396                 {
397                     try
398                     {
399                         dBusIntf.setDbusProperty(
400                             dbusMapping,
401                             dbusValToMap.at(
402                                 stateField[currState].effecter_state));
403                     }
404                     catch (const std::exception& e)
405                     {
406                         std::cerr
407                             << "Error setting property, ERROR=" << e.what()
408                             << " PROPERTY=" << dbusMapping.propertyName
409                             << " INTERFACE="
410                             << dbusMapping.interface << " PATH="
411                             << dbusMapping.objectPath << "\n";
412                         return PLDM_ERROR;
413                     }
414                 }
415                 uint8_t* nextState =
416                     reinterpret_cast<uint8_t*>(states) +
417                     sizeof(state_effecter_possible_states) -
418                     sizeof(states->states) +
419                     (states->possible_states_size * sizeof(states->states));
420                 states = reinterpret_cast<state_effecter_possible_states*>(
421                     nextState);
422             }
423         }
424         catch (const std::out_of_range& e)
425         {
426             std::cerr << "the effecterId does not exist. effecter id: "
427                       << effecterId << e.what() << '\n';
428         }
429 
430         return rc;
431     }
432 
433     /** @brief Build BMC Terminus Locator PDR
434      *
435      *  @param[in] repo - instance of concrete implementation of Repo
436      */
437     void generateTerminusLocatorPDR(Repo& repo);
438 
439   private:
440     pdr_utils::Repo pdrRepo;
441     uint16_t nextEffecterId{};
442     uint16_t nextSensorId{};
443     DbusObjMaps effecterDbusObjMaps{};
444     DbusObjMaps sensorDbusObjMaps{};
445     HostPDRHandler* hostPDRHandler;
446     events::StateSensorHandler stateSensorHandler;
447     DbusToPLDMEvent* dbusToPLDMEventHandler;
448     fru::Handler* fruHandler;
449     const pldm::utils::DBusHandler* dBusIntf;
450     std::string pdrJsonsDir;
451     bool pdrCreated;
452 };
453 
454 } // namespace platform
455 } // namespace responder
456 } // namespace pldm
457