| From 5a24a4a2239abf9d00ad4e7a8c9b870edb1eff39 Mon Sep 17 00:00:00 2001 |
| From: Harsh Tyagi <harshtya@google.com> |
| Date: Thu, 6 Jul 2023 16:13:40 +0000 |
| Subject: [PATCH] Add support for RDE Discovery Negotiate and Medium params |
| |
| Tested: |
| |
| Tested on a dev board that supported MCTP over PLDM communication by |
| connecting multiple PLDM devices. Also, supported by unit testing |
| |
| Patch Tracking Bug: 291993917 |
| Upstream-Status: Pending |
| Upstream info / review: https://gerrit.openbmc.org/c/openbmc/libpldm/+/65168 |
| Justification: (Design under review) |
| https://gerrit.openbmc.org/c/openbmc/docs/+/61256 |
| --- |
| include/libpldm/meson.build | 1 + |
| .../libpldm/requester/pldm_rde_requester.h | 259 +++++++++++ |
| src/requester/meson.build | 1 + |
| src/requester/pldm_rde_requester.c | 172 ++++++++ |
| tests/meson.build | 1 + |
| tests/requester/rde_requester_test.cpp | 410 ++++++++++++++++++ |
| 6 files changed, 844 insertions(+) |
| create mode 100644 include/libpldm/requester/pldm_rde_requester.h |
| create mode 100644 src/requester/pldm_rde_requester.c |
| create mode 100644 tests/requester/rde_requester_test.cpp |
| |
| diff --git a/include/libpldm/meson.build b/include/libpldm/meson.build |
| index 9e94156..e2e3bb3 100644 |
| --- a/include/libpldm/meson.build |
| +++ b/include/libpldm/meson.build |
| @@ -18,6 +18,7 @@ libpldm_headers = files( |
| 'utils.h', |
| 'requester/pldm_base_requester.h', |
| 'pldm_rde.h', |
| + 'requester/pldm_rde_requester.h', |
| ) |
| |
| if get_option('oem-ibm').allowed() |
| diff --git a/include/libpldm/requester/pldm_rde_requester.h b/include/libpldm/requester/pldm_rde_requester.h |
| new file mode 100644 |
| index 0000000..09b2de7 |
| --- /dev/null |
| +++ b/include/libpldm/requester/pldm_rde_requester.h |
| @@ -0,0 +1,259 @@ |
| +#ifndef PLDM_RDE_REQUESTER_H |
| +#define PLDM_RDE_REQUESTER_H |
| + |
| +#ifdef __cplusplus |
| +extern "C" { |
| +#endif |
| + |
| +#include "libpldm/base.h" |
| +#include "libpldm/requester/pldm_base_requester.h" |
| +#include "libpldm/pldm_rde.h" |
| + |
| +// Currently RDE supports a maximum of 50 dictionary resources |
| +#define MAX_RESOURCE_IDS 50 |
| + |
| +#define DEFAULT_INIT 0 |
| + |
| +typedef enum rde_requester_return_codes { |
| + PLDM_RDE_REQUESTER_SUCCESS = 0, |
| + PLDM_RDE_REQUESTER_NOT_PLDM_RDE_MSG = -1, |
| + PLDM_RDE_REQUESTER_NOT_RESP_MSG = -2, |
| + PLDM_RDE_REQUESTER_SEND_FAIL = -3, |
| + PLDM_RDE_REQUESTER_RECV_FAIL = -4, |
| + PLDM_RDE_REQUESTER_NO_NEXT_COMMAND_FOUND = -5, |
| + PLDM_RDE_REQUESTER_ENCODING_REQUEST_FAILURE = -6, |
| + PLDM_RDE_CONTEXT_INITIALIZATION_ERROR = -7, |
| + PLDM_RDE_CONTEXT_NOT_READY = -8, |
| + PLDM_RDE_NO_PDR_RESOURCES_FOUND = -9 |
| +} pldm_rde_requester_rc_t; |
| + |
| +typedef enum rde_requester_status { |
| + PLDM_RDE_REQUESTER_REQUEST_FAILED = -1, |
| + PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST = 0, |
| + PLDM_RDE_REQUESTER_WAITING_FOR_RESPONSE = 1, |
| + PLDM_RDE_REQUESTER_NO_PENDING_ACTION = 2 |
| +} rde_req_status_t; |
| + |
| +typedef enum rde_context_status { |
| + CONTEXT_FREE = 0, |
| + CONTEXT_BUSY = 1, |
| + CONTEXT_CONTINUE = 2 |
| +} rde_context_status; |
| + |
| +/** |
| + * @brief This will hold the PDR Resource information |
| + * This could be modified when the P&M PLDM Type is implemented |
| + */ |
| +struct pdr_resource { |
| + uint8_t resource_id_index; |
| + uint32_t transfer_handle; |
| + uint8_t dictionary_format; |
| + uint8_t transfer_operation; |
| + uint8_t schema_class; |
| +}; |
| +/** |
| + * @brief The entire RDE Update operation is captured by the following struct |
| + */ |
| +struct rde_update_operation { |
| + uint8_t request_id; |
| + uint32_t resource_id; |
| + uint16_t operation_id; |
| + uint8_t operation_type; |
| + uint8_t operation_status; |
| + uint8_t percentage_complete; |
| + uint32_t completion_time; |
| + uint32_t result_transfer_handle; |
| + |
| + // Request Data |
| + union pldm_rde_operation_flags operation_flags; |
| + uint32_t send_data_transfer_handle; |
| + uint8_t operation_locator_length; |
| + uint8_t *operation_locator; |
| + uint32_t request_payload_length; |
| + uint8_t *request_payload; |
| + |
| + // Response Data |
| + uint32_t resp_payload_length; |
| + uint8_t *response_data; |
| + union pldm_rde_op_execution_flags *resp_operation_flags; |
| + union pldm_rde_permission_flags *resp_permission_flags; |
| + struct pldm_rde_varstring *resp_etag; |
| + |
| + // op complete |
| + uint8_t completion_code; |
| +}; |
| + |
| +/** |
| + * @brief The entire RDE Read operation is captured by the following struct |
| + */ |
| +struct rde_read_operation { |
| + uint8_t request_id; |
| + uint32_t resource_id; |
| + uint16_t operation_id; |
| + uint8_t operation_type; |
| + uint8_t operation_status; |
| + uint8_t percentage_complete; |
| + uint32_t completion_time; |
| + uint32_t result_transfer_handle; |
| + |
| + // Request Data |
| + union pldm_rde_operation_flags operation_flags; |
| + uint32_t send_data_transfer_handle; |
| + uint8_t operation_locator_length; |
| + uint8_t *operation_locator; |
| + uint32_t request_payload_length; |
| + uint8_t *request_payload; |
| + |
| + // Response Data |
| + uint32_t resp_payload_length; |
| + uint8_t *response_data; |
| + union pldm_rde_op_execution_flags *resp_operation_flags; |
| + union pldm_rde_permission_flags *resp_permission_flags; |
| + struct pldm_rde_varstring *resp_etag; |
| + |
| + // For multipart receive |
| + uint32_t transfer_handle; |
| + uint8_t transfer_operation; |
| + |
| + // op complete |
| + uint8_t completion_code; |
| +}; |
| + |
| +/** |
| + * @brief RDE Requester context |
| + */ |
| +struct pldm_rde_requester_context { |
| + uint8_t context_status; |
| + int next_command; |
| + uint8_t requester_status; |
| + struct pdr_resource *current_pdr_resource; |
| + void *operation_ctx; |
| +}; |
| + |
| +/** |
| + * @brief Context Manager- Manages all the contexts and common information per |
| + * rde device |
| + */ |
| +struct pldm_rde_requester_manager { |
| + bool initialized; |
| + uint8_t n_ctx; |
| + char device_name[8]; |
| + int net_id; |
| + |
| + uint8_t mc_concurrency; |
| + uint32_t mc_transfer_size; |
| + bitfield16_t *mc_feature_support; |
| + uint32_t negotiated_transfer_size; |
| + |
| + uint32_t resource_ids[MAX_RESOURCE_IDS]; |
| + uint8_t number_of_resources; |
| + |
| + struct pldm_rde_device_info *device; |
| + // Pointer to an array of contexts of size n_ctx. |
| + struct pldm_rde_requester_context *ctx; |
| + // A callback to free the pldm_rde_requester_context memory. |
| + void (*free_requester_ctx)(void *ctx_memory); |
| +}; |
| + |
| +/** |
| + * @brief Callback function for letting the requester handle response payload |
| + */ |
| +typedef void (*callback_funct)(struct pldm_rde_requester_manager *manager, |
| + struct pldm_rde_requester_context *ctx, |
| + /*payload_array*/ uint8_t **, |
| + /*payload_length*/ uint32_t, |
| + /*has_checksum*/ bool); |
| + |
| +/** |
| + * @brief Initializes the context for PLDM RDE discovery commands |
| + * |
| + * @param[in] device_id - Device id of the RDE device |
| + * @param[in] net_id - Network ID to distinguish between RDE Devices |
| + * @param[in] manager - Pointer to Context 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 |
| + * memory to contexts |
| + * |
| + * @return pldm_requester_rc_t (errno may be set) |
| + */ |
| +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, |
| + struct pldm_rde_requester_context *(*alloc_requester_ctx)( |
| + uint8_t number_of_ctx), |
| + |
| + // Callback function to clean any context memory |
| + void (*free_requester_ctx)(void *ctx_memory)); |
| + |
| +/** |
| + * @brief Sets the first command to be triggered for base discovery and sets |
| + * the status of context to "Ready to PICK |
| + * |
| + * @param[in] ctx - pointer to a context which is to be initialized |
| + * |
| + * @return pldm_requester_rc_t (errno may be set) |
| + */ |
| +pldm_rde_requester_rc_t |
| +pldm_rde_start_discovery(struct pldm_rde_requester_context *ctx); |
| + |
| +/** |
| + * @brief Pushes the response values to the context of the PLDM_RDE 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[in] manager - Context Manager |
| + * @param[in] ctx - a pointer to the context |
| + * @param[in] resp_msg - a pointer to the response message that the caller |
| + * received |
| + * @param[in] resp_size - size of the response message payload |
| + * |
| + * @return pldm_requester_rc_t (errno may be set) |
| + */ |
| +pldm_rde_requester_rc_t |
| +pldm_rde_discovery_push_response(struct pldm_rde_requester_manager *manager, |
| + struct pldm_rde_requester_context *ctx, |
| + void *resp_msg, size_t resp_size); |
| + |
| +/** |
| + * @brief Gets the next Discovery Command required for RDE |
| + * |
| + * @param[in] instance_id - Getting the instance_id |
| + * @param[in] manager - PLDM RDE Manager object |
| + * @param[in] current_ctx - PLDM RDE Requester context which would be |
| + * responsible for all actions of discovery commands |
| + * @param[out] request - Request byte stream |
| + * |
| + * @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); |
| + |
| +/** |
| + * @brief Creates the RDE context required for RDE operation. Sets the initial |
| + * state of the context |
| + * |
| + * @param[in] current_ctx - Context to be set with the inital state |
| + * |
| + * @return pldm_requester_rc_t (errno may be set) |
| + */ |
| +pldm_rde_requester_rc_t |
| +pldm_rde_create_context(struct pldm_rde_requester_context *current_ctx); |
| + |
| +#ifdef __cplusplus |
| +} |
| +#endif |
| + |
| +#endif /* PLDM_RDE_REQUESTER_H */ |
| diff --git a/src/requester/meson.build b/src/requester/meson.build |
| index 47571ba..4430682 100644 |
| --- a/src/requester/meson.build |
| +++ b/src/requester/meson.build |
| @@ -2,4 +2,5 @@ libpldm_sources += files( |
| 'instance-id.c', |
| 'pldm.c', |
| 'pldm_base_requester.c', |
| + 'pldm_rde_requester.c' |
| ) |
| diff --git a/src/requester/pldm_rde_requester.c b/src/requester/pldm_rde_requester.c |
| new file mode 100644 |
| index 0000000..bf55c20 |
| --- /dev/null |
| +++ b/src/requester/pldm_rde_requester.c |
| @@ -0,0 +1,172 @@ |
| +#include "libpldm/requester/pldm_rde_requester.h" |
| + |
| +#include "libpldm/base.h" |
| +#include "libpldm/pldm.h" |
| + |
| +#include <stdio.h> |
| +#include <stdlib.h> |
| +#include <string.h> |
| + |
| +LIBPLDM_ABI_STABLE |
| +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, |
| + struct pldm_rde_requester_context *(*alloc_requester_ctx)( |
| + uint8_t number_of_ctx), |
| + void (*free_requester_ctx)(void *ctx_memory)) |
| +{ |
| + fprintf(stdout, "Initializing Context Manager...\n"); |
| + if (manager == NULL) { |
| + fprintf(stderr, "Memory not allocated to context manager.\n"); |
| + return PLDM_RDE_CONTEXT_INITIALIZATION_ERROR; |
| + } |
| + |
| + if ((device_id == NULL) || (strlen(device_id) == 0) || |
| + (strlen(device_id) > 8)) { |
| + fprintf(stderr, "Incorrect device id provided\n"); |
| + return PLDM_RDE_CONTEXT_INITIALIZATION_ERROR; |
| + } |
| + |
| + if ((alloc_requester_ctx == NULL) || (free_requester_ctx == NULL)) { |
| + fprintf(stderr, "No callback functions for handling request " |
| + "contexts found.\n"); |
| + return PLDM_RDE_CONTEXT_INITIALIZATION_ERROR; |
| + } |
| + |
| + manager->initialized = true; |
| + manager->mc_concurrency = mc_concurrency; |
| + manager->mc_transfer_size = mc_transfer_size; |
| + 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 |
| + 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; |
| +} |
| + |
| +LIBPLDM_ABI_STABLE |
| +pldm_rde_requester_rc_t |
| +pldm_rde_start_discovery(struct pldm_rde_requester_context *ctx) |
| +{ |
| + if (ctx->context_status == CONTEXT_BUSY) { |
| + return PLDM_RDE_CONTEXT_NOT_READY; |
| + } |
| + ctx->next_command = PLDM_NEGOTIATE_REDFISH_PARAMETERS; |
| + return PLDM_RDE_REQUESTER_SUCCESS; |
| +} |
| + |
| +LIBPLDM_ABI_STABLE |
| +pldm_rde_requester_rc_t |
| +pldm_rde_create_context(struct pldm_rde_requester_context *ctx) |
| +{ |
| + if (ctx == NULL) { |
| + return PLDM_RDE_CONTEXT_INITIALIZATION_ERROR; |
| + } |
| + ctx->context_status = CONTEXT_FREE; |
| + ctx->next_command = PLDM_RDE_REQUESTER_NO_NEXT_COMMAND_FOUND; |
| + 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_discovery_command( |
| + uint8_t instance_id, struct pldm_rde_requester_manager *manager, |
| + struct pldm_rde_requester_context *current_ctx, struct pldm_msg *request) |
| +{ |
| + 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_NEGOTIATE_REDFISH_PARAMETERS: { |
| + rc = encode_negotiate_redfish_parameters_req( |
| + instance_id, manager->mc_concurrency, |
| + manager->mc_feature_support, request); |
| + break; |
| + } |
| + case PLDM_NEGOTIATE_MEDIUM_PARAMETERS: { |
| + rc = encode_negotiate_medium_parameters_req( |
| + instance_id, manager->mc_transfer_size, request); |
| + break; |
| + } |
| + default: |
| + rc = PLDM_RDE_REQUESTER_NO_NEXT_COMMAND_FOUND; |
| + } |
| + if (rc) { |
| + fprintf(stderr, "Unable to encode request with rc: %d\n", rc); |
| + return PLDM_RDE_REQUESTER_ENCODING_REQUEST_FAILURE; |
| + } |
| + return PLDM_RDE_REQUESTER_SUCCESS; |
| +} |
| + |
| +LIBPLDM_ABI_STABLE |
| +pldm_rde_requester_rc_t |
| +pldm_rde_discovery_push_response(struct pldm_rde_requester_manager *manager, |
| + struct pldm_rde_requester_context *ctx, |
| + void *resp_msg, size_t resp_size) |
| +{ |
| + int rc = 0; |
| + switch (ctx->next_command) { |
| + case PLDM_NEGOTIATE_REDFISH_PARAMETERS: { |
| + uint8_t completion_code = DEFAULT_INIT; |
| + struct pldm_rde_device_info *deviceInfo = |
| + malloc(sizeof(struct pldm_rde_device_info)); |
| + rc = decode_negotiate_redfish_parameters_resp( |
| + resp_msg, resp_size - sizeof(struct pldm_msg_hdr), |
| + &completion_code, deviceInfo); |
| + if (rc || completion_code) { |
| + ctx->requester_status = |
| + PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| + } |
| + manager->device = deviceInfo; |
| + ctx->next_command = PLDM_NEGOTIATE_MEDIUM_PARAMETERS; |
| + ctx->context_status = CONTEXT_FREE; |
| + ctx->requester_status = |
| + PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST; |
| + return PLDM_RDE_REQUESTER_SUCCESS; |
| + } |
| + case PLDM_NEGOTIATE_MEDIUM_PARAMETERS: { |
| + uint8_t completion_code = DEFAULT_INIT; |
| + uint32_t max_device_transfer_size = DEFAULT_INIT; |
| + rc = decode_negotiate_medium_parameters_resp( |
| + resp_msg, resp_size - sizeof(struct pldm_msg_hdr), |
| + &completion_code, &max_device_transfer_size); |
| + if (rc || completion_code) { |
| + ctx->requester_status = |
| + PLDM_RDE_REQUESTER_REQUEST_FAILED; |
| + } |
| + manager->device->device_maximum_transfer_chunk_size = |
| + max_device_transfer_size; |
| + |
| + manager->negotiated_transfer_size = |
| + max_device_transfer_size > manager->mc_transfer_size |
| + ? manager->mc_transfer_size |
| + : max_device_transfer_size; |
| + |
| + ctx->next_command = 0; |
| + ctx->context_status = CONTEXT_FREE; |
| + ctx->requester_status = PLDM_RDE_REQUESTER_NO_PENDING_ACTION; |
| + return PLDM_RDE_REQUESTER_SUCCESS; |
| + } |
| + |
| + default: |
| + return PLDM_RDE_REQUESTER_NO_NEXT_COMMAND_FOUND; |
| + } |
| +} |
| diff --git a/tests/meson.build b/tests/meson.build |
| index 0449c3d..6fcbc93 100644 |
| --- a/tests/meson.build |
| +++ b/tests/meson.build |
| @@ -27,6 +27,7 @@ tests = [ |
| 'responder', |
| 'requester/base_requester_test', |
| 'libpldm_rde_test', |
| + 'requester/rde_requester_test', |
| ] |
| |
| if get_option('abi').contains('testing') |
| diff --git a/tests/requester/rde_requester_test.cpp b/tests/requester/rde_requester_test.cpp |
| new file mode 100644 |
| index 0000000..efa4113 |
| --- /dev/null |
| +++ b/tests/requester/rde_requester_test.cpp |
| @@ -0,0 +1,410 @@ |
| +#include <string.h> |
| + |
| +#include <array> |
| +#include <cstring> |
| +#include <iostream> |
| +#include <vector> |
| + |
| +#include "libpldm/requester/pldm_rde_requester.h" |
| + |
| +#include <gmock/gmock.h> |
| +#include <gtest/gtest.h> |
| +struct pldm_rde_requester_context rde_contexts[256]; |
| +std::vector<uint32_t> resource_ids; |
| +int rde_context_counter = 0; |
| + |
| +uint8_t TEST_MC_CONCURRENCY; |
| +uint32_t TEST_MC_TRANSFER_SIZE; |
| +bitfield8_t* TEST_DEV_CAPABILITES; |
| +bitfield16_t* TEST_MC_FEATURES; |
| +uint8_t TEST_NUMBER_OF_RESOURCES; |
| +std::string TEST_DEV_ID; |
| +int TEST_NET_ID; |
| +int TEST_INSTANCE_ID; |
| + |
| +std::map<uint8_t, int> rde_command_request_size = { |
| + {PLDM_NEGOTIATE_REDFISH_PARAMETERS, 3}, |
| + {PLDM_NEGOTIATE_MEDIUM_PARAMETERS, 4}, |
| + {PLDM_GET_SCHEMA_DICTIONARY, 5}, |
| + {PLDM_RDE_MULTIPART_RECEIVE, 7}}; |
| + |
| +void initial_setup() |
| +{ |
| + TEST_INSTANCE_ID = 1; |
| + TEST_MC_CONCURRENCY = uint8_t(3); |
| + TEST_MC_TRANSFER_SIZE = uint32_t(2056); |
| + TEST_MC_FEATURES = (bitfield16_t*)malloc(sizeof(bitfield16_t)); |
| + TEST_DEV_CAPABILITES = (bitfield8_t*)malloc(sizeof(bitfield8_t)); |
| + TEST_MC_FEATURES->value = (uint16_t)102; |
| + |
| + TEST_NUMBER_OF_RESOURCES = 2; |
| + resource_ids.emplace_back(0x00000000); |
| + resource_ids.emplace_back(0x00010000); |
| + |
| + TEST_NET_ID = 9; |
| + TEST_DEV_ID = "rde_dev"; |
| +} |
| + |
| +void free_memory(void* context) |
| +{ |
| + free(context); |
| +} |
| +struct pldm_rde_requester_context* |
| + allocate_memory_to_contexts(uint8_t number_of_contexts) |
| +{ |
| + int rc; |
| + int end = rde_context_counter + number_of_contexts; |
| + for (rde_context_counter = 0; rde_context_counter < end; |
| + rde_context_counter++) |
| + { |
| + struct pldm_rde_requester_context* current_ctx = |
| + (struct pldm_rde_requester_context*)malloc( |
| + sizeof(struct pldm_rde_requester_context)); |
| + IGNORE(rc); |
| + rc = pldm_rde_create_context(current_ctx); |
| + if (rc) |
| + { |
| + return NULL; |
| + } |
| + rde_contexts[rde_context_counter] = *current_ctx; |
| + } |
| + |
| + return &rde_contexts[0]; |
| +} |
| + |
| +TEST(ContextManagerInitializationSuccess, RDERequesterTest) |
| +{ |
| + 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); |
| + EXPECT_EQ(manager->mc_concurrency, TEST_MC_CONCURRENCY); |
| + EXPECT_EQ(manager->mc_transfer_size, TEST_MC_TRANSFER_SIZE); |
| + EXPECT_EQ(manager->mc_feature_support, TEST_MC_FEATURES); |
| + EXPECT_EQ(manager->device_name, TEST_DEV_ID); |
| + EXPECT_EQ(manager->net_id, TEST_NET_ID); |
| + EXPECT_EQ(manager->number_of_resources, TEST_NUMBER_OF_RESOURCES); |
| + EXPECT_EQ(manager->resource_ids[0], 0x00000000); |
| + EXPECT_EQ(manager->resource_ids[1], 0x00010000); |
| +} |
| + |
| +TEST(ContextManagerInitializationFailureDueToNullManager, RDERequesterTest) |
| +{ |
| + initial_setup(); |
| + |
| + struct pldm_rde_requester_manager* manager = NULL; |
| + 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_RDE_CONTEXT_INITIALIZATION_ERROR); |
| +} |
| + |
| +TEST(ContextManagerInitializationFailureDueToWrongDevId, RDERequesterTest) |
| +{ |
| + initial_setup(); |
| + std::string incorrect_dev_id; |
| + struct pldm_rde_requester_manager* manager = |
| + new pldm_rde_requester_manager(); |
| + int rc = pldm_rde_init_context( |
| + incorrect_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_RDE_CONTEXT_INITIALIZATION_ERROR); |
| + |
| + incorrect_dev_id = ""; |
| + rc = pldm_rde_init_context( |
| + incorrect_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_RDE_CONTEXT_INITIALIZATION_ERROR); |
| + |
| + incorrect_dev_id = "VERY_LONG_DEV_ID"; |
| + rc = pldm_rde_init_context( |
| + incorrect_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_RDE_CONTEXT_INITIALIZATION_ERROR); |
| +} |
| + |
| +TEST(ContextManagerInitializationFailureDueToNullAllocatorFunctions, |
| + RDERequesterTest) |
| +{ |
| + 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(), NULL, free_memory); |
| + EXPECT_EQ(rc, PLDM_RDE_CONTEXT_INITIALIZATION_ERROR); |
| + |
| + 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, NULL); |
| + EXPECT_EQ(rc, PLDM_RDE_CONTEXT_INITIALIZATION_ERROR); |
| +} |
| + |
| +TEST(StartRDEDiscoverySuccess, RDEDiscoveryTest) |
| +{ |
| + 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); |
| + |
| + struct pldm_rde_requester_context base_context = rde_contexts[0]; |
| + |
| + rc = pldm_rde_start_discovery(&base_context); |
| + |
| + EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS); |
| + EXPECT_EQ(base_context.next_command, PLDM_NEGOTIATE_REDFISH_PARAMETERS); |
| +} |
| + |
| +TEST(StartRDEDiscoveryFailure, RDEDiscoveryTest) |
| +{ |
| + 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); |
| + |
| + struct pldm_rde_requester_context base_context = rde_contexts[0]; |
| + |
| + base_context.context_status = CONTEXT_BUSY; |
| + rc = pldm_rde_start_discovery(&base_context); |
| + EXPECT_EQ(rc, PLDM_RDE_CONTEXT_NOT_READY); |
| +} |
| + |
| +TEST(CreateRequesterContextSuccess, RDEDiscoveryTest) |
| +{ |
| + 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); |
| + |
| + struct pldm_rde_requester_context* current_ctx = |
| + new pldm_rde_requester_context(); |
| + rc = pldm_rde_create_context(current_ctx); |
| + |
| + EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS); |
| + EXPECT_EQ(current_ctx->context_status, CONTEXT_FREE); |
| + EXPECT_EQ(current_ctx->requester_status, |
| + PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST); |
| + EXPECT_EQ(current_ctx->next_command, |
| + PLDM_RDE_REQUESTER_NO_NEXT_COMMAND_FOUND); |
| +} |
| + |
| +TEST(CreateRequesterContextFailure, RDEDiscoveryTest) |
| +{ |
| + 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); |
| + |
| + struct pldm_rde_requester_context* current_ctx = NULL; |
| + rc = pldm_rde_create_context(current_ctx); |
| + |
| + EXPECT_EQ(rc, PLDM_RDE_CONTEXT_INITIALIZATION_ERROR); |
| +} |
| + |
| +int test_get_next_request_seq(pldm_rde_requester_manager** manager, |
| + struct pldm_rde_requester_context** ctx, |
| + uint8_t next_command) |
| +{ |
| + (*ctx)->next_command = next_command; |
| + int requestBytes = 0; |
| + if (rde_command_request_size.find((*ctx)->next_command) != |
| + rde_command_request_size.end()) |
| + { |
| + requestBytes = rde_command_request_size[(*ctx)->next_command]; |
| + } |
| + std::vector<uint8_t> msg(sizeof(pldm_msg_hdr) + requestBytes); |
| + auto request = reinterpret_cast<pldm_msg*>(msg.data()); |
| + return pldm_rde_get_next_discovery_command(TEST_INSTANCE_ID, *manager, *ctx, |
| + request); |
| +} |
| +TEST(GetNextRequestInSequenceSuccess, PLDMRDEDiscovery) |
| +{ |
| + |
| + 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); |
| + |
| + struct pldm_rde_requester_context* base_context = |
| + new pldm_rde_requester_context(); |
| + rc = pldm_rde_create_context(base_context); |
| + |
| + rc = test_get_next_request_seq(&manager, &base_context, |
| + PLDM_NEGOTIATE_REDFISH_PARAMETERS); |
| + EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS); |
| + |
| + rc = test_get_next_request_seq(&manager, &base_context, |
| + PLDM_NEGOTIATE_MEDIUM_PARAMETERS); |
| + EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS); |
| +} |
| + |
| +TEST(GetNextRequestInSequenceFailure, PLDMRDEDiscovery) |
| +{ |
| + 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); |
| + |
| + struct pldm_rde_requester_context* base_context = |
| + new pldm_rde_requester_context(); |
| + rc = pldm_rde_create_context(base_context); |
| + rc = test_get_next_request_seq(&manager, &base_context, |
| + 0x0023); // Unknown request code to encode |
| + EXPECT_EQ(rc, PLDM_RDE_REQUESTER_ENCODING_REQUEST_FAILURE); |
| +} |
| + |
| +TEST(PushDiscoveryResponseRedfishParamSuccess, PLDMRDEDiscovery) |
| +{ |
| + 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); |
| + |
| + struct pldm_rde_requester_context* base_context = |
| + new pldm_rde_requester_context(); |
| + rc = pldm_rde_create_context(base_context); |
| + |
| + std::vector<uint8_t> response(sizeof(pldm_msg_hdr) + 12, 0); |
| + uint8_t* responseMsg = response.data(); |
| + size_t responseMsgSize = sizeof(pldm_msg_hdr) + 12; |
| + auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg); |
| + |
| + rc = test_get_next_request_seq(&manager, &base_context, |
| + PLDM_NEGOTIATE_REDFISH_PARAMETERS); |
| + EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS); |
| + rc = encode_negotiate_redfish_parameters_resp( |
| + TEST_INSTANCE_ID, /*completion_code=*/0, |
| + /*device_concurrency=*/TEST_MC_CONCURRENCY, *TEST_DEV_CAPABILITES, |
| + /*device_capabilities_flags=*/*TEST_MC_FEATURES, |
| + /*dev provider name*/ 0x00f, |
| + /*Example*/ TEST_DEV_ID.c_str(), |
| + /*device_configuration_signature*/ PLDM_RDE_VARSTRING_UTF_16, |
| + responsePtr); |
| + EXPECT_EQ(rc, 0); |
| + |
| + rc = pldm_rde_discovery_push_response(manager, base_context, responsePtr, |
| + responseMsgSize); |
| + |
| + struct pldm_rde_device_info* deviceInfo = manager->device; |
| + EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS); |
| + EXPECT_EQ(deviceInfo->device_concurrency, TEST_MC_CONCURRENCY); |
| + EXPECT_EQ(deviceInfo->device_capabilities_flag.byte, |
| + TEST_DEV_CAPABILITES->byte); |
| + EXPECT_EQ(deviceInfo->device_feature_support.value, |
| + TEST_MC_FEATURES->value); |
| + EXPECT_EQ(base_context->next_command, PLDM_NEGOTIATE_MEDIUM_PARAMETERS); |
| + |
| + rc = test_get_next_request_seq(&manager, &base_context, |
| + PLDM_NEGOTIATE_MEDIUM_PARAMETERS); |
| + EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS); |
| + |
| + rc = encode_negotiate_medium_parameters_resp( |
| + TEST_INSTANCE_ID, /*completion_code=*/0, |
| + /*device_maximum_transfer_bytes*/ 256, responsePtr); |
| + EXPECT_EQ(rc, 0); |
| +} |
| + |
| +TEST(PushDiscoveryResponseRedfishMediumParamSuccess, PLDMRDEDiscovery) |
| +{ |
| + 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); |
| + |
| + struct pldm_rde_requester_context* base_context = |
| + new pldm_rde_requester_context(); |
| + rc = pldm_rde_create_context(base_context); |
| + |
| + 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 = test_get_next_request_seq(&manager, &base_context, |
| + PLDM_NEGOTIATE_MEDIUM_PARAMETERS); |
| + EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS); |
| + |
| + rc = encode_negotiate_medium_parameters_resp( |
| + TEST_INSTANCE_ID, /*completion_code=*/0, |
| + /*device_maximum_transfer_bytes*/ 256, responsePtr); |
| + EXPECT_EQ(rc, 0); |
| + |
| + manager->device = (struct pldm_rde_device_info*)malloc( |
| + sizeof(struct pldm_rde_device_info)); |
| + manager->device->device_maximum_transfer_chunk_size = 256; |
| + manager->mc_transfer_size = 256; |
| + rc = pldm_rde_discovery_push_response(manager, base_context, responsePtr, |
| + responseMsgSize); |
| + |
| + EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS); |
| + EXPECT_EQ(manager->negotiated_transfer_size, 256); |
| +} |
| + |
| +TEST(PushDiscoveryResponseFailure, PLDMRDEDiscovery) |
| +{ |
| + 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); |
| + |
| + struct pldm_rde_requester_context* base_context = |
| + new pldm_rde_requester_context(); |
| + rc = pldm_rde_create_context(base_context); |
| + std::vector<uint8_t> response(sizeof(pldm_msg_hdr) + 12, 0); |
| + uint8_t* responseMsg = response.data(); |
| + size_t responseMsgSize = sizeof(pldm_msg_hdr) + 12; |
| + auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg); |
| + rc = pldm_rde_discovery_push_response(manager, base_context, responsePtr, |
| + responseMsgSize); |
| + |
| + EXPECT_EQ(rc, PLDM_RDE_REQUESTER_NO_NEXT_COMMAND_FOUND); |
| +} |
| -- |
| 2.43.0.rc2.451.g8631bc7472-goog |
| |