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