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