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