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