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
Terminus(pldm_tid_t tid,uint64_t supportedTypes)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
doesSupportType(uint8_t type)23 bool Terminus::doesSupportType(uint8_t type)
24 {
25 return supportedTypes.test(type);
26 }
27
doesSupportCommand(uint8_t type,uint8_t command)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
findTerminusName()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
createInventoryPath(std::string tName)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
parseTerminusPDRs()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>
getSensorAuxiliaryNames(SensorId id)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>
parseSensorAuxiliaryNamesPDR(const std::vector<uint8_t> & pdrData)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>
parseEntityAuxiliaryNamesPDR(const std::vector<uint8_t> & pdrData)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>
parseNumericSensorPDR(const std::vector<uint8_t> & 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
addNumericSensor(const std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr)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>
parseCompactNumericSensorNames(const std::vector<uint8_t> & sPdr)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>
parseCompactNumericSensorPDR(const std::vector<uint8_t> & sPdr)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
addCompactNumericSensor(const std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr)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
getSensorObject(SensorId id)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 */
isTableEnd(const uint8_t * table,const uint8_t * p,const size_t tableSize)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
updateInventoryWithFru(const uint8_t * fruData,const size_t fruLen)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