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