libpldm: Add decode API for GetFirmwareParameters response

decode_get_firmware_parameters_resp_comp_set_info decodes the
GetFirmwareParameters response except the component parameter table.
Update agent sends GetFirmwareParameters command to acquire the
component details such as classification types and corresponding
versions of  firmware device. Its defined in DSP0267 Version 1.1.0
sec:10.2.

Tested: Unit tests passed

Signed-off-by: gokulsanker <gokul.sanker.v.g@intel.com>
Change-Id: I73da32ffa494cc1242ffe310f78acf4596ed04cf
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index 66b4ab5..b0daddb 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -79,3 +79,78 @@
 	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,

 				       PLDM_GET_FIRMWARE_PARAMETERS, msg);

 }

+

+int decode_get_firmware_parameters_resp_comp_set_info(

+    const struct pldm_msg *msg, size_t payload_length,

+    struct pldm_get_firmware_parameters_resp *resp_data,

+    struct variable_field *active_comp_image_set_ver_str,

+    struct variable_field *pending_comp_image_set_ver_str)

+{

+	if (msg == NULL || resp_data == NULL ||

+	    active_comp_image_set_ver_str == NULL ||

+	    pending_comp_image_set_ver_str == NULL) {

+

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	struct pldm_get_firmware_parameters_resp *response =

+	    (struct pldm_get_firmware_parameters_resp *)msg->payload;

+

+	resp_data->completion_code = response->completion_code;

+

+	if (PLDM_SUCCESS != resp_data->completion_code) {

+		return PLDM_SUCCESS;

+	}

+

+	if (response->active_comp_image_set_ver_str_len == 0) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	size_t resp_len = sizeof(struct pldm_get_firmware_parameters_resp) +

+			  response->active_comp_image_set_ver_str_len +

+			  response->pending_comp_image_set_ver_str_len;

+

+	if (payload_length != resp_len) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	resp_data->capabilities_during_update.value =

+	    le32toh(response->capabilities_during_update.value);

+

+	resp_data->comp_count = le16toh(response->comp_count);

+	if (resp_data->comp_count == 0) {

+		return PLDM_ERROR;

+	}

+

+	resp_data->active_comp_image_set_ver_str_type =

+	    response->active_comp_image_set_ver_str_type;

+	resp_data->active_comp_image_set_ver_str_len =

+	    response->active_comp_image_set_ver_str_len;

+	resp_data->pending_comp_image_set_ver_str_type =

+	    response->pending_comp_image_set_ver_str_type;

+	resp_data->pending_comp_image_set_ver_str_len =

+	    response->pending_comp_image_set_ver_str_len;

+

+	active_comp_image_set_ver_str->ptr =

+	    msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);

+	active_comp_image_set_ver_str->length =

+	    resp_data->active_comp_image_set_ver_str_len;

+

+	if (resp_data->pending_comp_image_set_ver_str_len != 0) {

+		pending_comp_image_set_ver_str->ptr =

+		    msg->payload +

+		    sizeof(struct pldm_get_firmware_parameters_resp) +

+		    resp_data->active_comp_image_set_ver_str_len;

+		pending_comp_image_set_ver_str->length =

+		    resp_data->pending_comp_image_set_ver_str_len;

+	} else {

+		pending_comp_image_set_ver_str->ptr = NULL;

+		pending_comp_image_set_ver_str->length = 0;

+	}

+

+	return PLDM_SUCCESS;

+}

diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index 4d0b052..dc6d7d6 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -5,6 +5,7 @@
 extern "C" {

 #endif

 #include "base.h"

+#include "utils.h"

 

 #define PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES 0

 /** @brief Minimum length of device descriptor, 2 bytes for descriptor type,

@@ -30,6 +31,20 @@
 	uint8_t descriptor_count;

 } __attribute__((packed));

 

+/** @struct pldm_get_firmware_parameters_resp

+ *

+ *  Structure representing get firmware parameters response.

+ */

+struct pldm_get_firmware_parameters_resp {

+	uint8_t completion_code;

+	bitfield32_t capabilities_during_update;

+	uint16_t comp_count;

+	uint8_t active_comp_image_set_ver_str_type;

+	uint8_t active_comp_image_set_ver_str_len;

+	uint8_t pending_comp_image_set_ver_str_type;

+	uint8_t pending_comp_image_set_ver_str_len;

+} __attribute__((packed));

+

 /** @brief Create a PLDM request message for QueryDeviceIdentifiers

  *

  *  @param[in] instance_id - Message's instance id

@@ -77,6 +92,26 @@
 int encode_get_firmware_parameters_req(uint8_t instance_id,

 				       size_t payload_length,

 				       struct pldm_msg *msg);

+

+/** @brief Decode GetFirmwareParameters response parameters except the

+ *         ComponentParameterTable

+ *

+ *  @param[in] msg - Response message

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

+ *  @param[out] resp_data - Pointer to get firmware parameters response

+ *  @param[out] active_comp_image_set_ver_str - Pointer to active component

+ * image set version string

+ *  @param[out] pending_comp_image_set_ver_str - Pointer to pending component

+ * image set version string

+ *

+ *  @return pldm_completion_codes

+ */

+int decode_get_firmware_parameters_resp_comp_set_info(

+    const struct pldm_msg *msg, size_t payload_length,

+    struct pldm_get_firmware_parameters_resp *resp_data,

+    struct variable_field *active_comp_image_set_ver_str,

+    struct variable_field *pending_comp_image_set_ver_str);

+

 #ifdef __cplusplus

 }

 #endif

diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index cb0ec5a..b02e8ca 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -77,3 +77,72 @@
     EXPECT_EQ(requestPtr->hdr.type, PLDM_FWUP);

     EXPECT_EQ(requestPtr->hdr.command, PLDM_GET_FIRMWARE_PARAMETERS);

 }

+

+TEST(GetFirmwareParameters, goodPathDecodeResponseComponentSetInfo)

+{

+    // Random value for capabilities during update

+    constexpr uint32_t capabilitiesDuringUpdate = 0xBADBEEFE;

+    // Random value for component count

+    constexpr uint16_t componentCount = 0xAABB;

+    // ActiveCompImageSetVerStrLen is not fixed here taking it as 8

+    constexpr uint8_t activeCompImageSetVerStrLen = 8;

+    // PendingCompImageSetVerStrLen is not fixed here taking it as 8

+    constexpr uint8_t pendingCompImageSetVerStrLen = 8;

+    constexpr size_t payloadLen =

+        sizeof(struct pldm_get_firmware_parameters_resp) +

+        activeCompImageSetVerStrLen + pendingCompImageSetVerStrLen;

+

+    std::array<uint8_t, hdrSize + payloadLen> response{};

+    auto inResp = reinterpret_cast<struct pldm_get_firmware_parameters_resp*>(

+        response.data() + hdrSize);

+    inResp->completion_code = PLDM_SUCCESS;

+    inResp->capabilities_during_update.value =

+        htole32(capabilitiesDuringUpdate);

+    inResp->comp_count = htole16(componentCount);

+    inResp->active_comp_image_set_ver_str_type = 1;

+    inResp->active_comp_image_set_ver_str_len = activeCompImageSetVerStrLen;

+    inResp->pending_comp_image_set_ver_str_type = 1;

+    inResp->pending_comp_image_set_ver_str_len = pendingCompImageSetVerStrLen;

+

+    constexpr size_t activeCompImageSetVerStrPos =

+        hdrSize + sizeof(struct pldm_get_firmware_parameters_resp);

+    // filling default values for ActiveComponentImageSetVersionString

+    std::fill_n(response.data() + activeCompImageSetVerStrPos,

+                activeCompImageSetVerStrLen, 0xFF);

+    constexpr size_t pendingCompImageSetVerStrPos =

+        hdrSize + sizeof(struct pldm_get_firmware_parameters_resp) +

+        activeCompImageSetVerStrLen;

+    // filling default values for ActiveComponentImageSetVersionString

+    std::fill_n(response.data() + pendingCompImageSetVerStrPos,

+                pendingCompImageSetVerStrLen, 0xFF);

+

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

+    struct pldm_get_firmware_parameters_resp outResp;

+    struct variable_field outActiveCompImageSetVerStr;

+    struct variable_field outPendingCompImageSetVerStr;

+

+    auto rc = decode_get_firmware_parameters_resp_comp_set_info(

+        responseMsg, payloadLen, &outResp, &outActiveCompImageSetVerStr,

+        &outPendingCompImageSetVerStr);

+

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(outResp.completion_code, PLDM_SUCCESS);

+    EXPECT_EQ(outResp.capabilities_during_update.value,

+              capabilitiesDuringUpdate);

+    EXPECT_EQ(outResp.comp_count, componentCount);

+    EXPECT_EQ(inResp->active_comp_image_set_ver_str_type,

+              outResp.active_comp_image_set_ver_str_type);

+    EXPECT_EQ(inResp->active_comp_image_set_ver_str_len,

+              outResp.active_comp_image_set_ver_str_len);

+    EXPECT_EQ(0, memcmp(outActiveCompImageSetVerStr.ptr,

+                        response.data() + activeCompImageSetVerStrPos,

+                        outActiveCompImageSetVerStr.length));

+

+    EXPECT_EQ(inResp->pending_comp_image_set_ver_str_type,

+              outResp.pending_comp_image_set_ver_str_type);

+    EXPECT_EQ(inResp->pending_comp_image_set_ver_str_len,

+              outResp.pending_comp_image_set_ver_str_len);

+    EXPECT_EQ(0, memcmp(outPendingCompImageSetVerStr.ptr,

+                        response.data() + pendingCompImageSetVerStrPos,

+                        outPendingCompImageSetVerStr.length));

+}