libpldm: Add encode API for RequestUpdate cmd request

RequestUpdate command is the command to initiate a firmware update
for a firmware device. This implementation works with DSP0267_1.1.0,
DSP0267_1.0.1 and DSP0267_1.0.0.

Tested: Unit tests passed

Signed-off-by: gokulsanker <gokul.sanker.v.g@intel.com>
Change-Id: Id74a65aa5975839c89ca433c16cfc67dcf4890c1
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index 23487eb..11007a7 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -612,3 +612,62 @@
 	}

 	return PLDM_SUCCESS;

 }

+

+int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,

+			      uint16_t num_of_comp,

+			      uint8_t max_outstanding_transfer_req,

+			      uint16_t pkg_data_len,

+			      uint8_t comp_image_set_ver_str_type,

+			      uint8_t comp_image_set_ver_str_len,

+			      const struct variable_field *comp_img_set_ver_str,

+			      struct pldm_msg *msg, size_t payload_length)

+{

+	if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||

+	    msg == NULL) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	if (payload_length != sizeof(struct pldm_request_update_req) +

+				  comp_img_set_ver_str->length) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	if ((comp_image_set_ver_str_len == 0) ||

+	    (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||

+	    (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	if (!is_string_type_valid(comp_image_set_ver_str_type)) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	struct pldm_header_info header = {0};

+	header.instance = instance_id;

+	header.msg_type = PLDM_REQUEST;

+	header.pldm_type = PLDM_FWUP;

+	header.command = PLDM_REQUEST_UPDATE;

+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));

+	if (rc) {

+		return rc;

+	}

+

+	struct pldm_request_update_req *request =

+	    (struct pldm_request_update_req *)msg->payload;

+

+	request->max_transfer_size = htole32(max_transfer_size);

+	request->num_of_comp = htole16(num_of_comp);

+	request->max_outstanding_transfer_req = max_outstanding_transfer_req;

+	request->pkg_data_len = htole16(pkg_data_len);

+	request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;

+	request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;

+

+	memcpy(msg->payload + sizeof(struct pldm_request_update_req),

+	       comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);

+

+	return PLDM_SUCCESS;

+}
\ No newline at end of file
diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index f7039db..b21eaff 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -15,12 +15,15 @@
  */

 #define PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN 5

 #define PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES 0

+#define PLDM_FWUP_BASELINE_TRANSFER_SIZE 32

+#define PLDM_FWUP_MIN_OUTSTANDING_REQ 1

 

 /** @brief PLDM Firmware update commands

  */

 enum pldm_firmware_update_commands {

 	PLDM_QUERY_DEVICE_IDENTIFIERS = 0x01,

-	PLDM_GET_FIRMWARE_PARAMETERS = 0x02

+	PLDM_GET_FIRMWARE_PARAMETERS = 0x02,

+	PLDM_REQUEST_UPDATE = 0x10

 };

 

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

@@ -187,6 +190,19 @@
 	bitfield32_t capabilities_during_update;

 } __attribute__((packed));

 

+/** @struct pldm_request_update_req

+ *

+ *  Structure representing fixed part of Request Update request

+ */

+struct pldm_request_update_req {

+	uint32_t max_transfer_size;

+	uint16_t num_of_comp;

+	uint8_t max_outstanding_transfer_req;

+	uint16_t pkg_data_len;

+	uint8_t comp_image_set_ver_str_type;

+	uint8_t comp_image_set_ver_str_len;

+} __attribute__((packed));

+

 /** @brief Decode the PLDM package header information

  *

  *  @param[in] data - pointer to package header information

@@ -358,6 +374,40 @@
     struct variable_field *active_comp_ver_str,

     struct variable_field *pending_comp_ver_str);

 

+/** @brief Create PLDM request message for RequestUpdate

+ *

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

+ *  @param[in] max_transfer_size - Maximum size of the variable payload allowed

+ *                                 to be requested via RequestFirmwareData

+ *                                 command

+ *  @param[in] num_of_comp - Total number of components that will be passed to

+ *                           the FD during the update

+ *  @param[in] max_outstanding_transfer_req - Total number of outstanding

+ * 											  RequestFirmwareData

+ * commands that can be sent by the FD

+ *  @param[in] pkg_data_len - Value of the FirmwareDevicePackageDataLength field

+ *                            present in firmware package header

+ *  @param[in] comp_image_set_ver_str_type - StringType of

+ *                                           ComponentImageSetVersionString

+ *  @param[in] comp_image_set_ver_str_len - The length of the

+ *                                          ComponentImageSetVersionString

+ *  @param[in] comp_img_set_ver_str - Component Image Set version information

+ *  @param[in,out] msg - Message will be written to this

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

+ *

+ *  @return pldm_completion_codes

+ *

+ *  @note Caller is responsible for memory alloc and dealloc of param

+ *        'msg.payload'

+ */

