libpldm: Add APIs to decode descriptor entries

PLDM firmware update package header has record descriptors with type,
length and value. The response of QueryDeviceIdentifiers command has
the same format. This patch provides the decode API to iterate the
descriptor entries and also to parse the vendor defined descriptor
value.

The descriptor identifier table is based of DSP0267_1.1.0. The
implementation is compatible with the earlier verions DSP0267_1.0.0
and DSP0267_1.0.1.

Tested: Unit tests passed

Signed-off-by: Tom Joseph <rushtotom@gmail.com>
Change-Id: I900d190db3248068dbe93090ce646fd63ec957eb
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index 58dd21f..2030a6d 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -2,6 +2,156 @@
 #include <endian.h>

 #include <string.h>

 

+/** @brief Check whether string type value is valid

+ *

+ *  @return true if string type value is valid, false if not

+ */

+static bool is_string_type_valid(uint8_t string_type)

+{

+	switch (string_type) {

+	case PLDM_STR_TYPE_UNKNOWN:

+	case PLDM_STR_TYPE_ASCII:

+	case PLDM_STR_TYPE_UTF_8:

+	case PLDM_STR_TYPE_UTF_16:

+	case PLDM_STR_TYPE_UTF_16LE:

+	case PLDM_STR_TYPE_UTF_16BE:

+		return true;

+	default:

+		return false;

+	}

+}

+

+/** @brief Return the length of the descriptor type described in firmware update

+ *         specification

+ *

+ *  @return length of the descriptor type if descriptor type is valid else

+ *          return 0

+ */

+static uint16_t get_descriptor_type_length(uint16_t descriptor_type)

+{

+	switch (descriptor_type) {

+

+	case PLDM_FWUP_PCI_VENDOR_ID:

+		return PLDM_FWUP_PCI_VENDOR_ID_LENGTH;

+	case PLDM_FWUP_IANA_ENTERPRISE_ID:

+		return PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH;

+	case PLDM_FWUP_UUID:

+		return PLDM_FWUP_UUID_LENGTH;

+	case PLDM_FWUP_PNP_VENDOR_ID:

+		return PLDM_FWUP_PNP_VENDOR_ID_LENGTH;

+	case PLDM_FWUP_ACPI_VENDOR_ID:

+		return PLDM_FWUP_ACPI_VENDOR_ID_LENGTH;

+	case PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID:

+		return PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH;

+	case PLDM_FWUP_SCSI_VENDOR_ID:

+		return PLDM_FWUP_SCSI_VENDOR_ID_LENGTH;

+	case PLDM_FWUP_PCI_DEVICE_ID:

+		return PLDM_FWUP_PCI_DEVICE_ID_LENGTH;

+	case PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID:

+		return PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH;

+	case PLDM_FWUP_PCI_SUBSYSTEM_ID:

+		return PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH;

+	case PLDM_FWUP_PCI_REVISION_ID:

+		return PLDM_FWUP_PCI_REVISION_ID_LENGTH;

+	case PLDM_FWUP_PNP_PRODUCT_IDENTIFIER:

+		return PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH;

+	case PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER:

+		return PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH;

+	case PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING:

+		return PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH;

+	case PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING:

+		return PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH;

+	case PLDM_FWUP_SCSI_PRODUCT_ID:

+		return PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH;

+	case PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE:

+		return PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH;

+	default:

+		return 0;

+	}

+}

+

+int decode_descriptor_type_length_value(const uint8_t *data, size_t length,

+					uint16_t *descriptor_type,

+					struct variable_field *descriptor_data)

+{

+	uint16_t descriptor_length = 0;

+

+	if (data == NULL || descriptor_type == NULL ||

+	    descriptor_data == NULL) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	struct pldm_descriptor_tlv *entry =

+	    (struct pldm_descriptor_tlv *)(data);

+

+	*descriptor_type = le16toh(entry->descriptor_type);

+	descriptor_length = le16toh(entry->descriptor_length);

+	if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {

+		if (descriptor_length !=

+		    get_descriptor_type_length(*descriptor_type)) {

+			return PLDM_ERROR_INVALID_LENGTH;

+		}

+	}

+

+	if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +

+		      descriptor_length)) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	descriptor_data->ptr = entry->descriptor_data;

+	descriptor_data->length = descriptor_length;

+

+	return PLDM_SUCCESS;

+}

+

+int decode_vendor_defined_descriptor_value(

+    const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,

+    struct variable_field *descriptor_title_str,

+    struct variable_field *descriptor_data)

