Implement GetBIOSAttributeCurrentValueByHandle encode/decode API

Implemented the functions to encode/decode the request of
GetBIOSAttributeCurrentValueByHandle as required for the responder.
Corresponding unit test functions have also been added to check the
good decode requests and bad decode request.

Change-Id: I711bd13a37cfd3a825c58b37029d3c35903c7fc3
Signed-off-by: Zahed Hossain <zahzahed@in.ibm.com>
diff --git a/libpldm/bios.c b/libpldm/bios.c
index 3027f6c..212ed79 100644
--- a/libpldm/bios.c
+++ b/libpldm/bios.c
@@ -148,3 +148,63 @@
 
 	return PLDM_SUCCESS;
 }
+
+int decode_get_bios_attribute_current_value_by_handle_req(
+    const struct pldm_msg *msg, size_t payload_length,
+    uint32_t *transfer_handle, uint8_t *transfer_op_flag,
+    uint16_t *attribute_handle)
+{
+	if (msg == NULL || transfer_handle == NULL ||
+	    transfer_op_flag == NULL || attribute_handle == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_bios_attribute_current_value_by_handle_req *request =
+	    (struct pldm_get_bios_attribute_current_value_by_handle_req *)
+		msg->payload;
+	*transfer_handle = le32toh(request->transfer_handle);
+	*transfer_op_flag = request->transfer_op_flag;
+	*attribute_handle = le16toh(request->attribute_handle);
+
+	return PLDM_SUCCESS;
+}
+
+int encode_get_bios_current_value_by_handle_resp(
+    uint8_t instance_id, uint8_t completion_code, uint32_t next_transfer_handle,
+    uint8_t transfer_flag, const uint8_t *attribute_data,
+    size_t attribute_length, struct pldm_msg *msg)
+{
+	struct pldm_header_info header = {0};
+	int rc = PLDM_SUCCESS;
+
+	if (msg == NULL || attribute_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_get_bios_attribute_current_value_by_handle_resp *response =
+	    (struct pldm_get_bios_attribute_current_value_by_handle_resp *)
+		msg->payload;
+
+	response->completion_code = completion_code;
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE;
+	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+		return rc;
+	}
+	if (response->completion_code == PLDM_SUCCESS) {
+
+		response->next_transfer_handle = htole32(next_transfer_handle);
+		response->transfer_flag = transfer_flag;
+		if (attribute_data != NULL) {
+			memcpy(response->attribute_data, attribute_data,
+			       attribute_length);
+		}
+	}
+	return PLDM_SUCCESS;
+}
diff --git a/libpldm/bios.h b/libpldm/bios.h
index d8886c3..c018d07 100644
--- a/libpldm/bios.h
+++ b/libpldm/bios.h
@@ -16,6 +16,7 @@
 
 #define PLDM_GET_BIOS_TABLE_REQ_BYTES 6
 #define PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES 6
+#define PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES 7
 
 enum pldm_bios_completion_codes {
 	PLDM_BIOS_TABLE_UNAVAILABLE = 0x83,
@@ -24,7 +25,8 @@
 };
 enum pldm_bios_commands {
 	PLDM_GET_BIOS_TABLE = 0x01,
-	PLDM_GET_DATE_TIME = 0x0c
+	PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE = 0x08,
+	PLDM_GET_DATE_TIME = 0x0c,
 };
 
 enum pldm_bios_table_types {
@@ -103,6 +105,27 @@
 	uint16_t year;		 //!< Year in BCD format
 } __attribute__((packed));
 
+/** @struct pldm_get_bios_attribute_current_value_by_handle_req
+ *
+ *  structure representing GetBIOSAttributeCurrentValueByHandle request packet
+ */
+struct pldm_get_bios_attribute_current_value_by_handle_req {
+	uint32_t transfer_handle;
+	uint8_t transfer_op_flag;
+	uint16_t attribute_handle;
+} __attribute__((packed));
+
+/** @struct pldm_get_bios_attribute_current_value_by_handle_resp
+ *
+ *  structure representing GetBIOSAttributeCurrentValueByHandle response
+ */
+struct pldm_get_bios_attribute_current_value_by_handle_resp {
+	uint8_t completion_code;
+	uint32_t next_transfer_handle;
+	uint8_t transfer_flag;
+	uint8_t attribute_data[1];
+} __attribute__((packed));
+
 /* Requester */
 
 /* GetDateTime */
@@ -195,6 +218,42 @@
 			      uint32_t *transfer_handle,
 			      uint8_t *transfer_op_flag, uint8_t *table_type);
 