+int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,

+			      uint16_t num_of_comp,

+			      uint8_t max_outstanding_transfer_req,

+			      uint16_t pkg_data_len,

+			      uint8_t comp_image_set_ver_str_type,

+			      uint8_t comp_image_set_ver_str_len,

+			      const struct variable_field *comp_img_set_ver_str,

+			      struct pldm_msg *msg, size_t payload_length);

 #ifdef __cplusplus

 }

 #endif

diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index 444d71c..bbd3dfa 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -1266,3 +1266,130 @@
                         entry.data() + pendingCompVerStrPos,

                         outPendingCompVerStr.length));

 }

+

+TEST(RequestUpdate, goodPathEncodeRequest)

+{

+    constexpr uint8_t instanceId = 1;

+    constexpr uint32_t maxTransferSize = 512;

+    constexpr uint16_t numOfComp = 3;

+    constexpr uint8_t maxOutstandingTransferReq = 2;

+    constexpr uint16_t pkgDataLen = 0x1234;

+    constexpr std::string_view compImgSetVerStr = "0penBmcv1.0";

+    constexpr uint8_t compImgSetVerStrLen =

+        static_cast<uint8_t>(compImgSetVerStr.size());

+    variable_field compImgSetVerStrInfo{};

+    compImgSetVerStrInfo.ptr =

+        reinterpret_cast<const uint8_t*>(compImgSetVerStr.data());

+    compImgSetVerStrInfo.length = compImgSetVerStrLen;

+

+    std::array<uint8_t, hdrSize + sizeof(struct pldm_request_update_req) +

+                            compImgSetVerStrLen>

+        request{};

+    auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());

+

+    auto rc = encode_request_update_req(

+        instanceId, maxTransferSize, numOfComp, maxOutstandingTransferReq,

+        pkgDataLen, PLDM_STR_TYPE_ASCII, compImgSetVerStrLen,

+        &compImgSetVerStrInfo, requestMsg,

+        sizeof(struct pldm_request_update_req) + compImgSetVerStrLen);

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+

+    std::array<uint8_t, hdrSize + sizeof(struct pldm_request_update_req) +

+                            compImgSetVerStrLen>

+        outRequest{0x81, 0x05, 0x10, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00,

+                   0x02, 0x34, 0x12, 0x01, 0x0b, 0x30, 0x70, 0x65, 0x6e,

+                   0x42, 0x6d, 0x63, 0x76, 0x31, 0x2e, 0x30};

+    EXPECT_EQ(request, outRequest);

+}

+

+TEST(RequestUpdate, errorPathEncodeRequest)

+{

+    constexpr uint8_t instanceId = 1;

+    uint32_t maxTransferSize = 512;

+    constexpr uint16_t numOfComp = 3;

+    uint8_t maxOutstandingTransferReq = 2;

+    constexpr uint16_t pkgDataLen = 0x1234;

+    constexpr std::string_view compImgSetVerStr = "0penBmcv1.0";

+    uint8_t compImgSetVerStrLen = static_cast<uint8_t>(compImgSetVerStr.size());

+    variable_field compImgSetVerStrInfo{};

+    compImgSetVerStrInfo.ptr =

+        reinterpret_cast<const uint8_t*>(compImgSetVerStr.data());

+    compImgSetVerStrInfo.length = compImgSetVerStrLen;

+

+    std::array<uint8_t, hdrSize + sizeof(struct pldm_request_update_req) +

+                            compImgSetVerStr.size()>

+        request{};

+    auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());

