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