+{

+	if (data == NULL || descriptor_title_str_type == NULL ||

+	    descriptor_title_str == NULL || descriptor_data == NULL) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

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

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	struct pldm_vendor_defined_descriptor_title_data *entry =

+	    (struct pldm_vendor_defined_descriptor_title_data *)(data);

+	if (!is_string_type_valid(

+		entry->vendor_defined_descriptor_title_str_type) ||

+	    (entry->vendor_defined_descriptor_title_str_len == 0)) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	// Assuming atleast 1 byte of VendorDefinedDescriptorData

+	if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +

+		      entry->vendor_defined_descriptor_title_str_len)) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	*descriptor_title_str_type =

+	    entry->vendor_defined_descriptor_title_str_type;

+	descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;

+	descriptor_title_str->length =

+	    entry->vendor_defined_descriptor_title_str_len;

+

+	descriptor_data->ptr =

+	    descriptor_title_str->ptr + descriptor_title_str->length;

+	descriptor_data->length =

+	    length - sizeof(entry->vendor_defined_descriptor_title_str_type) -

+	    sizeof(entry->vendor_defined_descriptor_title_str_len) -

+	    descriptor_title_str->length;

+

+	return PLDM_SUCCESS;

+}

+

 int encode_query_device_identifiers_req(uint8_t instance_id,

 					size_t payload_length,

 					struct pldm_msg *msg)

diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index 1c3e21b..44a2850 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -21,6 +21,82 @@
 	PLDM_GET_FIRMWARE_PARAMETERS = 0x02

 };

 

+/** @brief String type values defined in the PLDM firmware update specification

+ */

+enum pldm_firmware_update_string_type {

+	PLDM_STR_TYPE_UNKNOWN = 0,

+	PLDM_STR_TYPE_ASCII = 1,

+	PLDM_STR_TYPE_UTF_8 = 2,

+	PLDM_STR_TYPE_UTF_16 = 3,

+	PLDM_STR_TYPE_UTF_16LE = 4,

+	PLDM_STR_TYPE_UTF_16BE = 5

+};

+

+/** @brief Descriptor types defined in PLDM firmware update specification

+ */

+enum pldm_firmware_update_descriptor_types {

+	PLDM_FWUP_PCI_VENDOR_ID = 0x0000,

+	PLDM_FWUP_IANA_ENTERPRISE_ID = 0x0001,

+	PLDM_FWUP_UUID = 0x0002,

+	PLDM_FWUP_PNP_VENDOR_ID = 0x0003,

+	PLDM_FWUP_ACPI_VENDOR_ID = 0x0004,

+	PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID = 0x0005,

+	PLDM_FWUP_SCSI_VENDOR_ID = 0x0006,

+	PLDM_FWUP_PCI_DEVICE_ID = 0x0100,

+	PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID = 0x0101,

+	PLDM_FWUP_PCI_SUBSYSTEM_ID = 0x0102,

+	PLDM_FWUP_PCI_REVISION_ID = 0x0103,

+	PLDM_FWUP_PNP_PRODUCT_IDENTIFIER = 0x0104,

+	PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER = 0x0105,

+	PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING = 0x0106,

+	PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING = 0x0107,

+	PLDM_FWUP_SCSI_PRODUCT_ID = 0x0108,

+	PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE = 0x0109,

+	PLDM_FWUP_VENDOR_DEFINED = 0xFFFF

+};

+

+/** @brief Descriptor types length defined in PLDM firmware update specification

+ */

+enum pldm_firmware_update_descriptor_types_length {

+	PLDM_FWUP_PCI_VENDOR_ID_LENGTH = 2,

+	PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH = 4,

+	PLDM_FWUP_UUID_LENGTH = 16,

+	PLDM_FWUP_PNP_VENDOR_ID_LENGTH = 3,

+	PLDM_FWUP_ACPI_VENDOR_ID_LENGTH = 4,

+	PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH = 3,

+	PLDM_FWUP_SCSI_VENDOR_ID_LENGTH = 8,

+	PLDM_FWUP_PCI_DEVICE_ID_LENGTH = 2,

+	PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH = 2,

+	PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH = 2,

+	PLDM_FWUP_PCI_REVISION_ID_LENGTH = 1,

+	PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH = 4,

+	PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH = 4,

+	PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH = 40,

+	PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH = 10,

+	PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH = 16,

+	PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH = 4

+};

+

