oem-ibm: libpldm: add file IO APIs

This commit implements encode and decode APIs for in-band readFile and
writeFile commands.

In-band file IO is preferred over DMA for smaller files.

Change-Id: I92ec011560ba39aed497f533074479236abeb766
Signed-off-by: vkaverap <vkaverap@in.ibm.com>
diff --git a/oem/ibm/libpldm/file_io.c b/oem/ibm/libpldm/file_io.c
index 7806ae6..dc8ad6b 100644
--- a/oem/ibm/libpldm/file_io.c
+++ b/oem/ibm/libpldm/file_io.c
@@ -155,3 +155,229 @@
 
 	return PLDM_SUCCESS;
 }
+
+int decode_read_file_req(const struct pldm_msg *msg, size_t payload_length,
+			 uint32_t *file_handle, uint32_t *offset,
+			 uint32_t *length)
+{
+	if (msg == NULL || file_handle == NULL || offset == NULL ||
+	    length == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_READ_FILE_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_read_file_req *request =
+	    (struct pldm_read_file_req *)msg->payload;
+
+	*file_handle = le32toh(request->file_handle);
+	*offset = le32toh(request->offset);
+	*length = le32toh(request->length);
+
+	return PLDM_SUCCESS;
+}
+
+int encode_read_file_req(uint8_t instance_id, uint32_t file_handle,
+			 uint32_t offset, uint32_t length, struct pldm_msg *msg)
+{
+	struct pldm_header_info header = {0};
+	int rc = PLDM_SUCCESS;
+
+	header.msg_type = PLDM_REQUEST;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_OEM;
+	header.command = PLDM_READ_FILE;
+
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (length == 0) {
+		return PLDM_INVALID_READ_LENGTH;
+	}
+
+	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_read_file_req *request =
+	    (struct pldm_read_file_req *)msg->payload;
+
+	request->file_handle = htole32(file_handle);
+	request->offset = htole32(offset);
+	request->length = htole32(length);
+
+	return PLDM_SUCCESS;
+}
+
+int decode_read_file_resp(const struct pldm_msg *msg, size_t payload_length,
+			  uint8_t *completion_code, uint32_t *length,
+			  size_t *file_data_offset)
+{
+	if (msg == NULL || completion_code == NULL || length == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length < PLDM_READ_FILE_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_read_file_resp *response =
+	    (struct pldm_read_file_resp *)msg->payload;
+
+	*completion_code = response->completion_code;
+	if (*completion_code == PLDM_SUCCESS) {
+		*length = le32toh(response->length);
+		if (payload_length != PLDM_READ_FILE_RESP_BYTES + *length) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		*file_data_offset = sizeof(*completion_code) + sizeof(*length);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+int encode_read_file_resp(uint8_t instance_id, uint8_t completion_code,
+			  uint32_t length, struct pldm_msg *msg)
+{
+	struct pldm_header_info header = {0};
+	int rc = PLDM_SUCCESS;
+
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_OEM;
+	header.command = PLDM_READ_FILE;
+
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_read_file_resp *response =
+	    (struct pldm_read_file_resp *)msg->payload;
+	response->completion_code = completion_code;
+
+	if (response->completion_code == PLDM_SUCCESS) {
+		response->length = htole32(length);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+int decode_write_file_req(const struct pldm_msg *msg, size_t payload_length,
+			  uint32_t *file_handle, uint32_t *offset,
+			  uint32_t *length, size_t *file_data_offset)
+{
+	if (msg == NULL || file_handle == NULL || length == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length < PLDM_WRITE_FILE_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_write_file_req *request =
+	    (struct pldm_write_file_req *)msg->payload;
+
+	*file_handle = le32toh(request->file_handle);
+	*offset = le32toh(request->offset);
+	*length = le32toh(request->length);
+	if (payload_length != PLDM_WRITE_FILE_REQ_BYTES + *length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	*file_data_offset =
+	    sizeof(*file_handle) + sizeof(*offset) + sizeof(*length);
+
+	return PLDM_SUCCESS;
+}
+
+int encode_write_file_req(uint8_t instance_id, uint32_t file_handle,
+			  uint32_t offset, uint32_t length,
+			  struct pldm_msg *msg)
+{
+	struct pldm_header_info header = {0};
+	int rc = PLDM_SUCCESS;
+
+	header.msg_type = PLDM_REQUEST;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_OEM;
+	header.command = PLDM_WRITE_FILE;
+
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+		return rc;
+	}
+
+	if (length == 0) {
+		return PLDM_INVALID_WRITE_LENGTH;
+	}
+
+	struct pldm_write_file_req *request =
+	    (struct pldm_write_file_req *)msg->payload;
+
+	request->file_handle = htole32(file_handle);
+	request->offset = htole32(offset);
+	request->length = htole32(length);
+
+	return PLDM_SUCCESS;
+}
+
+int decode_write_file_resp(const struct pldm_msg *msg, size_t payload_length,
+			   uint8_t *completion_code, uint32_t *length)
+{
+	if (msg == NULL || completion_code == NULL || length == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_WRITE_FILE_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_write_file_resp *response =
+	    (struct pldm_write_file_resp *)msg->payload;
+
+	*completion_code = le32toh(response->completion_code);
+	if (response->completion_code == PLDM_SUCCESS) {
+		*length = le32toh(response->length);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+int encode_write_file_resp(uint8_t instance_id, uint8_t completion_code,
+			   uint32_t length, struct pldm_msg *msg)
+{
+	struct pldm_header_info header = {0};
+	int rc = PLDM_SUCCESS;
+
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_OEM;
+	header.command = PLDM_WRITE_FILE;
+
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_write_file_resp *response =
+	    (struct pldm_write_file_resp *)msg->payload;
+	response->completion_code = completion_code;
+
+	if (response->completion_code == PLDM_SUCCESS) {
+		response->length = htole32(length);
+	}
+
+	return PLDM_SUCCESS;
+}
diff --git a/oem/ibm/libpldm/file_io.h b/oem/ibm/libpldm/file_io.h
index b3a0f73..437897c 100644
--- a/oem/ibm/libpldm/file_io.h
+++ b/oem/ibm/libpldm/file_io.h
@@ -14,6 +14,8 @@
  */
 enum pldm_fileio_commands {
 	PLDM_GET_FILE_TABLE = 0x1,
+	PLDM_READ_FILE = 0x4,
+	PLDM_WRITE_FILE = 0x5,
 	PLDM_READ_FILE_INTO_MEMORY = 0x6,
 	PLDM_WRITE_FILE_FROM_MEMORY = 0x7,
 };
@@ -40,6 +42,10 @@
 #define PLDM_RW_FILE_MEM_RESP_BYTES 5
 #define PLDM_GET_FILE_TABLE_REQ_BYTES 6
 #define PLDM_GET_FILE_TABLE_MIN_RESP_BYTES 6
+#define PLDM_READ_FILE_REQ_BYTES 12
+#define PLDM_READ_FILE_RESP_BYTES 5
+#define PLDM_WRITE_FILE_REQ_BYTES 12
+#define PLDM_WRITE_FILE_RESP_BYTES 5
 
 /** @struct pldm_read_write_file_memory_req
  *
@@ -178,6 +184,163 @@
 			       uint8_t transfer_flag, const uint8_t *table_data,
 			       size_t table_size, struct pldm_msg *msg);
 
+/** @struct pldm_read_file_req
+ *
+ *  Structure representing ReadFile request
+ */
+struct pldm_read_file_req {
+	uint32_t file_handle; //!< Handle to file
+	uint32_t offset;      //!< Offset to file where read starts
+	uint32_t length;      //!< Bytes to be read
+} __attribute__((packed));
+
+/** @struct pldm_read_file_resp
+ *
+ *  Structure representing ReadFile response data
+ */
+struct pldm_read_file_resp {
+	uint8_t completion_code; //!< Completion code
+	uint32_t length;	 //!< Number of bytes read
+	uint8_t file_data[1];    //!< Address of this is where file data starts
+} __attribute__((packed));
+
+/** @struct pldm_write_file_req
+ *
+ *  Structure representing WriteFile request
+ */
+struct pldm_write_file_req {
+	uint32_t file_handle; //!< Handle to file
+	uint32_t offset;      //!< Offset to file where write starts
+	uint32_t length;      //!< Bytes to be written
+	uint8_t file_data[1]; //!< Address of this is where file data starts
+} __attribute__((packed));
+
+/** @struct pldm_write_file_resp
+ *
+ *  Structure representing WriteFile response data
+ */
+struct pldm_write_file_resp {
+	uint8_t completion_code; //!< Completion code
+	uint32_t length;	 //!< Bytes written
+} __attribute__((packed));
+
+/** @brief Decode Read File commands request
+ *
+ *  @param[in] msg - PLDM request message payload
+ *  @param[in] payload_length - Length of request payload
+ *  @param[out] file_handle - A handle to the file
+ *  @param[out] offset - Offset to the file at which the read should begin
+ *  @param[out] length - Number of bytes read
+ *  @return pldm_completion_codes
+ */
+int decode_read_file_req(const struct pldm_msg *msg, size_t payload_length,
+			 uint32_t *file_handle, uint32_t *offset,
+			 uint32_t *length);
+
+/** @brief Encode Read File commands request
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] file_handle - A handle to the file
+ *  @param[in] offset - Offset to the file at which the read should begin
+ *  @param[in] length - Number of bytes read
+ *  @param[in,out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param 'msg'
+ */
+int encode_read_file_req(uint8_t instance_id, uint32_t file_handle,
+			 uint32_t offset, uint32_t length,
+			 struct pldm_msg *msg);
+
+/** @brief Decode Read File commands response
+ *
+ *  @param[in] msg - PLDM response message payload
+ *  @param[in] payload_length - Length of request payload
+ *  @param[out] completion_code - PLDM completion code
+ *  @param[out] length - Number of bytes read. This could be less than what the
+ *                       requester asked for.
+ *  @param[out] file_data_offset - Offset where file data should be read in pldm
+ * msg.
+ *  @return pldm_completion_codes
+ */
+int decode_read_file_resp(const struct pldm_msg *msg, size_t payload_length,
+			  uint8_t *completion_code, uint32_t *length,
+			  size_t *file_data_offset);
+
+/** @brief Create a PLDM response for Read File
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] completion_code - PLDM completion code
+ *  @param[in] length - Number of bytes read. This could be less than what the
+ *                      requester asked for.
+ *  @param[in,out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param 'msg'.
+ *  Although read file command response includes file data, this function
+ *  does not encode the file data to prevent additional copying of the data.
+ *  The position of file data is calculated by caller from address and size
+ *  of other input arguments.
+ */
+int encode_read_file_resp(uint8_t instance_id, uint8_t completion_code,
+			  uint32_t length, struct pldm_msg *msg);
+
+/** @brief Decode Write File commands request
+ *
+ *  @param[in] msg - PLDM request message payload
+ *  @param[in] payload_length - Length of request payload
+ *  @param[out] file_handle - A handle to the file
+ *  @param[out] offset - Offset to the file at which the write should begin
+ *  @param[out] length - Number of bytes to write
+ *  @param[out] file_data_offset - Offset where file data write begins in pldm
+ * msg.
+ *  @return pldm_completion_codes
+ */
+int decode_write_file_req(const struct pldm_msg *msg, size_t payload_length,
+			  uint32_t *file_handle, uint32_t *offset,
+			  uint32_t *length, size_t *file_data_offset);
+
+/** @brief Create a PLDM request for Write File
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] file_handle - A handle to the file
+ *  @param[in] offset - Offset to the file at which the read should begin
+ *  @param[in] length - Number of bytes written. This could be less than what
+ *                      the requester asked for.
+ *  @param[in,out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param 'msg'.
+ *  Although write file command request includes file data, this function
+ *  does not encode the file data to prevent additional copying of the data.
+ *  The position of file data is calculated by caller from address and size
+ *  of other input arguments.
+ */
+int encode_write_file_req(uint8_t instance_id, uint32_t file_handle,
+			  uint32_t offset, uint32_t length,
+			  struct pldm_msg *msg);
+
+/** @brief Decode Write File commands response
+ *
+ *  @param[in] msg - PLDM request message payload
+ *  @param[in] payload_length - Length of request payload
+ *  @param[out] completion_code - PLDM completion code
+ *  @param[out] length - Number of bytes written
+ *  @return pldm_completion_codes
+ */
+int decode_write_file_resp(const struct pldm_msg *msg, size_t payload_length,
+			   uint8_t *completion_code, uint32_t *length);
+
+/** @brief Create a PLDM response for Write File
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] completion_code - PLDM completion code
+ *  @param[in] length - Number of bytes written. This could be less than what
+ *                      the requester asked for.
+ *  @param[in,out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param 'msg'
+ */
+int encode_write_file_resp(uint8_t instance_id, uint8_t completion_code,
+			   uint32_t length, struct pldm_msg *msg);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/oem/ibm/test/libpldm_fileio_test.cpp b/oem/ibm/test/libpldm_fileio_test.cpp
index de766b1..665ceb1 100644
--- a/oem/ibm/test/libpldm_fileio_test.cpp
+++ b/oem/ibm/test/libpldm_fileio_test.cpp
@@ -350,3 +350,356 @@
     ASSERT_EQ(response->hdr.command, PLDM_GET_FILE_TABLE);
     ASSERT_EQ(response->payload[0], PLDM_ERROR);
 }
+
+TEST(ReadFile, testGoodDecodeRequest)
+{
+    std::array<uint8_t, PLDM_READ_FILE_REQ_BYTES + sizeof(pldm_msg_hdr)>
+        requestMsg{};
+
+    auto requestPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    size_t payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
+    auto request = reinterpret_cast<pldm_read_file_req*>(requestPtr->payload);
+
+    // Random value for fileHandle, offset and length
+    uint32_t fileHandle = 0x12345678;
+    uint32_t offset = 0x87654321;
+    uint32_t length = 0x13245768;
+
+    request->file_handle = fileHandle;
+    request->offset = offset;
+    request->length = length;
+
+    uint32_t retFileHandle = 0;
+    uint32_t retOffset = 0;
+    uint32_t retLength = 0;
+
+    // Invoke decode the read file request
+    auto rc = decode_read_file_req(requestPtr, payload_length, &retFileHandle,
+                                   &retOffset, &retLength);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(fileHandle, retFileHandle);
+    ASSERT_EQ(offset, retOffset);
+    ASSERT_EQ(length, retLength);
+}
+
+TEST(WriteFile, testGoodDecodeRequest)
+{
+    // Random value for fileHandle, offset, length and file data
+    uint32_t fileHandle = 0x12345678;
+    uint32_t offset = 0x87654321;
+    uint32_t length = 0x467;
+
+    std::vector<uint8_t> requestMsg(PLDM_WRITE_FILE_REQ_BYTES +
+                                    sizeof(pldm_msg_hdr) + length);
+    auto requestPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    size_t payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
+    auto request = reinterpret_cast<pldm_write_file_req*>(requestPtr->payload);
+
+    size_t fileDataOffset =
+        sizeof(fileHandle) + sizeof(offset) + sizeof(length);
+
+    request->file_handle = fileHandle;
+    request->offset = offset;
+    request->length = length;
+
+    uint32_t retFileHandle = 0;
+    uint32_t retOffset = 0;
+    uint32_t retLength = 0;
+    size_t retFileDataOffset = 0;
+
+    // Invoke decode the write file request
+    auto rc = decode_write_file_req(requestPtr, payload_length, &retFileHandle,
+                                    &retOffset, &retLength, &retFileDataOffset);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(fileHandle, retFileHandle);
+    ASSERT_EQ(offset, retOffset);
+    ASSERT_EQ(length, retLength);
+    ASSERT_EQ(fileDataOffset, retFileDataOffset);
+}
+
+TEST(ReadFile, testGoodDecodeResponse)
+{
+    // Random value for length
+    uint32_t length = 0x10;
+    uint8_t completionCode = PLDM_SUCCESS;
+
+    std::vector<uint8_t> responseMsg(PLDM_READ_FILE_RESP_BYTES +
+                                     sizeof(pldm_msg_hdr) + length);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    size_t payload_length = responseMsg.size() - sizeof(pldm_msg_hdr);
+    auto response =
+        reinterpret_cast<pldm_read_file_resp*>(responsePtr->payload);
+
+    response->completion_code = completionCode;
+    response->length = length;
+
+    size_t fileDataOffset = sizeof(completionCode) + sizeof(length);
+
+    uint32_t retLength = 0;
+    uint8_t retCompletionCode = 0;
+    size_t retFileDataOffset = 0;
+
+    // Invoke decode the read file response
+    auto rc =
+        decode_read_file_resp(responsePtr, payload_length, &retCompletionCode,
+                              &retLength, &retFileDataOffset);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(completionCode, retCompletionCode);
+    ASSERT_EQ(length, retLength);
+    ASSERT_EQ(fileDataOffset, retFileDataOffset);
+}
+
+TEST(WriteFile, testGoodDecodeResponse)
+{
+    std::array<uint8_t, PLDM_WRITE_FILE_RESP_BYTES + sizeof(pldm_msg_hdr)>
+        responseMsg{};
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    size_t payload_length = responseMsg.size() - sizeof(pldm_msg_hdr);
+    auto response =
+        reinterpret_cast<pldm_write_file_resp*>(responsePtr->payload);
+
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint32_t length = 0x4678;
+
+    response->completion_code = completionCode;
+    response->length = length;
+
+    uint32_t retLength = 0;
+    uint8_t retCompletionCode = 0;
+
+    // Invoke decode the write file response
+    auto rc = decode_write_file_resp(responsePtr, payload_length,
+                                     &retCompletionCode, &retLength);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(completionCode, retCompletionCode);
+    ASSERT_EQ(length, retLength);
+}
+
+TEST(ReadWriteFile, testBadDecodeResponse)
+{
+    uint32_t length = 0;
+    uint8_t completionCode = 0;
+    size_t fileDataOffset = 0;
+
+    // Bad decode response for read file
+    std::vector<uint8_t> responseMsg(PLDM_READ_FILE_RESP_BYTES +
+                                     sizeof(pldm_msg_hdr) + length);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    // Request payload message is missing
+    auto rc = decode_read_file_resp(NULL, 0, &completionCode, &length,
+                                    &fileDataOffset);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    // Payload length is invalid
+    rc = decode_read_file_resp(responsePtr, 0, &completionCode, &length,
+                               &fileDataOffset);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+    // Bad decode response for write file
+    std::array<uint8_t, PLDM_WRITE_FILE_RESP_BYTES + sizeof(pldm_msg_hdr)>
+        responseMsgWr{};
+    auto responseWr = reinterpret_cast<pldm_msg*>(responseMsgWr.data());
+
+    // Request payload message is missing
+    rc = decode_write_file_resp(NULL, 0, &completionCode, &length);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    // Payload length is invalid
+    rc = decode_write_file_resp(responseWr, 0, &completionCode, &length);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(ReadWriteFile, testBadDecodeRequest)
+{
+    uint32_t fileHandle = 0;
+    uint32_t offset = 0;
+    uint32_t length = 0;
+
+    // Bad decode request for read file
+    std::array<uint8_t, PLDM_READ_FILE_REQ_BYTES + sizeof(pldm_msg_hdr)>
+        requestMsg{};
+    auto requestPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    // Request payload message is missing
+    auto rc = decode_read_file_req(NULL, 0, &fileHandle, &offset, &length);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    // Payload length is invalid
+    rc = decode_read_file_req(requestPtr, 0, &fileHandle, &offset, &length);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+    // Bad decode request for write file
+    size_t fileDataOffset = 0;
+    std::array<uint8_t, PLDM_WRITE_FILE_REQ_BYTES> requestMsgWr{};
+    auto requestWr = reinterpret_cast<pldm_msg*>(requestMsgWr.data());
+
+    // Request payload message is missing
+    rc = decode_write_file_req(NULL, 0, &fileHandle, &offset, &length,
+                               &fileDataOffset);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    // Payload length is invalid
+    rc = decode_write_file_req(requestWr, 0, &fileHandle, &offset, &length,
+                               &fileDataOffset);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(ReadFile, testGoodEncodeResponse)
+{
+    // Good encode response for read file
+    uint32_t length = 0x4;
+
+    std::vector<uint8_t> responseMsg(PLDM_READ_FILE_RESP_BYTES +
+                                     sizeof(pldm_msg_hdr) + length);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    auto response =
+        reinterpret_cast<pldm_read_file_resp*>(responsePtr->payload);
+
+    // ReadFile
+    auto rc = encode_read_file_resp(0, PLDM_SUCCESS, length, responsePtr);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(responsePtr->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(responsePtr->hdr.instance_id, 0);
+    ASSERT_EQ(responsePtr->hdr.type, PLDM_OEM);
+    ASSERT_EQ(responsePtr->hdr.command, PLDM_READ_FILE);
+    ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
+    ASSERT_EQ(response->length, length);
+}
+
+TEST(WriteFile, testGoodEncodeResponse)
+{
+    uint32_t length = 0x467;
+
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_WRITE_FILE_RESP_BYTES>
+        responseMsg{};
+
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    auto response =
+        reinterpret_cast<pldm_write_file_resp*>(responsePtr->payload);
+
+    // WriteFile
+    auto rc = encode_write_file_resp(0, PLDM_SUCCESS, length, responsePtr);
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(responsePtr->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(responsePtr->hdr.instance_id, 0);
+    ASSERT_EQ(responsePtr->hdr.type, PLDM_OEM);
+    ASSERT_EQ(responsePtr->hdr.command, PLDM_WRITE_FILE);
+    ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
+    ASSERT_EQ(response->length, length);
+}
+
+TEST(ReadFile, testGoodEncodeRequest)
+{
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES>
+        requestMsg{};
+
+    uint32_t fileHandle = 0x12345678;
+    uint32_t offset = 0x87654321;
+    uint32_t length = 0x13245768;
+    auto requestPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto request = reinterpret_cast<pldm_read_file_req*>(requestPtr->payload);
+
+    // ReadFile
+    auto rc = encode_read_file_req(0, fileHandle, offset, length, requestPtr);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(requestPtr->hdr.request, PLDM_REQUEST);
+    ASSERT_EQ(requestPtr->hdr.instance_id, 0);
+    ASSERT_EQ(requestPtr->hdr.type, PLDM_OEM);
+    ASSERT_EQ(requestPtr->hdr.command, PLDM_READ_FILE);
+    ASSERT_EQ(request->file_handle, fileHandle);
+    ASSERT_EQ(request->offset, offset);
+    ASSERT_EQ(request->length, length);
+}
+
+TEST(WriteFile, testGoodEncodeRequest)
+{
+    uint32_t fileHandle = 0x12345678;
+    uint32_t offset = 0x87654321;
+    uint32_t length = 0x456;
+
+    std::vector<uint8_t> requestMsg(PLDM_WRITE_FILE_REQ_BYTES +
+                                    sizeof(pldm_msg_hdr) + length);
+    auto requestPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto request = reinterpret_cast<pldm_write_file_req*>(requestPtr->payload);
+
+    // WriteFile
+    auto rc = encode_write_file_req(0, fileHandle, offset, length, requestPtr);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(requestPtr->hdr.request, PLDM_REQUEST);
+    ASSERT_EQ(requestPtr->hdr.instance_id, 0);
+    ASSERT_EQ(requestPtr->hdr.type, PLDM_OEM);
+    ASSERT_EQ(requestPtr->hdr.command, PLDM_WRITE_FILE);
+    ASSERT_EQ(request->file_handle, fileHandle);
+    ASSERT_EQ(request->offset, offset);
+    ASSERT_EQ(request->length, length);
+}
+
+TEST(ReadWriteFile, testBadEncodeRequest)
+{
+    // Bad encode request for read file
+    uint32_t fileHandle = 0;
+    uint32_t offset = 0;
+    uint32_t length = 0;
+
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES>
+        requestMsg{};
+    auto requestPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    // ReadFile check invalid file length
+    auto rc = encode_read_file_req(0, fileHandle, offset, length, requestPtr);
+
+    ASSERT_EQ(rc, PLDM_INVALID_READ_LENGTH);
+
+    // Bad encode request for write file
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_WRITE_FILE_REQ_BYTES>
+        requestMsgWr{};
+    auto requestWr = reinterpret_cast<pldm_msg*>(requestMsgWr.data());
+
+    // WriteFile check for invalid file length
+    rc = encode_write_file_req(0, fileHandle, offset, length, requestWr);
+
+    ASSERT_EQ(rc, PLDM_INVALID_WRITE_LENGTH);
+}
+
+TEST(ReadWriteFile, testBadEncodeResponse)
+{
+    // Bad encode response for read file
+    uint32_t length = 0;
+
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_RESP_BYTES>
+        responseMsg{};
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    // ReadFile
+    auto rc = encode_read_file_resp(0, PLDM_ERROR, length, responsePtr);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(responsePtr->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(responsePtr->hdr.instance_id, 0);
+    ASSERT_EQ(responsePtr->hdr.type, PLDM_OEM);
+    ASSERT_EQ(responsePtr->hdr.command, PLDM_READ_FILE);
+    ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR);
+
+    // Bad encode response for write file
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_WRITE_FILE_RESP_BYTES>
+        responseMsgWr{};
+    auto responseWr = reinterpret_cast<pldm_msg*>(responseMsgWr.data());
+
+    // WriteFile
+    rc = encode_write_file_resp(0, PLDM_ERROR, length, responseWr);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(responseWr->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(responseWr->hdr.instance_id, 0);
+    ASSERT_EQ(responseWr->hdr.type, PLDM_OEM);
+    ASSERT_EQ(responseWr->hdr.command, PLDM_WRITE_FILE);
+    ASSERT_EQ(responseWr->payload[0], PLDM_ERROR);
+}