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