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