libpldm: Add decode API for RequestUpdate cmd response

RequestUpdate command is the command to initiate a firmware update
for a firmware device. 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: Id1c684aa17f140b318d587bd14116e03be2b4f20
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index 11007a7..b5b1162 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -670,4 +670,33 @@
 	       comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);

 

 	return PLDM_SUCCESS;

+}

+

+int decode_request_update_resp(const struct pldm_msg *msg,

+			       size_t payload_length, uint8_t *completion_code,

+			       uint16_t *fd_meta_data_len,

+			       uint8_t *fd_will_send_pkg_data)

+{

+	if (msg == NULL || completion_code == NULL ||

+	    fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||

+	    !payload_length) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	*completion_code = msg->payload[0];

+	if (*completion_code != PLDM_SUCCESS) {

+		return PLDM_SUCCESS;

+	}

+

+	if (payload_length != sizeof(struct pldm_request_update_resp)) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	struct pldm_request_update_resp *response =

+	    (struct pldm_request_update_resp *)msg->payload;

+

+	*fd_meta_data_len = le16toh(response->fd_meta_data_len);

+	*fd_will_send_pkg_data = response->fd_will_send_pkg_data;

+

+	return PLDM_SUCCESS;

 }
\ No newline at end of file
diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index b21eaff..a73e083 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -26,6 +26,31 @@
 	PLDM_REQUEST_UPDATE = 0x10

 };

 

+/** @brief PLDM Firmware update completion codes

+ */

+enum pldm_firmware_update_completion_codes {

+	PLDM_FWUP_NOT_IN_UPDATE_MODE = 0x80,

+	PLDM_FWUP_ALREADY_IN_UPDATE_MODE = 0x81,

+	PLDM_FWUP_DATA_OUT_OF_RANGE = 0x82,

+	PLDM_FWUP_INVALID_TRANSFER_LENGTH = 0x83,

+	PLDM_FWUP_INVALID_STATE_FOR_COMMAND = 0x84,

+	PLDM_FWUP_INCOMPLETE_UPDATE = 0x85,

+	PLDM_FWUP_BUSY_IN_BACKGROUND = 0x86,

+	PLDM_FWUP_CANCEL_PENDING = 0x87,

+	PLDM_FWUP_COMMAND_NOT_EXPECTED = 0x87,

+	PLDM_FWUP_RETRY_REQUEST_FW_DATA = 0x89,

+	PLDM_FWUP_UNABLE_TO_INITIATE_UPDATE = 0x8A,

+	PLDM_FWUP_ACTIVATION_NOT_REQUIRED = 0x8B,

+	PLDM_FWUP_SELF_CONTAINED_ACTIVATION_NOT_PERMITTED = 0x8C,

+	PLDM_FWUP_NO_DEVICE_METADATA = 0x8D,

+	PLDM_FWUP_RETRY_REQUEST_UPDATE = 0x8E,

+	PLDM_FWUP_NO_PACKAGE_DATA = 0x8F,

+	PLDM_FWUP_INVALID_TRANSFER_HANDLE = 0x90,

+	PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG = 0x91,

+	PLDM_FWUP_ACTIVATE_PENDING_IMAGE_NOT_PERMITTED = 0x92,

+	PLDM_FWUP_PACKAGE_DATA_ERROR = 0x93

+};

+

 /** @brief String type values defined in the PLDM firmware update specification

  */

 enum pldm_firmware_update_string_type {

@@ -203,6 +228,16 @@
 	uint8_t comp_image_set_ver_str_len;

 } __attribute__((packed));

 

+/** @struct pldm_request_update_resp

+ *

+ *  Structure representing Request Update response

+ */

+struct pldm_request_update_resp {

+	uint8_t completion_code;

+	uint16_t fd_meta_data_len;

+	uint8_t fd_will_send_pkg_data;

+} __attribute__((packed));

