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