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