1 #pragma once 2 3 #include "config.h" 4 5 #include "libpldm/platform.h" 6 #include "libpldm/states.h" 7 #include "pdr.h" 8 9 #include "common/utils.hpp" 10 #include "event_parser.hpp" 11 #include "fru.hpp" 12 #include "host-bmc/dbus_to_event_handler.hpp" 13 #include "host-bmc/host_pdr_handler.hpp" 14 #include "libpldmresponder/pdr.hpp" 15 #include "libpldmresponder/pdr_utils.hpp" 16 #include "oem_handler.hpp" 17 #include "pldmd/handler.hpp" 18 19 #include <stdint.h> 20 21 #include <map> 22 23 namespace pldm 24 { 25 namespace responder 26 { 27 namespace platform 28 { 29 30 using namespace pldm::utils; 31 using namespace pldm::responder::pdr_utils; 32 using namespace pldm::state_sensor; 33 34 using generatePDR = 35 std::function<void(const pldm::utils::DBusHandler& dBusIntf, 36 const Json& json, pdr_utils::RepoInterface& repo)>; 37 38 using EffecterId = uint16_t; 39 using DbusObjMaps = 40 std::map<EffecterId, 41 std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>>; 42 using DbusPath = std::string; 43 using EffecterObjs = std::vector<DbusPath>; 44 using EventType = uint8_t; 45 using EventHandler = std::function<int( 46 const pldm_msg* request, size_t payloadLength, uint8_t formatVersion, 47 uint8_t tid, size_t eventDataOffset)>; 48 using EventHandlers = std::vector<EventHandler>; 49 using EventMap = std::map<EventType, EventHandlers>; 50 using AssociatedEntityMap = std::map<DbusPath, pldm_entity>; 51 52 class Handler : public CmdHandler 53 { 54 public: 55 Handler(const pldm::utils::DBusHandler* dBusIntf, 56 const std::string& pdrJsonsDir, pldm_pdr* repo, 57 HostPDRHandler* hostPDRHandler, 58 DbusToPLDMEvent* dbusToPLDMEventHandler, fru::Handler* fruHandler, 59 pldm::responder::oem_platform::Handler* oemPlatformHandler, 60 sdeventplus::Event& event, bool buildPDRLazily = false, 61 const std::optional<EventMap>& addOnHandlersMap = std::nullopt) : 62 pdrRepo(repo), 63 hostPDRHandler(hostPDRHandler), 64 dbusToPLDMEventHandler(dbusToPLDMEventHandler), fruHandler(fruHandler), 65 dBusIntf(dBusIntf), oemPlatformHandler(oemPlatformHandler), 66 event(event), pdrJsonsDir(pdrJsonsDir), pdrCreated(false) 67 { 68 if (!buildPDRLazily) 69 { 70 generateTerminusLocatorPDR(pdrRepo); 71 generate(*dBusIntf, pdrJsonsDir, pdrRepo); 72 pdrCreated = true; 73 } 74 75 handlers.emplace(PLDM_GET_PDR, 76 [this](const pldm_msg* request, size_t payloadLength) { 77 return this->getPDR(request, payloadLength); 78 }); 79 handlers.emplace(PLDM_SET_NUMERIC_EFFECTER_VALUE, 80 [this](const pldm_msg* request, size_t payloadLength) { 81 return this->setNumericEffecterValue( 82 request, payloadLength); 83 }); 84 handlers.emplace(PLDM_SET_STATE_EFFECTER_STATES, 85 [this](const pldm_msg* request, size_t payloadLength) { 86 return this->setStateEffecterStates(request, 87 payloadLength); 88 }); 89 handlers.emplace(PLDM_PLATFORM_EVENT_MESSAGE, 90 [this](const pldm_msg* request, size_t payloadLength) { 91 return this->platformEventMessage(request, 92 payloadLength); 93 }); 94 handlers.emplace(PLDM_GET_STATE_SENSOR_READINGS, 95 [this](const pldm_msg* request, size_t payloadLength) { 96 return this->getStateSensorReadings(request, 97 payloadLength); 98 }); 99 100 // Default handler for PLDM Events 101 eventHandlers[PLDM_SENSOR_EVENT].emplace_back( 102 [this](const pldm_msg* request, size_t payloadLength, 103 uint8_t formatVersion, uint8_t tid, size_t eventDataOffset) { 104 return this->sensorEvent(request, payloadLength, formatVersion, 105 tid, eventDataOffset); 106 }); 107 eventHandlers[PLDM_PDR_REPOSITORY_CHG_EVENT].emplace_back( 108 [this](const pldm_msg* request, size_t payloadLength, 109 uint8_t formatVersion, uint8_t tid, size_t eventDataOffset) { 110 return this->pldmPDRRepositoryChgEvent(request, payloadLength, 111 formatVersion, tid, 112 eventDataOffset); 113 }); 114 115 // Additional OEM event handlers for PLDM events, append it to the 116 // standard handlers 117 if (addOnHandlersMap) 118 { 119 auto addOnHandlers = addOnHandlersMap.value(); 120 for (EventMap::iterator iter = addOnHandlers.begin(); 121 iter != addOnHandlers.end(); ++iter) 122 { 123 auto search = eventHandlers.find(iter->first); 124 if (search != eventHandlers.end()) 125 { 126 search->second.insert(std::end(search->second), 127 std::begin(iter->second), 128 std::end(iter->second)); 129 } 130 else 131 { 132 eventHandlers.emplace(iter->first, iter->second); 133 } 134 } 135 } 136 } 137 138 pdr_utils::Repo& getRepo() 139 { 140 return this->pdrRepo; 141 } 142 143 /** @brief Add D-Bus mapping and value mapping(stateId to D-Bus) for the 144 * Id. If the same id is added, the previous dbusObjs will 145 * be "over-written". 146 * 147 * @param[in] Id - effecter/sensor id 148 * @param[in] dbusObj - list of D-Bus object structure and list of D-Bus 149 * property value to attribute value 150 * @param[in] typeId - the type id of enum 151 */ 152 void addDbusObjMaps( 153 uint16_t id, 154 std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj, 155 TypeId typeId = TypeId::PLDM_EFFECTER_ID); 156 157 /** @brief Retrieve an id -> D-Bus objects mapping 158 * 159 * @param[in] Id - id 160 * @param[in] typeId - the type id of enum 161 * 162 * @return std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> - 163 * list of D-Bus object structure and list of D-Bus property value 164 * to attribute value 165 */ 166 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>& 167 getDbusObjMaps(uint16_t id, 168 TypeId typeId = TypeId::PLDM_EFFECTER_ID) const; 169 170 uint16_t getNextEffecterId() 171 { 172 return ++nextEffecterId; 173 } 174 175 uint16_t getNextSensorId() 176 { 177 return ++nextSensorId; 178 } 179 180 /** @brief Parse PDR JSONs and build PDR repository 181 * 182 * @param[in] dBusIntf - The interface object 183 * @param[in] dir - directory housing platform specific PDR JSON files 184 * @param[in] repo - instance of concrete implementation of Repo 185 */ 186 void generate(const pldm::utils::DBusHandler& dBusIntf, 187 const std::string& dir, Repo& repo); 188 189 /** @brief Parse PDR JSONs and build state effecter PDR repository 190 * 191 * @param[in] json - platform specific PDR JSON files 192 * @param[in] repo - instance of state effecter implementation of Repo 193 */ 194 void generateStateEffecterRepo(const Json& json, Repo& repo); 195 196 /** @brief map of PLDM event type to EventHandlers 197 * 198 */ 199 EventMap eventHandlers; 200 201 /** @brief Handler for GetPDR 202 * 203 * @param[in] request - Request message payload 204 * @param[in] payloadLength - Request payload length 205 * @param[out] Response - Response message written here 206 */ 207 Response getPDR(const pldm_msg* request, size_t payloadLength); 208 209 /** @brief Handler for setNumericEffecterValue 210 * 211 * @param[in] request - Request message 212 * @param[in] payloadLength - Request payload length 213 * @return Response - PLDM Response message 214 */ 215 Response setNumericEffecterValue(const pldm_msg* request, 216 size_t payloadLength); 217 218 /** @brief Handler for getStateSensorReadings 219 * 220 * @param[in] request - Request message 221 * @param[in] payloadLength - Request payload length 222 * @return Response - PLDM Response message 223 */ 224 Response getStateSensorReadings(const pldm_msg* request, 225 size_t payloadLength); 226 227 /** @brief Handler for setStateEffecterStates 228 * 229 * @param[in] request - Request message 230 * @param[in] payloadLength - Request payload length 231 * @return Response - PLDM Response message 232 */ 233 Response setStateEffecterStates(const pldm_msg* request, 234 size_t payloadLength); 235 236 /** @brief Handler for PlatformEventMessage 237 * 238 * @param[in] request - Request message 239 * @param[in] payloadLength - Request payload length 240 * @return Response - PLDM Response message 241 */ 242 Response platformEventMessage(const pldm_msg* request, 243 size_t payloadLength); 244 245 /** @brief Handler for event class Sensor event 246 * 247 * @param[in] request - Request message 248 * @param[in] payloadLength - Request payload length 249 * @param[in] formatVersion - Version of the event format 250 * @param[in] tid - Terminus ID of the event's originator 251 * @param[in] eventDataOffset - Offset of the event data in the request 252 * message 253 * @return PLDM completion code 254 */ 255 int sensorEvent(const pldm_msg* request, size_t payloadLength, 256 uint8_t formatVersion, uint8_t tid, size_t eventDataOffset); 257 258 /** @brief Handler for pldmPDRRepositoryChgEvent 259 * 260 * @param[in] request - Request message 261 * @param[in] payloadLength - Request payload length 262 * @param[in] formatVersion - Version of the event format 263 * @param[in] tid - Terminus ID of the event's originator 264 * @param[in] eventDataOffset - Offset of the event data in the request 265 * message 266 * @return PLDM completion code 267 */ 268 int pldmPDRRepositoryChgEvent(const pldm_msg* request, size_t payloadLength, 269 uint8_t formatVersion, uint8_t tid, 270 size_t eventDataOffset); 271 272 /** @brief Handler for extracting the PDR handles from changeEntries 273 * 274 * @param[in] changeEntryData - ChangeEntry data from changeRecord 275 * @param[in] changeEntryDataSize - total size of changeEntryData 276 * @param[in] numberOfChangeEntries - total number of changeEntries to 277 * extract 278 * @param[out] pdrRecordHandles - std::vector where the extracted PDR 279 * handles are placed 280 * @return PLDM completion code 281 */ 282 int getPDRRecordHandles(const ChangeEntry* changeEntryData, 283 size_t changeEntryDataSize, 284 size_t numberOfChangeEntries, 285 PDRRecordHandles& pdrRecordHandles); 286 287 /** @brief Function to set the effecter requested by pldm requester 288 * @param[in] dBusIntf - The interface object 289 * @param[in] effecterId - Effecter ID sent by the requester to act on 290 * @param[in] stateField - The state field data for each of the states, 291 * equal to composite effecter count in number 292 * @return - Success or failure in setting the states. Returns failure in 293 * terms of PLDM completion codes if atleast one state fails to be set 294 */ 295 template <class DBusInterface> 296 int setStateEffecterStatesHandler( 297 const DBusInterface& dBusIntf, uint16_t effecterId, 298 const std::vector<set_effecter_state_field>& stateField) 299 { 300 using namespace pldm::responder::pdr; 301 using namespace pldm::utils; 302 using StateSetNum = uint8_t; 303 304 state_effecter_possible_states* states = nullptr; 305 pldm_state_effecter_pdr* pdr = nullptr; 306 uint8_t compEffecterCnt = stateField.size(); 307 308 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> 309 stateEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy); 310 Repo stateEffecterPDRs(stateEffecterPdrRepo.get()); 311 getRepoByType(pdrRepo, stateEffecterPDRs, PLDM_STATE_EFFECTER_PDR); 312 if (stateEffecterPDRs.empty()) 313 { 314 std::cerr << "Failed to get record by PDR type\n"; 315 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 316 } 317 318 PdrEntry pdrEntry{}; 319 auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry); 320 while (pdrRecord) 321 { 322 pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data); 323 if (pdr->effecter_id != effecterId) 324 { 325 pdr = nullptr; 326 pdrRecord = 327 stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); 328 continue; 329 } 330 331 states = reinterpret_cast<state_effecter_possible_states*>( 332 pdr->possible_states); 333 if (compEffecterCnt > pdr->composite_effecter_count) 334 { 335 std::cerr << "The requester sent wrong composite effecter" 336 << " count for the effecter, EFFECTER_ID=" 337 << (unsigned)effecterId 338 << "COMP_EFF_CNT=" << (unsigned)compEffecterCnt 339 << "\n"; 340 return PLDM_ERROR_INVALID_DATA; 341 } 342 break; 343 } 344 345 if (!pdr) 346 { 347 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 348 } 349 350 int rc = PLDM_SUCCESS; 351 try 352 { 353 const auto& [dbusMappings, dbusValMaps] = 354 effecterDbusObjMaps.at(effecterId); 355 for (uint8_t currState = 0; currState < compEffecterCnt; 356 ++currState) 357 { 358 std::vector<StateSetNum> allowed{}; 359 // computation is based on table 79 from DSP0248 v1.1.1 360 uint8_t bitfieldIndex = 361 stateField[currState].effecter_state / 8; 362 uint8_t bit = 363 stateField[currState].effecter_state - (8 * bitfieldIndex); 364 if (states->possible_states_size < bitfieldIndex || 365 !(states->states[bitfieldIndex].byte & (1 << bit))) 366 { 367 std::cerr 368 << "Invalid state set value, EFFECTER_ID=" 369 << (unsigned)effecterId << " VALUE=" 370 << (unsigned)stateField[currState].effecter_state 371 << " COMPOSITE_EFFECTER_ID=" << (unsigned)currState 372 << " DBUS_PATH=" << dbusMappings[currState].objectPath 373 << "\n"; 374 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE; 375 break; 376 } 377 const DBusMapping& dbusMapping = dbusMappings[currState]; 378 const StatestoDbusVal& dbusValToMap = dbusValMaps[currState]; 379 380 if (stateField[currState].set_request == PLDM_REQUEST_SET) 381 { 382 try 383 { 384 dBusIntf.setDbusProperty( 385 dbusMapping, 386 dbusValToMap.at( 387 stateField[currState].effecter_state)); 388 } 389 catch (const std::exception& e) 390 { 391 std::cerr 392 << "Error setting property, ERROR=" << e.what() 393 << " PROPERTY=" << dbusMapping.propertyName 394 << " INTERFACE=" 395 << dbusMapping.interface << " PATH=" 396 << dbusMapping.objectPath << "\n"; 397 return PLDM_ERROR; 398 } 399 } 400 uint8_t* nextState = 401 reinterpret_cast<uint8_t*>(states) + 402 sizeof(state_effecter_possible_states) - 403 sizeof(states->states) + 404 (states->possible_states_size * sizeof(states->states)); 405 states = reinterpret_cast<state_effecter_possible_states*>( 406 nextState); 407 } 408 } 409 catch (const std::out_of_range& e) 410 { 411 std::cerr << "the effecterId does not exist. effecter id: " 412 << (unsigned)effecterId << e.what() << '\n'; 413 } 414 415 return rc; 416 } 417 418 /** @brief Build BMC Terminus Locator PDR 419 * 420 * @param[in] repo - instance of concrete implementation of Repo 421 */ 422 void generateTerminusLocatorPDR(Repo& repo); 423 424 /** @brief Get std::map associated with the entity 425 * key: object path 426 * value: pldm_entity 427 * 428 * @return std::map<ObjectPath, pldm_entity> 429 */ 430 inline const AssociatedEntityMap& getAssociateEntityMap() const 431 { 432 if (fruHandler == nullptr) 433 { 434 throw InternalFailure(); 435 } 436 return fruHandler->getAssociateEntityMap(); 437 } 438 439 /** @brief process the actions that needs to be performed after a GetPDR 440 * call is received 441 * @param[in] source - sdeventplus event source 442 */ 443 void _processPostGetPDRActions(sdeventplus::source::EventBase& source); 444 445 private: 446 pdr_utils::Repo pdrRepo; 447 uint16_t nextEffecterId{}; 448 uint16_t nextSensorId{}; 449 DbusObjMaps effecterDbusObjMaps{}; 450 DbusObjMaps sensorDbusObjMaps{}; 451 HostPDRHandler* hostPDRHandler; 452 DbusToPLDMEvent* dbusToPLDMEventHandler; 453 fru::Handler* fruHandler; 454 const pldm::utils::DBusHandler* dBusIntf; 455 pldm::responder::oem_platform::Handler* oemPlatformHandler; 456 sdeventplus::Event& event; 457 std::string pdrJsonsDir; 458 bool pdrCreated; 459 std::unique_ptr<sdeventplus::source::Defer> deferredGetPDREvent; 460 }; 461 462 /** @brief Function to check if a sensor falls in OEM range 463 * A sensor is considered to be oem if either of entity 464 * type or state set or both falls in oem range 465 * 466 * @param[in] handler - the interface object 467 * @param[in] sensorId - sensor id 468 * @param[in] sensorRearmCount - sensor rearm count 469 * @param[out] compSensorCnt - composite sensor count 470 * @param[out] entityType - entity type 471 * @param[out] entityInstance - entity instance number 472 * @param[out] stateSetId - state set id 473 * 474 * @return true if the sensor is OEM. All out parameters are invalid 475 * for a non OEM sensor 476 */ 477 bool isOemStateSensor(Handler& handler, uint16_t sensorId, 478 uint8_t sensorRearmCount, uint8_t& compSensorCnt, 479 uint16_t& entityType, uint16_t& entityInstance, 480 uint16_t& stateSetId); 481 482 /** @brief Function to check if an effecter falls in OEM range 483 * An effecter is considered to be oem if either of entity 484 * type or state set or both falls in oem range 485 * 486 * @param[in] handler - the interface object 487 * @param[in] effecterId - effecter id 488 * @param[in] compEffecterCnt - composite effecter count 489 * @param[out] entityType - entity type 490 * @param[out] entityInstance - entity instance number 491 * @param[out] stateSetId - state set id 492 * 493 * @return true if the effecter is OEM. All out parameters are invalid 494 * for a non OEM effecter 495 */ 496 bool isOemStateEffecter(Handler& handler, uint16_t effecterId, 497 uint8_t compEffecterCnt, uint16_t& entityType, 498 uint16_t& entityInstance, uint16_t& stateSetId); 499 500 } // namespace platform 501 } // namespace responder 502 } // namespace pldm 503