1 #include "platform.hpp" 2 3 #include "common/types.hpp" 4 #include "common/utils.hpp" 5 #include "event_parser.hpp" 6 #include "pdr.hpp" 7 #include "pdr_numeric_effecter.hpp" 8 #include "pdr_state_effecter.hpp" 9 #include "pdr_state_sensor.hpp" 10 #include "pdr_utils.hpp" 11 #include "platform_numeric_effecter.hpp" 12 #include "platform_state_effecter.hpp" 13 #include "platform_state_sensor.hpp" 14 #include "pldmd/dbus_impl_requester.hpp" 15 #include "pldmd/handler.hpp" 16 #include "requester/handler.hpp" 17 18 #include <libpldm/entity.h> 19 #include <libpldm/state_set.h> 20 21 #include <phosphor-logging/lg2.hpp> 22 23 PHOSPHOR_LOG2_USING; 24 25 using namespace pldm::utils; 26 using namespace pldm::responder::pdr; 27 using namespace pldm::responder::pdr_utils; 28 29 namespace pldm 30 { 31 namespace responder 32 { 33 namespace platform 34 { 35 using InternalFailure = 36 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 37 38 static const Json empty{}; 39 40 void Handler::addDbusObjMaps( 41 uint16_t id, 42 std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj, 43 TypeId typeId) 44 { 45 if (typeId == TypeId::PLDM_SENSOR_ID) 46 { 47 sensorDbusObjMaps.emplace(id, dbusObj); 48 } 49 else 50 { 51 effecterDbusObjMaps.emplace(id, dbusObj); 52 } 53 } 54 55 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>& 56 Handler::getDbusObjMaps(uint16_t id, TypeId typeId) const 57 { 58 if (typeId == TypeId::PLDM_SENSOR_ID) 59 { 60 return sensorDbusObjMaps.at(id); 61 } 62 else 63 { 64 return effecterDbusObjMaps.at(id); 65 } 66 } 67 68 void Handler::generate(const pldm::utils::DBusHandler& dBusIntf, 69 const std::vector<fs::path>& dir, Repo& repo) 70 { 71 for (const auto& directory : dir) 72 { 73 info("checking if : {DIR} exists", "DIR", directory); 74 if (!fs::exists(directory)) 75 { 76 return; 77 } 78 } 79 80 // A map of PDR type to a lambda that handles creation of that PDR type. 81 // The lambda essentially would parse the platform specific PDR JSONs to 82 // generate the PDR structures. This function iterates through the map to 83 // invoke all lambdas, so that all PDR types can be created. 84 85 const std::map<Type, generatePDR> generateHandlers = { 86 {PLDM_STATE_EFFECTER_PDR, 87 [this](const DBusHandler& dBusIntf, const auto& json, 88 RepoInterface& repo) { 89 pdr_state_effecter::generateStateEffecterPDR<pldm::utils::DBusHandler, 90 Handler>(dBusIntf, json, 91 *this, repo); 92 }}, 93 {PLDM_NUMERIC_EFFECTER_PDR, 94 [this](const DBusHandler& dBusIntf, const auto& json, 95 RepoInterface& repo) { 96 pdr_numeric_effecter::generateNumericEffecterPDR< 97 pldm::utils::DBusHandler, Handler>(dBusIntf, json, *this, repo); 98 }}, 99 {PLDM_STATE_SENSOR_PDR, [this](const DBusHandler& dBusIntf, 100 const auto& json, RepoInterface& repo) { 101 pdr_state_sensor::generateStateSensorPDR<pldm::utils::DBusHandler, 102 Handler>(dBusIntf, json, *this, 103 repo); 104 }}}; 105 106 Type pdrType{}; 107 for (const auto& directory : dir) 108 { 109 for (const auto& dirEntry : fs::directory_iterator(directory)) 110 { 111 try 112 { 113 if (fs::is_regular_file(dirEntry.path().string())) 114 { 115 auto json = readJson(dirEntry.path().string()); 116 if (!json.empty()) 117 { 118 auto effecterPDRs = json.value("effecterPDRs", empty); 119 for (const auto& effecter : effecterPDRs) 120 { 121 pdrType = effecter.value("pdrType", 0); 122 generateHandlers.at(pdrType)(dBusIntf, effecter, 123 repo); 124 } 125 126 auto sensorPDRs = json.value("sensorPDRs", empty); 127 for (const auto& sensor : sensorPDRs) 128 { 129 pdrType = sensor.value("pdrType", 0); 130 generateHandlers.at(pdrType)(dBusIntf, sensor, 131 repo); 132 } 133 } 134 } 135 } 136 catch (const InternalFailure& e) 137 { 138 error( 139 "PDR config directory '{PATH}' does not exist or empty for '{TYPE}' pdr: {ERROR}", 140 "TYPE", pdrType, "PATH", dirEntry.path(), "ERROR", e); 141 } 142 catch (const Json::exception& e) 143 { 144 error("Failed parsing PDR JSON file for '{TYPE}' pdr: {ERROR}", 145 "TYPE", pdrType, "ERROR", e); 146 pldm::utils::reportError( 147 "xyz.openbmc_project.PLDM.Error.Generate.PDRJsonFileParseFail"); 148 } 149 catch (const std::exception& e) 150 { 151 error("Failed parsing PDR JSON file for '{TYPE}' pdr: {ERROR}", 152 "TYPE", pdrType, "ERROR", e); 153 pldm::utils::reportError( 154 "xyz.openbmc_project.PLDM.Error.Generate.PDRJsonFileParseFail"); 155 } 156 } 157 } 158 } 159 160 Response Handler::getPDR(const pldm_msg* request, size_t payloadLength) 161 { 162 if (hostPDRHandler) 163 { 164 if (hostPDRHandler->isHostUp() && oemPlatformHandler != nullptr) 165 { 166 auto rc = oemPlatformHandler->checkBMCState(); 167 if (rc != PLDM_SUCCESS) 168 { 169 return ccOnlyResponse(request, PLDM_ERROR_NOT_READY); 170 } 171 } 172 } 173 174 // Build FRU table if not built, since entity association PDR's 175 // are built when the FRU table is constructed. 176 if (fruHandler) 177 { 178 fruHandler->buildFRUTable(); 179 } 180 181 if (!pdrCreated) 182 { 183 generateTerminusLocatorPDR(pdrRepo); 184 if (platformConfigHandler) 185 { 186 auto systemType = platformConfigHandler->getPlatformName(); 187 if (systemType.has_value()) 188 { 189 // In case of normal poweron , the system type would have been 190 // already filled by entity manager when ever BMC reaches Ready 191 // state. If this is not filled by time we get a getpdr request 192 // we can assume that the entity manager service is not present 193 // on this system & continue to build the common PDR's. 194 pdrJsonsDir.push_back(pdrJsonDir / systemType.value()); 195 } 196 } 197 198 if (oemPlatformHandler != nullptr) 199 { 200 oemPlatformHandler->buildOEMPDR(pdrRepo); 201 } 202 generate(*dBusIntf, pdrJsonsDir, pdrRepo); 203 204 pdrCreated = true; 205 206 if (dbusToPLDMEventHandler) 207 { 208 deferredGetPDREvent = std::make_unique<sdeventplus::source::Defer>( 209 event, 210 std::bind(std::mem_fn(&pldm::responder::platform::Handler:: 211 _processPostGetPDRActions), 212 this, std::placeholders::_1)); 213 } 214 } 215 216 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0); 217 218 if (payloadLength != PLDM_GET_PDR_REQ_BYTES) 219 { 220 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 221 } 222 223 uint32_t recordHandle{}; 224 uint32_t dataTransferHandle{}; 225 uint8_t transferOpFlag{}; 226 uint16_t reqSizeBytes{}; 227 uint16_t recordChangeNum{}; 228 229 auto rc = decode_get_pdr_req(request, payloadLength, &recordHandle, 230 &dataTransferHandle, &transferOpFlag, 231 &reqSizeBytes, &recordChangeNum); 232 if (rc != PLDM_SUCCESS) 233 { 234 return CmdHandler::ccOnlyResponse(request, rc); 235 } 236 237 uint16_t respSizeBytes{}; 238 uint8_t* recordData = nullptr; 239 try 240 { 241 pdr_utils::PdrEntry e; 242 auto record = pdr::getRecordByHandle(pdrRepo, recordHandle, e); 243 if (record == NULL) 244 { 245 return CmdHandler::ccOnlyResponse( 246 request, PLDM_PLATFORM_INVALID_RECORD_HANDLE); 247 } 248 249 if (reqSizeBytes) 250 { 251 respSizeBytes = e.size; 252 if (respSizeBytes > reqSizeBytes) 253 { 254 respSizeBytes = reqSizeBytes; 255 } 256 recordData = e.data; 257 } 258 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES + 259 respSizeBytes, 260 0); 261 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 262 rc = encode_get_pdr_resp( 263 request->hdr.instance_id, PLDM_SUCCESS, e.handle.nextRecordHandle, 264 0, PLDM_START_AND_END, respSizeBytes, recordData, 0, responsePtr); 265 if (rc != PLDM_SUCCESS) 266 { 267 return ccOnlyResponse(request, rc); 268 } 269 } 270 catch (const std::exception& e) 271 { 272 error("Error accessing PDR, HANDLE={REC_HANDLE} ERROR={ERR_EXCEP}", 273 "REC_HANDLE", recordHandle, "ERR_EXCEP", e.what()); 274 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR); 275 } 276 return response; 277 } 278 279 Response Handler::setStateEffecterStates(const pldm_msg* request, 280 size_t payloadLength) 281 { 282 Response response( 283 sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0); 284 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 285 uint16_t effecterId; 286 uint8_t compEffecterCnt; 287 constexpr auto maxCompositeEffecterCnt = 8; 288 std::vector<set_effecter_state_field> stateField(maxCompositeEffecterCnt, 289 {0, 0}); 290 291 if ((payloadLength > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) || 292 (payloadLength < sizeof(effecterId) + sizeof(compEffecterCnt) + 293 sizeof(set_effecter_state_field))) 294 { 295 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 296 } 297 298 int rc = decode_set_state_effecter_states_req(request, payloadLength, 299 &effecterId, &compEffecterCnt, 300 stateField.data()); 301 302 if (rc != PLDM_SUCCESS) 303 { 304 return CmdHandler::ccOnlyResponse(request, rc); 305 } 306 307 stateField.resize(compEffecterCnt); 308 const pldm::utils::DBusHandler dBusIntf; 309 uint16_t entityType{}; 310 uint16_t entityInstance{}; 311 uint16_t stateSetId{}; 312 313 if (isOemStateEffecter(*this, effecterId, compEffecterCnt, entityType, 314 entityInstance, stateSetId) && 315 oemPlatformHandler != nullptr && 316 !effecterDbusObjMaps.contains(effecterId)) 317 { 318 rc = oemPlatformHandler->oemSetStateEffecterStatesHandler( 319 entityType, entityInstance, stateSetId, compEffecterCnt, stateField, 320 effecterId); 321 } 322 else 323 { 324 rc = platform_state_effecter::setStateEffecterStatesHandler< 325 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 326 stateField); 327 } 328 if (rc != PLDM_SUCCESS) 329 { 330 return CmdHandler::ccOnlyResponse(request, rc); 331 } 332 333 rc = encode_set_state_effecter_states_resp(request->hdr.instance_id, rc, 334 responsePtr); 335 if (rc != PLDM_SUCCESS) 336 { 337 return ccOnlyResponse(request, rc); 338 } 339 340 return response; 341 } 342 343 Response Handler::platformEventMessage(const pldm_msg* request, 344 size_t payloadLength) 345 { 346 uint8_t formatVersion{}; 347 uint8_t tid{}; 348 uint8_t eventClass{}; 349 size_t offset{}; 350 351 auto rc = decode_platform_event_message_req( 352 request, payloadLength, &formatVersion, &tid, &eventClass, &offset); 353 if (rc != PLDM_SUCCESS) 354 { 355 return CmdHandler::ccOnlyResponse(request, rc); 356 } 357 358 if (eventClass == PLDM_HEARTBEAT_TIMER_ELAPSED_EVENT) 359 { 360 rc = PLDM_SUCCESS; 361 if (oemPlatformHandler) 362 { 363 oemPlatformHandler->resetWatchDogTimer(); 364 } 365 } 366 else 367 { 368 try 369 { 370 const auto& handlers = eventHandlers.at(eventClass); 371 for (const auto& handler : handlers) 372 { 373 auto rc = handler(request, payloadLength, formatVersion, tid, 374 offset); 375 if (rc != PLDM_SUCCESS) 376 { 377 return CmdHandler::ccOnlyResponse(request, rc); 378 } 379 } 380 } 381 catch (const std::out_of_range& e) 382 { 383 error("Error in handling platform event msg: {ERROR}", "ERROR", e); 384 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA); 385 } 386 } 387 Response response( 388 sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES, 0); 389 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 390 391 rc = encode_platform_event_message_resp(request->hdr.instance_id, rc, 392 PLDM_EVENT_NO_LOGGING, responsePtr); 393 if (rc != PLDM_SUCCESS) 394 { 395 return ccOnlyResponse(request, rc); 396 } 397 398 return response; 399 } 400 401 int Handler::sensorEvent(const pldm_msg* request, size_t payloadLength, 402 uint8_t /*formatVersion*/, uint8_t tid, 403 size_t eventDataOffset) 404 { 405 uint16_t sensorId{}; 406 uint8_t eventClass{}; 407 size_t eventClassDataOffset{}; 408 auto eventData = reinterpret_cast<const uint8_t*>(request->payload) + 409 eventDataOffset; 410 auto eventDataSize = payloadLength - eventDataOffset; 411 412 auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId, 413 &eventClass, &eventClassDataOffset); 414 if (rc != PLDM_SUCCESS) 415 { 416 return rc; 417 } 418 419 auto eventClassData = reinterpret_cast<const uint8_t*>(request->payload) + 420 eventDataOffset + eventClassDataOffset; 421 auto eventClassDataSize = payloadLength - eventDataOffset - 422 eventClassDataOffset; 423 424 if (eventClass == PLDM_STATE_SENSOR_STATE) 425 { 426 uint8_t sensorOffset{}; 427 uint8_t eventState{}; 428 uint8_t previousEventState{}; 429 430 rc = decode_state_sensor_data(eventClassData, eventClassDataSize, 431 &sensorOffset, &eventState, 432 &previousEventState); 433 if (rc != PLDM_SUCCESS) 434 { 435 return PLDM_ERROR; 436 } 437 438 // Emitting state sensor event signal 439 emitStateSensorEventSignal(tid, sensorId, sensorOffset, eventState, 440 previousEventState); 441 442 // If there are no HOST PDR's, there is no further action 443 if (hostPDRHandler == NULL) 444 { 445 return PLDM_SUCCESS; 446 } 447 448 // Handle PLDM events for which PDR is available 449 SensorEntry sensorEntry{tid, sensorId}; 450 451 pldm::pdr::EntityInfo entityInfo{}; 452 pldm::pdr::CompositeSensorStates compositeSensorStates{}; 453 std::vector<pldm::pdr::StateSetId> stateSetIds{}; 454 455 try 456 { 457 std::tie(entityInfo, compositeSensorStates, stateSetIds) = 458 hostPDRHandler->lookupSensorInfo(sensorEntry); 459 } 460 catch (const std::out_of_range&) 461 { 462 // If there is no mapping for tid, sensorId combination, try 463 // PLDM_TID_RESERVED, sensorId for terminus that is yet to 464 // implement TL PDR. 465 try 466 { 467 sensorEntry.terminusID = PLDM_TID_RESERVED; 468 std::tie(entityInfo, compositeSensorStates, stateSetIds) = 469 hostPDRHandler->lookupSensorInfo(sensorEntry); 470 } 471 // If there is no mapping for events return PLDM_SUCCESS 472 catch (const std::out_of_range&) 473 { 474 return PLDM_SUCCESS; 475 } 476 } 477 478 if (sensorOffset >= compositeSensorStates.size()) 479 { 480 return PLDM_ERROR_INVALID_DATA; 481 } 482 483 const auto& possibleStates = compositeSensorStates[sensorOffset]; 484 if (!possibleStates.contains(eventState)) 485 { 486 return PLDM_ERROR_INVALID_DATA; 487 } 488 489 const auto& [containerId, entityType, entityInstance] = entityInfo; 490 events::StateSensorEntry stateSensorEntry{containerId, entityType, 491 entityInstance, sensorOffset, 492 stateSetIds[sensorOffset]}; 493 return hostPDRHandler->handleStateSensorEvent(stateSensorEntry, 494 eventState); 495 } 496 else 497 { 498 return PLDM_ERROR_INVALID_DATA; 499 } 500 501 return PLDM_SUCCESS; 502 } 503 504 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request, 505 size_t payloadLength, 506 uint8_t /*formatVersion*/, uint8_t tid, 507 size_t eventDataOffset) 508 { 509 uint8_t eventDataFormat{}; 510 uint8_t numberOfChangeRecords{}; 511 size_t dataOffset{}; 512 513 auto eventData = reinterpret_cast<const uint8_t*>(request->payload) + 514 eventDataOffset; 515 auto eventDataSize = payloadLength - eventDataOffset; 516 517 auto rc = decode_pldm_pdr_repository_chg_event_data( 518 eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords, 519 &dataOffset); 520 if (rc != PLDM_SUCCESS) 521 { 522 return rc; 523 } 524 525 PDRRecordHandles pdrRecordHandles; 526 527 if (eventDataFormat == FORMAT_IS_PDR_TYPES) 528 { 529 return PLDM_ERROR_INVALID_DATA; 530 } 531 532 if (eventDataFormat == FORMAT_IS_PDR_HANDLES) 533 { 534 uint8_t eventDataOperation{}; 535 uint8_t numberOfChangeEntries{}; 536 537 auto changeRecordData = eventData + dataOffset; 538 auto changeRecordDataSize = eventDataSize - dataOffset; 539 540 while (changeRecordDataSize) 541 { 542 rc = decode_pldm_pdr_repository_change_record_data( 543 changeRecordData, changeRecordDataSize, &eventDataOperation, 544 &numberOfChangeEntries, &dataOffset); 545 546 if (rc != PLDM_SUCCESS) 547 { 548 return rc; 549 } 550 551 if (eventDataOperation == PLDM_RECORDS_ADDED || 552 eventDataOperation == PLDM_RECORDS_MODIFIED) 553 { 554 if (eventDataOperation == PLDM_RECORDS_MODIFIED) 555 { 556 hostPDRHandler->isHostPdrModified = true; 557 } 558 559 rc = getPDRRecordHandles( 560 reinterpret_cast<const ChangeEntry*>(changeRecordData + 561 dataOffset), 562 changeRecordDataSize - dataOffset, 563 static_cast<size_t>(numberOfChangeEntries), 564 pdrRecordHandles); 565 566 if (rc != PLDM_SUCCESS) 567 { 568 return rc; 569 } 570 } 571 572 changeRecordData += dataOffset + 573 (numberOfChangeEntries * sizeof(ChangeEntry)); 574 changeRecordDataSize -= 575 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 576 } 577 } 578 if (hostPDRHandler) 579 { 580 // if we get a Repository change event with the eventDataFormat 581 // as REFRESH_ENTIRE_REPOSITORY, then delete all the PDR's that 582 // have the matched Terminus handle 583 if (eventDataFormat == REFRESH_ENTIRE_REPOSITORY) 584 { 585 // We cannot get the Repo change event from the Terminus 586 // that is not already added to the BMC repository 587 588 for (auto it = hostPDRHandler->tlPDRInfo.cbegin(); 589 it != hostPDRHandler->tlPDRInfo.cend();) 590 { 591 if (std::get<0>(it->second) == tid) 592 { 593 pldm_pdr_remove_pdrs_by_terminus_handle(pdrRepo.getPdr(), 594 it->first); 595 hostPDRHandler->tlPDRInfo.erase(it++); 596 } 597 else 598 { 599 ++it; 600 } 601 } 602 } 603 hostPDRHandler->fetchPDR(std::move(pdrRecordHandles)); 604 } 605 606 return PLDM_SUCCESS; 607 } 608 609 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData, 610 size_t changeEntryDataSize, 611 size_t numberOfChangeEntries, 612 PDRRecordHandles& pdrRecordHandles) 613 { 614 if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry))) 615 { 616 return PLDM_ERROR_INVALID_DATA; 617 } 618 for (size_t i = 0; i < numberOfChangeEntries; i++) 619 { 620 pdrRecordHandles.push_back(changeEntryData[i]); 621 } 622 return PLDM_SUCCESS; 623 } 624 625 Response Handler::getNumericEffecterValue(const pldm_msg* request, 626 size_t payloadLength) 627 { 628 if (payloadLength != PLDM_GET_NUMERIC_EFFECTER_VALUE_REQ_BYTES) 629 { 630 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 631 } 632 633 uint16_t effecterId{}; 634 auto rc = decode_get_numeric_effecter_value_req(request, payloadLength, 635 &effecterId); 636 if (rc != PLDM_SUCCESS) 637 { 638 return ccOnlyResponse(request, rc); 639 } 640 641 const pldm::utils::DBusHandler dBusIntf; 642 uint8_t effecterDataSize{}; 643 pldm::utils::PropertyValue dbusValue; 644 std::string propertyType; 645 using effecterOperationalState = uint8_t; 646 using completionCode = uint8_t; 647 648 rc = platform_numeric_effecter::getNumericEffecterData< 649 pldm::utils::DBusHandler, Handler>( 650 dBusIntf, *this, effecterId, effecterDataSize, propertyType, dbusValue); 651 652 if (rc != PLDM_SUCCESS) 653 { 654 return ccOnlyResponse(request, rc); 655 } 656 657 // Refer DSP0248_1.2.0.pdf (section 22.3, Table 48) 658 // Completion Code (uint8), Effecter Data Size(uint8), Effecter Operational 659 // State(uint8), PendingValue (uint8|sint8|uint16|sint16|uint32|sint32 ) 660 // PresentValue (uint8|sint8|uint16|sint16|uint32|sint32 ) 661 // Size of PendingValue and PresentValue calculated based on size is 662 // provided in effecter data size 663 size_t responsePayloadLength = sizeof(completionCode) + 664 sizeof(effecterDataSize) + 665 sizeof(effecterOperationalState) + 666 getEffecterDataSize(effecterDataSize) + 667 getEffecterDataSize(effecterDataSize); 668 669 Response response(responsePayloadLength + sizeof(pldm_msg_hdr)); 670 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 671 672 rc = platform_numeric_effecter::getNumericEffecterValueHandler( 673 propertyType, dbusValue, effecterDataSize, responsePtr, 674 responsePayloadLength, request->hdr.instance_id); 675 676 if (rc != PLDM_SUCCESS) 677 { 678 error( 679 "Reponse to GetNumericEffecterValue failed RC={RC} for EffectorId={EFFECTER_ID} ", 680 "RC", rc, "EFFECTER_ID", effecterId); 681 return ccOnlyResponse(request, rc); 682 } 683 return response; 684 } 685 686 Response Handler::setNumericEffecterValue(const pldm_msg* request, 687 size_t payloadLength) 688 { 689 Response response(sizeof(pldm_msg_hdr) + 690 PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES); 691 uint16_t effecterId{}; 692 uint8_t effecterDataSize{}; 693 uint8_t effecterValue[4] = {}; 694 695 if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) + 696 sizeof(union_effecter_data_size)) || 697 (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1)) 698 { 699 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 700 } 701 702 int rc = decode_set_numeric_effecter_value_req( 703 request, payloadLength, &effecterId, &effecterDataSize, effecterValue); 704 705 if (rc == PLDM_SUCCESS) 706 { 707 const pldm::utils::DBusHandler dBusIntf; 708 rc = platform_numeric_effecter::setNumericEffecterValueHandler< 709 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 710 effecterDataSize, effecterValue, 711 sizeof(effecterValue)); 712 } 713 714 return ccOnlyResponse(request, rc); 715 } 716 717 void Handler::generateTerminusLocatorPDR(Repo& repo) 718 { 719 std::vector<uint8_t> pdrBuffer(sizeof(pldm_terminus_locator_pdr)); 720 721 auto pdr = reinterpret_cast<pldm_terminus_locator_pdr*>(pdrBuffer.data()); 722 723 pdr->hdr.record_handle = 0; 724 pdr->hdr.version = 1; 725 pdr->hdr.type = PLDM_TERMINUS_LOCATOR_PDR; 726 pdr->hdr.record_change_num = 0; 727 pdr->hdr.length = sizeof(pldm_terminus_locator_pdr) - sizeof(pldm_pdr_hdr); 728 pdr->terminus_handle = TERMINUS_HANDLE; 729 pdr->validity = PLDM_TL_PDR_VALID; 730 pdr->tid = TERMINUS_ID; 731 pdr->container_id = 0x0; 732 pdr->terminus_locator_type = PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID; 733 pdr->terminus_locator_value_size = 734 sizeof(pldm_terminus_locator_type_mctp_eid); 735 auto locatorValue = reinterpret_cast<pldm_terminus_locator_type_mctp_eid*>( 736 pdr->terminus_locator_value); 737 locatorValue->eid = BmcMctpEid; 738 739 PdrEntry pdrEntry{}; 740 pdrEntry.data = pdrBuffer.data(); 741 pdrEntry.size = pdrBuffer.size(); 742 repo.addRecord(pdrEntry); 743 if (hostPDRHandler) 744 { 745 hostPDRHandler->tlPDRInfo.insert_or_assign( 746 pdr->terminus_handle, 747 std::make_tuple(pdr->tid, locatorValue->eid, pdr->validity)); 748 } 749 } 750 751 Response Handler::getStateSensorReadings(const pldm_msg* request, 752 size_t payloadLength) 753 { 754 uint16_t sensorId{}; 755 bitfield8_t sensorRearm{}; 756 uint8_t reserved{}; 757 758 if (payloadLength != PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES) 759 { 760 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 761 } 762 763 int rc = decode_get_state_sensor_readings_req( 764 request, payloadLength, &sensorId, &sensorRearm, &reserved); 765 766 if (rc != PLDM_SUCCESS) 767 { 768 return ccOnlyResponse(request, rc); 769 } 770 771 // 0x01 to 0x08 772 uint8_t sensorRearmCount = std::popcount(sensorRearm.byte); 773 std::vector<get_sensor_state_field> stateField(sensorRearmCount); 774 uint8_t comSensorCnt{}; 775 const pldm::utils::DBusHandler dBusIntf; 776 777 uint16_t entityType{}; 778 uint16_t entityInstance{}; 779 uint16_t stateSetId{}; 780 781 if (isOemStateSensor(*this, sensorId, sensorRearmCount, comSensorCnt, 782 entityType, entityInstance, stateSetId) && 783 oemPlatformHandler != nullptr && !sensorDbusObjMaps.contains(sensorId)) 784 { 785 rc = oemPlatformHandler->getOemStateSensorReadingsHandler( 786 entityType, entityInstance, stateSetId, comSensorCnt, stateField); 787 } 788 else 789 { 790 rc = platform_state_sensor::getStateSensorReadingsHandler< 791 pldm::utils::DBusHandler, Handler>( 792 dBusIntf, *this, sensorId, sensorRearmCount, comSensorCnt, 793 stateField, dbusToPLDMEventHandler->getSensorCache()); 794 } 795 796 if (rc != PLDM_SUCCESS) 797 { 798 return ccOnlyResponse(request, rc); 799 } 800 801 Response response(sizeof(pldm_msg_hdr) + 802 PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES + 803 sizeof(get_sensor_state_field) * comSensorCnt); 804 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 805 rc = encode_get_state_sensor_readings_resp(request->hdr.instance_id, rc, 806 comSensorCnt, stateField.data(), 807 responsePtr); 808 if (rc != PLDM_SUCCESS) 809 { 810 return ccOnlyResponse(request, rc); 811 } 812 813 return response; 814 } 815 816 void Handler::_processPostGetPDRActions(sdeventplus::source::EventBase& 817 /*source */) 818 { 819 deferredGetPDREvent.reset(); 820 dbusToPLDMEventHandler->listenSensorEvent(pdrRepo, sensorDbusObjMaps); 821 } 822 823 bool isOemStateSensor(Handler& handler, uint16_t sensorId, 824 uint8_t sensorRearmCount, uint8_t& compSensorCnt, 825 uint16_t& entityType, uint16_t& entityInstance, 826 uint16_t& stateSetId) 827 { 828 pldm_state_sensor_pdr* pdr = nullptr; 829 830 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateSensorPdrRepo( 831 pldm_pdr_init(), pldm_pdr_destroy); 832 if (!stateSensorPdrRepo) 833 { 834 error("Failed to instantiate state sensor PDR repository"); 835 return false; 836 } 837 Repo stateSensorPDRs(stateSensorPdrRepo.get()); 838 getRepoByType(handler.getRepo(), stateSensorPDRs, PLDM_STATE_SENSOR_PDR); 839 if (stateSensorPDRs.empty()) 840 { 841 error("Failed to get record by PDR type"); 842 return false; 843 } 844 845 PdrEntry pdrEntry{}; 846 auto pdrRecord = stateSensorPDRs.getFirstRecord(pdrEntry); 847 while (pdrRecord) 848 { 849 pdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdrEntry.data); 850 assert(pdr != NULL); 851 if (pdr->sensor_id != sensorId) 852 { 853 pdr = nullptr; 854 pdrRecord = stateSensorPDRs.getNextRecord(pdrRecord, pdrEntry); 855 continue; 856 } 857 auto tmpEntityType = pdr->entity_type; 858 auto tmpEntityInstance = pdr->entity_instance; 859 auto tmpCompSensorCnt = pdr->composite_sensor_count; 860 auto tmpPossibleStates = 861 reinterpret_cast<state_sensor_possible_states*>( 862 pdr->possible_states); 863 auto tmpStateSetId = tmpPossibleStates->state_set_id; 864 865 if (sensorRearmCount > tmpCompSensorCnt) 866 { 867 error( 868 "The requester sent wrong sensorRearm count for the sensor, SENSOR_ID={SENSOR_ID} SENSOR_REARM_COUNT={SENSOR_REARM_CNT}", 869 "SENSOR_ID", sensorId, "SENSOR_REARM_CNT", 870 (uint16_t)sensorRearmCount); 871 break; 872 } 873 874 if ((tmpEntityType >= PLDM_OEM_ENTITY_TYPE_START && 875 tmpEntityType <= PLDM_OEM_ENTITY_TYPE_END) || 876 (tmpStateSetId >= PLDM_OEM_STATE_SET_ID_START && 877 tmpStateSetId < PLDM_OEM_STATE_SET_ID_END)) 878 { 879 entityType = tmpEntityType; 880 entityInstance = tmpEntityInstance; 881 stateSetId = tmpStateSetId; 882 compSensorCnt = tmpCompSensorCnt; 883 return true; 884 } 885 else 886 { 887 return false; 888 } 889 } 890 return false; 891 } 892 893 bool isOemStateEffecter(Handler& handler, uint16_t effecterId, 894 uint8_t compEffecterCnt, uint16_t& entityType, 895 uint16_t& entityInstance, uint16_t& stateSetId) 896 { 897 pldm_state_effecter_pdr* pdr = nullptr; 898 899 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateEffecterPdrRepo( 900 pldm_pdr_init(), pldm_pdr_destroy); 901 if (!stateEffecterPdrRepo) 902 { 903 error("Failed to instantiate state effecter PDR repository"); 904 return false; 905 } 906 Repo stateEffecterPDRs(stateEffecterPdrRepo.get()); 907 getRepoByType(handler.getRepo(), stateEffecterPDRs, 908 PLDM_STATE_EFFECTER_PDR); 909 if (stateEffecterPDRs.empty()) 910 { 911 error("Failed to get record by PDR type"); 912 return false; 913 } 914 915 PdrEntry pdrEntry{}; 916 auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry); 917 while (pdrRecord) 918 { 919 pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data); 920 assert(pdr != NULL); 921 if (pdr->effecter_id != effecterId) 922 { 923 pdr = nullptr; 924 pdrRecord = stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); 925 continue; 926 } 927 928 auto tmpEntityType = pdr->entity_type; 929 auto tmpEntityInstance = pdr->entity_instance; 930 auto tmpPossibleStates = 931 reinterpret_cast<state_effecter_possible_states*>( 932 pdr->possible_states); 933 auto tmpStateSetId = tmpPossibleStates->state_set_id; 934 935 if (compEffecterCnt > pdr->composite_effecter_count) 936 { 937 error( 938 "The requester sent wrong composite effecter count for the effecter, EFFECTER_ID={EFFECTER_ID} COMP_EFF_CNT={COMP_EFF_CNT}", 939 "EFFECTER_ID", effecterId, "COMP_EFF_CNT", 940 (uint16_t)compEffecterCnt); 941 return false; 942 } 943 944 if ((tmpEntityType >= PLDM_OEM_ENTITY_TYPE_START && 945 tmpEntityType <= PLDM_OEM_ENTITY_TYPE_END) || 946 (tmpStateSetId >= PLDM_OEM_STATE_SET_ID_START && 947 tmpStateSetId < PLDM_OEM_STATE_SET_ID_END)) 948 { 949 entityType = tmpEntityType; 950 entityInstance = tmpEntityInstance; 951 stateSetId = tmpStateSetId; 952 return true; 953 } 954 else 955 { 956 return false; 957 } 958 } 959 return false; 960 } 961 962 void Handler::setEventReceiver() 963 { 964 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 965 PLDM_SET_EVENT_RECEIVER_REQ_BYTES); 966 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 967 auto instanceId = instanceIdDb->next(eid); 968 uint8_t eventMessageGlobalEnable = 969 PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE; 970 uint8_t transportProtocolType = PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP; 971 uint8_t eventReceiverAddressInfo = pldm::responder::pdr::BmcMctpEid; 972 uint16_t heartbeatTimer = HEARTBEAT_TIMEOUT; 973 974 auto rc = encode_set_event_receiver_req( 975 instanceId, eventMessageGlobalEnable, transportProtocolType, 976 eventReceiverAddressInfo, heartbeatTimer, request); 977 if (rc != PLDM_SUCCESS) 978 { 979 instanceIdDb->free(eid, instanceId); 980 error("Failed to encode_set_event_receiver_req, rc = {RC}", "RC", 981 lg2::hex, rc); 982 return; 983 } 984 985 auto processSetEventReceiverResponse = 986 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 987 if (response == nullptr || !respMsgLen) 988 { 989 error("Failed to receive response for setEventReceiver command"); 990 return; 991 } 992 993 uint8_t completionCode{}; 994 auto rc = decode_set_event_receiver_resp(response, respMsgLen, 995 &completionCode); 996 if (rc || completionCode) 997 { 998 error( 999 "Failed to decode setEventReceiver command response, rc = {RC}, cc = {CC}", 1000 "RC", rc, "CC", (unsigned)completionCode); 1001 pldm::utils::reportError( 1002 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 1003 } 1004 }; 1005 rc = handler->registerRequest( 1006 eid, instanceId, PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER, 1007 std::move(requestMsg), std::move(processSetEventReceiverResponse)); 1008 1009 if (rc != PLDM_SUCCESS) 1010 { 1011 error("Failed to send the setEventReceiver request"); 1012 } 1013 1014 if (oemPlatformHandler) 1015 { 1016 oemPlatformHandler->countSetEventReceiver(); 1017 oemPlatformHandler->checkAndDisableWatchDog(); 1018 } 1019 } 1020 1021 } // namespace platform 1022 } // namespace responder 1023 } // namespace pldm 1024