+/** @struct pldm_descriptor_tlv

+ *

+ *  Structure representing descriptor type, length and value

+ */

+struct pldm_descriptor_tlv {

+	uint16_t descriptor_type;

+	uint16_t descriptor_length;

+	uint8_t descriptor_data[1];

+} __attribute__((packed));

+

+/** @struct pldm_vendor_defined_descriptor_title_data

+ *

+ *  Structure representing vendor defined descriptor title sections

+ */

+struct pldm_vendor_defined_descriptor_title_data {

+	uint8_t vendor_defined_descriptor_title_str_type;

+	uint8_t vendor_defined_descriptor_title_str_len;

+	uint8_t vendor_defined_descriptor_title_str[1];

+} __attribute__((packed));

+

 /** @struct pldm_query_device_identifiers_resp

  *

  *  Structure representing query device identifiers response.

@@ -65,6 +141,37 @@
 	bitfield32_t capabilities_during_update;

 } __attribute__((packed));

 

+/** @brief Decode the record descriptor entries in the firmware update package

+ *         and the Descriptors in the QueryDeviceIDentifiers command

+ *

+ *  @param[in] data - pointer to descriptor entry

+ *  @param[in] length - remaining length of the descriptor data

+ *  @param[out] descriptor_type - pointer to descriptor type

+ *  @param[out] descriptor_data - pointer to descriptor data

+ *

+ *  @return pldm_completion_codes

+ */

+int decode_descriptor_type_length_value(const uint8_t *data, size_t length,

+					uint16_t *descriptor_type,

+					struct variable_field *descriptor_data);

+

+/** @brief Decode the vendor defined descriptor value

+ *

+ *  @param[in] data - pointer to vendor defined descriptor value

+ *  @param[in] length - length of the vendor defined descriptor value

+ *  @param[out] descriptor_title_str_type - pointer to vendor defined descriptor

+ *                                          title string type

+ *  @param[out] descriptor_title_str - pointer to vendor defined descriptor

+ *                                     title string

+ *  @param[out] descriptor_data - pointer to vendor defined descriptor data

+ *

+ *  @return pldm_completion_codes

+ */

+int decode_vendor_defined_descriptor_value(

+    const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,

+    struct variable_field *descriptor_title_str,

+    struct variable_field *descriptor_data);

+

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

  *

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

diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index 3e35cf6..84adc15 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -1,3 +1,5 @@
+#include <cstring>

+

 #include "libpldm/base.h"

 #include "libpldm/firmware_update.h"

 

@@ -5,6 +7,223 @@
 

 constexpr auto hdrSize = sizeof(pldm_msg_hdr);

 

+TEST(DecodeDescriptors, goodPath3Descriptors)

