libpldm: Add RDE Dictionary extraction support

Tested:

Tested the integration with RDE daemon using the meta-gms
machine along with unit tests

Google-Bug-Id: 293472370
Change-Id: I7ea3c3c8e6c8641107886304c1201e92972ba221
Signed-off-by: Harsh Tyagi <harshtya@google.com>
diff --git a/recipes-phosphor/libpldm/libpldm/0005-Add-support-for-dictionary-extraction-for-resources.patch b/recipes-phosphor/libpldm/libpldm/0005-Add-support-for-dictionary-extraction-for-resources.patch
new file mode 100644
index 0000000..7756039
--- /dev/null
+++ b/recipes-phosphor/libpldm/libpldm/0005-Add-support-for-dictionary-extraction-for-resources.patch
@@ -0,0 +1,545 @@
+From 9d033bf04bef4812348dc95db5babbdbc7679094 Mon Sep 17 00:00:00 2001
+From: Harsh Tyagi <harshtya@google.com>
+Date: Wed, 16 Aug 2023 18:21:48 +0000
+Subject: [PATCH] Add support for dictionary extraction for resources
+
+Tested:
+
+Testing done on dev machine for extracting dictionaries
+
+Patch Tracking Bug: 293472370
+Upstream-Status: Pending
+Upstream info / review: https://gerrit.openbmc.org/c/openbmc/libpldm/+/65474
+Justification: (Design under review)
+https://gerrit.openbmc.org/c/openbmc/docs/+/61256
+---
+ .../libpldm/requester/pldm_rde_requester.h    |  44 ++++
+ src/requester/pldm_rde_requester.c            | 161 +++++++++++++
+ tests/requester/rde_requester_test.cpp        | 227 +++++++++++++++++-
+ 3 files changed, 424 insertions(+), 8 deletions(-)
+
+diff --git a/include/libpldm/requester/pldm_rde_requester.h b/include/libpldm/requester/pldm_rde_requester.h
+index ccf23ae..f3a46cf 100644
+--- a/include/libpldm/requester/pldm_rde_requester.h
++++ b/include/libpldm/requester/pldm_rde_requester.h
+@@ -252,6 +252,50 @@ pldm_rde_requester_rc_t pldm_rde_get_next_discovery_command(
+ pldm_rde_requester_rc_t
+ pldm_rde_create_context(struct pldm_rde_requester_context *current_ctx);
+ 
++/**
++ * @brief Initializes the context to trigger dictionary schema RDE ops
++ *
++ * @param[in] ctx - RDE Requester context to be initialized and set the state to
++ * trigger Dictionary Operations over RDE/PLDM
++ *
++ * @return pldm_requester_rc_t (errno may be set)
++ */
++pldm_rde_requester_rc_t
++pldm_rde_init_get_dictionary_schema(struct pldm_rde_requester_context *ctx);
++
++/**
++ * @brief Gets the next command in sequence required to extract dictionaries
++ * from the RDE Device for the given resources
++ *
++ * @param[in] instance_id - Instance ID corresponding to the request
++ * @param[in] manager - Context Manager
++ * @param[in] current_ctx - RDE Request Context
++ * @param[out] request - Request object that would hold the encoded request
++ * message for the requester to send
++ *
++ * @return pldm_requester_rc_t (errno may be set)
++ */
++pldm_rde_requester_rc_t pldm_rde_get_next_dictionary_schema_command(
++    uint8_t instance_id, struct pldm_rde_requester_manager *manager,
++    struct pldm_rde_requester_context *current_ctx, struct pldm_msg *request);
++
++/**
++ * @brief Pushes the response received into current context, updates the state
++ * of the context and/or returns the response payload back to the requester
++ *
++ * @param[in] manager - Context Manager
++ * @param[in] ctx - RDE Request Context
++ * @param[in] resp_msg - Response received from the RDE Device
++ * @param[in] resp_size - Size of the response message
++ * @param[in] callback - Pointer to a function that would be executed over the
++ * response payload as per requester's requirement
++ *
++ * @return pldm_requester_rc_t (errno may be set)
++ */
++pldm_rde_requester_rc_t pldm_rde_push_get_dictionary_response(
++    struct pldm_rde_requester_manager *manager,
++    struct pldm_rde_requester_context *ctx, void *resp_msg, size_t resp_size,
++    callback_funct callback);
+ #ifdef __cplusplus
+ }
+ #endif
+diff --git a/src/requester/pldm_rde_requester.c b/src/requester/pldm_rde_requester.c
+index 44dd5ee..47ac317 100644
+--- a/src/requester/pldm_rde_requester.c
++++ b/src/requester/pldm_rde_requester.c
+@@ -169,3 +169,164 @@ pldm_rde_discovery_push_response(struct pldm_rde_requester_manager *manager,
+ 		return PLDM_RDE_REQUESTER_NO_NEXT_COMMAND_FOUND;
+ 	}
+ }
++
++LIBPLDM_ABI_STABLE
++pldm_rde_requester_rc_t
++pldm_rde_init_get_dictionary_schema(struct pldm_rde_requester_context *ctx)
++{
++	if (ctx->context_status == CONTEXT_BUSY) {
++		return PLDM_RDE_CONTEXT_INITIALIZATION_ERROR;
++	}
++	ctx->next_command = PLDM_GET_SCHEMA_DICTIONARY;
++	struct pdr_resource *current_pdr_resource =
++	    (struct pdr_resource *)malloc(sizeof(struct pdr_resource));
++	ctx->current_pdr_resource = current_pdr_resource;
++	// start with 0th index of resource id array
++	current_pdr_resource->resource_id_index = 0;
++	current_pdr_resource->schema_class = PLDM_RDE_SCHEMA_MAJOR;
++	ctx->requester_status = PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
++	return PLDM_RDE_REQUESTER_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++pldm_rde_requester_rc_t pldm_rde_get_next_dictionary_schema_command(
++    uint8_t instance_id, struct pldm_rde_requester_manager *manager,
++    struct pldm_rde_requester_context *current_ctx, struct pldm_msg *request)
++{
++	if (manager->number_of_resources == 0) {
++		return PLDM_RDE_NO_PDR_RESOURCES_FOUND;
++	}
++	if (!manager->initialized) {
++		return PLDM_RDE_CONTEXT_INITIALIZATION_ERROR;
++	}
++
++	if (current_ctx->context_status == CONTEXT_BUSY) {
++		return PLDM_RDE_CONTEXT_NOT_READY;
++	}
++
++	int rc = 0;
++	switch (current_ctx->next_command) {
++	case PLDM_GET_SCHEMA_DICTIONARY: {
++		uint32_t resource_id =
++		    current_ctx->current_pdr_resource->resource_id_index;
++		rc = encode_get_schema_dictionary_req(
++		    instance_id, manager->resource_ids[resource_id],
++		    PLDM_RDE_SCHEMA_MAJOR, request);
++		break;
++	}
++	case PLDM_RDE_MULTIPART_RECEIVE:
++		rc = encode_rde_multipart_receive_req(
++		    instance_id,
++		    current_ctx->current_pdr_resource->transfer_handle, 0x00,
++		    current_ctx->current_pdr_resource->transfer_operation,
++		    request);
++		break;
++	default:
++		rc = PLDM_RDE_REQUESTER_NO_NEXT_COMMAND_FOUND;
++		break;
++	}
++	if (rc) {
++		fprintf(stderr, "Unable to encode request with rc: %d\n", rc);
++		return PLDM_RDE_REQUESTER_ENCODING_REQUEST_FAILURE;
++	}
++	return rc;
++}
++
++int set_next_dictionary_index(struct pldm_rde_requester_manager *manager,
++			      struct pldm_rde_requester_context *ctx)
++{
++	uint8_t new_rid_idx = ctx->current_pdr_resource->resource_id_index + 1;
++
++	if (new_rid_idx == manager->number_of_resources) {
++		fprintf(stdout,
++			"Processed all resources for dictionaries: %x \n",
++			(uint8_t)new_rid_idx);
++		ctx->next_command =
++		    PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
++		ctx->current_pdr_resource->transfer_operation =
++		    PLDM_XFER_COMPLETE;
++		ctx->requester_status = PLDM_RDE_REQUESTER_NO_PENDING_ACTION;
++		ctx->context_status = CONTEXT_FREE;
++	} else {
++		ctx->next_command = PLDM_GET_SCHEMA_DICTIONARY;
++		ctx->current_pdr_resource->resource_id_index = new_rid_idx;
++		ctx->current_pdr_resource->schema_class = PLDM_RDE_SCHEMA_MAJOR;
++		ctx->requester_status =
++		    PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
++	}
++	return PLDM_RDE_REQUESTER_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++pldm_rde_requester_rc_t pldm_rde_push_get_dictionary_response(
++    struct pldm_rde_requester_manager *manager,
++    struct pldm_rde_requester_context *ctx, void *resp_msg, size_t resp_size,
++    callback_funct callback)
++{
++	int rc = 0;
++	switch (ctx->next_command) {
++	case PLDM_GET_SCHEMA_DICTIONARY: {
++		uint8_t completion_code = DEFAULT_INIT;
++		rc = decode_get_schema_dictionary_resp(
++		    resp_msg, resp_size - sizeof(struct pldm_msg_hdr),
++		    &completion_code,
++		    &(ctx->current_pdr_resource->dictionary_format),
++		    &(ctx->current_pdr_resource->transfer_handle));
++		if (rc || completion_code) {
++			ctx->context_status = CONTEXT_FREE;
++			set_next_dictionary_index(manager, ctx);
++			break;
++		}
++
++		ctx->next_command = PLDM_RDE_MULTIPART_RECEIVE;
++		ctx->current_pdr_resource->transfer_operation =
++		    PLDM_XFER_FIRST_PART;
++		ctx->context_status = CONTEXT_FREE;
++		ctx->requester_status =
++		    PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
++		return PLDM_RDE_REQUESTER_SUCCESS;
++	}
++	case PLDM_RDE_MULTIPART_RECEIVE: {
++		uint8_t completion_code = DEFAULT_INIT;
++		uint8_t ret_transfer_flag = DEFAULT_INIT;
++		uint8_t *payload = NULL;
++		uint32_t ret_data_transfer_handle = DEFAULT_INIT;
++		uint32_t data_length_bytes = DEFAULT_INIT;
++
++		rc = decode_rde_multipart_receive_resp(
++		    resp_msg, resp_size - sizeof(struct pldm_msg_hdr),
++		    &completion_code, &ret_transfer_flag,
++		    &ret_data_transfer_handle, &data_length_bytes, &payload);
++
++		if (rc || completion_code) {
++			ctx->context_status = CONTEXT_FREE;
++			set_next_dictionary_index(manager, ctx);
++			break;
++		}
++		if ((ret_transfer_flag == PLDM_RDE_START) ||
++		    (ret_transfer_flag == PLDM_RDE_MIDDLE)) {
++			// Call the callback method to send back response
++			// payload to requester
++			callback(manager, ctx, &payload, data_length_bytes,
++				 false);
++			ctx->next_command = PLDM_RDE_MULTIPART_RECEIVE;
++			ctx->current_pdr_resource->transfer_operation =
++			    PLDM_XFER_NEXT_PART;
++			ctx->current_pdr_resource->transfer_handle =
++			    ret_data_transfer_handle;
++			ctx->requester_status =
++			    PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
++		} else if ((ret_transfer_flag == PLDM_RDE_START_AND_END) ||
++			   (ret_transfer_flag == PLDM_RDE_END)) {
++			callback(manager, ctx, &payload, data_length_bytes,
++				 true);
++			// find the next resource id from the resource id array
++			// if exists
++			set_next_dictionary_index(manager, ctx);
++		}
++		ctx->context_status = CONTEXT_FREE;
++		return PLDM_RDE_REQUESTER_SUCCESS;
++	}
++	}
++	return rc;
++}
+diff --git a/tests/requester/rde_requester_test.cpp b/tests/requester/rde_requester_test.cpp
+index efa4113..f6f80e6 100644
+--- a/tests/requester/rde_requester_test.cpp
++++ b/tests/requester/rde_requester_test.cpp
+@@ -164,6 +164,7 @@ TEST(StartRDEDiscoverySuccess, RDEDiscoveryTest)
+         TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
+         &resource_ids.front(), allocate_memory_to_contexts, free_memory);
+ 
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+     struct pldm_rde_requester_context base_context = rde_contexts[0];
+ 
+     rc = pldm_rde_start_discovery(&base_context);
+@@ -182,7 +183,7 @@ TEST(StartRDEDiscoveryFailure, RDEDiscoveryTest)
+         TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
+         TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
+         &resource_ids.front(), allocate_memory_to_contexts, free_memory);
+-
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+     struct pldm_rde_requester_context base_context = rde_contexts[0];
+ 
+     base_context.context_status = CONTEXT_BUSY;
+@@ -200,7 +201,7 @@ TEST(CreateRequesterContextSuccess, RDEDiscoveryTest)
+         TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
+         TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
+         &resource_ids.front(), allocate_memory_to_contexts, free_memory);
+-
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+     struct pldm_rde_requester_context* current_ctx =
+         new pldm_rde_requester_context();
+     rc = pldm_rde_create_context(current_ctx);
+@@ -223,7 +224,7 @@ TEST(CreateRequesterContextFailure, RDEDiscoveryTest)
+         TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
+         TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
+         &resource_ids.front(), allocate_memory_to_contexts, free_memory);
+-
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+     struct pldm_rde_requester_context* current_ctx = NULL;
+     rc = pldm_rde_create_context(current_ctx);
+ 
+@@ -257,7 +258,7 @@ TEST(GetNextRequestInSequenceSuccess, PLDMRDEDiscovery)
+         TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
+         TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
+         &resource_ids.front(), allocate_memory_to_contexts, free_memory);
+-
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+     struct pldm_rde_requester_context* base_context =
+         new pldm_rde_requester_context();
+     rc = pldm_rde_create_context(base_context);
+@@ -281,7 +282,7 @@ TEST(GetNextRequestInSequenceFailure, PLDMRDEDiscovery)
+         TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
+         TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
+         &resource_ids.front(), allocate_memory_to_contexts, free_memory);
+-
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+     struct pldm_rde_requester_context* base_context =
+         new pldm_rde_requester_context();
+     rc = pldm_rde_create_context(base_context);
+@@ -300,7 +301,7 @@ TEST(PushDiscoveryResponseRedfishParamSuccess, PLDMRDEDiscovery)
+         TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
+         TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
+         &resource_ids.front(), allocate_memory_to_contexts, free_memory);
+-
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+     struct pldm_rde_requester_context* base_context =
+         new pldm_rde_requester_context();
+     rc = pldm_rde_create_context(base_context);
+@@ -355,7 +356,7 @@ TEST(PushDiscoveryResponseRedfishMediumParamSuccess, PLDMRDEDiscovery)
+         TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
+         TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
+         &resource_ids.front(), allocate_memory_to_contexts, free_memory);
+-
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+     struct pldm_rde_requester_context* base_context =
+         new pldm_rde_requester_context();
+     rc = pldm_rde_create_context(base_context);
+@@ -395,7 +396,7 @@ TEST(PushDiscoveryResponseFailure, PLDMRDEDiscovery)
+         TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
+         TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
+         &resource_ids.front(), allocate_memory_to_contexts, free_memory);
+-
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+     struct pldm_rde_requester_context* base_context =
+         new pldm_rde_requester_context();
+     rc = pldm_rde_create_context(base_context);
+@@ -408,3 +409,213 @@ TEST(PushDiscoveryResponseFailure, PLDMRDEDiscovery)
+ 
+     EXPECT_EQ(rc, PLDM_RDE_REQUESTER_NO_NEXT_COMMAND_FOUND);
+ }
++
++TEST(InitDictionarySchemaSuccess, RDEDictionaryExtraction)
++{
++    initial_setup();
++    struct pldm_rde_requester_manager* manager =
++        new pldm_rde_requester_manager();
++
++    int rc = pldm_rde_init_context(
++        TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
++        TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
++        &resource_ids.front(), allocate_memory_to_contexts, free_memory);
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
++    struct pldm_rde_requester_context* base_context =
++        new pldm_rde_requester_context();
++    rc = pldm_rde_create_context(base_context);
++
++    rc = pldm_rde_init_get_dictionary_schema(base_context);
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++    EXPECT_EQ(base_context->current_pdr_resource->schema_class,
++              PLDM_RDE_SCHEMA_MAJOR);
++}
++
++TEST(InitDictionarySchemaFailure, RDEDictionaryExtraction)
++{
++    initial_setup();
++    struct pldm_rde_requester_manager* manager =
++        new pldm_rde_requester_manager();
++
++    int rc = pldm_rde_init_context(
++        TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
++        TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
++        &resource_ids.front(), allocate_memory_to_contexts, free_memory);
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
++    struct pldm_rde_requester_context* base_context =
++        new pldm_rde_requester_context();
++    base_context->context_status = CONTEXT_BUSY;
++
++    rc = pldm_rde_init_get_dictionary_schema(base_context);
++    EXPECT_EQ(rc, PLDM_RDE_CONTEXT_INITIALIZATION_ERROR);
++}
++
++TEST(GetNextDictionarySchemaSuccess, RDEDictionaryExtraction)
++{
++    initial_setup();
++    struct pldm_rde_requester_manager* manager =
++        new pldm_rde_requester_manager();
++
++    int rc = pldm_rde_init_context(
++        TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
++        TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
++        &resource_ids.front(), allocate_memory_to_contexts, free_memory);
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
++    struct pldm_rde_requester_context* base_context =
++        new pldm_rde_requester_context();
++    rc = pldm_rde_create_context(base_context);
++
++    rc = pldm_rde_init_get_dictionary_schema(base_context);
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++
++    int requestBytes = 0;
++    if (rde_command_request_size.find(base_context->next_command) !=
++        rde_command_request_size.end())
++    {
++        requestBytes = rde_command_request_size[base_context->next_command];
++    }
++    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + requestBytes);
++    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
++    rc = pldm_rde_get_next_dictionary_schema_command(TEST_INSTANCE_ID, manager,
++                                                     base_context, request);
++
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++}
++
++TEST(GetNextDictionarySchemaFailure, RDEDictionaryExtraction)
++{
++    initial_setup();
++    struct pldm_rde_requester_manager* manager =
++        new pldm_rde_requester_manager();
++
++    int rc = pldm_rde_init_context(
++        TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
++        TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
++        &resource_ids.front(), allocate_memory_to_contexts, free_memory);
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
++    struct pldm_rde_requester_context* base_context =
++        new pldm_rde_requester_context();
++    rc = pldm_rde_create_context(base_context);
++
++    base_context->next_command = 0x23;
++
++    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
++    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
++    rc = pldm_rde_get_next_dictionary_schema_command(TEST_INSTANCE_ID, manager,
++                                                     base_context, request);
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_ENCODING_REQUEST_FAILURE);
++}
++
++TEST(MultipartReceiveSuccess, RDEDictionaryExtraction)
++{
++    initial_setup();
++    struct pldm_rde_requester_manager* manager =
++        new pldm_rde_requester_manager();
++
++    int rc = pldm_rde_init_context(
++        TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
++        TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
++        &resource_ids.front(), allocate_memory_to_contexts, free_memory);
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
++    struct pldm_rde_requester_context* base_context =
++        new pldm_rde_requester_context();
++    rc = pldm_rde_create_context(base_context);
++
++    rc = pldm_rde_init_get_dictionary_schema(base_context);
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++
++    base_context->next_command = PLDM_RDE_MULTIPART_RECEIVE;
++    base_context->current_pdr_resource->transfer_handle = 0x00;
++
++    int requestBytes = 0;
++    if (rde_command_request_size.find(base_context->next_command) !=
++        rde_command_request_size.end())
++    {
++        requestBytes = rde_command_request_size[base_context->next_command];
++    }
++    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + requestBytes);
++    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
++
++    rc = pldm_rde_get_next_dictionary_schema_command(TEST_INSTANCE_ID, manager,
++                                                     base_context, request);
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++}
++void dummy_callback(struct pldm_rde_requester_manager* manager,
++                    struct pldm_rde_requester_context* ctx, uint8_t** payload,
++                    uint32_t payload_length, bool has_checksum)
++{
++    IGNORE(manager);
++    IGNORE(ctx);
++    IGNORE(payload);
++    IGNORE(payload_length);
++    IGNORE(has_checksum);
++}
++TEST(PushResponseForGetDictionarySchema, RDEDictionaryExtraction)
++{
++    initial_setup();
++    struct pldm_rde_requester_manager* manager =
++        new pldm_rde_requester_manager();
++
++    int rc = pldm_rde_init_context(
++        TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
++        TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
++        &resource_ids.front(), allocate_memory_to_contexts, free_memory);
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
++    struct pldm_rde_requester_context* base_context =
++        new pldm_rde_requester_context();
++    rc = pldm_rde_create_context(base_context);
++
++    rc = pldm_rde_init_get_dictionary_schema(base_context);
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++
++    std::vector<uint8_t> response(sizeof(pldm_msg_hdr) + 6, 0);
++    uint8_t* responseMsg = response.data();
++    size_t responseMsgSize = sizeof(pldm_msg_hdr) + 6;
++    auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
++
++    rc = encode_get_schema_dictionary_resp(TEST_INSTANCE_ID,
++                                           /*cc*/ 0,
++                                           /* dictionary_format*/ 0x00,
++                                           /*transfer_handle*/ 0x00,
++                                           responsePtr);
++
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++    rc = pldm_rde_push_get_dictionary_response(
++        manager, base_context, responsePtr, responseMsgSize, dummy_callback);
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++}
++
++TEST(PushResponseForMultipartReceive, RDEDictionaryExtraction)
++{
++    initial_setup();
++    struct pldm_rde_requester_manager* manager =
++        new pldm_rde_requester_manager();
++
++    int rc = pldm_rde_init_context(
++        TEST_DEV_ID.c_str(), TEST_NET_ID, manager, TEST_MC_CONCURRENCY,
++        TEST_MC_TRANSFER_SIZE, TEST_MC_FEATURES, TEST_NUMBER_OF_RESOURCES,
++        &resource_ids.front(), allocate_memory_to_contexts, free_memory);
++    EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
++    struct pldm_rde_requester_context* base_context =
++        new pldm_rde_requester_context();
++    rc = pldm_rde_create_context(base_context);
++
++    rc = pldm_rde_init_get_dictionary_schema(base_context);
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++
++    base_context->next_command = PLDM_RDE_MULTIPART_RECEIVE;
++    std::vector<uint8_t> response(sizeof(pldm_msg_hdr) + 20, 0);
++    uint8_t* responseMsg = response.data();
++    size_t responseMsgSize = sizeof(pldm_msg_hdr) + 20;
++    auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
++
++    uint8_t payload[] = {2, 3, 4};
++    rc = encode_rde_multipart_receive_resp(
++        TEST_INSTANCE_ID, /*completion_code*/ 0, /*transfer_flag*/ 0x00,
++        /*next_data_transfer_handle*/ 0x00, /*data_length_bytes*/ 8,
++        /*add_checksum*/ false, /*checksum*/ 0x00, &payload[0], responsePtr);
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++    rc = pldm_rde_push_get_dictionary_response(
++        manager, base_context, responsePtr, responseMsgSize, dummy_callback);
++    EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
++}
+-- 
+2.42.0.rc1.204.g551eb34607-goog
+
diff --git a/recipes-phosphor/libpldm/libpldm_%.bbappend b/recipes-phosphor/libpldm/libpldm_%.bbappend
index 16212aa..f69e24b 100644
--- a/recipes-phosphor/libpldm/libpldm_%.bbappend
+++ b/recipes-phosphor/libpldm/libpldm_%.bbappend
@@ -7,4 +7,5 @@
     file://0002-Add-support-for-network-id-in-pldm_send-and-pldm_rec.patch \
     file://0003-Add-encoders-and-decoders-for-RDE-support.patch \
     file://0004-Add-support-for-RDE-Discovery-Negotiate-and-Medium-p.patch \
+    file://0005-Add-support-for-dictionary-extraction-for-resources.patch \
 "