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