+{

+    // In the descriptor data there are 3 descriptor entries

+    // 1) IANA enterprise ID

+    constexpr std::array<uint8_t, PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH> iana{

+        0x0a, 0x0b, 0x0c, 0xd};

+    // 2) UUID

+    constexpr std::array<uint8_t, PLDM_FWUP_UUID_LENGTH> uuid{

+        0x12, 0x44, 0xd2, 0x64, 0x8d, 0x7d, 0x47, 0x18,

+        0xa0, 0x30, 0xfc, 0x8a, 0x56, 0x58, 0x7d, 0x5b};

+    // 3) Vendor Defined

+    constexpr std::string_view vendorTitle{"OpenBMC"};

+    constexpr size_t vendorDescriptorLen = 2;

+    constexpr std::array<uint8_t, vendorDescriptorLen> vendorDescriptorData{

+        0x01, 0x02};

+

+    constexpr size_t vendorDefinedDescriptorLen =

+        sizeof(pldm_vendor_defined_descriptor_title_data()

+                   .vendor_defined_descriptor_title_str_type) +

+        sizeof(pldm_vendor_defined_descriptor_title_data()

+                   .vendor_defined_descriptor_title_str_len) +

+        vendorTitle.size() + vendorDescriptorData.size();

+

+    constexpr size_t descriptorsLength =

+        3 * (sizeof(pldm_descriptor_tlv().descriptor_type) +

+             sizeof(pldm_descriptor_tlv().descriptor_length)) +

+        iana.size() + uuid.size() + vendorDefinedDescriptorLen;

+

+    constexpr std::array<uint8_t, descriptorsLength> descriptors{

+        0x01, 0x00, 0x04, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x02, 0x00, 0x10,

+        0x00, 0x12, 0x44, 0xd2, 0x64, 0x8d, 0x7d, 0x47, 0x18, 0xa0, 0x30,

+        0xfc, 0x8a, 0x56, 0x58, 0x7d, 0x5b, 0xFF, 0xFF, 0x0B, 0x00, 0x01,

+        0x07, 0x4f, 0x70, 0x65, 0x6e, 0x42, 0x4d, 0x43, 0x01, 0x02};

+

+    size_t descriptorCount = 1;

+    size_t descriptorsRemainingLength = descriptorsLength;

+    int rc = 0;

+

+    while (descriptorsRemainingLength && (descriptorCount <= 3))

+    {

+        uint16_t descriptorType = 0;

+        uint16_t descriptorLen = 0;

+        variable_field descriptorData{};

+

+        rc = decode_descriptor_type_length_value(

+            descriptors.data() + descriptorsLength - descriptorsRemainingLength,

+            descriptorsRemainingLength, &descriptorType, &descriptorData);

+        EXPECT_EQ(rc, PLDM_SUCCESS);

+

+        if (descriptorCount == 1)

+        {

+            EXPECT_EQ(descriptorType, PLDM_FWUP_IANA_ENTERPRISE_ID);

+            EXPECT_EQ(descriptorData.length,

+                      PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH);

+            EXPECT_EQ(true,

+                      std::equal(descriptorData.ptr,

+                                 descriptorData.ptr + descriptorData.length,

+                                 iana.begin(), iana.end()));

+        }

+        else if (descriptorCount == 2)

+        {

+            EXPECT_EQ(descriptorType, PLDM_FWUP_UUID);

+            EXPECT_EQ(descriptorData.length, PLDM_FWUP_UUID_LENGTH);

+            EXPECT_EQ(true,

+                      std::equal(descriptorData.ptr,

+                                 descriptorData.ptr + descriptorData.length,

+                                 uuid.begin(), uuid.end()));

+        }

+        else if (descriptorCount == 3)

+        {

+            EXPECT_EQ(descriptorType, PLDM_FWUP_VENDOR_DEFINED);

+            EXPECT_EQ(descriptorData.length, vendorDefinedDescriptorLen);

+

+            uint8_t descriptorTitleStrType = 0;

+            variable_field descriptorTitleStr{};

+            variable_field vendorDefinedDescriptorData{};

+

+            rc = decode_vendor_defined_descriptor_value(

+                descriptorData.ptr, descriptorData.length,

+                &descriptorTitleStrType, &descriptorTitleStr,

+                &vendorDefinedDescriptorData);

+            EXPECT_EQ(rc, PLDM_SUCCESS);

+

+            EXPECT_EQ(descriptorTitleStrType, PLDM_STR_TYPE_ASCII);

+            EXPECT_EQ(descriptorTitleStr.length, vendorTitle.size());

+            std::string vendorTitleStr(

+                reinterpret_cast<const char*>(descriptorTitleStr.ptr),

+                descriptorTitleStr.length);

+            EXPECT_EQ(vendorTitleStr, vendorTitle);

+

+            EXPECT_EQ(vendorDefinedDescriptorData.length,

+                      vendorDescriptorData.size());

+            EXPECT_EQ(true, std::equal(vendorDefinedDescriptorData.ptr,

+                                       vendorDefinedDescriptorData.ptr +

+                                           vendorDefinedDescriptorData.length,

+                                       vendorDescriptorData.begin(),

+                                       vendorDescriptorData.end()));

+        }

+

+        descriptorsRemainingLength -= sizeof(descriptorType) +

+                                      sizeof(descriptorLen) +

+                                      descriptorData.length;

+        descriptorCount++;

+    }

+}

+

+TEST(DecodeDescriptors, errorPathDecodeDescriptorTLV)

