pldmtool: Add support for CancelUpdate

Tested:

pldmtool fw_update CancelUpdate -m 13
{
    "CompletionCode": "SUCCESS",
    "NonFunctioningComponentIndication": "False"
}

Change-Id: I9a5824658e8e8f2611427b8722947d9777e08813
Signed-off-by: Tom Joseph <rushtotom@gmail.com>
diff --git a/pldmtool/pldm_fw_update_cmd.cpp b/pldmtool/pldm_fw_update_cmd.cpp
index 3921925..d992d94 100644
--- a/pldmtool/pldm_fw_update_cmd.cpp
+++ b/pldmtool/pldm_fw_update_cmd.cpp
@@ -1251,6 +1251,64 @@
 
         ordered_json data;
         fillCompletionCode(cc, data, PLDM_FWUP);
+
+        pldmtool::helper::DisplayInJson(data);
+    }
+};
+
+class CancelUpdate : public CommandInterface
+{
+  public:
+    ~CancelUpdate() = default;
+    CancelUpdate() = delete;
+    CancelUpdate(const CancelUpdate&) = delete;
+    CancelUpdate(CancelUpdate&&) = delete;
+    CancelUpdate& operator=(const CancelUpdate&) = delete;
+    CancelUpdate& operator=(CancelUpdate&&) = delete;
+
+    using CommandInterface::CommandInterface;
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
+        auto request = new (requestMsg.data()) pldm_msg;
+        auto rc = encode_cancel_update_req(instanceId, request,
+                                           PLDM_CANCEL_UPDATE_REQ_BYTES);
+
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t cc = 0;
+        bool8_t nonFunctioningComponentIndication;
+        bitfield64_t nonFunctioningComponentBitmap{0};
+        auto rc = decode_cancel_update_resp(responsePtr, payloadLength, &cc,
+                                            &nonFunctioningComponentIndication,
+                                            &nonFunctioningComponentBitmap);
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "Parsing CancelUpdate response failed: "
+                      << "rc=" << rc << ",cc=" << static_cast<int>(cc) << "\n";
+            return;
+        }
+
+        ordered_json data;
+
+        fillCompletionCode(cc, data, PLDM_FWUP);
+
+        if (cc == PLDM_SUCCESS)
+        {
+            data["NonFunctioningComponentIndication"] =
+                nonFunctioningComponentIndication ? "True" : "False";
+
+            if (nonFunctioningComponentIndication)
+            {
+                data["NonFunctioningComponentBitmap"] =
+                    std::to_string(nonFunctioningComponentBitmap.value);
+            }
+        }
+
         pldmtool::helper::DisplayInJson(data);
     }
 };
@@ -1299,6 +1357,11 @@
         "CancelUpdateComponent", "To cancel component update");
     commands.push_back(std::make_unique<CancelUpdateComponent>(
         "fw_update", "CancelUpdateComponent", cancelUpdateComp));
+
+    auto cancelUpdate =
+        fwUpdate->add_subcommand("CancelUpdate", "To cancel update");
+    commands.push_back(std::make_unique<CancelUpdate>(
+        "fw_update", "CancelUpdate", cancelUpdate));
 }
 
 } // namespace fw_update