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, 503 entityType, 504 entityInstance, 505 sensorOffset, 506 stateSetIds[sensorOffset], 507 false}; 508 return hostPDRHandler->handleStateSensorEvent(stateSensorEntry, 509 eventState); 510 } 511 else 512 { 513 return PLDM_ERROR_INVALID_DATA; 514 } 515 516 return PLDM_SUCCESS; 517 } 518 519 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request, 520 size_t payloadLength, 521 uint8_t /*formatVersion*/, uint8_t tid, 522 size_t eventDataOffset) 523 { 524 uint8_t eventDataFormat{}; 525 uint8_t numberOfChangeRecords{}; 526 size_t dataOffset{}; 527 528 auto eventData = reinterpret_cast<const uint8_t*>(request->payload) + 529 eventDataOffset; 530 auto eventDataSize = payloadLength - eventDataOffset; 531 532 auto rc = decode_pldm_pdr_repository_chg_event_data( 533 eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords, 534 &dataOffset); 535 if (rc != PLDM_SUCCESS) 536 { 537 return rc; 538 } 539 540 PDRRecordHandles pdrRecordHandles; 541 542 if (eventDataFormat == FORMAT_IS_PDR_TYPES) 543 { 544 return PLDM_ERROR_INVALID_DATA; 545 } 546 547 if (eventDataFormat == FORMAT_IS_PDR_HANDLES) 548 { 549 uint8_t eventDataOperation{}; 550 uint8_t numberOfChangeEntries{}; 551 552 auto changeRecordData = eventData + dataOffset; 553 auto changeRecordDataSize = eventDataSize - dataOffset; 554 555 while (changeRecordDataSize) 556 { 557 rc = decode_pldm_pdr_repository_change_record_data( 558 changeRecordData, changeRecordDataSize, &eventDataOperation, 559 &numberOfChangeEntries, &dataOffset); 560 561 if (rc != PLDM_SUCCESS) 562 { 563 return rc; 564 } 565 566 if (eventDataOperation == PLDM_RECORDS_ADDED || 567 eventDataOperation == PLDM_RECORDS_MODIFIED) 568 { 569 if (eventDataOperation == PLDM_RECORDS_MODIFIED) 570 { 571 hostPDRHandler->isHostPdrModified = true; 572 } 573 574 rc = getPDRRecordHandles( 575 reinterpret_cast<const ChangeEntry*>(changeRecordData + 576 dataOffset), 577 changeRecordDataSize - dataOffset, 578 static_cast<size_t>(numberOfChangeEntries), 579 pdrRecordHandles); 580 581 if (rc != PLDM_SUCCESS) 582 { 583 return rc; 584 } 585 } 586 587 changeRecordData += dataOffset + 588 (numberOfChangeEntries * sizeof(ChangeEntry)); 589 changeRecordDataSize -= 590 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 591 } 592 } 593 if (hostPDRHandler) 594 { 595 // if we get a Repository change event with the eventDataFormat 596 // as REFRESH_ENTIRE_REPOSITORY, then delete all the PDR's that 597 // have the matched Terminus handle 598 if (eventDataFormat == REFRESH_ENTIRE_REPOSITORY) 599 { 600 // We cannot get the Repo change event from the Terminus 601 // that is not already added to the BMC repository 602 603 for (auto it = hostPDRHandler->tlPDRInfo.cbegin(); 604 it != hostPDRHandler->tlPDRInfo.cend();) 605 { 606 if (std::get<0>(it->second) == tid) 607 { 608 pldm_pdr_remove_pdrs_by_terminus_handle(pdrRepo.getPdr(), 609 it->first); 610 hostPDRHandler->tlPDRInfo.erase(it++); 611 } 612 else 613 { 614 ++it; 615 } 616 } 617 } 618 hostPDRHandler->fetchPDR(std::move(pdrRecordHandles)); 619 } 620 621 return PLDM_SUCCESS; 622 } 623 624 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData, 625 size_t changeEntryDataSize, 626 size_t numberOfChangeEntries, 627 PDRRecordHandles& pdrRecordHandles) 628 { 629 if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry))) 630 { 631 return PLDM_ERROR_INVALID_DATA; 632 } 633 for (size_t i = 0; i < numberOfChangeEntries; i++) 634 { 635 pdrRecordHandles.push_back(changeEntryData[i]); 636 } 637 return PLDM_SUCCESS; 638 } 639 640 Response Handler::getNumericEffecterValue(const pldm_msg* request, 641 size_t payloadLength) 642 { 643 if (payloadLength != PLDM_GET_NUMERIC_EFFECTER_VALUE_REQ_BYTES) 644 { 645 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 646 } 647 648 uint16_t effecterId{}; 649 auto rc = decode_get_numeric_effecter_value_req(request, payloadLength, 650 &effecterId); 651 if (rc != PLDM_SUCCESS) 652 { 653 return ccOnlyResponse(request, rc); 654 } 655 656 const pldm::utils::DBusHandler dBusIntf; 657 uint8_t effecterDataSize{}; 658 pldm::utils::PropertyValue dbusValue; 659 std::string propertyType; 660 using effecterOperationalState = uint8_t; 661 using completionCode = uint8_t; 662 663 rc = platform_numeric_effecter::getNumericEffecterData< 664 pldm::utils::DBusHandler, Handler>( 665 dBusIntf, *this, effecterId, effecterDataSize, propertyType, dbusValue); 666 667 if (rc != PLDM_SUCCESS) 668 { 669 return ccOnlyResponse(request, rc); 670 } 671 672 // Refer DSP0248_1.2.0.pdf (section 22.3, Table 48) 673 // Completion Code (uint8), Effecter Data Size(uint8), Effecter Operational 674 // State(uint8), PendingValue (uint8|sint8|uint16|sint16|uint32|sint32 ) 675 // PresentValue (uint8|sint8|uint16|sint16|uint32|sint32 ) 676 // Size of PendingValue and PresentValue calculated based on size is 677 // provided in effecter data size 678 size_t responsePayloadLength = sizeof(completionCode) + 679 sizeof(effecterDataSize) + 680 sizeof(effecterOperationalState) + 681 getEffecterDataSize(effecterDataSize) + 682 getEffecterDataSize(effecterDataSize); 683 684 Response response(responsePayloadLength + sizeof(pldm_msg_hdr)); 685 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 686 687 rc = platform_numeric_effecter::getNumericEffecterValueHandler( 688 propertyType, dbusValue, effecterDataSize, responsePtr, 689 responsePayloadLength, request->hdr.instance_id); 690 691 if (rc != PLDM_SUCCESS) 692 { 693 error( 694 "Failed to get response of GetNumericEffecterValue for effecter ID '{EFFECTERID}', response code '{RC}'.", 695 "EFFECTERID", effecterId, "RC", rc); 696 return ccOnlyResponse(request, rc); 697 } 698 return response; 699 } 700 701 Response Handler::setNumericEffecterValue(const pldm_msg* request, 702 size_t payloadLength) 703 { 704 Response response(sizeof(pldm_msg_hdr) + 705 PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES); 706 uint16_t effecterId{}; 707 uint8_t effecterDataSize{}; 708 uint8_t effecterValue[4] = {}; 709 710 if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) + 711 sizeof(union_effecter_data_size)) || 712 (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1)) 713 { 714 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 715 } 716 717 int rc = decode_set_numeric_effecter_value_req( 718 request, payloadLength, &effecterId, &effecterDataSize, effecterValue); 719 720 if (rc == PLDM_SUCCESS) 721 { 722 const pldm::utils::DBusHandler dBusIntf; 723 rc = platform_numeric_effecter::setNumericEffecterValueHandler< 724 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 725 effecterDataSize, effecterValue, 726 sizeof(effecterValue)); 727 } 728 729 return ccOnlyResponse(request, rc); 730 } 731 732 void Handler::generateTerminusLocatorPDR(Repo& repo) 733 { 734 std::vector<uint8_t> pdrBuffer(sizeof(pldm_terminus_locator_pdr)); 735 736 auto pdr = reinterpret_cast<pldm_terminus_locator_pdr*>(pdrBuffer.data()); 737 738 pdr->hdr.record_handle = 0; 739 pdr->hdr.version = 1; 740 pdr->hdr.type = PLDM_TERMINUS_LOCATOR_PDR; 741 pdr->hdr.record_change_num = 0; 742 pdr->hdr.length = sizeof(pldm_terminus_locator_pdr) - sizeof(pldm_pdr_hdr); 743 pdr->terminus_handle = TERMINUS_HANDLE; 744 pdr->validity = PLDM_TL_PDR_VALID; 745 pdr->tid = TERMINUS_ID; 746 pdr->container_id = 0x0; 747 pdr->terminus_locator_type = PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID; 748 pdr->terminus_locator_value_size = 749 sizeof(pldm_terminus_locator_type_mctp_eid); 750 auto locatorValue = reinterpret_cast<pldm_terminus_locator_type_mctp_eid*>( 751 pdr->terminus_locator_value); 752 locatorValue->eid = BmcMctpEid; 753 754 PdrEntry pdrEntry{}; 755 pdrEntry.data = pdrBuffer.data(); 756 pdrEntry.size = pdrBuffer.size(); 757 repo.addRecord(pdrEntry); 758 if (hostPDRHandler) 759 { 760 hostPDRHandler->tlPDRInfo.insert_or_assign( 761 pdr->terminus_handle, 762 std::make_tuple(pdr->tid, locatorValue->eid, pdr->validity)); 763 } 764 } 765 766 Response Handler::getStateSensorReadings(const pldm_msg* request, 767 size_t payloadLength) 768 { 769 uint16_t sensorId{}; 770 bitfield8_t sensorRearm{}; 771 uint8_t reserved{}; 772 773 if (payloadLength != PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES) 774 { 775 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 776 } 777 778 int rc = decode_get_state_sensor_readings_req( 779 request, payloadLength, &sensorId, &sensorRearm, &reserved); 780 781 if (rc != PLDM_SUCCESS) 782 { 783 return ccOnlyResponse(request, rc); 784 } 785 786 // 0x01 to 0x08 787 uint8_t sensorRearmCount = std::popcount(sensorRearm.byte); 788 std::vector<get_sensor_state_field> stateField(sensorRearmCount); 789 uint8_t comSensorCnt{}; 790 const pldm::utils::DBusHandler dBusIntf; 791 792 uint16_t entityType{}; 793 uint16_t entityInstance{}; 794 uint16_t stateSetId{}; 795 796 if (isOemStateSensor(*this, sensorId, sensorRearmCount, comSensorCnt, 797 entityType, entityInstance, stateSetId) && 798 oemPlatformHandler != nullptr && !sensorDbusObjMaps.contains(sensorId)) 799 { 800 rc = oemPlatformHandler->getOemStateSensorReadingsHandler( 801 entityType, entityInstance, stateSetId, comSensorCnt, stateField); 802 } 803 else 804 { 805 rc = platform_state_sensor::getStateSensorReadingsHandler< 806 pldm::utils::DBusHandler, Handler>( 807 dBusIntf, *this, sensorId, sensorRearmCount, comSensorCnt, 808 stateField, dbusToPLDMEventHandler->getSensorCache()); 809 } 810 811 if (rc != PLDM_SUCCESS) 812 { 813 return ccOnlyResponse(request, rc); 814 } 815 816 Response response(sizeof(pldm_msg_hdr) + 817 PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES + 818 sizeof(get_sensor_state_field) * comSensorCnt); 819 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 820 rc = encode_get_state_sensor_readings_resp(request->hdr.instance_id, rc, 821 comSensorCnt, stateField.data(), 822 responsePtr); 823 if (rc != PLDM_SUCCESS) 824 { 825 return ccOnlyResponse(request, rc); 826 } 827 828 return response; 829 } 830 831 void Handler::_processPostGetPDRActions(sdeventplus::source::EventBase& 832 /*source */) 833 { 834 deferredGetPDREvent.reset(); 835 dbusToPLDMEventHandler->listenSensorEvent(pdrRepo, sensorDbusObjMaps); 836 } 837 838 bool isOemStateSensor(Handler& handler, uint16_t sensorId, 839 uint8_t sensorRearmCount, uint8_t& compSensorCnt, 840 uint16_t& entityType, uint16_t& entityInstance, 841 uint16_t& stateSetId) 842 { 843 pldm_state_sensor_pdr* pdr = nullptr; 844 845 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateSensorPdrRepo( 846 pldm_pdr_init(), pldm_pdr_destroy); 847 if (!stateSensorPdrRepo) 848 { 849 error("Failed to instantiate state sensor PDR repository"); 850 return false; 851 } 852 Repo stateSensorPDRs(stateSensorPdrRepo.get()); 853 getRepoByType(handler.getRepo(), stateSensorPDRs, PLDM_STATE_SENSOR_PDR); 854 if (stateSensorPDRs.empty()) 855 { 856 error("Failed to get record by PDR type"); 857 return false; 858 } 859 860 PdrEntry pdrEntry{}; 861 auto pdrRecord = stateSensorPDRs.getFirstRecord(pdrEntry); 862 while (pdrRecord) 863 { 864 pdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdrEntry.data); 865 assert(pdr != NULL); 866 if (pdr->sensor_id != sensorId) 867 { 868 pdr = nullptr; 869 pdrRecord = stateSensorPDRs.getNextRecord(pdrRecord, pdrEntry); 870 continue; 871 } 872 auto tmpEntityType = pdr->entity_type; 873 auto tmpEntityInstance = pdr->entity_instance; 874 auto tmpCompSensorCnt = pdr->composite_sensor_count; 875 auto tmpPossibleStates = 876 reinterpret_cast<state_sensor_possible_states*>( 877 pdr->possible_states); 878 auto tmpStateSetId = tmpPossibleStates->state_set_id; 879 880 if (sensorRearmCount > tmpCompSensorCnt) 881 { 882 error( 883 "The requester sent wrong sensor rearm count '{SENSOR_REARM_COUNT}' for the sensor ID '{SENSORID}'.", 884 "SENSOR_REARM_COUNT", (uint16_t)sensorRearmCount, "SENSORID", 885 sensorId); 886 break; 887 } 888 889 if ((tmpEntityType >= PLDM_OEM_ENTITY_TYPE_START && 890 tmpEntityType <= PLDM_OEM_ENTITY_TYPE_END) || 891 (tmpStateSetId >= PLDM_OEM_STATE_SET_ID_START && 892 tmpStateSetId < PLDM_OEM_STATE_SET_ID_END)) 893 { 894 entityType = tmpEntityType; 895 entityInstance = tmpEntityInstance; 896 stateSetId = tmpStateSetId; 897 compSensorCnt = tmpCompSensorCnt; 898 return true; 899 } 900 else 901 { 902 return false; 903 } 904 } 905 return false; 906 } 907 908 bool isOemStateEffecter(Handler& handler, uint16_t effecterId, 909 uint8_t compEffecterCnt, uint16_t& entityType, 910 uint16_t& entityInstance, uint16_t& stateSetId) 911 { 912 pldm_state_effecter_pdr* pdr = nullptr; 913 914 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateEffecterPdrRepo( 915 pldm_pdr_init(), pldm_pdr_destroy); 916 if (!stateEffecterPdrRepo) 917 { 918 error("Failed to instantiate state effecter PDR repository"); 919 return false; 920 } 921 Repo stateEffecterPDRs(stateEffecterPdrRepo.get()); 922 getRepoByType(handler.getRepo(), stateEffecterPDRs, 923 PLDM_STATE_EFFECTER_PDR); 924 if (stateEffecterPDRs.empty()) 925 { 926 error("Failed to get record by PDR type"); 927 return false; 928 } 929 930 PdrEntry pdrEntry{}; 931 auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry); 932 while (pdrRecord) 933 { 934 pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data); 935 assert(pdr != NULL); 936 if (pdr->effecter_id != effecterId) 937 { 938 pdr = nullptr; 939 pdrRecord = stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); 940 continue; 941 } 942 943 auto tmpEntityType = pdr->entity_type; 944 auto tmpEntityInstance = pdr->entity_instance; 945 auto tmpPossibleStates = 946 reinterpret_cast<state_effecter_possible_states*>( 947 pdr->possible_states); 948 auto tmpStateSetId = tmpPossibleStates->state_set_id; 949 950 if (compEffecterCnt > pdr->composite_effecter_count) 951 { 952 error( 953 "The requester sent wrong composite effecter count '{COMPOSITE_EFFECTER_COUNT}' for the effecter ID '{EFFECTERID}'.", 954 "COMPOSITE_EFFECTER_COUNT", compEffecterCnt, "EFFECTERID", 955 effecterId); 956 return false; 957 } 958 959 if ((tmpEntityType >= PLDM_OEM_ENTITY_TYPE_START && 960 tmpEntityType <= PLDM_OEM_ENTITY_TYPE_END) || 961 (tmpStateSetId >= PLDM_OEM_STATE_SET_ID_START && 962 tmpStateSetId < PLDM_OEM_STATE_SET_ID_END)) 963 { 964 entityType = tmpEntityType; 965 entityInstance = tmpEntityInstance; 966 stateSetId = tmpStateSetId; 967 return true; 968 } 969 else 970 { 971 return false; 972 } 973 } 974 return false; 975 } 976 977 void Handler::setEventReceiver() 978 { 979 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 980 PLDM_SET_EVENT_RECEIVER_REQ_BYTES); 981 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 982 auto instanceId = instanceIdDb->next(eid); 983 uint8_t eventMessageGlobalEnable = 984 PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE; 985 uint8_t transportProtocolType = PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP; 986 uint8_t eventReceiverAddressInfo = pldm::responder::pdr::BmcMctpEid; 987 uint16_t heartbeatTimer = HEARTBEAT_TIMEOUT; 988 989 auto rc = encode_set_event_receiver_req( 990 instanceId, eventMessageGlobalEnable, transportProtocolType, 991 eventReceiverAddressInfo, heartbeatTimer, request); 992 if (rc != PLDM_SUCCESS) 993 { 994 instanceIdDb->free(eid, instanceId); 995 error( 996 "Failed to encode set event receiver request, response code '{RC}'", 997 "RC", lg2::hex, rc); 998 return; 999 } 1000 1001 auto processSetEventReceiverResponse = 1002 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 1003 if (response == nullptr || !respMsgLen) 1004 { 1005 error("Failed to receive response for setEventReceiver command"); 1006 return; 1007 } 1008 1009 uint8_t completionCode{}; 1010 auto rc = decode_set_event_receiver_resp(response, respMsgLen, 1011 &completionCode); 1012 if (rc || completionCode) 1013 { 1014 error( 1015 "Failed to decode setEventReceiver command, response code '{RC}' and completion code '{CC}'", 1016 "RC", rc, "CC", completionCode); 1017 pldm::utils::reportError( 1018 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 1019 } 1020 }; 1021 rc = handler->registerRequest( 1022 eid, instanceId, PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER, 1023 std::move(requestMsg), std::move(processSetEventReceiverResponse)); 1024 1025 if (rc != PLDM_SUCCESS) 1026 { 1027 error("Failed to send the setEventReceiver request"); 1028 } 1029 1030 if (oemPlatformHandler) 1031 { 1032 oemPlatformHandler->countSetEventReceiver(); 1033 oemPlatformHandler->checkAndDisableWatchDog(); 1034 } 1035 } 1036 1037 } // namespace platform 1038 } // namespace responder 1039 } // namespace pldm 1040