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