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