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