libpldm: Add decode API for CancelUpdate response
Update agent sends this command to FD/FDP to exit from update mode
even if activation is required to begin operating at the new firmware
level. FD/FDP will transition to IDLE state on CancelUpdate. 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: I302418f85dd0b870c4d3ace7e04fcc4b873f54a7
diff --git a/libpldm/firmware_update.c b/libpldm/firmware_update.c
index 53c1387..fd66549 100644
--- a/libpldm/firmware_update.c
+++ b/libpldm/firmware_update.c
@@ -280,6 +280,24 @@
}
}
+/** @brief Check if non functioning component indication in CancelUpdate
+ * response is valid
+ *
+ * @return true if non functioning component indication is valid, false if not
+ */
+static bool is_non_functioning_component_indication_valid(
+ bool8_t non_functioning_component_indication)
+{
+ switch (non_functioning_component_indication) {
+ case PLDM_FWUP_COMPONENTS_FUNCTIONING:
+ case PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
int decode_pldm_package_header_info(
const uint8_t *data, size_t length,
struct pldm_package_header_information *package_header_info,
@@ -1507,3 +1525,41 @@
return PLDM_SUCCESS;
}
+
+int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
+ uint8_t *completion_code,
+ bool8_t *non_functioning_component_indication,
+ bitfield64_t *non_functioning_component_bitmap)
+{
+ if (msg == NULL || completion_code == NULL ||
+ non_functioning_component_indication == NULL ||
+ non_functioning_component_bitmap == NULL || !payload_length) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+ if (*completion_code != PLDM_SUCCESS) {
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ struct pldm_cancel_update_resp *response =
+ (struct pldm_cancel_update_resp *)msg->payload;
+
+ if (!is_non_functioning_component_indication_valid(
+ response->non_functioning_component_indication)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *non_functioning_component_indication =
+ response->non_functioning_component_indication;
+
+ if (*non_functioning_component_indication) {
+ non_functioning_component_bitmap->value =
+ le64toh(response->non_functioning_component_bitmap);
+ }
+
+ return PLDM_SUCCESS;
+}
diff --git a/libpldm/firmware_update.h b/libpldm/firmware_update.h
index 697a479..ed403bb 100644
--- a/libpldm/firmware_update.h
+++ b/libpldm/firmware_update.h
@@ -311,6 +311,13 @@
PLDM_FD_STATUS_VENDOR_DEFINED_MAX = 255
};
+/** @brief Components functional indicator in CancelUpdate response
+ */
+enum pldm_firmware_update_non_functioning_component_indication {
+ PLDM_FWUP_COMPONENTS_FUNCTIONING = 0,
+ PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING = 1
+};
+
/** @struct pldm_package_header_information
*
* Structure representing fixed part of package header information
@@ -543,6 +550,16 @@
bitfield32_t update_option_flags_enabled;
} __attribute__((packed));
+/** @struct pldm_cancel_update_resp
+ *
+ * Structure representing CancelUpdate response.
+ */
+struct pldm_cancel_update_resp {
+ uint8_t completion_code;
+ bool8_t non_functioning_component_indication;
+ uint64_t non_functioning_component_bitmap;
+} __attribute__((packed));
+
/** @brief Decode the PLDM package header information
*
* @param[in] data - pointer to package header information
@@ -1089,6 +1106,25 @@
int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
size_t payload_length);
+/** @brief Decode CancelUpdate response message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to completion code
+ * @param[out] non_functioning_component_indication - Pointer to non
+ functioning
+ * component indication
+ * @param[out] non_functioning_component_bitmap - Pointer to non
+ functioning
+ * component bitmap
+ *
+ * @return pldm_completion_codes
+ */
+int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
+ uint8_t *completion_code,
+ bool8_t *non_functioning_component_indication,
+ bitfield64_t *non_functioning_component_bitmap);
+
#ifdef __cplusplus
}
#endif
diff --git a/libpldm/pldm_types.h b/libpldm/pldm_types.h
index 5e7e068..3c5f086 100644
--- a/libpldm/pldm_types.h
+++ b/libpldm/pldm_types.h
@@ -90,6 +90,76 @@
} __attribute__((packed)) bits;
} bitfield32_t;
+typedef union {
+ uint64_t value;
+ struct {
+ uint8_t bit0 : 1;
+ uint8_t bit1 : 1;
+ uint8_t bit2 : 1;
+ uint8_t bit3 : 1;
+ uint8_t bit4 : 1;
+ uint8_t bit5 : 1;
+ uint8_t bit6 : 1;
+ uint8_t bit7 : 1;
+ uint8_t bit8 : 1;
+ uint8_t bit9 : 1;
+ uint8_t bit10 : 1;
+ uint8_t bit11 : 1;
+ uint8_t bit12 : 1;
+ uint8_t bit13 : 1;
+ uint8_t bit14 : 1;
+ uint8_t bit15 : 1;
+ uint8_t bit16 : 1;
+ uint8_t bit17 : 1;
+ uint8_t bit18 : 1;
+ uint8_t bit19 : 1;
+ uint8_t bit20 : 1;
+ uint8_t bit21 : 1;
+ uint8_t bit22 : 1;
+ uint8_t bit23 : 1;
+ uint8_t bit24 : 1;
+ uint8_t bit25 : 1;
+ uint8_t bit26 : 1;
+ uint8_t bit27 : 1;
+ uint8_t bit28 : 1;
+ uint8_t bit29 : 1;
+ uint8_t bit30 : 1;
+ uint8_t bit31 : 1;
+ uint8_t bit32 : 1;
+ uint8_t bit33 : 1;
+ uint8_t bit34 : 1;
+ uint8_t bit35 : 1;
+ uint8_t bit36 : 1;
+ uint8_t bit37 : 1;
+ uint8_t bit38 : 1;
+ uint8_t bit39 : 1;
+ uint8_t bit40 : 1;
+ uint8_t bit41 : 1;
+ uint8_t bit42 : 1;
+ uint8_t bit43 : 1;
+ uint8_t bit44 : 1;
+ uint8_t bit45 : 1;
+ uint8_t bit46 : 1;
+ uint8_t bit47 : 1;
+ uint8_t bit48 : 1;
+ uint8_t bit49 : 1;
+ uint8_t bit50 : 1;
+ uint8_t bit51 : 1;
+ uint8_t bit52 : 1;
+ uint8_t bit53 : 1;
+ uint8_t bit54 : 1;
+ uint8_t bit55 : 1;
+ uint8_t bit56 : 1;
+ uint8_t bit57 : 1;
+ uint8_t bit58 : 1;
+ uint8_t bit59 : 1;
+ uint8_t bit60 : 1;
+ uint8_t bit61 : 1;
+ uint8_t bit62 : 1;
+ uint8_t bit63 : 1;
+ } __attribute__((packed)) bits;
+} bitfield64_t;
+
typedef float real32_t;
#endif /* PLDM_TYPES_H */
diff --git a/libpldm/tests/libpldm_firmware_update_test.cpp b/libpldm/tests/libpldm_firmware_update_test.cpp
index 9ef53f7..746dfd6 100644
--- a/libpldm/tests/libpldm_firmware_update_test.cpp
+++ b/libpldm/tests/libpldm_firmware_update_test.cpp
@@ -2817,3 +2817,106 @@
PLDM_CANCEL_UPDATE_REQ_BYTES + 1);
EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
}
+
+TEST(CancelUpdate, goodPathDecodeResponse)
+{
+ constexpr std::bitset<64> nonFunctioningComponentBitmap1{0};
+ constexpr std::array<uint8_t, hdrSize + sizeof(pldm_cancel_update_resp)>
+ cancelUpdateResponse1{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ auto responseMsg1 =
+ reinterpret_cast<const pldm_msg*>(cancelUpdateResponse1.data());
+ uint8_t completionCode = 0;
+ bool8_t nonFunctioningComponentIndication = 0;
+ bitfield64_t nonFunctioningComponentBitmap{0};
+ auto rc = decode_cancel_update_resp(
+ responseMsg1, cancelUpdateResponse1.size() - hdrSize, &completionCode,
+ &nonFunctioningComponentIndication, &nonFunctioningComponentBitmap);
+ EXPECT_EQ(rc, PLDM_SUCCESS);
+ EXPECT_EQ(completionCode, PLDM_SUCCESS);
+ EXPECT_EQ(nonFunctioningComponentIndication,
+ PLDM_FWUP_COMPONENTS_FUNCTIONING);
+ EXPECT_EQ(nonFunctioningComponentBitmap.value,
+ nonFunctioningComponentBitmap1);
+
+ constexpr std::bitset<64> nonFunctioningComponentBitmap2{0x0101};
+ constexpr std::array<uint8_t, hdrSize + sizeof(pldm_cancel_update_resp)>
+ cancelUpdateResponse2{0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ auto responseMsg2 =
+ reinterpret_cast<const pldm_msg*>(cancelUpdateResponse2.data());
+ rc = decode_cancel_update_resp(
+ responseMsg2, cancelUpdateResponse2.size() - hdrSize, &completionCode,
+ &nonFunctioningComponentIndication, &nonFunctioningComponentBitmap);
+ EXPECT_EQ(rc, PLDM_SUCCESS);
+ EXPECT_EQ(completionCode, PLDM_SUCCESS);
+ EXPECT_EQ(nonFunctioningComponentIndication,
+ PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING);
+ EXPECT_EQ(nonFunctioningComponentBitmap.value,
+ nonFunctioningComponentBitmap2);
+
+ constexpr std::array<uint8_t, hdrSize + sizeof(completionCode)>
+ cancelUpdateResponse3{0x00, 0x00, 0x00, 0x86};
+ auto responseMsg3 =
+ reinterpret_cast<const pldm_msg*>(cancelUpdateResponse3.data());
+ rc = decode_cancel_update_resp(
+ responseMsg3, cancelUpdateResponse3.size() - hdrSize, &completionCode,
+ &nonFunctioningComponentIndication, &nonFunctioningComponentBitmap);
+ EXPECT_EQ(rc, PLDM_SUCCESS);
+ EXPECT_EQ(completionCode, PLDM_FWUP_BUSY_IN_BACKGROUND);
+}
+
+TEST(CancelUpdate, errorPathDecodeResponse)
+{
+ constexpr std::array<uint8_t, hdrSize> cancelUpdateResponse1{0x00, 0x00,
+ 0x00};
+ auto responseMsg1 =
+ reinterpret_cast<const pldm_msg*>(cancelUpdateResponse1.data());
+ uint8_t completionCode = 0;
+ bool8_t nonFunctioningComponentIndication = 0;
+ bitfield64_t nonFunctioningComponentBitmap{0};
+
+ auto rc = decode_cancel_update_resp(
+ nullptr, cancelUpdateResponse1.size() - hdrSize, &completionCode,
+ &nonFunctioningComponentIndication, &nonFunctioningComponentBitmap);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ rc = decode_cancel_update_resp(
+ responseMsg1, cancelUpdateResponse1.size() - hdrSize, nullptr,
+ &nonFunctioningComponentIndication, &nonFunctioningComponentBitmap);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ rc = decode_cancel_update_resp(
+ responseMsg1, cancelUpdateResponse1.size() - hdrSize, &completionCode,
+ nullptr, &nonFunctioningComponentBitmap);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ rc = decode_cancel_update_resp(
+ responseMsg1, cancelUpdateResponse1.size() - hdrSize, &completionCode,
+ &nonFunctioningComponentIndication, nullptr);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ rc = decode_cancel_update_resp(
+ responseMsg1, cancelUpdateResponse1.size() - hdrSize, &completionCode,
+ &nonFunctioningComponentIndication, &nonFunctioningComponentBitmap);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+ constexpr std::array<uint8_t, hdrSize + sizeof(completionCode)>
+ cancelUpdateResponse2{0x00, 0x00, 0x00, 0x00};
+ auto responseMsg2 =
+ reinterpret_cast<const pldm_msg*>(cancelUpdateResponse2.data());
+ rc = decode_cancel_update_resp(
+ responseMsg2, cancelUpdateResponse2.size() - hdrSize, &completionCode,
+ &nonFunctioningComponentIndication, &nonFunctioningComponentBitmap);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+ constexpr std::array<uint8_t, hdrSize + sizeof(pldm_cancel_update_resp)>
+ cancelUpdateResponse3{0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ auto responseMsg3 =
+ reinterpret_cast<const pldm_msg*>(cancelUpdateResponse3.data());
+ rc = decode_cancel_update_resp(
+ responseMsg3, cancelUpdateResponse3.size() - hdrSize, &completionCode,
+ &nonFunctioningComponentIndication, &nonFunctioningComponentBitmap);
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}