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