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