blob: d468530347eeab681f9542b1aa9780adf34ec50e [file]
From 0827b337f8d9a6ebc8ec0404b825352f603f5f2b Mon Sep 17 00:00:00 2001
From: Harsh Tyagi <harshtya@google.com>
Date: Tue, 13 Jun 2023 01:30:34 +0000
Subject: [PATCH] Add encoders and decoders for RDE support
Tested:
Tested on a dev board that supported MCTP over PLDM communication by
connecting multiple PLDM devices
Patch Tracking Bug: 290104814
Upstream-Status: Pending
Upstream info / review: https://gerrit.openbmc.org/c/openbmc/libpldm/+/65087
Justification: This change will be supported under AF_MCTP topic upstream
https://gerrit.openbmc.org/q/topic:AF_MCTP (If not the above code will be
reviewed)
---
include/libpldm/meson.build | 1 +
include/libpldm/pldm_rde.h | 827 +++++++++++++++++++++++++++++++++
src/meson.build | 3 +-
src/pldm_rde.c | 892 ++++++++++++++++++++++++++++++++++++
tests/libpldm_rde_test.cpp | 889 +++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
6 files changed, 2612 insertions(+), 1 deletion(-)
create mode 100644 include/libpldm/pldm_rde.h
create mode 100644 src/pldm_rde.c
create mode 100644 tests/libpldm_rde_test.cpp
diff --git a/include/libpldm/meson.build b/include/libpldm/meson.build
index 22f6295..9e94156 100644
--- a/include/libpldm/meson.build
+++ b/include/libpldm/meson.build
@@ -17,6 +17,7 @@ libpldm_headers = files(
'transport/mctp-demux.h',
'utils.h',
'requester/pldm_base_requester.h',
+ 'pldm_rde.h',
)
if get_option('oem-ibm').allowed()
diff --git a/include/libpldm/pldm_rde.h b/include/libpldm/pldm_rde.h
new file mode 100644
index 0000000..462c395
--- /dev/null
+++ b/include/libpldm/pldm_rde.h
@@ -0,0 +1,827 @@
+#ifndef PLDM_RDE_H
+#define PLDM_RDE_H
+
+#include "libpldm/base.h"
+#include "libpldm/pldm_types.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Minimum transfer size allowed is 64 bytes.
+#define PLDM_RDE_MIN_TRANSFER_SIZE_BYTES 64
+// Dictionary VersionTag for DSP0218 v1.0.0, v1.1.0, v1.1.1.
+#define PLDM_RDE_DICT_VERSION_TAG 0x00
+#define PLDM_RDE_NOT_A_OPERATION 0x00
+#define PLD_RDE_NULL_TRANSFER_HANDLE 0
+#define PLD_RDE_OP_PENDING_TRANSFER_HANDLE 0xFFFFFFFF
+#define PLDM_RDE_COMP_TIME_NOT_SUPPORTED 0xFFFFFFFF
+#define PLDM_RDE_COMP_PERCENTAGE_NOT_SUPPORTED 254
+// Variable struct header sizes
+#define PLDM_RDE_MULTIPART_RECEIVE_RESP_HDR_SIZE 10
+#define PLDM_RDE_OPERATION_INIT_REQ_HDR_SIZE 17
+#define PLDM_RDE_OPERATION_INIT_RESP_HDR_SIZE 17
+#define PLDM_RDE_OPERATION_STATUS_RESP_HDR_SIZE 17
+
+#define PLDM_RDE 0x06 /*Response should support PLDM_PLATFORM and PLDM_RDE*/
+#define RDE_NEGOTIATE_REDFISH_PARAMETERS_RESP_BYTES 12
+#define RDE_NEGOTIATE_MEDIUM_PARAMETERS_RESP_BYTES 5
+#define RDE_GET_DICTIONARY_SCHEMA_RESP_BYTES 6
+#define RDE_MULTIPART_RECV_MINIMUM_RESP_BYTES 6
+#define RDE_READ_OPERATION_INIT_MIN_BYTES 13
+#define RESOURCE_ID_ANY 0xFFFFFFFF
+#define IGNORE(x) (void)(x)
+
+/** @brief RDE Supported Commands
+ */
+enum pldm_rde_commands {
+ PLDM_NEGOTIATE_REDFISH_PARAMETERS = 0x01,
+ PLDM_NEGOTIATE_MEDIUM_PARAMETERS = 0x02,
+ PLDM_GET_SCHEMA_DICTIONARY = 0x03,
+ PLDM_GET_SCHEMA_FILE = 0x0C,
+ PLDM_RDE_OPERATION_INIT = 0x10,
+ PLDM_RDE_OPERATION_COMPLETE = 0x13,
+ PLDM_RDE_OPERATION_STATUS = 0x14,
+ PLDM_RDE_MULTIPART_SEND = 0x30,
+ PLDM_RDE_MULTIPART_RECEIVE = 0x31,
+};
+
+typedef enum pldm_rde_varstring_format {
+ PLDM_RDE_VARSTRING_UNKNOWN = 0,
+ PLDM_RDE_VARSTRING_ASCII = 1,
+ PLDM_RDE_VARSTRING_UTF_8 = 2,
+ PLDM_RDE_VARSTRING_UTF_16 = 3,
+ PLDM_RDE_VARSTRING_UTF_16LE = 4,
+ PLDM_RDE_VARSTRING_UTF_16BE = 5,
+} pldm_rde_varstring_format;
+
+enum pldm_rde_schema_type {
+ PLDM_RDE_SCHEMA_MAJOR = 0,
+ PLDM_RDE_SCHEMA_EVENT = 1,
+ PLDM_RDE_SCHEMA_ANNOTATION = 2,
+ PLDM_RDE_SCHEMA_COLLECTION_MEMBER_TYPE = 3,
+ PLDM_RDE_SCHEMA_ERROR = 4,
+ PLDM_RDE_SCHEMA_REGISTRY = 5,
+};
+
+enum pldm_rde_completion_codes {
+ PLDM_RDE_ERROR_CANNOT_CREATE_OPERATION = 0x81,
+ PLDM_RDE_ERROR_NOT_ALLOWED = 0x82,
+ PLDM_RDE_ERROR_WRONG_LOCATION_TYPE = 0x83,
+ PLDM_RDE_ERROR_OPERATION_ABANDONED = 0x84,
+ PLDM_RDE_ERROR_OPERATION_EXISTS = 0x86,
+ PLDM_RDE_ERROR_OPERATION_FAILED = 0x87,
+ PLDM_RDE_ERROR_UNEXPECTED = 0x88,
+ PLDM_RDE_ERROR_UNSUPPORTED = 0x89,
+ PLDM_RDE_ERROR_NO_SUCH_RESOURCE = 0x92,
+};
+
+// TODO: Do we need this because base.h already has this
+/**
+ * @brief Transfer operation flags.
+ */
+enum pldm_rde_transfer_operation {
+ PLDM_RDE_XFER_FIRST_PART = 0,
+ PLDM_RDE_XFER_NEXT_PART = 1,
+ PLDM_RDE_XFER_ABORT = 2,
+};
+// TODO: Do we need this because base.h already has this
+enum pldm_rde_transfer_flag {
+ PLDM_RDE_START = 0,
+ PLDM_RDE_MIDDLE = 1,
+ PLDM_RDE_END = 2,
+ PLDM_RDE_START_AND_END = 3,
+};
+
+enum pldm_rde_operation_type {
+ PLDM_RDE_OPERATION_HEAD = 0,
+ PLDM_RDE_OPERATION_READ = 1,
+ PLDM_RDE_OPERATION_CREATE = 2,
+ PLDM_RDE_OPERATION_DELETE = 3,
+ PLDM_RDE_OPERATION_UPDATE = 4,
+ PLDM_RDE_OPERATION_REPLACE = 5,
+ PLDM_RDE_OPERATION_ACTION = 6,
+};
+
+enum pldm_rde_operation_status {
+ PLDM_RDE_OPERATION_INACTIVE = 0,
+ PLDM_RDE_OPERATION_NEEDS_INPUT = 1,
+ PLDM_RDE_OPERATION_TRIGGERED = 2,
+ PLDM_RDE_OPERATION_RUNNING = 3,
+ PLDM_RDE_OPERATION_HAVE_RESULTS = 4,
+ PLDM_RDE_OPERATION_COMPLETED = 5,
+ PLDM_RDE_OPERATION_FAILED = 6,
+ PLDM_RDE_OPERATION_ABANDONED = 7,
+};
+
+/**
+ * @brief MC feature support.
+ *
+ * The flags can be OR'd together to build the feature support for a MC.
+ */
+enum pldm_rde_mc_feature {
+ PLDM_RDE_MC_HEAD_SUPPORTED = 1,
+ PLDM_RDE_MC_READ_SUPPORTED = 2,
+ PLDM_RDE_MC_CREATE_SUPPORTED = 4,
+ PLDM_RDE_MC_DELETE_SUPPORTED = 8,
+ PLDM_RDE_MC_UPDATE_SUPPORTED = 16,
+ PLDM_RDE_MC_REPLACE_SUPPORTED = 32,
+ PLDM_RDE_MC_ACTION_SUPPORTED = 64,
+ PLDM_RDE_MC_EVENTS_SUPPORTED = 128,
+ PLDM_RDE_MC_BEJ_1_1_SUPPORTED = 256,
+};
+/**
+ * @brief Device capability flags.
+ *
+ * The flags can be OR'd together to build capabilities of a device.
+ */
+enum pldm_rde_device_capability {
+ PLDM_RDE_DEVICE_ATOMIC_RESOURCE_READ_SUPPORT = 1,
+ PLDM_RDE_DEVICE_EXPAND_SUPPORT = 2,
+ PLDM_RDE_DEVICE_BEJ_1_1_SUPPORT = 4,
+};
+/**
+ * @brief Device feature support.
+ *
+ * The flags can be OR'd together to build features of a RDE device.
+ */
+enum pldm_rde_device_feature {
+ PLDM_RDE_DEVICE_HEAD_SUPPORTED = 1,
+ PLDM_RDE_DEVICE_READ_SUPPORTED = 2,
+ PLDM_RDE_DEVICE_CREATE_SUPPORTED = 4,
+ PLDM_RDE_DEVICE_DELETE_SUPPORTED = 8,
+ PLDM_RDE_DEVICE_UPDATE_SUPPORTED = 16,
+ PLDM_RDE_DEVICE_REPLACE_SUPPORTED = 32,
+ PLDM_RDE_DEVICE_ACTION_SUPPORTED = 64,
+ PLDM_RDE_DEVICE_EVENTS_SUPPORTED = 128,
+};
+
+/**
+ * @brief NegotiateRedfishParameters request data structure.
+ */
+struct pldm_rde_negotiate_redfish_parameters_req {
+ uint8_t mc_concurrency_support;
+ bitfield16_t mc_feature_support;
+} __attribute__((packed));
+/**
+ * @brief varstring PLDM data type.
+ *
+ * sizeof(struct pldm_rde_varstring) will include the space for the NULL
+ * character.
+ */
+struct pldm_rde_varstring {
+ uint8_t string_format;
+ // Includes NULL terminator.
+ uint8_t string_length_bytes;
+ // String data should be NULL terminated.
+ uint8_t string_data[1];
+} __attribute__((packed));
+/**
+ * @brief NegotiateRedfishParameters response data structure.
+ */
+struct pldm_rde_negotiate_redfish_parameters_resp {
+ uint8_t completion_code;
+ uint8_t device_concurrency_support;
+ bitfield8_t device_capabilities_flags;
+ bitfield16_t device_feature_support;
+ uint32_t device_configuration_signature;
+ struct pldm_rde_varstring device_provider_name;
+} __attribute__((packed));
+/**
+ * @brief NegotiateMediumParameters request data structure.
+ */
+struct pldm_rde_negotiate_medium_parameters_req {
+ uint32_t mc_maximum_transfer_chunk_size_bytes;
+} __attribute__((packed));
+/**
+ * @brief NegotiateMediumParameters response data structure.
+ */
+struct pldm_rde_negotiate_medium_parameters_resp {
+ uint8_t completion_code;
+ uint32_t device_maximum_transfer_chunk_size_bytes;
+} __attribute__((packed));
+/**
+ * @brief GetSchemaDictionary request data structure.
+ */
+struct pldm_rde_get_schema_dictionary_req {
+ uint32_t resource_id;
+ uint8_t requested_schema_class;
+} __attribute__((packed));
+/**
+ * @brief GetSchemaDictionary response data structure.
+ */
+struct pldm_rde_get_schema_dictionary_resp {
+ uint8_t completion_code;
+ uint8_t dictionary_format;
+ uint32_t transfer_handle;
+} __attribute__((packed));
+/**
+ * @brief RDEMultipartReceive request data structure.
+ */
+struct pldm_rde_multipart_receive_req {
+ uint32_t data_transfer_handle;
+ uint16_t operation_id;
+ uint8_t transfer_operation;
+} __attribute__((packed));
+/**
+ * @brief RDEMultipartReceive response data structure.
+ */
+struct pldm_rde_multipart_receive_resp {
+ uint8_t completion_code;
+ uint8_t transfer_flag;
+ uint32_t next_data_transfer_handle;
+ uint32_t data_length_bytes;
+ uint8_t payload[1];
+} __attribute__((packed));
+/**
+ * @brief OperationFlags used in RDEOperationInit request data structure.
+ */
+union pldm_rde_operation_flags {
+ uint8_t byte;
+ struct {
+ uint8_t locator_valid : 1;
+ uint8_t contains_request_payload : 1;
+ uint8_t contains_custom_request_parameters : 1;
+ uint8_t excerpt_flag : 1;
+ uint8_t reserved : 4;
+ } __attribute__((packed)) bits;
+};
+/**
+ * @brief RDEOperationInit request data structure.
+ */
+struct pldm_rde_operation_init_req {
+ uint32_t resource_id;
+ uint16_t operation_id;
+ uint8_t operation_type;
+ union pldm_rde_operation_flags operation_flags;
+ uint32_t send_data_transfer_handle;
+ uint8_t operation_locator_length;
+ uint32_t request_payload_length;
+ // Variable length data: bejLocator and the payload.
+ uint8_t var_data[1];
+} __attribute__((packed));
+/**
+ * @brief OperationExecutionFlags used in RDEOperationInit and
+ * RDEOperationStatus response data structures.
+ */
+union pldm_rde_op_execution_flags {
+ uint8_t byte;
+ struct {
+ uint8_t task_spawned : 1;
+ uint8_t have_custom_response_parameters : 1;
+ uint8_t have_result_payload : 1;
+ uint8_t cache_allowed : 1;
+ uint8_t reserved : 4;
+ } __attribute__((packed)) bits;
+};
+/**
+ * @brief PermissionFlags used in RDEOperationInit and RDEOperationStatus
+ * response data structures.
+ */
+union pldm_rde_permission_flags {
+ uint8_t byte;
+ struct {
+ uint8_t read_allowed : 1;
+ uint8_t update_allowed : 1;
+ uint8_t replace_allowed : 1;
+ uint8_t create_allowed : 1;
+ uint8_t delete_allowed : 1;
+ uint8_t head_allowed : 1;
+ uint8_t reserved : 2;
+ } __attribute__((packed)) bits;
+};
+/**
+ * @brief RDEOperationInit response data structure.
+ */
+struct pldm_rde_operation_init_resp {
+ uint8_t completion_code;
+ uint8_t operation_status;
+ uint8_t completion_percentage;
+ uint32_t completion_time_seconds;
+ union pldm_rde_op_execution_flags operation_execution_flags;
+ uint32_t result_transfer_handle;
+ union pldm_rde_permission_flags permission_flags;
+ uint32_t response_payload_length;
+ // Variable length data: varstring and the payload.
+ uint8_t var_data[1];
+} __attribute__((packed));
+/**
+ * @brief RDEOperationComplete request data structure.
+ */
+struct pldm_rde_operation_complete_req {
+ uint32_t resource_id;
+ uint16_t operation_id;
+} __attribute__((packed));
+/**
+ * @brief RDEOperationComplete response data structure.
+ */
+struct pldm_rde_operation_complete_resp {
+ uint8_t completion_code;
+} __attribute__((packed));
+/**
+ * @brief RDEOperationStatus request data structure.
+ */
+struct pldm_rde_operation_status_req {
+ uint32_t resource_id;
+ uint16_t operation_id;
+} __attribute__((packed));
+/**
+ * @brief RDEOperationStatus response data structure.
+ */
+struct pldm_rde_operation_status_resp {
+ uint8_t completion_code;
+ uint8_t operation_status;
+ uint8_t completion_percentage;
+ uint32_t completion_time_seconds;
+ union pldm_rde_op_execution_flags operation_execution_flags;
+ uint32_t result_transfer_handle;
+ union pldm_rde_permission_flags permission_flags;
+ uint32_t response_payload_length;
+ // Variable length data: varstring and the payload.
+ uint8_t var_data[1];
+} __attribute__((packed));
+
+struct pldm_rde_device_info {
+ uint8_t device_concurrency;
+ bitfield8_t device_capabilities_flag;
+ bitfield16_t device_feature_support;
+ uint32_t device_configuration_signature;
+ struct pldm_rde_varstring device_provider_name;
+ uint32_t device_maximum_transfer_chunk_size; // in bytes
+};
+/**
+ * @brief Encode NegotiateRedfishParameters request.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] concurrency_support - MC concurrency support.
+ * @param[in] feature_support - MC feature support flags.
+ * @param[out] msg - Request message.
+ * @return pldm_completion_codes.
+ */
+int encode_negotiate_redfish_parameters_req(uint8_t instance_id,
+ uint8_t concurrency_support,
+ bitfield16_t *feature_support,
+ struct pldm_msg *msg);
+/**
+ * @brief Decode NegotiateRedfishParameters request.
+ *
+ * @param[in] msg - Request message.
+ * @param[in] payload_length - Length of request message payload.
+ * @param[out] mc_concurrency_support - Pointer to a uint8_t variable.
+ * @param[out] mc_feature_support - Pointer to a bitfield16_t variable.
+ * @return pldm_completion_codes.
+ */
+int decode_negotiate_redfish_parameters_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *mc_concurrency_support,
+ bitfield16_t *mc_feature_support);
+/**
+ * @brief Create a PLDM response message for NegotiateRedfishParameters.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] completion_code - PLDM completion code.
+ * @param[in] device_concurrency_support - Concurrency support.
+ * @param[in] device_capabilities_flags - Capabilities flags.
+ * @param[in] device_feature_support - Feature support flags.
+ * @param[in] device_configuration_signature - RDE device signature.
+ * @param[in] device_provider_name - Null terminated device provider name.
+ * @param[in] name_format - String format of the device_provider_name.
+ * @param[out] msg - Response message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_negotiate_redfish_parameters_resp(
+ uint8_t instance_id, uint8_t completion_code,
+ uint8_t device_concurrency_support, bitfield8_t device_capabilities_flags,
+ bitfield16_t device_feature_support,
+ uint32_t device_configuration_signature, const char *device_provider_name,
+ enum pldm_rde_varstring_format name_format, struct pldm_msg *msg);
+
+/**
+ * @brief Decode NegotiateRedfishParameters Response.
+ *
+ * @param[in] msg - Request message.
+ * @param[in] payload_length - Length of request message payload.
+ * @param[out] completion_code - Completion code as set by the responder.
+ * @param[out] device - Device Info as sent in the response (Memory to be
+ * manager by the caller).
+ * @return pldm_completion_codes.
+ */
+int decode_negotiate_redfish_parameters_resp(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ struct pldm_rde_device_info *device);
+
+/**
+ * @brief Encode NegotiateMediumParameters request.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] maximum_transfer_size - Maximum amount of data the MC can
+ * support for a single message transfer.
+ * @param[out] msg - Request message.
+ * @return pldm_completion_codes.
+ */
+int encode_negotiate_medium_parameters_req(uint8_t instance_id,
+ uint32_t maximum_transfer_size,
+ struct pldm_msg *msg);
+/**
+ * @brief Decode NegotiateMediumParameters request.
+ *
+ * @param[in] msg - Request message.
+ * @param[in] payload_length - Length of request message payload.
+ * @param[out] mc_maximum_transfer_size - Pointer to a uint32_t variable.
+ * @return pldm_completion_codes.
+ */
+int decode_negotiate_medium_parameters_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint32_t *mc_maximum_transfer_size);
+/**
+ * @brief Create a PLDM response message for NegotiateMediumParameters.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] completion_code - PLDM completion code.
+ * @param[in] device_maximum_transfer_bytes - Device maximum transfer byte
+ * support.
+ * @param[out] msg - Response message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_negotiate_medium_parameters_resp(
+ uint8_t instance_id, uint8_t completion_code,
+ uint32_t device_maximum_transfer_bytes, struct pldm_msg *msg);
+/**
+ * @brief Decode Negotiate Medium Parameters response
+ *
+ * @param[in] msg: PLDM Msg byte array received from the responder
+ * @param[in] payload_length: Length of the payload
+ * @param[out] completion_code: Completion code as set by the responder
+ * @param[out] device_maximum_transfer_bytes: Max bytes device can transfer
+ */
+int decode_negotiate_medium_parameters_resp(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ uint32_t *device_maximum_transfer_bytes);
+/**
+ * @brief Encode GetSchemaDictionary request.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] resource_id - The ResourceID of any resource in the Redfish
+ * Resource PDR.
+ * @param[in] schema_class - The class of schema being requested.
+ * @param[out] msg - Request message.
+ * @return pldm_completion_codes.
+ */
+int encode_get_schema_dictionary_req(uint8_t instance_id, uint32_t resource_id,
+ uint8_t schema_class,
+ struct pldm_msg *msg);
+/**
+ * @brief Decode GetSchemaDictionary request.
+ *
+ * @param[in] msg - Request message.
+ * @param[in] payload_length - Length of request message payload.
+ * @param[out] resource_id - Pointer to a uint32_t variable.
+ * @param[out] requested_schema_class - Pointer to a uint8_t variable.
+ * @return pldm_completion_codes.
+ */
+int decode_get_schema_dictionary_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint32_t *resource_id,
+ uint8_t *requested_schema_class);
+/**
+ * @brief Encode GetSchemaDictionary response.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] completion_code - PLDM completion code.
+ * @param[in] dictionary_format - The format of the dictionary.
+ * @param[in] transfer_handle - A data transfer handle that the MC shall
+ * use.
+ * @param[out] msg - Response message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_get_schema_dictionary_resp(uint8_t instance_id,
+ uint8_t completion_code,
+ uint8_t dictionary_format,
+ uint32_t transfer_handle,
+ struct pldm_msg *msg);
+/**
+ * @brief Decode Get Schema Dictionary Response
+ *
+ * @param[in] msg - Response Message
+ * @param[in] payload_length - Length of the payload
+ * @param[out] completion_code - Completion Code
+ * @param[out] dictionary_format - Dictionary Format for the particular resource
+ * id
+ * @param[out] transfer_handle - Transfer Handle to be used to get dictionary
+ */
+int decode_get_schema_dictionary_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code,
+ uint8_t *dictionary_format,
+ uint32_t *transfer_handle);
+/**
+ * @brief Encode RDEMultipartReceive request.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] data_transfer_handle - A handle to uniquely identify the chunk
+ * of data to be retrieved.
+ * @param[in] operation_id - Identification number for this operation.
+ * @param[in] transfer_operation - The portion of data requested for the
+ * transfer.
+ * @param[out] msg - Request will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_rde_multipart_receive_req(uint8_t instance_id,
+ uint32_t data_transfer_handle,
+ uint16_t operation_id,
+ uint8_t transfer_operation,
+ struct pldm_msg *msg);
+/**
+ * @brief Decode RDEMultipartReceive request.
+ *
+ * @param[in] msg - Request message.
+ * @param[in] payload_length - Length of request message payload.
+ * @param[out] data_transfer_handle - A handle to uniquely identify the
+ * chunk of data to be retrieved.
+ * @param[out] operation_id - Identification number for this operation.
+ * @param[out] transfer_operation - The portion of data requested for the
+ * transfer.
+ * @return pldm_completion_codes.
+ */
+int decode_rde_multipart_receive_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint32_t *data_transfer_handle,
+ uint16_t *operation_id,
+ uint8_t *transfer_operation);
+/**
+ * @brief Encode RDEMultipartReceive response.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] completion_code - PLDM completion code.
+ * @param[in] transfer_flag - The portion of data being sent to MC.
+ * @param[in] next_data_transfer_handle - A handle to uniquely identify the
+ * next chunk of data to be retrieved.
+ * @param[in] data_length_bytes - Length of the payload.
+ * @param[in] add_checksum - Indicate whether the payload needs to include
+ * the provided checksum.
+ * @param[in] checksum - Checksum.
+ * @param[in] payload - Pointer to the payload.
+ * @param[out] msg - Response message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_rde_multipart_receive_resp(
+ uint8_t instance_id, uint8_t completion_code, uint8_t transfer_flag,
+ uint32_t next_data_transfer_handle, uint32_t data_length_bytes,
+ bool add_checksum, uint32_t checksum, const uint8_t *payload,
+ struct pldm_msg *msg);
+/**
+ * @brief Decode RDE Multipart Receive Response
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Expected length of the response, since the
+ * response could be equal to the negotiated transfer chunk size, the requester
+ * should usually set it to the negotiated transfer size
+ * @param[out] completion_code - Completion code of the response set by RDE
+ * @param[out] ret_transfer_flag - Transfer flag returned by RDE
+ * @param[out] ret_transfer_operation - Transfer operation returned by RDE
+ * @param[out] data_length_bytes - The length of the payload in response
+ * @param[out] payload - Pointer to the payload
+ */
+int decode_rde_multipart_receive_resp(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ uint8_t *ret_transfer_flag, uint32_t *ret_data_transfer_handle,
+ uint32_t *data_length_bytes, uint8_t **payload);
+/**
+ * @brief Encode RDEOperationInit request.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] resource_id - The ResourceID.
+ * @param[in] operation_id - Identification number for this operation.
+ * @param[in] operation_type - The type of Redfish Operation being
+ * performed.
+ * @param[in] operation_flags - Flags associated with this Operation.
+ * @param[in] send_data_transfer_handle - Handle to be used with the first
+ * RDEMultipartSend command.
+ * @param[in] operation_locator_length - Length of the OperationLocator for
+ * this Operation.
+ * @param[in] request_payload_length - Length of the request payload in this
+ * message.
+ * @param[in] operation_locator - BEJ locator indicating where the new
+ * Operation is to take place within the resource.
+ * @param[in] request_payload - The request payload.
+ * @param[out] msg - Request will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_rde_operation_init_req(
+ uint8_t instance_id, uint32_t resource_id, uint16_t operation_id,
+ uint8_t operation_type,
+ const union pldm_rde_operation_flags *operation_flags,
+ uint32_t send_data_transfer_handle, uint8_t operation_locator_length,
+ uint32_t request_payload_length, const uint8_t *operation_locator,
+ uint8_t *request_payload, struct pldm_msg *msg);
+/**
+ * @brief Decode RDEOperationInit request.
+ *
+ * @param[in] msg - Request message.
+ * @param[in] payload_length - Length of request message payload.
+ * @param[out] resource_id - The ResourceID.
+ * @param[out] operation_id - Identification number for this operation.
+ * @param[out] operation_type - The type of Redfish Operation being
+ * performed.
+ * @param[out] operation_flags - Flags associated with this Operation.
+ * @param[out] send_data_transfer_handle - Handle to be used with the first
+ * RDEMultipartSend command.
+ * @param[out] operation_locator_length - Length of the OperationLocator for
+ * this Operation.
+ * @param[out] request_payload_length - Length of the request payload in
+ * this message.
+ * @param[out] operation_locator - BEJ locator indicating where the new
+ * Operation is to take place within the resource.
+ * @param[out] request_payload - The request payload.
+ * @return pldm_completion_codes.
+ */
+int decode_rde_operation_init_req(
+ const struct pldm_msg *msg, size_t payload_length, uint32_t *resource_id,
+ uint16_t *operation_id, uint8_t *operation_type,
+ union pldm_rde_operation_flags *operation_flags,
+ uint32_t *send_data_transfer_handle, uint8_t *operation_locator_length,
+ uint32_t *request_payload_length, uint8_t **operation_locator,
+ uint8_t **request_payload);
+/**
+ * @brief Encode RDEOperationInit response.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] completion_code - PLDM completion code.
+ * @param[in] operation_status - Status of the operation.
+ * @param[in] completion_percentage - Percentage complete.
+ * @param[in] completion_time_seconds - An estimate of the number of seconds
+ * remaining before the Operation is completed.
+ * @param[in] operation_execution_flags - Explains the result of operation.
+ * @param[in] result_transfer_handle - A data transfer handle that the MC
+ * may use to retrieve a larger response payload.
+ * @param[in] permission_flags - Indicates the access level granted to the
+ * resource targeted by the Operation.
+ * @param[in] response_payload_length - Length of the response payload.
+ * @param[in] etag_format - Format of the etag string.
+ * @param[in] etag - ETag.
+ * @param[in] response_payload - The response payload if the payload fits.
+ * @param[out] msg - Response message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_rde_operation_init_resp(
+ uint8_t instance_id, uint8_t completion_code, uint8_t operation_status,
+ uint8_t completion_percentage, uint32_t completion_time_seconds,
+ const union pldm_rde_op_execution_flags *operation_execution_flags,
+ uint32_t result_transfer_handle,
+ const union pldm_rde_permission_flags *permission_flags,
+ uint32_t response_payload_length,
+ enum pldm_rde_varstring_format etag_format, const char *etag,
+ const uint8_t *response_payload, struct pldm_msg *msg);
+/**
+ * @brief Decode RDEOperationInit Resp
+ */
+int decode_rde_operation_init_resp(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ uint8_t *completion_percentage, uint8_t *operation_status,
+ uint32_t *completion_time_seconds, uint32_t *result_transfer_handle,
+ uint32_t *response_payload_length,
+ union pldm_rde_permission_flags **permission_flags,
+ union pldm_rde_op_execution_flags **operation_execution_flags,
+ struct pldm_rde_varstring **resp_etag, uint8_t **response_payload);
+/**
+ * @brief Encode RDEOperationComplete request.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] resource_id - The ResourceID.
+ * @param[in] operation_id - Identification number for this operation.
+ * @param[out] msg - Request will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_rde_operation_complete_req(uint8_t instance_id, uint32_t resource_id,
+ uint16_t operation_id,
+ struct pldm_msg *msg);
+/**
+ * @brief Decode RDEOperationComplete request.
+ *
+ * @param[in] msg - Request message.
+ * @param[in] payload_length - Length of request message payload.
+ * @param[out] resource_id - The ResourceID.
+ * @param[out] operation_id - Identification number for this operation.
+ * @return pldm_completion_codes.
+ */
+int decode_rde_operation_complete_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint32_t *resource_id,
+ uint16_t *operation_id);
+/**
+ * @brief Encode RDEOperationComplete response.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] completion_code - PLDM completion code.
+ * @param[out] msg - Response message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_rde_operation_complete_resp(uint8_t instance_id,
+ uint8_t completion_code,
+ struct pldm_msg *msg);
+
+/**
+ * @brief Encode RDEOperationComplete response.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] completion_code - PLDM completion code.
+ * @param[out] msg - Response message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int decode_rde_operation_complete_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code);
+/**
+ * @brief Encode RDEOperationStatus request.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] resource_id - The ResourceID.
+ * @param[in] operation_id - Identification number for this operation.
+ * @param[out] msg - Request will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_rde_operation_status_req(uint8_t instance_id, uint32_t resource_id,
+ uint16_t operation_id,
+ struct pldm_msg *msg);
+/**
+ * @brief Decode RDEOperationStatus request.
+ *
+ * @param[in] msg - Request message.
+ * @param[in] payload_length - Length of request message payload.
+ * @param[out] resource_id - The ResourceID.
+ * @param[out] operation_id - Identification number for this operation.
+ * @return pldm_completion_codes.
+ */
+int decode_rde_operation_status_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint32_t *resource_id,
+ uint16_t *operation_id);
+/**
+ * @brief Encode RDEOperationStatus response.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] completion_code - PLDM completion code.
+ * @param[in] operation_status - Status of the operation.
+ * @param[in] completion_percentage - Percentage complete.
+ * @param[in] completion_time_seconds - An estimate of the number of seconds
+ * remaining before the Operation is completed.
+ * @param[in] operation_execution_flags - Explains the result of operation.
+ * @param[in] result_transfer_handle - A data transfer handle that the MC
+ * may use to retrieve a larger response payload.
+ * @param[in] permission_flags - Indicates the access level granted to the
+ * resource targeted by the Operation.
+ * @param[in] response_payload_length - Length of the response payload.
+ * @param[in] etag_format - Format of the etag string.
+ * @param[in] etag - ETag.
+ * @param[in] response_payload - The response payload if the payload fits.
+ * @param[out] msg - Response message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_rde_operation_status_resp(
+ uint8_t instance_id, uint8_t completion_code, uint8_t operation_status,
+ uint8_t completion_percentage, uint32_t completion_time_seconds,
+ const union pldm_rde_op_execution_flags *operation_execution_flags,
+ uint32_t result_transfer_handle,
+ const union pldm_rde_permission_flags *permission_flags,
+ uint32_t response_payload_length,
+ enum pldm_rde_varstring_format etag_format, const char *etag,
+ const uint8_t *response_payload, struct pldm_msg *msg);
+
+/**
+ * @brief Encode RDEOperationStatus response.
+ *
+ * @param[in] instance_id - Message's instance id.
+ * @param[in] completion_code - PLDM completion code.
+ * @param[in] operation_status - Status of the operation.
+ * @param[in] completion_percentage - Percentage complete.
+ * @param[in] completion_time_seconds - An estimate of the number of seconds
+ * remaining before the Operation is completed.
+ * @param[in] operation_execution_flags - Explains the result of operation.
+ * @param[in] result_transfer_handle - A data transfer handle that the MC
+ * may use to retrieve a larger response payload.
+ * @param[in] permission_flags - Indicates the access level granted to the
+ * resource targeted by the Operation.
+ * @param[in] response_payload_length - Length of the response payload.
+ * @param[in] etag_format - Format of the etag string.
+ * @param[in] etag - ETag.
+ * @param[in] response_payload - The response payload if the payload fits.
+ * @param[out] msg - Response message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int decode_rde_operation_status_resp(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ uint8_t *completion_percentage, uint8_t *operation_status,
+ uint32_t *completion_time_seconds, uint32_t *result_transfer_handle,
+ uint32_t *response_payload_length,
+ union pldm_rde_permission_flags **permission_flags,
+ union pldm_rde_op_execution_flags **operation_execution_flags,
+ struct pldm_rde_varstring **resp_etag, uint8_t **payload);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PLDM_RDE_H */
\ No newline at end of file
diff --git a/src/meson.build b/src/meson.build
index 9f4487c..57583b2 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -7,7 +7,8 @@ libpldm_sources = files(
'fru.c',
'pdr.c',
'responder.c',
- 'utils.c'
+ 'utils.c',
+ 'pldm_rde.c',
)
subdir('requester')
diff --git a/src/pldm_rde.c b/src/pldm_rde.c
new file mode 100644
index 0000000..90d31cc
--- /dev/null
+++ b/src/pldm_rde.c
@@ -0,0 +1,892 @@
+#include "libpldm/pldm_rde.h"
+#include "libpldm/base.h"
+#include <endian.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int encode_negotiate_redfish_parameters_resp(
+ uint8_t instance_id, uint8_t completion_code,
+ uint8_t device_concurrency_support, bitfield8_t device_capabilities_flags,
+ bitfield16_t device_feature_support,
+ uint32_t device_configuration_signature, const char *device_provider_name,
+ enum pldm_rde_varstring_format name_format, struct pldm_msg *msg)
+{
+ if ((NULL == msg) || (NULL == device_provider_name)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.command = PLDM_NEGOTIATE_REDFISH_PARAMETERS;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_negotiate_redfish_parameters_resp *response =
+ (struct pldm_rde_negotiate_redfish_parameters_resp *)msg->payload;
+ response->completion_code = completion_code;
+ if (response->completion_code != PLDM_SUCCESS) {
+ return PLDM_SUCCESS;
+ }
+ response->device_concurrency_support = device_concurrency_support;
+ response->device_capabilities_flags.byte =
+ device_capabilities_flags.byte;
+ response->device_feature_support.value =
+ htole16(device_feature_support.value);
+ response->device_configuration_signature =
+ htole32(device_configuration_signature);
+ response->device_provider_name.string_format = name_format;
+ // length should include NULL terminator.
+ response->device_provider_name.string_length_bytes =
+ strlen(device_provider_name) + 1;
+ // Copy including NULL terminator.
+ memcpy(response->device_provider_name.string_data, device_provider_name,
+ response->device_provider_name.string_length_bytes);
+ return PLDM_SUCCESS;
+}
+
+int encode_negotiate_redfish_parameters_req(uint8_t instance_id,
+ uint8_t concurrency_support,
+ bitfield16_t *feature_support,
+ struct pldm_msg *msg)
+{
+ if ((msg == NULL) || (feature_support == NULL) ||
+ (concurrency_support == 0)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.msg_type = PLDM_REQUEST;
+ header.command = PLDM_NEGOTIATE_REDFISH_PARAMETERS;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_negotiate_redfish_parameters_req *req =
+ (struct pldm_rde_negotiate_redfish_parameters_req *)msg->payload;
+ req->mc_concurrency_support = concurrency_support;
+ req->mc_feature_support.value = htole16(feature_support->value);
+ return PLDM_SUCCESS;
+}
+
+int decode_negotiate_redfish_parameters_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *mc_concurrency_support,
+ bitfield16_t *mc_feature_support)
+{
+ if ((msg == NULL) || (mc_concurrency_support == NULL) ||
+ (mc_feature_support == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (payload_length !=
+ sizeof(struct pldm_rde_negotiate_redfish_parameters_req)) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ struct pldm_rde_negotiate_redfish_parameters_req *request =
+ (struct pldm_rde_negotiate_redfish_parameters_req *)msg->payload;
+ if (request->mc_concurrency_support == 0) {
+ fprintf(stderr, "Concurrency support is 0\n");
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ *mc_concurrency_support = request->mc_concurrency_support;
+ mc_feature_support->value = le16toh(request->mc_feature_support.value);
+ return PLDM_SUCCESS;
+}
+
+int encode_negotiate_medium_parameters_resp(
+ uint8_t instance_id, uint8_t completion_code,
+ uint32_t device_maximum_transfer_bytes, struct pldm_msg *msg)
+{
+ if (NULL == msg) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.command = PLDM_NEGOTIATE_MEDIUM_PARAMETERS;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_negotiate_medium_parameters_resp *response =
+ (struct pldm_rde_negotiate_medium_parameters_resp *)msg->payload;
+ response->completion_code = completion_code;
+ if (response->completion_code != PLDM_SUCCESS) {
+ return PLDM_SUCCESS;
+ }
+ response->device_maximum_transfer_chunk_size_bytes =
+ htole32(device_maximum_transfer_bytes);
+ return PLDM_SUCCESS;
+}
+
+int decode_negotiate_redfish_parameters_resp(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ struct pldm_rde_device_info *device)
+{
+ if ((msg == NULL) || (device == NULL) || (completion_code == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+
+ if (PLDM_SUCCESS != *completion_code) {
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length < RDE_NEGOTIATE_REDFISH_PARAMETERS_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_rde_negotiate_redfish_parameters_resp *response =
+ (struct pldm_rde_negotiate_redfish_parameters_resp *)msg->payload;
+
+ device->device_concurrency = response->device_concurrency_support;
+ device->device_capabilities_flag = response->device_capabilities_flags;
+ device->device_configuration_signature =
+ le32toh(response->device_configuration_signature);
+ device->device_feature_support.value =
+ le16toh(response->device_feature_support.value);
+ device->device_provider_name = response->device_provider_name;
+ return PLDM_SUCCESS;
+}
+
+int decode_negotiate_medium_parameters_resp(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ uint32_t *device_maximum_transfer_bytes)
+{
+ if ((msg == NULL) || (device_maximum_transfer_bytes == NULL) ||
+ (completion_code == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+
+ if (PLDM_SUCCESS != *completion_code) {
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length < RDE_NEGOTIATE_MEDIUM_PARAMETERS_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_rde_negotiate_medium_parameters_resp *response =
+ (struct pldm_rde_negotiate_medium_parameters_resp *)msg->payload;
+
+ *device_maximum_transfer_bytes =
+ le32toh(response->device_maximum_transfer_chunk_size_bytes);
+
+ return PLDM_SUCCESS;
+}
+
+int encode_negotiate_medium_parameters_req(uint8_t instance_id,
+ uint32_t maximum_transfer_size,
+ struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.msg_type = PLDM_REQUEST;
+ header.command = PLDM_NEGOTIATE_MEDIUM_PARAMETERS;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_negotiate_medium_parameters_req *req =
+ (struct pldm_rde_negotiate_medium_parameters_req *)msg->payload;
+ req->mc_maximum_transfer_chunk_size_bytes =
+ htole32(maximum_transfer_size);
+ return PLDM_SUCCESS;
+}
+
+int decode_negotiate_medium_parameters_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint32_t *mc_maximum_transfer_size)
+{
+ if ((msg == NULL) || (mc_maximum_transfer_size == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (payload_length !=
+ sizeof(struct pldm_rde_negotiate_medium_parameters_req)) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ struct pldm_rde_negotiate_medium_parameters_req *request =
+ (struct pldm_rde_negotiate_medium_parameters_req *)msg->payload;
+ *mc_maximum_transfer_size =
+ le32toh(request->mc_maximum_transfer_chunk_size_bytes);
+ if (*mc_maximum_transfer_size < PLDM_RDE_MIN_TRANSFER_SIZE_BYTES) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ return PLDM_SUCCESS;
+}
+
+int encode_get_schema_dictionary_req(uint8_t instance_id, uint32_t resource_id,
+ uint8_t schema_class, struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.msg_type = PLDM_REQUEST;
+ header.command = PLDM_GET_SCHEMA_DICTIONARY;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_get_schema_dictionary_req *req =
+ (struct pldm_rde_get_schema_dictionary_req *)msg->payload;
+ req->resource_id = htole32(resource_id);
+ req->requested_schema_class = schema_class;
+ return PLDM_SUCCESS;
+}
+
+int decode_get_schema_dictionary_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint32_t *resource_id,
+ uint8_t *requested_schema_class)
+{
+ if ((msg == NULL) || (resource_id == NULL) ||
+ (requested_schema_class == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (payload_length !=
+ sizeof(struct pldm_rde_get_schema_dictionary_req)) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ struct pldm_rde_get_schema_dictionary_req *request =
+ (struct pldm_rde_get_schema_dictionary_req *)msg->payload;
+ *resource_id = le32toh(request->resource_id);
+ *requested_schema_class = request->requested_schema_class;
+ if (*requested_schema_class > PLDM_RDE_SCHEMA_REGISTRY) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ return PLDM_SUCCESS;
+}
+
+int encode_get_schema_dictionary_resp(uint8_t instance_id,
+ uint8_t completion_code,
+ uint8_t dictionary_format,
+ uint32_t transfer_handle,
+ struct pldm_msg *msg)
+{
+ if (NULL == msg) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.command = PLDM_GET_SCHEMA_DICTIONARY;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_get_schema_dictionary_resp *response =
+ (struct pldm_rde_get_schema_dictionary_resp *)msg->payload;
+ response->completion_code = completion_code;
+ if (response->completion_code != PLDM_SUCCESS) {
+ return PLDM_SUCCESS;
+ }
+ response->dictionary_format = dictionary_format;
+ response->transfer_handle = htole32(transfer_handle);
+ return PLDM_SUCCESS;
+}
+
+int decode_get_schema_dictionary_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code,
+ uint8_t *dictionary_format,
+ uint32_t *transfer_handle)
+{
+ if ((msg == NULL) || (dictionary_format == NULL) ||
+ (completion_code == NULL) || (transfer_handle == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+
+ if (PLDM_SUCCESS != *completion_code) {
+ fprintf(stderr, "COMPLETION CODE ERROR\n");
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length < RDE_GET_DICTIONARY_SCHEMA_RESP_BYTES) {
+ fprintf(stderr, "RESPONSE INVALID LEN CODE ERROR\n");
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_rde_get_schema_dictionary_resp *response =
+ (struct pldm_rde_get_schema_dictionary_resp *)msg->payload;
+ *dictionary_format = response->dictionary_format;
+ *transfer_handle = le32toh(response->transfer_handle);
+ return PLDM_SUCCESS;
+}
+
+int encode_rde_multipart_receive_req(uint8_t instance_id,
+ uint32_t data_transfer_handle,
+ uint16_t operation_id,
+ uint8_t transfer_operation,
+ struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.msg_type = PLDM_REQUEST;
+ header.command = PLDM_RDE_MULTIPART_RECEIVE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_multipart_receive_req *req =
+ (struct pldm_rde_multipart_receive_req *)msg->payload;
+ req->data_transfer_handle = htole32(data_transfer_handle);
+ req->operation_id = htole16(operation_id);
+ req->transfer_operation = transfer_operation;
+ return PLDM_SUCCESS;
+}
+
+int decode_rde_multipart_receive_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint32_t *data_transfer_handle,
+ uint16_t *operation_id,
+ uint8_t *transfer_operation)
+{
+ if ((msg == NULL) || (data_transfer_handle == NULL) ||
+ (operation_id == NULL) || (transfer_operation == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (payload_length != sizeof(struct pldm_rde_multipart_receive_req)) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ struct pldm_rde_multipart_receive_req *request =
+ (struct pldm_rde_multipart_receive_req *)msg->payload;
+ *data_transfer_handle = le32toh(request->data_transfer_handle);
+ *operation_id = le16toh(request->operation_id);
+ *transfer_operation = request->transfer_operation;
+ if (*transfer_operation > PLDM_RDE_XFER_ABORT) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ return PLDM_SUCCESS;
+}
+
+int encode_rde_multipart_receive_resp(
+ uint8_t instance_id, uint8_t completion_code, uint8_t transfer_flag,
+ uint32_t next_data_transfer_handle, uint32_t data_length_bytes,
+ bool add_checksum, uint32_t checksum, const uint8_t *payload,
+ struct pldm_msg *msg)
+{
+ if (NULL == msg) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.command = PLDM_RDE_MULTIPART_RECEIVE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_multipart_receive_resp *response =
+ (struct pldm_rde_multipart_receive_resp *)msg->payload;
+ response->completion_code = completion_code;
+ if (response->completion_code != PLDM_SUCCESS) {
+ return PLDM_SUCCESS;
+ }
+ response->transfer_flag = transfer_flag;
+ response->next_data_transfer_handle =
+ htole32(next_data_transfer_handle);
+ memcpy(response->payload, (uint8_t *)payload, data_length_bytes);
+ uint32_t tot_length = data_length_bytes;
+ if (add_checksum) {
+ tot_length += 4;
+ checksum = htole32(checksum);
+ memcpy(response->payload + data_length_bytes, &checksum,
+ sizeof(uint32_t));
+ }
+ response->data_length_bytes = htole32(tot_length);
+ return PLDM_SUCCESS;
+}
+
+int decode_rde_multipart_receive_resp(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ uint8_t *ret_transfer_flag, uint32_t *ret_data_transfer_handle,
+ uint32_t *data_length_bytes, uint8_t **payload)
+{
+ if ((msg == NULL) || (completion_code == NULL) ||
+ (ret_transfer_flag == NULL) || (ret_data_transfer_handle == NULL) ||
+ (data_length_bytes == NULL) || (payload == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+
+ if (PLDM_SUCCESS != *completion_code) {
+ fprintf(stderr, "Decoded successfully with failed completion "
+ "code in multipart\n");
+ return PLDM_ERROR;
+ }
+
+ if (payload_length < RDE_MULTIPART_RECV_MINIMUM_RESP_BYTES) {
+ fprintf(stderr, "Decoded successfully with invalid payload "
+ "length in multipart\n");
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_rde_multipart_receive_resp *response =
+ (struct pldm_rde_multipart_receive_resp *)msg->payload;
+ *ret_transfer_flag = response->transfer_flag;
+ *ret_data_transfer_handle =
+ le32toh(response->next_data_transfer_handle);
+ *data_length_bytes = le32toh(response->data_length_bytes);
+ *payload = &response->payload[0];
+ return PLDM_SUCCESS;
+}
+
+int encode_rde_operation_init_req(
+ uint8_t instance_id, uint32_t resource_id, uint16_t operation_id,
+ uint8_t operation_type,
+ const union pldm_rde_operation_flags *operation_flags,
+ uint32_t send_data_transfer_handle, uint8_t operation_locator_length,
+ uint32_t request_payload_length, const uint8_t *operation_locator,
+ uint8_t *request_payload, struct pldm_msg *msg)
+{
+ if ((msg == NULL) || (operation_flags == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if ((operation_locator_length > 0) && (operation_locator == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if ((request_payload_length > 0) && (request_payload == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.msg_type = PLDM_REQUEST;
+ header.command = PLDM_RDE_OPERATION_INIT;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_operation_init_req *req =
+ (struct pldm_rde_operation_init_req *)msg->payload;
+ req->resource_id = htole32(resource_id);
+ req->operation_id = htole16(operation_id);
+ req->operation_type = operation_type;
+ req->operation_flags.byte = operation_flags->byte;
+ req->send_data_transfer_handle = htole32(send_data_transfer_handle);
+ req->operation_locator_length = operation_locator_length;
+ req->request_payload_length = htole32(request_payload_length);
+ if (operation_locator_length > 0) {
+ memcpy(req->var_data, (uint8_t *)operation_locator,
+ operation_locator_length);
+ }
+ if (request_payload_length > 0) {
+ memcpy(req->var_data + operation_locator_length,
+ (uint8_t *)request_payload, request_payload_length);
+ request_payload = NULL;
+ }
+ return PLDM_SUCCESS;
+}
+
+static bool pldm_rde_is_valid_mc_op_id(uint16_t operation_id)
+{
+ // Operation identifiers with the MSBit set are reserved for use by the
+ // MC. Operation identifiers with the MSBit clear are reserved for use
+ // by the RDE Device. The value 0x0000 is reserved to indicate no
+ // Operation.
+ if ((operation_id == 0) || ((operation_id >> 15) == 0)) {
+ return false;
+ }
+ return true;
+}
+
+int decode_rde_operation_init_req(
+ const struct pldm_msg *msg, size_t payload_length, uint32_t *resource_id,
+ uint16_t *operation_id, uint8_t *operation_type,
+ union pldm_rde_operation_flags *operation_flags,
+ uint32_t *send_data_transfer_handle, uint8_t *operation_locator_length,
+ uint32_t *request_payload_length, uint8_t **operation_locator,
+ uint8_t **request_payload)
+{
+ if ((msg == NULL) || (resource_id == NULL) || (operation_id == NULL) ||
+ (operation_type == NULL) || (operation_flags == NULL) ||
+ (send_data_transfer_handle == NULL) ||
+ (operation_locator_length == NULL) ||
+ (request_payload_length == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (payload_length < PLDM_RDE_OPERATION_INIT_REQ_HDR_SIZE) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ struct pldm_rde_operation_init_req *request =
+ (struct pldm_rde_operation_init_req *)msg->payload;
+ *operation_id = le16toh(request->operation_id);
+ if (!pldm_rde_is_valid_mc_op_id(*operation_id)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ *resource_id = le32toh(request->resource_id);
+ *operation_type = request->operation_type;
+ operation_flags->byte = request->operation_flags.byte;
+ *send_data_transfer_handle =
+ le32toh(request->send_data_transfer_handle);
+ *operation_locator_length = request->operation_locator_length;
+ *request_payload_length = le32toh(request->request_payload_length);
+ if (*operation_locator_length > 0) {
+ *operation_locator = request->var_data;
+ } else {
+ *operation_locator = NULL;
+ }
+ if (*request_payload_length > 0) {
+ *request_payload =
+ request->var_data + *operation_locator_length;
+ } else {
+ *request_payload = NULL;
+ }
+ return PLDM_SUCCESS;
+}
+
+int encode_rde_operation_init_resp(
+ uint8_t instance_id, uint8_t completion_code, uint8_t operation_status,
+ uint8_t completion_percentage, uint32_t completion_time_seconds,
+ const union pldm_rde_op_execution_flags *operation_execution_flags,
+ uint32_t result_transfer_handle,
+ const union pldm_rde_permission_flags *permission_flags,
+ uint32_t response_payload_length,
+ enum pldm_rde_varstring_format etag_format, const char *etag,
+ const uint8_t *response_payload, struct pldm_msg *msg)
+{
+ if ((msg == NULL) || (operation_execution_flags == NULL) ||
+ (permission_flags == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if ((response_payload_length > 0) && (response_payload == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.command = PLDM_RDE_OPERATION_INIT;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_operation_init_resp *response =
+ (struct pldm_rde_operation_init_resp *)msg->payload;
+ response->completion_code = completion_code;
+ if (response->completion_code != PLDM_SUCCESS) {
+ return PLDM_SUCCESS;
+ }
+ response->operation_status = operation_status;
+ response->completion_percentage = completion_percentage;
+ response->completion_time_seconds = htole32(completion_time_seconds);
+ response->operation_execution_flags.byte =
+ operation_execution_flags->byte;
+ response->result_transfer_handle = htole32(result_transfer_handle);
+ response->permission_flags.byte = permission_flags->byte;
+ response->response_payload_length = htole32(response_payload_length);
+ struct pldm_rde_varstring *resp_etag =
+ (struct pldm_rde_varstring *)response->var_data;
+ resp_etag->string_format = etag_format;
+ // length should include NULL terminator.
+ size_t etag_len_wo_null = strlen(etag);
+ resp_etag->string_length_bytes = etag_len_wo_null + 1;
+ // Copy including NULL terminator.
+ memcpy(resp_etag->string_data, etag, resp_etag->string_length_bytes);
+ // Copy the payload.
+ if (response_payload_length > 0) {
+ memcpy(response->var_data + sizeof(struct pldm_rde_varstring) +
+ etag_len_wo_null,
+ (uint8_t *)response_payload, response_payload_length);
+ }
+ return PLDM_SUCCESS;
+}
+
+int decode_rde_operation_init_resp(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ uint8_t *completion_percentage, uint8_t *operation_status,
+ uint32_t *completion_time_seconds, uint32_t *result_transfer_handle,
+ uint32_t *response_payload_length,
+ union pldm_rde_permission_flags **permission_flags,
+ union pldm_rde_op_execution_flags **operation_execution_flags,
+ struct pldm_rde_varstring **resp_etag, uint8_t **response_payload)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ *completion_code = msg->payload[0];
+ if (PLDM_SUCCESS != *completion_code) {
+ fprintf(stderr,
+ "Decoded successfully with failed completion code\n");
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length < RDE_READ_OPERATION_INIT_MIN_BYTES) {
+ fprintf(stderr,
+ "Decoded successfully with failed payload length\n");
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_rde_operation_init_resp *response =
+ (struct pldm_rde_operation_init_resp *)msg->payload;
+
+ *operation_status = response->operation_status;
+ *completion_percentage = response->completion_percentage;
+ *completion_time_seconds = le32toh(response->completion_time_seconds);
+ (*operation_execution_flags)->byte =
+ response->operation_execution_flags.byte;
+ *result_transfer_handle = le32toh(response->result_transfer_handle);
+ (*permission_flags)->byte = response->permission_flags.byte;
+ *response_payload_length = le32toh(response->response_payload_length);
+
+ *resp_etag = (struct pldm_rde_varstring *)response->var_data;
+
+ if (*operation_status == PLDM_RDE_OPERATION_COMPLETED) {
+ *response_payload = &(*resp_etag)->string_data[0] +
+ (*resp_etag)->string_length_bytes;
+ }
+ return 0;
+}
+
+int encode_rde_operation_complete_req(uint8_t instance_id, uint32_t resource_id,
+ uint16_t operation_id,
+ struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.msg_type = PLDM_REQUEST;
+ header.command = PLDM_RDE_OPERATION_COMPLETE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_operation_complete_req *req =
+ (struct pldm_rde_operation_complete_req *)msg->payload;
+ req->resource_id = htole32(resource_id);
+ req->operation_id = htole16(operation_id);
+ return PLDM_SUCCESS;
+}
+
+int decode_rde_operation_complete_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint32_t *resource_id,
+ uint16_t *operation_id)
+{
+ if ((msg == NULL) || (resource_id == NULL) || (operation_id == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (payload_length < sizeof(struct pldm_rde_operation_complete_req)) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ struct pldm_rde_operation_complete_req *request =
+ (struct pldm_rde_operation_complete_req *)msg->payload;
+ *resource_id = le32toh(request->resource_id);
+ *operation_id = le16toh(request->operation_id);
+ return PLDM_SUCCESS;
+}
+
+int encode_rde_operation_complete_resp(uint8_t instance_id,
+ uint8_t completion_code,
+ struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.command = PLDM_RDE_OPERATION_COMPLETE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_operation_complete_resp *response =
+ (struct pldm_rde_operation_complete_resp *)msg->payload;
+ response->completion_code = completion_code;
+ return PLDM_SUCCESS;
+}
+
+int decode_rde_operation_complete_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code)
+{
+ if (msg == NULL) {
+ fprintf(stderr, "Invalid message object\n");
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (payload_length < 1) {
+ fprintf(stderr, "Invalid payload length\n");
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ *completion_code = msg->payload[0];
+
+ if (PLDM_SUCCESS != *completion_code) {
+ fprintf(stderr,
+ "Decoded successfully with failed completion code\n");
+ return PLDM_SUCCESS;
+ }
+ return PLDM_SUCCESS;
+}
+
+int encode_rde_operation_status_req(uint8_t instance_id, uint32_t resource_id,
+ uint16_t operation_id, struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.msg_type = PLDM_REQUEST;
+ header.command = PLDM_RDE_OPERATION_STATUS;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_operation_status_req *req =
+ (struct pldm_rde_operation_status_req *)msg->payload;
+ req->resource_id = htole32(resource_id);
+ req->operation_id = htole16(operation_id);
+ return PLDM_SUCCESS;
+}
+
+int decode_rde_operation_status_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint32_t *resource_id,
+ uint16_t *operation_id)
+{
+ if ((msg == NULL) || (resource_id == NULL) || (operation_id == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (payload_length < sizeof(struct pldm_rde_operation_status_req)) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ struct pldm_rde_operation_status_req *request =
+ (struct pldm_rde_operation_status_req *)msg->payload;
+ *resource_id = le32toh(request->resource_id);
+ *operation_id = le16toh(request->operation_id);
+ return PLDM_SUCCESS;
+}
+
+int encode_rde_operation_status_resp(
+ uint8_t instance_id, uint8_t completion_code, uint8_t operation_status,
+ uint8_t completion_percentage, uint32_t completion_time_seconds,
+ const union pldm_rde_op_execution_flags *operation_execution_flags,
+ uint32_t result_transfer_handle,
+ const union pldm_rde_permission_flags *permission_flags,
+ uint32_t response_payload_length,
+ enum pldm_rde_varstring_format etag_format, const char *etag,
+ const uint8_t *response_payload, struct pldm_msg *msg)
+{
+ if ((msg == NULL) || (operation_execution_flags == NULL) ||
+ (permission_flags == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if ((response_payload_length > 0) && (response_payload == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.command = PLDM_RDE_OPERATION_STATUS;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_rde_operation_status_resp *response =
+ (struct pldm_rde_operation_status_resp *)msg->payload;
+ response->completion_code = completion_code;
+ if (response->completion_code != PLDM_SUCCESS) {
+ return PLDM_SUCCESS;
+ }
+ response->operation_status = operation_status;
+ response->completion_percentage = completion_percentage;
+ response->completion_time_seconds = htole32(completion_time_seconds);
+ response->operation_execution_flags.byte =
+ operation_execution_flags->byte;
+ response->result_transfer_handle = htole32(result_transfer_handle);
+ response->permission_flags.byte = permission_flags->byte;
+ response->response_payload_length = htole32(response_payload_length);
+ struct pldm_rde_varstring *resp_etag =
+ (struct pldm_rde_varstring *)response->var_data;
+ resp_etag->string_format = etag_format;
+ // length should include NULL terminator.
+ size_t etag_len_wo_null = strlen(etag);
+ resp_etag->string_length_bytes = etag_len_wo_null + 1;
+ // Copy including NULL terminator.
+ memcpy(resp_etag->string_data, etag, resp_etag->string_length_bytes);
+ // Copy the payload.
+ if (response_payload_length > 0) {
+ memcpy(response->var_data + sizeof(struct pldm_rde_varstring) +
+ etag_len_wo_null,
+ (uint8_t *)response_payload, response_payload_length);
+ }
+ return PLDM_SUCCESS;
+}
+
+int decode_rde_operation_status_resp(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ uint8_t *completion_percentage, uint8_t *operation_status,
+ uint32_t *completion_time_seconds, uint32_t *result_transfer_handle,
+ uint32_t *response_payload_length,
+ union pldm_rde_permission_flags **permission_flags,
+ union pldm_rde_op_execution_flags **operation_execution_flags,
+ struct pldm_rde_varstring **resp_etag, uint8_t **response_payload)
+{
+ if (msg == NULL) {
+ fprintf(stderr, "Invalid msg object\n");
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+ if (PLDM_SUCCESS != *completion_code) {
+ fprintf(stderr,
+ "Decoded successfully with failed completion code\n");
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length < RDE_READ_OPERATION_INIT_MIN_BYTES) {
+ fprintf(stderr,
+ "Decoded sucessfully with failed payload length\n");
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_rde_operation_init_resp *response =
+ (struct pldm_rde_operation_init_resp *)msg->payload;
+
+ *operation_status = response->operation_status;
+ *completion_percentage = response->completion_percentage;
+ *completion_time_seconds = le32toh(response->completion_time_seconds);
+ (*operation_execution_flags)->byte =
+ response->operation_execution_flags.byte;
+ *result_transfer_handle = le32toh(response->result_transfer_handle);
+ (*permission_flags)->byte = response->permission_flags.byte;
+ *response_payload_length = le32toh(response->response_payload_length);
+
+ *resp_etag = (struct pldm_rde_varstring *)response->var_data;
+ if (*operation_status == PLDM_RDE_OPERATION_COMPLETED) {
+ *response_payload = &(*resp_etag)->string_data[0] +
+ (*resp_etag)->string_length_bytes;
+ }
+ return 0;
+}
diff --git a/tests/libpldm_rde_test.cpp b/tests/libpldm_rde_test.cpp
new file mode 100644
index 0000000..56e322b
--- /dev/null
+++ b/tests/libpldm_rde_test.cpp
@@ -0,0 +1,889 @@
+#include <endian.h>
+
+#include "libpldm/pldm_rde.h"
+
+#include <gmock/gmock-matchers.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+TEST(NegotiateRedfishParametersTest, EncodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint8_t deviceConcurrencySupport = 1;
+ bitfield8_t deviceCapabilitiesFlags = {.byte = 0x3F};
+ bitfield16_t deviceFeatureSupport = {.value = 0x7389};
+ uint32_t deviceConfigurationSignature = 0xABCDEF12;
+ constexpr const char* device = "This is a test";
+ // Already has the space for the null character in sizeof(struct
+ // pldm_rde_negotiate_redfish_parameters_resp).
+ std::array<uint8_t,
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_negotiate_redfish_parameters_resp) +
+ 14>
+ responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ EXPECT_EQ(encode_negotiate_redfish_parameters_resp(
+ instanceId, completionCode, deviceConcurrencySupport,
+ deviceCapabilitiesFlags, deviceFeatureSupport,
+ deviceConfigurationSignature, device,
+ PLDM_RDE_VARSTRING_ASCII, response),
+ PLDM_SUCCESS);
+ // verify header.
+ EXPECT_EQ(response->hdr.instance_id, instanceId);
+ EXPECT_EQ(response->hdr.request, 0);
+ EXPECT_EQ(response->hdr.type, PLDM_RDE);
+ EXPECT_EQ(response->hdr.command, PLDM_NEGOTIATE_REDFISH_PARAMETERS);
+ // verify payload.
+ auto resp_payload =
+ reinterpret_cast<pldm_rde_negotiate_redfish_parameters_resp*>(
+ response->payload);
+ EXPECT_EQ(resp_payload->completion_code, completionCode);
+ EXPECT_EQ(resp_payload->device_concurrency_support,
+ deviceConcurrencySupport);
+ EXPECT_EQ(resp_payload->device_capabilities_flags.byte,
+ deviceCapabilitiesFlags.byte);
+ EXPECT_EQ(le16toh(resp_payload->device_feature_support.value),
+ deviceFeatureSupport.value);
+ EXPECT_EQ(le32toh(resp_payload->device_configuration_signature),
+ deviceConfigurationSignature);
+ EXPECT_EQ(resp_payload->device_provider_name.string_format,
+ PLDM_RDE_VARSTRING_ASCII);
+ EXPECT_EQ(resp_payload->device_provider_name.string_length_bytes,
+ strlen(device) + 1);
+ EXPECT_EQ(memcmp(resp_payload->device_provider_name.string_data, device,
+ strlen(device) + 1),
+ 0);
+}
+TEST(NegotiateRedfishParametersTest, EncodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint8_t mcConcurrencySupport = 13;
+ bitfield16_t mcFeatureSupport = {.value = 0x7389};
+ std::array<uint8_t,
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_negotiate_redfish_parameters_req)>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ auto req_payload =
+ reinterpret_cast<pldm_rde_negotiate_redfish_parameters_req*>(
+ request->payload);
+ EXPECT_EQ(encode_negotiate_redfish_parameters_req(
+ instanceId, mcConcurrencySupport, &mcFeatureSupport, request),
+ PLDM_SUCCESS);
+ EXPECT_EQ(request->hdr.instance_id, instanceId);
+ EXPECT_EQ(request->hdr.type, PLDM_RDE);
+ EXPECT_EQ(request->hdr.request, 1);
+ EXPECT_EQ(request->hdr.command, PLDM_NEGOTIATE_REDFISH_PARAMETERS);
+ EXPECT_EQ(req_payload->mc_concurrency_support, mcConcurrencySupport);
+ EXPECT_EQ(le16toh(req_payload->mc_feature_support.value),
+ mcFeatureSupport.value);
+}
+TEST(NegotiateRedfishParametersTest, DecodeRequestSuccess)
+{
+ uint8_t mcConcurrencySupport = 1;
+ bitfield16_t mcFeatureSupport = {.value = 0x7389};
+ std::array<uint8_t,
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_negotiate_redfish_parameters_req)>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ auto req_payload =
+ reinterpret_cast<pldm_rde_negotiate_redfish_parameters_req*>(
+ request->payload);
+ req_payload->mc_concurrency_support = mcConcurrencySupport;
+ req_payload->mc_feature_support.value = htole16(mcFeatureSupport.value);
+ uint8_t decodedMcConcurrencySupport;
+ bitfield16_t decodedMcFeatureSupport;
+ EXPECT_EQ(decode_negotiate_redfish_parameters_req(
+ request,
+ sizeof(struct pldm_rde_negotiate_redfish_parameters_req),
+ &decodedMcConcurrencySupport, &decodedMcFeatureSupport),
+ PLDM_SUCCESS);
+ EXPECT_EQ(decodedMcConcurrencySupport, mcConcurrencySupport);
+ EXPECT_EQ(decodedMcFeatureSupport.value, mcFeatureSupport.value);
+}
+TEST(NegotiateMediumParametersTest, EncodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t maxTranferSize = 0xABCDEF18;
+ std::array<uint8_t,
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_negotiate_medium_parameters_req)>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ auto req_payload =
+ reinterpret_cast<pldm_rde_negotiate_medium_parameters_req*>(
+ request->payload);
+ EXPECT_EQ(encode_negotiate_medium_parameters_req(instanceId, maxTranferSize,
+ request),
+ PLDM_SUCCESS);
+ EXPECT_EQ(request->hdr.instance_id, instanceId);
+ EXPECT_EQ(request->hdr.type, PLDM_RDE);
+ EXPECT_EQ(request->hdr.request, 1);
+ EXPECT_EQ(request->hdr.command, PLDM_NEGOTIATE_MEDIUM_PARAMETERS);
+ EXPECT_EQ(le32toh(req_payload->mc_maximum_transfer_chunk_size_bytes),
+ maxTranferSize);
+}
+TEST(NegotiateMediumParametersTest, DecodeRequestSuccess)
+{
+ uint32_t mcSize = 0x10000000;
+ std::array<uint8_t,
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_negotiate_medium_parameters_req)>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ auto req_payload =
+ reinterpret_cast<pldm_rde_negotiate_medium_parameters_req*>(
+ request->payload);
+ req_payload->mc_maximum_transfer_chunk_size_bytes = htole32(mcSize);
+ uint32_t decodedMcSize;
+ EXPECT_EQ(decode_negotiate_medium_parameters_req(
+ request,
+ sizeof(struct pldm_rde_negotiate_medium_parameters_req),
+ &decodedMcSize),
+ PLDM_SUCCESS);
+ EXPECT_EQ(decodedMcSize, mcSize);
+}
+TEST(NegotiateMediumParametersTest, EncodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint32_t deviceSize = 0x10000000;
+ std::array<uint8_t,
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_negotiate_medium_parameters_resp)>
+ responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ EXPECT_EQ(encode_negotiate_medium_parameters_resp(
+ instanceId, completionCode, deviceSize, response),
+ PLDM_SUCCESS);
+ // verify header.
+ EXPECT_EQ(response->hdr.instance_id, instanceId);
+ EXPECT_EQ(response->hdr.request, 0);
+ EXPECT_EQ(response->hdr.type, PLDM_RDE);
+ EXPECT_EQ(response->hdr.command, PLDM_NEGOTIATE_MEDIUM_PARAMETERS);
+ // verify payload.
+ auto resp_payload =
+ reinterpret_cast<pldm_rde_negotiate_medium_parameters_resp*>(
+ response->payload);
+ EXPECT_EQ(resp_payload->completion_code, completionCode);
+ EXPECT_EQ(le32toh(resp_payload->device_maximum_transfer_chunk_size_bytes),
+ deviceSize);
+}
+TEST(GetSchemaDictionaryTest, EncodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint8_t schema_class = 1;
+ uint32_t resourceId = 0xABCDEF18;
+ std::array<uint8_t, sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_get_schema_dictionary_req)>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ auto req_payload =
+ reinterpret_cast<pldm_rde_get_schema_dictionary_req*>(request->payload);
+ EXPECT_EQ(encode_get_schema_dictionary_req(instanceId, resourceId,
+ schema_class, request),
+ PLDM_SUCCESS);
+ EXPECT_EQ(request->hdr.instance_id, instanceId);
+ EXPECT_EQ(request->hdr.type, PLDM_RDE);
+ EXPECT_EQ(request->hdr.request, 1);
+ EXPECT_EQ(request->hdr.command, PLDM_GET_SCHEMA_DICTIONARY);
+ EXPECT_EQ(le32toh(req_payload->resource_id), resourceId);
+ EXPECT_EQ(req_payload->requested_schema_class, schema_class);
+}
+TEST(GetSchemaDictionaryTest, DecodeRequestSuccess)
+{
+ uint32_t resourceId = 0xABCDEF12;
+ std::array<uint8_t, sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_get_schema_dictionary_req)>
+ requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ auto req_payload =
+ reinterpret_cast<pldm_rde_get_schema_dictionary_req*>(request->payload);
+ req_payload->resource_id = htole32(resourceId);
+ req_payload->requested_schema_class = PLDM_RDE_SCHEMA_ANNOTATION;
+ uint32_t decodedResourceId;
+ uint8_t decodedSchemaClass;
+ EXPECT_EQ(decode_get_schema_dictionary_req(
+ request, sizeof(struct pldm_rde_get_schema_dictionary_req),
+ &decodedResourceId, &decodedSchemaClass),
+ PLDM_SUCCESS);
+ EXPECT_EQ(decodedResourceId, resourceId);
+ EXPECT_EQ(decodedSchemaClass, PLDM_RDE_SCHEMA_ANNOTATION);
+}
+TEST(GetSchemaDictionaryTest, EncodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint8_t dictionaryFormat = 0x00;
+ uint32_t transferHandle = 0xABCDEF12;
+ std::array<uint8_t, sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_get_schema_dictionary_resp)>
+ responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ EXPECT_EQ(encode_get_schema_dictionary_resp(instanceId, completionCode,
+ dictionaryFormat,
+ transferHandle, response),
+ PLDM_SUCCESS);
+ // verify header.
+ EXPECT_EQ(response->hdr.instance_id, instanceId);
+ EXPECT_EQ(response->hdr.request, 0);
+ EXPECT_EQ(response->hdr.type, PLDM_RDE);
+ EXPECT_EQ(response->hdr.command, PLDM_GET_SCHEMA_DICTIONARY);
+ // verify payload.
+ auto resp_payload = reinterpret_cast<pldm_rde_get_schema_dictionary_resp*>(
+ response->payload);
+ EXPECT_EQ(resp_payload->completion_code, completionCode);
+ EXPECT_EQ(resp_payload->dictionary_format, dictionaryFormat);
+ EXPECT_EQ(le32toh(resp_payload->transfer_handle), transferHandle);
+}
+TEST(NegotiateRedfishParamsTest, DecodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint8_t deviceConcurrencySupport = 1;
+ bitfield8_t deviceCapabilitiesFlags = {.byte = 0x3F};
+ bitfield16_t deviceFeatureSupport = {.value = 0x7389};
+ uint32_t deviceConfigurationSignature = 0xABCDEF12;
+ constexpr const char* device = "This is a test";
+
+ std::array<uint8_t,
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_negotiate_redfish_parameters_resp) +
+ 14>
+ responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ auto deviceInfo = std::make_unique<pldm_rde_device_info>();
+ uint8_t cc;
+ encode_negotiate_redfish_parameters_resp(
+ instanceId, completionCode, deviceConcurrencySupport,
+ deviceCapabilitiesFlags, deviceFeatureSupport,
+ deviceConfigurationSignature, device, PLDM_RDE_VARSTRING_ASCII,
+ response);
+ EXPECT_EQ(
+ decode_negotiate_redfish_parameters_resp(
+ response,
+ sizeof(struct pldm_rde_negotiate_redfish_parameters_resp) + 14, &cc,
+ deviceInfo.get()),
+ PLDM_SUCCESS);
+
+ EXPECT_EQ(deviceInfo.get()->device_capabilities_flag.byte,
+ deviceCapabilitiesFlags.byte);
+ EXPECT_EQ(deviceInfo.get()->device_feature_support.value,
+ deviceFeatureSupport.value);
+ EXPECT_EQ(deviceInfo.get()->device_configuration_signature,
+ deviceConfigurationSignature);
+ EXPECT_EQ(cc, completionCode);
+ EXPECT_EQ(deviceInfo.get()->device_concurrency, deviceConcurrencySupport);
+}
+TEST(NegotiateMediumParams, DecodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint32_t deviceSize = 0x10000000;
+ std::array<uint8_t,
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_negotiate_medium_parameters_resp)>
+ responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ EXPECT_EQ(encode_negotiate_medium_parameters_resp(
+ instanceId, completionCode, deviceSize, response),
+ PLDM_SUCCESS);
+
+ // verify payload.
+ auto resp_payload =
+ reinterpret_cast<pldm_rde_negotiate_medium_parameters_resp*>(
+ response->payload);
+ EXPECT_EQ(resp_payload->completion_code, completionCode);
+ EXPECT_EQ(le32toh(resp_payload->device_maximum_transfer_chunk_size_bytes),
+ deviceSize);
+
+ uint8_t cc;
+ uint32_t deviceMaxTransferBytes;
+ EXPECT_EQ(decode_negotiate_medium_parameters_resp(
+ response,
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_negotiate_medium_parameters_resp),
+ &cc, &deviceMaxTransferBytes),
+ PLDM_SUCCESS);
+ EXPECT_EQ(deviceMaxTransferBytes, deviceSize);
+}
+TEST(GetSchemaDictionary, DecodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint8_t dictionaryFormat = 0x00;
+ uint32_t transferHandle = 0xABCDEF12;
+ constexpr int payloadLength =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_get_schema_dictionary_resp);
+ std::array<uint8_t, payloadLength> responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ EXPECT_EQ(encode_get_schema_dictionary_resp(instanceId, completionCode,
+ dictionaryFormat,
+ transferHandle, response),
+ PLDM_SUCCESS);
+ uint8_t cc, returnDictionaryFormat;
+ uint32_t returnTransferHandle;
+ EXPECT_EQ(decode_get_schema_dictionary_resp(response, payloadLength, &cc,
+ &returnDictionaryFormat,
+ &returnTransferHandle),
+ PLDM_SUCCESS);
+ EXPECT_EQ(cc, completionCode);
+ EXPECT_EQ(returnDictionaryFormat, dictionaryFormat);
+ EXPECT_EQ(returnTransferHandle, transferHandle);
+}
+TEST(MultipartReceive, EncodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t transferHandle = 0xABCDEF12;
+ uint16_t operationId = 0x01;
+ uint8_t transferOperation = PLDM_XFER_FIRST_PART;
+ constexpr int reqLength =
+ sizeof(struct pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES;
+ std::array<uint8_t, reqLength> requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ auto reqPayload =
+ reinterpret_cast<pldm_rde_multipart_receive_req*>(request->payload);
+ EXPECT_EQ(encode_rde_multipart_receive_req(instanceId, transferHandle,
+ operationId, transferOperation,
+ request),
+ PLDM_SUCCESS);
+ EXPECT_EQ(request->hdr.instance_id, instanceId);
+ EXPECT_EQ(request->hdr.type, PLDM_RDE);
+ EXPECT_EQ(request->hdr.request, 1);
+ EXPECT_EQ(request->hdr.command, PLDM_RDE_MULTIPART_RECEIVE);
+ EXPECT_EQ(reqPayload->operation_id, operationId);
+ EXPECT_EQ(reqPayload->data_transfer_handle, transferHandle);
+ EXPECT_EQ(reqPayload->transfer_operation, transferOperation);
+}
+TEST(MultipartReceive, DecodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t transferHandle = 0xABCDEF12;
+ uint16_t operationId = 0x01;
+ uint8_t transferOperation = PLDM_XFER_FIRST_PART;
+ constexpr int reqLength =
+ sizeof(struct pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES;
+ std::array<uint8_t, reqLength> requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ EXPECT_EQ(encode_rde_multipart_receive_req(instanceId, transferHandle,
+ operationId, transferOperation,
+ request),
+ PLDM_SUCCESS);
+
+ uint32_t returnTransferHandle;
+ uint16_t returnOperationId;
+ uint8_t returnTransferOperation;
+ EXPECT_EQ(decode_rde_multipart_receive_req(
+ request, sizeof(struct pldm_rde_multipart_receive_req),
+ &returnTransferHandle, &returnOperationId,
+ &returnTransferOperation),
+ PLDM_SUCCESS);
+ EXPECT_EQ(returnOperationId, operationId);
+ EXPECT_EQ(returnTransferHandle, transferHandle);
+ EXPECT_EQ(returnTransferOperation, transferOperation);
+}
+TEST(MultipartReceive, EncodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint8_t transferOperation = PLDM_XFER_FIRST_PART;
+ uint32_t transferHandle = 0xABCDEF12;
+
+ uint8_t payload[] = {0x01, 0x02, 0x03};
+ constexpr int payloadSize = sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_multipart_receive_resp) +
+ /*payload array size*/ 3;
+ std::array<uint8_t, payloadSize> responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+ EXPECT_EQ(encode_rde_multipart_receive_resp(
+ instanceId, completionCode, transferOperation, transferHandle,
+ /*payload array size*/ 3,
+ /*addChecksum*/ false, /*checksum*/ 0x00, &payload[0],
+ response),
+ PLDM_SUCCESS);
+
+ // // verify header.
+ EXPECT_EQ(response->hdr.instance_id, instanceId);
+ EXPECT_EQ(response->hdr.request, 0);
+ EXPECT_EQ(response->hdr.type, PLDM_RDE);
+ EXPECT_EQ(response->hdr.command, PLDM_RDE_MULTIPART_RECEIVE);
+ // // verify payload.
+ auto resp_payload =
+ reinterpret_cast<pldm_rde_multipart_receive_resp*>(response->payload);
+ EXPECT_EQ(resp_payload->completion_code, completionCode);
+ EXPECT_EQ(resp_payload->transfer_flag, transferOperation);
+ EXPECT_EQ(resp_payload->next_data_transfer_handle, transferHandle);
+ EXPECT_EQ(resp_payload->data_length_bytes, /*payload array size*/ 3);
+}
+TEST(MultipartReceive, DecodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint8_t transferOperation = PLDM_XFER_FIRST_PART;
+ uint32_t transferHandle = 0xABCDEF12;
+
+ uint8_t payload[] = {0x01, 0x02, 0x03};
+ constexpr size_t payloadSize = 3;
+ constexpr int responseSize =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_multipart_receive_resp) +
+ /*payload array size*/ payloadSize;
+ std::array<uint8_t, responseSize> responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+ EXPECT_EQ(encode_rde_multipart_receive_resp(
+ instanceId, completionCode, transferOperation, transferHandle,
+ /*payload array size*/ payloadSize,
+ /*addChecksum*/ false, /*checksum*/ 0x00, &payload[0],
+ response),
+ PLDM_SUCCESS);
+
+ uint8_t cc;
+ uint8_t returnTransferFlag;
+ uint32_t returnTransferHandle;
+ uint32_t returnDataLenBytes;
+
+ uint8_t* returnPayload;
+ EXPECT_EQ(decode_rde_multipart_receive_resp(
+ response, /*ASSUME_MAX_SIZE*/ 256, &cc, &returnTransferFlag,
+ &returnTransferHandle, &returnDataLenBytes, &returnPayload),
+ PLDM_SUCCESS);
+ EXPECT_EQ(cc, completionCode);
+ EXPECT_EQ(returnTransferFlag, transferOperation);
+ EXPECT_EQ(returnDataLenBytes, payloadSize);
+}
+
+TEST(RDEOperationInit, EncodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t resourceId = 0x0001000;
+ uint16_t operationId = 32770;
+ uint8_t operationType = PLDM_RDE_OPERATION_READ;
+ auto operationFlags = std::make_unique<union pldm_rde_operation_flags>();
+ operationFlags.get()->byte = 0x00;
+ uint32_t transferHandle = 0xABCDEF12;
+ constexpr size_t requestSize = sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_init_req);
+ std::array<uint8_t, requestSize> requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+ EXPECT_EQ(encode_rde_operation_init_req(instanceId, resourceId, operationId,
+ operationType, operationFlags.get(),
+ transferHandle, 0, 0, NULL, NULL,
+ request),
+ PLDM_SUCCESS);
+
+ // Test Header values
+ EXPECT_EQ(request->hdr.instance_id, instanceId);
+ EXPECT_EQ(request->hdr.request, PLDM_REQUEST);
+ EXPECT_EQ(request->hdr.type, PLDM_RDE);
+ EXPECT_EQ(request->hdr.command, PLDM_RDE_OPERATION_INIT);
+
+ // Test payload values
+ auto reqPayload =
+ reinterpret_cast<pldm_rde_operation_init_req*>(request->payload);
+ EXPECT_EQ(reqPayload->resource_id, resourceId);
+ EXPECT_EQ(reqPayload->operation_id, operationId);
+ EXPECT_EQ(reqPayload->operation_type, operationType);
+ EXPECT_EQ(reqPayload->operation_flags.byte, operationFlags.get()->byte);
+ EXPECT_EQ(reqPayload->operation_locator_length, 0);
+ EXPECT_EQ(reqPayload->request_payload_length, 0);
+}
+
+TEST(RDEOperationInit, DecodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t resourceId = 0x0001000;
+ uint16_t operationId = 32770;
+ uint8_t operationType = PLDM_RDE_OPERATION_READ;
+ auto operationFlags = std::make_unique<union pldm_rde_operation_flags>();
+ operationFlags.get()->byte = 0x00;
+ uint32_t transferHandle = 0xABCDEF12;
+ constexpr size_t requestSize = sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_init_req);
+ std::array<uint8_t, requestSize> requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+ encode_rde_operation_init_req(instanceId, resourceId, operationId,
+ operationType, operationFlags.get(),
+ transferHandle, 0, 0, NULL, NULL, request);
+
+ uint32_t returnResourceId;
+ uint16_t returnOperationId;
+ uint8_t returnOperationType;
+ uint32_t returnSendTransferHandle;
+ uint8_t returnOperationLocatorLength;
+ uint32_t returnRequestPayloadLength;
+ uint8_t* returnOperationLocator = std::make_unique<uint8_t>().get();
+ uint8_t* returnRequestPayload = std::make_unique<uint8_t>().get();
+ union pldm_rde_operation_flags returnOperationFlags;
+
+ EXPECT_EQ(decode_rde_operation_init_req(
+ request, sizeof(struct pldm_rde_operation_init_req),
+ &returnResourceId, &returnOperationId, &returnOperationType,
+ &returnOperationFlags, &returnSendTransferHandle,
+ &returnOperationLocatorLength, &returnRequestPayloadLength,
+ &returnOperationLocator, &returnRequestPayload),
+ PLDM_SUCCESS);
+ EXPECT_EQ(returnResourceId, resourceId);
+ EXPECT_EQ(returnOperationId, operationId);
+ EXPECT_EQ(returnOperationType, operationType);
+ EXPECT_EQ(returnSendTransferHandle, transferHandle);
+ EXPECT_EQ(returnOperationFlags.byte, operationFlags.get()->byte);
+ EXPECT_EQ(returnOperationLocatorLength, 0);
+ EXPECT_EQ(returnRequestPayloadLength, 0);
+}
+
+TEST(RDEOperationInit, EncodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint8_t operationStatus = PLDM_RDE_OPERATION_COMPLETED;
+ uint8_t completionPercentage = 100;
+ uint32_t completionTimeSeconds = 1;
+ union pldm_rde_op_execution_flags operationExecutionFlags;
+ operationExecutionFlags.byte = 0x01;
+ uint32_t resultTransferHandle = 0x01;
+ union pldm_rde_permission_flags permissionFlags;
+ permissionFlags.byte = 0x02;
+ enum pldm_rde_varstring_format etagFormat = PLDM_RDE_VARSTRING_UTF_8;
+ const char etag[] = "etag";
+
+ constexpr size_t responsePayloadLength =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_init_resp) + 4;
+ std::array<uint8_t, responsePayloadLength> responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ EXPECT_EQ(encode_rde_operation_init_resp(
+ instanceId, completionCode, operationStatus,
+ completionPercentage, completionTimeSeconds,
+ &operationExecutionFlags, resultTransferHandle,
+ &permissionFlags, 0, etagFormat, etag, NULL, response),
+ PLDM_SUCCESS);
+ // verify header.
+ EXPECT_EQ(response->hdr.instance_id, instanceId);
+ EXPECT_EQ(response->hdr.request, 0);
+ EXPECT_EQ(response->hdr.type, PLDM_RDE);
+ EXPECT_EQ(response->hdr.command, PLDM_RDE_OPERATION_INIT);
+ // verify payload.
+ auto respPayload =
+ reinterpret_cast<pldm_rde_operation_init_resp*>(response->payload);
+ EXPECT_EQ(respPayload->completion_code, completionCode);
+ EXPECT_EQ(respPayload->operation_status, operationStatus);
+ EXPECT_EQ(respPayload->completion_percentage, completionPercentage);
+ EXPECT_EQ(respPayload->completion_time_seconds, completionTimeSeconds);
+ EXPECT_EQ(respPayload->operation_execution_flags.byte,
+ operationExecutionFlags.byte);
+ EXPECT_EQ(respPayload->permission_flags.byte, permissionFlags.byte);
+}
+
+TEST(RDEOperationInit, DecodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint8_t operationStatus = PLDM_RDE_OPERATION_COMPLETED;
+ uint8_t completionPercentage = 100;
+ uint32_t completionTimeSeconds = 1;
+ union pldm_rde_op_execution_flags operationExecutionFlags;
+ operationExecutionFlags.byte = 0x01;
+ uint32_t resultTransferHandle = 0x01;
+ union pldm_rde_permission_flags permissionFlags;
+ permissionFlags.byte = 0x02;
+ enum pldm_rde_varstring_format etagFormat = PLDM_RDE_VARSTRING_UTF_8;
+ const char etag[] = "etag";
+
+ constexpr size_t responsePayloadLength =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_init_resp) + 4;
+ std::array<uint8_t, responsePayloadLength> responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ EXPECT_EQ(encode_rde_operation_init_resp(
+ instanceId, completionCode, operationStatus,
+ completionPercentage, completionTimeSeconds,
+ &operationExecutionFlags, resultTransferHandle,
+ &permissionFlags, 0, etagFormat, etag, NULL, response),
+ PLDM_SUCCESS);
+
+ uint8_t returnCompletionCode;
+ uint8_t returnOperationStatus;
+ uint8_t returnCompletionPercentage;
+ uint32_t returnCompletionTimeSeconds;
+ uint32_t returnTransferHandle;
+ uint32_t returnResponsePayloadLength;
+
+ union pldm_rde_op_execution_flags* returnExecutionFlags =
+ (union pldm_rde_op_execution_flags*)malloc(
+ sizeof(union pldm_rde_op_execution_flags));
+ union pldm_rde_permission_flags* returnPermissionFlags =
+ (union pldm_rde_permission_flags*)malloc(
+ sizeof(union pldm_rde_permission_flags));
+
+ auto returnEtag = std::make_unique<pldm_rde_varstring>().get();
+ auto responsePayload = std::make_unique<uint8_t>().get();
+ EXPECT_EQ(decode_rde_operation_init_resp(
+ response, responsePayloadLength, &returnCompletionCode,
+ &returnCompletionPercentage, &returnOperationStatus,
+ &returnCompletionTimeSeconds, &returnTransferHandle,
+ &returnResponsePayloadLength, &returnPermissionFlags,
+ &returnExecutionFlags, &returnEtag, &responsePayload),
+ PLDM_SUCCESS);
+
+ EXPECT_EQ(returnCompletionCode, completionCode);
+ EXPECT_EQ(returnCompletionPercentage, completionPercentage);
+ EXPECT_EQ(returnOperationStatus, operationStatus);
+ EXPECT_EQ(returnCompletionTimeSeconds, completionTimeSeconds);
+ EXPECT_EQ(returnTransferHandle, resultTransferHandle);
+ EXPECT_EQ(returnResponsePayloadLength, 0);
+ EXPECT_EQ(returnPermissionFlags->byte, permissionFlags.byte);
+ EXPECT_EQ(returnExecutionFlags->byte, operationExecutionFlags.byte);
+ EXPECT_EQ(returnEtag->string_length_bytes,
+ std::end(etag) - std::begin(etag));
+}
+TEST(RDEOperationComplete, EncodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t resourceId = 0x0001000;
+ uint16_t operationId = 32770;
+ constexpr size_t requestSize =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_complete_req);
+ std::array<uint8_t, requestSize> requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+ EXPECT_EQ(encode_rde_operation_complete_req(instanceId, resourceId,
+ operationId, request),
+ PLDM_SUCCESS);
+ // Test Headers
+ EXPECT_EQ(request->hdr.instance_id, instanceId);
+ EXPECT_EQ(request->hdr.type, PLDM_RDE);
+ EXPECT_EQ(request->hdr.request, PLDM_REQUEST);
+ EXPECT_EQ(request->hdr.command, PLDM_RDE_OPERATION_COMPLETE);
+
+ auto reqPayload =
+ reinterpret_cast<pldm_rde_operation_complete_req*>(request->payload);
+ EXPECT_EQ(reqPayload->resource_id, resourceId);
+ EXPECT_EQ(reqPayload->operation_id, operationId);
+}
+
+TEST(RDEOperationComplete, DecodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t resourceId = 0x0001000;
+ uint16_t operationId = 32770;
+ constexpr size_t requestSize =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_complete_req);
+ std::array<uint8_t, requestSize> requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+ EXPECT_EQ(encode_rde_operation_complete_req(instanceId, resourceId,
+ operationId, request),
+ PLDM_SUCCESS);
+
+ uint16_t returnOperationId;
+ uint32_t returnResourceId;
+ EXPECT_EQ(decode_rde_operation_status_req(
+ request, requestSize, &returnResourceId, &returnOperationId),
+ PLDM_SUCCESS);
+
+ EXPECT_EQ(returnOperationId, operationId);
+ EXPECT_EQ(returnResourceId, resourceId);
+}
+
+TEST(RDEOperationComplete, EncodeResponseSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t completionCode = 0;
+ constexpr size_t responseSize =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_complete_resp);
+ std::array<uint8_t, responseSize> responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+ EXPECT_EQ(encode_rde_operation_complete_resp(instanceId, completionCode,
+ response),
+ PLDM_SUCCESS);
+
+ EXPECT_EQ(response->hdr.instance_id, instanceId);
+ EXPECT_EQ(response->hdr.request, PLDM_RESPONSE);
+ EXPECT_EQ(response->hdr.type, PLDM_RDE);
+ EXPECT_EQ(response->hdr.command, PLDM_RDE_OPERATION_COMPLETE);
+
+ auto respPayload =
+ reinterpret_cast<pldm_rde_operation_init_resp*>(response->payload);
+
+ EXPECT_EQ(respPayload->completion_code, completionCode);
+}
+
+TEST(RDEOperationComplete, DecodeResponseSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t completionCode = 0;
+ constexpr size_t responseSize =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_complete_resp);
+ std::array<uint8_t, responseSize> responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+ encode_rde_operation_complete_resp(instanceId, completionCode, response);
+
+ uint8_t cc;
+ EXPECT_EQ(decode_rde_operation_complete_resp(response, responseSize, &cc),
+ PLDM_SUCCESS);
+ EXPECT_EQ(cc, PLDM_SUCCESS);
+}
+TEST(RDEOperationStatus, EncodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t resourceId = 0x0001000;
+ uint16_t operationId = 32770;
+
+ constexpr size_t requestSize = sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_status_req);
+ std::array<uint8_t, requestSize> requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+ EXPECT_EQ(encode_rde_operation_status_req(instanceId, resourceId,
+ operationId, request),
+ PLDM_SUCCESS);
+
+ // Test Header values
+ EXPECT_EQ(request->hdr.instance_id, instanceId);
+ EXPECT_EQ(request->hdr.request, PLDM_REQUEST);
+ EXPECT_EQ(request->hdr.type, PLDM_RDE);
+ EXPECT_EQ(request->hdr.command, PLDM_RDE_OPERATION_STATUS);
+
+ // Test payload values
+ auto reqPayload =
+ reinterpret_cast<pldm_rde_operation_status_req*>(request->payload);
+ EXPECT_EQ(reqPayload->resource_id, resourceId);
+ EXPECT_EQ(reqPayload->operation_id, operationId);
+}
+TEST(RDEOperationStatus, DecodeRequestSuccess)
+{
+ uint8_t instanceId = 11;
+ uint32_t resourceId = 0x0001000;
+ uint16_t operationId = 32770;
+
+ constexpr size_t requestSize = sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_status_req);
+ std::array<uint8_t, requestSize> requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+ encode_rde_operation_status_req(instanceId, resourceId, operationId,
+ request);
+ uint32_t returnResourceId;
+ uint16_t returnOperationId;
+ EXPECT_EQ(decode_rde_operation_status_req(
+ request, requestSize, &returnResourceId, &returnOperationId),
+ PLDM_SUCCESS);
+ EXPECT_EQ(returnResourceId, resourceId);
+ EXPECT_EQ(returnOperationId, operationId);
+}
+TEST(RDEOperationStatus, EncodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint8_t operationStatus = PLDM_RDE_OPERATION_COMPLETED;
+ uint8_t completionPercentage = 100;
+ uint32_t completionTimeSeconds = 1;
+ union pldm_rde_op_execution_flags operationExecutionFlags;
+ operationExecutionFlags.byte = 0x01;
+ uint32_t resultTransferHandle = 0x01;
+ union pldm_rde_permission_flags permissionFlags;
+ permissionFlags.byte = 0x02;
+ enum pldm_rde_varstring_format etagFormat = PLDM_RDE_VARSTRING_UTF_8;
+ const char etag[] = "etag";
+
+ constexpr size_t responsePayloadLength =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_status_resp) + 4;
+ std::array<uint8_t, responsePayloadLength> responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ EXPECT_EQ(encode_rde_operation_status_resp(
+ instanceId, completionCode, operationStatus,
+ completionPercentage, completionTimeSeconds,
+ &operationExecutionFlags, resultTransferHandle,
+ &permissionFlags, 0, etagFormat, etag, NULL, response),
+ PLDM_SUCCESS);
+ // verify header.
+ EXPECT_EQ(response->hdr.instance_id, instanceId);
+ EXPECT_EQ(response->hdr.request, 0);
+ EXPECT_EQ(response->hdr.type, PLDM_RDE);
+ EXPECT_EQ(response->hdr.command, PLDM_RDE_OPERATION_STATUS);
+ // verify payload.
+ auto respPayload =
+ reinterpret_cast<pldm_rde_operation_status_resp*>(response->payload);
+ EXPECT_EQ(respPayload->completion_code, completionCode);
+ EXPECT_EQ(respPayload->operation_status, operationStatus);
+ EXPECT_EQ(respPayload->completion_percentage, completionPercentage);
+ EXPECT_EQ(respPayload->completion_time_seconds, completionTimeSeconds);
+ EXPECT_EQ(respPayload->operation_execution_flags.byte,
+ operationExecutionFlags.byte);
+ EXPECT_EQ(respPayload->permission_flags.byte, permissionFlags.byte);
+}
+TEST(RDEOperationStatus, DecodeResponseSuccess)
+{
+ uint8_t completionCode = 0;
+ uint8_t instanceId = 11;
+ uint8_t operationStatus = PLDM_RDE_OPERATION_COMPLETED;
+ uint8_t completionPercentage = 100;
+ uint32_t completionTimeSeconds = 1;
+ union pldm_rde_op_execution_flags operationExecutionFlags;
+ operationExecutionFlags.byte = 0x01;
+ uint32_t resultTransferHandle = 0x01;
+ union pldm_rde_permission_flags permissionFlags;
+ permissionFlags.byte = 0x02;
+ enum pldm_rde_varstring_format etagFormat = PLDM_RDE_VARSTRING_UTF_8;
+ const char etag[] = "etag";
+
+ constexpr size_t responsePayloadLength =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_rde_operation_status_resp) + 4;
+ std::array<uint8_t, responsePayloadLength> responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ EXPECT_EQ(encode_rde_operation_status_resp(
+ instanceId, completionCode, operationStatus,
+ completionPercentage, completionTimeSeconds,
+ &operationExecutionFlags, resultTransferHandle,
+ &permissionFlags, 0, etagFormat, etag, NULL, response),
+ PLDM_SUCCESS);
+
+ uint8_t returnCompletionCode;
+ uint8_t returnOperationStatus;
+ uint8_t returnCompletionPercentage;
+ uint32_t returnCompletionTimeSeconds;
+ uint32_t returnTransferHandle;
+ uint32_t returnResponsePayloadLength;
+
+ union pldm_rde_op_execution_flags* returnExecutionFlags =
+ (union pldm_rde_op_execution_flags*)malloc(
+ sizeof(union pldm_rde_op_execution_flags));
+ union pldm_rde_permission_flags* returnPermissionFlags =
+ (union pldm_rde_permission_flags*)malloc(
+ sizeof(union pldm_rde_permission_flags));
+
+ auto returnEtag = std::make_unique<pldm_rde_varstring>().get();
+ auto responsePayload = std::make_unique<uint8_t>().get();
+ EXPECT_EQ(decode_rde_operation_status_resp(
+ response, responsePayloadLength, &returnCompletionCode,
+ &returnCompletionPercentage, &returnOperationStatus,
+ &returnCompletionTimeSeconds, &returnTransferHandle,
+ &returnResponsePayloadLength, &returnPermissionFlags,
+ &returnExecutionFlags, &returnEtag, &responsePayload),
+ PLDM_SUCCESS);
+
+ EXPECT_EQ(returnCompletionCode, completionCode);
+ EXPECT_EQ(returnCompletionPercentage, completionPercentage);
+ EXPECT_EQ(returnOperationStatus, operationStatus);
+ EXPECT_EQ(returnCompletionTimeSeconds, completionTimeSeconds);
+ EXPECT_EQ(returnTransferHandle, resultTransferHandle);
+ EXPECT_EQ(returnResponsePayloadLength, 0);
+ EXPECT_EQ(returnPermissionFlags->byte, permissionFlags.byte);
+ EXPECT_EQ(returnExecutionFlags->byte, operationExecutionFlags.byte);
+ EXPECT_EQ(returnEtag->string_length_bytes,
+ std::end(etag) - std::begin(etag));
+}
diff --git a/tests/meson.build b/tests/meson.build
index a15e7ec..0449c3d 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -26,6 +26,7 @@ tests = [
'msgbuf',
'responder',
'requester/base_requester_test',
+ 'libpldm_rde_test',
]
if get_option('abi').contains('testing')
--
2.43.0.rc2.451.g8631bc7472-goog