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