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/hypervisor/eth0/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/hypervisor/eth0/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/hypervisor/eth1/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/hypervisor/eth1/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 if (!pdrCreated) 139 { 140 generate(*dBusIntf, pdrJsonsDir, pdrRepo); 141 pdrCreated = true; 142 } 143 144 // Build FRU table if not built, since entity association PDR's are built 145 // when the FRU table is constructed. 146 if (fruHandler) 147 { 148 fruHandler->buildFRUTable(); 149 } 150 151 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0); 152 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 153 154 if (payloadLength != PLDM_GET_PDR_REQ_BYTES) 155 { 156 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 157 } 158 159 uint32_t recordHandle{}; 160 uint32_t dataTransferHandle{}; 161 uint8_t transferOpFlag{}; 162 uint16_t reqSizeBytes{}; 163 uint16_t recordChangeNum{}; 164 165 auto rc = decode_get_pdr_req(request, payloadLength, &recordHandle, 166 &dataTransferHandle, &transferOpFlag, 167 &reqSizeBytes, &recordChangeNum); 168 if (rc != PLDM_SUCCESS) 169 { 170 return CmdHandler::ccOnlyResponse(request, rc); 171 } 172 173 uint16_t respSizeBytes{}; 174 uint8_t* recordData = nullptr; 175 try 176 { 177 pdr_utils::PdrEntry e; 178 auto record = pdr::getRecordByHandle(pdrRepo, recordHandle, e); 179 if (record == NULL) 180 { 181 return CmdHandler::ccOnlyResponse( 182 request, PLDM_PLATFORM_INVALID_RECORD_HANDLE); 183 } 184 185 if (reqSizeBytes) 186 { 187 respSizeBytes = e.size; 188 if (respSizeBytes > reqSizeBytes) 189 { 190 respSizeBytes = reqSizeBytes; 191 } 192 recordData = e.data; 193 } 194 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES + 195 respSizeBytes, 196 0); 197 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 198 rc = encode_get_pdr_resp( 199 request->hdr.instance_id, PLDM_SUCCESS, e.handle.nextRecordHandle, 200 0, PLDM_START_AND_END, respSizeBytes, recordData, 0, responsePtr); 201 if (rc != PLDM_SUCCESS) 202 { 203 return ccOnlyResponse(request, rc); 204 } 205 } 206 catch (const std::exception& e) 207 { 208 std::cerr << "Error accessing PDR, HANDLE=" << recordHandle 209 << " ERROR=" << e.what() << "\n"; 210 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR); 211 } 212 return response; 213 } 214 215 Response Handler::setStateEffecterStates(const pldm_msg* request, 216 size_t payloadLength) 217 { 218 Response response( 219 sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0); 220 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 221 uint16_t effecterId; 222 uint8_t compEffecterCnt; 223 constexpr auto maxCompositeEffecterCnt = 8; 224 std::vector<set_effecter_state_field> stateField(maxCompositeEffecterCnt, 225 {0, 0}); 226 227 if ((payloadLength > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) || 228 (payloadLength < sizeof(effecterId) + sizeof(compEffecterCnt) + 229 sizeof(set_effecter_state_field))) 230 { 231 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 232 } 233 234 int rc = decode_set_state_effecter_states_req(request, payloadLength, 235 &effecterId, &compEffecterCnt, 236 stateField.data()); 237 238 if (rc != PLDM_SUCCESS) 239 { 240 return CmdHandler::ccOnlyResponse(request, rc); 241 } 242 243 stateField.resize(compEffecterCnt); 244 const pldm::utils::DBusHandler dBusIntf; 245 rc = platform_state_effecter::setStateEffecterStatesHandler< 246 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 247 stateField); 248 if (rc != PLDM_SUCCESS) 249 { 250 return CmdHandler::ccOnlyResponse(request, rc); 251 } 252 253 rc = encode_set_state_effecter_states_resp(request->hdr.instance_id, rc, 254 responsePtr); 255 if (rc != PLDM_SUCCESS) 256 { 257 return ccOnlyResponse(request, rc); 258 } 259 260 return response; 261 } 262 263 Response Handler::platformEventMessage(const pldm_msg* request, 264 size_t payloadLength) 265 { 266 uint8_t formatVersion{}; 267 uint8_t tid{}; 268 uint8_t eventClass{}; 269 size_t offset{}; 270 271 auto rc = decode_platform_event_message_req( 272 request, payloadLength, &formatVersion, &tid, &eventClass, &offset); 273 if (rc != PLDM_SUCCESS) 274 { 275 return CmdHandler::ccOnlyResponse(request, rc); 276 } 277 278 try 279 { 280 const auto& handlers = eventHandlers.at(eventClass); 281 for (const auto& handler : handlers) 282 { 283 auto rc = 284 handler(request, payloadLength, formatVersion, tid, offset); 285 if (rc != PLDM_SUCCESS) 286 { 287 return CmdHandler::ccOnlyResponse(request, rc); 288 } 289 } 290 } 291 catch (const std::out_of_range& e) 292 { 293 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA); 294 } 295 296 Response response( 297 sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES, 0); 298 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 299 300 rc = encode_platform_event_message_resp(request->hdr.instance_id, rc, 301 PLDM_EVENT_NO_LOGGING, responsePtr); 302 if (rc != PLDM_SUCCESS) 303 { 304 return ccOnlyResponse(request, rc); 305 } 306 307 return response; 308 } 309 310 int Handler::sensorEvent(const pldm_msg* request, size_t payloadLength, 311 uint8_t /*formatVersion*/, uint8_t tid, 312 size_t eventDataOffset) 313 { 314 uint16_t sensorId{}; 315 uint8_t eventClass{}; 316 size_t eventClassDataOffset{}; 317 auto eventData = 318 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 319 auto eventDataSize = payloadLength - eventDataOffset; 320 321 auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId, 322 &eventClass, &eventClassDataOffset); 323 if (rc != PLDM_SUCCESS) 324 { 325 return rc; 326 } 327 328 auto eventClassData = reinterpret_cast<const uint8_t*>(request->payload) + 329 eventDataOffset + eventClassDataOffset; 330 auto eventClassDataSize = 331 payloadLength - eventDataOffset - eventClassDataOffset; 332 333 if (eventClass == PLDM_STATE_SENSOR_STATE) 334 { 335 uint8_t sensorOffset{}; 336 uint8_t eventState{}; 337 uint8_t previousEventState{}; 338 339 rc = decode_state_sensor_data(eventClassData, eventClassDataSize, 340 &sensorOffset, &eventState, 341 &previousEventState); 342 if (rc != PLDM_SUCCESS) 343 { 344 return PLDM_ERROR; 345 } 346 347 // Emitting state sensor event signal 348 emitStateSensorEventSignal(tid, sensorId, sensorOffset, eventState, 349 previousEventState); 350 351 // Handle PLDM events for which PDR is not available, setSensorEventData 352 // will return PLDM_ERROR_INVALID_DATA if the sensorID is not found in 353 // the hardcoded sensor list. 354 rc = setSensorEventData(sensorId, sensorOffset, eventState); 355 if (rc != PLDM_ERROR_INVALID_DATA) 356 { 357 return rc; 358 } 359 360 // If there are no HOST PDR's, there is no further action 361 if (hostPDRHandler == NULL) 362 { 363 return PLDM_SUCCESS; 364 } 365 366 // Handle PLDM events for which PDR is available 367 SensorEntry sensorEntry{tid, sensorId}; 368 try 369 { 370 const auto& [entityInfo, compositeSensorStates] = 371 hostPDRHandler->lookupSensorInfo(sensorEntry); 372 if (sensorOffset >= compositeSensorStates.size()) 373 { 374 return PLDM_ERROR_INVALID_DATA; 375 } 376 377 const auto& possibleStates = compositeSensorStates[sensorOffset]; 378 if (possibleStates.find(eventState) == possibleStates.end()) 379 { 380 return PLDM_ERROR_INVALID_DATA; 381 } 382 383 const auto& [containerId, entityType, entityInstance] = entityInfo; 384 events::StateSensorEntry stateSensorEntry{ 385 containerId, entityType, entityInstance, sensorOffset}; 386 return stateSensorHandler.eventAction(stateSensorEntry, eventState); 387 } 388 // If there is no mapping for events return PLDM_SUCCESS 389 catch (const std::out_of_range& e) 390 { 391 return PLDM_SUCCESS; 392 } 393 } 394 else 395 { 396 return PLDM_ERROR_INVALID_DATA; 397 } 398 399 return PLDM_SUCCESS; 400 } 401 402 int Handler::setSensorEventData(uint16_t sensorId, uint8_t sensorOffset, 403 uint8_t eventState) 404 { 405 EventEntry eventEntry = ((static_cast<uint32_t>(eventState)) << 24) + 406 ((static_cast<uint32_t>(sensorOffset)) << 16) + 407 sensorId; 408 auto iter = eventEntryMap.find(eventEntry); 409 if (iter == eventEntryMap.end()) 410 { 411 return PLDM_ERROR_INVALID_DATA; 412 } 413 414 const auto& dBusInfo = iter->second; 415 try 416 { 417 pldm::utils::DBusMapping dbusMapping{ 418 dBusInfo.dBusValues.objectPath, dBusInfo.dBusValues.interface, 419 dBusInfo.dBusValues.propertyName, dBusInfo.dBusValues.propertyType}; 420 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, 421 dBusInfo.dBusPropertyValue); 422 } 423 catch (std::exception& e) 424 { 425 std::cerr 426 << "Error Setting dbus property,SensorID=" << eventEntry 427 << "DBusInfo=" << dBusInfo.dBusValues.objectPath 428 << dBusInfo.dBusValues.interface << dBusInfo.dBusValues.propertyName 429 << "ERROR=" << e.what() << "\n"; 430 return PLDM_ERROR; 431 } 432 return PLDM_SUCCESS; 433 } 434 435 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request, 436 size_t payloadLength, 437 uint8_t /*formatVersion*/, 438 uint8_t /*tid*/, size_t eventDataOffset) 439 { 440 uint8_t eventDataFormat{}; 441 uint8_t numberOfChangeRecords{}; 442 size_t dataOffset{}; 443 444 auto eventData = 445 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 446 auto eventDataSize = payloadLength - eventDataOffset; 447 448 auto rc = decode_pldm_pdr_repository_chg_event_data( 449 eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords, 450 &dataOffset); 451 if (rc != PLDM_SUCCESS) 452 { 453 return rc; 454 } 455 456 PDRRecordHandles pdrRecordHandles; 457 458 if (eventDataFormat == FORMAT_IS_PDR_TYPES) 459 { 460 return PLDM_ERROR_INVALID_DATA; 461 } 462 463 if (eventDataFormat == FORMAT_IS_PDR_HANDLES) 464 { 465 uint8_t eventDataOperation{}; 466 uint8_t numberOfChangeEntries{}; 467 468 auto changeRecordData = eventData + dataOffset; 469 auto changeRecordDataSize = eventDataSize - dataOffset; 470 471 while (changeRecordDataSize) 472 { 473 rc = decode_pldm_pdr_repository_change_record_data( 474 changeRecordData, changeRecordDataSize, &eventDataOperation, 475 &numberOfChangeEntries, &dataOffset); 476 477 if (rc != PLDM_SUCCESS) 478 { 479 return rc; 480 } 481 482 if (eventDataOperation == PLDM_RECORDS_ADDED) 483 { 484 rc = getPDRRecordHandles( 485 reinterpret_cast<const ChangeEntry*>(changeRecordData + 486 dataOffset), 487 changeRecordDataSize - dataOffset, 488 static_cast<size_t>(numberOfChangeEntries), 489 pdrRecordHandles); 490 491 if (rc != PLDM_SUCCESS) 492 { 493 return rc; 494 } 495 } 496 497 changeRecordData += 498 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 499 changeRecordDataSize -= 500 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 501 } 502 } 503 if (hostPDRHandler) 504 { 505 hostPDRHandler->fetchPDR(std::move(pdrRecordHandles)); 506 } 507 508 return PLDM_SUCCESS; 509 } 510 511 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData, 512 size_t changeEntryDataSize, 513 size_t numberOfChangeEntries, 514 PDRRecordHandles& pdrRecordHandles) 515 { 516 if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry))) 517 { 518 return PLDM_ERROR_INVALID_DATA; 519 } 520 for (size_t i = 0; i < numberOfChangeEntries; i++) 521 { 522 pdrRecordHandles.push_back(changeEntryData[i]); 523 } 524 return PLDM_SUCCESS; 525 } 526 527 Response Handler::setNumericEffecterValue(const pldm_msg* request, 528 size_t payloadLength) 529 { 530 Response response(sizeof(pldm_msg_hdr) + 531 PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES); 532 uint16_t effecterId{}; 533 uint8_t effecterDataSize{}; 534 uint8_t effecterValue[4] = {}; 535 536 if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) + 537 sizeof(union_effecter_data_size)) || 538 (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1)) 539 { 540 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 541 } 542 543 int rc = decode_set_numeric_effecter_value_req( 544 request, payloadLength, &effecterId, &effecterDataSize, 545 reinterpret_cast<uint8_t*>(&effecterValue)); 546 547 if (rc == PLDM_SUCCESS) 548 { 549 const pldm::utils::DBusHandler dBusIntf; 550 rc = platform_numeric_effecter::setNumericEffecterValueHandler< 551 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 552 effecterDataSize, effecterValue, 553 sizeof(effecterValue)); 554 } 555 556 return ccOnlyResponse(request, rc); 557 } 558 559 } // namespace platform 560 } // namespace responder 561 } // namespace pldm 562