xref: /openbmc/pldm/fw-update/inventory_manager.cpp (revision 22bcb07d7f48f5ff237776bf6450baca3875db20)
1 #include "inventory_manager.hpp"
2 
3 #include "common/utils.hpp"
4 #include "xyz/openbmc_project/Software/Version/server.hpp"
5 
6 #include <libpldm/firmware_update.h>
7 
8 #include <phosphor-logging/lg2.hpp>
9 
10 #include <functional>
11 
12 PHOSPHOR_LOG2_USING;
13 
14 namespace pldm
15 {
16 namespace fw_update
17 {
discoverFDs(const std::vector<mctp_eid_t> & eids)18 void InventoryManager::discoverFDs(const std::vector<mctp_eid_t>& eids)
19 {
20     for (const auto& eid : eids)
21     {
22         try
23         {
24             sendQueryDeviceIdentifiersRequest(eid);
25         }
26         catch (const std::exception& e)
27         {
28             error(
29                 "Failed to discover file descriptors for endpoint ID {EID} with {ERROR}",
30                 "EID", eid, "ERROR", e);
31         }
32     }
33 }
34 
sendQueryDeviceIdentifiersRequest(mctp_eid_t eid)35 void InventoryManager::sendQueryDeviceIdentifiersRequest(mctp_eid_t eid)
36 {
37     auto instanceId = instanceIdDb.next(eid);
38     Request requestMsg(
39         sizeof(pldm_msg_hdr) + PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES);
40     auto request = new (requestMsg.data()) pldm_msg;
41     auto rc = encode_query_device_identifiers_req(
42         instanceId, PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES, request);
43     if (rc)
44     {
45         instanceIdDb.free(eid, instanceId);
46         error(
47             "Failed to encode query device identifiers request for endpoint ID {EID} with response code {RC}",
48             "EID", eid, "RC", rc);
49         throw std::runtime_error(
50             "Failed to encode QueryDeviceIdentifiers request");
51     }
52 
53     rc = handler.registerRequest(
54         eid, instanceId, PLDM_FWUP, PLDM_QUERY_DEVICE_IDENTIFIERS,
55         std::move(requestMsg),
56         [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
57             this->queryDeviceIdentifiers(eid, response, respMsgLen);
58         });
59     if (rc)
60     {
61         error(
62             "Failed to send query device identifiers request for endpoint ID {EID} with response code {RC}",
63             "EID", eid, "RC", rc);
64         throw std::runtime_error(
65             "Failed to send QueryDeviceIdentifiers request");
66     }
67 }
68 
queryDeviceIdentifiers(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)69 void InventoryManager::queryDeviceIdentifiers(
70     mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
71 {
72     if (response == nullptr || !respMsgLen)
73     {
74         error(
75             "No response received for query device identifiers for endpoint ID {EID}",
76             "EID", eid);
77         return;
78     }
79 
80     uint8_t completionCode = PLDM_SUCCESS;
81     uint32_t deviceIdentifiersLen = 0;
82     uint8_t descriptorCount = 0;
83     uint8_t* descriptorPtr = nullptr;
84 
85     auto rc = decode_query_device_identifiers_resp(
86         response, respMsgLen, &completionCode, &deviceIdentifiersLen,
87         &descriptorCount, &descriptorPtr);
88     if (rc)
89     {
90         error(
91             "Failed to decode query device identifiers response for endpoint ID {EID} and descriptor count {DESCRIPTOR_COUNT}, response code {RC}",
92             "EID", eid, "DESCRIPTOR_COUNT", descriptorCount, "RC", rc);
93         return;
94     }
95 
96     if (completionCode)
97     {
98         error(
99             "Failed to query device identifiers response for endpoint ID {EID}, completion code {CC}",
100             "EID", eid, "CC", completionCode);
101         return;
102     }
103 
104     Descriptors descriptors{};
105     while (descriptorCount-- && (deviceIdentifiersLen > 0))
106     {
107         uint16_t descriptorType = 0;
108         variable_field descriptorData{};
109 
110         rc = decode_descriptor_type_length_value(
111             descriptorPtr, deviceIdentifiersLen, &descriptorType,
112             &descriptorData);
113         if (rc)
114         {
115             error(
116                 "Failed to decode descriptor type {TYPE}, length {LENGTH} and value for endpoint ID {EID}, response code {RC}",
117                 "TYPE", descriptorType, "LENGTH", deviceIdentifiersLen, "EID",
118                 eid, "RC", rc);
119             return;
120         }
121 
122         if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
123         {
124             std::vector<uint8_t> descData(
125                 descriptorData.ptr, descriptorData.ptr + descriptorData.length);
126             descriptors.emplace(descriptorType, std::move(descData));
127         }
128         else
129         {
130             uint8_t descriptorTitleStrType = 0;
131             variable_field descriptorTitleStr{};
132             variable_field vendorDefinedDescriptorData{};
133 
134             rc = decode_vendor_defined_descriptor_value(
135                 descriptorData.ptr, descriptorData.length,
136                 &descriptorTitleStrType, &descriptorTitleStr,
137                 &vendorDefinedDescriptorData);
138             if (rc)
139             {
140                 error(
141                     "Failed to decode vendor-defined descriptor value for endpoint ID {EID}, response code {RC}",
142                     "EID", eid, "RC", rc);
143                 return;
144             }
145 
146             auto vendorDefinedDescriptorTitleStr =
147                 utils::toString(descriptorTitleStr);
148             std::vector<uint8_t> vendorDescData(
149                 vendorDefinedDescriptorData.ptr,
150                 vendorDefinedDescriptorData.ptr +
151                     vendorDefinedDescriptorData.length);
152             descriptors.emplace(descriptorType,
153                                 std::make_tuple(vendorDefinedDescriptorTitleStr,
154                                                 vendorDescData));
155         }
156         auto nextDescriptorOffset =
157             sizeof(pldm_descriptor_tlv().descriptor_type) +
158             sizeof(pldm_descriptor_tlv().descriptor_length) +
159             descriptorData.length;
160         descriptorPtr += nextDescriptorOffset;
161         deviceIdentifiersLen -= nextDescriptorOffset;
162     }
163 
164     descriptorMap.emplace(eid, std::move(descriptors));
165 
166     // Send GetFirmwareParameters request
167     sendGetFirmwareParametersRequest(eid);
168 }
169 
sendQueryDownstreamDevicesRequest(mctp_eid_t eid)170 void InventoryManager::sendQueryDownstreamDevicesRequest(mctp_eid_t eid)
171 {
172     Request requestMsg(sizeof(pldm_msg_hdr));
173     auto instanceId = instanceIdDb.next(eid);
174     auto request = new (requestMsg.data()) pldm_msg;
175     auto rc = encode_query_downstream_devices_req(instanceId, request);
176     if (rc)
177     {
178         instanceIdDb.free(eid, instanceId);
179         error(
180             "Failed to encode query downstream devices request for endpoint ID EID {EID} with response code {RC}",
181             "EID", eid, "RC", rc);
182         throw std::runtime_error(
183             "Failed to encode query downstream devices request");
184     }
185 
186     rc = handler.registerRequest(
187         eid, instanceId, PLDM_FWUP, PLDM_QUERY_DOWNSTREAM_DEVICES,
188         std::move(requestMsg),
189         [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
190             this->queryDownstreamDevices(eid, response, respMsgLen);
191         });
192     if (rc)
193     {
194         error(
195             "Failed to send QueryDownstreamDevices request for endpoint ID {EID} with response code {RC}",
196             "EID", eid, "RC", rc);
197     }
198 }
199 
queryDownstreamDevices(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)200 void InventoryManager::queryDownstreamDevices(
201     mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
202 {
203     if (!response || !respMsgLen)
204     {
205         error(
206             "No response received for QueryDownstreamDevices for endpoint ID {EID}",
207             "EID", eid);
208         return;
209     }
210 
211     pldm_query_downstream_devices_resp downstreamDevicesResp{};
212     auto rc = decode_query_downstream_devices_resp(response, respMsgLen,
213                                                    &downstreamDevicesResp);
214     if (rc)
215     {
216         error(
217             "Decoding QueryDownstreamDevices response failed for endpoint ID {EID} with response code {RC}",
218             "EID", eid, "RC", rc);
219         return;
220     }
221 
222     switch (downstreamDevicesResp.completion_code)
223     {
224         case PLDM_SUCCESS:
225             break;
226         case PLDM_ERROR_UNSUPPORTED_PLDM_CMD:
227             /* QueryDownstreamDevices is optional, consider the device does not
228              * support Downstream Devices.
229              */
230             info("Endpoint ID {EID} does not support QueryDownstreamDevices",
231                  "EID", eid);
232             return;
233         default:
234             error(
235                 "QueryDownstreamDevices response failed with error completion code for endpoint ID {EID} with completion code {CC}",
236                 "EID", eid, "CC", downstreamDevicesResp.completion_code);
237             return;
238     }
239 
240     switch (downstreamDevicesResp.downstream_device_update_supported)
241     {
242         case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_SUPPORTED:
243             /** DataTransferHandle will be skipped when TransferOperationFlag is
244              *  `GetFirstPart`. Use 0x0 as default by following example in
245              *  Figure 9 in DSP0267 1.1.0
246              */
247             try
248             {
249                 sendQueryDownstreamIdentifiersRequest(eid, 0x0,
250                                                       PLDM_GET_FIRSTPART);
251             }
252             catch (const std::exception& e)
253             {
254                 error(
255                     "Failed to send QueryDownstreamIdentifiers request for endpoint ID {EID} with {ERROR}",
256                     "EID", eid, "ERROR", e);
257             }
258             break;
259         case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_NOT_SUPPORTED:
260             /* The FDP does not support firmware updates but may report
261              * inventory information on downstream devices.
262              * In this scenario, sends only GetDownstreamFirmwareParameters
263              * to the FDP.
264              * The definition can be found at Table 15 of DSP0267_1.1.0
265              */
266             break;
267         default:
268             error(
269                 "Unknown response of DownstreamDeviceUpdateSupported from endpoint ID {EID} with value {VALUE}",
270                 "EID", eid, "VALUE",
271                 downstreamDevicesResp.downstream_device_update_supported);
272             return;
273     }
274 }
275 
sendQueryDownstreamIdentifiersRequest(mctp_eid_t eid,uint32_t dataTransferHandle,enum transfer_op_flag transferOperationFlag)276 void InventoryManager::sendQueryDownstreamIdentifiersRequest(
277     mctp_eid_t eid, uint32_t dataTransferHandle,
278     enum transfer_op_flag transferOperationFlag)
279 {
280     auto instanceId = instanceIdDb.next(eid);
281     Request requestMsg(
282         sizeof(pldm_msg_hdr) + PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES);
283     auto request = new (requestMsg.data()) pldm_msg;
284     pldm_query_downstream_identifiers_req requestParameters{
285         dataTransferHandle, static_cast<uint8_t>(transferOperationFlag)};
286 
287     auto rc = encode_query_downstream_identifiers_req(
288         instanceId, &requestParameters, request,
289         PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES);
290     if (rc)
291     {
292         instanceIdDb.free(eid, instanceId);
293         error(
294             "Failed to encode query downstream identifiers request for endpoint ID {EID} with response code {RC}",
295             "EID", eid, "RC", rc);
296         throw std::runtime_error(
297             "Failed to encode query downstream identifiers request");
298     }
299 
300     rc = handler.registerRequest(
301         eid, instanceId, PLDM_FWUP, PLDM_QUERY_DOWNSTREAM_IDENTIFIERS,
302         std::move(requestMsg),
303         [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
304             this->queryDownstreamIdentifiers(eid, response, respMsgLen);
305         });
306     if (rc)
307     {
308         error(
309             "Failed to send QueryDownstreamIdentifiers request for endpoint ID {EID} with response code {RC}",
310             "EID", eid, "RC", rc);
311     }
312 }
313 
queryDownstreamIdentifiers(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)314 void InventoryManager::queryDownstreamIdentifiers(
315     mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
316 {
317     if (!response || !respMsgLen)
318     {
319         error(
320             "No response received for QueryDownstreamIdentifiers for endpoint ID {EID}",
321             "EID", eid);
322         descriptorMap.erase(eid);
323         return;
324     }
325 
326     pldm_query_downstream_identifiers_resp downstreamIds{};
327     pldm_downstream_device_iter devs{};
328 
329     auto rc = decode_query_downstream_identifiers_resp(response, respMsgLen,
330                                                        &downstreamIds, &devs);
331     if (rc)
332     {
333         error(
334             "Decoding QueryDownstreamIdentifiers response failed for endpoint ID {EID} with response code {RC}",
335             "EID", eid, "RC", rc);
336         return;
337     }
338 
339     if (downstreamIds.completion_code)
340     {
341         error(
342             "QueryDownstreamIdentifiers response failed with error completion code for endpoint ID {EID} with completion code {CC}",
343             "EID", eid, "CC", unsigned(downstreamIds.completion_code));
344         return;
345     }
346 
347     DownstreamDeviceInfo initialDownstreamDevices{};
348     DownstreamDeviceInfo* downstreamDevices;
349     if (!downstreamDescriptorMap.contains(eid) ||
350         downstreamIds.transfer_flag == PLDM_START ||
351         downstreamIds.transfer_flag == PLDM_START_AND_END)
352     {
353         downstreamDevices = &initialDownstreamDevices;
354     }
355     else
356     {
357         downstreamDevices = &downstreamDescriptorMap.at(eid);
358     }
359 
360     pldm_downstream_device dev;
361     foreach_pldm_downstream_device(devs, dev, rc)
362     {
363         pldm_descriptor desc;
364         Descriptors descriptors{};
365         foreach_pldm_downstream_device_descriptor(devs, dev, desc, rc)
366         {
367             const auto descriptorData =
368                 new (const_cast<void*>(desc.descriptor_data))
369                     uint8_t[desc.descriptor_length];
370             if (desc.descriptor_type != PLDM_FWUP_VENDOR_DEFINED)
371             {
372                 std::vector<uint8_t> descData(
373                     descriptorData, descriptorData + desc.descriptor_length);
374                 descriptors.emplace(desc.descriptor_type, std::move(descData));
375             }
376             else
377             {
378                 uint8_t descriptorTitleStrType = 0;
379                 variable_field descriptorTitleStr{};
380                 variable_field vendorDefinedDescriptorData{};
381 
382                 rc = decode_vendor_defined_descriptor_value(
383                     descriptorData, desc.descriptor_length,
384                     &descriptorTitleStrType, &descriptorTitleStr,
385                     &vendorDefinedDescriptorData);
386 
387                 if (rc)
388                 {
389                     error(
390                         "Decoding Vendor-defined descriptor value failed for endpoint ID {EID} with response code {RC}",
391                         "EID", eid, "RC", rc);
392                     return;
393                 }
394 
395                 auto vendorDefinedDescriptorTitleStr =
396                     utils::toString(descriptorTitleStr);
397                 std::vector<uint8_t> vendorDescData(
398                     vendorDefinedDescriptorData.ptr,
399                     vendorDefinedDescriptorData.ptr +
400                         vendorDefinedDescriptorData.length);
401                 descriptors.emplace(
402                     desc.descriptor_type,
403                     std::make_tuple(vendorDefinedDescriptorTitleStr,
404                                     vendorDescData));
405             }
406         }
407         if (rc)
408         {
409             error(
410                 "Failed to decode downstream device descriptor for endpoint ID {EID} with response code {RC}",
411                 "EID", eid, "RC", rc);
412             return;
413         }
414         downstreamDevices->emplace(dev.downstream_device_index, descriptors);
415     }
416     if (rc)
417     {
418         error(
419             "Failed to decode downstream devices from iterator for endpoint ID {EID} with response code {RC}",
420             "EID", eid, "RC", rc);
421         return;
422     }
423 
424     switch (downstreamIds.transfer_flag)
425     {
426         case PLDM_START:
427             downstreamDescriptorMap.insert_or_assign(
428                 eid, std::move(initialDownstreamDevices));
429             [[fallthrough]];
430         case PLDM_MIDDLE:
431             sendQueryDownstreamIdentifiersRequest(
432                 eid, downstreamIds.next_data_transfer_handle,
433                 PLDM_GET_NEXTPART);
434             break;
435         case PLDM_START_AND_END:
436             downstreamDescriptorMap.insert_or_assign(
437                 eid, std::move(initialDownstreamDevices));
438             /** DataTransferHandle will be skipped when TransferOperationFlag is
439              *  `GetFirstPart`. Use 0x0 as default by following example in
440              *  Figure 9 in DSP0267 1.1.0
441              */
442             [[fallthrough]];
443         case PLDM_END:
444             sendGetDownstreamFirmwareParametersRequest(eid, 0x0,
445                                                        PLDM_GET_FIRSTPART);
446             break;
447     }
448 }
449 
sendGetDownstreamFirmwareParametersRequest(mctp_eid_t eid,uint32_t dataTransferHandle,enum transfer_op_flag transferOperationFlag)450 void InventoryManager::sendGetDownstreamFirmwareParametersRequest(
451     mctp_eid_t eid, uint32_t dataTransferHandle,
452     enum transfer_op_flag transferOperationFlag)
453 {
454     Request requestMsg(sizeof(pldm_msg_hdr) +
455                        PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES);
456     auto instanceId = instanceIdDb.next(eid);
457     auto request = new (requestMsg.data()) pldm_msg;
458     pldm_get_downstream_firmware_parameters_req requestParameters{
459         dataTransferHandle, static_cast<uint8_t>(transferOperationFlag)};
460     auto rc = encode_get_downstream_firmware_parameters_req(
461         instanceId, &requestParameters, request,
462         PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES);
463     if (rc)
464     {
465         instanceIdDb.free(eid, instanceId);
466         error(
467             "Failed to encode query downstream firmware parameters request for endpoint ID {EID} with response code {RC}",
468             "EID", eid, "RC", rc);
469         throw std::runtime_error(
470             "Failed to encode query downstream firmware parameters request");
471     }
472 
473     rc = handler.registerRequest(
474         eid, instanceId, PLDM_FWUP, PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS,
475         std::move(requestMsg),
476         [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
477             this->getDownstreamFirmwareParameters(eid, response, respMsgLen);
478         });
479     if (rc)
480     {
481         error(
482             "Failed to send QueryDownstreamFirmwareParameters request for endpoint ID {EID} with response code {RC}",
483             "EID", eid, "RC", rc);
484     }
485 }
486 
getDownstreamFirmwareParameters(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)487 void InventoryManager::getDownstreamFirmwareParameters(
488     mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
489 {
490     if (!response || !respMsgLen)
491     {
492         error(
493             "No response received for QueryDownstreamFirmwareParameters for endpoint ID {EID}",
494             "EID", eid);
495         descriptorMap.erase(eid);
496         return;
497     }
498 
499     pldm_get_downstream_firmware_parameters_resp resp{};
500     pldm_downstream_device_parameters_iter params{};
501     pldm_downstream_device_parameters_entry entry{};
502 
503     auto rc = decode_get_downstream_firmware_parameters_resp(
504         response, respMsgLen, &resp, &params);
505 
506     if (rc)
507     {
508         error(
509             "Decoding QueryDownstreamFirmwareParameters response failed for endpoint ID {EID} with response code {RC}",
510             "EID", eid, "RC", rc);
511         return;
512     }
513 
514     if (resp.completion_code)
515     {
516         error(
517             "QueryDownstreamFirmwareParameters response failed with error completion code for endpoint ID {EID} with completion code {CC}",
518             "EID", eid, "CC", resp.completion_code);
519         return;
520     }
521 
522     foreach_pldm_downstream_device_parameters_entry(params, entry, rc)
523     {
524         // Reserved for upcoming use
525         [[maybe_unused]] variable_field activeCompVerStr{
526             reinterpret_cast<const uint8_t*>(entry.active_comp_ver_str),
527             entry.active_comp_ver_str_len};
528     }
529     if (rc)
530     {
531         error(
532             "Failed to decode downstream device parameters from iterator for endpoint ID {EID} with response code {RC}",
533             "EID", eid, "RC", rc);
534         return;
535     }
536 
537     switch (resp.transfer_flag)
538     {
539         case PLDM_START:
540         case PLDM_MIDDLE:
541             sendGetDownstreamFirmwareParametersRequest(
542                 eid, resp.next_data_transfer_handle, PLDM_GET_NEXTPART);
543             break;
544     }
545 }
546 
sendGetFirmwareParametersRequest(mctp_eid_t eid)547 void InventoryManager::sendGetFirmwareParametersRequest(mctp_eid_t eid)
548 {
549     auto instanceId = instanceIdDb.next(eid);
550     Request requestMsg(
551         sizeof(pldm_msg_hdr) + PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
552     auto request = new (requestMsg.data()) pldm_msg;
553     auto rc = encode_get_firmware_parameters_req(
554         instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
555     if (rc)
556     {
557         instanceIdDb.free(eid, instanceId);
558         error(
559             "Failed to encode get firmware parameters req for endpoint ID {EID}, response code {RC}",
560             "EID", eid, "RC", rc);
561         return;
562     }
563 
564     rc = handler.registerRequest(
565         eid, instanceId, PLDM_FWUP, PLDM_GET_FIRMWARE_PARAMETERS,
566         std::move(requestMsg),
567         [this](mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen) {
568             this->getFirmwareParameters(eid, response, respMsgLen);
569         });
570     if (rc)
571     {
572         error(
573             "Failed to send get firmware parameters request for endpoint ID {EID}, response code {RC}",
574             "EID", eid, "RC", rc);
575     }
576 }
577 
getFirmwareParameters(mctp_eid_t eid,const pldm_msg * response,size_t respMsgLen)578 void InventoryManager::getFirmwareParameters(
579     mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
580 {
581     if (response == nullptr || !respMsgLen)
582     {
583         error(
584             "No response received for get firmware parameters for endpoint ID {EID}",
585             "EID", eid);
586         descriptorMap.erase(eid);
587         return;
588     }
589 
590     pldm_get_firmware_parameters_resp fwParams{};
591     variable_field activeCompImageSetVerStr{};
592     variable_field pendingCompImageSetVerStr{};
593     variable_field compParamTable{};
594 
595     auto rc = decode_get_firmware_parameters_resp(
596         response, respMsgLen, &fwParams, &activeCompImageSetVerStr,
597         &pendingCompImageSetVerStr, &compParamTable);
598     if (rc)
599     {
600         error(
601             "Failed to decode get firmware parameters response for endpoint ID {EID}, response code {RC}",
602             "EID", eid, "RC", rc);
603         return;
604     }
605 
606     if (fwParams.completion_code)
607     {
608         auto fw_param_cc = fwParams.completion_code;
609         error(
610             "Failed to get firmware parameters response for endpoint ID {EID}, completion code {CC}",
611             "EID", eid, "CC", fw_param_cc);
612         return;
613     }
614 
615     auto compParamPtr = compParamTable.ptr;
616     auto compParamTableLen = compParamTable.length;
617     pldm_component_parameter_entry compEntry{};
618     variable_field activeCompVerStr{};
619     variable_field pendingCompVerStr{};
620 
621     ComponentInfo componentInfo{};
622     while (fwParams.comp_count-- && (compParamTableLen > 0))
623     {
624         auto rc = decode_get_firmware_parameters_resp_comp_entry(
625             compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
626             &pendingCompVerStr);
627         if (rc)
628         {
629             error(
630                 "Failed to decode component parameter table entry for endpoint ID {EID}, response code {RC}",
631                 "EID", eid, "RC", rc);
632             return;
633         }
634 
635         auto compClassification = compEntry.comp_classification;
636         auto compIdentifier = compEntry.comp_identifier;
637         componentInfo.emplace(
638             std::make_pair(compClassification, compIdentifier),
639             compEntry.comp_classification_index);
640         compParamPtr += sizeof(pldm_component_parameter_entry) +
641                         activeCompVerStr.length + pendingCompVerStr.length;
642         compParamTableLen -= sizeof(pldm_component_parameter_entry) +
643                              activeCompVerStr.length + pendingCompVerStr.length;
644     }
645     componentInfoMap.emplace(eid, std::move(componentInfo));
646 }
647 
648 } // namespace fw_update
649 
650 } // namespace pldm
651