blob: a6a8cbd092a1abbafafb528f12ba6901fb369a8a [file]
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