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