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