+

 /** @brief Decode the PLDM package header information

  *

  *  @param[in] data - pointer to package header information

@@ -408,6 +443,22 @@
 			      uint8_t comp_image_set_ver_str_len,

 			      const struct variable_field *comp_img_set_ver_str,

 			      struct pldm_msg *msg, size_t payload_length);

+

+/** @brief Decode a RequestUpdate response message

+ *

+ *  @param[in] msg - Response message

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

+ *  @param[out] completion_code - Pointer to hold the completion code

+ *  @param[out] fd_meta_data_len - Pointer to hold the length of FD metadata

+ *  @param[out] fd_will_send_pkg_data - Pointer to hold information whether FD

+ *                                      will send GetPackageData command

+ *  @return pldm_completion_codes

+ */

+int decode_request_update_resp(const struct pldm_msg *msg,

+			       size_t payload_length, uint8_t *completion_code,

+			       uint16_t *fd_meta_data_len,

+			       uint8_t *fd_will_send_pkg_data);

+

 #ifdef __cplusplus

 }

 #endif

diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index bbd3dfa..ca2b1a4 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -1393,3 +1393,81 @@
         sizeof(struct pldm_request_update_req) + compImgSetVerStrLen);

     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

 }

+

+TEST(RequestUpdate, goodPathDecodeResponse)

+{

+    constexpr uint16_t fdMetaDataLen = 1024;

+    constexpr uint8_t fdWillSendPkgData = 1;

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

+        requestUpdateResponse1{0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01};

+

+    auto responseMsg1 =

+        reinterpret_cast<const pldm_msg*>(requestUpdateResponse1.data());

+    uint8_t outCompletionCode = 0;

+    uint16_t outFdMetaDataLen = 0;

+    uint8_t outFdWillSendPkgData = 0;

+

+    auto rc = decode_request_update_resp(

+        responseMsg1, requestUpdateResponse1.size() - hdrSize,

+        &outCompletionCode, &outFdMetaDataLen, &outFdWillSendPkgData);

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(outCompletionCode, PLDM_SUCCESS);

+    EXPECT_EQ(outFdMetaDataLen, fdMetaDataLen);

+    EXPECT_EQ(outFdWillSendPkgData, fdWillSendPkgData);

+

+    outCompletionCode = 0;

+    outFdMetaDataLen = 0;

+    outFdWillSendPkgData = 0;

+

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

+        requestUpdateResponse2{0x00, 0x00, 0x00, 0x81};

+    auto responseMsg2 =

+        reinterpret_cast<const pldm_msg*>(requestUpdateResponse2.data());

+    rc = decode_request_update_resp(

+        responseMsg2, requestUpdateResponse2.size() - hdrSize,

+        &outCompletionCode, &outFdMetaDataLen, &outFdWillSendPkgData);

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(outCompletionCode, PLDM_FWUP_ALREADY_IN_UPDATE_MODE);

+}

+

+TEST(RequestUpdate, errorPathDecodeResponse)

+{

+    constexpr std::array<uint8_t,

+                         hdrSize + sizeof(pldm_request_update_resp) - 1>

+        requestUpdateResponse{0x00, 0x00, 0x00, 0x00, 0x00, 0x04};

+

+    auto responseMsg =

+        reinterpret_cast<const pldm_msg*>(requestUpdateResponse.data());

+    uint8_t outCompletionCode = 0;

+    uint16_t outFdMetaDataLen = 0;

+    uint8_t outFdWillSendPkgData = 0;

+

+    auto rc = decode_request_update_resp(

+        nullptr, requestUpdateResponse.size() - hdrSize, &outCompletionCode,

+        &outFdMetaDataLen, &outFdWillSendPkgData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_request_update_resp(

+        responseMsg, requestUpdateResponse.size() - hdrSize, nullptr,

+        &outFdMetaDataLen, &outFdWillSendPkgData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_request_update_resp(

+        responseMsg, requestUpdateResponse.size() - hdrSize, &outCompletionCode,

+        nullptr, &outFdWillSendPkgData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_request_update_resp(

+        responseMsg, requestUpdateResponse.size() - hdrSize, &outCompletionCode,

+        &outFdMetaDataLen, nullptr);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_request_update_resp(responseMsg, 0, &outCompletionCode,

+                                    &outFdMetaDataLen, &outFdWillSendPkgData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_request_update_resp(

+        responseMsg, requestUpdateResponse.size() - hdrSize, &outCompletionCode,

+        &outFdMetaDataLen, &outFdWillSendPkgData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+}