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