+{

+    int rc = 0;

+    // IANA Enterprise ID descriptor length incorrect

+    constexpr std::array<uint8_t, 7> invalidIANADescriptor1{

+        0x01, 0x00, 0x03, 0x00, 0x0a, 0x0b, 0x0c};

+    uint16_t descriptorType = 0;

+    variable_field descriptorData{};

+

+    rc = decode_descriptor_type_length_value(nullptr,

+                                             invalidIANADescriptor1.size(),

+                                             &descriptorType, &descriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_descriptor_type_length_value(invalidIANADescriptor1.data(),

+                                             invalidIANADescriptor1.size(),

+                                             nullptr, &descriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_descriptor_type_length_value(invalidIANADescriptor1.data(),

+                                             invalidIANADescriptor1.size(),

+                                             &descriptorType, nullptr);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_descriptor_type_length_value(

+        invalidIANADescriptor1.data(), PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN - 1,

+        &descriptorType, &descriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+

+    rc = decode_descriptor_type_length_value(invalidIANADescriptor1.data(),

+                                             invalidIANADescriptor1.size(),

+                                             &descriptorType, &descriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+

+    // IANA Enterprise ID descriptor data less than length

+    std::array<uint8_t, 7> invalidIANADescriptor2{0x01, 0x00, 0x04, 0x00,

+                                                  0x0a, 0x0b, 0x0c};

+    rc = decode_descriptor_type_length_value(invalidIANADescriptor2.data(),

+                                             invalidIANADescriptor2.size(),

+                                             &descriptorType, &descriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+}

+

+TEST(DecodeDescriptors, errorPathVendorDefinedDescriptor)

+{

+    int rc = 0;

+    // VendorDefinedDescriptorTitleStringType is invalid

+    constexpr std::array<uint8_t, 9> invalidVendorDescriptor1{

+        0x06, 0x07, 0x4f, 0x70, 0x65, 0x6e, 0x42, 0x4d, 0x43};

+    uint8_t descriptorStringType = 0;

+    variable_field descriptorTitleStr{};

+    variable_field vendorDefinedDescriptorData{};

+

+    rc = decode_vendor_defined_descriptor_value(

+        nullptr, invalidVendorDescriptor1.size(), &descriptorStringType,

+        &descriptorTitleStr, &vendorDefinedDescriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_vendor_defined_descriptor_value(

+        invalidVendorDescriptor1.data(), invalidVendorDescriptor1.size(),

+        &descriptorStringType, &descriptorTitleStr,

+        &vendorDefinedDescriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_vendor_defined_descriptor_value(

+        invalidVendorDescriptor1.data(), invalidVendorDescriptor1.size(),

+        nullptr, &descriptorTitleStr, &vendorDefinedDescriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_vendor_defined_descriptor_value(

+        invalidVendorDescriptor1.data(), invalidVendorDescriptor1.size(),

+        &descriptorStringType, nullptr, &vendorDefinedDescriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_vendor_defined_descriptor_value(

+        invalidVendorDescriptor1.data(), invalidVendorDescriptor1.size(),

+        &descriptorStringType, &descriptorTitleStr, nullptr);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_vendor_defined_descriptor_value(

+        invalidVendorDescriptor1.data(),

+        sizeof(pldm_vendor_defined_descriptor_title_data) - 1,

+        &descriptorStringType, &descriptorTitleStr,

+        &vendorDefinedDescriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+

+    rc = decode_vendor_defined_descriptor_value(

+        invalidVendorDescriptor1.data(), invalidVendorDescriptor1.size(),

+        &descriptorStringType, &descriptorTitleStr,

+        &vendorDefinedDescriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    // VendorDefinedDescriptorTitleStringLength is 0

+    std::array<uint8_t, 9> invalidVendorDescriptor2{

+        0x01, 0x00, 0x4f, 0x70, 0x65, 0x6e, 0x42, 0x4d, 0x43};

+    rc = decode_vendor_defined_descriptor_value(

+        invalidVendorDescriptor2.data(), invalidVendorDescriptor2.size(),

+        &descriptorStringType, &descriptorTitleStr,

+        &vendorDefinedDescriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    // VendorDefinedDescriptorData not present in the data

+    std::array<uint8_t, 9> invalidVendorDescriptor3{

+        0x01, 0x07, 0x4f, 0x70, 0x65, 0x6e, 0x42, 0x4d, 0x43};

+    rc = decode_vendor_defined_descriptor_value(

+        invalidVendorDescriptor3.data(), invalidVendorDescriptor3.size(),

+        &descriptorStringType, &descriptorTitleStr,

+        &vendorDefinedDescriptorData);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+}

+

 TEST(QueryDeviceIdentifiers, goodPathEncodeRequest)

 {

     std::array<uint8_t, sizeof(pldm_msg_hdr)> requestMsg{};

diff --git a/libpldm/utils.h b/libpldm/utils.h
index 1e15e18..3011a5a 100644
--- a/libpldm/utils.h
+++ b/libpldm/utils.h
@@ -12,7 +12,7 @@
 
 /** @struct variable_field
  *
- *  Structure representing variable filed in the pldm message
+ *  Structure representing variable field in the pldm message
  */
 struct variable_field {
 	const uint8_t *ptr;