dsp: firmware update: Add encode/decode APIs for DD update

encode/decode command RequestDownstreamDeviceUpdate, based on
DSP0267 1.3.0.

Change-Id: I904a7229fe4a440904e6cf95c8e46b5956c3476c
Signed-off-by: Sora Su <baxiche@gmail.com>
diff --git a/tests/dsp/firmware_update.cpp b/tests/dsp/firmware_update.cpp
index 01ea091..fa2d60c 100644
--- a/tests/dsp/firmware_update.cpp
+++ b/tests/dsp/firmware_update.cpp
@@ -2957,6 +2957,180 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
 }
 
+#ifdef LIBPLDM_API_TESTING
+TEST(RequestDownstreamDeviceUpdate, goodPathEncodeRequest)
+{
+    constexpr uint8_t instanceId = 1;
+
+    std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES>
+        request{};
+
+    auto requestMsg = new (request.data()) pldm_msg;
+
+    constexpr struct pldm_request_downstream_device_update_req req_data = {
+        .maximum_downstream_device_transfer_size = 512,
+        .maximum_outstanding_transfer_requests = 2,
+        .downstream_device_package_data_length = 0x1234,
+    };
+    size_t enc_payload_len = PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES;
+
+    auto rc = encode_request_downstream_device_update_req(
+        instanceId, &req_data, requestMsg, &enc_payload_len);
+
+    EXPECT_EQ(rc, 0);
+
+    std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES>
+        outRequest{0x81, 0x05, 0x20, 0x00, 0x02, 0x00, 0x00, 0x02, 0x34, 0x12};
+    EXPECT_EQ(request, outRequest);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(RequestDownstreamDeviceUpdate, errorPathEncodeRequest)
+{
+    constexpr uint8_t instanceId = 1;
+    size_t enc_payload_len = PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES;
+
+    std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES>
+        request{};
+
+    struct pldm_request_downstream_device_update_req req_data = {
+        .maximum_downstream_device_transfer_size = 512,
+        .maximum_outstanding_transfer_requests = 2,
+        .downstream_device_package_data_length = 0x1234,
+    };
+
+    auto requestMsg = new (request.data()) pldm_msg;
+
+    auto rc = encode_request_downstream_device_update_req(
+        instanceId, nullptr, requestMsg, &enc_payload_len);
+    EXPECT_EQ(rc, -EINVAL);
+    rc = encode_request_downstream_device_update_req(
+        instanceId, &req_data, requestMsg, &enc_payload_len);
+    EXPECT_EQ(rc, 0);
+
+    rc = encode_request_downstream_device_update_req(instanceId, &req_data,
+                                                     nullptr, &enc_payload_len);
+    EXPECT_EQ(rc, -EINVAL);
+    rc = encode_request_downstream_device_update_req(
+        instanceId, &req_data, requestMsg, &enc_payload_len);
+    EXPECT_EQ(rc, 0);
+
+    rc = encode_request_downstream_device_update_req(instanceId, &req_data,
+                                                     requestMsg, nullptr);
+    EXPECT_EQ(rc, -EINVAL);
+    rc = encode_request_downstream_device_update_req(
+        instanceId, &req_data, requestMsg, &enc_payload_len);
+    EXPECT_EQ(rc, 0);
+
+    enc_payload_len =
+        static_cast<size_t>(PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES) - 1;
+    rc = encode_request_downstream_device_update_req(
+        instanceId, &req_data, requestMsg, &enc_payload_len);
+    EXPECT_EQ(rc, -EOVERFLOW);
+    enc_payload_len =
+        static_cast<size_t>(PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES);
+    rc = encode_request_downstream_device_update_req(
+        instanceId, &req_data, requestMsg, &enc_payload_len);
+    EXPECT_EQ(rc, 0);
+
+    req_data.maximum_downstream_device_transfer_size = 31;
+    rc = encode_request_downstream_device_update_req(
+        instanceId, &req_data, requestMsg, &enc_payload_len);
+    EXPECT_EQ(rc, -EINVAL);
+    req_data.maximum_downstream_device_transfer_size =
+        PLDM_FWUP_BASELINE_TRANSFER_SIZE;
+
+    req_data.maximum_outstanding_transfer_requests = 0;
+    rc = encode_request_downstream_device_update_req(
+        instanceId, &req_data, requestMsg, &enc_payload_len);
+    EXPECT_EQ(rc, -EINVAL);
+    req_data.maximum_outstanding_transfer_requests = 2;
+    rc = encode_request_downstream_device_update_req(
+        instanceId, &req_data, requestMsg, &enc_payload_len);
+    EXPECT_EQ(rc, 0);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(RequestDownstreamDeviceUpdate, goodPathDecodeResponse)
+{
+    /* Test a success completion code */
+    constexpr uint16_t ddMetaDataLen = 1024;
+    constexpr uint8_t ddWillSendPkgData = 1;
+    constexpr uint16_t getPkgDataMaxTransferSize = 512;
+    std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES>
+        requestUpdateResponse1{0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x04, 0x01, 0x00, 0x02};
+
+    auto responseMsg1 = new (requestUpdateResponse1.data()) pldm_msg;
+
+    struct pldm_request_downstream_device_update_resp resp_data1 = {
+        .completion_code = 0,
+        .downstream_device_meta_data_length = 0,
+        .downstream_device_will_send_get_package_data = 0,
+        .get_package_data_maximum_transfer_size = 0};
+
+    auto rc = decode_request_downstream_device_update_resp(
+        responseMsg1, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES,
+        &resp_data1);
+    EXPECT_EQ(rc, 0);
+    EXPECT_EQ(resp_data1.completion_code, PLDM_SUCCESS);
+    EXPECT_EQ(resp_data1.downstream_device_meta_data_length, ddMetaDataLen);
+    EXPECT_EQ(resp_data1.downstream_device_will_send_get_package_data,
+              ddWillSendPkgData);
+    EXPECT_EQ(resp_data1.get_package_data_maximum_transfer_size,
+              getPkgDataMaxTransferSize);
+
+    /* Test a failure completion code */
+    std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES>
+        requestUpdateResponse2{0x00, 0x00, 0x00, 0x81};
+
+    auto responseMsg2 = new (requestUpdateResponse2.data()) pldm_msg;
+
+    struct pldm_request_downstream_device_update_resp resp_data2 = {
+        .completion_code = 0,
+        .downstream_device_meta_data_length = 0,
+        .downstream_device_will_send_get_package_data = 0,
+        .get_package_data_maximum_transfer_size = 0};
+
+    rc = decode_request_downstream_device_update_resp(
+        responseMsg2, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES,
+        &resp_data2);
+    EXPECT_EQ(rc, 0);
+    EXPECT_EQ(resp_data2.completion_code, PLDM_FWUP_ALREADY_IN_UPDATE_MODE);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(RequestDownstreamDeviceUpdate, errorPathDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES>
+        requestUpdateResponse{0x00, 0x00, 0x00, 0x00, 0x00,
+                              0x04, 0x01, 0x00, 0x02};
+
+    auto responseMsg = new (requestUpdateResponse.data()) pldm_msg;
+
+    struct pldm_request_downstream_device_update_resp resp_data = {
+        .completion_code = 0,
+        .downstream_device_meta_data_length = 0,
+        .downstream_device_will_send_get_package_data = 0,
+        .get_package_data_maximum_transfer_size = 0};
+
+    auto rc = decode_request_downstream_device_update_resp(
+        nullptr, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, &resp_data);
+    EXPECT_EQ(rc, -EINVAL);
+
+    rc = decode_request_downstream_device_update_resp(
+        responseMsg, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, nullptr);
+    EXPECT_EQ(rc, -EINVAL);
+
+    rc = decode_request_downstream_device_update_resp(responseMsg, 0,
+                                                      &resp_data);
+    EXPECT_EQ(rc, -EOVERFLOW);
+}
+#endif // LIBPLDM_API_TESTING
+
 TEST(PassComponentTable, goodPathEncodeRequest)
 {
     constexpr uint8_t instanceId = 1;