libpldm: Add decode API for RequestFirmwareData request

In order for the FD to retrieve a section of a component image, the
FD sends RequestFirmwareData request message to the UA, specifying
its offset and length. The UA will send a response message that
includes the component image portion specified by the offset and
length from the request message. 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: Ifa4ef11dab4cef90bbe11d7c906e9414f637a8d1
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index 3b881e5..b3ab07e 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -993,4 +993,26 @@
 	*time_before_req_fw_data = le16toh(response->time_before_req_fw_data);

 

 	return PLDM_SUCCESS;

+}

+

+int decode_request_firmware_data_req(const struct pldm_msg *msg,

+				     size_t payload_length, uint32_t *offset,

+				     uint32_t *length)

+{

+	if (msg == NULL || offset == NULL || length == NULL) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

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

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+	struct pldm_request_firmware_data_req *request =

+	    (struct pldm_request_firmware_data_req *)msg->payload;

+	*offset = le32toh(request->offset);

+	*length = le32toh(request->length);

+

+	if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {

+		return PLDM_FWUP_INVALID_TRANSFER_LENGTH;

+	}

+

+	return PLDM_SUCCESS;

 }
\ No newline at end of file
diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index e213ea0..ccb2b28 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -366,6 +366,15 @@
 	uint16_t time_before_req_fw_data;

 } __attribute__((packed));

 

+/** @struct pldm_request_firmware_data_req

+ *

+ *  Structure representing RequestFirmwareData request.

+ */

+struct pldm_request_firmware_data_req {

+	uint32_t offset;

+	uint32_t length;

+} __attribute__((packed));

+

 /** @brief Decode the PLDM package header information

  *

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

@@ -682,6 +691,20 @@
 				 uint8_t *comp_compatability_resp_code,

 				 bitfield32_t *update_option_flags_enabled,

 				 uint16_t *time_before_req_fw_data);

+

+/** @brief Decode RequestFirmwareData request message

+ *

+ *	@param[in] msg - Request message

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

+ *	@param[out] offset - Pointer to hold offset

+ *	@param[out] length - Pointer to hold the size of the component image

+ *                       segment requested by the FD/FDP

+ *

+ *	@return pldm_completion_codes

+ */

+int decode_request_firmware_data_req(const struct pldm_msg *msg,

+				     size_t payload_length, uint32_t *offset,

+				     uint32_t *length);

 #ifdef __cplusplus

 }

 #endif

diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index cc2d0f0..19b515c 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -1975,3 +1975,60 @@
         &updateOptionFlagsEnabled, &timeBeforeReqFWData);

     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

 }

+

+TEST(RequestFirmwareData, goodPathDecodeRequest)

+{

+    constexpr uint32_t offset = 300;

+    constexpr uint32_t length = 255;

+    constexpr std::array<uint8_t,

+                         hdrSize + sizeof(pldm_request_firmware_data_req)>

+        reqFWDataReq{0x00, 0x00, 0x00, 0x2C, 0x01, 0x00,

+                     0x00, 0xFF, 0x00, 0x00, 0x00};

+    auto requestMsg = reinterpret_cast<const pldm_msg*>(reqFWDataReq.data());

+

+    uint32_t outOffset = 0;

+    uint32_t outLength = 0;

+    auto rc = decode_request_firmware_data_req(

+        requestMsg, sizeof(pldm_request_firmware_data_req), &outOffset,

+        &outLength);

+

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(outOffset, offset);

+    EXPECT_EQ(outLength, length);

+}

+

+TEST(RequestFirmwareData, errorPathDecodeRequest)

+{

+    constexpr std::array<uint8_t,

+                         hdrSize + sizeof(pldm_request_firmware_data_req)>

+        reqFWDataReq{0x00, 0x00, 0x00, 0x2C, 0x01, 0x00,

+                     0x00, 0x1F, 0x00, 0x00, 0x00};

+    auto requestMsg = reinterpret_cast<const pldm_msg*>(reqFWDataReq.data());

+

+    uint32_t outOffset = 0;

+    uint32_t outLength = 0;

+    auto rc = decode_request_firmware_data_req(

+        nullptr, sizeof(pldm_request_firmware_data_req), &outOffset,

+        &outLength);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_request_firmware_data_req(

+        requestMsg, sizeof(pldm_request_firmware_data_req), nullptr,

+        &outLength);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_request_firmware_data_req(

+        requestMsg, sizeof(pldm_request_firmware_data_req), &outOffset,

+        nullptr);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_request_firmware_data_req(

+        requestMsg, sizeof(pldm_request_firmware_data_req) - 1, &outOffset,

+        &outLength);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+

+    rc = decode_request_firmware_data_req(

+        requestMsg, sizeof(pldm_request_firmware_data_req), &outOffset,

+        &outLength);

+    EXPECT_EQ(rc, PLDM_FWUP_INVALID_TRANSFER_LENGTH);

+}