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