1 2 #include "platform.hpp" 3 4 #include "pdr_numeric_effecter.hpp" 5 #include "pdr_state_effecter.hpp" 6 #include "utils.hpp" 7 8 namespace pldm 9 { 10 namespace responder 11 { 12 namespace platform 13 { 14 15 using InternalFailure = 16 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 17 18 static const Json empty{}; 19 20 using EventEntryMap = std::map<EventEntry, DBusInfo>; 21 22 const EventEntryMap eventEntryMap = { 23 { 24 0x01010007, // SensorID for VMI Port 0 ipv4 = 7, SensorOffset for the 25 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 1 26 // (Valid Configuration) 27 {"/xyz/openbmc_project/network/vmi/intf0/ipv4/addr0", 28 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", true}, 29 }, 30 { 31 0x02010007, // SensorID for VMI Port 0 ipv4 = 7, SensorOffset for the 32 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 2 33 // (Invalid Configuration) 34 {"/xyz/openbmc_project/network/vmi/intf0/ipv4/addr0", 35 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", false}, 36 }, 37 { 38 0x01010008, // SensorID for VMI Port 1 ipv4 = 8, SensorOffset for the 39 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 1 40 // (Valid Configuration) 41 {"/xyz/openbmc_project/network/vmi/intf1/ipv4/addr0", 42 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", true}, 43 }, 44 { 45 0x02010008, // SensorID for VMI Port 1 ipv4 = 8, SensorOffset for the 46 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 2 47 // (Invalid Configuration) 48 {"/xyz/openbmc_project/network/vmi/intf1/ipv4/addr0", 49 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", false}, 50 }}; 51 52 void Handler::addDbusObjMaps( 53 uint16_t effecterId, 54 std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj) 55 { 56 dbusObjMaps.emplace(effecterId, dbusObj); 57 } 58 59 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>& 60 Handler::getDbusObjMaps(uint16_t effecterId) const 61 { 62 return dbusObjMaps.at(effecterId); 63 } 64 65 void Handler::generate(const std::string& dir, Repo& repo) 66 { 67 // A map of PDR type to a lambda that handles creation of that PDR type. 68 // The lambda essentially would parse the platform specific PDR JSONs to 69 // generate the PDR structures. This function iterates through the map to 70 // invoke all lambdas, so that all PDR types can be created. 71 72 const std::map<Type, generatePDR> generateHandlers = { 73 {PLDM_STATE_EFFECTER_PDR, 74 [this](const auto& json, RepoInterface& repo) { 75 pdr_state_effecter::generateStateEffecterPDR<Handler>(json, *this, 76 repo); 77 }}, 78 {PLDM_NUMERIC_EFFECTER_PDR, 79 [this](const auto& json, RepoInterface& repo) { 80 pdr_numeric_effecter::generateNumericEffecterPDR<Handler>( 81 json, *this, repo); 82 }}}; 83 84 Type pdrType{}; 85 for (const auto& dirEntry : fs::directory_iterator(dir)) 86 { 87 try 88 { 89 auto json = readJson(dirEntry.path().string()); 90 if (!json.empty()) 91 { 92 auto effecterPDRs = json.value("effecterPDRs", empty); 93 for (const auto& effecter : effecterPDRs) 94 { 95 pdrType = effecter.value("pdrType", 0); 96 generateHandlers.at(pdrType)(effecter, repo); 97 } 98 } 99 } 100 catch (const InternalFailure& e) 101 { 102 std::cerr << "PDR config directory does not exist or empty, TYPE= " 103 << pdrType << "PATH= " << dirEntry 104 << " ERROR=" << e.what() << "\n"; 105 } 106 catch (const Json::exception& e) 107 { 108 std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType 109 << " ERROR=" << e.what() << "\n"; 110 pldm::utils::reportError( 111 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 112 } 113 catch (const std::exception& e) 114 { 115 std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType 116 << " ERROR=" << e.what() << "\n"; 117 pldm::utils::reportError( 118 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 119 } 120 } 121 } 122 123 Response Handler::getPDR(const pldm_msg* request, size_t payloadLength) 124 { 125 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0); 126 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 127 128 if (payloadLength != PLDM_GET_PDR_REQ_BYTES) 129 { 130 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 131 } 132 133 uint32_t recordHandle{}; 134 uint32_t dataTransferHandle{}; 135 uint8_t transferOpFlag{}; 136 uint16_t reqSizeBytes{}; 137 uint16_t recordChangeNum{}; 138 139 auto rc = decode_get_pdr_req(request, payloadLength, &recordHandle, 140 &dataTransferHandle, &transferOpFlag, 141 &reqSizeBytes, &recordChangeNum); 142 if (rc != PLDM_SUCCESS) 143 { 144 return CmdHandler::ccOnlyResponse(request, rc); 145 } 146 147 uint16_t respSizeBytes{}; 148 uint8_t* recordData = nullptr; 149 try 150 { 151 pdr_utils::PdrEntry e; 152 auto record = pdr::getRecordByHandle(pdrRepo, recordHandle, e); 153 if (record == NULL) 154 { 155 return CmdHandler::ccOnlyResponse( 156 request, PLDM_PLATFORM_INVALID_RECORD_HANDLE); 157 } 158 159 if (reqSizeBytes) 160 { 161 respSizeBytes = e.size; 162 if (respSizeBytes > reqSizeBytes) 163 { 164 respSizeBytes = reqSizeBytes; 165 } 166 recordData = e.data; 167 } 168 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES + 169 respSizeBytes, 170 0); 171 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 172 rc = encode_get_pdr_resp( 173 request->hdr.instance_id, PLDM_SUCCESS, e.handle.nextRecordHandle, 174 0, PLDM_START_AND_END, respSizeBytes, recordData, 0, responsePtr); 175 if (rc != PLDM_SUCCESS) 176 { 177 return ccOnlyResponse(request, rc); 178 } 179 } 180 catch (const std::exception& e) 181 { 182 std::cerr << "Error accessing PDR, HANDLE=" << recordHandle 183 << " ERROR=" << e.what() << "\n"; 184 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR); 185 } 186 return response; 187 } 188 189 Response Handler::setStateEffecterStates(const pldm_msg* request, 190 size_t payloadLength) 191 { 192 Response response( 193 sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0); 194 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 195 uint16_t effecterId; 196 uint8_t compEffecterCnt; 197 constexpr auto maxCompositeEffecterCnt = 8; 198 std::vector<set_effecter_state_field> stateField(maxCompositeEffecterCnt, 199 {0, 0}); 200 201 if ((payloadLength > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) || 202 (payloadLength < sizeof(effecterId) + sizeof(compEffecterCnt) + 203 sizeof(set_effecter_state_field))) 204 { 205 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 206 } 207 208 int rc = decode_set_state_effecter_states_req(request, payloadLength, 209 &effecterId, &compEffecterCnt, 210 stateField.data()); 211 212 if (rc != PLDM_SUCCESS) 213 { 214 return CmdHandler::ccOnlyResponse(request, rc); 215 } 216 217 stateField.resize(compEffecterCnt); 218 const pldm::utils::DBusHandler dBusIntf; 219 rc = setStateEffecterStatesHandler<pldm::utils::DBusHandler>( 220 dBusIntf, effecterId, stateField); 221 if (rc != PLDM_SUCCESS) 222 { 223 return CmdHandler::ccOnlyResponse(request, rc); 224 } 225 226 rc = encode_set_state_effecter_states_resp(request->hdr.instance_id, rc, 227 responsePtr); 228 if (rc != PLDM_SUCCESS) 229 { 230 return ccOnlyResponse(request, rc); 231 } 232 233 return response; 234 } 235 236 Response Handler::platformEventMessage(const pldm_msg* request, 237 size_t payloadLength) 238 { 239 uint8_t formatVersion{}; 240 uint8_t tid{}; 241 uint8_t eventClass{}; 242 size_t offset{}; 243 244 auto rc = decode_platform_event_message_req( 245 request, payloadLength, &formatVersion, &tid, &eventClass, &offset); 246 if (rc != PLDM_SUCCESS) 247 { 248 return CmdHandler::ccOnlyResponse(request, rc); 249 } 250 251 try 252 { 253 const auto& handlers = eventHandlers.at(eventClass); 254 for (const auto& handler : handlers) 255 { 256 auto rc = 257 handler(request, payloadLength, formatVersion, tid, offset); 258 if (rc != PLDM_SUCCESS) 259 { 260 return CmdHandler::ccOnlyResponse(request, rc); 261 } 262 } 263 } 264 catch (const std::out_of_range& e) 265 { 266 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA); 267 } 268 269 Response response( 270 sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES, 0); 271 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 272 273 rc = encode_platform_event_message_resp(request->hdr.instance_id, rc, 274 PLDM_EVENT_NO_LOGGING, responsePtr); 275 if (rc != PLDM_SUCCESS) 276 { 277 return ccOnlyResponse(request, rc); 278 } 279 280 return response; 281 } 282 283 int Handler::sensorEvent(const pldm_msg* request, size_t payloadLength, 284 uint8_t /*formatVersion*/, uint8_t /*tid*/, 285 size_t eventDataOffset) 286 { 287 uint16_t sensorId{}; 288 uint8_t eventClass{}; 289 size_t eventClassDataOffset{}; 290 auto eventData = 291 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 292 auto eventDataSize = payloadLength - eventDataOffset; 293 294 auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId, 295 &eventClass, &eventClassDataOffset); 296 if (rc != PLDM_SUCCESS) 297 { 298 return rc; 299 } 300 301 auto eventClassData = reinterpret_cast<const uint8_t*>(request->payload) + 302 eventDataOffset + eventClassDataOffset; 303 auto eventClassDataSize = 304 payloadLength - eventDataOffset - eventClassDataOffset; 305 306 if (eventClass == PLDM_STATE_SENSOR_STATE) 307 { 308 uint8_t sensorOffset{}; 309 uint8_t eventState{}; 310 uint8_t previousEventState{}; 311 312 rc = decode_state_sensor_data(eventClassData, eventClassDataSize, 313 &sensorOffset, &eventState, 314 &previousEventState); 315 if (rc != PLDM_SUCCESS) 316 { 317 return PLDM_ERROR; 318 } 319 320 rc = setSensorEventData(sensorId, sensorOffset, eventState); 321 322 if (rc != PLDM_SUCCESS) 323 { 324 return PLDM_ERROR; 325 } 326 } 327 else 328 { 329 return PLDM_ERROR_INVALID_DATA; 330 } 331 332 return PLDM_SUCCESS; 333 } 334 335 int Handler::setSensorEventData(uint16_t sensorId, uint8_t sensorOffset, 336 uint8_t eventState) 337 { 338 EventEntry eventEntry = ((static_cast<uint32_t>(eventState)) << 24) + 339 ((static_cast<uint32_t>(sensorOffset)) << 16) + 340 sensorId; 341 auto iter = eventEntryMap.find(eventEntry); 342 if (iter == eventEntryMap.end()) 343 { 344 return PLDM_SUCCESS; 345 } 346 347 const auto& dBusInfo = iter->second; 348 try 349 { 350 pldm::utils::DBusMapping dbusMapping{ 351 dBusInfo.dBusValues.objectPath, dBusInfo.dBusValues.interface, 352 dBusInfo.dBusValues.propertyName, dBusInfo.dBusValues.propertyType}; 353 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, 354 dBusInfo.dBusPropertyValue); 355 } 356 catch (std::exception& e) 357 { 358 359 std::cerr 360 << "Error Setting dbus property,SensorID=" << eventEntry 361 << "DBusInfo=" << dBusInfo.dBusValues.objectPath 362 << dBusInfo.dBusValues.interface << dBusInfo.dBusValues.propertyName 363 << "ERROR=" << e.what() << "\n"; 364 return PLDM_ERROR; 365 } 366 return PLDM_SUCCESS; 367 } 368 369 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request, 370 size_t payloadLength, 371 uint8_t /*formatVersion*/, 372 uint8_t /*tid*/, size_t eventDataOffset) 373 { 374 uint8_t eventDataFormat{}; 375 uint8_t numberOfChangeRecords{}; 376 size_t dataOffset{}; 377 378 auto eventData = 379 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 380 auto eventDataSize = payloadLength - eventDataOffset; 381 382 auto rc = decode_pldm_pdr_repository_chg_event_data( 383 eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords, 384 &dataOffset); 385 if (rc != PLDM_SUCCESS) 386 { 387 return rc; 388 } 389 390 PDRRecordHandles pdrRecordHandles; 391 if (eventDataFormat == FORMAT_IS_PDR_HANDLES) 392 { 393 uint8_t eventDataOperation{}; 394 uint8_t numberOfChangeEntries{}; 395 396 auto changeRecordData = eventData + dataOffset; 397 auto changeRecordDataSize = eventDataSize - dataOffset; 398 399 while (changeRecordDataSize) 400 { 401 rc = decode_pldm_pdr_repository_change_record_data( 402 changeRecordData, changeRecordDataSize, &eventDataOperation, 403 &numberOfChangeEntries, &dataOffset); 404 405 if (rc != PLDM_SUCCESS) 406 { 407 return rc; 408 } 409 410 if (eventDataOperation == PLDM_RECORDS_ADDED) 411 { 412 rc = getPDRRecordHandles( 413 reinterpret_cast<const ChangeEntry*>(changeRecordData + 414 dataOffset), 415 changeRecordDataSize - dataOffset, 416 static_cast<size_t>(numberOfChangeEntries), 417 pdrRecordHandles); 418 419 if (rc != PLDM_SUCCESS) 420 { 421 return rc; 422 } 423 } 424 425 changeRecordData += 426 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 427 changeRecordDataSize -= 428 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 429 } 430 431 if (hostPDRHandler && !pdrRecordHandles.empty()) 432 { 433 hostPDRHandler->fetchPDR(std::move(pdrRecordHandles)); 434 } 435 } 436 else 437 { 438 return PLDM_ERROR_INVALID_DATA; 439 } 440 441 return PLDM_SUCCESS; 442 } 443 444 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData, 445 size_t changeEntryDataSize, 446 size_t numberOfChangeEntries, 447 PDRRecordHandles& pdrRecordHandles) 448 { 449 if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry))) 450 { 451 return PLDM_ERROR_INVALID_DATA; 452 } 453 for (size_t i = 0; i < numberOfChangeEntries; i++) 454 { 455 pdrRecordHandles.push_back(changeEntryData[i]); 456 } 457 return PLDM_SUCCESS; 458 } 459 460 } // namespace platform 461 } // namespace responder 462 } // namespace pldm 463