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