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