libpldm: Add patches to support Redfish PDR encoding/decoding
This CL adds support for platfrom requester to send Platfrom type
command to RDE device. Additonally it adds APIs for GetPDR command
and Redfish Resource PDR support.
Add encoders/decoders to dynamically encode/decode
the Redfish Resources in PLDM response message.
Also add unit tests for all the the encoder/decoder
APIs
Design Doc : go/redfish-pdr-support
Tested: All the unit tests pass.. Ran the complete minibmc weekly
tests workflow including the rde soak tests. All tests passed
successfully. Verified that the platform requester is able to
handle PDR commands.
Fusion-Link: https://fusion2.corp.google.com/c0e4c574-b87b-3184-a2fa-1bec790cdf41
Platforms-Affected: platform6
Google-Bug-Id: 344955303
Google-Bug-Id: 344954307
Google-Bug-Id: 341389794
Google-Bug-Id: 341389695
Google-Bug-Id: 286465868
Change-Id: I481d27e77f959173ea821cc9f77008eebfcc3fed
Signed-off-by: Nikhil Namjoshi <nikhilnamjoshi@google.com>
diff --git a/recipes-phosphor/libpldm/libpldm/0010-Add-support-platform-requester-type-command-support.patch b/recipes-phosphor/libpldm/libpldm/0010-Add-support-platform-requester-type-command-support.patch
new file mode 100644
index 0000000..4bb5234
--- /dev/null
+++ b/recipes-phosphor/libpldm/libpldm/0010-Add-support-platform-requester-type-command-support.patch
@@ -0,0 +1,1115 @@
+From 2758e6b53c0db18d501468f6ffdc8a8f623576d0 Mon Sep 17 00:00:00 2001
+From: Nikhil Namjoshi <nikhilnamjoshi@google.com>
+Date: Wed, 29 May 2024 04:51:54 +0000
+Subject: [PATCH 1/2] Add support platform requester type command support
+
+This CL adds support for platfrom requester to send Platform type
+command to RDE device. Additonally it adds APIs for GetPDR command
+and Redfish Resource PDR support
+
+Tested: Ran the complete minibmc weekly tests workflow
+including the rde soak tests. All tests passed successfully.
+Verified that the platform requester is able to handle PDR
+commands.
+
+Fusion-Link: https://fusion2.corp.google.com/c8be2eaa-dfd9-322e-965d-fb2fe908a678
+
+Patch Tracking Bug: b/344954307
+Upstream info / review:
+Upstream-Status: Pending
+Justification:
+
+There is dependency on upstreaming rded first, followed by other libpldm
+command support like OperationInit, Operation,Status, OperationComplete
+and OperationKill. We could not reach consensus with the upstream to have
+platform requester code in libpldm.
+
+Google-Bug-Id: 341389695
+Google-Bug-Id: 286465868
+Change-Id: I3663ec68bee3871fca64bc2f6ee4062b877e366f
+Signed-off-by: Nikhil Namjoshi <nikhilnamjoshi@google.com>
+---
+ include/libpldm/meson.build | 1 +
+ include/libpldm/platform.h | 121 +++++++
+ .../requester/pldm_platform_requester.h | 181 ++++++++++
+ .../libpldm/requester/pldm_rde_requester.h | 41 ++-
+ src/platform.c | 317 ++++++++++++++++++
+ src/requester/meson.build | 3 +-
+ src/requester/pldm_platform_requester.c | 213 ++++++++++++
+ src/requester/pldm_rde_requester.c | 36 +-
+ 8 files changed, 890 insertions(+), 23 deletions(-)
+ create mode 100644 include/libpldm/requester/pldm_platform_requester.h
+ create mode 100644 src/requester/pldm_platform_requester.c
+
+diff --git a/include/libpldm/meson.build b/include/libpldm/meson.build
+index e2e3bb3..ec90b8b 100644
+--- a/include/libpldm/meson.build
++++ b/include/libpldm/meson.build
+@@ -19,6 +19,7 @@ libpldm_headers = files(
+ 'requester/pldm_base_requester.h',
+ 'pldm_rde.h',
+ 'requester/pldm_rde_requester.h',
++ 'requester/pldm_platform_requester.h',
+ )
+
+ if get_option('oem-ibm').allowed()
+diff --git a/include/libpldm/platform.h b/include/libpldm/platform.h
+index a2c001c..ce91af8 100644
+--- a/include/libpldm/platform.h
++++ b/include/libpldm/platform.h
+@@ -89,6 +89,8 @@ extern "C" {
+ #define PLDM_STR_UTF_8_MAX_LEN 256
+ #define PLDM_STR_UTF_16_MAX_LEN 256
+
++#define PLDM_EXTERNAL_RESOURCE_ID 0x00000000U
++
+ enum pldm_effecter_data_size {
+ PLDM_EFFECTER_DATA_SIZE_UINT8,
+ PLDM_EFFECTER_DATA_SIZE_SINT8,
+@@ -1125,6 +1127,27 @@ struct pldm_get_sensor_reading_resp {
+ uint8_t present_reading[1];
+ } __attribute__((packed));
+
++struct pldm_platform_redfish_resource_uri_data {
++ // Length includes null terminator
++ uint16_t sub_uri_length;
++ char sub_uri[1];
++} __attribute__((packed));
++
++struct pldm_platform_additional_redfish_resource_pdr_data {
++ uint32_t resource_id;
++ struct pldm_platform_redfish_resource_uri_data uri_data;
++} __attribute__((packed));
++
++struct pldm_platform_redfish_resource_pdr_data {
++ uint32_t resource_id;
++ uint8_t resource_flags;
++ uint32_t containing_resource_id;
++ // Length includes null terminator
++ uint16_t proposed_containing_resource_length;
++ char proposed_containing_resource_name[1];
++
++} __attribute__((packed));
++
+ /* Responder */
+
+ /* SetNumericEffecterValue */
+@@ -1230,6 +1253,52 @@ int encode_get_pdr_resp(uint8_t instance_id, uint8_t completion_code,
+ uint16_t resp_cnt, const uint8_t *record_data,
+ uint8_t transfer_crc, struct pldm_msg *msg);
+
++/**
++ * @brief API to add the metadata and first Redfish
++ * resource to GetPDR response
++ *
++ * @param[in] pdr_header_ver - PDR Header version
++ * @param[in] record_handle - Record Handle for the given PDR
++ * @param[in] resource_id - First Resource Id to be added
++ * @param[in] record_change_num - Record change number of the changed PDR
++ * @param[in] sub_uri - Sub uri string
++ * @param[in] is_redfish_resource_root - Flag to indicate if it is a root
++ * resource
++ * @param[in] is_redfish_resource_collection - Flag to indicate if the resource is
++ * a collection
++ * @param[in] is_redfish_resource_contained_in_collection - Flag to indicate
++ * if the resource is contained in a collection
++ * @param[in] containing_resource_id - Resource Id of the containing
++ * resource
++ * @param[in] proposed_containing_resource_name - Proposed containing resource name
++ * @param[in] additional_resource_count - Additional resource count in the Redfish
++ * PDR
++ * @param[out] msg Pointer to PLDM msg container
++ */
++
++int add_redfish_pdr_to_encoded_get_pdr_resp(
++ uint8_t pdr_header_ver, uint32_t record_handle, uint32_t resource_id,
++ uint16_t record_change_num, const char *sub_uri,
++ uint8_t is_redfish_resource_root,
++ uint8_t is_redfish_resource_collection,
++ uint8_t is_redfish_resource_contained_in_collection,
++ uint32_t containing_resource_id,
++ const char *proposed_containing_resource_name,
++ uint16_t additional_resource_count, struct pldm_msg *msg);
++
++/**
++ * @brief API to add additional Redfish resource
++ * to GetPDR response
++ *
++ * @param[in] sub_resource_id - Additional Resource Id to be added
++ * @param[in] sub_resource_uri - Sub resource uri string
++ * @param[out] msg - Pointer to PLDM msg container
++ * @param[in] max_pdr_msg_bytes - Max PDR message bytes
++ */
++int add_additional_redfish_resource_to_encoded_get_pdr_resp(
++ uint32_t sub_resource_id, const char *sub_resource_uri,
++ struct pldm_msg *msg, uint32_t max_pdr_msg_bytes);
++
+ /** @brief Decode GetPDR request data
+ *
+ * @param[in] msg - Request message
+@@ -1488,6 +1557,58 @@ int decode_get_pdr_resp(const struct pldm_msg *msg, size_t payload_length,
+ uint8_t *record_data, size_t record_data_length,
+ uint8_t *transfer_crc);
+
++/** @brief Decode GetPDR header and record data bytes
++ *
++ * @param[in] record_data - Array of PDR record bytes
++ * @param[in] record_length - Total length of record
++ * @param[in] expected_pdr_header_version - Expected PDR header version
++ * @param[out] record_handle - Memory to store the record handle of the PDR
++ * @param[out] record_change_number - Memory to store the record change number
++ * @param[out] actual_pdr_byte_count - Memory to store the actual pdr byte count
++ * @return pldm_completion_codes
++ */
++int decode_pdr_header_and_get_record_data(uint8_t *record_data,
++ uint16_t record_length,
++ uint8_t expected_pdr_header_version,
++ uint32_t *record_handle,
++ uint32_t *record_change_number,
++ uint16_t *actual_pdr_byte_count);
++
++/** @brief Decode PDR metadata and first redfish resource from PDR record data bytes
++ *
++ * @param[in] record_data - Array of PDR record bytes
++ * @param[out] resource_id - Memory to store the first resource id
++ * @param[out] resource_flags - Memory to store the resource flags
++ * @param[out] containing_resource_id - Memory to store the containing resource id
++ * @param[out] proposed_containing_resource_length - Memory to store the containing
++ * resource name length
++ * @param[out] proposed_containing_resource_name - Memory to store the containing
++ * resource name
++ * @param[out] resource_uri_length - Memory to store the resource uri length
++ * @param[out] resource_uri - Memory to store the resource uri name
++ * @param[out] additional_resource_id_count - Memory to store additional resource id count
++ * @return pldm_completion_codes
++ */
++int get_redfish_pdr_from_decoded_get_pdr_resp(
++ uint8_t *record_data, uint32_t *resource_id, uint8_t *resource_flags,
++ uint32_t *containing_resource_id,
++ uint16_t *proposed_containing_resource_length,
++ char **proposed_containing_resource_name, uint16_t *resource_uri_length,
++ char **resource_uri, uint16_t *additional_resource_id_count);
++
++/** @brief Decode additional redfish resource from PDR record data bytes
++ *
++ * @param[in] record_data - Array of PDR record bytes
++ * @param[in] resource_index - The additional resource index to decode
++ * @param[out] resource_id - Memory to store the first resource id
++ * @param[out] resource_uri_length - Memory to store the resource uri length
++ * @param[out] resource_uri - Memory to store the resource uri name
++ * @return pldm_completion_codes
++ */
++int get_additional_redfish_resource_from_decoded_get_pdr_resp(
++ uint8_t *record_data, uint16_t resource_index, uint32_t *resource_id,
++ uint16_t *resource_uri_length, char **resource_uri);
++
+ /* SetStateEffecterStates */
+
+ /** @brief Create a PLDM request message for SetStateEffecterStates
+diff --git a/include/libpldm/requester/pldm_platform_requester.h b/include/libpldm/requester/pldm_platform_requester.h
+new file mode 100644
+index 0000000..dc83a83
+--- /dev/null
++++ b/include/libpldm/requester/pldm_platform_requester.h
+@@ -0,0 +1,181 @@
++#ifndef PLDM_PLATFORM_REQUESTER_H
++#define PLDM_PLATFORM_REQUESTER_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include "libpldm/base.h"
++#include "libpldm/platform.h"
++#include "libpldm/requester/pldm_base_requester.h"
++
++/**
++ * @brief Platform Requester Error enums
++ */
++typedef enum platform_requester_return_codes {
++ PLDM_PLATFORM_REQUESTER_SUCCESS = 0,
++ PLDM_PLATFORM_REQUESTER_NOT_PLDM_PLATFORM_MSG = -1,
++ PLDM_PLATFORM_REQUESTER_NOT_RESP_MSG = -2,
++ PLDM_PLATFORM_REQUESTER_SEND_FAIL = -3,
++ PLDM_PLATFORM_REQUESTER_RECV_FAIL = -4,
++ PLDM_PLATFORM_REQUESTER_NO_NEXT_COMMAND_FOUND = -5,
++ PLDM_PLATFORM_REQUESTER_ENCODING_REQUEST_FAILURE = -6,
++ PLDM_PLATFORM_REQUESTER_DECODING_RESPONSE_FAILURE = -7,
++ PLDM_PLATFORM_REQUESTER_IO_FAILURE = -8,
++ PLDM_PLATFORM_CONTEXT_INITIALIZATION_ERROR = -9,
++ PLDM_PLATFORM_CONTEXT_NOT_READY = -10,
++
++} pldm_platform_requester_rc_t;
++
++/**
++ * @brief Platform Requester Status enums
++ */
++typedef enum platform_requester_status {
++ PLDM_PLATFORM_REQUESTER_REQUEST_FAILED = -1,
++ PLDM_PLATFORM_REQUESTER_READY_TO_PICK_NEXT_REQUEST = 0,
++ PLDM_PLATFORM_REQUESTER_WAITING_FOR_RESPONSE = 1,
++ PLDM_PLATFORM_REQUESTER_NO_PENDING_ACTION = 2
++} platform_req_status_t;
++
++/**
++ * @brief Platform Requester context
++ */
++struct pldm_platform_requester_context {
++ bool initialized;
++ int next_command;
++ uint8_t requester_status;
++ void *operation_ctx;
++
++ char device_name[8];
++ int net_id;
++ uint32_t negotiated_transfer_size;
++};
++
++/**
++ * @brief Get PDR operation context
++ */
++struct pldm_platform_get_pdr_operation {
++ uint32_t record_handle;
++ uint32_t data_transfer_handle;
++ uint8_t transfer_op_flag;
++ uint16_t record_change_num;
++ uint16_t request_count;
++};
++
++/**
++ * @brief Initializes the context for PLDM Platform commands
++ *
++ * @param[inout] ctx - Platform requester context
++ * @param[in] device_id - RDE Device ID String
++ * @param[in] net_id - Network ID to distinguish between RDE Devices
++ * @param[in] mc_transfer_size - Negotiated Transfer Size for the PLDM message
++ *
++ * @return pldm_platform_requester_rc_t (errno may be set)
++ */
++pldm_platform_requester_rc_t pldm_platform_init_context(
++ struct pldm_platform_requester_context *ctx, const char *device_id,
++ int net_id, uint32_t negotiated_transfer_size);
++
++/**
++ * @brief Initializes the Platform Operation context
++ *
++ * @param[inout] ctx - Platform requester context
++ * @param[in] get_pdr_ctx - Platform Operation context
++ *
++ * @return pldm_platform_requester_rc_t (errno may be set)
++ */
++pldm_platform_requester_rc_t pldm_platform_init_get_pdr_operation_context(
++ struct pldm_platform_requester_context *ctx,
++ struct pldm_platform_get_pdr_operation *get_pdr_ctx);
++
++/**
++ * @brief Sets up the state machine for starting PDR discovery
++ *
++ * @param[inout] ctx - Platform requester context
++ *
++ * @return pldm_platform_requester_rc_t (errno may be set)
++ */
++pldm_platform_requester_rc_t pldm_platform_start_pdr_discovery(
++ struct pldm_platform_requester_context *ctx);
++
++/**
++ * @brief Gets the next GetPDR request
++ *
++ * @param[inout] ctx - Platform requester context
++ * @param[in] instance_id - Instance Id of the PLDM message
++ * @param[inout] request - PLDM Request
++ * @param[in] request_length - Max request length
++ *
++ * @return pldm_platform_requester_rc_t (errno may be set)
++ */
++pldm_platform_requester_rc_t pldm_platform_get_next_get_pdr_request(
++ struct pldm_platform_requester_context *ctx, uint8_t instance_id,
++ struct pldm_msg *request, size_t request_length);
++
++/**
++ * @brief Pushes the response values to the context of the PLDM_PLATFORM type
++ * command that was executed and updates the command status. It alse sets
++ * the next_command attribute of the context based on the last executed
++ * command.
++ *
++ * @param[inout] ctx - Platform requester context
++ * @param[inout] resp_msg - Platform PLDM message
++ * @param[in] resp_size - Max response length
++ * @param[in] expected_pdr_header_version - Expected PDR Header version
++ * @param[inout] record_data - PDR record data
++ * @param[in] record_data_length - PDR record data length
++ * @param[out] is_record_data_complete - Flag to indicate if the PDR data
++ * part received marks the complete PDR transfer
++ *
++ * @return pldm_platform_requester_rc_t (errno may be set)
++ */
++pldm_platform_requester_rc_t pldm_platform_push_get_pdr_response(
++ struct pldm_platform_requester_context *ctx, void *resp_msg,
++ size_t resp_size, uint8_t expected_pdr_header_version, uint8_t *record_data,
++ size_t record_data_length, bool *is_record_data_complete);
++
++/**
++ * @brief Decodes the PDR record metadata and the first PDR resource data
++ *
++ * @param[in] record_data - PDR record data
++ * @param[out] resource_id - Memory to store resource ID
++ * @param[out] resource_flags - Memory to store resource flags
++ * @param[out] containing_resource_id - Memory to store containing resource ID
++ * @param[out] proposed_containing_resource_length - Memory to store containing
++ * resource name length
++ * @param[out] proposed_containing_resource_name - Memory to store containing
++ * resource name
++ * @param[out] resource_uri_length - Memory to store first resource uri length
++ * @param[out] resource_uri - Memory to store the resource uri
++ * @param[out] additional_resource_id_count - Memory to store the additional
++ * resource count in the PDR
++ *
++ * @return pldm_platform_requester_rc_t (errno may be set)
++ */
++pldm_platform_requester_rc_t pldm_platform_decode_first_pdr_resource(
++ uint8_t *record_data, uint32_t *resource_id, uint8_t *resource_flags,
++ uint32_t *containing_resource_id,
++ uint16_t *proposed_containing_resource_length,
++ char **proposed_containing_resource_name, uint16_t *resource_uri_length,
++ char **resource_uri, uint16_t *additional_resource_id_count);
++
++/**
++ * @brief Decodes the additional PDR resource data
++ *
++ * @param[in] record_data - PDR record data
++ * @param[in] resource_index - Additional resource index
++ * @param[out] resource_id - Memory to store resource ID
++ * @param[out] resource_uri_length - Memory to store first resource uri length
++ * @param[out] resource_uri - Memory to store the resource uri
++ *
++ * @return pldm_platform_requester_rc_t (errno may be set)
++ */
++pldm_platform_requester_rc_t pldm_platform_decode_additional_pdr_resource(
++ uint8_t *record_data, uint16_t resource_index, uint32_t *resource_id,
++ uint16_t *resource_uri_length, char **resource_uri);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* PLDM_RDE_REQUESTER_H */
+diff --git a/include/libpldm/requester/pldm_rde_requester.h b/include/libpldm/requester/pldm_rde_requester.h
+index 92ced28..2e73806 100644
+--- a/include/libpldm/requester/pldm_rde_requester.h
++++ b/include/libpldm/requester/pldm_rde_requester.h
+@@ -209,10 +209,6 @@ typedef void (*callback_funct)(struct pldm_rde_requester_manager *manager,
+ * @param[in] mc_concurrency - Concurrency supported by MC
+ * @param[in] mc_transfer_size - Transfer Size of MC
+ * @param[in] mc_features - Pointer to MC Features
+- * @param[in] number_of_resources - Number of resources supported (until PDR is
+- * implemented)
+- * @param[in] resource_id_address - The initial resource id index to begin
+- * Discovery
+ * @param[in] alloc_requester_ctx - Pointer to a function to allocated contexts
+ * for a RDE device
+ * @param[in] free_requester_ctx - Pointer to a function that frees allocated
+@@ -224,14 +220,29 @@ pldm_rde_requester_rc_t
+ pldm_rde_init_context(const char *device_id, int net_id,
+ struct pldm_rde_requester_manager *manager,
+ uint8_t mc_concurrency, uint32_t mc_transfer_size,
+- bitfield16_t *mc_features, uint8_t number_of_resources,
+- uint32_t *resource_id_address,
++ bitfield16_t *mc_features,
+ struct pldm_rde_requester_context *(*alloc_requester_ctx)(
+- uint8_t number_of_ctx),
++ uint8_t number_of_ctx),
+
+ // Callback function to clean any context memory
+ void (*free_requester_ctx)(void *ctx_memory));
+
++/**
++ * @brief Sets the context with resource IDs discovered in the PDR
++ *
++ * @param[in] manager - Pointer to Context Manager
++ * @param[in] number_of_resources - Number of resources supported (until PDR is
++ * implemented)
++ * @param[in] resource_id_address - The initial resource id index to begin
++ * Discovery
++ *
++ * @return pldm_requester_rc_t (errno may be set)
++*/
++pldm_rde_requester_rc_t
++pldm_rde_set_resources_in_context(struct pldm_rde_requester_manager *manager,
++ uint8_t number_of_resources,
++ uint32_t *resource_id_address);
++
+ /**
+ * @brief Sets the first command to be triggered for base discovery and sets
+ * the status of context to "Ready to PICK
+@@ -274,8 +285,9 @@ pldm_rde_discovery_push_response(struct pldm_rde_requester_manager *manager,
+ * @return pldm_requester_rc_t (errno may be set)
+ */
+ pldm_rde_requester_rc_t pldm_rde_get_next_discovery_command(
+- uint8_t instance_id, struct pldm_rde_requester_manager *manager,
+- struct pldm_rde_requester_context *current_ctx, struct pldm_msg *request);
++ uint8_t instance_id, struct pldm_rde_requester_manager *manager,
++ struct pldm_rde_requester_context *current_ctx,
++ struct pldm_msg *request);
+
+ /**
+ * @brief Creates the RDE context required for RDE operation. Sets the initial
+@@ -312,8 +324,9 @@ pldm_rde_init_get_dictionary_schema(struct pldm_rde_requester_context *ctx);
+ * @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);
++ 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
+@@ -329,9 +342,9 @@ pldm_rde_requester_rc_t pldm_rde_get_next_dictionary_schema_command(
+ * @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);
++ struct pldm_rde_requester_manager *manager,
++ struct pldm_rde_requester_context *ctx, void *resp_msg,
++ size_t resp_size, callback_funct callback);
+
+ /**
+ * @brief Initialize RDE operation context for performing any RDE operation
+diff --git a/src/platform.c b/src/platform.c
+index 1bd7889..edbb568 100644
+--- a/src/platform.c
++++ b/src/platform.c
+@@ -10,6 +10,7 @@
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <stdio.h>
+
+ static int pldm_platform_pdr_hdr_validate(struct pldm_value_pdr_hdr *ctx,
+ size_t lower, size_t upper)
+@@ -372,6 +373,181 @@ int encode_get_pdr_resp(uint8_t instance_id, uint8_t completion_code,
+ return PLDM_SUCCESS;
+ }
+
++LIBPLDM_ABI_STABLE
++int add_redfish_pdr_to_encoded_get_pdr_resp(
++ uint8_t pdr_header_ver,
++ uint32_t record_handle,
++ uint32_t resource_id,
++ uint16_t record_change_num,
++ const char* sub_uri,
++ uint8_t is_redfish_resource_root,
++ uint8_t is_redfish_resource_collection,
++ uint8_t is_redfish_resource_contained_in_collection,
++ uint32_t containing_resource_id,
++ const char* proposed_containing_resource_name,
++ uint16_t additional_resource_count,
++ struct pldm_msg *msg)
++{
++ if ((msg == NULL) || (sub_uri == NULL) || (proposed_containing_resource_name == NULL)) {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ if (is_redfish_resource_root)
++ {
++ if (containing_resource_id != PLDM_EXTERNAL_RESOURCE_ID)
++ {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ // If the containing resource is EXTERNAL, we expect a non-NULL byte
++ if (strcmp(proposed_containing_resource_name, "\0") == 0)
++ {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++ } else {
++ // If the containing resource is not EXTERNAL, we expect a NULL byte
++ if (strcmp(proposed_containing_resource_name, "\0") != 0)
++ {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++ }
++
++ struct pldm_get_pdr_resp *response =
++ (struct pldm_get_pdr_resp *)msg->payload;
++
++ struct pldm_platform_redfish_resource_pdr_data* redfish_pdr_data
++ = (struct pldm_platform_redfish_resource_pdr_data*)
++ ((uint8_t*)response->record_data + sizeof(struct pldm_pdr_hdr));
++
++ redfish_pdr_data->resource_id = htole32(resource_id);
++ redfish_pdr_data->resource_flags = 0;
++ redfish_pdr_data->resource_flags |= (is_redfish_resource_root << 0);
++ redfish_pdr_data->resource_flags |= (is_redfish_resource_collection << 1);
++ redfish_pdr_data->resource_flags |= (is_redfish_resource_contained_in_collection << 2);
++ redfish_pdr_data->containing_resource_id = htole32(containing_resource_id);
++
++ uint16_t proposed_containing_resource_length = strlen(proposed_containing_resource_name)
++ + 1 /* Include the NULL terminator */;
++ redfish_pdr_data->proposed_containing_resource_length = htole16(proposed_containing_resource_length);
++ memcpy(redfish_pdr_data->proposed_containing_resource_name,
++ proposed_containing_resource_name, proposed_containing_resource_length);
++
++ uint32_t redfish_pdr_data_size = sizeof(struct pldm_platform_redfish_resource_pdr_data) +
++ (uint32_t)proposed_containing_resource_length - sizeof(char);
++ struct pldm_platform_redfish_resource_uri_data* first_resource_data =
++ (struct pldm_platform_redfish_resource_uri_data*)
++ (redfish_pdr_data->proposed_containing_resource_name + proposed_containing_resource_length);
++
++ uint16_t sub_uri_length = strlen(sub_uri) + 1 /* Include the NULL terminator */;
++ first_resource_data->sub_uri_length = htole16(sub_uri_length);
++ memcpy(first_resource_data->sub_uri, sub_uri, sub_uri_length);
++
++ uint32_t first_resource_data_size = (uint32_t)sizeof(sub_uri_length) + (uint32_t)sub_uri_length;
++
++ uint16_t* additional_resource_id_count =
++ (uint16_t*)((uint8_t*)first_resource_data + first_resource_data_size);
++ additional_resource_count = htole16(additional_resource_count);
++ memcpy(additional_resource_id_count, &additional_resource_count, sizeof(additional_resource_count));
++
++ struct pldm_pdr_hdr* pdr_header = (struct pldm_pdr_hdr*) response->record_data;
++
++ pdr_header->record_handle = htole32(record_handle) ;
++ pdr_header->version = pdr_header_ver;
++ pdr_header->type = PLDM_REDFISH_RESOURCE_PDR;
++ pdr_header->record_change_num = htole16(record_change_num);
++ pdr_header->length =
++ htole16(redfish_pdr_data_size + first_resource_data_size +
++ sizeof(uint16_t) /*additional resource count size*/);
++
++ response->response_count = htole16((uint16_t)(sizeof(struct pldm_pdr_hdr) + le16toh(pdr_header->length)));
++
++ return PLDM_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++int add_additional_redfish_resource_to_encoded_get_pdr_resp(
++ uint32_t sub_resource_id,
++ const char* sub_resource_uri,
++ struct pldm_msg *msg,
++ uint32_t max_pdr_msg_bytes)
++{
++ if ((msg == NULL) || (sub_resource_uri == NULL)) {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ struct pldm_get_pdr_resp *response =
++ (struct pldm_get_pdr_resp *)msg->payload;
++
++ uint32_t total_pdr_bytes = (uint32_t)le16toh(response->response_count);
++
++ uint16_t sub_resource_uri_length = strlen(sub_resource_uri) + 1 /* Include the NULL terminator */;
++ uint32_t additonal_resource_pdr_data_size =
++ sizeof(struct pldm_platform_additional_redfish_resource_pdr_data) +
++ (uint32_t)sub_resource_uri_length - sizeof(char);
++
++ // Check if the next additional redfish resource fits in the response message
++ if ((total_pdr_bytes + additonal_resource_pdr_data_size) > max_pdr_msg_bytes)
++ {
++ return PLDM_ERROR_INVALID_LENGTH;
++ }
++
++ struct pldm_platform_redfish_resource_pdr_data* redfish_pdr_data
++ = (struct pldm_platform_redfish_resource_pdr_data*)
++ ((uint8_t*)response->record_data + sizeof(struct pldm_pdr_hdr));
++ uint32_t proposed_containing_resource_length = le16toh(redfish_pdr_data->proposed_containing_resource_length);
++
++ struct pldm_platform_redfish_resource_uri_data* first_resource_data =
++ (struct pldm_platform_redfish_resource_uri_data*)
++ (redfish_pdr_data->proposed_containing_resource_name + proposed_containing_resource_length);
++
++ uint16_t sub_uri_length = (uint32_t)le16toh(first_resource_data->sub_uri_length);
++ uint32_t first_resource_data_size = (uint32_t)sizeof(sub_uri_length) + (uint32_t)sub_uri_length;
++
++ uint16_t* additional_resource_id_count =
++ ((uint16_t*)((uint8_t*)first_resource_data + first_resource_data_size));
++ uint16_t additional_resource_count = htole16(le16toh(*additional_resource_id_count) + 1);
++ memcpy(additional_resource_id_count, &additional_resource_count, sizeof(additional_resource_count));
++
++ struct pldm_platform_additional_redfish_resource_pdr_data* additonal_resource_pdr_data =
++ (struct pldm_platform_additional_redfish_resource_pdr_data*)
++ ((uint8_t*)response->record_data + total_pdr_bytes);
++ additonal_resource_pdr_data->resource_id = htole32(sub_resource_id);
++ additonal_resource_pdr_data->uri_data.sub_uri_length = htole16(sub_resource_uri_length);
++ memcpy(additonal_resource_pdr_data->uri_data.sub_uri, sub_resource_uri, sub_resource_uri_length);
++
++ total_pdr_bytes += additonal_resource_pdr_data_size;
++
++ struct pldm_pdr_hdr* pdr_header = (struct pldm_pdr_hdr*)response->record_data;
++
++ pdr_header->length =
++ htole16(total_pdr_bytes - sizeof(struct pldm_pdr_hdr));
++
++
++ response->response_count = htole16(total_pdr_bytes);
++ return PLDM_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++int get_encoded_pdr_bytes_from_get_pdr_resp(
++ uint16_t* response_count,
++ struct pldm_msg *msg)
++{
++ if (msg == NULL) {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ if (response_count == NULL)
++ {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ struct pldm_get_pdr_resp *response =
++ (struct pldm_get_pdr_resp *)msg->payload;
++ *response_count = le16toh(response->response_count);
++
++ return PLDM_SUCCESS;
++}
++
+ LIBPLDM_ABI_STABLE
+ int encode_get_pdr_repository_info_resp(
+ uint8_t instance_id, uint8_t completion_code, uint8_t repository_state,
+@@ -552,6 +728,147 @@ int decode_get_pdr_resp(const struct pldm_msg *msg, size_t payload_length,
+ return pldm_msgbuf_destroy(buf);
+ }
+
++LIBPLDM_ABI_STABLE
++int decode_pdr_header_and_get_record_data(
++ uint8_t* record_data, uint16_t record_length,
++ uint8_t expected_pdr_header_version,
++ uint32_t* record_handle, uint32_t* record_change_number,
++ uint16_t* actual_pdr_byte_count)
++{
++ struct pldm_pdr_hdr* pdr_header = (struct pldm_pdr_hdr *)record_data;
++
++ if (expected_pdr_header_version != pdr_header->version)
++ {
++ return PLDM_ERROR;
++ }
++
++ if (pdr_header->type != PLDM_REDFISH_RESOURCE_PDR)
++ {
++ return PLDM_ERROR;
++ }
++
++ *actual_pdr_byte_count = le16toh(pdr_header->length);
++
++ // Total record length should not exceed the response size
++ if ((*actual_pdr_byte_count + sizeof(struct pldm_pdr_hdr)) > record_length)
++ {
++ fprintf(stderr, "Total record length %u exceed response size %u\n", (uint32_t)(*actual_pdr_byte_count + sizeof(struct pldm_pdr_hdr)), record_length);
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ *record_handle = le32toh(pdr_header->record_handle);
++ *record_change_number = le32toh(pdr_header->record_change_num);
++
++ return PLDM_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++int get_redfish_pdr_from_decoded_get_pdr_resp(
++ uint8_t* record_data,
++ uint32_t* resource_id, uint8_t* resource_flags,
++ uint32_t* containing_resource_id,
++ uint16_t* proposed_containing_resource_length,
++ char** proposed_containing_resource_name,
++ uint16_t* resource_uri_length,
++ char** resource_uri,
++ uint16_t* additional_resource_id_count)
++{
++ if ((record_data == NULL) || (resource_id == NULL) ||
++ (resource_flags == NULL) ||
++ (containing_resource_id == NULL) ||
++ (proposed_containing_resource_length == NULL) ||
++ (proposed_containing_resource_name == NULL) ||
++ (resource_uri_length == NULL) || (resource_uri == NULL) ||
++ (additional_resource_id_count == NULL)) {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ struct pldm_platform_redfish_resource_pdr_data* redfish_pdr_data
++ = (struct pldm_platform_redfish_resource_pdr_data*) record_data;
++ *resource_id = le32toh(redfish_pdr_data->resource_id);
++ *resource_flags = redfish_pdr_data->resource_flags;
++ *containing_resource_id = le32toh(redfish_pdr_data->containing_resource_id);
++ *proposed_containing_resource_length =
++ le16toh(redfish_pdr_data->proposed_containing_resource_length);
++ *proposed_containing_resource_name = redfish_pdr_data->proposed_containing_resource_name;
++
++ uint16_t redfish_resource_pdr_data_actual_size = sizeof(struct pldm_platform_redfish_resource_pdr_data) -
++ sizeof(char) + *proposed_containing_resource_length;
++ struct pldm_platform_redfish_resource_uri_data* first_resource_data =
++ (struct pldm_platform_redfish_resource_uri_data*)
++ ((uint8_t*)redfish_pdr_data + redfish_resource_pdr_data_actual_size);
++ *resource_uri_length = le16toh(first_resource_data->sub_uri_length);
++ *resource_uri = first_resource_data->sub_uri;
++
++ uint16_t redfish_first_resource_data_actual_size =
++ sizeof(struct pldm_platform_redfish_resource_uri_data) - sizeof(char) + *resource_uri_length;
++ uint16_t* additional_resource_count =
++ (uint16_t*) ((uint8_t*)first_resource_data + redfish_first_resource_data_actual_size);
++ *additional_resource_id_count = le16toh(*(additional_resource_count));
++
++ return PLDM_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++int get_additional_redfish_resource_from_decoded_get_pdr_resp(
++ uint8_t *record_data,
++ uint16_t resource_index, uint32_t *resource_id,
++ uint16_t* resource_uri_length, char** resource_uri)
++{
++ if ((record_data == NULL) || (resource_id == NULL) ||
++ (resource_uri_length == NULL) ||
++ (resource_uri == NULL) ||
++ (*resource_uri == NULL)) {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ struct pldm_platform_redfish_resource_pdr_data* redfish_pdr_data
++ = (struct pldm_platform_redfish_resource_pdr_data*) record_data;
++
++ uint16_t proposed_containing_resource_length =
++ le16toh(redfish_pdr_data->proposed_containing_resource_length);
++
++ uint16_t redfish_resource_pdr_data_actual_size = sizeof(struct pldm_platform_redfish_resource_pdr_data) -
++ sizeof(char) + proposed_containing_resource_length;
++
++ struct pldm_platform_redfish_resource_uri_data* first_resource_data =
++ (struct pldm_platform_redfish_resource_uri_data*)
++ ((uint8_t*)redfish_pdr_data + redfish_resource_pdr_data_actual_size);
++
++ uint16_t first_resource_uri_length = le16toh(first_resource_data->sub_uri_length);
++
++ uint16_t redfish_first_resource_data_actual_size =
++ sizeof(struct pldm_platform_redfish_resource_uri_data) - sizeof(char) + first_resource_uri_length;
++ uint16_t* additional_resource_count =
++ (uint16_t*) ((uint8_t*)first_resource_data + redfish_first_resource_data_actual_size);
++
++ if (resource_index >= *additional_resource_count)
++ {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
++ uint8_t* data_ptr =
++ (uint8_t*)
++ ((uint8_t*)additional_resource_count + sizeof(uint16_t) /*additional resource count size*/);
++ for (uint16_t id = 0; id < resource_index; id++)
++ {
++ struct pldm_platform_additional_redfish_resource_pdr_data* additional_redfish_resource =
++ (struct pldm_platform_additional_redfish_resource_pdr_data*)(data_ptr);
++ uint16_t additional_resource_uri_length = le16toh(additional_redfish_resource->uri_data.sub_uri_length);
++ data_ptr = data_ptr + sizeof( struct pldm_platform_additional_redfish_resource_pdr_data) -
++ sizeof(char) + additional_resource_uri_length;
++ }
++
++ struct pldm_platform_additional_redfish_resource_pdr_data* additional_redfish_resource =
++ (struct pldm_platform_additional_redfish_resource_pdr_data*)(data_ptr);
++ *resource_id = le32toh(additional_redfish_resource->resource_id);
++ *resource_uri_length = le16toh(additional_redfish_resource->uri_data.sub_uri_length);
++ *resource_uri = additional_redfish_resource->uri_data.sub_uri;
++
++ return PLDM_SUCCESS;
++}
++
++
+ LIBPLDM_ABI_STABLE
+ int decode_set_numeric_effecter_value_req(const struct pldm_msg *msg,
+ size_t payload_length,
+diff --git a/src/requester/meson.build b/src/requester/meson.build
+index 4430682..b22ab81 100644
+--- a/src/requester/meson.build
++++ b/src/requester/meson.build
+@@ -2,5 +2,6 @@ libpldm_sources += files(
+ 'instance-id.c',
+ 'pldm.c',
+ 'pldm_base_requester.c',
+- 'pldm_rde_requester.c'
++ 'pldm_rde_requester.c',
++ 'pldm_platform_requester.c'
+ )
+diff --git a/src/requester/pldm_platform_requester.c b/src/requester/pldm_platform_requester.c
+new file mode 100644
+index 0000000..fef4e9a
+--- /dev/null
++++ b/src/requester/pldm_platform_requester.c
+@@ -0,0 +1,213 @@
++#include "libpldm/requester/pldm_platform_requester.h"
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include "libpldm/base.h"
++#include "libpldm/pldm.h"
++
++LIBPLDM_ABI_STABLE
++pldm_platform_requester_rc_t pldm_platform_init_context(
++ struct pldm_platform_requester_context* ctx, const char* device_id,
++ int net_id, uint32_t negotiated_transfer_size) {
++ if (ctx->initialized) {
++ fprintf(stderr, "No memory allocated for platform context\n");
++ return PLDM_PLATFORM_CONTEXT_INITIALIZATION_ERROR;
++ }
++
++ ctx->initialized = true;
++
++ ctx->requester_status = PLDM_PLATFORM_REQUESTER_NO_PENDING_ACTION;
++ strcpy(ctx->device_name, device_id);
++ ctx->net_id = net_id;
++ ctx->negotiated_transfer_size = negotiated_transfer_size;
++ return PLDM_PLATFORM_REQUESTER_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++pldm_platform_requester_rc_t pldm_platform_init_get_pdr_operation_context(
++ struct pldm_platform_requester_context* ctx,
++ struct pldm_platform_get_pdr_operation* get_pdr_ctx) {
++ if ((ctx == NULL) || (get_pdr_ctx == NULL)) {
++ return PLDM_PLATFORM_CONTEXT_INITIALIZATION_ERROR;
++ }
++ ctx->next_command = -1;
++
++ get_pdr_ctx->record_handle = 0x00000000;
++ get_pdr_ctx->data_transfer_handle = 0x00000000;
++ get_pdr_ctx->transfer_op_flag = PLDM_GET_FIRSTPART;
++ get_pdr_ctx->record_change_num = 0x0000;
++ get_pdr_ctx->request_count =
++ ctx->negotiated_transfer_size - sizeof(struct pldm_get_pdr_resp) - 1;
++
++ ctx->operation_ctx = get_pdr_ctx;
++
++ return PLDM_PLATFORM_REQUESTER_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++pldm_platform_requester_rc_t pldm_platform_start_pdr_discovery(
++ struct pldm_platform_requester_context* ctx) {
++ if (!ctx->initialized &&
++ ctx->requester_status != PLDM_PLATFORM_REQUESTER_NO_PENDING_ACTION) {
++ return PLDM_PLATFORM_CONTEXT_NOT_READY;
++ }
++
++ // Set the default first command as PLDM_GET_PDR
++ ctx->next_command = PLDM_GET_PDR;
++
++ ctx->requester_status = PLDM_PLATFORM_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
++ return PLDM_PLATFORM_REQUESTER_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++pldm_platform_requester_rc_t pldm_platform_get_next_get_pdr_request(
++ struct pldm_platform_requester_context* ctx, uint8_t instance_id,
++ struct pldm_msg* request, size_t request_length) {
++ if ((ctx == NULL) || (request == NULL)) {
++ fprintf(stderr, "Inputs cannot be NULL\n");
++ return PLDM_PLATFORM_REQUESTER_IO_FAILURE;
++ }
++
++ int rc;
++ switch (ctx->next_command) {
++ case PLDM_GET_PDR: {
++ struct pldm_platform_get_pdr_operation* get_pdr_ctx = ctx->operation_ctx;
++ rc = encode_get_pdr_req(
++ instance_id, get_pdr_ctx->record_handle,
++ get_pdr_ctx->data_transfer_handle, get_pdr_ctx->transfer_op_flag,
++ get_pdr_ctx->request_count, get_pdr_ctx->record_change_num, request,
++ request_length);
++ break;
++ }
++ default:
++ return PLDM_PLATFORM_REQUESTER_NO_NEXT_COMMAND_FOUND;
++ }
++
++ if (rc) {
++ fprintf(stderr, "Unable to encode request with rc: %d\n", rc);
++ return PLDM_PLATFORM_REQUESTER_ENCODING_REQUEST_FAILURE;
++ }
++ return PLDM_PLATFORM_REQUESTER_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++pldm_platform_requester_rc_t pldm_platform_push_get_pdr_response(
++ struct pldm_platform_requester_context* ctx, void* resp_msg,
++ size_t resp_size, uint8_t expected_pdr_header_version, uint8_t* record_data,
++ size_t record_data_length, bool* is_record_data_complete) {
++ switch (ctx->next_command) {
++ case PLDM_GET_PDR: {
++ struct pldm_platform_get_pdr_operation* get_pdr_ctx = ctx->operation_ctx;
++ uint8_t completion_code;
++ uint16_t response_count;
++ uint8_t transfer_flag;
++ uint32_t next_record_hndl;
++ uint32_t next_data_transfer_hndl;
++ uint8_t transfer_crc;
++
++ int rc = decode_get_pdr_resp(
++ resp_msg, resp_size - sizeof(struct pldm_msg_hdr), &completion_code,
++ &next_record_hndl, &next_data_transfer_hndl, &transfer_flag,
++ &response_count, record_data, record_data_length, &transfer_crc);
++ if (rc || completion_code) {
++ ctx->requester_status = PLDM_PLATFORM_REQUESTER_REQUEST_FAILED;
++ fprintf(stderr,
++ "Response decode failed with rc: %d, "
++ "completion code: %d\n",
++ rc, completion_code);
++ return PLDM_PLATFORM_REQUESTER_DECODING_RESPONSE_FAILURE;
++ }
++
++ uint32_t resp_record_handle = 0;
++ uint32_t resp_record_num = 0;
++ uint16_t actual_pdr_byte_count = 0;
++ rc = decode_pdr_header_and_get_record_data(
++ record_data, response_count, expected_pdr_header_version,
++ &resp_record_handle, &resp_record_num, &actual_pdr_byte_count);
++ if (rc) {
++ ctx->requester_status = PLDM_PLATFORM_REQUESTER_REQUEST_FAILED;
++ fprintf(stderr,
++ "Response decode failed with rc: %d, "
++ "completion code: %d\n",
++ rc, completion_code);
++ return PLDM_PLATFORM_REQUESTER_DECODING_RESPONSE_FAILURE;
++ }
++
++ if ((sizeof(struct pldm_pdr_hdr) + actual_pdr_byte_count) !=
++ (response_count)) {
++ ctx->requester_status = PLDM_PLATFORM_REQUESTER_REQUEST_FAILED;
++ fprintf(stderr,
++ "Sum of actual PDR bytes and common PDR header does not match "
++ "the Total PDR byte count in GetPDR response."
++ "(Actual PDR bytes + common PDR header bytes) : %u, Total PDR "
++ "bytes : %u\n",
++ (uint32_t)(sizeof(struct pldm_pdr_hdr) + actual_pdr_byte_count),
++ response_count);
++ return PLDM_PLATFORM_REQUESTER_DECODING_RESPONSE_FAILURE;
++ }
++
++ if ((transfer_flag == PLDM_START) || (transfer_flag == PLDM_MIDDLE)) {
++ get_pdr_ctx->transfer_op_flag = PLDM_GET_NEXTPART;
++ get_pdr_ctx->data_transfer_handle = next_data_transfer_hndl;
++ get_pdr_ctx->record_handle = next_record_hndl;
++ ctx->next_command = PLDM_GET_PDR;
++ *is_record_data_complete = false;
++ } else {
++ *is_record_data_complete = true;
++ get_pdr_ctx->transfer_op_flag = PLDM_GET_FIRSTPART;
++ get_pdr_ctx->data_transfer_handle = 0x00000000;
++ // Check if there are more PDRs to be retrieved
++ if (next_record_hndl != 0x00000000) {
++ get_pdr_ctx->record_handle = next_record_hndl;
++ ctx->next_command = PLDM_GET_PDR;
++ ctx->requester_status =
++ PLDM_PLATFORM_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
++ } else {
++ get_pdr_ctx->record_handle = 0x00000000;
++ ctx->next_command = -1;
++ ctx->requester_status = PLDM_PLATFORM_REQUESTER_NO_PENDING_ACTION;
++ }
++ }
++
++ get_pdr_ctx->record_change_num = resp_record_num;
++ return PLDM_PLATFORM_REQUESTER_SUCCESS;
++ }
++ default:
++ return PLDM_PLATFORM_REQUESTER_NO_NEXT_COMMAND_FOUND;
++ }
++
++ return PLDM_PLATFORM_REQUESTER_NOT_PLDM_PLATFORM_MSG;
++}
++
++LIBPLDM_ABI_STABLE
++pldm_platform_requester_rc_t pldm_platform_decode_first_pdr_resource(
++ uint8_t* record_data, uint32_t* resource_id, uint8_t* resource_flags,
++ uint32_t* containing_resource_id,
++ uint16_t* proposed_containing_resource_length,
++ char** proposed_containing_resource_name, uint16_t* resource_uri_length,
++ char** resource_uri, uint16_t* additional_resource_id_count) {
++ if (get_redfish_pdr_from_decoded_get_pdr_resp(
++ record_data, resource_id, resource_flags, containing_resource_id,
++ proposed_containing_resource_length,
++ proposed_containing_resource_name, resource_uri_length, resource_uri,
++ additional_resource_id_count) != PLDM_SUCCESS) {
++ return PLDM_PLATFORM_REQUESTER_DECODING_RESPONSE_FAILURE;
++ }
++
++ return PLDM_PLATFORM_REQUESTER_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++pldm_platform_requester_rc_t pldm_platform_decode_additional_pdr_resource(
++ uint8_t* record_data, uint16_t resource_index, uint32_t* resource_id,
++ uint16_t* resource_uri_length, char** resource_uri) {
++ if (get_additional_redfish_resource_from_decoded_get_pdr_resp(
++ record_data, resource_index, resource_id, resource_uri_length,
++ resource_uri) != PLDM_SUCCESS) {
++ return PLDM_PLATFORM_REQUESTER_DECODING_RESPONSE_FAILURE;
++ }
++
++ return PLDM_PLATFORM_REQUESTER_SUCCESS;
++}
+diff --git a/src/requester/pldm_rde_requester.c b/src/requester/pldm_rde_requester.c
+index c7e1705..ea0b26a 100644
+--- a/src/requester/pldm_rde_requester.c
++++ b/src/requester/pldm_rde_requester.c
+@@ -26,8 +26,7 @@ pldm_rde_requester_rc_t
+ pldm_rde_init_context(const char *device_id, int net_id,
+ struct pldm_rde_requester_manager *manager,
+ uint8_t mc_concurrency, uint32_t mc_transfer_size,
+- bitfield16_t *mc_features, uint8_t number_of_resources,
+- uint32_t *resource_id_address,
++ bitfield16_t *mc_features,
+ struct pldm_rde_requester_context *(*alloc_requester_ctx)(
+ uint8_t number_of_ctx),
+ void (*free_requester_ctx)(void *ctx_memory))
+@@ -56,17 +55,38 @@ pldm_rde_init_context(const char *device_id, int net_id,
+ manager->mc_feature_support = mc_features;
+ strcpy(manager->device_name, device_id);
+ manager->net_id = net_id;
+- // The resource IDs will be set during PDR Retrieval when PDR Type is
+- // implemented in the future
++ manager->number_of_resources = 0;
++
++ manager->ctx = alloc_requester_ctx(mc_concurrency);
++
++ manager->free_requester_ctx = *free_requester_ctx;
++ return PLDM_RDE_REQUESTER_SUCCESS;
++}
++
++LIBPLDM_ABI_STABLE
++pldm_rde_requester_rc_t
++pldm_rde_set_resources_in_context(
++ struct pldm_rde_requester_manager *manager,
++ uint8_t number_of_resources,
++ uint32_t *resource_id_address)
++{
++ fprintf(stdout, "Setting Resource IDs in Context Manager...\n");
++ if (manager == NULL) {
++ fprintf(stderr, "Memory not allocated to context manager.\n");
++ return PLDM_RDE_CONTEXT_INITIALIZATION_ERROR;
++ }
++
++ if (resource_id_address == NULL)
++ {
++ fprintf(stderr, "Memory not allocated to resource id array.\n");
++ return PLDM_RDE_CONTEXT_INITIALIZATION_ERROR;
++ }
++
+ for (int i = 0; i < number_of_resources; i++) {
+ manager->resource_ids[i] = *resource_id_address;
+ resource_id_address++;
+ }
+ manager->number_of_resources = number_of_resources;
+- // alloactor returns the index of the first context in the array
+- manager->ctx = alloc_requester_ctx(mc_concurrency);
+-
+- manager->free_requester_ctx = *free_requester_ctx;
+ return PLDM_RDE_REQUESTER_SUCCESS;
+ }
+
+--
+2.47.0.338.g60cca15819-goog
+
diff --git a/recipes-phosphor/libpldm/libpldm/0011-Add-support-for-Redfish-PDR-encoding-decoding.patch b/recipes-phosphor/libpldm/libpldm/0011-Add-support-for-Redfish-PDR-encoding-decoding.patch
new file mode 100644
index 0000000..d3e3e2d
--- /dev/null
+++ b/recipes-phosphor/libpldm/libpldm/0011-Add-support-for-Redfish-PDR-encoding-decoding.patch
@@ -0,0 +1,1029 @@
+From 56247720caa21a809c829b82161831f4960e1113 Mon Sep 17 00:00:00 2001
+From: Nikhil Namjoshi <nikhilnamjoshi@google.com>
+Date: Thu, 30 May 2024 22:59:27 +0000
+Subject: [PATCH 2/2] Add support for Redfish PDR encoding/decoding
+
+Add encoders/decoders to dynamically encode/decode
+the Redfish Resources in PLDM response message.
+Also add unit tests for all the the encoder/decoder
+APIs.
+
+Tested: All the unit tests pass. Ran the complete minibmc weekly
+tests workflow including the rde soak tests. All tests passed
+successfully.
+
+Fusion-Link: https://fusion2.corp.google.com/c8be2eaa-dfd9-322e-965d-fb2fe908a678
+
+Patch Tracking Bug: b/344955303
+Upstream info / review:
+Upstream-Status: Pending
+Justification:
+
+There is dependency on upstreaming rded first, followed by other libpldm
+command support like OperationInit, Operation,Status, OperationComplete
+and OperationKill. We could not reach consensus with the upstream to have
+platform requester code in libpldm.
+
+Google-Bug-Id: 341389794
+Google-Bug-Id: 341389695
+Google-Bug-Id: 286465868
+Change-Id: I0a8db494c7af5c7a696e99ff97bb22b0be05944a
+Signed-off-by: Nikhil Namjoshi <nikhilnamjoshi@google.com>
+---
+ include/libpldm/platform.h | 9 +
+ src/platform.c | 22 +-
+ tests/libpldm_platform_test.cpp | 898 ++++++++++++++++++++++++++++++++
+ 3 files changed, 927 insertions(+), 2 deletions(-)
+
+diff --git a/include/libpldm/platform.h b/include/libpldm/platform.h
+index ce91af8..fff8c2a 100644
+--- a/include/libpldm/platform.h
++++ b/include/libpldm/platform.h
+@@ -1299,6 +1299,15 @@ int add_additional_redfish_resource_to_encoded_get_pdr_resp(
+ uint32_t sub_resource_id, const char *sub_resource_uri,
+ struct pldm_msg *msg, uint32_t max_pdr_msg_bytes);
+
++/**
++ * @brief API to get the total number of encoded PDR bytes
++ *
++ * @param[out] response_count - Pointer to memory to store pdr byte count
++ * @param[in] msg - Pointer to PLDM msg container
++ */
++int get_encoded_pdr_bytes_from_get_pdr_resp(uint16_t *response_count,
++ struct pldm_msg *msg);
++
+ /** @brief Decode GetPDR request data
+ *
+ * @param[in] msg - Request message
+diff --git a/src/platform.c b/src/platform.c
+index 0e34bc9..beec2e9 100644
+--- a/src/platform.c
++++ b/src/platform.c
+@@ -404,12 +404,24 @@ int add_redfish_pdr_to_encoded_get_pdr_resp(
+ {
+ return PLDM_ERROR_INVALID_DATA;
+ }
++
++ // If the containing resource is EXTERNAL, we expect a NULL byte
++ if (strcmp(sub_uri, "\0") != 0)
++ {
++ return PLDM_ERROR_INVALID_DATA;
++ }
+ } else {
+ // If the containing resource is not EXTERNAL, we expect a NULL byte
+ if (strcmp(proposed_containing_resource_name, "\0") != 0)
+ {
+ return PLDM_ERROR_INVALID_DATA;
+ }
++
++ // If the containing resource is EXTERNAL, we do not expect NULL byte
++ if (strcmp(sub_uri, "\0") == 0)
++ {
++ return PLDM_ERROR_INVALID_DATA;
++ }
+ }
+
+ struct pldm_get_pdr_resp *response =
+@@ -735,6 +747,13 @@ int decode_pdr_header_and_get_record_data(
+ uint32_t* record_handle, uint32_t* record_change_number,
+ uint16_t* actual_pdr_byte_count)
+ {
++ if ((record_data == NULL) || (record_handle == NULL) ||
++ (record_change_number == NULL) ||
++ (actual_pdr_byte_count == NULL))
++ {
++ return PLDM_ERROR_INVALID_DATA;
++ }
++
+ struct pldm_pdr_hdr* pdr_header = (struct pldm_pdr_hdr *)record_data;
+
+ if (expected_pdr_header_version != pdr_header->version)
+@@ -817,8 +836,7 @@ int get_additional_redfish_resource_from_decoded_get_pdr_resp(
+ {
+ if ((record_data == NULL) || (resource_id == NULL) ||
+ (resource_uri_length == NULL) ||
+- (resource_uri == NULL) ||
+- (*resource_uri == NULL)) {
++ (resource_uri == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+diff --git a/tests/libpldm_platform_test.cpp b/tests/libpldm_platform_test.cpp
+index f3ec7e7..f5cb168 100644
+--- a/tests/libpldm_platform_test.cpp
++++ b/tests/libpldm_platform_test.cpp
+@@ -201,6 +201,469 @@ TEST(GetPDR, testBadEncodeResponse)
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+ }
+
++TEST(GetPDR, testAdditionOfRedfishPDRToResp)
++{
++ uint8_t pdr_header_ver = 2;
++ uint32_t record_handle = 50;
++ uint32_t resource_id = 0x00080000;
++ uint16_t record_change_num = 12;
++ const char* sub_uri = "\0";
++ uint16_t sub_uri_length = strlen(sub_uri) + 1;
++ uint8_t is_redfish_resource_root = 1;
++ uint8_t is_redfish_resource_collection = 1;
++ uint8_t is_redfish_resource_contained_in_collection = 0;
++ uint32_t containing_resource_id = 0x00000000;
++ const char* proposed_containing_resource_name = "Chassis";
++ uint16_t proposed_containing_resource_length =
++ strlen(proposed_containing_resource_name) + 1;
++ uint16_t additional_resource_count = 255;
++ uint8_t test_pldm_msg[2048 + sizeof(struct pldm_pdr_hdr)] = {0};
++ struct pldm_msg* msg = (struct pldm_msg*)test_pldm_msg;
++
++ // Verify that if input msg is NULL, the API errors out.
++ EXPECT_EQ(
++ add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, is_redfish_resource_root, is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection, containing_resource_id,
++ proposed_containing_resource_name, additional_resource_count, NULL),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that if input proposed_containing_resource_name is NULL,
++ // the API errors out.
++ EXPECT_EQ(add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, is_redfish_resource_root,
++ is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection,
++ containing_resource_id, NULL, additional_resource_count, msg),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that if input sub_uri is NULL, the API errors out.
++ EXPECT_EQ(
++ add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num, NULL,
++ is_redfish_resource_root, is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection, containing_resource_id,
++ proposed_containing_resource_name, additional_resource_count, msg),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that if is_redfish_resource_root is 1, and the
++ // containing_resource_id is not PLDM_EXTERNAL_RESOURCE_ID, the
++ // API errors out
++ EXPECT_EQ(add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, 1 /*is_redfish_resource_root*/,
++ is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection,
++ 0x000040000 /*containing_resource_id*/,
++ proposed_containing_resource_name, additional_resource_count,
++ msg),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that if is_redfish_resource_root is 1, and the
++ // proposed_containing_resource_name is a NULL byte, the
++ // API errors out
++ EXPECT_EQ(add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, 1 /*is_redfish_resource_root*/,
++ is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection,
++ PLDM_EXTERNAL_RESOURCE_ID /*containing_resource_id*/,
++ "\0" /*proposed_containing_resource_name*/,
++ additional_resource_count, msg),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that if is_redfish_resource_root is 0, and the
++ // proposed_containing_resource_name is not a NULL byte, the
++ // API errors out
++ EXPECT_EQ(add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, 0 /*is_redfish_resource_root*/,
++ is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection,
++ 0x00004000 /*containing_resource_id*/,
++ "Chassis" /*proposed_containing_resource_name*/,
++ additional_resource_count, msg),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that if is_redfish_resource_root is 1, and the
++ // sub_uri is not a NULL byte, the API errors out
++ EXPECT_EQ(add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ "Chassis" /*sub_uri*/, 1 /*is_redfish_resource_root*/,
++ is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection,
++ containing_resource_id,
++ "Chassis" /*proposed_containing_resource_name*/,
++ additional_resource_count, msg),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that if is_redfish_resource_root is 0, and the
++ // sub_uri is a NULL byte, the API errors out
++ EXPECT_EQ(add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ "\0" /*sub_uri*/, 1 /*is_redfish_resource_root*/,
++ is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection,
++ containing_resource_id,
++ "\0" /*proposed_containing_resource_name*/,
++ additional_resource_count, msg),
++ PLDM_ERROR_INVALID_DATA);
++
++ EXPECT_EQ(encode_get_pdr_resp(1 /*instance_id*/, PLDM_SUCCESS,
++ 1
++ /*next_record_handle*/,
++ 0
++ /*next_data_transfer_handle*/,
++ PLDM_START_AND_END, 0 /*resp_cnt*/,
++ NULL
++ /*record_data*/,
++ 0 /*transfer_crc*/, msg),
++ PLDM_SUCCESS);
++
++ EXPECT_EQ(
++ add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, is_redfish_resource_root, is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection, containing_resource_id,
++ proposed_containing_resource_name, additional_resource_count, msg),
++ PLDM_SUCCESS);
++
++ struct pldm_get_pdr_resp* response =
++ (struct pldm_get_pdr_resp*)msg->payload;
++
++ struct pldm_pdr_hdr* pdr_header =
++ (struct pldm_pdr_hdr*)response->record_data;
++
++ EXPECT_EQ(record_handle, le32toh(pdr_header->record_handle));
++ EXPECT_EQ(pdr_header_ver, pdr_header->version);
++ EXPECT_EQ(PLDM_REDFISH_RESOURCE_PDR, pdr_header->type);
++ EXPECT_EQ(record_change_num, le16toh(pdr_header->record_change_num));
++
++ uint32_t redfish_pdr_data_size =
++ sizeof(struct pldm_platform_redfish_resource_pdr_data) +
++ (uint32_t)proposed_containing_resource_length - sizeof(char);
++ uint32_t first_resource_data_size =
++ sizeof(struct pldm_platform_redfish_resource_uri_data) +
++ (uint32_t)sub_uri_length - sizeof(char);
++ uint16_t pdr_length = redfish_pdr_data_size + first_resource_data_size +
++ sizeof(uint16_t) /*additional
++ resource count size*/
++ ;
++ EXPECT_EQ(pdr_length, le16toh(pdr_header->length));
++ uint16_t response_length = pdr_length + sizeof(struct pldm_pdr_hdr);
++ EXPECT_EQ(response_length, le16toh(response->response_count));
++
++ struct pldm_platform_redfish_resource_pdr_data* redfish_pdr_data =
++ (struct
++ pldm_platform_redfish_resource_pdr_data*)((uint8_t*)
++ response->record_data +
++ sizeof(struct pldm_pdr_hdr));
++
++ EXPECT_EQ(resource_id, le32toh(redfish_pdr_data->resource_id));
++
++ uint8_t resource_flags = (is_redfish_resource_root << 0) |
++ (is_redfish_resource_collection << 1) |
++ (is_redfish_resource_contained_in_collection << 2);
++ EXPECT_EQ(resource_flags, redfish_pdr_data->resource_flags);
++ EXPECT_EQ(containing_resource_id,
++ le32toh(redfish_pdr_data->containing_resource_id));
++ EXPECT_EQ(proposed_containing_resource_length,
++ le16toh(redfish_pdr_data->proposed_containing_resource_length));
++ EXPECT_STREQ(proposed_containing_resource_name,
++ redfish_pdr_data->proposed_containing_resource_name);
++
++ struct pldm_platform_redfish_resource_uri_data* first_resource_data =
++ (struct
++ pldm_platform_redfish_resource_uri_data*)((uint8_t*)redfish_pdr_data +
++ redfish_pdr_data_size);
++ EXPECT_EQ(sub_uri_length, le16toh(first_resource_data->sub_uri_length));
++ EXPECT_STREQ(sub_uri, first_resource_data->sub_uri);
++ uint16_t* additional_resource_id_count =
++ (uint16_t*)((uint8_t*)first_resource_data + first_resource_data_size);
++ EXPECT_EQ(additional_resource_count, *additional_resource_id_count);
++}
++
++TEST(GetPDR, testAdditionOfAdditionalRedfishResourceToPDRResp)
++{
++ uint8_t pdr_header_ver = 2;
++ uint32_t record_handle = 50;
++ uint32_t resource_id = 0x00010001;
++ uint16_t record_change_num = 12;
++ const char* sub_uri = "Tray";
++ uint16_t sub_uri_length = strlen(sub_uri) + 1;
++ uint8_t is_redfish_resource_root = 0;
++ uint8_t is_redfish_resource_collection = 0;
++ uint8_t is_redfish_resource_contained_in_collection = 1;
++ uint32_t containing_resource_id = 0x00010000;
++ const char* proposed_containing_resource_name = "\0";
++ uint16_t proposed_containing_resource_length =
++ strlen(proposed_containing_resource_name) + 1;
++ uint16_t additional_resource_count = 0;
++ uint8_t test_pldm_msg[2048 + sizeof(struct pldm_pdr_hdr)] = {0};
++ struct pldm_msg* msg = (struct pldm_msg*)test_pldm_msg;
++
++ // Verify the API fails if we send NULL sub_resource_uri
++ EXPECT_EQ(add_additional_redfish_resource_to_encoded_get_pdr_resp(
++ resource_id, NULL, msg, 2048 /*max_pdr_msg_bytes*/
++ ),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify the API fails if we send NULL msg
++ EXPECT_EQ(add_additional_redfish_resource_to_encoded_get_pdr_resp(
++ resource_id, sub_uri, NULL, 2048 /*max_pdr_msg_bytes*/
++ ),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify the API fails if the data does not fit in the messgae
++ EXPECT_EQ(add_additional_redfish_resource_to_encoded_get_pdr_resp(
++ resource_id, sub_uri, msg, 1 /*max_pdr_msg_bytes*/
++ ),
++ PLDM_ERROR_INVALID_LENGTH);
++
++ EXPECT_EQ(encode_get_pdr_resp(1 /*instance_id*/, PLDM_SUCCESS,
++ 1
++ /*next_record_handle*/,
++ 0
++ /*next_data_transfer_handle*/,
++ PLDM_START_AND_END, 0 /*resp_cnt*/,
++ NULL
++ /*record_data*/,
++ 0 /*transfer_crc*/, msg),
++ PLDM_SUCCESS);
++
++ EXPECT_EQ(
++ add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, is_redfish_resource_root, is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection, containing_resource_id,
++ proposed_containing_resource_name, additional_resource_count, msg),
++ PLDM_SUCCESS);
++
++ struct pldm_get_pdr_resp* response =
++ (struct pldm_get_pdr_resp*)msg->payload;
++
++ struct pldm_pdr_hdr* pdr_header =
++ (struct pldm_pdr_hdr*)response->record_data;
++
++ EXPECT_EQ(record_handle, le32toh(pdr_header->record_handle));
++ EXPECT_EQ(pdr_header_ver, pdr_header->version);
++ EXPECT_EQ(PLDM_REDFISH_RESOURCE_PDR, pdr_header->type);
++ EXPECT_EQ(record_change_num, le16toh(pdr_header->record_change_num));
++
++ uint32_t redfish_pdr_data_size =
++ sizeof(struct pldm_platform_redfish_resource_pdr_data) +
++ (uint32_t)proposed_containing_resource_length - sizeof(char);
++ uint32_t first_resource_data_size =
++ sizeof(struct pldm_platform_redfish_resource_uri_data) +
++ (uint32_t)sub_uri_length - sizeof(char);
++ uint16_t pdr_length = redfish_pdr_data_size + first_resource_data_size +
++ sizeof(uint16_t) /*additional
++ resource count size*/
++ ;
++ EXPECT_EQ(pdr_length, le16toh(pdr_header->length));
++ uint16_t response_length = pdr_length + sizeof(struct pldm_pdr_hdr);
++ EXPECT_EQ(response_length, le16toh(response->response_count));
++
++ struct pldm_platform_redfish_resource_pdr_data* redfish_pdr_data =
++ (struct
++ pldm_platform_redfish_resource_pdr_data*)((uint8_t*)
++ response->record_data +
++ sizeof(struct pldm_pdr_hdr));
++
++ EXPECT_EQ(resource_id, le32toh(redfish_pdr_data->resource_id));
++
++ uint8_t resource_flags = (is_redfish_resource_root << 0) |
++ (is_redfish_resource_collection << 1) |
++ (is_redfish_resource_contained_in_collection << 2);
++ EXPECT_EQ(resource_flags, redfish_pdr_data->resource_flags);
++ EXPECT_EQ(containing_resource_id,
++ le32toh(redfish_pdr_data->containing_resource_id));
++ EXPECT_EQ(proposed_containing_resource_length,
++ le16toh(redfish_pdr_data->proposed_containing_resource_length));
++ EXPECT_STREQ(proposed_containing_resource_name,
++ redfish_pdr_data->proposed_containing_resource_name);
++
++ struct pldm_platform_redfish_resource_uri_data* first_resource_data =
++ (struct
++ pldm_platform_redfish_resource_uri_data*)((uint8_t*)redfish_pdr_data +
++ redfish_pdr_data_size);
++ EXPECT_EQ(sub_uri_length, le16toh(first_resource_data->sub_uri_length));
++ EXPECT_STREQ(sub_uri, first_resource_data->sub_uri);
++ uint16_t* additional_resource_id_count =
++ (uint16_t*)((uint8_t*)first_resource_data + first_resource_data_size);
++ EXPECT_EQ(additional_resource_count, *additional_resource_id_count);
++
++ const char* sub_uri1 = "SATA0";
++ uint16_t sub_uri_length1 = strlen(sub_uri1) + 1;
++ uint32_t resource_id1 = 0x00010002;
++ EXPECT_EQ(add_additional_redfish_resource_to_encoded_get_pdr_resp(
++ resource_id1, sub_uri1, msg, 2048 /*max_pdr_msg_bytes*/
++ ),
++ PLDM_SUCCESS);
++
++ struct pldm_platform_additional_redfish_resource_pdr_data*
++ additonal_resource_pdr_data =
++ (struct
++ pldm_platform_additional_redfish_resource_pdr_data*)((uint8_t*)
++ additional_resource_id_count +
++ sizeof(
++ uint16_t));
++ EXPECT_EQ(resource_id1, le32toh(additonal_resource_pdr_data->resource_id));
++ EXPECT_EQ(sub_uri_length1,
++ le16toh(additonal_resource_pdr_data->uri_data.sub_uri_length));
++ EXPECT_STREQ(sub_uri1, additonal_resource_pdr_data->uri_data.sub_uri);
++
++ uint32_t additonal_resource_pdr_data_size =
++ sizeof(struct pldm_platform_additional_redfish_resource_pdr_data) +
++ (uint32_t)sub_uri_length1 - sizeof(char);
++ uint16_t total_pdr_bytes = sizeof(struct pldm_pdr_hdr) + pdr_length +
++ additonal_resource_pdr_data_size;
++ additional_resource_id_count =
++ (uint16_t*)((uint8_t*)first_resource_data + first_resource_data_size);
++ EXPECT_EQ(additional_resource_count + 1,
++ le16toh(*additional_resource_id_count));
++ EXPECT_EQ(total_pdr_bytes, le16toh(response->response_count));
++}
++
++TEST(GetPDR, testGetEncodedPDRBytesFromGetPDRResp)
++{
++ uint8_t pdr_header_ver = 2;
++ uint32_t record_handle = 50;
++ uint32_t resource_id = 0x00040001;
++ uint16_t record_change_num = 12;
++ const char* sub_uri = "brick_p12v_temp";
++ uint16_t sub_uri_length = strlen(sub_uri) + 1;
++ uint8_t is_redfish_resource_root = 0;
++ uint8_t is_redfish_resource_collection = 0;
++ uint8_t is_redfish_resource_contained_in_collection = 1;
++ uint32_t containing_resource_id = 0x00040000;
++ const char* proposed_containing_resource_name = "\0";
++ uint16_t proposed_containing_resource_length =
++ strlen(proposed_containing_resource_name) + 1;
++ uint16_t additional_resource_count = 0;
++ uint8_t test_pldm_msg[2048 + sizeof(struct pldm_pdr_hdr)] = {0};
++ struct pldm_msg* msg = (struct pldm_msg*)test_pldm_msg;
++
++ // Verify that the API fails if response counter pointer in NULL
++ EXPECT_EQ(get_encoded_pdr_bytes_from_get_pdr_resp(NULL, msg),
++ PLDM_ERROR_INVALID_DATA);
++
++ uint16_t response_count = 0;
++ // Verify that the API fails if msg pointer in NULL
++ EXPECT_EQ(get_encoded_pdr_bytes_from_get_pdr_resp(&response_count, NULL),
++ PLDM_ERROR_INVALID_DATA);
++
++ EXPECT_EQ(encode_get_pdr_resp(1 /*instance_id*/, PLDM_SUCCESS,
++ 1
++ /*next_record_handle*/,
++ 0
++ /*next_data_transfer_handle*/,
++ PLDM_START_AND_END, 0 /*resp_cnt*/,
++ NULL
++ /*record_data*/,
++ 0 /*transfer_crc*/, msg),
++ PLDM_SUCCESS);
++
++ EXPECT_EQ(
++ add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, is_redfish_resource_root, is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection, containing_resource_id,
++ proposed_containing_resource_name, additional_resource_count, msg),
++ PLDM_SUCCESS);
++
++ struct pldm_get_pdr_resp* response =
++ (struct pldm_get_pdr_resp*)msg->payload;
++
++ struct pldm_pdr_hdr* pdr_header =
++ (struct pldm_pdr_hdr*)response->record_data;
++
++ EXPECT_EQ(record_handle, le32toh(pdr_header->record_handle));
++ EXPECT_EQ(pdr_header_ver, pdr_header->version);
++ EXPECT_EQ(PLDM_REDFISH_RESOURCE_PDR, pdr_header->type);
++ EXPECT_EQ(record_change_num, le16toh(pdr_header->record_change_num));
++
++ uint32_t redfish_pdr_data_size =
++ sizeof(struct pldm_platform_redfish_resource_pdr_data) +
++ (uint32_t)proposed_containing_resource_length - sizeof(char);
++ uint32_t first_resource_data_size =
++ sizeof(struct pldm_platform_redfish_resource_uri_data) +
++ (uint32_t)sub_uri_length - sizeof(char);
++ uint16_t pdr_length = redfish_pdr_data_size + first_resource_data_size +
++ sizeof(uint16_t) /*additional
++ resource count size*/
++ ;
++ EXPECT_EQ(pdr_length, le16toh(pdr_header->length));
++ uint16_t response_length = pdr_length + sizeof(struct pldm_pdr_hdr);
++ EXPECT_EQ(response_length, le16toh(response->response_count));
++
++ struct pldm_platform_redfish_resource_pdr_data* redfish_pdr_data =
++ (struct
++ pldm_platform_redfish_resource_pdr_data*)((uint8_t*)
++ response->record_data +
++ sizeof(struct pldm_pdr_hdr));
++
++ EXPECT_EQ(resource_id, le32toh(redfish_pdr_data->resource_id));
++
++ uint8_t resource_flags = (is_redfish_resource_root << 0) |
++ (is_redfish_resource_collection << 1) |
++ (is_redfish_resource_contained_in_collection << 2);
++ EXPECT_EQ(resource_flags, redfish_pdr_data->resource_flags);
++ EXPECT_EQ(containing_resource_id,
++ le32toh(redfish_pdr_data->containing_resource_id));
++ EXPECT_EQ(proposed_containing_resource_length,
++ le16toh(redfish_pdr_data->proposed_containing_resource_length));
++ EXPECT_STREQ(proposed_containing_resource_name,
++ redfish_pdr_data->proposed_containing_resource_name);
++
++ struct pldm_platform_redfish_resource_uri_data* first_resource_data =
++ (struct
++ pldm_platform_redfish_resource_uri_data*)((uint8_t*)redfish_pdr_data +
++ redfish_pdr_data_size);
++ EXPECT_EQ(sub_uri_length, le16toh(first_resource_data->sub_uri_length));
++ EXPECT_STREQ(sub_uri, first_resource_data->sub_uri);
++ uint16_t* additional_resource_id_count =
++ (uint16_t*)((uint8_t*)first_resource_data + first_resource_data_size);
++ EXPECT_EQ(additional_resource_count, *additional_resource_id_count);
++
++ const char* sub_uri1 = "vol_p3v3_aux_scaled";
++ uint16_t sub_uri_length1 = strlen(sub_uri1) + 1;
++ uint32_t resource_id1 = 0x00040002;
++ EXPECT_EQ(add_additional_redfish_resource_to_encoded_get_pdr_resp(
++ resource_id1, sub_uri1, msg, 2048 /*max_pdr_msg_bytes*/
++ ),
++ PLDM_SUCCESS);
++
++ struct pldm_platform_additional_redfish_resource_pdr_data*
++ additonal_resource_pdr_data =
++ (struct
++ pldm_platform_additional_redfish_resource_pdr_data*)((uint8_t*)
++ additional_resource_id_count +
++ sizeof(
++ uint16_t));
++ EXPECT_EQ(resource_id1, le32toh(additonal_resource_pdr_data->resource_id));
++ EXPECT_EQ(sub_uri_length1,
++ le16toh(additonal_resource_pdr_data->uri_data.sub_uri_length));
++ EXPECT_STREQ(sub_uri1, additonal_resource_pdr_data->uri_data.sub_uri);
++
++ uint32_t additonal_resource_pdr_data_size =
++ sizeof(struct pldm_platform_additional_redfish_resource_pdr_data) +
++ (uint32_t)sub_uri_length1 - sizeof(char);
++ uint16_t total_pdr_bytes = sizeof(struct pldm_pdr_hdr) + pdr_length +
++ additonal_resource_pdr_data_size;
++ additional_resource_id_count =
++ (uint16_t*)((uint8_t*)first_resource_data + first_resource_data_size);
++ EXPECT_EQ(additional_resource_count + 1,
++ le16toh(*additional_resource_id_count));
++ EXPECT_EQ(total_pdr_bytes, le16toh(response->response_count));
++
++ EXPECT_EQ(get_encoded_pdr_bytes_from_get_pdr_resp(&response_count, msg),
++ PLDM_SUCCESS);
++ EXPECT_EQ(total_pdr_bytes, response_count);
++}
++
+ TEST(GetPDR, testGoodDecodeRequest)
+ {
+ std::array<uint8_t, hdrSize + PLDM_GET_PDR_REQ_BYTES> requestMsg{};
+@@ -387,6 +850,441 @@ TEST(GetPDR, testBadDecodeResponse)
+ EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+ }
+
++TEST(GetPDR, testDecodePdrHeaderAndGetRecordData)
++{
++ uint8_t pdr_header_ver = 2;
++ uint32_t record_handle = 50;
++ uint32_t resource_id = 0x00040001;
++ uint16_t record_change_num = 12;
++ const char* sub_uri = "brick_p12v_temp";
++ uint8_t is_redfish_resource_root = 0;
++ uint8_t is_redfish_resource_collection = 0;
++ uint8_t is_redfish_resource_contained_in_collection = 1;
++ uint32_t containing_resource_id = 0x00040000;
++ const char* proposed_containing_resource_name = "\0";
++ uint16_t additional_resource_count = 0;
++ uint8_t test_pldm_msg[2048 + sizeof(pldm_msg_hdr)] = {0};
++ struct pldm_msg* msg = (struct pldm_msg*)test_pldm_msg;
++
++ EXPECT_EQ(encode_get_pdr_resp(1 /*instance_id*/, PLDM_SUCCESS,
++ record_handle + 1
++ /*next_record_handle*/,
++ 1
++ /*next_data_transfer_handle*/,
++ PLDM_START_AND_END, 0 /*resp_cnt*/,
++ NULL
++ /*record_data*/,
++ 0 /*transfer_crc*/, msg),
++ PLDM_SUCCESS);
++
++ EXPECT_EQ(
++ add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, is_redfish_resource_root, is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection, containing_resource_id,
++ proposed_containing_resource_name, additional_resource_count, msg),
++ PLDM_SUCCESS);
++ struct pldm_get_pdr_resp* response =
++ (struct pldm_get_pdr_resp*)msg->payload;
++
++ uint16_t total_pdr_bytes = le16toh(response->response_count);
++
++ uint8_t completion_code = 0;
++ uint32_t next_record_hndl = 0;
++ uint32_t next_data_transfer_hndl = 0;
++ uint8_t transfer_flag = 0;
++ uint16_t resp_cnt = 0;
++ size_t record_data_length = 2048 - PLDM_GET_PDR_MIN_RESP_BYTES;
++ uint8_t transfer_crc;
++ uint8_t record_data_read[2048 - PLDM_GET_PDR_MIN_RESP_BYTES] = {0};
++ EXPECT_EQ(decode_get_pdr_resp(msg, 2048 + sizeof(pldm_msg_hdr),
++ &completion_code, &next_record_hndl,
++ &next_data_transfer_hndl, &transfer_flag,
++ &resp_cnt, record_data_read,
++ record_data_length, &transfer_crc),
++ PLDM_SUCCESS);
++ EXPECT_EQ(completion_code, PLDM_SUCCESS);
++ EXPECT_EQ(next_record_hndl, record_handle + 1);
++ EXPECT_EQ(next_data_transfer_hndl, 1);
++ EXPECT_EQ(transfer_flag, PLDM_START_AND_END);
++ EXPECT_EQ(resp_cnt, total_pdr_bytes);
++ EXPECT_EQ(transfer_crc, 0);
++
++ uint32_t record_handle_read = 0;
++ uint32_t record_change_number_read = 0;
++ uint16_t actual_pdr_byte_count_read = 0;
++
++ // Verify that the APIs fails if record_data is NULL
++ EXPECT_EQ(decode_pdr_header_and_get_record_data(
++ NULL, resp_cnt, pdr_header_ver, &record_handle_read,
++ &record_change_number_read, &actual_pdr_byte_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the APIs fails if record_hande is NULL
++ EXPECT_EQ(decode_pdr_header_and_get_record_data(
++ record_data_read, resp_cnt, pdr_header_ver, NULL,
++ &record_change_number_read, &actual_pdr_byte_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the APIs fails if record_change_number is NULL
++ EXPECT_EQ(decode_pdr_header_and_get_record_data(
++ record_data_read, resp_cnt, pdr_header_ver, &record_handle,
++ NULL, &actual_pdr_byte_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the APIs fails if actual_pdr_byte_count_read is NULL
++ EXPECT_EQ(decode_pdr_header_and_get_record_data(
++ record_data_read, resp_cnt, pdr_header_ver, &record_handle,
++ &record_change_number_read, NULL),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the API fails if PDR Header version is not expected.
++ EXPECT_EQ(decode_pdr_header_and_get_record_data(
++ record_data_read, resp_cnt,
++ 3
++ /*expected_pdr_header_version*/,
++ &record_handle_read, &record_change_number_read,
++ &actual_pdr_byte_count_read),
++ PLDM_ERROR);
++
++ // Verify that the API fails if record length is small.
++ EXPECT_EQ(decode_pdr_header_and_get_record_data(
++ record_data_read, 1 /*record_length*/, pdr_header_ver,
++ &record_handle_read, &record_change_number_read,
++ &actual_pdr_byte_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ EXPECT_EQ(decode_pdr_header_and_get_record_data(
++ record_data_read, resp_cnt, pdr_header_ver,
++ &record_handle_read, &record_change_number_read,
++ &actual_pdr_byte_count_read),
++ PLDM_SUCCESS);
++ EXPECT_EQ(record_handle_read, record_handle);
++ EXPECT_EQ(record_change_number_read, record_change_num);
++ EXPECT_EQ(actual_pdr_byte_count_read,
++ total_pdr_bytes - sizeof(struct pldm_pdr_hdr));
++}
++
++TEST(GetPDR, testGetRedfishPDRFromDecodedGetPdrResp)
++{
++ uint8_t pdr_header_ver = 2;
++ uint32_t record_handle = 50;
++ uint32_t resource_id = 0x00040001;
++ uint16_t record_change_num = 12;
++ const char* sub_uri = "brick_p12v_temp";
++ uint16_t sub_uri_length = strlen(sub_uri) + 1;
++ uint8_t is_redfish_resource_root = 0;
++ uint8_t is_redfish_resource_collection = 0;
++ uint8_t is_redfish_resource_contained_in_collection = 1;
++ uint32_t containing_resource_id = 0x00040000;
++ const char* proposed_containing_resource_name = "\0";
++ uint16_t proposed_containing_resource_length =
++ strlen(proposed_containing_resource_name) + 1;
++ uint16_t additional_resource_count = 0;
++ uint8_t test_pldm_msg[2048 + sizeof(pldm_msg_hdr)] = {0};
++ struct pldm_msg* msg = (struct pldm_msg*)test_pldm_msg;
++
++ EXPECT_EQ(encode_get_pdr_resp(1 /*instance_id*/, PLDM_SUCCESS,
++ record_handle + 1
++ /*next_record_handle*/,
++ 1
++ /*next_data_transfer_handle*/,
++ PLDM_START_AND_END, 0 /*resp_cnt*/,
++ NULL
++ /*record_data*/,
++ 0 /*transfer_crc*/, msg),
++ PLDM_SUCCESS);
++
++ EXPECT_EQ(
++ add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, is_redfish_resource_root, is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection, containing_resource_id,
++ proposed_containing_resource_name, additional_resource_count, msg),
++ PLDM_SUCCESS);
++
++ uint8_t completion_code = 0;
++ uint32_t next_record_hndl = 0;
++ uint32_t next_data_transfer_hndl = 0;
++ uint8_t transfer_flag = 0;
++ uint16_t resp_cnt = 0;
++ size_t record_data_length = 2048 - PLDM_GET_PDR_MIN_RESP_BYTES;
++ uint8_t transfer_crc;
++ uint8_t record_data_read[2048 - PLDM_GET_PDR_MIN_RESP_BYTES] = {0};
++ EXPECT_EQ(decode_get_pdr_resp(msg, 2048 + sizeof(pldm_msg_hdr),
++ &completion_code, &next_record_hndl,
++ &next_data_transfer_hndl, &transfer_flag,
++ &resp_cnt, record_data_read,
++ record_data_length, &transfer_crc),
++ PLDM_SUCCESS);
++ EXPECT_EQ(completion_code, PLDM_SUCCESS);
++
++ uint32_t record_handle_read = 0;
++ uint32_t record_change_number_read = 0;
++ uint16_t actual_pdr_byte_count_read = 0;
++
++ EXPECT_EQ(decode_pdr_header_and_get_record_data(
++ record_data_read, resp_cnt, pdr_header_ver,
++ &record_handle_read, &record_change_number_read,
++ &actual_pdr_byte_count_read),
++ PLDM_SUCCESS);
++ uint8_t* actual_pdr_record_data_read =
++ record_data_read + sizeof(pldm_pdr_hdr);
++ uint32_t resource_id_read = 0x00000000;
++ uint8_t resource_flags_read = 0;
++ uint32_t containing_resource_id_read = 0;
++ uint16_t proposed_containing_resource_length_read = 0;
++ char* proposed_containing_resource_name_read = NULL;
++ uint16_t resource_uri_length_read = 0;
++ char* resource_uri_read = NULL;
++ uint16_t additional_resource_id_count_read = 0;
++
++ // Verify that the API fails if input record data is NULL
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ NULL, &resource_id_read, &resource_flags_read,
++ &containing_resource_id_read,
++ &proposed_containing_resource_length_read,
++ &proposed_containing_resource_name_read,
++ &resource_uri_length_read, &resource_uri_read,
++ &additional_resource_id_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the API fails if input resource id pointer is NULL
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, NULL, &resource_flags_read,
++ &containing_resource_id_read,
++ &proposed_containing_resource_length_read,
++ &proposed_containing_resource_name_read,
++ &resource_uri_length_read, &resource_uri_read,
++ &additional_resource_id_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the API fails if input resource flags pointer is NULL
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, &resource_id_read, NULL,
++ &containing_resource_id_read,
++ &proposed_containing_resource_length_read,
++ &proposed_containing_resource_name_read,
++ &resource_uri_length_read, &resource_uri_read,
++ &additional_resource_id_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the API fails if input containing resource id pointer is
++ // NULL
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, &resource_id_read,
++ &resource_flags_read, NULL,
++ &proposed_containing_resource_length_read,
++ &proposed_containing_resource_name_read,
++ &resource_uri_length_read, &resource_uri_read,
++ &additional_resource_id_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the API fails if input proposed containing resource length
++ // pointer is NULL
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, &resource_id_read,
++ &resource_flags_read, &containing_resource_id_read, NULL,
++ &proposed_containing_resource_name_read,
++ &resource_uri_length_read, &resource_uri_read,
++ &additional_resource_id_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the API fails if input proposed containing resource name
++ // is NULL
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, &resource_id_read,
++ &resource_flags_read, &containing_resource_id_read,
++ &proposed_containing_resource_length_read, NULL,
++ &resource_uri_length_read, &resource_uri_read,
++ &additional_resource_id_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the API fails if input resource uri length is NULL
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, &resource_id_read,
++ &resource_flags_read, &containing_resource_id_read,
++ &proposed_containing_resource_length_read,
++ &proposed_containing_resource_name_read, NULL,
++ &resource_uri_read, &additional_resource_id_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the API fails if input resource uri pointer is NULL
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, &resource_id_read,
++ &resource_flags_read, &containing_resource_id_read,
++ &proposed_containing_resource_length_read,
++ &proposed_containing_resource_name_read,
++ &resource_uri_length_read, NULL,
++ &additional_resource_id_count_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that the API fails if additional resource id count pointer is
++ // NULL
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, &resource_id_read,
++ &resource_flags_read, &containing_resource_id_read,
++ &proposed_containing_resource_length_read,
++ &proposed_containing_resource_name_read,
++ &resource_uri_length_read, &resource_uri_read, NULL),
++ PLDM_ERROR_INVALID_DATA);
++
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, &resource_id_read,
++ &resource_flags_read, &containing_resource_id_read,
++ &proposed_containing_resource_length_read,
++ &proposed_containing_resource_name_read,
++ &resource_uri_length_read, &resource_uri_read,
++ &additional_resource_id_count_read),
++ PLDM_SUCCESS);
++
++ EXPECT_EQ(resource_id, resource_id_read);
++ EXPECT_EQ(resource_flags_read,
++ ((is_redfish_resource_root << 0) |
++ (is_redfish_resource_collection << 1) |
++ (is_redfish_resource_contained_in_collection << 2)));
++ EXPECT_EQ(containing_resource_id_read, containing_resource_id);
++ EXPECT_EQ(proposed_containing_resource_length_read,
++ proposed_containing_resource_length);
++ EXPECT_STREQ(proposed_containing_resource_name_read,
++ proposed_containing_resource_name);
++ EXPECT_EQ(resource_uri_length_read, sub_uri_length);
++ EXPECT_STREQ(resource_uri_read, sub_uri);
++ EXPECT_EQ(additional_resource_id_count_read, 0);
++}
++
++TEST(GetPDR, testGetAdditionalRedfishResourceFromDecodedGetPdrResp)
++{
++ uint8_t pdr_header_ver = 2;
++ uint32_t record_handle = 50;
++ uint32_t resource_id = 0x00040001;
++ uint16_t record_change_num = 12;
++ const char* sub_uri = "brick_p12v_temp";
++ uint8_t is_redfish_resource_root = 0;
++ uint8_t is_redfish_resource_collection = 0;
++ uint8_t is_redfish_resource_contained_in_collection = 1;
++ uint32_t containing_resource_id = 0x00040000;
++ const char* proposed_containing_resource_name = "\0";
++ uint16_t additional_resource_count = 0;
++ uint8_t test_pldm_msg[2048 + sizeof(pldm_msg_hdr)] = {0};
++ struct pldm_msg* msg = (struct pldm_msg*)test_pldm_msg;
++
++ EXPECT_EQ(encode_get_pdr_resp(1 /*instance_id*/, PLDM_SUCCESS,
++ record_handle + 1
++ /*next_record_handle*/,
++ 1
++ /*next_data_transfer_handle*/,
++ PLDM_START_AND_END, 0 /*resp_cnt*/,
++ NULL
++ /*record_data*/,
++ 0 /*transfer_crc*/, msg),
++ PLDM_SUCCESS);
++
++ EXPECT_EQ(
++ add_redfish_pdr_to_encoded_get_pdr_resp(
++ pdr_header_ver, record_handle, resource_id, record_change_num,
++ sub_uri, is_redfish_resource_root, is_redfish_resource_collection,
++ is_redfish_resource_contained_in_collection, containing_resource_id,
++ proposed_containing_resource_name, additional_resource_count, msg),
++ PLDM_SUCCESS);
++
++ const char* sub_uri1 = "vol_p3v3_aux_scaled";
++ uint16_t sub_uri_length1 = strlen(sub_uri1) + 1;
++ uint32_t resource_id1 = 0x00040002;
++ EXPECT_EQ(add_additional_redfish_resource_to_encoded_get_pdr_resp(
++ resource_id1, sub_uri1, msg, 2048 /*max_pdr_msg_bytes*/
++ ),
++ PLDM_SUCCESS);
++
++ uint8_t completion_code = 0;
++ uint32_t next_record_hndl = 0;
++ uint32_t next_data_transfer_hndl = 0;
++ uint8_t transfer_flag = 0;
++ uint16_t resp_cnt = 0;
++ size_t record_data_length = 2048 - PLDM_GET_PDR_MIN_RESP_BYTES;
++ uint8_t transfer_crc;
++ uint8_t record_data_read[2048 - PLDM_GET_PDR_MIN_RESP_BYTES] = {0};
++ EXPECT_EQ(decode_get_pdr_resp(msg, 2048 + sizeof(pldm_msg_hdr),
++ &completion_code, &next_record_hndl,
++ &next_data_transfer_hndl, &transfer_flag,
++ &resp_cnt, record_data_read,
++ record_data_length, &transfer_crc),
++ PLDM_SUCCESS);
++
++ uint32_t record_handle_read = 0;
++ uint32_t record_change_number_read = 0;
++ uint16_t actual_pdr_byte_count_read = 0;
++
++ EXPECT_EQ(decode_pdr_header_and_get_record_data(
++ record_data_read, resp_cnt, pdr_header_ver,
++ &record_handle_read, &record_change_number_read,
++ &actual_pdr_byte_count_read),
++ PLDM_SUCCESS);
++
++ uint8_t* actual_pdr_record_data_read =
++ record_data_read + sizeof(pldm_pdr_hdr);
++ uint32_t resource_id_read = 0x00000000;
++ uint8_t resource_flags_read = 0;
++ uint32_t containing_resource_id_read = 0;
++ uint16_t proposed_containing_resource_length_read = 0;
++ char* proposed_containing_resource_name_read = NULL;
++ uint16_t resource_uri_length_read = 0;
++ char* resource_uri_read = NULL;
++ uint16_t additional_resource_id_count_read = 0;
++
++ EXPECT_EQ(get_redfish_pdr_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, &resource_id_read,
++ &resource_flags_read, &containing_resource_id_read,
++ &proposed_containing_resource_length_read,
++ &proposed_containing_resource_name_read,
++ &resource_uri_length_read, &resource_uri_read,
++ &additional_resource_id_count_read),
++ PLDM_SUCCESS);
++
++ uint32_t resource_id1_read = 0;
++ uint16_t sub_uri_length1_read = 0;
++ char* sub_uri1_read = NULL;
++
++ // Verify that API fails if record data pointer is NULL
++ EXPECT_EQ(get_additional_redfish_resource_from_decoded_get_pdr_resp(
++ NULL /*record_data*/, 0, &resource_id1_read,
++ &sub_uri_length1_read, &sub_uri1_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that API fails if resource id pointer is NULL
++ EXPECT_EQ(get_additional_redfish_resource_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, 0, NULL /*resource_id*/,
++ &sub_uri_length1_read, &sub_uri1_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that API fails if resource uri length pointer is NULL
++ EXPECT_EQ(get_additional_redfish_resource_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, 0, &resource_id1_read,
++ NULL /*resource_uri_length*/, &sub_uri1_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that API fails if resource uri pointer is NULL
++ EXPECT_EQ(get_additional_redfish_resource_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, 0, &resource_id1_read,
++ &sub_uri_length1_read, NULL /*resource_uri*/),
++ PLDM_ERROR_INVALID_DATA);
++
++ // Verify that API fails if resource index is out of range
++ EXPECT_EQ(get_additional_redfish_resource_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, 100, &resource_id1_read,
++ &sub_uri_length1_read, &sub_uri1_read),
++ PLDM_ERROR_INVALID_DATA);
++
++ EXPECT_EQ(get_additional_redfish_resource_from_decoded_get_pdr_resp(
++ actual_pdr_record_data_read, 0, &resource_id1_read,
++ &sub_uri_length1_read, &sub_uri1_read),
++ PLDM_SUCCESS);
++
++ EXPECT_EQ(resource_id1, resource_id1_read);
++ EXPECT_EQ(sub_uri_length1, sub_uri_length1_read);
++ EXPECT_STREQ(sub_uri1, sub_uri1_read);
++}
++
+ TEST(GetPDRRepositoryInfo, testGoodEncodeResponse)
+ {
+ uint8_t completionCode = 0;
+--
+2.47.0.277.g8800431eea-goog
+
diff --git a/recipes-phosphor/libpldm/libpldm_%.bbappend b/recipes-phosphor/libpldm/libpldm_%.bbappend
index c7119b0..14a6979 100644
--- a/recipes-phosphor/libpldm/libpldm_%.bbappend
+++ b/recipes-phosphor/libpldm/libpldm_%.bbappend
@@ -14,4 +14,6 @@
file://0007-Adding-RDEOperationEnumerate-support.patch \
file://0008-Add-APIs-to-get-Op-Enumerate-s-encoded-request-and-d.patch \
file://0009-libpldm-support-SupplyCustomRequestParameters-comman.patch \
+ file://0010-Add-support-platform-requester-type-command-support.patch \
+ file://0011-Add-support-for-Redfish-PDR-encoding-decoding.patch \
"