libpldm: Add RdeOperationEnumerate support
Add encoders and decoders for RDEOperationEnumerate
Additionlly added code hooks to serve RDEOperationEnumerate
requests from the client. Also added test for the encoders
and decoders
Tested:
Unit tested the encoders and decoders
Additionally tested the fix through libmctp app by sending
RdeOperationEnumerate requested in the middle of the
RdeOperationComplete request
```
0xc0000
Reading 0xc0000
Received. EID: 9 tag_owner: 0 msg_tag: 6 len:265
cc: 0
operation_status: 5
completion_percentage: 100
Has paylaod: Yes
response_payload_length: 242
etag len: 1
etag:
{"@odata.id":"/redfish/v1/Chassis/Tray/Controls","@odata.type":"#ControlCollection.ControlCollection","Name":"Control Collection","Members":[{"@odata.id":"/redfish/v1/Chassis/Tray/Controls/HDD_pid"},{"@odata.id":"/redfish/v1/Chassis/Tray/Controls/fans"}],"Members@odata.count":2}
{
"@odata.id": "/redfish/v1/Chassis/Tray/Controls",
"@odata.type": "#ControlCollection.ControlCollection",
"Members": [
{
"@odata.id": "/redfish/v1/Chassis/Tray/Controls/HDD_pid"
},
{
"@odata.id": "/redfish/v1/Chassis/Tray/Controls/fans"
}
],
"Members@odata.count": 2,
"Name": "Control Collection"
}
Received. EID: 9 tag_owner: 0 msg_tag: 6 len:13
cc: 0
operation count : 1
Resource Id : 786432
Operation Id: 65451
Operation Type : 1
Resource id verified
Received. EID: 9 tag_owner: 0 msg_tag: 6 len:4
cc: 0
operation completed!!!
```
Google-Bug-Id: 323193207
Google-Bug-Id: 286466007
Change-Id: Ifbee2b4d5a41c0a6af0f299b5a9a799ce682ffba
Signed-off-by: Nikhil Namjoshi <nikhilnamjoshi@google.com>
diff --git a/recipes-phosphor/libpldm/libpldm/0007-Adding-RDEOperationEnumerate-support.patch b/recipes-phosphor/libpldm/libpldm/0007-Adding-RDEOperationEnumerate-support.patch
new file mode 100644
index 0000000..1035fd7
--- /dev/null
+++ b/recipes-phosphor/libpldm/libpldm/0007-Adding-RDEOperationEnumerate-support.patch
@@ -0,0 +1,646 @@
+From 016f55dfaf07c3b90bdc8ef0318629751f1a3b6e Mon Sep 17 00:00:00 2001
+From: Nikhil Namjoshi <nikhilnamjoshi@google.com>
+Date: Thu, 7 Dec 2023 00:05:33 +0000
+Subject: [PATCH] Adding RDEOperationEnumerate support
+
+Add encoders and decoders for RDEOperationEnumerate.
+Additionlly added code hooks to serve RDEOperationEnumerate
+requests from the client. Also added test for the encoders
+and decoders.
+
+Tested:
+Unit tested the encoders and decoders
+Additionally tested the fix through libmctp app by sending
+RdeOperationEnumerate requested in the middle of the
+RdeOperationComplete request
+
+```
+0xc0000
+Reading 0xc0000
+
+Received. EID: 9 tag_owner: 0 msg_tag: 6 len:265
+cc: 0
+operation_status: 5
+completion_percentage: 100
+Has paylaod: Yes
+response_payload_length: 242
+etag len: 1
+etag:
+{"@odata.id":"/redfish/v1/Chassis/Tray/Controls","@odata.type":"#ControlCollection.ControlCollection","Name":"Control Collection","Members":[{"@odata.id":"/redfish/v1/Chassis/Tray/Controls/HDD_pid"},{"@odata.id":"/redfish/v1/Chassis/Tray/Controls/fans"}],"Members@odata.count":2}
+
+{
+ "@odata.id": "/redfish/v1/Chassis/Tray/Controls",
+ "@odata.type": "#ControlCollection.ControlCollection",
+ "Members": [
+ {
+ "@odata.id": "/redfish/v1/Chassis/Tray/Controls/HDD_pid"
+ },
+ {
+ "@odata.id": "/redfish/v1/Chassis/Tray/Controls/fans"
+ }
+ ],
+ "Members@odata.count": 2,
+ "Name": "Control Collection"
+}
+
+Received. EID: 9 tag_owner: 0 msg_tag: 6 len:13
+cc: 0
+operation count : 1
+Resource Id : 786432
+Operation Id: 65451
+Operation Type : 1
+Resource id verified
+
+Received. EID: 9 tag_owner: 0 msg_tag: 6 len:4
+cc: 0
+operation completed!!!
+```
+
+Patch Tracking Bug: b/323193207
+Upstream info / review: NA
+Upstream-Status: Pending
+Justification:
+There is dependency on upstreaming rded first, followed
+by other libpldm command support like OperationInit,
+Operation,Status, OperationComplete and OperationKill
+
+Change-Id: Ifda68fc89837d746a360bc7e56e932c79db6a9e8
+Signed-off-by: Nikhil Namjoshi <nikhilnamjoshi@google.com>
+---
+ include/libpldm/pldm_rde.h | 92 ++++++++++++-
+ src/pldm_rde.c | 150 ++++++++++++++++++++
+ tests/libpldm_rde_test.cpp | 271 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 512 insertions(+), 1 deletion(-)
+
+diff --git a/include/libpldm/pldm_rde.h b/include/libpldm/pldm_rde.h
+index 3b8c1e8..5b2a3dc 100644
+--- a/include/libpldm/pldm_rde.h
++++ b/include/libpldm/pldm_rde.h
+@@ -25,6 +25,7 @@ extern "C" {
+ #define PLDM_RDE_OPERATION_INIT_REQ_HDR_SIZE 17
+ #define PLDM_RDE_OPERATION_INIT_RESP_HDR_SIZE 17
+ #define PLDM_RDE_OPERATION_STATUS_RESP_HDR_SIZE 17
++#define PLDM_RDE_OPERATION_ENUMERATE_RESP_HDR_SIZE 3
+
+ #define PLDM_RDE 0x06 /*Response should support PLDM_PLATFORM and PLDM_RDE*/
+ #define RDE_NEGOTIATE_REDFISH_PARAMETERS_RESP_BYTES 12
+@@ -46,6 +47,7 @@ enum pldm_rde_commands {
+ PLDM_RDE_OPERATION_COMPLETE = 0x13,
+ PLDM_RDE_OPERATION_STATUS = 0x14,
+ PLDM_RDE_OPERATION_KILL = 0x15,
++ PLDM_RDE_OPERATION_ENUMERATE = 0x16,
+ PLDM_RDE_MULTIPART_SEND = 0x30,
+ PLDM_RDE_MULTIPART_RECEIVE = 0x31,
+ };
+@@ -331,6 +333,26 @@ struct pldm_rde_operation_complete_req {
+ struct pldm_rde_operation_complete_resp {
+ uint8_t completion_code;
+ } __attribute__((packed));
++
++/**
++ * @brief RDEOperationEnumerate response operation data structure.
++ */
++struct pldm_rde_operation_enumerate_operation_data {
++ uint32_t resource_id;
++ uint16_t operation_id;
++ uint8_t operation_type;
++} __attribute__((packed));
++
++/**
++ * @brief RDEOperationEnumerate response data structure.
++ */
++struct pldm_rde_operation_enumerate_resp {
++ uint8_t completion_code;
++ uint16_t operation_count;
++ // Variable length data.
++ uint8_t var_data[1];
++} __attribute__((packed));
++
+ /**
+ * @brief RDEOperationStatus request data structure.
+ */
+@@ -754,6 +776,74 @@ int encode_rde_operation_complete_resp(uint8_t instance_id,
+ int decode_rde_operation_complete_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code);
++
++/**
++ * @brief Encode RDEOperationEnumerate request.
++ *
++ * @param[in] instance_id - Message's instance id.
++ * @param[out] msg - Request will be written to this.
++ * @return pldm_completion_codes.
++ */
++int encode_rde_operation_enumerate_req(uint8_t instance_id,
++ struct pldm_msg *msg);
++
++/**
++ * @brief Decode RDEOperationEnumerate request.
++ *
++ * @param[in] msg - Request message.
++ * @param[in] payload_length - Length of request message payload.
++ * @return pldm_completion_codes.
++ */
++int decode_rde_operation_enumerate_req(const struct pldm_msg *msg,
++ size_t payload_length);
++
++/**
++ * @brief Encodes RDEOperationEnumerate response.
++ *
++ * @param[in] instance_id - Message's instance id.
++ * @param[in] completion_code - PLDM completion code.
++ * @param[out] msg - Response message will be written to this.
++ * @return pldm_completion_codes.
++ */
++int encode_rde_operation_enumerate_resp(uint8_t instance_id,
++ uint8_t completion_code,
++ struct pldm_msg *msg);
++
++/**
++ * @brief Updates encoded RDEOperationEnumerate response by appending operation
++ * data to the response.
++ *
++ * @param[in] resource_id - Resource id
++ * @param[in] operation_id - Operation Id
++ * @param[in] operation_type - Operation type
++ * @param[out] msg - Response message will be written to this.
++ * @return pldm_completion_codes.
++ */
++int update_encoded_rde_operation_enumerate_resp(const uint32_t resource_id,
++ const uint16_t operation_id,
++ const uint8_t operation_type,
++ struct pldm_msg *msg);
++
++/**
++ * @brief Decode RDEOperationEnumerate response.
++ * NOTE: The operation_count and operation_data will have
++ * valid data only when then completion_code is PLDM_SUCCESS
++ *
++ * @param[in] msg - Response message will be written to this.
++ * @param[out] completion_code - PLDM completion code.
++ * @param[out] operation_count - Number of active operations in RDE device.
++ * @param[out] operation_data - An array of struct
++ * pldm_rde_operation_enumerate_operation_data to store the operation data
++ * @param[in] operation_data_array_size - Size of the input array of struct
++ * pldm_rde_operation_enumerate_operation_data
++ * @return pldm_completion_codes.
++ */
++int decode_rde_operation_enumerate_resp(
++ const struct pldm_msg *msg, uint8_t *completion_code,
++ uint16_t *operation_count,
++ struct pldm_rde_operation_enumerate_operation_data *operation_data,
++ uint16_t operation_data_array_size);
++
+ /**
+ * @brief Encode RDEOperationStatus request.
+ *
+@@ -844,4 +934,4 @@ int decode_rde_operation_status_resp(
+ }
+ #endif
+
+-#endif /* PLDM_RDE_H */
+\ No newline at end of file
++#endif /* PLDM_RDE_H */
+diff --git a/src/pldm_rde.c b/src/pldm_rde.c
+index 2c87f8e..7116827 100644
+--- a/src/pldm_rde.c
++++ b/src/pldm_rde.c
+@@ -785,6 +785,156 @@ int decode_rde_operation_complete_resp(const struct pldm_msg *msg,
+ return PLDM_SUCCESS;
+ }
+
++LIBPLDM_ABI_STABLE
++int encode_rde_operation_enumerate_req(uint8_t instance_id,
++ struct pldm_msg *msg)
++{
++ if (msg == NULL) {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++ struct pldm_header_info header = {0};
++ header.instance = instance_id;
++ header.pldm_type = PLDM_RDE;
++ header.msg_type = PLDM_REQUEST;
++ header.command = PLDM_RDE_OPERATION_ENUMERATE;
++ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
++ if (rc != PLDM_SUCCESS) {
++ return rc;
++ }
++
++ return PLDM_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++int decode_rde_operation_enumerate_req(const struct pldm_msg *msg,
++ size_t payload_length)
++{
++ if (msg == NULL) {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ // Enumerate operation should not have any request payload
++ if (payload_length != 0) {
++ return PLDM_ERROR_INVALID_LENGTH;
++ }
++
++ return PLDM_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++int encode_rde_operation_enumerate_resp(uint8_t instance_id,
++ uint8_t completion_code,
++ struct pldm_msg *msg)
++{
++ if (msg == NULL) {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ struct pldm_header_info header = {0};
++ header.msg_type = PLDM_RESPONSE;
++ header.instance = instance_id;
++ header.pldm_type = PLDM_RDE;
++ header.command = PLDM_RDE_OPERATION_ENUMERATE;
++ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
++ if (rc != PLDM_SUCCESS) {
++ return rc;
++ }
++ struct pldm_rde_operation_enumerate_resp *response =
++ (struct pldm_rde_operation_enumerate_resp *)msg->payload;
++ response->completion_code = completion_code;
++
++ // Initially set the operation count to 0. Operation data can be added
++ // by calling update_encoded_rde_operation_enumerate_resp API
++ response->operation_count = 0;
++ return PLDM_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++int update_encoded_rde_operation_enumerate_resp(const uint32_t resource_id,
++ const uint16_t operation_id,
++ const uint8_t operation_type,
++ struct pldm_msg *msg)
++{
++ if (msg == NULL) {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ struct pldm_rde_operation_enumerate_operation_data operation_data = {0};
++ operation_data.resource_id = htole32(resource_id);
++ operation_data.operation_id = htole16(operation_id);
++ operation_data.operation_type = operation_type;
++
++ struct pldm_rde_operation_enumerate_resp *response =
++ (struct pldm_rde_operation_enumerate_resp *)msg->payload;
++
++ uint16_t operation_count = le16toh(response->operation_count);
++ memcpy(response->var_data +
++ (sizeof(struct pldm_rde_operation_enumerate_operation_data) *
++ operation_count),
++ (void *)&operation_data,
++ sizeof(struct pldm_rde_operation_enumerate_operation_data));
++
++ response->operation_count = htole16(operation_count + 1);
++ return PLDM_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++int decode_rde_operation_enumerate_resp(
++ const struct pldm_msg *msg, uint8_t *completion_code,
++ uint16_t *operation_count,
++ struct pldm_rde_operation_enumerate_operation_data *operation_data,
++ uint16_t operation_data_array_size)
++{
++ if (msg == NULL) {
++ fprintf(stderr, "Invalid msg object\n");
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ if ((completion_code == NULL) || (operation_count == NULL) ||
++ (operation_data == NULL)) {
++ fprintf(stderr, "Invalid input pointers\n");
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ struct pldm_rde_operation_enumerate_resp *response =
++ (struct pldm_rde_operation_enumerate_resp *)msg->payload;
++
++ *completion_code = response->completion_code;
++ if (*completion_code != PLDM_SUCCESS) {
++ fprintf(
++ stderr,
++ "Unsuccessful completion code received in op status: %x\n",
++ (uint8_t)(*completion_code));
++ return PLDM_SUCCESS;
++ }
++
++ *operation_count = le16toh(response->operation_count);
++ if (operation_data_array_size < *operation_count) {
++ fprintf(stderr,
++ "Input operation_data struct array too small\n");
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ for (uint16_t i = 0; i < *operation_count; i++) {
++ struct pldm_rde_operation_enumerate_operation_data
++ native_operation_data;
++ memcpy(
++ (void *)&native_operation_data,
++ response->var_data +
++ i * sizeof(struct
++ pldm_rde_operation_enumerate_operation_data),
++ sizeof(struct pldm_rde_operation_enumerate_operation_data));
++ operation_data[i].resource_id =
++ le32toh(native_operation_data.resource_id);
++ operation_data[i].operation_id =
++ le16toh(native_operation_data.operation_id);
++ operation_data[i].operation_type =
++ native_operation_data.operation_type;
++ }
++
++ return PLDM_SUCCESS;
++}
++
+ LIBPLDM_ABI_STABLE
+ int encode_rde_operation_status_req(uint8_t instance_id, uint32_t resource_id,
+ uint16_t operation_id, struct pldm_msg *msg)
+diff --git a/tests/libpldm_rde_test.cpp b/tests/libpldm_rde_test.cpp
+index 56e322b..ed4625e 100644
+--- a/tests/libpldm_rde_test.cpp
++++ b/tests/libpldm_rde_test.cpp
+@@ -887,3 +887,274 @@ TEST(RDEOperationStatus, DecodeResponseSuccess)
+ EXPECT_EQ(returnEtag->string_length_bytes,
+ std::end(etag) - std::begin(etag));
+ }
++
++TEST(RDEOperationEnumerate, EncodeRequest)
++{
++ uint8_t instanceId = 23;
++
++ constexpr size_t requestSize = sizeof(struct pldm_msg_hdr);
++ std::array<uint8_t, requestSize> requestMsg{};
++ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
++
++ // When input msg of type struct pldm_msg * is NULL
++ EXPECT_EQ(encode_rde_operation_enumerate_req(instanceId, NULL),
++ PLDM_ERROR_INVALID_DATA);
++
++ // When all inputs are valid
++ EXPECT_EQ(encode_rde_operation_enumerate_req(instanceId, request),
++ PLDM_SUCCESS);
++
++ // Test Header values
++ EXPECT_EQ(request->hdr.instance_id, instanceId);
++ EXPECT_EQ(request->hdr.request, PLDM_REQUEST);
++ EXPECT_EQ(request->hdr.type, PLDM_RDE);
++ EXPECT_EQ(request->hdr.command, PLDM_RDE_OPERATION_ENUMERATE);
++}
++
++TEST(RDEOperationEnumerate, DecodeRequest)
++{
++ uint8_t instanceId = 25;
++
++ constexpr size_t requestSize = sizeof(struct pldm_msg_hdr);
++ std::array<uint8_t, requestSize> requestMsg{};
++ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
++
++ encode_rde_operation_enumerate_req(instanceId, request);
++
++ // When input msg of type struct pldm_msg * is NULL
++ EXPECT_EQ(decode_rde_operation_enumerate_req(
++ NULL, requestSize - sizeof(struct pldm_msg_hdr)),
++ PLDM_ERROR_INVALID_DATA);
++
++ // When when the request size in non-zero indicating a request payload is
++ // present
++ EXPECT_EQ(decode_rde_operation_enumerate_req(request, 10),
++ PLDM_ERROR_INVALID_LENGTH);
++
++ // When all inputs are valid
++ EXPECT_EQ(decode_rde_operation_enumerate_req(
++ request, requestSize - sizeof(struct pldm_msg_hdr)),
++ PLDM_SUCCESS);
++}
++
++TEST(RDEOperationEnumerate, EncodeResponse)
++{
++ uint8_t instanceId = 29;
++ uint8_t completionCode = 0;
++
++ constexpr size_t responsePayloadLength =
++ sizeof(struct pldm_msg_hdr) +
++ PLDM_RDE_OPERATION_ENUMERATE_RESP_HDR_SIZE;
++ std::array<uint8_t, responsePayloadLength> responseMsg{};
++ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
++
++ // When input msg of type struct pldm_msg* is NULL
++ EXPECT_EQ(
++ encode_rde_operation_enumerate_resp(instanceId, completionCode, NULL),
++ PLDM_ERROR_INVALID_DATA);
++
++ // When all the inputs are valid
++ EXPECT_EQ(encode_rde_operation_enumerate_resp(instanceId, completionCode,
++ response),
++ PLDM_SUCCESS);
++
++ // verify header.
++ EXPECT_EQ(response->hdr.instance_id, instanceId);
++ EXPECT_EQ(response->hdr.request, 0);
++ EXPECT_EQ(response->hdr.type, PLDM_RDE);
++ EXPECT_EQ(response->hdr.command, PLDM_RDE_OPERATION_ENUMERATE);
++
++ // verify payload.
++ auto respPayload =
++ reinterpret_cast<pldm_rde_operation_enumerate_resp*>(response->payload);
++ EXPECT_EQ(respPayload->completion_code, completionCode);
++ EXPECT_EQ(respPayload->operation_count, 0);
++}
++
++TEST(RDEOperationEnumerate, UpdateEncodedResponse)
++{
++ uint8_t instanceId = 29;
++ uint8_t completionCode = 0;
++ const uint16_t operationCount = 3;
++
++ constexpr size_t responsePayloadLength =
++ sizeof(struct pldm_msg_hdr) +
++ PLDM_RDE_OPERATION_ENUMERATE_RESP_HDR_SIZE +
++ (operationCount *
++ sizeof(struct pldm_rde_operation_enumerate_operation_data));
++ std::array<uint8_t, responsePayloadLength> responseMsg{};
++ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
++
++ EXPECT_EQ(encode_rde_operation_enumerate_resp(instanceId, completionCode,
++ response),
++ PLDM_SUCCESS);
++
++ struct pldm_rde_operation_enumerate_operation_data
++ enumerateData[operationCount] = {
++ {.resource_id = 54314,
++ .operation_id = 2,
++ .operation_type = PLDM_RDE_OPERATION_READ},
++ {.resource_id = 32456,
++ .operation_id = 1,
++ .operation_type = PLDM_RDE_OPERATION_UPDATE},
++ {.resource_id = 76543,
++ .operation_id = 6,
++ .operation_type = PLDM_RDE_OPERATION_ACTION}};
++
++ // When input msg of type struct pldm_msg* is NULL
++ EXPECT_EQ(update_encoded_rde_operation_enumerate_resp(
++ enumerateData[0].resource_id, enumerateData[0].operation_id,
++ enumerateData[0].operation_type, NULL),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Update the encoded payload with enumerate_data one by one and verify that
++ // response payload metadata gets updated accordingly
++ for (int i = 0; i < operationCount; i++)
++ {
++
++ EXPECT_EQ(update_encoded_rde_operation_enumerate_resp(
++ enumerateData[i].resource_id,
++ enumerateData[i].operation_id,
++ enumerateData[i].operation_type, response),
++ PLDM_SUCCESS);
++ auto respPayload2 =
++ reinterpret_cast<pldm_rde_operation_enumerate_resp*>(
++ response->payload);
++ EXPECT_EQ(respPayload2->completion_code, completionCode);
++ EXPECT_EQ(respPayload2->operation_count, i + 1);
++ }
++
++ // verify payload.
++ auto respPayload3 =
++ reinterpret_cast<pldm_rde_operation_enumerate_resp*>(response->payload);
++ EXPECT_EQ(respPayload3->completion_code, completionCode);
++ EXPECT_EQ(respPayload3->operation_count, operationCount);
++
++ struct pldm_rde_operation_enumerate_operation_data* enumerateRespData =
++ (struct pldm_rde_operation_enumerate_operation_data*)
++ respPayload3->var_data;
++
++ // Verify that the enumerate_data in the response is updated
++ for (int i = 0; i < operationCount; i++)
++ {
++ EXPECT_EQ(enumerateRespData[i].resource_id,
++ enumerateData[i].resource_id);
++ EXPECT_EQ(enumerateRespData[i].operation_id,
++ enumerateData[i].operation_id);
++ EXPECT_EQ(enumerateRespData[i].operation_type,
++ enumerateData[i].operation_type);
++ }
++}
++
++TEST(RDEOperationEnumerate, DecodeResponse)
++{
++ uint8_t instanceId = 29;
++ uint8_t completionCodeInput = 0;
++ const uint16_t operationCountInput = 3;
++
++ uint8_t completionCodeOutput = 0;
++ uint16_t operationCountOutput = 0;
++
++ struct pldm_rde_operation_enumerate_operation_data
++ enumerateRespData[operationCountInput];
++
++ struct pldm_rde_operation_enumerate_operation_data
++ enumerateData[operationCountInput] = {
++ {.resource_id = 54314,
++ .operation_id = 2,
++ .operation_type = PLDM_RDE_OPERATION_READ},
++ {.resource_id = 32456,
++ .operation_id = 1,
++ .operation_type = PLDM_RDE_OPERATION_UPDATE},
++ {.resource_id = 76543,
++ .operation_id = 6,
++ .operation_type = PLDM_RDE_OPERATION_ACTION}};
++
++ constexpr size_t responsePayloadLength =
++ sizeof(struct pldm_msg_hdr) +
++ PLDM_RDE_OPERATION_ENUMERATE_RESP_HDR_SIZE +
++ (operationCountInput *
++ sizeof(struct pldm_rde_operation_enumerate_operation_data));
++ std::array<uint8_t, responsePayloadLength> responseMsg{};
++ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
++
++ // When input msg of type struct pldm_msg* is NULL
++ EXPECT_EQ(decode_rde_operation_enumerate_resp(
++ NULL, &completionCodeOutput, &operationCountOutput,
++ enumerateRespData, operationCountInput),
++ PLDM_ERROR_INVALID_DATA);
++
++ // When input completion_code is NULL
++ EXPECT_EQ(decode_rde_operation_enumerate_resp(
++ response, NULL, &operationCountOutput, enumerateRespData,
++ operationCountInput),
++ PLDM_ERROR_INVALID_DATA);
++
++ // When input operation_count is NULL
++ EXPECT_EQ(decode_rde_operation_enumerate_resp(
++ response, &completionCodeOutput, NULL, enumerateRespData,
++ operationCountInput),
++ PLDM_ERROR_INVALID_DATA);
++
++ // When input operation_data is NULL
++ EXPECT_EQ(decode_rde_operation_enumerate_resp(
++ response, &completionCodeOutput, &operationCountOutput, NULL,
++ operationCountInput),
++ PLDM_ERROR_INVALID_DATA);
++
++ // When input array size is smaller that the actual operation count
++ EXPECT_EQ(decode_rde_operation_enumerate_resp(
++ response, &completionCodeOutput, &operationCountOutput,
++ enumerateRespData, operationCountInput - 1),
++ PLDM_SUCCESS);
++
++ // When all the inputs are valid
++ EXPECT_EQ(encode_rde_operation_enumerate_resp(
++ instanceId, completionCodeInput, response),
++ PLDM_SUCCESS);
++
++ // Update the encoded payload with enumerate_data one by one
++ for (int i = 0; i < operationCountInput; i++)
++ {
++ EXPECT_EQ(update_encoded_rde_operation_enumerate_resp(
++ enumerateData[i].resource_id,
++ enumerateData[i].operation_id,
++ enumerateData[i].operation_type, response),
++ PLDM_SUCCESS);
++ }
++
++ EXPECT_EQ(decode_rde_operation_enumerate_resp(
++ response, &completionCodeOutput, &operationCountOutput,
++ enumerateRespData, operationCountInput),
++ PLDM_SUCCESS);
++
++ auto respPayload1 =
++ reinterpret_cast<pldm_rde_operation_enumerate_resp*>(response->payload);
++ EXPECT_EQ(respPayload1->completion_code, completionCodeInput);
++ EXPECT_EQ(respPayload1->operation_count, operationCountInput);
++
++ // Verify that the enumerate_data in the response is updated
++ for (int i = 0; i < operationCountInput; i++)
++ {
++ EXPECT_EQ(enumerateRespData[i].resource_id,
++ enumerateData[i].resource_id);
++ EXPECT_EQ(enumerateRespData[i].operation_id,
++ enumerateData[i].operation_id);
++ EXPECT_EQ(enumerateRespData[i].operation_type,
++ enumerateData[i].operation_type);
++ }
++
++ // When encoder encounters error and sets error completion code
++ EXPECT_EQ(
++ encode_rde_operation_enumerate_resp(instanceId, PLDM_ERROR, response),
++ PLDM_SUCCESS);
++ EXPECT_EQ(decode_rde_operation_enumerate_resp(
++ response, &completionCodeOutput, &operationCountOutput,
++ enumerateRespData, operationCountInput),
++ PLDM_SUCCESS);
++
++ auto respPayload2 =
++ reinterpret_cast<pldm_rde_operation_enumerate_resp*>(response->payload);
++ EXPECT_EQ(respPayload2->completion_code, PLDM_ERROR);
++ EXPECT_EQ(respPayload2->operation_count, 0);
++}
+--
+2.43.0.594.gd9cf4e227d-goog
+
diff --git a/recipes-phosphor/libpldm/libpldm_%.bbappend b/recipes-phosphor/libpldm/libpldm_%.bbappend
index 83b6728..d80cb31 100644
--- a/recipes-phosphor/libpldm/libpldm_%.bbappend
+++ b/recipes-phosphor/libpldm/libpldm_%.bbappend
@@ -9,4 +9,5 @@
file://0004-Add-support-for-RDE-Discovery-Negotiate-and-Medium-p.patch \
file://0005-Add-support-for-dictionary-extraction-for-resources.patch \
file://0006-Fix-memory-issue-in-rde.patch \
+ file://0007-Adding-RDEOperationEnumerate-support.patch \
"