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