libpldm: Add decode API for ApplyComplete request

After firmware verification is successful, the FD transitions into
the APPLY state and begins transferring the component image into the
storage location where the object resides. After the FD finishes
applying the component successfully, it issues an ApplyComplete
command indicating success and the FD transitions to the READY XFER
state to be ready for the next component transfer. 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: Idb39407867c31534609b82aa92bfd8400527245d
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index e92da63..2dfa721 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -1122,4 +1122,32 @@
 	msg->payload[0] = completion_code;

 

 	return PLDM_SUCCESS;

-}
\ No newline at end of file
+}

+

+int decode_apply_complete_req(

+    const struct pldm_msg *msg, size_t payload_length, uint8_t *apply_result,

+    bitfield16_t *comp_activation_methods_modification)

+{

+	if (msg == NULL || apply_result == NULL ||

+	    comp_activation_methods_modification == NULL) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	if (payload_length != sizeof(struct pldm_apply_complete_req)) {

+		return PLDM_ERROR_INVALID_LENGTH;

+	}

+

+	struct pldm_apply_complete_req *request =

+	    (struct pldm_apply_complete_req *)msg->payload;

+

+	*apply_result = request->apply_result;

+	comp_activation_methods_modification->value =

+	    le16toh(request->comp_activation_methods_modification.value);

+

+	if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&

+	    comp_activation_methods_modification->value) {

+		return PLDM_ERROR_INVALID_DATA;

+	}

+

+	return PLDM_SUCCESS;

+}

diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index 9163f96..58b8063 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -133,6 +133,21 @@
 	PLDM_COMP_DOWNSTREAM_DEVICE = 0xFFFF

 };

 

+/** @brief ComponentActivationMethods is the bit position in the bitfield that

+ *         provides the capability of the FD for firmware activation. Multiple

+ *         activation methods can be supported.

+ */

+enum pldm_comp_activation_methods {

+	PLDM_ACTIVATION_AUTOMATIC = 0,

+	PLDM_ACTIVATION_SELF_CONTAINED = 1,

+	PLDM_ACTIVATION_MEDIUM_SPECIFIC_RESET = 2,

+	PLDM_ACTIVATION_SYSTEM_REBOOT = 3,

+	PLDM_ACTIVATION_DC_POWER_CYCLE = 4,

+	PLDM_ACTIVATION_AC_POWER_CYCLE = 5,

+	PLDM_SUPPORTS_ACTIVATE_PENDING_IMAGE = 6,

+	PLDM_SUPPORTS_ACTIVATE_PENDING_IMAGE_SET = 7

+};

+

 /** @brief ComponentResponse values in the response of PassComponentTable

  */

 enum pldm_component_responses {

@@ -221,6 +236,16 @@
 	PLDM_FWUP_VENDOR_VERIFY_RESULT_RANGE_MAX = 0xAF

 };

 

+/**@brief ApplyResult values in the response of ApplyComplete

+ */

+enum pldm_firmware_update_apply_result_values {

+	PLDM_FWUP_APPLY_SUCCESS = 0x00,

+	PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD = 0x01,

+	PLDM_FWUP_APPLY_FAILURE_MEMORY_ISSUE = 0x02,

+	PLDM_FWUP_VENDOR_APPLY_RESULT_RANGE_MIN = 0xB0,

+	PLDM_FWUP_VENDOR_APPLY_RESULT_RANGE_MAX = 0xCF

+};

+

 /** @struct pldm_package_header_information

  *

  *  Structure representing fixed part of package header information

@@ -412,6 +437,15 @@
 	uint32_t length;

 } __attribute__((packed));

 

+/** @struct pldm_apply_complete_req

+ *

+ *  Structure representing ApplyComplete request.

+ */

+struct pldm_apply_complete_req {

+	uint8_t apply_result;

+	bitfield16_t comp_activation_methods_modification;

+} __attribute__((packed));

