libpldm: Add encode API for TransferComplete response

The FD sends TransferComplete command to the UA once the FD has
transferred all the data for the component image or determines the
transfer has failed. If the TransferResult of the request message
indicates the transfer completed without error then, upon the
successful completion of this command, the FD proceeds to the next
step that verifies the firmware. This implementation works with
DSP0267_1.1.0, DSP0267_1.0.1 and DSP0267_1.0.0.

Tested: Unit tests passed

Signed-off-by: gokulsanker <gokul.sanker.v.g@intel.com>
Change-Id: Ief084641400d5b2b23e346a0e9916091e48f4a37
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index b10c1a1..34cb296 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -1056,3 +1056,29 @@
 	*transfer_result = msg->payload[0];

 	return PLDM_SUCCESS;

 }

+

+int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,

+				  struct pldm_msg *msg, size_t payload_length)

+{

+	if (msg == NULL) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	if (payload_length != sizeof(completion_code)) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	struct pldm_header_info header = {0};

+	header.instance = instance_id;

+	header.msg_type = PLDM_RESPONSE;

+	header.pldm_type = PLDM_FWUP;

+	header.command = PLDM_TRANSFER_COMPLETE;

+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));

+	if (rc) {

+		return rc;

+	}

+

+	msg->payload[0] = completion_code;

+

+	return PLDM_SUCCESS;

+}
\ No newline at end of file
diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index 7b1c9f1..faca594 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -26,7 +26,8 @@
 	PLDM_REQUEST_UPDATE = 0x10,

 	PLDM_PASS_COMPONENT_TABLE = 0x13,

 	PLDM_UPDATE_COMPONENT = 0x14,

-	PLDM_REQUEST_FIRMWARE_DATA = 0x15

+	PLDM_REQUEST_FIRMWARE_DATA = 0x15,

+	PLDM_TRANSFER_COMPLETE = 0x16

 };

 

 /** @brief PLDM Firmware update completion codes

@@ -193,9 +194,9 @@
 	PLDM_FWUP_GENERIC_ERROR = 0x0A

 };

 

-/** @brief TransferResult values in the response of TransferComplete

+/** @brief TransferResult values in the request of TransferComplete

  */

-enum pldm_firmware_update_transfer_result {

+enum pldm_firmware_update_transfer_result_values {

 	PLDM_FWUP_TRANSFER_SUCCESS = 0x00,

 	PLDM_FWUP_TRANSFER_ERROR_IMAGE_CORRUPT = 0x02,

 	PLDM_FWUP_TRANSFER_ERROR_VERSION_MISMATCH = 0x02,

@@ -763,6 +764,21 @@
 int decode_transfer_complete_req(const struct pldm_msg *msg,

 				 size_t payload_length,

 				 uint8_t *transfer_result);

+

+/** @brief Create PLDM response message for TransferComplete

+ *

+ *  @param[in] instance_id - Message's instance id

+ *  @param[in] completion_code - CompletionCode

+ *  @param[in,out] msg - Message will be written to this

+ *  @param[in] payload_length - Length of response message payload

+ *

+ *  @return pldm_completion_codes

+ *

+ *  @note  Caller is responsible for memory alloc and dealloc of param

+ *         'msg.payload'

+ */

+int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,

+				  struct pldm_msg *msg, size_t payload_length);

 #ifdef __cplusplus

 }

 #endif

diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index 0aacb7b..a276e24 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -2122,3 +2122,43 @@
     rc = decode_transfer_complete_req(requestMsg, 0, &outTransferResult);

     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

 }

+

+TEST(TransferComplete, goodPathEncodeResponse)

+{

+    constexpr uint8_t instanceId = 4;

+    constexpr uint8_t completionCode = PLDM_SUCCESS;

+    constexpr std::array<uint8_t, hdrSize + sizeof(completionCode)>

+        outTransferCompleteResponse1{0x04, 0x05, 0x16, 0x00};

+    std::array<uint8_t, hdrSize + sizeof(completionCode)>

+        transferCompleteResponse1{0x00, 0x00, 0x00, 0x00};

+    auto responseMsg1 =

+        reinterpret_cast<pldm_msg*>(transferCompleteResponse1.data());

+    auto rc = encode_transfer_complete_resp(

+        instanceId, completionCode, responseMsg1, sizeof(completionCode));

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(transferCompleteResponse1, outTransferCompleteResponse1);

+

+    constexpr std::array<uint8_t, hdrSize + sizeof(completionCode)>

+        outTransferCompleteResponse2{0x04, 0x05, 0x16, 0x87};

+    std::array<uint8_t, hdrSize + sizeof(completionCode)>

+        transferCompleteResponse2{0x00, 0x00, 0x00, 0x00};

+    auto responseMsg2 =

+        reinterpret_cast<pldm_msg*>(transferCompleteResponse2.data());

+    rc = encode_transfer_complete_resp(instanceId,

+                                       PLDM_FWUP_COMMAND_NOT_EXPECTED,

+                                       responseMsg2, sizeof(completionCode));

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(transferCompleteResponse2, outTransferCompleteResponse2);

+}

+

+TEST(TransferComplete, errorPathEncodeResponse)

+{

+    std::array<uint8_t, hdrSize> transferCompleteResponse{0x00, 0x00, 0x00};

+    auto responseMsg =

+        reinterpret_cast<pldm_msg*>(transferCompleteResponse.data());

+    auto rc = encode_transfer_complete_resp(0, PLDM_SUCCESS, nullptr, 0);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = encode_transfer_complete_resp(0, PLDM_SUCCESS, responseMsg, 0);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+}