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 <map> 21 22 namespace pldm 23 { 24 namespace responder 25 { 26 namespace platform 27 { 28 29 using generatePDR = std::function<void(const pldm::utils::DBusHandler& dBusIntf, 30 const pldm::utils::Json& json, 31 pdr_utils::RepoInterface& repo)>; 32 33 using EffecterId = uint16_t; 34 using DbusObjMaps = 35 std::map<EffecterId, 36 std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>>; 37 using DbusPath = std::string; 38 using EffecterObjs = std::vector<DbusPath>; 39 using EventType = uint8_t; 40 using EventHandler = std::function<int( 41 const pldm_msg* request, size_t payloadLength, uint8_t formatVersion, 42 uint8_t tid, size_t eventDataOffset)>; 43 using EventHandlers = std::vector<EventHandler>; 44 using EventMap = std::map<EventType, EventHandlers>; 45 using AssociatedEntityMap = std::map<DbusPath, pldm_entity>; 46 47 class Handler : public CmdHandler 48 { 49 public: 50 Handler(const pldm::utils::DBusHandler* dBusIntf, 51 const std::string& pdrJsonsDir, pldm_pdr* repo, 52 HostPDRHandler* hostPDRHandler, 53 pldm::state_sensor::DbusToPLDMEvent* dbusToPLDMEventHandler, 54 fru::Handler* fruHandler, 55 pldm::responder::oem_platform::Handler* oemPlatformHandler, 56 sdeventplus::Event& event, bool buildPDRLazily = false, 57 const std::optional<EventMap>& addOnHandlersMap = std::nullopt) : 58 pdrRepo(repo), 59 hostPDRHandler(hostPDRHandler), 60 dbusToPLDMEventHandler(dbusToPLDMEventHandler), fruHandler(fruHandler), 61 dBusIntf(dBusIntf), oemPlatformHandler(oemPlatformHandler), 62 event(event), pdrJsonsDir(pdrJsonsDir), pdrCreated(false) 63 { 64 if (!buildPDRLazily) 65 { 66 generateTerminusLocatorPDR(pdrRepo); 67 generate(*dBusIntf, pdrJsonsDir, pdrRepo); 68 pdrCreated = true; 69 } 70 71 handlers.emplace(PLDM_GET_PDR, 72 [this](const pldm_msg* request, size_t payloadLength) { 73 return this->getPDR(request, payloadLength); 74 }); 75 handlers.emplace(PLDM_SET_NUMERIC_EFFECTER_VALUE, 76 [this](const pldm_msg* request, size_t payloadLength) { 77 return this->setNumericEffecterValue( 78 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, 83 payloadLength); 84 }); 85 handlers.emplace(PLDM_PLATFORM_EVENT_MESSAGE, 86 [this](const pldm_msg* request, size_t payloadLength) { 87 return this->platformEventMessage(request, 88 payloadLength); 89 }); 90 handlers.emplace(PLDM_GET_STATE_SENSOR_READINGS, 91 [this](const pldm_msg* request, size_t payloadLength) { 92 return this->getStateSensorReadings(request, 93 payloadLength); 94 }); 95 96 // Default handler for PLDM Events 97 eventHandlers[PLDM_SENSOR_EVENT].emplace_back( 98 [this](const pldm_msg* request, size_t payloadLength, 99 uint8_t formatVersion, uint8_t tid, size_t eventDataOffset) { 100 return this->sensorEvent(request, payloadLength, formatVersion, 101 tid, eventDataOffset); 102 }); 103 eventHandlers[PLDM_PDR_REPOSITORY_CHG_EVENT].emplace_back( 104 [this](const pldm_msg* request, size_t payloadLength, 105 uint8_t formatVersion, uint8_t tid, size_t eventDataOffset) { 106 return this->pldmPDRRepositoryChgEvent(request, payloadLength, 107 formatVersion, tid, 108 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 getStateSensorReadings 220 * 221 * @param[in] request - Request message 222 * @param[in] payloadLength - Request payload length 223 * @return Response - PLDM Response message 224 */ 225 Response getStateSensorReadings(const pldm_msg* request, 226 size_t payloadLength); 227 228 /** @brief Handler for setStateEffecterStates 229 * 230 * @param[in] request - Request message 231 * @param[in] payloadLength - Request payload length 232 * @return Response - PLDM Response message 233 */ 234 Response setStateEffecterStates(const pldm_msg* request, 235 size_t payloadLength); 236 237 /** @brief Handler for PlatformEventMessage 238 * 239 * @param[in] request - Request message 240 * @param[in] payloadLength - Request payload length 241 * @return Response - PLDM Response message 242 */ 243 Response platformEventMessage(const pldm_msg* request, 244 size_t payloadLength); 245 246 /** @brief Handler for event class Sensor event 247 * 248 * @param[in] request - Request message 249 * @param[in] payloadLength - Request payload length 250 * @param[in] formatVersion - Version of the event format 251 * @param[in] tid - Terminus ID of the event's originator 252 * @param[in] eventDataOffset - Offset of the event data in the request 253 * message 254 * @return PLDM completion code 255 */ 256 int sensorEvent(const pldm_msg* request, size_t payloadLength, 257 uint8_t formatVersion, uint8_t tid, size_t eventDataOffset); 258 259 /** @brief Handler for pldmPDRRepositoryChgEvent 260 * 261 * @param[in] request - Request message 262 * @param[in] payloadLength - Request payload length 263 * @param[in] formatVersion - Version of the event format 264 * @param[in] tid - Terminus ID of the event's originator 265 * @param[in] eventDataOffset - Offset of the event data in the request 266 * message 267 * @return PLDM completion code 268 */ 269 int pldmPDRRepositoryChgEvent(const pldm_msg* request, size_t payloadLength, 270 uint8_t formatVersion, uint8_t tid, 271 size_t eventDataOffset); 272 273 /** @brief Handler for extracting the PDR handles from changeEntries 274 * 275 * @param[in] changeEntryData - ChangeEntry data from changeRecord 276 * @param[in] changeEntryDataSize - total size of changeEntryData 277 * @param[in] numberOfChangeEntries - total number of changeEntries to 278 * extract 279 * @param[out] pdrRecordHandles - std::vector where the extracted PDR 280 * handles are placed 281 * @return PLDM completion code 282 */ 283 int getPDRRecordHandles(const ChangeEntry* changeEntryData, 284 size_t changeEntryDataSize, 285 size_t numberOfChangeEntries, 286 PDRRecordHandles& pdrRecordHandles); 287 288 /** @brief Function to set the effecter requested by pldm requester 289 * @param[in] dBusIntf - The interface object 290 * @param[in] effecterId - Effecter ID sent by the requester to act on 291 * @param[in] stateField - The state field data for each of the states, 292 * equal to composite effecter count in number 293 * @return - Success or failure in setting the states. Returns failure in 294 * terms of PLDM completion codes if atleast one state fails to be set 295 */ 296 template <class DBusInterface> 297 int setStateEffecterStatesHandler( 298 const DBusInterface& dBusIntf, uint16_t effecterId, 299 const std::vector<set_effecter_state_field>& stateField) 300 { 301 using namespace pldm::responder::pdr; 302 using namespace pldm::utils; 303 using StateSetNum = uint8_t; 304 305 state_effecter_possible_states* states = nullptr; 306 pldm_state_effecter_pdr* pdr = nullptr; 307 uint8_t compEffecterCnt = stateField.size(); 308 309 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> 310 stateEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy); 311 pldm::responder::pdr_utils::Repo stateEffecterPDRs( 312 stateEffecterPdrRepo.get()); 313 getRepoByType(pdrRepo, stateEffecterPDRs, PLDM_STATE_EFFECTER_PDR); 314 if (stateEffecterPDRs.empty()) 315 { 316 std::cerr << "Failed to get record by PDR type\n"; 317 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 318 } 319 320 pldm::responder::pdr_utils::PdrEntry pdrEntry{}; 321 auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry); 322 while (pdrRecord) 323 { 324 pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data); 325 if (pdr->effecter_id != effecterId) 326 { 327 pdr = nullptr; 328 pdrRecord = 329 stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); 330 continue; 331 } 332 333 states = reinterpret_cast<state_effecter_possible_states*>( 334 pdr->possible_states); 335 if (compEffecterCnt > pdr->composite_effecter_count) 336 { 337 std::cerr << "The requester sent wrong composite effecter" 338 << " count for the effecter, EFFECTER_ID=" 339 << (unsigned)effecterId 340 << "COMP_EFF_CNT=" << (unsigned)compEffecterCnt 341 << "\n"; 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, dbusValMaps] = 356 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 = 363 stateField[currState].effecter_state / 8; 364 uint8_t bit = 365 stateField[currState].effecter_state - (8 * bitfieldIndex); 366 if (states->possible_states_size < bitfieldIndex || 367 !(states->states[bitfieldIndex].byte & (1 << bit))) 368 { 369 std::cerr 370 << "Invalid state set value, EFFECTER_ID=" 371 << (unsigned)effecterId << " VALUE=" 372 << (unsigned)stateField[currState].effecter_state 373 << " COMPOSITE_EFFECTER_ID=" << (unsigned)currState 374 << " DBUS_PATH=" << dbusMappings[currState].objectPath 375 << "\n"; 376 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE; 377 break; 378 } 379 const DBusMapping& dbusMapping = dbusMappings[currState]; 380 const pldm::responder::pdr_utils::StatestoDbusVal& 381 dbusValToMap = dbusValMaps[currState]; 382 383 if (stateField[currState].set_request == PLDM_REQUEST_SET) 384 { 385 try 386 { 387 dBusIntf.setDbusProperty( 388 dbusMapping, 389 dbusValToMap.at( 390 stateField[currState].effecter_state)); 391 } 392 catch (const std::exception& e) 393 { 394 std::cerr 395 << "Error setting property, ERROR=" << e.what() 396 << " PROPERTY=" << dbusMapping.propertyName 397 << " INTERFACE=" 398 << dbusMapping.interface << " PATH=" 399 << dbusMapping.objectPath << "\n"; 400 return PLDM_ERROR; 401 } 402 } 403 uint8_t* nextState = 404 reinterpret_cast<uint8_t*>(states) + 405 sizeof(state_effecter_possible_states) - 406 sizeof(states->states) + 407 (states->possible_states_size * sizeof(states->states)); 408 states = reinterpret_cast<state_effecter_possible_states*>( 409 nextState); 410 } 411 } 412 catch (const std::out_of_range& e) 413 { 414 std::cerr << "the effecterId does not exist. effecter id: " 415 << (unsigned)effecterId << e.what() << '\n'; 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