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