libpldm: Add API to decode component image info
This patch provides API to decode the individual component image
information and also do basic validation.
The API works with DSP0267_1.1.0, DSP0267_1.0.1 and DSP0267_1.0.0.
Tested: Unit tests passed
Signed-off-by: Tom Joseph <rushtotom@gmail.com>
Change-Id: Ife0ab62cf0890d0144b1fda1c4ba5e9262be4714
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index 379549d..23487eb 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -297,6 +297,70 @@
return PLDM_SUCCESS;
}
+int decode_pldm_comp_image_info(
+ const uint8_t *data, size_t length,
+ struct pldm_component_image_information *pldm_comp_image_info,
+ struct variable_field *comp_version_str)
+{
+ if (data == NULL || pldm_comp_image_info == NULL ||
+ comp_version_str == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (length < sizeof(struct pldm_component_image_information)) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_component_image_information *data_header =
+ (struct pldm_component_image_information *)(data);
+
+ if (!is_string_type_valid(data_header->comp_version_string_type) ||
+ (data_header->comp_version_string_length == 0)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (length < sizeof(struct pldm_component_image_information) +
+ data_header->comp_version_string_length) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ pldm_comp_image_info->comp_classification =
+ le16toh(data_header->comp_classification);
+ pldm_comp_image_info->comp_identifier =
+ le16toh(data_header->comp_identifier);
+ pldm_comp_image_info->comp_comparison_stamp =
+ le32toh(data_header->comp_comparison_stamp);
+ pldm_comp_image_info->comp_options.value =
+ le16toh(data_header->comp_options.value);
+ pldm_comp_image_info->requested_comp_activation_method.value =
+ le16toh(data_header->requested_comp_activation_method.value);
+ pldm_comp_image_info->comp_location_offset =
+ le32toh(data_header->comp_location_offset);
+ pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
+ pldm_comp_image_info->comp_version_string_type =
+ data_header->comp_version_string_type;
+ pldm_comp_image_info->comp_version_string_length =
+ data_header->comp_version_string_length;
+
+ if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
+ pldm_comp_image_info->comp_comparison_stamp !=
+ PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (pldm_comp_image_info->comp_location_offset == 0 ||
+ pldm_comp_image_info->comp_size == 0) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ comp_version_str->ptr =
+ data + sizeof(struct pldm_component_image_information);
+ comp_version_str->length =
+ pldm_comp_image_info->comp_version_string_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 f84b8c7..f7039db 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -8,6 +8,7 @@
#include "utils.h"
#define PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE 8
+#define PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP 0xFFFFFFFF
#define PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES 0
/** @brief Minimum length of device descriptor, 2 bytes for descriptor type,
* 2 bytes for descriptor length and atleast 1 byte of descriptor data
@@ -125,6 +126,23 @@
uint8_t vendor_defined_descriptor_title_str[1];
} __attribute__((packed));
+/** @struct pldm_component_image_information
+ *
+ * Structure representing fixed part of individual component information in
+ * PLDM firmware update package
+ */
+struct pldm_component_image_information {
+ uint16_t comp_classification;
+ uint16_t comp_identifier;
+ uint32_t comp_comparison_stamp;
+ bitfield16_t comp_options;
+ bitfield16_t requested_comp_activation_method;
+ uint32_t comp_location_offset;
+ uint32_t comp_size;
+ uint8_t comp_version_string_type;
+ uint8_t comp_version_string_length;
+} __attribute__((packed));
+
/** @struct pldm_query_device_identifiers_resp
*
* Structure representing query device identifiers response.
@@ -239,6 +257,21 @@
struct variable_field *descriptor_title_str,
struct variable_field *descriptor_data);
+/** @brief Decode individual component image information
+ *
+ * @param[in] data - pointer to component image information
+ * @param[in] length - available length in the firmware update package
+ * @param[out] pldm_comp_image_info - pointer to fixed part of component image
+ * information
+ * @param[out] comp_version_str - pointer to component version string
+ *
+ * @return pldm_completion_codes
+ */
+int decode_pldm_comp_image_info(
+ const uint8_t *data, size_t length,
+ struct pldm_component_image_information *pldm_comp_image_info,
+ struct variable_field *comp_version_str);
+
/** @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 cb5d22e..444d71c 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -635,6 +635,145 @@
EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
}
+TEST(DecodeComponentImageInfo, goodPath)
+{
+ // Firmware
+ constexpr uint16_t compClassification = 16;
+ constexpr uint16_t compIdentifier = 300;
+ constexpr uint32_t compComparisonStamp = 0xFFFFFFFF;
+ // Force update
+ constexpr std::bitset<16> compOptions{1};
+ // System reboot[Bit position 3] & Medium-specific reset[Bit position 2]
+ constexpr std::bitset<16> reqCompActivationMethod{0x0c};
+ // Random ComponentLocationOffset
+ constexpr uint32_t compLocOffset = 357;
+ // Random ComponentSize
+ constexpr uint32_t compSize = 27;
+ // ComponentVersionString
+ constexpr std::string_view compVersionStr{"VersionString1"};
+ constexpr size_t compImageInfoSize =
+ sizeof(pldm_component_image_information) + compVersionStr.size();
+
+ constexpr std::array<uint8_t, compImageInfoSize> compImageInfo{
+ 0x10, 0x00, 0x2c, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x0c, 0x00,
+ 0x65, 0x01, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x56, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31};
+ pldm_component_image_information outCompImageInfo{};
+ variable_field outCompVersionStr{};
+
+ auto rc =
+ decode_pldm_comp_image_info(compImageInfo.data(), compImageInfo.size(),
+ &outCompImageInfo, &outCompVersionStr);
+
+ EXPECT_EQ(rc, PLDM_SUCCESS);
+ EXPECT_EQ(outCompImageInfo.comp_classification, compClassification);
+ EXPECT_EQ(outCompImageInfo.comp_identifier, compIdentifier);
+ EXPECT_EQ(outCompImageInfo.comp_comparison_stamp, compComparisonStamp);
+ EXPECT_EQ(outCompImageInfo.comp_options.value, compOptions);
+ EXPECT_EQ(outCompImageInfo.requested_comp_activation_method.value,
+ reqCompActivationMethod);
+ EXPECT_EQ(outCompImageInfo.comp_location_offset, compLocOffset);
+ EXPECT_EQ(outCompImageInfo.comp_size, compSize);
+ EXPECT_EQ(outCompImageInfo.comp_version_string_type, PLDM_STR_TYPE_ASCII);
+ EXPECT_EQ(outCompImageInfo.comp_version_string_length,
+ compVersionStr.size());
+
+ EXPECT_EQ(outCompVersionStr.length,
+ outCompImageInfo.comp_version_string_length);
+ std::string componentVersionString(
+ reinterpret_cast<const char*>(outCompVersionStr.ptr),
+ outCompVersionStr.length);
+ EXPECT_EQ(componentVersionString, compVersionStr);
+}
+
+TEST(DecodeComponentImageInfo, errorPaths)
+{
+ int rc = 0;
+ // ComponentVersionString
+ constexpr std::string_view compVersionStr{"VersionString1"};
+ constexpr size_t compImageInfoSize =
+ sizeof(pldm_component_image_information) + compVersionStr.size();
+ // Invalid ComponentVersionStringType - 0x06
+ constexpr std::array<uint8_t, compImageInfoSize> invalidCompImageInfo1{
+ 0x10, 0x00, 0x2c, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x0c, 0x00,
+ 0x65, 0x01, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x06, 0x0e, 0x56, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31};
+ pldm_component_image_information outCompImageInfo{};
+ variable_field outCompVersionStr{};
+
+ rc = decode_pldm_comp_image_info(nullptr, invalidCompImageInfo1.size(),
+ &outCompImageInfo, &outCompVersionStr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ rc = decode_pldm_comp_image_info(invalidCompImageInfo1.data(),
+ invalidCompImageInfo1.size(), nullptr,
+ &outCompVersionStr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ rc = decode_pldm_comp_image_info(invalidCompImageInfo1.data(),
+ invalidCompImageInfo1.size(),
+ &outCompImageInfo, nullptr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ rc = decode_pldm_comp_image_info(invalidCompImageInfo1.data(),
+ sizeof(pldm_component_image_information) -
+ 1,
+ &outCompImageInfo, &outCompVersionStr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+ rc = decode_pldm_comp_image_info(invalidCompImageInfo1.data(),
+ invalidCompImageInfo1.size(),
+ &outCompImageInfo, &outCompVersionStr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ // Invalid ComponentVersionStringLength - 0x00
+ constexpr std::array<uint8_t, compImageInfoSize> invalidCompImageInfo2{
+ 0x10, 0x00, 0x2c, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x0c, 0x00,
+ 0x65, 0x01, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x56, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31};
+ rc = decode_pldm_comp_image_info(invalidCompImageInfo2.data(),
+ invalidCompImageInfo2.size(),
+ &outCompImageInfo, &outCompVersionStr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ // Use Component Comparison Stamp is not set, but ComponentComparisonStamp
+ // is not 0xFFFFFFFF
+ constexpr std::array<uint8_t, compImageInfoSize> invalidCompImageInfo3{
+ 0x10, 0x00, 0x2c, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00,
+ 0x65, 0x01, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x56, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31};
+
+ rc = decode_pldm_comp_image_info(invalidCompImageInfo3.data(),
+ invalidCompImageInfo3.size() - 1,
+ &outCompImageInfo, &outCompVersionStr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+ rc = decode_pldm_comp_image_info(invalidCompImageInfo3.data(),
+ invalidCompImageInfo3.size(),
+ &outCompImageInfo, &outCompVersionStr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ // Invalid ComponentLocationOffset - 0
+ constexpr std::array<uint8_t, compImageInfoSize> invalidCompImageInfo4{
+ 0x10, 0x00, 0x2c, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x56, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31};
+ rc = decode_pldm_comp_image_info(invalidCompImageInfo4.data(),
+ invalidCompImageInfo4.size(),
+ &outCompImageInfo, &outCompVersionStr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ // Invalid ComponentSize - 0
+ constexpr std::array<uint8_t, compImageInfoSize> invalidCompImageInfo5{
+ 0x10, 0x00, 0x2c, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x0c, 0x00,
+ 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x56, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31};
+ rc = decode_pldm_comp_image_info(invalidCompImageInfo5.data(),
+ invalidCompImageInfo5.size(),
+ &outCompImageInfo, &outCompVersionStr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
TEST(QueryDeviceIdentifiers, goodPathEncodeRequest)
{
std::array<uint8_t, sizeof(pldm_msg_hdr)> requestMsg{};