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