libpldm: Add encode API for RequestFirmwareData response

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. For performance reasons the
ComponentImagePortion is encoded in the response message by the
application. 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: I012b59d762314a575c39796378d0ca8713375710
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index b3ab07e..05b6db9 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -1015,4 +1015,28 @@
 	}

 

 	return PLDM_SUCCESS;

+}

+

+int encode_request_firmware_data_resp(uint8_t instance_id,

+				      uint8_t completion_code,

+				      struct pldm_msg *msg,

+				      size_t payload_length)

+{

+	if (msg == NULL || !payload_length) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	struct pldm_header_info header = {0};

+	header.instance = instance_id;

+	header.msg_type = PLDM_RESPONSE;

+	header.pldm_type = PLDM_FWUP;

+	header.command = PLDM_REQUEST_FIRMWARE_DATA;

+	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 ccb2b28..24f8c56 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -25,7 +25,8 @@
 	PLDM_GET_FIRMWARE_PARAMETERS = 0x02,

 	PLDM_REQUEST_UPDATE = 0x10,

 	PLDM_PASS_COMPONENT_TABLE = 0x13,

-	PLDM_UPDATE_COMPONENT = 0x14

+	PLDM_UPDATE_COMPONENT = 0x14,

+	PLDM_REQUEST_FIRMWARE_DATA = 0x15

 };

 

 /** @brief PLDM Firmware update completion codes

@@ -705,6 +706,30 @@
 int decode_request_firmware_data_req(const struct pldm_msg *msg,

 				     size_t payload_length, uint32_t *offset,

 				     uint32_t *length);

+

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

+ *

+ *  The ComponentImagePortion is not encoded in the PLDM response message

+ *  by encode_request_firmware_data_resp to avoid an additional copy. Populating

+ *  ComponentImagePortion in the PLDM response message is handled by the user

+ *  of this API. The payload_length validation considers only the

+ *  CompletionCode.

+ *

+ *	@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_request_firmware_data_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 19b515c..8aa012f 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -2032,3 +2032,51 @@
         &outLength);

     EXPECT_EQ(rc, PLDM_FWUP_INVALID_TRANSFER_LENGTH);

 }

+

+TEST(RequestFirmwareData, goodPathEncodeResponse)

+{

+    constexpr uint8_t instanceId = 3;

+    constexpr uint8_t completionCode = PLDM_SUCCESS;

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

+                                      PLDM_FWUP_BASELINE_TRANSFER_SIZE>

+        outReqFwDataResponse1{0x03, 0x05, 0x15, 0x00, 0x01, 0x02, 0x03, 0x04,

+                              0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,

+                              0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,

+                              0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,

+                              0x1D, 0x1E, 0x1F, 0x20};

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

+                            PLDM_FWUP_BASELINE_TRANSFER_SIZE>

+        reqFwDataResponse1{0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,

+                           0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,

+                           0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,

+                           0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,

+                           0x1D, 0x1E, 0x1F, 0x20};

+    auto responseMsg1 = reinterpret_cast<pldm_msg*>(reqFwDataResponse1.data());

+    auto rc = encode_request_firmware_data_resp(

+        instanceId, completionCode, responseMsg1,

+        sizeof(completionCode) + PLDM_FWUP_BASELINE_TRANSFER_SIZE);

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(reqFwDataResponse1, outReqFwDataResponse1);

+

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

+        outReqFwDataResponse2{0x03, 0x05, 0x15, 0x82};

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

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

+    auto responseMsg2 = reinterpret_cast<pldm_msg*>(reqFwDataResponse2.data());

+    rc = encode_request_firmware_data_resp(

+        instanceId, PLDM_FWUP_DATA_OUT_OF_RANGE, responseMsg2,

+        sizeof(completionCode));

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(reqFwDataResponse2, outReqFwDataResponse2);

+}

+

+TEST(RequestFirmwareData, errorPathEncodeResponse)

+{

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

+    auto responseMsg = reinterpret_cast<pldm_msg*>(reqFwDataResponse.data());

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

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

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

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+}