libpldm: Add encode API for ApplyComplete response

After firmware verification is successful, the FD transitions
into the APPLY state and begins transferring the component image into
the storage location where the object resides. After the FD finishes
applying the component successfully, it issues an ApplyComplete
command indicating success and the FD transitions to the READY XFER
state to be ready for the next component transfer. 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: Ia1471e03863ad343416c1d26083a2db5ed2cb525
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index 2dfa721..8dd09d2 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -1151,3 +1151,29 @@
 

 	return PLDM_SUCCESS;

 }

+

+int encode_apply_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_APPLY_COMPLETE;

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

+	if (rc) {

+		return rc;

+	}

+

+	msg->payload[0] = completion_code;

+

+	return PLDM_SUCCESS;

+}

diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index 58b8063..afa87fe 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -28,7 +28,8 @@
 	PLDM_UPDATE_COMPONENT = 0x14,

 	PLDM_REQUEST_FIRMWARE_DATA = 0x15,

 	PLDM_TRANSFER_COMPLETE = 0x16,

-	PLDM_VERIFY_COMPLETE = 0x17

+	PLDM_VERIFY_COMPLETE = 0x17,

+	PLDM_APPLY_COMPLETE = 0x18

 };

 

 /** @brief PLDM Firmware update completion codes

@@ -236,7 +237,7 @@
 	PLDM_FWUP_VENDOR_VERIFY_RESULT_RANGE_MAX = 0xAF

 };

 

-/**@brief ApplyResult values in the response of ApplyComplete

+/**@brief ApplyResult values in the request of ApplyComplete

  */

 enum pldm_firmware_update_apply_result_values {

 	PLDM_FWUP_APPLY_SUCCESS = 0x00,

@@ -867,6 +868,21 @@
     const struct pldm_msg *msg, size_t payload_length, uint8_t *apply_result,

     bitfield16_t *comp_activation_methods_modification);

 

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

+ *

+ *  @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_apply_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 8622c76..a9829a2 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -2310,3 +2310,42 @@
                                    &outCompActivationModification);

     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

 }

+

+TEST(ApplyComplete, goodPathEncodeResponse)

+{

+    constexpr uint8_t instanceId = 6;

+    constexpr uint8_t completionCode = PLDM_SUCCESS;

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

+        outApplyCompleteResponse1{0x06, 0x05, 0x18, 0x00};

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

+        applyCompleteResponse1{0x00, 0x00, 0x00, 0x00};

+    auto responseMsg1 =

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

+    auto rc = encode_apply_complete_resp(instanceId, completionCode,

+                                         responseMsg1, sizeof(completionCode));

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(applyCompleteResponse1, outApplyCompleteResponse1);

+

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

+        outApplyCompleteResponse2{0x06, 0x05, 0x18, 0x87};

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

+        applyCompleteResponse2{0x00, 0x00, 0x00, 0x00};

+    auto responseMsg2 =

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

+    rc = encode_apply_complete_resp(instanceId, PLDM_FWUP_COMMAND_NOT_EXPECTED,

+                                    responseMsg2, sizeof(completionCode));

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(applyCompleteResponse2, outApplyCompleteResponse2);

+}

+

+TEST(ApplyComplete, errorPathEncodeResponse)

+{

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

+    auto responseMsg =

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

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

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

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

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+}