1 #include "terminus.hpp" 2 3 #include "libpldm/platform.h" 4 5 #include "dbus_impl_fru.hpp" 6 #include "terminus_manager.hpp" 7 8 #include <common/utils.hpp> 9 10 #include <ranges> 11 12 namespace pldm 13 { 14 namespace platform_mc 15 { 16 17 Terminus::Terminus(pldm_tid_t tid, uint64_t supportedTypes) : 18 initialized(false), maxBufferSize(PLDM_PLATFORM_EVENT_MSG_MAX_BUFFER_SIZE), 19 synchronyConfigurationSupported(0), pollEvent(false), tid(tid), 20 supportedTypes(supportedTypes) 21 {} 22 23 bool Terminus::doesSupportType(uint8_t type) 24 { 25 return supportedTypes.test(type); 26 } 27 28 bool Terminus::doesSupportCommand(uint8_t type, uint8_t command) 29 { 30 if (!doesSupportType(type)) 31 { 32 return false; 33 } 34 35 try 36 { 37 const size_t idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + (command / 8); 38 if (idx >= supportedCmds.size()) 39 { 40 return false; 41 } 42 43 if (supportedCmds[idx] & (1 << (command % 8))) 44 { 45 lg2::info( 46 "PLDM type {TYPE} command {CMD} is supported by terminus {TID}", 47 "TYPE", type, "CMD", command, "TID", getTid()); 48 return true; 49 } 50 } 51 catch (const std::exception& e) 52 { 53 return false; 54 } 55 56 return false; 57 } 58 59 std::optional<std::string_view> Terminus::findTerminusName() 60 { 61 auto it = std::find_if( 62 entityAuxiliaryNamesTbl.begin(), entityAuxiliaryNamesTbl.end(), 63 [](const std::shared_ptr<EntityAuxiliaryNames>& entityAuxiliaryNames) { 64 const auto& [key, entityNames] = *entityAuxiliaryNames; 65 /** 66 * There is only one Overall system container entity in one 67 * terminus. The entity auxiliary name PDR of that terminus with the 68 * that type of containerID will include terminus name. 69 */ 70 return ( 71 entityAuxiliaryNames && 72 key.containerId == PLDM_PLATFORM_ENTITY_SYSTEM_CONTAINER_ID && 73 entityNames.size()); 74 }); 75 76 if (it != entityAuxiliaryNamesTbl.end()) 77 { 78 const auto& [key, entityNames] = **it; 79 if (!entityNames.size()) 80 { 81 return std::nullopt; 82 } 83 return entityNames[0].second; 84 } 85 86 return std::nullopt; 87 } 88 89 bool Terminus::createInventoryPath(std::string tName) 90 { 91 if (tName.empty()) 92 { 93 return false; 94 } 95 96 /* inventory object is created */ 97 if (inventoryItemBoardInft) 98 { 99 return false; 100 } 101 102 inventoryPath = "/xyz/openbmc_project/inventory/system/board/" + tName; 103 try 104 { 105 inventoryItemBoardInft = 106 std::make_unique<pldm::dbus_api::PldmEntityReq>( 107 utils::DBusHandler::getBus(), inventoryPath.c_str()); 108 return true; 109 } 110 catch (const sdbusplus::exception_t& e) 111 { 112 lg2::error( 113 "Failed to create Inventory Board interface for device {PATH}", 114 "PATH", inventoryPath); 115 } 116 117 return false; 118 } 119 120 void Terminus::parseTerminusPDRs() 121 { 122 std::vector<std::shared_ptr<pldm_numeric_sensor_value_pdr>> 123 numericSensorPdrs{}; 124 std::vector<std::shared_ptr<pldm_compact_numeric_sensor_pdr>> 125 compactNumericSensorPdrs{}; 126 127 for (auto& pdr : pdrs) 128 { 129 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data()); 130 switch (pdrHdr->type) 131 { 132 case PLDM_SENSOR_AUXILIARY_NAMES_PDR: 133 { 134 auto sensorAuxNames = parseSensorAuxiliaryNamesPDR(pdr); 135 if (!sensorAuxNames) 136 { 137 lg2::error( 138 "Failed to parse PDR with type {TYPE} handle {HANDLE}", 139 "TYPE", pdrHdr->type, "HANDLE", 140 static_cast<uint32_t>(pdrHdr->record_handle)); 141 continue; 142 } 143 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames)); 144 break; 145 } 146 case PLDM_NUMERIC_SENSOR_PDR: 147 { 148 auto parsedPdr = parseNumericSensorPDR(pdr); 149 if (!parsedPdr) 150 { 151 lg2::error( 152 "Failed to parse PDR with type {TYPE} handle {HANDLE}", 153 "TYPE", pdrHdr->type, "HANDLE", 154 static_cast<uint32_t>(pdrHdr->record_handle)); 155 continue; 156 } 157 numericSensorPdrs.emplace_back(std::move(parsedPdr)); 158 break; 159 } 160 case PLDM_COMPACT_NUMERIC_SENSOR_PDR: 161 { 162 auto parsedPdr = parseCompactNumericSensorPDR(pdr); 163 if (!parsedPdr) 164 { 165 lg2::error( 166 "Failed to parse PDR with type {TYPE} handle {HANDLE}", 167 "TYPE", pdrHdr->type, "HANDLE", 168 static_cast<uint32_t>(pdrHdr->record_handle)); 169 continue; 170 } 171 auto sensorAuxNames = parseCompactNumericSensorNames(pdr); 172 if (!sensorAuxNames) 173 { 174 lg2::error( 175 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}", 176 "TYPE", pdrHdr->type, "HANDLE", 177 static_cast<uint32_t>(pdrHdr->record_handle)); 178 continue; 179 } 180 compactNumericSensorPdrs.emplace_back(std::move(parsedPdr)); 181 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames)); 182 break; 183 } 184 case PLDM_ENTITY_AUXILIARY_NAMES_PDR: 185 { 186 auto entityNames = parseEntityAuxiliaryNamesPDR(pdr); 187 if (!entityNames) 188 { 189 lg2::error( 190 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}", 191 "TYPE", pdrHdr->type, "HANDLE", 192 static_cast<uint32_t>(pdrHdr->record_handle)); 193 continue; 194 } 195 entityAuxiliaryNamesTbl.emplace_back(std::move(entityNames)); 196 break; 197 } 198 default: 199 { 200 lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}", 201 "TYPE", pdrHdr->type, "HANDLE", 202 static_cast<uint32_t>(pdrHdr->record_handle)); 203 break; 204 } 205 } 206 } 207 208 auto tName = findTerminusName(); 209 if (tName && !tName.value().empty()) 210 { 211 lg2::info("Terminus {TID} has Auxiliary Name {NAME}.", "TID", tid, 212 "NAME", tName.value()); 213 terminusName = static_cast<std::string>(tName.value()); 214 } 215 216 if (terminusName.empty() && 217 (numericSensorPdrs.size() || compactNumericSensorPdrs.size())) 218 { 219 lg2::error( 220 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.", 221 "TID", tid); 222 return; 223 } 224 225 if (createInventoryPath(terminusName)) 226 { 227 lg2::error("Terminus ID {TID}: Created Inventory path {PATH}.", "TID", 228 tid, "PATH", inventoryPath); 229 } 230 231 for (auto pdr : numericSensorPdrs) 232 { 233 addNumericSensor(pdr); 234 } 235 236 for (auto pdr : compactNumericSensorPdrs) 237 { 238 addCompactNumericSensor(pdr); 239 } 240 } 241 242 std::shared_ptr<SensorAuxiliaryNames> 243 Terminus::getSensorAuxiliaryNames(SensorId id) 244 { 245 auto it = std::find_if( 246 sensorAuxiliaryNamesTbl.begin(), sensorAuxiliaryNamesTbl.end(), 247 [id]( 248 const std::shared_ptr<SensorAuxiliaryNames>& sensorAuxiliaryNames) { 249 const auto& [sensorId, sensorCnt, sensorNames] = 250 *sensorAuxiliaryNames; 251 return sensorId == id; 252 }); 253 254 if (it != sensorAuxiliaryNamesTbl.end()) 255 { 256 return *it; 257 } 258 return nullptr; 259 }; 260 261 std::shared_ptr<SensorAuxiliaryNames> 262 Terminus::parseSensorAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData) 263 { 264 constexpr uint8_t nullTerminator = 0; 265 auto pdr = reinterpret_cast<const struct pldm_sensor_auxiliary_names_pdr*>( 266 pdrData.data()); 267 const uint8_t* ptr = pdr->names; 268 std::vector<AuxiliaryNames> sensorAuxNames{}; 269 char16_t alignedBuffer[PLDM_STR_UTF_16_MAX_LEN]; 270 for ([[maybe_unused]] const auto& sensor : 271 std::views::iota(0, static_cast<int>(pdr->sensor_count))) 272 { 273 const uint8_t nameStringCount = static_cast<uint8_t>(*ptr); 274 ptr += sizeof(uint8_t); 275 AuxiliaryNames nameStrings{}; 276 for ([[maybe_unused]] const auto& count : 277 std::views::iota(0, static_cast<int>(nameStringCount))) 278 { 279 std::string_view nameLanguageTag( 280 reinterpret_cast<const char*>(ptr)); 281 ptr += nameLanguageTag.size() + sizeof(nullTerminator); 282 283 int u16NameStringLen = 0; 284 for (int i = 0; ptr[i] != 0 || ptr[i + 1] != 0; i += 2) 285 { 286 u16NameStringLen++; 287 } 288 /* include terminator */ 289 u16NameStringLen++; 290 291 std::fill(std::begin(alignedBuffer), std::end(alignedBuffer), 0); 292 if (u16NameStringLen > PLDM_STR_UTF_16_MAX_LEN) 293 { 294 lg2::error("Sensor name to long."); 295 return nullptr; 296 } 297 memcpy(alignedBuffer, ptr, u16NameStringLen * sizeof(uint16_t)); 298 std::u16string u16NameString(alignedBuffer, u16NameStringLen); 299 ptr += u16NameString.size() * sizeof(uint16_t); 300 std::transform(u16NameString.cbegin(), u16NameString.cend(), 301 u16NameString.begin(), 302 [](uint16_t utf16) { return be16toh(utf16); }); 303 std::string nameString = 304 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, 305 char16_t>{} 306 .to_bytes(u16NameString); 307 nameStrings.emplace_back(std::make_pair( 308 nameLanguageTag, pldm::utils::trimNameForDbus(nameString))); 309 } 310 sensorAuxNames.emplace_back(std::move(nameStrings)); 311 } 312 return std::make_shared<SensorAuxiliaryNames>( 313 pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames)); 314 } 315 316 std::shared_ptr<EntityAuxiliaryNames> 317 Terminus::parseEntityAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData) 318 { 319 auto names_offset = sizeof(struct pldm_pdr_hdr) + 320 PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH; 321 auto names_size = pdrData.size() - names_offset; 322 323 size_t decodedPdrSize = 324 sizeof(struct pldm_entity_auxiliary_names_pdr) + names_size; 325 auto vPdr = std::vector<char>(decodedPdrSize); 326 auto decodedPdr = 327 reinterpret_cast<struct pldm_entity_auxiliary_names_pdr*>(vPdr.data()); 328 329 auto rc = decode_entity_auxiliary_names_pdr(pdrData.data(), pdrData.size(), 330 decodedPdr, decodedPdrSize); 331 332 if (rc) 333 { 334 lg2::error( 335 "Failed to decode Entity Auxiliary Name PDR data, error {RC}.", 336 "RC", rc); 337 return nullptr; 338 } 339 340 auto vNames = 341 std::vector<pldm_entity_auxiliary_name>(decodedPdr->name_string_count); 342 decodedPdr->names = vNames.data(); 343 344 rc = decode_pldm_entity_auxiliary_names_pdr_index(decodedPdr); 345 if (rc) 346 { 347 lg2::error("Failed to decode Entity Auxiliary Name, error {RC}.", "RC", 348 rc); 349 return nullptr; 350 } 351 352 AuxiliaryNames nameStrings{}; 353 for (const auto& count : 354 std::views::iota(0, static_cast<int>(decodedPdr->name_string_count))) 355 { 356 std::string_view nameLanguageTag = 357 static_cast<std::string_view>(decodedPdr->names[count].tag); 358 const size_t u16NameStringLen = 359 std::char_traits<char16_t>::length(decodedPdr->names[count].name); 360 std::u16string u16NameString(decodedPdr->names[count].name, 361 u16NameStringLen); 362 std::transform(u16NameString.cbegin(), u16NameString.cend(), 363 u16NameString.begin(), 364 [](uint16_t utf16) { return be16toh(utf16); }); 365 std::string nameString = 366 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{} 367 .to_bytes(u16NameString); 368 nameStrings.emplace_back(std::make_pair( 369 nameLanguageTag, pldm::utils::trimNameForDbus(nameString))); 370 } 371 372 EntityKey key{decodedPdr->container.entity_type, 373 decodedPdr->container.entity_instance_num, 374 decodedPdr->container.entity_container_id}; 375 376 return std::make_shared<EntityAuxiliaryNames>(key, nameStrings); 377 } 378 379 std::shared_ptr<pldm_numeric_sensor_value_pdr> 380 Terminus::parseNumericSensorPDR(const std::vector<uint8_t>& pdr) 381 { 382 const uint8_t* ptr = pdr.data(); 383 auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>(); 384 auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get()); 385 if (rc) 386 { 387 return nullptr; 388 } 389 return parsedPdr; 390 } 391 392 void Terminus::addNumericSensor( 393 const std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr) 394 { 395 uint16_t sensorId = pdr->sensor_id; 396 if (terminusName.empty()) 397 { 398 lg2::error( 399 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.", 400 "TID", tid); 401 return; 402 } 403 std::string sensorName = 404 terminusName + "_" + "Sensor_" + std::to_string(pdr->sensor_id); 405 406 if (pdr->sensor_auxiliary_names_pdr) 407 { 408 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId); 409 if (sensorAuxiliaryNames) 410 { 411 const auto& [sensorId, sensorCnt, sensorNames] = 412 *sensorAuxiliaryNames; 413 if (sensorCnt == 1) 414 { 415 for (const auto& [languageTag, name] : sensorNames[0]) 416 { 417 if (languageTag == "en" && !name.empty()) 418 { 419 sensorName = terminusName + "_" + name; 420 } 421 } 422 } 423 } 424 } 425 426 try 427 { 428 auto sensor = std::make_shared<NumericSensor>( 429 tid, true, pdr, sensorName, inventoryPath); 430 lg2::info("Created NumericSensor {NAME}", "NAME", sensorName); 431 numericSensors.emplace_back(sensor); 432 } 433 catch (const sdbusplus::exception_t& e) 434 { 435 lg2::error( 436 "Failed to create NumericSensor. error - {ERROR} sensorname - {NAME}", 437 "ERROR", e, "NAME", sensorName); 438 } 439 } 440 441 std::shared_ptr<SensorAuxiliaryNames> 442 Terminus::parseCompactNumericSensorNames(const std::vector<uint8_t>& sPdr) 443 { 444 std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>> 445 sensorAuxNames{}; 446 AuxiliaryNames nameStrings{}; 447 auto pdr = 448 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data()); 449 450 if (sPdr.size() < 451 (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t))) 452 { 453 return nullptr; 454 } 455 456 if (!pdr->sensor_name_length || 457 (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) - 458 sizeof(uint8_t) + pdr->sensor_name_length))) 459 { 460 return nullptr; 461 } 462 463 std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name), 464 pdr->sensor_name_length); 465 nameStrings.emplace_back( 466 std::make_pair("en", pldm::utils::trimNameForDbus(nameString))); 467 sensorAuxNames.emplace_back(std::move(nameStrings)); 468 469 return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1, 470 std::move(sensorAuxNames)); 471 } 472 473 std::shared_ptr<pldm_compact_numeric_sensor_pdr> 474 Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr) 475 { 476 auto pdr = 477 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data()); 478 if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr)) 479 { 480 // Handle error: input data too small to contain valid pdr 481 return nullptr; 482 } 483 auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>(); 484 485 parsedPdr->hdr = pdr->hdr; 486 parsedPdr->terminus_handle = pdr->terminus_handle; 487 parsedPdr->sensor_id = pdr->sensor_id; 488 parsedPdr->entity_type = pdr->entity_type; 489 parsedPdr->entity_instance = pdr->entity_instance; 490 parsedPdr->container_id = pdr->container_id; 491 parsedPdr->sensor_name_length = pdr->sensor_name_length; 492 parsedPdr->base_unit = pdr->base_unit; 493 parsedPdr->unit_modifier = pdr->unit_modifier; 494 parsedPdr->occurrence_rate = pdr->occurrence_rate; 495 parsedPdr->range_field_support = pdr->range_field_support; 496 parsedPdr->warning_high = pdr->warning_high; 497 parsedPdr->warning_low = pdr->warning_low; 498 parsedPdr->critical_high = pdr->critical_high; 499 parsedPdr->critical_low = pdr->critical_low; 500 parsedPdr->fatal_high = pdr->fatal_high; 501 parsedPdr->fatal_low = pdr->fatal_low; 502 return parsedPdr; 503 } 504 505 void Terminus::addCompactNumericSensor( 506 const std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr) 507 { 508 uint16_t sensorId = pdr->sensor_id; 509 if (terminusName.empty()) 510 { 511 lg2::error( 512 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.", 513 "TID", tid); 514 return; 515 } 516 std::string sensorName = 517 terminusName + "_" + "Sensor_" + std::to_string(pdr->sensor_id); 518 519 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId); 520 if (sensorAuxiliaryNames) 521 { 522 const auto& [sensorId, sensorCnt, sensorNames] = *sensorAuxiliaryNames; 523 if (sensorCnt == 1) 524 { 525 for (const auto& [languageTag, name] : sensorNames[0]) 526 { 527 if (languageTag == "en" && !name.empty()) 528 { 529 sensorName = terminusName + "_" + name; 530 } 531 } 532 } 533 } 534 535 try 536 { 537 auto sensor = std::make_shared<NumericSensor>( 538 tid, true, pdr, sensorName, inventoryPath); 539 lg2::info("Created Compact NumericSensor {NAME}", "NAME", sensorName); 540 numericSensors.emplace_back(sensor); 541 } 542 catch (const sdbusplus::exception_t& e) 543 { 544 lg2::error( 545 "Failed to create Compact NumericSensor. error - {ERROR} sensorname - {NAME}", 546 "ERROR", e, "NAME", sensorName); 547 } 548 } 549 550 std::shared_ptr<NumericSensor> Terminus::getSensorObject(SensorId id) 551 { 552 if (terminusName.empty()) 553 { 554 lg2::error( 555 "Terminus ID {TID}: DOES NOT have terminus name. No numeric sensor object.", 556 "TID", tid); 557 return nullptr; 558 } 559 if (!numericSensors.size()) 560 { 561 lg2::error("Terminus ID {TID} name {NAME}: DOES NOT have sensor.", 562 "TID", tid, "NAME", terminusName); 563 return nullptr; 564 } 565 566 for (auto& sensor : numericSensors) 567 { 568 if (!sensor) 569 { 570 continue; 571 } 572 573 if (sensor->sensorId == id) 574 { 575 return sensor; 576 } 577 } 578 579 return nullptr; 580 } 581 582 /** @brief Check if a pointer is go through end of table 583 * @param[in] table - pointer to FRU record table 584 * @param[in] p - pointer to each record of FRU record table 585 * @param[in] tableSize - FRU table size 586 */ 587 static bool isTableEnd(const uint8_t* table, const uint8_t* p, 588 const size_t tableSize) 589 { 590 auto offset = p - table; 591 return (tableSize - offset) < sizeof(struct pldm_fru_record_data_format); 592 } 593 594 void Terminus::updateInventoryWithFru(const uint8_t* fruData, 595 const size_t fruLen) 596 { 597 auto tmp = getTerminusName(); 598 if (!tmp || tmp.value().empty()) 599 { 600 lg2::error( 601 "Terminus ID {TID}: Failed to update Inventory with Fru Data - error : Terminus name is empty.", 602 "TID", tid); 603 return; 604 } 605 606 if (createInventoryPath(static_cast<std::string>(tmp.value()))) 607 { 608 lg2::info("Terminus ID {TID}: Created Inventory path.", "TID", tid); 609 } 610 611 auto ptr = fruData; 612 while (!isTableEnd(fruData, ptr, fruLen)) 613 { 614 auto record = reinterpret_cast<const pldm_fru_record_data_format*>(ptr); 615 ptr += sizeof(pldm_fru_record_data_format) - 616 sizeof(pldm_fru_record_tlv); 617 618 if (!record->num_fru_fields) 619 { 620 lg2::error( 621 "Invalid number of fields {NUM} of Record ID Type {TYPE} of terminus {TID}", 622 "NUM", record->num_fru_fields, "TYPE", record->record_type, 623 "TID", tid); 624 return; 625 } 626 627 if (record->record_type != PLDM_FRU_RECORD_TYPE_GENERAL) 628 { 629 lg2::error( 630 "Does not support Fru Record ID Type {TYPE} of terminus {TID}", 631 "TYPE", record->record_type, "TID", tid); 632 633 for ([[maybe_unused]] const auto& idx : 634 std::views::iota(0, static_cast<int>(record->num_fru_fields))) 635 { 636 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(ptr); 637 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length; 638 } 639 continue; 640 } 641 /* FRU General record type */ 642 for ([[maybe_unused]] const auto& idx : 643 std::views::iota(0, static_cast<int>(record->num_fru_fields))) 644 { 645 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(ptr); 646 std::string fruField{}; 647 if (tlv->type != PLDM_FRU_FIELD_TYPE_IANA) 648 { 649 auto strOptional = 650 pldm::utils::fruFieldValuestring(tlv->value, tlv->length); 651 if (!strOptional) 652 { 653 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length; 654 continue; 655 } 656 fruField = strOptional.value(); 657 658 if (fruField.empty()) 659 { 660 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length; 661 continue; 662 } 663 } 664 665 switch (tlv->type) 666 { 667 case PLDM_FRU_FIELD_TYPE_MODEL: 668 inventoryItemBoardInft->model(fruField); 669 break; 670 case PLDM_FRU_FIELD_TYPE_PN: 671 inventoryItemBoardInft->partNumber(fruField); 672 break; 673 case PLDM_FRU_FIELD_TYPE_SN: 674 inventoryItemBoardInft->serialNumber(fruField); 675 break; 676 case PLDM_FRU_FIELD_TYPE_MANUFAC: 677 inventoryItemBoardInft->manufacturer(fruField); 678 break; 679 case PLDM_FRU_FIELD_TYPE_NAME: 680 inventoryItemBoardInft->names({fruField}); 681 break; 682 case PLDM_FRU_FIELD_TYPE_VERSION: 683 inventoryItemBoardInft->version(fruField); 684 break; 685 case PLDM_FRU_FIELD_TYPE_ASSET_TAG: 686 inventoryItemBoardInft->assetTag(fruField); 687 break; 688 case PLDM_FRU_FIELD_TYPE_VENDOR: 689 case PLDM_FRU_FIELD_TYPE_CHASSIS: 690 case PLDM_FRU_FIELD_TYPE_SKU: 691 case PLDM_FRU_FIELD_TYPE_DESC: 692 case PLDM_FRU_FIELD_TYPE_EC_LVL: 693 case PLDM_FRU_FIELD_TYPE_OTHER: 694 break; 695 case PLDM_FRU_FIELD_TYPE_IANA: 696 auto iana = 697 pldm::utils::fruFieldParserU32(tlv->value, tlv->length); 698 if (!iana) 699 { 700 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length; 701 continue; 702 } 703 break; 704 } 705 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length; 706 } 707 } 708 } 709 710 } // namespace platform_mc 711 } // namespace pldm 712