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