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