libpldm: Add decode API for ComponentParameterTable entry

ComponentParameterTable is present in the response of
GetFirmwareParameters command. ComponentParameterTable is a table that
contains component entries for all of the updateable components which
reside on the firmware device.

decode_get_firmware_parameters_resp_comp_entry decodes each entry in
the ComponentParameterTable.

Tested: Unit tests passed

Signed-off-by: gokulsanker <gokul.sanker.v.g@intel.com>
Change-Id: I3698b268cf42345d80d7d218919d42ffad0b011f
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index b0daddb..58dd21f 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -1,5 +1,6 @@
 #include "firmware_update.h"

 #include <endian.h>

+#include <string.h>

 

 int encode_query_device_identifiers_req(uint8_t instance_id,

 					size_t payload_length,

@@ -154,3 +155,77 @@
 

 	return PLDM_SUCCESS;

 }

+

+int decode_get_firmware_parameters_resp_comp_entry(

+    const uint8_t *data, size_t length,

+    struct pldm_component_parameter_entry *component_data,

+    struct variable_field *active_comp_ver_str,

+    struct variable_field *pending_comp_ver_str)

+{

+	if (data == NULL || component_data == NULL ||

+	    active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	if (length < sizeof(struct pldm_component_parameter_entry)) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	struct pldm_component_parameter_entry *entry =

+	    (struct pldm_component_parameter_entry *)(data);

+	if (entry->active_comp_ver_str_len == 0) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	size_t entry_length = sizeof(struct pldm_component_parameter_entry) +

+			      entry->active_comp_ver_str_len +

+			      entry->pending_comp_ver_str_len;

+

+	if (length != entry_length) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	component_data->comp_classification =

+	    le16toh(entry->comp_classification);

+	component_data->comp_identifier = le16toh(entry->comp_identifier);

+	component_data->comp_classification_index =

+	    entry->comp_classification_index;

+	component_data->active_comp_comparison_stamp =

+	    le32toh(entry->active_comp_comparison_stamp);

+	component_data->active_comp_ver_str_type =

+	    entry->active_comp_ver_str_type;

+	component_data->active_comp_ver_str_len =

+	    entry->active_comp_ver_str_len;

+	memcpy(component_data->active_comp_release_date,

+	       entry->active_comp_release_date,

+	       sizeof(entry->active_comp_release_date));

+	component_data->pending_comp_comparison_stamp =

+	    le32toh(entry->pending_comp_comparison_stamp);

+	component_data->pending_comp_ver_str_type =

+	    entry->pending_comp_ver_str_type;

+	component_data->pending_comp_ver_str_len =

+	    entry->pending_comp_ver_str_len;

+	memcpy(component_data->pending_comp_release_date,

+	       entry->pending_comp_release_date,

+	       sizeof(entry->pending_comp_release_date));

+	component_data->comp_activation_methods.value =

+	    le16toh(entry->comp_activation_methods.value);

+	component_data->capabilities_during_update.value =

+	    le32toh(entry->capabilities_during_update.value);

+

+	active_comp_ver_str->ptr =

+	    data + sizeof(struct pldm_component_parameter_entry);

+	active_comp_ver_str->length = entry->active_comp_ver_str_len;

+

+	if (entry->pending_comp_ver_str_len != 0) {

+

+		pending_comp_ver_str->ptr =

+		    data + sizeof(struct pldm_component_parameter_entry) +

+		    entry->active_comp_ver_str_len;

+		pending_comp_ver_str->length = entry->pending_comp_ver_str_len;

+	} else {

+		pending_comp_ver_str->ptr = NULL;

+		pending_comp_ver_str->length = 0;

+	}

+	return PLDM_SUCCESS;

+}

diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index dc6d7d6..1c3e21b 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -45,6 +45,26 @@
 	uint8_t pending_comp_image_set_ver_str_len;

 } __attribute__((packed));

 

+/** @struct pldm_component_parameter_entry

+ *

+ *  Structure representing component parameter table entry.

+ */