+/* GetBIOSAttributeCurrentValueByHandle */
+
+/** @brief Decode GetBIOSAttributeCurrentValueByHandle request packet
+ *
+ *  @param[in] msg - Request message
+ *  @param[in] payload_length - Length of request message payload
+ *  @param[out] transfer_handle - Handle to identify a BIOS table transfer
+ *  @param[out] transfer_op_flag - Flag to indicate the start of a multipart
+ * transfer
+ *  @param[out] attribute_handle - Handle to identify the BIOS attribute
+ *  @return pldm_completion_codes
+ */
+int decode_get_bios_attribute_current_value_by_handle_req(
+    const struct pldm_msg *msg, size_t payload_length,
+    uint32_t *transfer_handle, uint8_t *transfer_op_flag,
+    uint16_t *attribute_handle);
+
+/** @brief Create a PLDM response message for
+ * GetBIOSAttributeCurrentValueByHandle
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] completion_code - PLDM completion code
+ *  @param[in] next_transfer_handle - handle to identify the next portion of the
+ * transfer
+ *  @param[in] transfer_flag - To indicate what part of the transfer this
+ * response represents
+ *  @param[in] attribute_data - contains current value of attribute
+ *  @param[in] attribute_length - Length of attribute
+ *  @param[out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ */
+int encode_get_bios_current_value_by_handle_resp(
+    uint8_t instance_id, uint8_t completion_code, uint32_t next_transfer_handle,
+    uint8_t transfer_flag, const uint8_t *attribute_data,
+    size_t attribute_length, struct pldm_msg *msg);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/test/libpldm_bios_test.cpp b/test/libpldm_bios_test.cpp
index aff5d6d..00a160f 100644
--- a/test/libpldm_bios_test.cpp
+++ b/test/libpldm_bios_test.cpp
@@ -206,3 +206,126 @@
 
     ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
 }
+
+TEST(GetBIOSAttributeCurrentValueByHandle, testGoodDecodeRequest)
+{
+    uint32_t transferHandle = 45;
+    uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
+    uint16_t attributehandle = 10;
+    uint32_t retTransferHandle = 0;
+    uint8_t retTransferOpFlag = 0;
+    uint16_t retattributehandle = 0;
+    std::array<uint8_t, hdrSize + sizeof(transferHandle) +
+                            sizeof(transferOpFlag) + sizeof(attributehandle)>
+        requestMsg{};
+
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    struct pldm_get_bios_attribute_current_value_by_handle_req* request =
+        reinterpret_cast<
+            struct pldm_get_bios_attribute_current_value_by_handle_req*>(
+            req->payload);
+
+    request->transfer_handle = transferHandle;
+    request->transfer_op_flag = transferOpFlag;
+    request->attribute_handle = attributehandle;
+
+    auto rc = decode_get_bios_attribute_current_value_by_handle_req(
+        req, requestMsg.size() - hdrSize, &retTransferHandle,
+        &retTransferOpFlag, &retattributehandle);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(transferHandle, retTransferHandle);
+    ASSERT_EQ(transferOpFlag, retTransferOpFlag);
+    ASSERT_EQ(attributehandle, retattributehandle);
+}
+
+TEST(GetBIOSAttributeCurrentValueByHandle, testBadDecodeRequest)
+{
+
+    uint32_t transferHandle = 0;
+    uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
+    uint16_t attribute_handle = 0;
+    uint32_t retTransferHandle = 0;
+    uint8_t retTransferOpFlag = 0;
+    uint16_t retattribute_handle = 0;
+    std::array<uint8_t, hdrSize + sizeof(transferHandle) +
+                            sizeof(transferOpFlag) + sizeof(attribute_handle)>
+        requestMsg{};
+
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    struct pldm_get_bios_attribute_current_value_by_handle_req* request =
+        reinterpret_cast<
+            struct pldm_get_bios_attribute_current_value_by_handle_req*>(
+            req->payload);
+
+    request->transfer_handle = transferHandle;
+    request->transfer_op_flag = transferOpFlag;
+    request->attribute_handle = attribute_handle;
+
+    auto rc = decode_get_bios_attribute_current_value_by_handle_req(
+        NULL, requestMsg.size() - hdrSize, &retTransferHandle,
+        &retTransferOpFlag, &retattribute_handle);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    transferHandle = 31;
+    request->transfer_handle = transferHandle;
+
+    rc = decode_get_bios_attribute_current_value_by_handle_req(
+        req, 0, &retTransferHandle, &retTransferOpFlag, &retattribute_handle);
+
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(GetBIOSAttributeCurrentValueByHandle, testGoodEncodeResponse)
+{
+
+    uint8_t instanceId = 10;
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint32_t nextTransferHandle = 32;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    uint8_t attributeData = 44;
+    std::array<uint8_t,
+               hdrSize +
+                   sizeof(pldm_get_bios_attribute_current_value_by_handle_resp)>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = encode_get_bios_current_value_by_handle_resp(
+        instanceId, completionCode, nextTransferHandle, transferFlag,
+        &attributeData, sizeof(attributeData), response);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+
+    struct pldm_get_bios_attribute_current_value_by_handle_resp* resp =
+        reinterpret_cast<
+            struct pldm_get_bios_attribute_current_value_by_handle_resp*>(
+            response->payload);
+
+    ASSERT_EQ(completionCode, resp->completion_code);
+    ASSERT_EQ(nextTransferHandle, resp->next_transfer_handle);
+    ASSERT_EQ(transferFlag, resp->transfer_flag);
+    ASSERT_EQ(
+        0, memcmp(&attributeData, resp->attribute_data, sizeof(attributeData)));
+}
+
+TEST(GetBIOSAttributeCurrentValueByHandle, testBadEncodeResponse)
+{
+    uint32_t nextTransferHandle = 32;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    uint8_t attributeData = 44;
+
+    auto rc = encode_get_bios_current_value_by_handle_resp(
+        0, PLDM_SUCCESS, nextTransferHandle, transferFlag, &attributeData,
+        sizeof(attributeData), nullptr);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    std::array<uint8_t,
+               hdrSize +
+                   sizeof(pldm_get_bios_attribute_current_value_by_handle_resp)>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    rc = encode_get_bios_current_value_by_handle_resp(
+        0, PLDM_SUCCESS, nextTransferHandle, transferFlag, nullptr,
+        sizeof(attributeData), response);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}