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