+

 /** @brief Decode the PLDM package header information

  *

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

@@ -819,6 +853,20 @@
 int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,

 				struct pldm_msg *msg, size_t payload_length);

 

+/** @brief Decode ApplyComplete request message

+ *

+ *  @param[in] msg - Request message

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

+ *  @param[in] apply_result - Pointer to hold ApplyResult

+ *  @param[in] comp_activation_methods_modification - Pointer to hold the

+ *                                        ComponentActivationMethodsModification

+ *

+ *  @return pldm_completion_codes

+ */

+int decode_apply_complete_req(

+    const struct pldm_msg *msg, size_t payload_length, uint8_t *apply_result,

+    bitfield16_t *comp_activation_methods_modification);

+

 #ifdef __cplusplus

 }

 #endif

diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index 710a209..8622c76 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -2242,3 +2242,71 @@
     rc = encode_verify_complete_resp(0, PLDM_SUCCESS, responseMsg, 0);

     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

 }

+

+TEST(ApplyComplete, goodPathDecodeRequest)

+{

+    constexpr uint8_t applyResult1 =

+        PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD;

+    // DC power cycle [Bit position 4] & AC power cycle [Bit position 5]

+    constexpr std::bitset<16> compActivationModification1{0x30};

+    constexpr std::array<uint8_t, hdrSize + sizeof(pldm_apply_complete_req)>

+        applyCompleteReq1{0x00, 0x00, 0x00, 0x01, 0x30, 0x00};

+    auto requestMsg1 =

+        reinterpret_cast<const pldm_msg*>(applyCompleteReq1.data());

+    uint8_t outApplyResult = 0;

+    bitfield16_t outCompActivationModification{};

+    auto rc = decode_apply_complete_req(

+        requestMsg1, sizeof(pldm_apply_complete_req), &outApplyResult,

+        &outCompActivationModification);

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(outApplyResult, applyResult1);

+    EXPECT_EQ(outCompActivationModification.value, compActivationModification1);

+

+    constexpr uint8_t applyResult2 = PLDM_FWUP_APPLY_SUCCESS;

+    constexpr std::bitset<16> compActivationModification2{};

+    constexpr std::array<uint8_t, hdrSize + sizeof(pldm_apply_complete_req)>

+        applyCompleteReq2{0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

+    auto requestMsg2 =

+        reinterpret_cast<const pldm_msg*>(applyCompleteReq2.data());

+    rc = decode_apply_complete_req(requestMsg2, sizeof(pldm_apply_complete_req),

+                                   &outApplyResult,

+                                   &outCompActivationModification);

+    EXPECT_EQ(rc, PLDM_SUCCESS);

+    EXPECT_EQ(outApplyResult, applyResult2);

+    EXPECT_EQ(outCompActivationModification.value, compActivationModification2);

+}

+

+TEST(ApplyComplete, errorPathDecodeRequest)

+{

+    constexpr std::array<uint8_t, hdrSize> applyCompleteReq1{0x00, 0x00, 0x00};

+    auto requestMsg1 =

+        reinterpret_cast<const pldm_msg*>(applyCompleteReq1.data());

+    uint8_t outApplyResult = 0;

+    bitfield16_t outCompActivationModification{};

+

+    auto rc = decode_apply_complete_req(

+        nullptr, sizeof(pldm_apply_complete_req), &outApplyResult,

+        &outCompActivationModification);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_apply_complete_req(requestMsg1, sizeof(pldm_apply_complete_req),

+                                   nullptr, &outCompActivationModification);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_apply_complete_req(requestMsg1, sizeof(pldm_apply_complete_req),

+                                   &outApplyResult, nullptr);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+

+    rc = decode_apply_complete_req(requestMsg1, 0, &outApplyResult,

+                                   &outCompActivationModification);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);

+

+    constexpr std::array<uint8_t, hdrSize + sizeof(pldm_apply_complete_req)>

+        applyCompleteReq2{0x00, 0x00, 0x00, 0x00, 0x01, 0x00};

+    auto requestMsg2 =

+        reinterpret_cast<const pldm_msg*>(applyCompleteReq2.data());

+    rc = decode_apply_complete_req(requestMsg2, sizeof(pldm_apply_complete_req),

+                                   &outApplyResult,

+                                   &outCompActivationModification);

+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);

+}