+struct pldm_component_parameter_entry {

+	uint16_t comp_classification;

+	uint16_t comp_identifier;

+	uint8_t comp_classification_index;

+	uint32_t active_comp_comparison_stamp;

+	uint8_t active_comp_ver_str_type;

+	uint8_t active_comp_ver_str_len;

+	uint8_t active_comp_release_date[8];

+	uint32_t pending_comp_comparison_stamp;

+	uint8_t pending_comp_ver_str_type;

+	uint8_t pending_comp_ver_str_len;

+	uint8_t pending_comp_release_date[8];

+	bitfield16_t comp_activation_methods;

+	bitfield32_t capabilities_during_update;

+} __attribute__((packed));

+

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

  *

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

@@ -112,6 +132,24 @@
     struct variable_field *active_comp_image_set_ver_str,

     struct variable_field *pending_comp_image_set_ver_str);

 

+/** @brief Decode component entries in the component parameter table which is

+ *         part of the response of GetFirmwareParameters command

+ *

+ *  @param[in] data - Component entry

+ *  @param[in] length - Length of component entry

+ *  @param[out] component_data - Pointer to component parameter table

+ *  @param[out] active_comp_ver_str - Pointer to active component version string

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

+ *                                     string

+ *

+ *  @return pldm_completion_codes

+ */

+int decode_get_firmware_parameters_resp_comp_entry(

+    const uint8_t *data, size_t length,

+    struct pldm_component_parameter_entry *component_data,

+    struct variable_field *active_comp_ver_str,

+    struct variable_field *pending_comp_ver_str);

+

 #ifdef __cplusplus

 }

 #endif

diff --git a/libpldm/pldm_types.h b/libpldm/pldm_types.h
index ee823a5..5e7e068 100644
--- a/libpldm/pldm_types.h
+++ b/libpldm/pldm_types.h
@@ -31,6 +31,28 @@
 typedef uint8_t bool8_t;
 
 typedef union {
+	uint16_t value;
+	struct {
+		uint8_t bit0 : 1;
+		uint8_t bit1 : 1;
+		uint8_t bit2 : 1;
+		uint8_t bit3 : 1;
+		uint8_t bit4 : 1;
+		uint8_t bit5 : 1;
+		uint8_t bit6 : 1;
+		uint8_t bit7 : 1;
+		uint8_t bit8 : 1;
+		uint8_t bit9 : 1;
+		uint8_t bit10 : 1;
+		uint8_t bit11 : 1;
+		uint8_t bit12 : 1;
+		uint8_t bit13 : 1;
+		uint8_t bit14 : 1;
+		uint8_t bit15 : 1;
+	} __attribute__((packed)) bits;
+} bitfield16_t;
+
+typedef union {
 	uint32_t value;
 	struct {
 		uint8_t bit0 : 1;
diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index b02e8ca..3e35cf6 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -146,3 +146,94 @@
                         response.data() + pendingCompImageSetVerStrPos,

                         outPendingCompImageSetVerStr.length));

 }

+

+TEST(GetFirmwareParameters, goodPathDecodeComponentParameterEntry)