+

+    auto rc = encode_request_update_req(

+        instanceId, maxTransferSize, numOfComp, maxOutstandingTransferReq,

+        pkgDataLen, PLDM_STR_TYPE_ASCII, compImgSetVerStrLen, nullptr,

+        requestMsg,

+        sizeof(struct pldm_request_update_req) + compImgSetVerStrLen);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    compImgSetVerStrInfo.ptr = nullptr;

+    rc = encode_request_update_req(

+        instanceId, maxTransferSize, numOfComp, maxOutstandingTransferReq,

+        pkgDataLen, PLDM_STR_TYPE_ASCII, compImgSetVerStrLen,

+        &compImgSetVerStrInfo, requestMsg,

+        sizeof(struct pldm_request_update_req) + compImgSetVerStrLen);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+    compImgSetVerStrInfo.ptr =

+        reinterpret_cast<const uint8_t*>(compImgSetVerStr.data());

+

+    rc = encode_request_update_req(

+        instanceId, maxTransferSize, numOfComp, maxOutstandingTransferReq,

+        pkgDataLen, PLDM_STR_TYPE_ASCII, compImgSetVerStrLen,

+        &compImgSetVerStrInfo, nullptr,

+        sizeof(struct pldm_request_update_req) + compImgSetVerStrLen);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = encode_request_update_req(instanceId, maxTransferSize, numOfComp,

+                                   maxOutstandingTransferReq, pkgDataLen,

+                                   PLDM_STR_TYPE_ASCII, compImgSetVerStrLen,

+                                   &compImgSetVerStrInfo, requestMsg, 0);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+

+    compImgSetVerStrLen = 0;

+    rc = encode_request_update_req(

+        instanceId, maxTransferSize, numOfComp, maxOutstandingTransferReq,

+        pkgDataLen, PLDM_STR_TYPE_ASCII, 0, &compImgSetVerStrInfo, nullptr,

+        sizeof(struct pldm_request_update_req) + compImgSetVerStrLen);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+    compImgSetVerStrLen = static_cast<uint8_t>(compImgSetVerStr.size());

+

+    compImgSetVerStrInfo.length = 0xFFFF;

+    rc = encode_request_update_req(

+        instanceId, maxTransferSize, numOfComp, maxOutstandingTransferReq,

+        pkgDataLen, PLDM_STR_TYPE_ASCII, compImgSetVerStrLen,

+        &compImgSetVerStrInfo, nullptr,

+        sizeof(struct pldm_request_update_req) + compImgSetVerStrLen);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+    compImgSetVerStrInfo.length = compImgSetVerStrLen;

+

+    maxTransferSize = PLDM_FWUP_BASELINE_TRANSFER_SIZE - 1;

+    rc = encode_request_update_req(

+        instanceId, maxTransferSize, numOfComp, maxOutstandingTransferReq,

+        pkgDataLen, PLDM_STR_TYPE_ASCII, compImgSetVerStrLen,

+        &compImgSetVerStrInfo, nullptr,

+        sizeof(struct pldm_request_update_req) + compImgSetVerStrLen);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+    maxTransferSize = PLDM_FWUP_BASELINE_TRANSFER_SIZE;

+

+    maxOutstandingTransferReq = PLDM_FWUP_MIN_OUTSTANDING_REQ - 1;

+    rc = encode_request_update_req(

+        instanceId, maxTransferSize, numOfComp, maxOutstandingTransferReq,

+        pkgDataLen, PLDM_STR_TYPE_ASCII, compImgSetVerStrLen,

+        &compImgSetVerStrInfo, nullptr,

+        sizeof(struct pldm_request_update_req) + compImgSetVerStrLen);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+    maxOutstandingTransferReq = PLDM_FWUP_MIN_OUTSTANDING_REQ;

+

+    rc = encode_request_update_req(

+        instanceId, maxTransferSize, numOfComp, maxOutstandingTransferReq,

+        pkgDataLen, PLDM_STR_TYPE_UNKNOWN, compImgSetVerStrLen,

+        &compImgSetVerStrInfo, nullptr,

+        sizeof(struct pldm_request_update_req) + compImgSetVerStrLen);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+}