xref: /openbmc/pldm/pldmtool/pldm_fw_update_cmd.cpp (revision a5d303d560870a7f2d994022dfbe13098196adf1)
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 #include <format>
9 
10 namespace pldmtool
11 {
12 
13 namespace fw_update
14 {
15 
16 namespace
17 {
18 
19 using namespace pldmtool::helper;
20 using namespace pldm::fw_update;
21 
22 std::vector<std::unique_ptr<CommandInterface>> commands;
23 
24 } // namespace
25 
26 const std::map<uint8_t, std::string> fdStateMachine{
27     {PLDM_FD_STATE_IDLE, "IDLE"},
28     {PLDM_FD_STATE_LEARN_COMPONENTS, "LEARN COMPONENTS"},
29     {PLDM_FD_STATE_READY_XFER, "READY XFER"},
30     {PLDM_FD_STATE_DOWNLOAD, "DOWNLOAD"},
31     {PLDM_FD_STATE_VERIFY, "VERIFY"},
32     {PLDM_FD_STATE_APPLY, "APPLY"},
33     {PLDM_FD_STATE_ACTIVATE, "ACTIVATE"}};
34 
35 const std::map<uint8_t, const char*> fdAuxState{
36     {PLDM_FD_OPERATION_IN_PROGRESS, "Operation in progress"},
37     {PLDM_FD_OPERATION_SUCCESSFUL, "Operation successful"},
38     {PLDM_FD_OPERATION_FAILED, "Operation Failed"},
39     {PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER,
40      "Not applicable in current state"}};
41 
42 const std::map<uint8_t, const char*> fdAuxStateStatus{
43     {PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS,
44      "AuxState is In Progress or Success"},
45     {PLDM_FD_TIMEOUT, "Timeout occurred while performing action"},
46     {PLDM_FD_GENERIC_ERROR, "Generic Error has occurred"}};
47 
48 const std::map<uint8_t, const char*> fdReasonCode{
49     {PLDM_FD_INITIALIZATION, "Initialization of firmware device has occurred"},
50     {PLDM_FD_ACTIVATE_FW, "ActivateFirmware command was received"},
51     {PLDM_FD_CANCEL_UPDATE, "CancelUpdate command was received"},
52     {PLDM_FD_TIMEOUT_LEARN_COMPONENT,
53      "Timeout occurred when in LEARN COMPONENT state"},
54     {PLDM_FD_TIMEOUT_READY_XFER, "Timeout occurred when in READY XFER state"},
55     {PLDM_FD_TIMEOUT_DOWNLOAD, "Timeout occurred when in DOWNLOAD state"},
56     {PLDM_FD_TIMEOUT_VERIFY, "Timeout occurred when in VERIFY state"},
57     {PLDM_FD_TIMEOUT_APPLY, "Timeout occurred when in APPLY state"}};
58 
59 /**
60  * @brief descriptor type to name mapping
61  *
62  */
63 const std::map<DescriptorType, const char*> descriptorName{
64     {PLDM_FWUP_PCI_VENDOR_ID, "PCI Vendor ID"},
65     {PLDM_FWUP_IANA_ENTERPRISE_ID, "IANA Enterprise ID"},
66     {PLDM_FWUP_UUID, "UUID"},
67     {PLDM_FWUP_PNP_VENDOR_ID, "PnP Vendor ID"},
68     {PLDM_FWUP_ACPI_VENDOR_ID, "ACPI Vendor ID"},
69     {PLDM_FWUP_PCI_DEVICE_ID, "PCI Device ID"},
70     {PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID, "PCI Subsystem Vendor ID"},
71     {PLDM_FWUP_PCI_SUBSYSTEM_ID, "PCI Subsystem ID"},
72     {PLDM_FWUP_PCI_REVISION_ID, "PCI Revision ID"},
73     {PLDM_FWUP_PNP_PRODUCT_IDENTIFIER, "PnP Product Identifier"},
74     {PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER, "ACPI Product Identifier"},
75     {PLDM_FWUP_VENDOR_DEFINED, "Vendor Defined"}};
76 
77 const std::map<std::string, transfer_resp_flag> transferRespFlag{
78     {"START", PLDM_START},
79     {"MIDDLE", PLDM_MIDDLE},
80     {"END", PLDM_END},
81     {"STARTANDEND", PLDM_START_AND_END},
82 };
83 
84 const std::map<const char*, pldm_self_contained_activation_req>
85     pldmSelfContainedActivation{
86         {"False", PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS},
87         {"True", PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS},
88     };
89 
90 /*
91  * Convert PLDM Firmware String Type to uint8_t
92  *
93  *  @param[in]  compImgVerStrType - the component version string
94  *
95  *  @return - the component version string converted to a numeric value.
96  */
convertStringTypeToUInt8(std::string compImgVerStrType)97 uint8_t convertStringTypeToUInt8(std::string compImgVerStrType)
98 {
99     static const std::map<std::string, pldm_firmware_update_string_type>
100         pldmFirmwareUpdateStringType{
101             {"UNKNOWN", PLDM_STR_TYPE_UNKNOWN},
102             {"ASCII", PLDM_STR_TYPE_ASCII},
103             {"UTF_8", PLDM_STR_TYPE_UTF_8},
104             {"UTF_16", PLDM_STR_TYPE_UTF_16},
105             {"UTF_16LE", PLDM_STR_TYPE_UTF_16LE},
106             {"UTF_16BE", PLDM_STR_TYPE_UTF_16BE},
107         };
108 
109     if (pldmFirmwareUpdateStringType.contains(compImgVerStrType))
110     {
111         return pldmFirmwareUpdateStringType.at(compImgVerStrType);
112     }
113     else
114     {
115         return static_cast<uint8_t>(std::stoi(compImgVerStrType));
116     }
117 }
118 
119 class GetStatus : public CommandInterface
120 {
121   public:
122     ~GetStatus() = default;
123     GetStatus() = delete;
124     GetStatus(const GetStatus&) = delete;
125     GetStatus(GetStatus&&) = default;
126     GetStatus& operator=(const GetStatus&) = delete;
127     GetStatus& operator=(GetStatus&&) = delete;
128 
129     using CommandInterface::CommandInterface;
130 
createRequestMsg()131     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
132     {
133         std::vector<uint8_t> requestMsg(
134             sizeof(pldm_msg_hdr) + PLDM_GET_STATUS_REQ_BYTES);
135         auto request = new (requestMsg.data()) pldm_msg;
136         auto rc = encode_get_status_req(instanceId, request,
137                                         PLDM_GET_STATUS_REQ_BYTES);
138         return {rc, requestMsg};
139     }
140 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)141     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
142     {
143         uint8_t completionCode = 0;
144         uint8_t currentState = 0;
145         uint8_t previousState = 0;
146         uint8_t auxState = 0;
147         uint8_t auxStateStatus = 0;
148         uint8_t progressPercent = 0;
149         uint8_t reasonCode = 0;
150         bitfield32_t updateOptionFlagsEnabled{0};
151 
152         auto rc = decode_get_status_resp(
153             responsePtr, payloadLength, &completionCode, &currentState,
154             &previousState, &auxState, &auxStateStatus, &progressPercent,
155             &reasonCode, &updateOptionFlagsEnabled);
156         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
157         {
158             std::cerr << "Response Message Error: "
159                       << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
160             return;
161         }
162 
163         ordered_json data;
164         data["CurrentState"] = fdStateMachine.at(currentState);
165         data["PreviousState"] = fdStateMachine.at(previousState);
166         data["AuxState"] = fdAuxState.at(auxState);
167         if (auxStateStatus >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
168             auxStateStatus <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)
169         {
170             data["AuxStateStatus"] = auxStateStatus;
171         }
172         else
173         {
174             data["AuxStateStatus"] = fdAuxStateStatus.at(auxStateStatus);
175         }
176         data["ProgressPercent"] = progressPercent;
177         if (reasonCode >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN &&
178             reasonCode <= PLDM_FD_STATUS_VENDOR_DEFINED_MAX)
179         {
180             data["ReasonCode"] = reasonCode;
181         }
182         else
183         {
184             data["ReasonCode"] = fdReasonCode.at(reasonCode);
185         }
186         data["UpdateOptionFlagsEnabled"] = updateOptionFlagsEnabled.value;
187 
188         pldmtool::helper::DisplayInJson(data);
189     }
190 };
191 
192 const std::map<uint16_t, std::string> componentClassification{
193     {PLDM_COMP_UNKNOWN, "Unknown"},
194     {PLDM_COMP_OTHER, "Other"},
195     {PLDM_COMP_DRIVER, "Driver"},
196     {PLDM_COMP_CONFIGURATION_SOFTWARE, "Configuration Software"},
197     {PLDM_COMP_APPLICATION_SOFTWARE, "Application Software"},
198     {PLDM_COMP_INSTRUMENTATION, "Instrumentation"},
199     {PLDM_COMP_FIRMWARE_OR_BIOS, "Firmware/BIOS"},
200     {PLDM_COMP_DIAGNOSTIC_SOFTWARE, "Diagnostic Software"},
201     {PLDM_COMP_OPERATING_SYSTEM, "Operating System"},
202     {PLDM_COMP_MIDDLEWARE, "Middleware"},
203     {PLDM_COMP_FIRMWARE, "Firmware"},
204     {PLDM_COMP_BIOS_OR_FCODE, "BIOS/FCode"},
205     {PLDM_COMP_SUPPORT_OR_SERVICEPACK, "Support/Service Pack"},
206     {PLDM_COMP_SOFTWARE_BUNDLE, "Software Bundle"},
207     {PLDM_COMP_DOWNSTREAM_DEVICE, "Downstream Device"}};
208 
209 class GetFwParams : public CommandInterface
210 {
211   public:
212     ~GetFwParams() = default;
213     GetFwParams() = delete;
214     GetFwParams(const GetFwParams&) = delete;
215     GetFwParams(GetFwParams&&) = default;
216     GetFwParams& operator=(const GetFwParams&) = delete;
217     GetFwParams& operator=(GetFwParams&&) = delete;
218 
219     using CommandInterface::CommandInterface;
220 
createRequestMsg()221     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
222     {
223         std::vector<uint8_t> requestMsg(
224             sizeof(pldm_msg_hdr) + PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
225         auto request = new (requestMsg.data()) pldm_msg;
226         auto rc = encode_get_firmware_parameters_req(
227             instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
228         return {rc, requestMsg};
229     }
230 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)231     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
232     {
233         pldm_get_firmware_parameters_resp fwParams{};
234         variable_field activeCompImageSetVersion{};
235         variable_field pendingCompImageSetVersion{};
236         variable_field compParameterTable{};
237 
238         auto rc = decode_get_firmware_parameters_resp(
239             responsePtr, payloadLength, &fwParams, &activeCompImageSetVersion,
240             &pendingCompImageSetVersion, &compParameterTable);
241         if (rc != PLDM_SUCCESS || fwParams.completion_code != PLDM_SUCCESS)
242         {
243             std::cerr << "Response Message Error: "
244                       << "rc=" << rc << ",cc=" << (int)fwParams.completion_code
245                       << "\n";
246             return;
247         }
248 
249         ordered_json capabilitiesDuringUpdate;
250         if (fwParams.capabilities_during_update.bits.bit0)
251         {
252             capabilitiesDuringUpdate
253                 ["Component Update Failure Recovery Capability"] =
254                     "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer.";
255         }
256         else
257         {
258             capabilitiesDuringUpdate
259                 ["Component Update Failure Recovery Capability"] =
260                     "Device will revert to previous component image upon failure, timeout or cancellation of the transfer.";
261         }
262 
263         if (fwParams.capabilities_during_update.bits.bit1)
264         {
265             capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
266                 "Device will not be able to update component again unless it exits update mode and the UA sends a new Request Update command.";
267         }
268         else
269         {
270             capabilitiesDuringUpdate["Component Update Failure Retry Capability"] =
271                 " Device can have component updated again without exiting update mode and restarting transfer via RequestUpdate command.";
272         }
273 
274         if (fwParams.capabilities_during_update.bits.bit2)
275         {
276             capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
277                 "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.";
278         }
279         else
280         {
281             capabilitiesDuringUpdate["Firmware Device Partial Updates"] =
282                 "Firmware Device cannot accept a partial update and all components present on the FD shall be updated.";
283         }
284 
285         if (fwParams.capabilities_during_update.bits.bit3)
286         {
287             capabilitiesDuringUpdate
288                 ["Firmware Device Host Functionality during Firmware Update"] =
289                     "Device will not revert to previous component image upon failure, timeout or cancellation of the transfer";
290         }
291         else
292         {
293             capabilitiesDuringUpdate
294                 ["Firmware Device Host Functionality during Firmware Update"] =
295                     "Device will revert to previous component image upon failure, timeout or cancellation of the transfer";
296         }
297 
298         if (fwParams.capabilities_during_update.bits.bit4)
299         {
300             capabilitiesDuringUpdate["Firmware Device Update Mode Restrictions"] =
301                 "Firmware device unable to enter update mode if host OS environment is active.";
302         }
303         else
304         {
305             capabilitiesDuringUpdate
306                 ["Firmware Device Update Mode Restrictions"] =
307                     "No host OS environment restriction for update mode";
308         }
309 
310         ordered_json data;
311         data["CapabilitiesDuringUpdate"] = capabilitiesDuringUpdate;
312         data["ComponentCount"] = static_cast<uint16_t>(fwParams.comp_count);
313         data["ActiveComponentImageSetVersionString"] =
314             pldm::utils::toString(activeCompImageSetVersion);
315         data["PendingComponentImageSetVersionString"] =
316             pldm::utils::toString(pendingCompImageSetVersion);
317 
318         auto compParamPtr = compParameterTable.ptr;
319         auto compParamTableLen = compParameterTable.length;
320         pldm_component_parameter_entry compEntry{};
321         variable_field activeCompVerStr{};
322         variable_field pendingCompVerStr{};
323         ordered_json compDataEntries;
324 
325         while (fwParams.comp_count-- && (compParamTableLen > 0))
326         {
327             ordered_json compData;
328             auto rc = decode_get_firmware_parameters_resp_comp_entry(
329                 compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
330                 &pendingCompVerStr);
331             if (rc)
332             {
333                 std::cerr
334                     << "Decoding component parameter table entry failed, RC="
335                     << rc << "\n";
336                 return;
337             }
338 
339             if (componentClassification.contains(compEntry.comp_classification))
340             {
341                 compData["ComponentClassification"] =
342                     componentClassification.at(compEntry.comp_classification);
343             }
344             else
345             {
346                 compData["ComponentClassification"] =
347                     static_cast<uint16_t>(compEntry.comp_classification);
348             }
349             compData["ComponentIdentifier"] =
350                 static_cast<uint16_t>(compEntry.comp_identifier);
351             compData["ComponentClassificationIndex"] =
352                 static_cast<uint8_t>(compEntry.comp_classification_index);
353             compData["ActiveComponentComparisonStamp"] =
354                 static_cast<uint32_t>(compEntry.active_comp_comparison_stamp);
355 
356             // ActiveComponentReleaseData
357             std::array<uint8_t, 8> noReleaseData{0x00, 0x00, 0x00, 0x00,
358                                                  0x00, 0x00, 0x00, 0x00};
359             if (std::equal(noReleaseData.begin(), noReleaseData.end(),
360                            compEntry.active_comp_release_date))
361             {
362                 compData["ActiveComponentReleaseDate"] = "";
363             }
364             else
365             {
366                 std::string activeComponentReleaseDate(
367                     reinterpret_cast<const char*>(
368                         compEntry.active_comp_release_date),
369                     sizeof(compEntry.active_comp_release_date));
370                 compData["ActiveComponentReleaseDate"] =
371                     activeComponentReleaseDate;
372             }
373 
374             compData["PendingComponentComparisonStamp"] =
375                 static_cast<uint32_t>(compEntry.pending_comp_comparison_stamp);
376 
377             // PendingComponentReleaseData
378             if (std::equal(noReleaseData.begin(), noReleaseData.end(),
379                            compEntry.pending_comp_release_date))
380             {
381                 compData["PendingComponentReleaseDate"] = "";
382             }
383             else
384             {
385                 std::string pendingComponentReleaseDate(
386                     reinterpret_cast<const char*>(
387                         compEntry.pending_comp_release_date),
388                     sizeof(compEntry.pending_comp_release_date));
389                 compData["PendingComponentReleaseDate"] =
390                     pendingComponentReleaseDate;
391             }
392 
393             // ComponentActivationMethods
394             ordered_json componentActivationMethods;
395             if (compEntry.comp_activation_methods.bits.bit0)
396             {
397                 componentActivationMethods.push_back("Automatic");
398             }
399             else if (compEntry.comp_activation_methods.bits.bit1)
400             {
401                 componentActivationMethods.push_back("Self-Contained");
402             }
403             else if (compEntry.comp_activation_methods.bits.bit2)
404             {
405                 componentActivationMethods.push_back("Medium-specific reset");
406             }
407             else if (compEntry.comp_activation_methods.bits.bit3)
408             {
409                 componentActivationMethods.push_back("System reboot");
410             }
411             else if (compEntry.comp_activation_methods.bits.bit4)
412             {
413                 componentActivationMethods.push_back("DC power cycel");
414             }
415             else if (compEntry.comp_activation_methods.bits.bit5)
416             {
417                 componentActivationMethods.push_back("AC power cycle");
418             }
419             compData["ComponentActivationMethods"] = componentActivationMethods;
420 
421             // CapabilitiesDuringUpdate
422             ordered_json compCapabilitiesDuringUpdate;
423             if (compEntry.capabilities_during_update.bits.bit0)
424             {
425                 compCapabilitiesDuringUpdate
426                     ["Firmware Device apply state functionality"] =
427                         "Firmware Device performs an auto-apply during transfer phase and apply step will be completed immediately.";
428             }
429             else
430             {
431                 compCapabilitiesDuringUpdate
432                     ["Firmware Device apply state functionality"] =
433                         " 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.";
434             }
435             compData["CapabilitiesDuringUpdate"] = compCapabilitiesDuringUpdate;
436 
437             compData["ActiveComponentVersionString"] =
438                 pldm::utils::toString(activeCompVerStr);
439             compData["PendingComponentVersionString"] =
440                 pldm::utils::toString(pendingCompVerStr);
441 
442             compParamPtr += sizeof(pldm_component_parameter_entry) +
443                             activeCompVerStr.length + pendingCompVerStr.length;
444             compParamTableLen -=
445                 sizeof(pldm_component_parameter_entry) +
446                 activeCompVerStr.length + pendingCompVerStr.length;
447             compDataEntries.push_back(compData);
448         }
449         data["ComponentParameterEntries"] = compDataEntries;
450 
451         pldmtool::helper::DisplayInJson(data);
452     }
453 };
454 
455 class QueryDeviceIdentifiers : public CommandInterface
456 {
457   public:
458     ~QueryDeviceIdentifiers() = default;
459     QueryDeviceIdentifiers() = delete;
460     QueryDeviceIdentifiers(const QueryDeviceIdentifiers&) = delete;
461     QueryDeviceIdentifiers(QueryDeviceIdentifiers&&) = default;
462     QueryDeviceIdentifiers& operator=(const QueryDeviceIdentifiers&) = delete;
463     QueryDeviceIdentifiers& operator=(QueryDeviceIdentifiers&&) = delete;
464 
465     /**
466      * @brief Implementation of createRequestMsg for QueryDeviceIdentifiers
467      *
468      * @return std::pair<int, std::vector<uint8_t>>
469      */
470     std::pair<int, std::vector<uint8_t>> createRequestMsg() override;
471 
472     /**
473      * @brief Implementation of parseResponseMsg for QueryDeviceIdentifiers
474      *
475      * @param[in] responsePtr
476      * @param[in] payloadLength
477      */
478     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override;
479     using CommandInterface::CommandInterface;
480 
481   private:
482     /**
483      * @brief Method to update QueryDeviceIdentifiers json response in a user
484      * friendly format
485      *
486      * @param[in] descriptors - descriptor json response
487      * @param[in] descriptorType - descriptor type
488      * @param[in] descriptorVal - descriptor value
489      */
490     void updateDescriptor(
491         ordered_json& descriptors, const DescriptorType& descriptorType,
492         const std::variant<DescriptorData, VendorDefinedDescriptorInfo>&
493             descriptorVal);
494 };
495 
updateDescriptor(ordered_json & descriptors,const DescriptorType & descriptorType,const std::variant<DescriptorData,VendorDefinedDescriptorInfo> & descriptorVal)496 void QueryDeviceIdentifiers::updateDescriptor(
497     ordered_json& descriptors, const DescriptorType& descriptorType,
498     const std::variant<DescriptorData, VendorDefinedDescriptorInfo>&
499         descriptorVal)
500 {
501     std::ostringstream descDataStream;
502     DescriptorData descData;
503     if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
504     {
505         descData = std::get<DescriptorData>(descriptorVal);
506     }
507     else
508     {
509         descData = std::get<VendorDefinedDescriptorData>(
510             std::get<VendorDefinedDescriptorInfo>(descriptorVal));
511     }
512     for (int byte : descData)
513     {
514         descDataStream << std::setfill('0') << std::setw(2) << std::hex << byte;
515     }
516 
517     if (descriptorName.contains(descriptorType))
518     {
519         // Update the existing json response if entry is already present
520         for (auto& descriptor : descriptors)
521         {
522             if (descriptor["Type"] == descriptorName.at(descriptorType))
523             {
524                 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
525                 {
526                     descriptor["Value"].emplace_back(descDataStream.str());
527                 }
528                 else
529                 {
530                     ordered_json vendorDefinedVal;
531                     vendorDefinedVal[std::get<VendorDefinedDescriptorTitle>(
532                         std::get<VendorDefinedDescriptorInfo>(descriptorVal))] =
533                         descDataStream.str();
534                     descriptor["Value"].emplace_back(vendorDefinedVal);
535                 }
536                 return;
537             }
538         }
539         // Entry is not present, add type and value to json response
540         ordered_json descriptor = ordered_json::object(
541             {{"Type", descriptorName.at(descriptorType)},
542              {"Value", ordered_json::array()}});
543         if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
544         {
545             descriptor["Value"].emplace_back(descDataStream.str());
546         }
547         else
548         {
549             ordered_json vendorDefinedVal;
550             vendorDefinedVal[std::get<VendorDefinedDescriptorTitle>(
551                 std::get<VendorDefinedDescriptorInfo>(descriptorVal))] =
552                 descDataStream.str();
553             descriptor["Value"].emplace_back(vendorDefinedVal);
554         }
555         descriptors.emplace_back(descriptor);
556     }
557     else
558     {
559         std::cerr << "Unknown descriptor type, type=" << descriptorType << "\n";
560     }
561 }
createRequestMsg()562 std::pair<int, std::vector<uint8_t>> QueryDeviceIdentifiers::createRequestMsg()
563 {
564     std::vector<uint8_t> requestMsg(
565         sizeof(pldm_msg_hdr) + PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES);
566     auto request = new (requestMsg.data()) pldm_msg;
567     auto rc = encode_query_device_identifiers_req(
568         instanceId, PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES, request);
569     return {rc, requestMsg};
570 }
571 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)572 void QueryDeviceIdentifiers::parseResponseMsg(pldm_msg* responsePtr,
573                                               size_t payloadLength)
574 {
575     uint8_t completionCode = PLDM_SUCCESS;
576     uint32_t deviceIdentifiersLen = 0;
577     uint8_t descriptorCount = 0;
578     uint8_t* descriptorPtr = nullptr;
579     uint8_t eid = getMCTPEID();
580     auto rc = decode_query_device_identifiers_resp(
581         responsePtr, payloadLength, &completionCode, &deviceIdentifiersLen,
582         &descriptorCount, &descriptorPtr);
583     if (rc)
584     {
585         std::cerr << "Decoding QueryDeviceIdentifiers response failed,EID="
586                   << unsigned(eid) << ", RC=" << rc << "\n";
587         return;
588     }
589     if (completionCode)
590     {
591         std::cerr << "QueryDeviceIdentifiers response failed with error "
592                      "completion code, EID="
593                   << unsigned(eid) << ", CC=" << unsigned(completionCode)
594                   << "\n";
595         return;
596     }
597     ordered_json data;
598     data["EID"] = eid;
599     ordered_json descriptors;
600     while (descriptorCount-- && (deviceIdentifiersLen > 0))
601     {
602         DescriptorType descriptorType = 0;
603         variable_field descriptorData{};
604 
605         rc = decode_descriptor_type_length_value(
606             descriptorPtr, deviceIdentifiersLen, &descriptorType,
607             &descriptorData);
608         if (rc)
609         {
610             std::cerr << "Decoding descriptor type, length and value failed,"
611                       << "EID=" << unsigned(eid) << ",RC=" << rc << "\n ";
612             return;
613         }
614 
615         if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
616         {
617             std::vector<uint8_t> descData(
618                 descriptorData.ptr, descriptorData.ptr + descriptorData.length);
619             updateDescriptor(descriptors, descriptorType, descData);
620         }
621         else
622         {
623             uint8_t descriptorTitleStrType = 0;
624             variable_field descriptorTitleStr{};
625             variable_field vendorDefinedDescriptorData{};
626 
627             rc = decode_vendor_defined_descriptor_value(
628                 descriptorData.ptr, descriptorData.length,
629                 &descriptorTitleStrType, &descriptorTitleStr,
630                 &vendorDefinedDescriptorData);
631             if (rc)
632             {
633                 std::cerr << "Decoding Vendor-defined descriptor value"
634                           << "failed EID=" << unsigned(eid) << ", RC=" << rc
635                           << "\n ";
636                 return;
637             }
638 
639             auto vendorDescTitle = pldm::utils::toString(descriptorTitleStr);
640             std::vector<uint8_t> vendorDescData(
641                 vendorDefinedDescriptorData.ptr,
642                 vendorDefinedDescriptorData.ptr +
643                     vendorDefinedDescriptorData.length);
644             updateDescriptor(descriptors, descriptorType,
645                              std::make_tuple(vendorDescTitle, vendorDescData));
646         }
647         auto nextDescriptorOffset =
648             sizeof(pldm_descriptor_tlv().descriptor_type) +
649             sizeof(pldm_descriptor_tlv().descriptor_length) +
650             descriptorData.length;
651         descriptorPtr += nextDescriptorOffset;
652         deviceIdentifiersLen -= nextDescriptorOffset;
653     }
654     data["Descriptors"] = descriptors;
655     pldmtool::helper::DisplayInJson(data);
656 }
657 
658 class RequestUpdate : public CommandInterface
659 {
660   public:
661     ~RequestUpdate() = default;
662     RequestUpdate() = delete;
663     RequestUpdate(const RequestUpdate&) = delete;
664     RequestUpdate(RequestUpdate&&) = delete;
665     RequestUpdate& operator=(const RequestUpdate&) = delete;
666     RequestUpdate& operator=(RequestUpdate&&) = delete;
667 
RequestUpdate(const char * type,const char * name,CLI::App * app)668     explicit RequestUpdate(const char* type, const char* name, CLI::App* app) :
669         CommandInterface(type, name, app)
670     {
671         app->add_option(
672                "--max_transfer_size", maxTransferSize,
673                "Specifies the maximum size, in bytes, of the variable payload allowed to\n"
674                "be requested by the FD via the RequestFirmwareData command that is contained\n"
675                "within a PLDM message. This value shall be equal to or greater than firmware update\n"
676                "baseline transfer size.")
677             ->required();
678 
679         app->add_option(
680                "--num_comps", numComps,
681                "Specifies the number of components that will be passed to the FD during the update.\n"
682                "The FD can use this value to compare against the number of PassComponentTable\n"
683                "commands received.")
684             ->required();
685 
686         app->add_option(
687                "--max_transfer_reqs", maxTransferReqs,
688                "Specifies the number of outstanding RequestFirmwareData commands that can be\n"
689                "sent by the FD. The minimum required value is '1' which the UA shall support.\n"
690                "It is optional for the UA to support a value higher than '1' for this field.")
691             ->required();
692 
693         app->add_option(
694                "--package_data_length", packageDataLength,
695                "This field shall be set to the value contained within\n"
696                "the FirmwareDevicePackageDataLength field that was provided in\n"
697                "the firmware package header. If no firmware package data was\n"
698                "provided in the firmware update package then this length field\n"
699                "shall be set to 0x0000.")
700             ->required();
701 
702         app->add_option(
703                "--comp_img_ver_str_type", compImgVerStrType,
704                "The type of string used in the ComponentImageSetVersionString\n"
705                "field. Possible values\n"
706                "{UNKNOWN->0, ASCII->1, UTF_8->2, UTF_16->3, UTF_16LE->4, UTF_16BE->5}\n"
707                "OR {0,1,2,3,4,5}")
708             ->required()
709             ->check([](const std::string& value) -> std::string {
710                 static const std::set<std::string> validStrings{
711                     "UNKNOWN", "ASCII",    "UTF_8",
712                     "UTF_16",  "UTF_16LE", "UTF_16BE"};
713 
714                 if (validStrings.contains(value))
715                 {
716                     return "";
717                 }
718 
719                 try
720                 {
721                     int intValue = std::stoi(value);
722                     if (intValue >= 0 && intValue <= 255)
723                     {
724                         return "";
725                     }
726                     return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
727                 }
728                 catch (const std::exception&)
729                 {
730                     return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
731                 }
732             });
733 
734         app->add_option(
735                "--comp_img_ver_str_len", compImgVerStrLen,
736                "The length, in bytes, of the ComponentImageSetVersionString.")
737             ->required();
738 
739         app->add_option(
740                "--comp_img_set_ver_str", compImgSetVerStr,
741                "Component Image Set version information, up to 255 bytes.")
742             ->required();
743     }
744 
createRequestMsg()745     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
746     {
747         variable_field compImgSetVerStrInfo{};
748         compImgSetVerStrInfo.ptr =
749             reinterpret_cast<const uint8_t*>(compImgSetVerStr.data());
750         compImgSetVerStrInfo.length =
751             static_cast<uint8_t>(compImgSetVerStr.size());
752 
753         std::vector<uint8_t> requestMsg(
754             sizeof(pldm_msg_hdr) + sizeof(struct pldm_request_update_req) +
755             compImgSetVerStrInfo.length);
756 
757         auto request = new (requestMsg.data()) pldm_msg;
758 
759         auto rc = encode_request_update_req(
760             instanceId, maxTransferSize, numComps, maxTransferReqs,
761             packageDataLength, convertStringTypeToUInt8(compImgVerStrType),
762             compImgVerStrLen, &compImgSetVerStrInfo, request,
763             sizeof(struct pldm_request_update_req) +
764                 compImgSetVerStrInfo.length);
765 
766         return {rc, requestMsg};
767     }
768 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)769     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
770     {
771         uint8_t cc = 0;
772         uint16_t fdMetaDataLen = 0;
773         uint8_t fdWillSendPkgData = 0;
774 
775         auto rc =
776             decode_request_update_resp(responsePtr, payloadLength, &cc,
777                                        &fdMetaDataLen, &fdWillSendPkgData);
778         if (rc)
779         {
780             std::cerr << "Response Message Error: "
781                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
782             return;
783         }
784 
785         ordered_json data;
786         fillCompletionCode(cc, data, PLDM_FWUP);
787 
788         if (cc == PLDM_SUCCESS)
789         {
790             data["FirmwareDeviceMetaDataLength"] = fdMetaDataLen;
791             data["FDWillSendGetPackageDataCommand"] =
792                 std::format("0x{:02X}", fdWillSendPkgData);
793         }
794         pldmtool::helper::DisplayInJson(data);
795     }
796 
797   private:
798     uint32_t maxTransferSize;
799     uint16_t numComps;
800     uint8_t maxTransferReqs;
801     uint16_t packageDataLength;
802     std::string compImgVerStrType;
803     uint8_t compImgVerStrLen;
804     std::string compImgSetVerStr;
805 };
806 
807 class PassComponentTable : public CommandInterface
808 {
809   public:
810     ~PassComponentTable() = default;
811     PassComponentTable() = delete;
812     PassComponentTable(const PassComponentTable&) = delete;
813     PassComponentTable(PassComponentTable&&) = delete;
814     PassComponentTable& operator=(const PassComponentTable&) = delete;
815     PassComponentTable& operator=(PassComponentTable&&) = delete;
816 
PassComponentTable(const char * type,const char * name,CLI::App * app)817     explicit PassComponentTable(const char* type, const char* name,
818                                 CLI::App* app) :
819         CommandInterface(type, name, app)
820     {
821         app->add_option(
822                "--transfer_flag", transferFlag,
823                "The transfer flag that indicates what part of the Component Table\n"
824                "this request represents.\nPossible values\n"
825                "{Start = 0x1, Middle = 0x2, End = 0x4, StartAndEnd = 0x5}")
826             ->required()
827             ->transform(
828                 CLI::CheckedTransformer(transferRespFlag, CLI::ignore_case));
829 
830         app->add_option(
831                "--comp_classification", compClassification,
832                "Vendor specific component classification information.\n"
833                "Special values: 0x0000, 0xFFFF = reserved")
834             ->required();
835 
836         app->add_option("--comp_identifier", compIdentifier,
837                         "FD vendor selected unique value "
838                         "to distinguish between component images")
839             ->required();
840 
841         app->add_option("--comp_classification_idx", compClassificationIdx,
842                         "The component classification index which was obtained "
843                         "from the GetFirmwareParameters command to indicate \n"
844                         "which firmware component the information contained "
845                         "within this command is applicable for")
846             ->required();
847 
848         app->add_option(
849                "--comp_compare_stamp", compCompareStamp,
850                "FD vendor selected value to use as a comparison value in determining if a firmware\n"
851                "component is down-level or up-level. For the same component identifier,\n"
852                "the greater of two component comparison stamps is considered up-level compared\n"
853                "to the other when performing an unsigned integer comparison")
854             ->required();
855 
856         app->add_option(
857                "--comp_ver_str_type", compVerStrType,
858                "The type of strings used in the ComponentVersionString\n"
859                "Possible values\n"
860                "{UNKNOWN->0, ASCII->1, UTF_8->2, UTF_16->3, UTF_16LE->4, UTF_16BE->5}\n"
861                "OR {0,1,2,3,4,5}")
862             ->required()
863             ->check([](const std::string& value) -> std::string {
864                 static const std::set<std::string> validStrings{
865                     "UNKNOWN", "ASCII",    "UTF_8",
866                     "UTF_16",  "UTF_16LE", "UTF_16BE"};
867 
868                 if (validStrings.contains(value))
869                 {
870                     return "";
871                 }
872 
873                 try
874                 {
875                     int intValue = std::stoi(value);
876                     if (intValue >= 0 && intValue <= 255)
877                     {
878                         return "";
879                     }
880                     return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
881                 }
882                 catch (const std::exception&)
883                 {
884                     return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
885                 }
886             });
887 
888         app->add_option("--comp_ver_str_len", compVerStrLen,
889                         "The length, in bytes, of the ComponentVersionString")
890             ->required();
891 
892         app->add_option(
893                "--comp_ver_str", compVerStr,
894                "Firmware component version information up to 255 bytes. \n"
895                "Contains a variable type string describing the component version")
896             ->required();
897     }
898 
createRequestMsg()899     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
900     {
901         variable_field compVerStrInfo{};
902         std::vector<uint8_t> compVerStrData(compVerStr.begin(),
903                                             compVerStr.end());
904         compVerStrInfo.ptr = compVerStrData.data();
905         compVerStrInfo.length = static_cast<uint8_t>(compVerStrData.size());
906 
907         std::vector<uint8_t> requestMsg(
908             sizeof(pldm_msg_hdr) +
909             sizeof(struct pldm_pass_component_table_req) +
910             compVerStrInfo.length);
911 
912         auto request = new (requestMsg.data()) pldm_msg;
913 
914         auto rc = encode_pass_component_table_req(
915             instanceId, transferFlag, compClassification, compIdentifier,
916             compClassificationIdx, compCompareStamp,
917             convertStringTypeToUInt8(compVerStrType), compVerStrInfo.length,
918             &compVerStrInfo, request,
919             sizeof(pldm_pass_component_table_req) + compVerStrInfo.length);
920 
921         return {rc, requestMsg};
922     }
923 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)924     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
925     {
926         uint8_t cc = 0;
927         uint8_t compResponse = 0;
928         uint8_t compResponseCode = 0;
929 
930         auto rc = decode_pass_component_table_resp(
931             responsePtr, payloadLength, &cc, &compResponse, &compResponseCode);
932 
933         if (rc != PLDM_SUCCESS)
934         {
935             std::cerr << "Response Message Error: "
936                       << "rc=" << rc << ",cc=" << (int)cc << "\n";
937             return;
938         }
939 
940         ordered_json data;
941         fillCompletionCode(cc, data, PLDM_FWUP);
942 
943         if (cc == PLDM_SUCCESS)
944         {
945             data["ComponentResponse"] =
946                 compResponse ? "Component may be updateable"
947                              : "Component can be updated";
948 
949             data["ComponentResponseCode"] =
950                 std::format("0x{:02X}", compResponseCode);
951         }
952 
953         pldmtool::helper::DisplayInJson(data);
954     }
955 
956   private:
957     uint8_t transferFlag;
958     uint16_t compClassification;
959     uint16_t compIdentifier;
960     uint8_t compClassificationIdx;
961     uint32_t compCompareStamp;
962     std::string compVerStrType;
963     uint8_t compVerStrLen;
964     std::string compVerStr;
965 };
966 
967 class UpdateComponent : public CommandInterface
968 {
969   public:
970     ~UpdateComponent() = default;
971     UpdateComponent() = delete;
972     UpdateComponent(const UpdateComponent&) = delete;
973     UpdateComponent(UpdateComponent&&) = delete;
974     UpdateComponent& operator=(const UpdateComponent&) = delete;
975     UpdateComponent& operator=(UpdateComponent&&) = delete;
976 
UpdateComponent(const char * type,const char * name,CLI::App * app)977     explicit UpdateComponent(const char* type, const char* name,
978                              CLI::App* app) : CommandInterface(type, name, app)
979     {
980         app->add_option(
981                "--component_classification", componentClassification,
982                "Classification value provided by the firmware package header information for\n"
983                "the component to be transferred.\n"
984                "Special values: 0x0000, 0xFFFF = reserved")
985             ->required();
986 
987         app->add_option(
988                "--component_identifier", componentIdentifier,
989                "FD vendor selected unique value to distinguish between component images")
990             ->required();
991 
992         app->add_option(
993                "--component_classification_index", componentClassificationIndex,
994                "The component classification index which was obtained from the GetFirmwareParameters\n"
995                "command to indicate which firmware component the information contained within this\n"
996                "command is applicable for")
997             ->required();
998 
999         app->add_option(
1000                "--component_comparison_stamp", componentComparisonStamp,
1001                "FD vendor selected value to use as a comparison value in determining if a firmware\n"
1002                "component is down-level or up-level. For the same component identifier, the greater\n"
1003                "of two component comparison stamps is considered up-level compared to the other\n"
1004                "when performing an unsigned integer comparison")
1005             ->required();
1006 
1007         app->add_option("--component_image_size", componentImageSize,
1008                         "Size in bytes of the component image")
1009             ->required();
1010 
1011         app->add_option(
1012                "--update_option_flags", strUpdateOptionFlags,
1013                "32-bit field, where each non-reserved bit represents an update option that can be\n"
1014                "requested by the UA to be enabled for the transfer of this component image.\n"
1015                "[2] Security Revision Number Delayed Update\n"
1016                "[1] Component Opaque Data\n"
1017                "[0] Request Force Update of component")
1018             ->required();
1019 
1020         app->add_option(
1021                "--component_version_string_type", componentVersionStringType,
1022                "The type of strings used in the ComponentVersionString\n"
1023                "Possible values\n"
1024                "{UNKNOWN->0, ASCII->1, UTF_8->2, UTF_16->3, UTF_16LE->4, UTF_16BE->5}\n"
1025                "OR {0,1,2,3,4,5}")
1026             ->required()
1027             ->check([](const std::string& value) -> std::string {
1028                 static const std::set<std::string> validStrings{
1029                     "UNKNOWN", "ASCII",    "UTF_8",
1030                     "UTF_16",  "UTF_16LE", "UTF_16BE"};
1031 
1032                 if (validStrings.contains(value))
1033                 {
1034                     return "";
1035                 }
1036 
1037                 try
1038                 {
1039                     int intValue = std::stoi(value);
1040                     if (intValue >= 0 && intValue <= 255)
1041                     {
1042                         return "";
1043                     }
1044                     return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
1045                 }
1046                 catch (const std::exception&)
1047                 {
1048                     return "Invalid value. Must be one of UNKNOWN, ASCII, UTF_8, UTF_16, UTF_16LE, UTF_16BE, or a number between 0 and 255";
1049                 }
1050             });
1051 
1052         app->add_option("--component_version_string_length",
1053                         componentVersionStringLength,
1054                         "The length, in bytes, of the ComponentVersionString")
1055             ->required();
1056 
1057         app->add_option(
1058                "--component_version_string", componentVersionString,
1059                "Firmware component version information up to 255 bytes.\n"
1060                "Contains a variable type string describing the component version")
1061             ->required();
1062     }
1063 
createRequestMsg()1064     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
1065     {
1066         variable_field componentVersionStringInfo{};
1067 
1068         componentVersionStringInfo.ptr =
1069             reinterpret_cast<const uint8_t*>(componentVersionString.data());
1070         componentVersionStringInfo.length =
1071             static_cast<uint8_t>(componentVersionString.size());
1072 
1073         std::vector<uint8_t> requestMsg(
1074             sizeof(pldm_msg_hdr) + sizeof(struct pldm_update_component_req) +
1075             componentVersionStringInfo.length);
1076 
1077         auto request = new (requestMsg.data()) pldm_msg;
1078 
1079         bitfield32_t updateOptionFlags;
1080         std::stringstream ss(strUpdateOptionFlags);
1081         ss >> std::hex >> updateOptionFlags.value;
1082         if (ss.fail())
1083         {
1084             std::cerr << "Failed to parse update option flags: "
1085                       << strUpdateOptionFlags << "\n";
1086             return {PLDM_ERROR_INVALID_DATA, std::vector<uint8_t>()};
1087         }
1088 
1089         auto rc = encode_update_component_req(
1090             instanceId, componentClassification, componentIdentifier,
1091             componentClassificationIndex, componentComparisonStamp,
1092             componentImageSize, updateOptionFlags,
1093             convertStringTypeToUInt8(componentVersionStringType),
1094             componentVersionStringLength, &componentVersionStringInfo, request,
1095             sizeof(pldm_update_component_req) +
1096                 componentVersionStringInfo.length);
1097 
1098         return {rc, requestMsg};
1099     }
1100 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)1101     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
1102     {
1103         uint8_t cc = 0;
1104         uint8_t componentCompatibilityResp = 0;
1105         uint8_t componentCompatibilityRespCode = 0;
1106         bitfield32_t updateOptionFlagsEnabled{};
1107         uint16_t timeBeforeReqFWData = 0;
1108 
1109         auto rc = decode_update_component_resp(
1110             responsePtr, payloadLength, &cc, &componentCompatibilityResp,
1111             &componentCompatibilityRespCode, &updateOptionFlagsEnabled,
1112             &timeBeforeReqFWData);
1113 
1114         if (rc != PLDM_SUCCESS)
1115         {
1116             std::cerr << "Parsing UpdateComponent response failed: "
1117                       << "rc=" << rc << ",cc=" << static_cast<int>(cc) << "\n";
1118             return;
1119         }
1120 
1121         ordered_json data;
1122         fillCompletionCode(cc, data, PLDM_FWUP);
1123 
1124         if (cc == PLDM_SUCCESS)
1125         {
1126             // Possible values:
1127             // 0 – Component can be updated,
1128             // 1 – Component will not be updated
1129             data["ComponentCompatibilityResponse"] =
1130                 componentCompatibilityResp ? "Component will not be updated"
1131                                            : "Component can be updated";
1132 
1133             data["ComponentCompatibilityResponseCode"] =
1134                 std::format("0x{:02X}", componentCompatibilityRespCode);
1135             data["UpdateOptionFlagsEnabled"] =
1136                 std::to_string(updateOptionFlagsEnabled.value);
1137             data["EstimatedTimeBeforeSendingRequestFirmwareData"] =
1138                 std::to_string(timeBeforeReqFWData) + "s";
1139         }
1140 
1141         pldmtool::helper::DisplayInJson(data);
1142     }
1143 
1144   private:
1145     uint16_t componentClassification;
1146     uint16_t componentIdentifier;
1147     uint8_t componentClassificationIndex;
1148     uint32_t componentComparisonStamp;
1149     uint32_t componentImageSize;
1150     std::string strUpdateOptionFlags;
1151     std::string componentVersionStringType;
1152     uint8_t componentVersionStringLength;
1153     std::string componentVersionString;
1154 };
1155 
1156 class ActivateFirmware : public CommandInterface
1157 {
1158   public:
1159     ~ActivateFirmware() = default;
1160     ActivateFirmware() = delete;
1161     ActivateFirmware(const ActivateFirmware&) = delete;
1162     ActivateFirmware(ActivateFirmware&&) = delete;
1163     ActivateFirmware& operator=(const ActivateFirmware&) = delete;
1164     ActivateFirmware& operator=(ActivateFirmware&&) = delete;
1165 
ActivateFirmware(const char * type,const char * name,CLI::App * app)1166     explicit ActivateFirmware(const char* type, const char* name,
1167                               CLI::App* app) : CommandInterface(type, name, app)
1168     {
1169         app->add_option("--self_contained_activation_request",
1170                         selfContainedActivRequest,
1171                         "Self contained activation request")
1172             ->required()
1173             ->transform(CLI::CheckedTransformer(pldmSelfContainedActivation,
1174                                                 CLI::ignore_case));
1175     }
1176 
createRequestMsg()1177     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
1178     {
1179         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
1180         auto request = new (requestMsg.data()) pldm_msg;
1181         auto rc = encode_activate_firmware_req(
1182             instanceId, selfContainedActivRequest, request,
1183             sizeof(pldm_activate_firmware_req));
1184 
1185         return {rc, requestMsg};
1186     }
1187 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)1188     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
1189     {
1190         uint8_t cc = 0;
1191         uint16_t estimatedTimeForActivation = 0;
1192 
1193         auto rc = decode_activate_firmware_resp(responsePtr, payloadLength, &cc,
1194                                                 &estimatedTimeForActivation);
1195         if (rc != PLDM_SUCCESS)
1196         {
1197             std::cerr << "Parsing ActivateFirmware response failed: "
1198                       << "rc=" << rc << ",cc=" << static_cast<int>(cc) << "\n";
1199             return;
1200         }
1201 
1202         ordered_json data;
1203         fillCompletionCode(cc, data, PLDM_FWUP);
1204 
1205         if (cc == PLDM_SUCCESS)
1206         {
1207             data["EstimatedTimeForSelfContainedActivation"] =
1208                 std::to_string(estimatedTimeForActivation) + "s";
1209         }
1210 
1211         pldmtool::helper::DisplayInJson(data);
1212     }
1213 
1214   private:
1215     bool8_t selfContainedActivRequest;
1216 };
1217 
1218 class CancelUpdateComponent : public CommandInterface
1219 {
1220   public:
1221     ~CancelUpdateComponent() = default;
1222     CancelUpdateComponent() = delete;
1223     CancelUpdateComponent(const CancelUpdateComponent&) = delete;
1224     CancelUpdateComponent(CancelUpdateComponent&&) = delete;
1225     CancelUpdateComponent& operator=(const CancelUpdateComponent&) = delete;
1226     CancelUpdateComponent& operator=(CancelUpdateComponent&&) = delete;
1227 
1228     using CommandInterface::CommandInterface;
1229 
createRequestMsg()1230     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
1231     {
1232         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
1233         auto request = new (requestMsg.data()) pldm_msg;
1234         auto rc = encode_cancel_update_component_req(
1235             instanceId, request, PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES);
1236         return {rc, requestMsg};
1237     }
1238 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)1239     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
1240     {
1241         uint8_t cc = 0;
1242 
1243         auto rc = decode_cancel_update_component_resp(responsePtr,
1244                                                       payloadLength, &cc);
1245         if (rc != PLDM_SUCCESS)
1246         {
1247             std::cerr << "Parsing CancelUpdateComponent response failed: "
1248                       << "rc=" << rc << ",cc=" << static_cast<int>(cc) << "\n";
1249             return;
1250         }
1251 
1252         ordered_json data;
1253         fillCompletionCode(cc, data, PLDM_FWUP);
1254 
1255         pldmtool::helper::DisplayInJson(data);
1256     }
1257 };
1258 
1259 class CancelUpdate : public CommandInterface
1260 {
1261   public:
1262     ~CancelUpdate() = default;
1263     CancelUpdate() = delete;
1264     CancelUpdate(const CancelUpdate&) = delete;
1265     CancelUpdate(CancelUpdate&&) = delete;
1266     CancelUpdate& operator=(const CancelUpdate&) = delete;
1267     CancelUpdate& operator=(CancelUpdate&&) = delete;
1268 
1269     using CommandInterface::CommandInterface;
1270 
createRequestMsg()1271     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
1272     {
1273         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
1274         auto request = new (requestMsg.data()) pldm_msg;
1275         auto rc = encode_cancel_update_req(instanceId, request,
1276                                            PLDM_CANCEL_UPDATE_REQ_BYTES);
1277 
1278         return {rc, requestMsg};
1279     }
1280 
parseResponseMsg(pldm_msg * responsePtr,size_t payloadLength)1281     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
1282     {
1283         uint8_t cc = 0;
1284         bool8_t nonFunctioningComponentIndication;
1285         bitfield64_t nonFunctioningComponentBitmap{0};
1286         auto rc = decode_cancel_update_resp(responsePtr, payloadLength, &cc,
1287                                             &nonFunctioningComponentIndication,
1288                                             &nonFunctioningComponentBitmap);
1289         if (rc != PLDM_SUCCESS)
1290         {
1291             std::cerr << "Parsing CancelUpdate response failed: "
1292                       << "rc=" << rc << ",cc=" << static_cast<int>(cc) << "\n";
1293             return;
1294         }
1295 
1296         ordered_json data;
1297 
1298         fillCompletionCode(cc, data, PLDM_FWUP);
1299 
1300         if (cc == PLDM_SUCCESS)
1301         {
1302             data["NonFunctioningComponentIndication"] =
1303                 nonFunctioningComponentIndication ? "True" : "False";
1304 
1305             if (nonFunctioningComponentIndication)
1306             {
1307                 data["NonFunctioningComponentBitmap"] =
1308                     std::to_string(nonFunctioningComponentBitmap.value);
1309             }
1310         }
1311 
1312         pldmtool::helper::DisplayInJson(data);
1313     }
1314 };
1315 
registerCommand(CLI::App & app)1316 void registerCommand(CLI::App& app)
1317 {
1318     auto fwUpdate =
1319         app.add_subcommand("fw_update", "firmware update type commands");
1320     fwUpdate->require_subcommand(1);
1321 
1322     auto getStatus = fwUpdate->add_subcommand("GetStatus", "Status of the FD");
1323     commands.push_back(
1324         std::make_unique<GetStatus>("fw_update", "GetStatus", getStatus));
1325 
1326     auto getFwParams = fwUpdate->add_subcommand(
1327         "GetFwParams", "To get the component details of the FD");
1328     commands.push_back(
1329         std::make_unique<GetFwParams>("fw_update", "GetFwParams", getFwParams));
1330 
1331     auto queryDeviceIdentifiers = fwUpdate->add_subcommand(
1332         "QueryDeviceIdentifiers", "To query device identifiers of the FD");
1333     commands.push_back(std::make_unique<QueryDeviceIdentifiers>(
1334         "fw_update", "QueryDeviceIdentifiers", queryDeviceIdentifiers));
1335 
1336     auto requestUpdate = fwUpdate->add_subcommand(
1337         "RequestUpdate", "To initiate a firmware update");
1338     commands.push_back(std::make_unique<RequestUpdate>(
1339         "fw_update", "RequestUpdate", requestUpdate));
1340 
1341     auto passCompTable = fwUpdate->add_subcommand("PassComponentTable",
1342                                                   "To pass component table");
1343     commands.push_back(std::make_unique<PassComponentTable>(
1344         "fw_update", "PassComponentTable", passCompTable));
1345 
1346     auto updateComp = fwUpdate->add_subcommand(
1347         "UpdateComponent", "To request updating a specific firmware component");
1348     commands.push_back(std::make_unique<UpdateComponent>(
1349         "fw_update", "UpdateComponent", updateComp));
1350 
1351     auto activateFirmware =
1352         fwUpdate->add_subcommand("ActivateFirmware", "To activate firmware");
1353     commands.push_back(std::make_unique<ActivateFirmware>(
1354         "fw_update", "ActivateFirmware", activateFirmware));
1355 
1356     auto cancelUpdateComp = fwUpdate->add_subcommand(
1357         "CancelUpdateComponent", "To cancel component update");
1358     commands.push_back(std::make_unique<CancelUpdateComponent>(
1359         "fw_update", "CancelUpdateComponent", cancelUpdateComp));
1360 
1361     auto cancelUpdate =
1362         fwUpdate->add_subcommand("CancelUpdate", "To cancel update");
1363     commands.push_back(std::make_unique<CancelUpdate>(
1364         "fw_update", "CancelUpdate", cancelUpdate));
1365 }
1366 
1367 } // namespace fw_update
1368 
1369 } // namespace pldmtool
1370