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