+{

+    // Random value for component classification

+    constexpr uint16_t compClassification = 0x0A0B;

+    // Random value for component classification

+    constexpr uint16_t compIdentifier = 0x0C0D;

+    // Random value for component classification

+    constexpr uint32_t timestamp = 0X12345678;

+    // Random value for component activation methods

+    constexpr uint16_t compActivationMethods = 0xBBDD;

+    // Random value for capabilities during update

+    constexpr uint32_t capabilitiesDuringUpdate = 0xBADBEEFE;

+

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

+    constexpr uint8_t activeCompVerStrLen = 8;

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

+    constexpr uint8_t pendingCompVerStrLen = 8;

+    constexpr size_t entryLength =

+        sizeof(struct pldm_component_parameter_entry) + activeCompVerStrLen +

+        pendingCompVerStrLen;

+    std::array<uint8_t, entryLength> entry{};

+

+    auto inEntry =

+        reinterpret_cast<struct pldm_component_parameter_entry*>(entry.data());

+

+    inEntry->comp_classification = htole16(compClassification);

+    inEntry->comp_identifier = htole16(compIdentifier);

+    inEntry->comp_classification_index = 0x0F;

+    inEntry->active_comp_comparison_stamp = htole32(timestamp);

+    inEntry->active_comp_ver_str_type = 1;

+    inEntry->active_comp_ver_str_len = activeCompVerStrLen;

+    std::fill_n(inEntry->active_comp_release_date,

+                sizeof(inEntry->active_comp_release_date), 0xFF);

+    inEntry->pending_comp_comparison_stamp = htole32(timestamp);

+    inEntry->pending_comp_ver_str_type = 1;

+    inEntry->pending_comp_ver_str_len = pendingCompVerStrLen;

+    std::fill_n(inEntry->pending_comp_release_date,

+                sizeof(inEntry->pending_comp_release_date), 0xFF);

+    inEntry->comp_activation_methods.value = htole16(compActivationMethods);

+    inEntry->capabilities_during_update.value =

+        htole32(capabilitiesDuringUpdate);

+    constexpr auto activeCompVerStrPos =

+        sizeof(struct pldm_component_parameter_entry);

+    std::fill_n(entry.data() + activeCompVerStrPos, activeCompVerStrLen, 0xAA);

+    constexpr auto pendingCompVerStrPos =

+        activeCompVerStrPos + activeCompVerStrLen;

+    std::fill_n(entry.data() + pendingCompVerStrPos, pendingCompVerStrLen,

+                0xBB);

+

+    struct pldm_component_parameter_entry outEntry;

+    struct variable_field outActiveCompVerStr;

+    struct variable_field outPendingCompVerStr;

+

+    auto rc = decode_get_firmware_parameters_resp_comp_entry(

+        entry.data(), entryLength, &outEntry, &outActiveCompVerStr,

+        &outPendingCompVerStr);

+

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+

+    EXPECT_EQ(outEntry.comp_classification, compClassification);

+    EXPECT_EQ(outEntry.comp_identifier, compIdentifier);

+    EXPECT_EQ(inEntry->comp_classification_index,

+              outEntry.comp_classification_index);

+    EXPECT_EQ(outEntry.active_comp_comparison_stamp, timestamp);

+    EXPECT_EQ(inEntry->active_comp_ver_str_type,

+              outEntry.active_comp_ver_str_type);

+    EXPECT_EQ(inEntry->active_comp_ver_str_len,

+              outEntry.active_comp_ver_str_len);

+    EXPECT_EQ(0, memcmp(inEntry->active_comp_release_date,

+                        outEntry.active_comp_release_date,

+                        sizeof(inEntry->active_comp_release_date)));

+    EXPECT_EQ(outEntry.pending_comp_comparison_stamp, timestamp);

+    EXPECT_EQ(inEntry->pending_comp_ver_str_type,

+              outEntry.pending_comp_ver_str_type);

+    EXPECT_EQ(inEntry->pending_comp_ver_str_len,

+              outEntry.pending_comp_ver_str_len);

+    EXPECT_EQ(0, memcmp(inEntry->pending_comp_release_date,

+                        outEntry.pending_comp_release_date,

+                        sizeof(inEntry->pending_comp_release_date)));

+    EXPECT_EQ(outEntry.comp_activation_methods.value, compActivationMethods);

+    EXPECT_EQ(outEntry.capabilities_during_update.value,

+              capabilitiesDuringUpdate);

+

+    EXPECT_EQ(0, memcmp(outActiveCompVerStr.ptr,

+                        entry.data() + activeCompVerStrPos,

+                        outActiveCompVerStr.length));

+    EXPECT_EQ(0, memcmp(outPendingCompVerStr.ptr,

+                        entry.data() + pendingCompVerStrPos,

+                        outPendingCompVerStr.length));

+}