1 #include "pldm_fw_update_cmd.hpp"
2 
3 #include "common/utils.hpp"
4 #include "pldm_cmd_helper.hpp"
5 
6 #include <libpldm/firmware_update.h>
7 
8 namespace pldmtool
9 {
10 
11 namespace fw_update
12 {
13 
14 namespace
15 {
16 
17 using namespace pldmtool::helper;
18 using namespace pldm::fw_update;
19 
20 std::vector<std::unique_ptr<CommandInterface>> commands;
21 
22 } // namespace
23 
24 const std::map<uint8_t, std::string> fdStateMachine{
25     {PLDM_FD_STATE_IDLE, "IDLE"},
26     {PLDM_FD_STATE_LEARN_COMPONENTS, "LEARN COMPONENTS"},
27     {PLDM_FD_STATE_READY_XFER, "READY XFER"},
28     {PLDM_FD_STATE_DOWNLOAD, "DOWNLOAD"},
29     {PLDM_FD_STATE_VERIFY, "VERIFY"},
30     {PLDM_FD_STATE_APPLY, "APPLY"},
31     {PLDM_FD_STATE_ACTIVATE, "ACTIVATE"}};
32 
33 const std::map<uint8_t, const char*> fdAuxState{
34     {PLDM_FD_OPERATION_IN_PROGRESS, "Operation in progress"},
35     {PLDM_FD_OPERATION_SUCCESSFUL, "Operation successful"},
36     {PLDM_FD_OPERATION_FAILED, "Operation Failed"},
37     {PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER,
38      "Not applicable in current state"}};
39 
40 const std::map<uint8_t, const char*> fdAuxStateStatus{
41     {PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS,
42      "AuxState is In Progress or Success"},
43     {PLDM_FD_TIMEOUT, "Timeout occurred while performing action"},
44     {PLDM_FD_GENERIC_ERROR, "Generic Error has occurred"}};
45 
46 const std::map<uint8_t, const char*> fdReasonCode{
47     {PLDM_FD_INITIALIZATION, "Initialization of firmware device has occurred"},
48     {PLDM_FD_ACTIVATE_FW, "ActivateFirmware command was received"},
49     {PLDM_FD_CANCEL_UPDATE, "CancelUpdate command was received"},
50     {PLDM_FD_TIMEOUT_LEARN_COMPONENT,
51      "Timeout occurred when in LEARN COMPONENT state"},
52     {PLDM_FD_TIMEOUT_READY_XFER, "Timeout occurred when in READY XFER state"},
53     {PLDM_FD_TIMEOUT_DOWNLOAD, "Timeout occurred when in DOWNLOAD state"},
54     {PLDM_FD_TIMEOUT_VERIFY, "Timeout occurred when in VERIFY state"},
55     {PLDM_FD_TIMEOUT_APPLY, "Timeout occurred when in APPLY state"}};
56 
57 /**
58  * @brief descriptor type to name mapping
59  *
60  */
61 const std::map<DescriptorType, const char*> descriptorName{
62     {PLDM_FWUP_PCI_VENDOR_ID, "PCI Vendor ID"},
63     {PLDM_FWUP_IANA_ENTERPRISE_ID, "IANA Enterprise ID"},
64     {PLDM_FWUP_UUID, "UUID"},
65     {PLDM_FWUP_PNP_VENDOR_ID, "PnP Vendor ID"},
66     {PLDM_FWUP_ACPI_VENDOR_ID, "ACPI Vendor ID"},
67     {PLDM_FWUP_PCI_DEVICE_ID, "PCI Device ID"},
68     {PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID, "PCI Subsystem Vendor ID"},
69     {PLDM_FWUP_PCI_SUBSYSTEM_ID, "PCI Subsystem ID"},
70     {PLDM_FWUP_PCI_REVISION_ID, "PCI Revision ID"},
71     {PLDM_FWUP_PNP_PRODUCT_IDENTIFIER, "PnP Product Identifier"},
72     {PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER, "ACPI Product Identifier"},
73     {PLDM_FWUP_VENDOR_DEFINED, "Vendor Defined"}};
74 
75 class GetStatus : public CommandInterface
76 {
77   public:
78     ~GetStatus() = default;
79     GetStatus() = delete;
80     GetStatus(const GetStatus&) = delete;
81     GetStatus(GetStatus&&) = default;
82     GetStatus& operator=(const GetStatus&) = delete;
83     GetStatus& operator=(GetStatus&&) = delete;
84 
85     using CommandInterface::CommandInterface;
86 
87     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
88     {
89         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
90                                         PLDM_GET_STATUS_REQ_BYTES);
91         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
92         auto rc = encode_get_status_req(instanceId, request,
93                                         PLDM_GET_STATUS_REQ_BYTES);
94         return {rc, requestMsg};
95     }
96 
97     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
98     {
99         uint8_t completionCode = 0;
100         uint8_t currentState = 0;
101         uint8_t previousState = 0;
102         uint8_t auxState = 0;
103         uint8_t auxStateStatus = 0;
104         uint8_t progressPercent = 0;
105         uint8_t reasonCode = 0;
106         bitfield32_t updateOptionFlagsEnabled{0};
107 
108         auto rc = decode_get_status_resp(
109             responsePtr, payloadLength, &completionCode, &currentState,
110             &previousState, &auxState, &auxStateStatus, &progressPercent,
111             &reasonCode, &updateOptionFlagsEnabled);
112         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
113         {
114             std::cerr << "Response Message Error: "
115                       << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
116             return;
117         }
118 
119         ordered_json data;
120         data["CurrentState"] = fdStateMachine.at(currentState);
121         data["PreviousState"] = fdStateMachine.at(previousState);
122         data["AuxState"] = fdAuxState.at(auxState);
123         if (auxStateStatus >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
124             auxStateStatus <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)
125         {
126             data["AuxStateStatus"] = auxStateStatus;
127         }
128         else
129         {
130             data["AuxStateStatus"] = fdAuxStateStatus.at(auxStateStatus);
131         }
132         data["ProgressPercent"] = progressPercent;
133         if (reasonCode >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN &&
134             reasonCode <= PLDM_FD_STATUS_VENDOR_DEFINED_MAX)
135         {
136             data["ReasonCode"] = reasonCode;
137         }
138         else
139         {
140             data["ReasonCode"] = fdReasonCode.at(reasonCode);
141         }
142         data["UpdateOptionFlagsEnabled"] = updateOptionFlagsEnabled.value;
143 
144         pldmtool::helper::DisplayInJson(data);
145     }
146 };
147 
148 const std::map<uint16_t, std::string> componentClassification{
149     {PLDM_COMP_UNKNOWN, "Unknown"},
150     {PLDM_COMP_OTHER, "Other"},
151     {PLDM_COMP_DRIVER, "Driver"},
152     {PLDM_COMP_CONFIGURATION_SOFTWARE, "Configuration Software"},
153     {PLDM_COMP_APPLICATION_SOFTWARE, "Application Software"},
154     {PLDM_COMP_INSTRUMENTATION, "Instrumentation"},
155     {PLDM_COMP_FIRMWARE_OR_BIOS, "Firmware/BIOS"},
156     {PLDM_COMP_DIAGNOSTIC_SOFTWARE, "Diagnostic Software"},
157     {PLDM_COMP_OPERATING_SYSTEM, "Operating System"},
158     {PLDM_COMP_MIDDLEWARE, "Middleware"},
159     {PLDM_COMP_FIRMWARE, "Firmware"},
160     {PLDM_COMP_BIOS_OR_FCODE, "BIOS/FCode"},
161     {PLDM_COMP_SUPPORT_OR_SERVICEPACK, "Support/Service Pack"},
162     {PLDM_COMP_SOFTWARE_BUNDLE, "Software Bundle"},
163     {PLDM_COMP_DOWNSTREAM_DEVICE, "Downstream Device"}};
164 
165 class GetFwParams : public CommandInterface
166 {
167   public:
168     ~GetFwParams() = default;
169     GetFwParams() = delete;
170     GetFwParams(const GetFwParams&) = delete;
171     GetFwParams(GetFwParams&&) = default;
172     GetFwParams& operator=(const GetFwParams&) = delete;
173     GetFwParams& operator=(GetFwParams&&) = delete;
174 
175     using CommandInterface::CommandInterface;
176 
177     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
178     {
179         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
180                                         PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
181         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
182         auto rc = encode_get_firmware_parameters_req(
183             instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
184         return {rc, requestMsg};
185     }
186 
187     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
188     {
189         pldm_get_firmware_parameters_resp fwParams{};
190         variable_field activeCompImageSetVersion{};
191         variable_field pendingCompImageSetVersion{};
192         variable_field compParameterTable{};
193 
194         auto rc = decode_get_firmware_parameters_resp(
195             responsePtr, payloadLength, &fwParams, &activeCompImageSetVersion,
196             &pendingCompImageSetVersion, &compParameterTable);
197         if (rc != PLDM_SUCCESS || fwParams.completion_code != PLDM_SUCCESS)
198         {
199             std::cerr << "Response Message Error: "
200                       << "rc=" << rc << ",cc=" << (int)fwParams.completion_code
201                       << "\n";
202             return;
203         }
204 
205         ordered_json capabilitiesDuringUpdate;
206         if (fwParams.capabilities_during_update.bits.bit0)
207         {
208             capabilitiesDuringUpdate
209                 ["Component Update Failure Recovery Capability"] =
210                     "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer.";
211         }
212         else
213         {
214             capabilitiesDuringUpdate
215                 ["Component Update Failure Recovery Capability"] =
216                     "Device will revert to previous component image upon failure, timeout or cancellation of the transfer.";
217         }
218 
219         if (fwParams.capabilities_during_update.bits.bit1)
220         {
221             capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
222                 "Device will not be able to update component again unless it exits update mode and the UA sends a new Request Update command.";
223         }
224         else
225         {
226             capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
227                 " Device can have component updated again without exiting update mode and restarting transfer via RequestUpdate command.";
228         }
229 
230         if (fwParams.capabilities_during_update.bits.bit2)
231         {
232             capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
233                 "Firmware Device can support a partial update, whereby a package which contains a component image set that is a subset of all components currently residing on the FD, can be transferred.";
234         }
235         else
236         {
237             capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
238                 "Firmware Device cannot accept a partial update and all components present on the FD shall be updated.";
239         }
240 
241         if (fwParams.capabilities_during_update.bits.bit3)
242         {
243             capabilitiesDuringUpdate
244                 ["Firmware Device Host Functionality during Firmware Update"] =
245                     "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer";
246         }
247         else
248         {
249             capabilitiesDuringUpdate
250                 ["Firmware Device Host Functionality during Firmware Update"] =
251                     "Device will revert to previous component image upon failure, timeout or cancellation of the transfer";
252         }
253 
254         if (fwParams.capabilities_during_update.bits.bit4)
255         {
256             capabilitiesDuringUpdate["Firmware Device Update Mode Restrictions"] =
257                 "Firmware device unable to enter update mode if host OS environment is active.";
258         }
259         else
260         {
261             capabilitiesDuringUpdate
262                 ["Firmware Device Update Mode Restrictions"] =
263                     "No host OS environment restriction for update mode";
264         }
265 
266         ordered_json data;
267         data["CapabilitiesDuringUpdate"] = capabilitiesDuringUpdate;
268         data["ComponentCount"] = static_cast<uint16_t>(fwParams.comp_count);
269         data["ActiveComponentImageSetVersionString"] =
270             pldm::utils::toString(activeCompImageSetVersion);
271         data["PendingComponentImageSetVersionString"] =
272             pldm::utils::toString(pendingCompImageSetVersion);
273 
274         auto compParamPtr = compParameterTable.ptr;
275         auto compParamTableLen = compParameterTable.length;
276         pldm_component_parameter_entry compEntry{};
277         variable_field activeCompVerStr{};
278         variable_field pendingCompVerStr{};
279         ordered_json compDataEntries;
280 
281         while (fwParams.comp_count-- && (compParamTableLen > 0))
282         {
283             ordered_json compData;
284             auto rc = decode_get_firmware_parameters_resp_comp_entry(
285                 compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
286                 &pendingCompVerStr);
287             if (rc)
288             {
289                 std::cerr
290                     << "Decoding component parameter table entry failed, RC="
291                     << rc << "\n";
292                 return;
293             }
294 
295             if (componentClassification.contains(compEntry.comp_classification))
296             {
297                 compData["ComponentClassification"] =
298                     componentClassification.at(compEntry.comp_classification);
299             }
300             else
301             {
302                 compData["ComponentClassification"] =
303                     static_cast<uint16_t>(compEntry.comp_classification);
304             }
305             compData["ComponentIdentifier"] =
306                 static_cast<uint16_t>(compEntry.comp_identifier);
307             compData["ComponentClassificationIndex"] =
308                 static_cast<uint8_t>(compEntry.comp_classification_index);
309             compData["ActiveComponentComparisonStamp"] =
310                 static_cast<uint32_t>(compEntry.active_comp_comparison_stamp);
311 
312             // ActiveComponentReleaseData
313             std::array<uint8_t, 8> noReleaseData{0x00, 0x00, 0x00, 0x00,
314                                                  0x00, 0x00, 0x00, 0x00};
315             if (std::equal(noReleaseData.begin(), noReleaseData.end(),
316                            compEntry.active_comp_release_date))
317             {
318                 compData["ActiveComponentReleaseDate"] = "";
319             }
320             else
321             {
322                 std::string activeComponentReleaseDate(
323                     reinterpret_cast<const char*>(
324                         compEntry.active_comp_release_date),
325                     sizeof(compEntry.active_comp_release_date));
326                 compData["ActiveComponentReleaseDate"] =
327                     activeComponentReleaseDate;
328             }
329 
330             compData["PendingComponentComparisonStamp"] =
331                 static_cast<uint32_t>(compEntry.pending_comp_comparison_stamp);
332 
333             // PendingComponentReleaseData
334             if (std::equal(noReleaseData.begin(), noReleaseData.end(),
335                            compEntry.pending_comp_release_date))
336             {
337                 compData["PendingComponentReleaseDate"] = "";
338             }
339             else
340             {
341                 std::string pendingComponentReleaseDate(
342                     reinterpret_cast<const char*>(
343                         compEntry.pending_comp_release_date),
344                     sizeof(compEntry.pending_comp_release_date));
345                 compData["PendingComponentReleaseDate"] =
346                     pendingComponentReleaseDate;
347             }
348 
349             // ComponentActivationMethods
350             ordered_json componentActivationMethods;
351             if (compEntry.comp_activation_methods.bits.bit0)
352             {
353                 componentActivationMethods.push_back("Automatic");
354             }
355             else if (compEntry.comp_activation_methods.bits.bit1)
356             {
357                 componentActivationMethods.push_back("Self-Contained");
358             }
359             else if (compEntry.comp_activation_methods.bits.bit2)
360             {
361                 componentActivationMethods.push_back("Medium-specific reset");
362             }
363             else if (compEntry.comp_activation_methods.bits.bit3)
364             {
365                 componentActivationMethods.push_back("System reboot");
366             }
367             else if (compEntry.comp_activation_methods.bits.bit4)
368             {
369                 componentActivationMethods.push_back("DC power cycel");
370             }
371             else if (compEntry.comp_activation_methods.bits.bit5)
372             {
373                 componentActivationMethods.push_back("AC power cycle");
374             }
375             compData["ComponentActivationMethods"] = componentActivationMethods;
376 
377             // CapabilitiesDuringUpdate
378             ordered_json compCapabilitiesDuringUpdate;
379             if (compEntry.capabilities_during_update.bits.bit0)
380             {
381                 compCapabilitiesDuringUpdate
382                     ["Firmware Device apply state functionality"] =
383                         "Firmware Device performs an auto-apply during transfer phase and apply step will be completed immediately.";
384             }
385             else
386             {
387                 compCapabilitiesDuringUpdate
388                     ["Firmware Device apply state functionality"] =
389                         " Firmware Device will execute an operation during the APPLY state which will include migrating the new component image to its final non-volatile storage destination.";
390             }
391             compData["CapabilitiesDuringUpdate"] = compCapabilitiesDuringUpdate;
392 
393             compData["ActiveComponentVersionString"] =
394                 pldm::utils::toString(activeCompVerStr);
395             compData["PendingComponentVersionString"] =
396                 pldm::utils::toString(pendingCompVerStr);
397 
398             compParamPtr += sizeof(pldm_component_parameter_entry) +
399                             activeCompVerStr.length + pendingCompVerStr.length;
400             compParamTableLen -= sizeof(pldm_component_parameter_entry) +
401                                  activeCompVerStr.length +
402                                  pendingCompVerStr.length;
403             compDataEntries.push_back(compData);
404         }
405         data["ComponentParameterEntries"] = compDataEntries;
406 
407         pldmtool::helper::DisplayInJson(data);
408     }
409 };
410 
411 class QueryDeviceIdentifiers : public CommandInterface
412 {
413   public:
414     ~QueryDeviceIdentifiers() = default;
415     QueryDeviceIdentifiers() = delete;
416     QueryDeviceIdentifiers(const QueryDeviceIdentifiers&) = delete;
417     QueryDeviceIdentifiers(QueryDeviceIdentifiers&&) = default;
418     QueryDeviceIdentifiers& operator=(const QueryDeviceIdentifiers&) = delete;
419     QueryDeviceIdentifiers& operator=(QueryDeviceIdentifiers&&) = delete;
420 
421     /**
422      * @brief Implementation of createRequestMsg for QueryDeviceIdentifiers
423      *
424      * @return std::pair<int, std::vector<uint8_t>>
425      */
426     std::pair<int, std::vector<uint8_t>> createRequestMsg() override;
427 
428     /**
429      * @brief Implementation of parseResponseMsg for QueryDeviceIdentifiers
430      *
431      * @param[in] responsePtr
432      * @param[in] payloadLength
433      */
434     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override;
435     using CommandInterface::CommandInterface;
436 
437   private:
438     /**
439      * @brief Method to update QueryDeviceIdentifiers json response in a user
440      * friendly format
441      *
442      * @param[in] descriptors - descriptor json response
443      * @param[in] descriptorType - descriptor type
444      * @param[in] descriptorVal - descriptor value
445      */
446     void updateDescriptor(
447         ordered_json& descriptors, const DescriptorType& descriptorType,
448         const std::variant<DescriptorData, VendorDefinedDescriptorInfo>&
449             descriptorVal);
450 };
451 
452 void QueryDeviceIdentifiers::updateDescriptor(
453     ordered_json& descriptors, const DescriptorType& descriptorType,
454     const std::variant<DescriptorData, VendorDefinedDescriptorInfo>&
455         descriptorVal)
456 {
457     std::ostringstream descDataStream;
458     DescriptorData descData;
459     if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
460     {
461         descData = std::get<DescriptorData>(descriptorVal);
462     }
463     else
464     {
465         descData = std::get<VendorDefinedDescriptorData>(
466             std::get<VendorDefinedDescriptorInfo>(descriptorVal));
467     }
468     for (int byte : descData)
469     {
470         descDataStream << std::setfill('0') << std::setw(2) << std::hex << byte;
471     }
472 
473     if (descriptorName.contains(descriptorType))
474     {
475         // Update the existing json response if entry is already present
476         for (auto& descriptor : descriptors)
477         {
478             if (descriptor["Type"] == descriptorName.at(descriptorType))
479             {
480                 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
481                 {
482                     descriptor["Value"].emplace_back(descDataStream.str());
483                 }
484                 else
485                 {
486                     ordered_json vendorDefinedVal;
487                     vendorDefinedVal[std::get<VendorDefinedDescriptorTitle>(
488                         std::get<VendorDefinedDescriptorInfo>(descriptorVal))] =
489                         descDataStream.str();
490                     descriptor["Value"].emplace_back(vendorDefinedVal);
491                 }
492                 return;
493             }
494         }
495         // Entry is not present, add type and value to json response
496         ordered_json descriptor =
497             ordered_json::object({{"Type", descriptorName.at(descriptorType)},
498                                   {"Value", ordered_json::array()}});
499         if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
500         {
501             descriptor["Value"].emplace_back(descDataStream.str());
502         }
503         else
504         {
505             ordered_json vendorDefinedVal;
506             vendorDefinedVal[std::get<VendorDefinedDescriptorTitle>(
507                 std::get<VendorDefinedDescriptorInfo>(descriptorVal))] =
508                 descDataStream.str();
509             descriptor["Value"].emplace_back(vendorDefinedVal);
510         }
511         descriptors.emplace_back(descriptor);
512     }
513     else
514     {
515         std::cerr << "Unknown descriptor type, type=" << descriptorType << "\n";
516     }
517 }
518 std::pair<int, std::vector<uint8_t>> QueryDeviceIdentifiers::createRequestMsg()
519 {
520     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
521                                     PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES);
522     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
523     auto rc = encode_query_device_identifiers_req(
524         instanceId, PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES, request);
525     return {rc, requestMsg};
526 }
527 
528 void QueryDeviceIdentifiers::parseResponseMsg(pldm_msg* responsePtr,
529                                               size_t payloadLength)
530 {
531     uint8_t completionCode = PLDM_SUCCESS;
532     uint32_t deviceIdentifiersLen = 0;
533     uint8_t descriptorCount = 0;
534     uint8_t* descriptorPtr = nullptr;
535     uint8_t eid = getMCTPEID();
536     auto rc = decode_query_device_identifiers_resp(
537         responsePtr, payloadLength, &completionCode, &deviceIdentifiersLen,
538         &descriptorCount, &descriptorPtr);
539     if (rc)
540     {
541         std::cerr << "Decoding QueryDeviceIdentifiers response failed,EID="
542                   << unsigned(eid) << ", RC=" << rc << "\n";
543         return;
544     }
545     if (completionCode)
546     {
547         std::cerr << "QueryDeviceIdentifiers response failed with error "
548                      "completion code, EID="
549                   << unsigned(eid) << ", CC=" << unsigned(completionCode)
550                   << "\n";
551         return;
552     }
553     ordered_json data;
554     data["EID"] = eid;
555     ordered_json descriptors;
556     while (descriptorCount-- && (deviceIdentifiersLen > 0))
557     {
558         DescriptorType descriptorType = 0;
559         variable_field descriptorData{};
560 
561         rc = decode_descriptor_type_length_value(
562             descriptorPtr, deviceIdentifiersLen, &descriptorType,
563             &descriptorData);
564         if (rc)
565         {
566             std::cerr << "Decoding descriptor type, length and value failed,"
567                       << "EID=" << unsigned(eid) << ",RC=" << rc << "\n ";
568             return;
569         }
570 
571         if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
572         {
573             std::vector<uint8_t> descData(
574                 descriptorData.ptr, descriptorData.ptr + descriptorData.length);
575             updateDescriptor(descriptors, descriptorType, descData);
576         }
577         else
578         {
579             uint8_t descriptorTitleStrType = 0;
580             variable_field descriptorTitleStr{};
581             variable_field vendorDefinedDescriptorData{};
582 
583             rc = decode_vendor_defined_descriptor_value(
584                 descriptorData.ptr, descriptorData.length,
585                 &descriptorTitleStrType, &descriptorTitleStr,
586                 &vendorDefinedDescriptorData);
587             if (rc)
588             {
589                 std::cerr << "Decoding Vendor-defined descriptor value"
590                           << "failed EID=" << unsigned(eid) << ", RC=" << rc
591                           << "\n ";
592                 return;
593             }
594 
595             auto vendorDescTitle = pldm::utils::toString(descriptorTitleStr);
596             std::vector<uint8_t> vendorDescData(
597                 vendorDefinedDescriptorData.ptr,
598                 vendorDefinedDescriptorData.ptr +
599                     vendorDefinedDescriptorData.length);
600             updateDescriptor(descriptors, descriptorType,
601                              std::make_tuple(vendorDescTitle, vendorDescData));
602         }
603         auto nextDescriptorOffset =
604             sizeof(pldm_descriptor_tlv().descriptor_type) +
605             sizeof(pldm_descriptor_tlv().descriptor_length) +
606             descriptorData.length;
607         descriptorPtr += nextDescriptorOffset;
608         deviceIdentifiersLen -= nextDescriptorOffset;
609     }
610     data["Descriptors"] = descriptors;
611     pldmtool::helper::DisplayInJson(data);
612 }
613 
614 void registerCommand(CLI::App& app)
615 {
616     auto fwUpdate = app.add_subcommand("fw_update",
617                                        "firmware update type commands");
618     fwUpdate->require_subcommand(1);
619 
620     auto getStatus = fwUpdate->add_subcommand("GetStatus", "Status of the FD");
621     commands.push_back(
622         std::make_unique<GetStatus>("fw_update", "GetStatus", getStatus));
623 
624     auto getFwParams = fwUpdate->add_subcommand(
625         "GetFwParams", "To get the component details of the FD");
626     commands.push_back(
627         std::make_unique<GetFwParams>("fw_update", "GetFwParams", getFwParams));
628 
629     auto queryDeviceIdentifiers = fwUpdate->add_subcommand(
630         "QueryDeviceIdentifiers", "To query device identifiers of the FD");
631     commands.push_back(std::make_unique<QueryDeviceIdentifiers>(
632         "fw_update", "QueryDeviceIdentifiers", queryDeviceIdentifiers));
633 }
634 
635 } // namespace fw_update
636 
637 } // namespace pldmtool
638