libpldm: Add API to decode package header info
This patch provides API to decode the firmware update package header
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: I208a219cd4b9c9b9869eb3e286259b2f51206487
diff --git a/libpldm/base.h b/libpldm/base.h
index 451137d..8644a5a 100644
--- a/libpldm/base.h
+++ b/libpldm/base.h
@@ -91,6 +91,8 @@
#define PLDM_VERSION_0 0
#define PLDM_CURRENT_VERSION PLDM_VERSION_0
+#define PLDM_TIMESTAMP104_SIZE 13
+
/** @struct pldm_msg_hdr
*
* Structure representing PLDM message header fields
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index acb95fd..d31ec4a 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -71,6 +71,60 @@
}
}
+int decode_pldm_package_header_info(
+ const uint8_t *data, size_t length,
+ struct pldm_package_header_information *package_header_info,
+ struct variable_field *package_version_str)
+{
+ if (data == NULL || package_header_info == NULL ||
+ package_version_str == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (length < sizeof(struct pldm_package_header_information)) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_package_header_information *data_header =
+ (struct pldm_package_header_information *)(data);
+
+ if (!is_string_type_valid(data_header->package_version_string_type) ||
+ (data_header->package_version_string_length == 0)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (length < sizeof(struct pldm_package_header_information) +
+ data_header->package_version_string_length) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ if ((data_header->component_bitmap_bit_length %
+ PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ memcpy(package_header_info->uuid, data_header->uuid,
+ sizeof(data_header->uuid));
+ package_header_info->package_header_format_version =
+ data_header->package_header_format_version;
+ package_header_info->package_header_size =
+ le16toh(data_header->package_header_size);
+ memcpy(package_header_info->timestamp104, data_header->timestamp104,
+ sizeof(data_header->timestamp104));
+ package_header_info->component_bitmap_bit_length =
+ le16toh(data_header->component_bitmap_bit_length);
+ package_header_info->package_version_string_type =
+ data_header->package_version_string_type;
+ package_header_info->package_version_string_length =
+ data_header->package_version_string_length;
+ package_version_str->ptr =
+ data + sizeof(struct pldm_package_header_information);
+ package_version_str->length =
+ package_header_info->package_version_string_length;
+
+ return PLDM_SUCCESS;
+}
+
int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
uint16_t *descriptor_type,
struct variable_field *descriptor_data)
diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index 97a13fb..a14bfb5 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -7,6 +7,7 @@
#include "base.h"
#include "utils.h"
+#define PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE 8
#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
@@ -77,6 +78,20 @@
PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH = 4
};
+/** @struct pldm_package_header_information
+ *
+ * Structure representing fixed part of package header information
+ */
+struct pldm_package_header_information {
+ uint8_t uuid[PLDM_FWUP_UUID_LENGTH];
+ uint8_t package_header_format_version;
+ uint16_t package_header_size;
+ uint8_t timestamp104[PLDM_TIMESTAMP104_SIZE];
+ uint16_t component_bitmap_bit_length;
+ uint8_t package_version_string_type;
+ uint8_t package_version_string_length;
+} __attribute__((packed));
+
/** @struct pldm_descriptor_tlv
*
* Structure representing descriptor type, length and value
@@ -141,6 +156,21 @@
bitfield32_t capabilities_during_update;
} __attribute__((packed));
+/** @brief Decode the PLDM package header information
+ *
+ * @param[in] data - pointer to package header information
+ * @param[in] length - available length in the firmware update package
+ * @param[out] package_header_info - pointer to fixed part of PLDM package
+ * header information
+ * @param[out] package_version_str - pointer to package version string
+ *
+ * @return pldm_completion_codes
+ */
+int decode_pldm_package_header_info(
+ const uint8_t *data, size_t length,
+ struct pldm_package_header_information *package_header_info,
+ struct variable_field *package_version_str);
+
/** @brief Decode the record descriptor entries in the firmware update package
* and the Descriptors in the QueryDeviceIDentifiers command
*
diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index f87fd5b..8f8775c 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -8,6 +8,142 @@
constexpr auto hdrSize = sizeof(pldm_msg_hdr);
+TEST(DecodePackageHeaderInfo, goodPath)
+{
+ // Package header identifier for Version 1.0.x
+ constexpr std::array<uint8_t, PLDM_FWUP_UUID_LENGTH> uuid{
+ 0xf0, 0x18, 0x87, 0x8c, 0xcb, 0x7d, 0x49, 0x43,
+ 0x98, 0x00, 0xa0, 0x2F, 0x05, 0x9a, 0xca, 0x02};
+ // Package header version for DSP0267 version 1.0.x
+ constexpr uint8_t pkgHeaderFormatRevision = 0x01;
+ // Random PackageHeaderSize
+ constexpr uint16_t pkgHeaderSize = 303;
+ // PackageReleaseDateTime - "25/12/2021 00:00:00"
+ std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> timestamp104{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x19, 0x0c, 0xe5, 0x07, 0x00};
+ constexpr uint16_t componentBitmapBitLength = 8;
+ // PackageVersionString
+ constexpr std::string_view packageVersionStr{"OpenBMCv1.0"};
+ constexpr size_t packagerHeaderSize =
+ sizeof(pldm_package_header_information) + packageVersionStr.size();
+
+ constexpr std::array<uint8_t, packagerHeaderSize> packagerHeaderInfo{
+ 0xf0, 0x18, 0x87, 0x8c, 0xcb, 0x7d, 0x49, 0x43, 0x98, 0x00, 0xa0, 0x2F,
+ 0x05, 0x9a, 0xca, 0x02, 0x01, 0x2f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x19, 0x0c, 0xe5, 0x07, 0x00, 0x08, 0x00, 0x01, 0x0b,
+ 0x4f, 0x70, 0x65, 0x6e, 0x42, 0x4d, 0x43, 0x76, 0x31, 0x2e, 0x30};
+ pldm_package_header_information pkgHeader{};
+ variable_field packageVersion{};
+
+ auto rc = decode_pldm_package_header_info(packagerHeaderInfo.data(),
+ packagerHeaderInfo.size(),
+ &pkgHeader, &packageVersion);
+
+ EXPECT_EQ(rc, PLDM_SUCCESS);
+ EXPECT_EQ(true,
+ std::equal(pkgHeader.uuid, pkgHeader.uuid + PLDM_FWUP_UUID_LENGTH,
+ uuid.begin(), uuid.end()));
+ EXPECT_EQ(pkgHeader.package_header_format_version, pkgHeaderFormatRevision);
+ EXPECT_EQ(pkgHeader.package_header_size, pkgHeaderSize);
+ EXPECT_EQ(true, std::equal(pkgHeader.timestamp104,
+ pkgHeader.timestamp104 + PLDM_TIMESTAMP104_SIZE,
+ timestamp104.begin(), timestamp104.end()));
+ EXPECT_EQ(pkgHeader.component_bitmap_bit_length, componentBitmapBitLength);
+ EXPECT_EQ(pkgHeader.package_version_string_type, PLDM_STR_TYPE_ASCII);
+ EXPECT_EQ(pkgHeader.package_version_string_length,
+ packageVersionStr.size());
+ std::string packageVersionString(
+ reinterpret_cast<const char*>(packageVersion.ptr),
+ packageVersion.length);
+ EXPECT_EQ(packageVersionString, packageVersionStr);
+}
+
+TEST(DecodePackageHeaderInfo, errorPaths)
+{
+ int rc = 0;
+ constexpr std::string_view packageVersionStr{"OpenBMCv1.0"};
+ constexpr size_t packagerHeaderSize =
+ sizeof(pldm_package_header_information) + packageVersionStr.size();
+
+ // Invalid Package Version String Type - 0x06
+ constexpr std::array<uint8_t, packagerHeaderSize>
+ invalidPackagerHeaderInfo1{
+ 0xf0, 0x18, 0x87, 0x8c, 0xcb, 0x7d, 0x49, 0x43, 0x98, 0x00,
+ 0xa0, 0x2F, 0x05, 0x9a, 0xca, 0x02, 0x02, 0x2f, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x0c, 0xe5,
+ 0x07, 0x00, 0x08, 0x00, 0x06, 0x0b, 0x4f, 0x70, 0x65, 0x6e,
+ 0x42, 0x4d, 0x43, 0x76, 0x31, 0x2e, 0x30};
+
+ pldm_package_header_information packageHeader{};
+ variable_field packageVersion{};
+
+ rc = decode_pldm_package_header_info(nullptr,
+ invalidPackagerHeaderInfo1.size(),
+ &packageHeader, &packageVersion);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ rc = decode_pldm_package_header_info(invalidPackagerHeaderInfo1.data(),
+ invalidPackagerHeaderInfo1.size(),
+ nullptr, &packageVersion);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ rc = decode_pldm_package_header_info(invalidPackagerHeaderInfo1.data(),
+ invalidPackagerHeaderInfo1.size(),
+ &packageHeader, nullptr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ rc = decode_pldm_package_header_info(
+ invalidPackagerHeaderInfo1.data(),
+ sizeof(pldm_package_header_information) - 1, &packageHeader,
+ &packageVersion);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+ rc = decode_pldm_package_header_info(invalidPackagerHeaderInfo1.data(),
+ invalidPackagerHeaderInfo1.size(),
+ &packageHeader, &packageVersion);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ // Invalid Package Version String Length - 0x00
+ constexpr std::array<uint8_t, packagerHeaderSize>
+ invalidPackagerHeaderInfo2{
+ 0xf0, 0x18, 0x87, 0x8c, 0xcb, 0x7d, 0x49, 0x43, 0x98, 0x00,
+ 0xa0, 0x2F, 0x05, 0x9a, 0xca, 0x02, 0x02, 0x2f, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x0c, 0xe5,
+ 0x07, 0x00, 0x08, 0x00, 0x01, 0x00, 0x4f, 0x70, 0x65, 0x6e,
+ 0x42, 0x4d, 0x43, 0x76, 0x31, 0x2e, 0x30};
+ rc = decode_pldm_package_header_info(invalidPackagerHeaderInfo2.data(),
+ invalidPackagerHeaderInfo2.size(),
+ &packageHeader, &packageVersion);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ // Package version string length less than in the header information
+ constexpr std::array<uint8_t, packagerHeaderSize - 1>
+ invalidPackagerHeaderInfo3{
+ 0xf0, 0x18, 0x87, 0x8c, 0xcb, 0x7d, 0x49, 0x43, 0x98, 0x00,
+ 0xa0, 0x2F, 0x05, 0x9a, 0xca, 0x02, 0x02, 0x2f, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x0c, 0xe5,
+ 0x07, 0x00, 0x08, 0x00, 0x01, 0x0b, 0x4f, 0x70, 0x65, 0x6e,
+ 0x42, 0x4d, 0x43, 0x76, 0x31, 0x2e};
+ rc = decode_pldm_package_header_info(invalidPackagerHeaderInfo3.data(),
+ invalidPackagerHeaderInfo3.size(),
+ &packageHeader, &packageVersion);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+ // ComponentBitmapBitLength not a multiple of 8
+ constexpr std::array<uint8_t, packagerHeaderSize>
+ invalidPackagerHeaderInfo4{
+ 0xf0, 0x18, 0x87, 0x8c, 0xcb, 0x7d, 0x49, 0x43, 0x98, 0x00,
+ 0xa0, 0x2F, 0x05, 0x9a, 0xca, 0x02, 0x02, 0x2f, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x0c, 0xe5,
+ 0x07, 0x00, 0x09, 0x00, 0x01, 0x0b, 0x4f, 0x70, 0x65, 0x6e,
+ 0x42, 0x4d, 0x43, 0x76, 0x31, 0x2e, 0x30};
+ rc = decode_pldm_package_header_info(invalidPackagerHeaderInfo4.data(),
+ invalidPackagerHeaderInfo4.size(),
+ &packageHeader, &packageVersion);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
TEST(DecodeDescriptors, goodPath3Descriptors)
{
// In the descriptor data there are 3 descriptor entries