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 \
 "