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 '{COMPOSITE_EFFECTER_COUNT}' for the effecter ID '{EFFECTERID}'.", 365 "COMPOSITE_EFFECTER_COUNT", (unsigned)compEffecterCnt, 366 "EFFECTERID", (unsigned)effecterId); 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 for effecter ID '{EFFECTERID}', effecter state '{EFFECTER_STATE}', composite effecter ID '{COMPOSITE_EFFECTER_ID}' and path '{PATH}'.", 396 "EFFECTERID", (unsigned)effecterId, "EFFECTER_STATE", 397 (unsigned)stateField[currState].effecter_state, 398 "COMPOSITE_EFFECTER_COUNT", (unsigned)currState, "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 "Failed to set property '{PROPERTY}' of interface '{INTERFACE}' at path '{PATH}', error - {ERROR}", 420 "PROPERTY", dbusMapping.propertyName, "DBUS_INTF", 421 dbusMapping.interface, "DBUS_OBJ_PATH", 422 dbusMapping.objectPath.c_str(), "ERROR", e); 423 return PLDM_ERROR; 424 } 425 } 426 uint8_t* nextState = 427 reinterpret_cast<uint8_t*>(states) + 428 sizeof(state_effecter_possible_states) - 429 sizeof(states->states) + 430 (states->possible_states_size * sizeof(states->states)); 431 states = reinterpret_cast<state_effecter_possible_states*>( 432 nextState); 433 } 434 } 435 catch (const std::out_of_range& e) 436 { 437 error( 438 "The effecter ID '{EFFECTERID}' does not exist, error - {ERROR}.", 439 "EFFECTERID", (unsigned)effecterId, "ERROR", e); 440 } 441 442 return rc; 443 } 444 445 /** @brief Build BMC Terminus Locator PDR 446 * 447 * @param[in] repo - instance of concrete implementation of Repo 448 */ 449 void generateTerminusLocatorPDR(pldm::responder::pdr_utils::Repo& repo); 450 451 /** @brief Get std::map associated with the entity 452 * key: object path 453 * value: pldm_entity 454 * 455 * @return std::map<ObjectPath, pldm_entity> 456 */ 457 inline const AssociatedEntityMap& getAssociateEntityMap() const 458 { 459 if (fruHandler == nullptr) 460 { 461 throw InternalFailure(); 462 } 463 return fruHandler->getAssociateEntityMap(); 464 } 465 466 /** @brief update the sensor cache map 467 * @param[in] sensorId - sensor id that needs an update 468 * @param[in] sensorRearm - rearm value within the sensor 469 * @param[in] value - value that needs to be cached 470 */ 471 472 inline void updateSensorCache(pldm::pdr::SensorID sensorId, 473 size_t sensorRearm, uint8_t value) 474 { 475 if (dbusToPLDMEventHandler) 476 { 477 dbusToPLDMEventHandler->updateSensorCacheMaps(sensorId, sensorRearm, 478 value); 479 } 480 } 481 482 /** @brief process the actions that needs to be performed after a GetPDR 483 * call is received 484 * @param[in] source - sdeventplus event source 485 */ 486 void _processPostGetPDRActions(sdeventplus::source::EventBase& source); 487 488 /** @brief Method for setEventreceiver */ 489 void setEventReceiver(); 490 491 private: 492 uint8_t eid; 493 InstanceIdDb* instanceIdDb; 494 pdr_utils::Repo pdrRepo; 495 uint16_t nextEffecterId{}; 496 uint16_t nextSensorId{}; 497 DbusObjMaps effecterDbusObjMaps{}; 498 DbusObjMaps sensorDbusObjMaps{}; 499 HostPDRHandler* hostPDRHandler; 500 pldm::state_sensor::DbusToPLDMEvent* dbusToPLDMEventHandler; 501 fru::Handler* fruHandler; 502 const pldm::utils::DBusHandler* dBusIntf; 503 pldm::responder::oem_platform::Handler* oemPlatformHandler; 504 pldm::responder::platform_config::Handler* platformConfigHandler; 505 pldm::requester::Handler<pldm::requester::Request>* handler; 506 sdeventplus::Event& event; 507 fs::path pdrJsonDir; 508 bool pdrCreated; 509 std::vector<fs::path> pdrJsonsDir; 510 std::unique_ptr<sdeventplus::source::Defer> deferredGetPDREvent; 511 }; 512 513 /** @brief Function to check if a sensor falls in OEM range 514 * A sensor is considered to be oem if either of entity 515 * type or state set or both falls in oem range 516 * 517 * @param[in] handler - the interface object 518 * @param[in] sensorId - sensor id 519 * @param[in] sensorRearmCount - sensor rearm count 520 * @param[out] compSensorCnt - composite sensor count 521 * @param[out] entityType - entity type 522 * @param[out] entityInstance - entity instance number 523 * @param[out] stateSetId - state set id 524 * 525 * @return true if the sensor is OEM. All out parameters are invalid 526 * for a non OEM sensor 527 */ 528 bool isOemStateSensor(Handler& handler, uint16_t sensorId, 529 uint8_t sensorRearmCount, uint8_t& compSensorCnt, 530 uint16_t& entityType, uint16_t& entityInstance, 531 uint16_t& stateSetId); 532 533 /** @brief Function to check if an effecter falls in OEM range 534 * An effecter is considered to be oem if either of entity 535 * type or state set or both falls in oem range 536 * 537 * @param[in] handler - the interface object 538 * @param[in] effecterId - effecter id 539 * @param[in] compEffecterCnt - composite effecter count 540 * @param[out] entityType - entity type 541 * @param[out] entityInstance - entity instance number 542 * @param[out] stateSetId - state set id 543 * 544 * @return true if the effecter is OEM. All out parameters are invalid 545 * for a non OEM effecter 546 */ 547 bool isOemStateEffecter(Handler& handler, uint16_t effecterId, 548 uint8_t compEffecterCnt, uint16_t& entityType, 549 uint16_t& entityInstance, uint16_t& stateSetId); 550 551 } // namespace platform 552 } // namespace responder 553 } // namespace pldm 554