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