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