blob: c17b7ce6454aa1bd2f37b718932e4feedbbe867b [file]
From 950c48197417ed7184ba922736618c29c9e60d5d Mon Sep 17 00:00:00 2001
From: Harsh Tyagi <harshtya@google.com>
Date: Mon, 24 Jul 2023 22:10:11 +0000
Subject: [PATCH] Add PLDM Base discovery command sequence library
Tested:
Added unit test for PLDM discovery command sequence library
Patch Tracking Bug: b/277635368
Upstream-Status: Pending
Upstream info / review: https://gerrit.openbmc.org/c/openbmc/libpldm/+/64103
Justification: Blocked on design: https://gerrit.openbmc.org/c/openbmc/docs/+/61256
---
include/libpldm/meson.build | 1 +
.../libpldm/requester/pldm_base_requester.h | 89 +++++++++++++++
src/requester/meson.build | 3 +-
src/requester/pldm_base_requester.c | 82 ++++++++++++++
tests/meson.build | 1 +
tests/requester/base_requester_test.cpp | 104 ++++++++++++++++++
6 files changed, 279 insertions(+), 1 deletion(-)
create mode 100644 include/libpldm/requester/pldm_base_requester.h
create mode 100644 src/requester/pldm_base_requester.c
create mode 100644 tests/requester/base_requester_test.cpp
diff --git a/include/libpldm/meson.build b/include/libpldm/meson.build
index 235a7a6..22f6295 100644
--- a/include/libpldm/meson.build
+++ b/include/libpldm/meson.build
@@ -16,6 +16,7 @@ libpldm_headers = files(
'transport/af-mctp.h',
'transport/mctp-demux.h',
'utils.h',
+ 'requester/pldm_base_requester.h',
)
if get_option('oem-ibm').allowed()
diff --git a/include/libpldm/requester/pldm_base_requester.h b/include/libpldm/requester/pldm_base_requester.h
new file mode 100644
index 0000000..ce49637
--- /dev/null
+++ b/include/libpldm/requester/pldm_base_requester.h
@@ -0,0 +1,89 @@
+#ifndef PLDM_BASE_REQUESTER_H
+#define PLDM_BASE_REQUESTER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "libpldm/base.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define PLDM_TYPES 6
+#define MAX_DEV_NAME_SIZE 32
+
+typedef enum requester_return_codes {
+ PLDM_BASE_REQUESTER_SUCCESS = 0,
+ PLDM_BASE_REQUESTER_NOT_PLDM_BASE_MSG = -1,
+ PLDM_BASE_REQUESTER_NOT_RESP_MSG = -2,
+ PLDM_BASE_REQUESTER_SEND_FAIL = -3,
+ PLDM_BASE_REQUESTER_RECV_FAIL = -4,
+ PLDM_BASE_REQUESTER_NO_NEXT_COMMAND_FOUND = -5,
+ PLDM_BASE_REQUESTER_ENCODING_REQUEST_FAILURE = -6,
+ PLDM_BASE_CONTEXT_INITIALIZATION_ERROR = -7,
+ PLDM_BASE_CONTEXT_NOT_READY = -8
+} pldm_base_requester_rc_t;
+
+typedef enum requester_status {
+ PLDM_BASE_REQUESTER_REQUEST_FAILED = -1,
+ PLDM_BASE_REQUESTER_READY_TO_PICK_NEXT_REQUEST = 0,
+ PLDM_BASE_REQUESTER_WAITING_FOR_RESPONSE = 1,
+ PLDM_BASE_REQUESTER_NO_PENDING_ACTION = 2
+} req_status_t;
+
+struct requester_base_context {
+ bool initialized;
+ uint8_t next_command;
+ uint8_t requester_status;
+ uint8_t command_pldm_type;
+ uint8_t tid;
+ char dev_name[MAX_DEV_NAME_SIZE];
+ int net_id; // MCTP network id
+ bitfield8_t pldm_types[PLDM_MAX_TYPES / 8];
+ uint8_t pldm_commands[PLDM_MAX_TYPES][PLDM_MAX_CMDS_PER_TYPE];
+ ver32_t pldm_versions[PLDM_MAX_TYPES];
+};
+/**
+ * @brief Initializes the context for PLDM Base discovery commands
+ *
+ * @param[in] ctx - pointer to a context which is to be initialized
+ *
+ * @return pldm_requester_rc_t (errno may be set)
+ */
+pldm_base_requester_rc_t
+pldm_base_init_context(struct requester_base_context *ctx,
+ const char *dev_name, int net_id);
+
+/**
+ * @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_base_requester_rc_t
+pldm_base_start_discovery(struct requester_base_context *ctx);
+/**
+ * @brief Gets the next PLDM command from a request buffer to be processed
+ *
+ * @param[in] ctx - pointer to a context which is to be initialized
+ * @param[in] instance_id - instance id of the pldm requester
+ * @param[out] request - byte array that will store the encoded request msg
+ * according to the pldm command type. Caller is responsible for allocating and
+ * cleaning up memory of this variable
+ *
+ * @return pldm_requester_rc_t (errno may be set)
+ */
+pldm_base_requester_rc_t
+pldm_base_get_next_request(struct requester_base_context *ctx,
+ uint8_t instance_id, struct pldm_msg *request);
+
+//TODO(@harshtya): Add pldm_push_base_response() function declaration that takes
+//care of updating the context with the responses received for PLDM requests
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PLDM_BASE_REQUESTER_H */
\ No newline at end of file
diff --git a/src/requester/meson.build b/src/requester/meson.build
index 663b607..47571ba 100644
--- a/src/requester/meson.build
+++ b/src/requester/meson.build
@@ -1,4 +1,5 @@
libpldm_sources += files(
'instance-id.c',
- 'pldm.c'
+ 'pldm.c',
+ 'pldm_base_requester.c',
)
diff --git a/src/requester/pldm_base_requester.c b/src/requester/pldm_base_requester.c
new file mode 100644
index 0000000..5183171
--- /dev/null
+++ b/src/requester/pldm_base_requester.c
@@ -0,0 +1,82 @@
+#include "libpldm/requester/pldm_base_requester.h"
+
+#include "libpldm/base.h"
+#include "libpldm/pldm.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+LIBPLDM_ABI_STABLE
+pldm_base_requester_rc_t
+pldm_base_init_context(struct requester_base_context *ctx,
+ const char *device_id, int net_id)
+{
+ if (ctx->initialized) {
+ fprintf(stderr, "No memory allocated to base context\n");
+ return PLDM_BASE_CONTEXT_INITIALIZATION_ERROR;
+ }
+
+ ctx->initialized = true;
+ ctx->requester_status = PLDM_BASE_REQUESTER_NO_PENDING_ACTION;
+ strcpy(ctx->dev_name, device_id);
+ ctx->net_id = net_id;
+ return PLDM_BASE_REQUESTER_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+pldm_base_requester_rc_t
+pldm_base_start_discovery(struct requester_base_context *ctx)
+{
+ if (!ctx->initialized &&
+ ctx->requester_status != PLDM_BASE_REQUESTER_NO_PENDING_ACTION) {
+ return PLDM_BASE_CONTEXT_NOT_READY;
+ }
+ ctx->next_command = PLDM_GET_TID;
+ ctx->requester_status = PLDM_BASE_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
+ return PLDM_BASE_REQUESTER_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+pldm_base_requester_rc_t
+pldm_base_get_next_request(struct requester_base_context *ctx,
+ uint8_t instance_id, struct pldm_msg *request)
+{
+ int rc;
+ switch (ctx->next_command) {
+ case PLDM_GET_TID: {
+ rc = encode_get_tid_req(instance_id, request);
+ break;
+ }
+ case PLDM_GET_PLDM_TYPES: {
+ rc = encode_get_types_req(instance_id, request);
+ break;
+ }
+ case PLDM_GET_PLDM_VERSION: {
+ uint8_t pldm_type = ctx->command_pldm_type;
+ rc = encode_get_version_req(instance_id, /*transfer_handle=*/0,
+ PLDM_GET_FIRSTPART, pldm_type,
+ request);
+ break;
+ }
+
+ case PLDM_GET_PLDM_COMMANDS: {
+ uint8_t pldmType = ctx->command_pldm_type;
+ rc = encode_get_commands_req(instance_id, pldmType,
+ ctx->pldm_versions[pldmType],
+ request);
+ break;
+ }
+
+ default:
+ return PLDM_BASE_REQUESTER_NO_NEXT_COMMAND_FOUND;
+ }
+
+ if (rc) {
+ fprintf(stderr, "Unable to encode request with rc: %d", rc);
+ return PLDM_BASE_REQUESTER_ENCODING_REQUEST_FAILURE;
+ }
+ return PLDM_BASE_REQUESTER_SUCCESS;
+}
+
+// TODO(@harshtya): Add code for pldm_base_push_response()
diff --git a/tests/meson.build b/tests/meson.build
index dba7870..a15e7ec 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -25,6 +25,7 @@ tests = [
'libpldm_firmware_update_test',
'msgbuf',
'responder',
+ 'requester/base_requester_test',
]
if get_option('abi').contains('testing')
diff --git a/tests/requester/base_requester_test.cpp b/tests/requester/base_requester_test.cpp
new file mode 100644
index 0000000..0b589c8
--- /dev/null
+++ b/tests/requester/base_requester_test.cpp
@@ -0,0 +1,104 @@
+#include <string.h>
+
+#include <array>
+#include <cstring>
+#include <iostream>
+#include <vector>
+
+#include "libpldm/requester/pldm_base_requester.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+std::string TEST_DEVICE_ID = "DEVICE_ID";
+int TEST_NET_ID = 1;
+uint8_t TEST_INSTANCE_ID = 1;
+
+std::map<uint8_t, int> command_request_size = {
+ {PLDM_GET_TID, 0},
+ {PLDM_GET_PLDM_TYPES, 0},
+ {PLDM_GET_PLDM_VERSION, PLDM_GET_VERSION_REQ_BYTES},
+ {PLDM_GET_PLDM_COMMANDS, PLDM_GET_COMMANDS_REQ_BYTES}};
+
+int get_request_bytes(uint8_t request_type)
+{
+ auto it = command_request_size.find(request_type);
+ if (it != command_request_size.end())
+ {
+ return it->second;
+ }
+ return -1;
+}
+TEST(BaseContextInitializationSuccess, PLDMBaseDiscovery)
+{
+ struct requester_base_context* ctx = new requester_base_context();
+ int rc = pldm_base_init_context(ctx, TEST_DEVICE_ID.c_str(), TEST_NET_ID);
+ EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+ EXPECT_EQ(ctx->initialized, true);
+ EXPECT_EQ(ctx->requester_status, PLDM_BASE_REQUESTER_NO_PENDING_ACTION);
+}
+
+TEST(BaseContextStartDiscovery, PLDMBaseDiscovery)
+{
+ // Initializing context
+ struct requester_base_context* ctx = new requester_base_context();
+ int rc = pldm_base_init_context(ctx, TEST_DEVICE_ID.c_str(), TEST_NET_ID);
+
+ rc = pldm_base_start_discovery(ctx);
+ EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+ EXPECT_EQ(ctx->next_command, PLDM_GET_TID);
+ EXPECT_EQ(ctx->requester_status,
+ PLDM_BASE_REQUESTER_READY_TO_PICK_NEXT_REQUEST);
+}
+
+TEST(BaseContextStartDiscoveryFailure, PLDMBaseDiscovery)
+{
+ struct requester_base_context* ctx = new requester_base_context();
+
+ int rc = pldm_base_start_discovery(ctx);
+ EXPECT_EQ(rc, PLDM_BASE_CONTEXT_NOT_READY);
+}
+
+int test_get_next_request_seq(struct requester_base_context** ctx,
+ uint8_t next_command)
+{
+ (*ctx)->next_command = next_command;
+ int requestBytes = get_request_bytes((*ctx)->next_command);
+ std::vector<uint8_t> msg_tid(sizeof(pldm_msg_hdr) + requestBytes);
+ auto request = reinterpret_cast<pldm_msg*>(msg_tid.data());
+ return pldm_base_get_next_request(*ctx, TEST_INSTANCE_ID, request);
+}
+
+TEST(GetNextRequestInSequenceSuccess, PLDMBaseDiscovery)
+{
+ int rc;
+ // Initializing context
+ struct requester_base_context* ctx = new requester_base_context();
+ rc = pldm_base_init_context(ctx, TEST_DEVICE_ID.c_str(), TEST_NET_ID);
+ rc = pldm_base_start_discovery(ctx);
+
+ rc = test_get_next_request_seq(&ctx, PLDM_GET_TID);
+ EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+
+ rc = test_get_next_request_seq(&ctx, PLDM_GET_PLDM_TYPES);
+ EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+
+ rc = test_get_next_request_seq(&ctx, PLDM_GET_PLDM_VERSION);
+ EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+
+ rc = test_get_next_request_seq(&ctx, PLDM_GET_PLDM_COMMANDS);
+ EXPECT_EQ(rc, PLDM_BASE_REQUESTER_SUCCESS);
+
+ rc = test_get_next_request_seq(&ctx, PLDM_BASE_REQUESTER_NO_NEXT_COMMAND_FOUND);
+ EXPECT_EQ(rc, PLDM_BASE_REQUESTER_NO_NEXT_COMMAND_FOUND);
+
+}
+
+TEST(GetNextRequestInSequenceFailure, PLDMBaseDiscovery)
+{
+ int rc;
+ // Initializing context
+ struct requester_base_context* ctx = new requester_base_context();
+ rc = test_get_next_request_seq(&ctx, 0x0023);
+ EXPECT_EQ(rc, PLDM_BASE_REQUESTER_NO_NEXT_COMMAND_FOUND);
+}
\ No newline at end of file
--
2.43.0.rc2.451.g8631bc7472-goog