blob: 9509a5d8bef55a1fa4c983406ec7a16f17839a17 [file]
From 906886902ee74bfe60a5ae4604b29608596cf09a Mon Sep 17 00:00:00 2001
From: Konda Reddy Kachana <kkachana@google.com>
Date: Wed, 22 Nov 2023 06:12:47 +0000
Subject: [PATCH] libpldm: support SupplyCustomRequestParameters command
Support for SupplyCustomRequestParameters to enable expand
feature for RDE devices. Adding encoding and decoding APIs
for SupplyCustomRequestParameters command request and response.
Tested:
[----------] 2 tests from SupplyCustomRequestParameters
[ RUN ] SupplyCustomRequestParameters.EncodeRequestSuccess
[ OK ] SupplyCustomRequestParameters.EncodeRequestSuccess (0 ms)
[ RUN ] SupplyCustomRequestParameters.DecodeResponseSuccess
[ OK ] SupplyCustomRequestParameters.DecodeResponseSuccess (0 ms)
[----------] 2 tests from SupplyCustomRequestParameters (0 ms total)
Google-Bug-Id: 313670415
Change-Id: I025294c35242f264bab2a9748df332652a0d81d0
Signed-off-by: Konda Reddy Kachana <kkachana@google.com>
---
include/libpldm/pldm_rde.h | 168 ++++++++++++-
.../libpldm/requester/pldm_rde_requester.h | 29 ++-
src/pldm_rde.c | 232 +++++++++++++++++-
src/requester/pldm_rde_requester.c | 125 +++++++++-
tests/libpldm_rde_test.cpp | 175 +++++++++++++
tests/requester/rde_requester_test.cpp | 21 +-
6 files changed, 730 insertions(+), 20 deletions(-)
diff --git a/include/libpldm/pldm_rde.h b/include/libpldm/pldm_rde.h
index 5b2a3dc..4f7bc41 100644
--- a/include/libpldm/pldm_rde.h
+++ b/include/libpldm/pldm_rde.h
@@ -36,6 +36,12 @@ extern "C" {
#define RESOURCE_ID_ANY 0xFFFFFFFF
#define IGNORE(x) (void)(x)
+// Custom Headers
+#define PLDM_RDE_EXPAND_TYPE "PLDM-RDE-Expand-Type"
+#define EXPAND_DOT "."
+#define EXPAND_TILDE "~"
+#define EXPAND_STAR "*"
+
/** @brief RDE Supported Commands
*/
enum pldm_rde_commands {
@@ -44,6 +50,7 @@ enum pldm_rde_commands {
PLDM_GET_SCHEMA_DICTIONARY = 0x03,
PLDM_GET_SCHEMA_FILE = 0x0C,
PLDM_RDE_OPERATION_INIT = 0x10,
+ PLDM_SUPPLY_CUSTOM_REQUEST_PARAMETERS = 0x11,
PLDM_RDE_OPERATION_COMPLETE = 0x13,
PLDM_RDE_OPERATION_STATUS = 0x14,
PLDM_RDE_OPERATION_KILL = 0x15,
@@ -120,6 +127,12 @@ enum pldm_rde_operation_status {
PLDM_RDE_OPERATION_ABANDONED = 7,
};
+typedef enum pldm_rde_etag_operation {
+ PLDM_RDE_ETAG_IGNORE = 0,
+ PLDM_RDE_ETAG_IF_MATCH = 1,
+ PLDM_RDE_ETAG_IF_NONE_MATCH = 2,
+} pldm_rde_etag_operation;
+
/**
* @brief MC feature support.
*
@@ -320,6 +333,38 @@ struct pldm_rde_operation_init_resp {
// Variable length data: varstring and the payload.
uint8_t var_data[1];
} __attribute__((packed));
+
+/**
+ * @brief SupplyCustomRequestParameters request data structure.
+ */
+struct pldm_supply_custom_request_parameters_req {
+ uint32_t resource_id;
+ uint16_t operation_id;
+ uint16_t link_expand;
+ uint16_t collection_skip;
+ uint16_t collection_top;
+ uint16_t pagination_offset;
+ uint8_t etag_operation;
+ uint8_t etag_count;
+ uint8_t var_data[1];
+} __attribute__((packed));
+
+/**
+ * @brief SupplyCustomRequestParameters response data structure.
+ */
+struct pldm_supply_custom_request_parameters_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.
*/
@@ -718,6 +763,123 @@ int decode_rde_operation_init_resp(
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 SupplyCustomRequestParameters 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] link_expand - The value of a $levels qualifier to a $expand
+ * query option.
+ * @param[in] collection_skip - The value of a $skip query option.
+ * @param[in] collection_top - The value of a $top query option.
+ * @param[in] pagination_offset - The page offset for paginated response data.
+ * @param[out] msg - Request message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_supply_custom_request_parameters_req(
+ uint8_t instance_id, uint32_t resource_id, uint16_t operation_id,
+ uint16_t link_expand, uint16_t collection_skip, uint16_t collection_top,
+ uint16_t pagination_offset, struct pldm_msg *msg);
+
+/**
+ * @brief Encode SupplyCustomRequestParameters request's etags.
+ *
+ * @param[in] etag_operation - ETagOperation type.
+ * @param[in] etag_count - Number of ETags supplied in this message;
+ * should be zero if ETagOperation above is ETAG_IGNORE and nonzero otherwise.
+ * @param[in] etag_formats - The list of etag formats.
+ * @param[in] etags - The list of etags.
+ * @param[in] end_of_etags_offset - Offset in msg to encode etags.
+ * @param[out] msg - Request message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_etags_in_supply_custom_request_parameters_req(
+ pldm_rde_etag_operation etag_operation,
+ uint8_t etag_count, enum pldm_rde_varstring_format *etag_formats, char **etags,
+ uint8_t *end_of_etags_offset, struct pldm_msg *msg);
+
+/**
+ * @brief Encode SupplyCustomRequestParameters request's headers.
+ *
+ * @param[in] Header_count - The number of RDE custom headers being supplied
+ * in this operation.
+ * @param[in] hdrname_formats - List if hdrnames formats.
+ * @param[in] hdrnames - List if custom headers, including the PLDM-RDE-
+ * prefix.
+ * @param[in] hdrparam_formats - List if hdrparams formats.
+ * @param[in] hdrparams - List of parameters associated with
+ * the header.
+ * @param[in] header_offset - Offset in msg to encode headers.
+ * @param[out] msg - Request message will be written to this.
+ * @return pldm_completion_codes.
+ */
+int encode_headers_in_supply_custom_request_parameters_req(
+ uint8_t header_count, enum pldm_rde_varstring_format *hdrname_formats, char **hdrnames,
+ enum pldm_rde_varstring_format *hdrparam_formats, char **hdrparams,
+ const uint8_t *header_offset, struct pldm_msg *msg);
+
+/**
+ * @brief Encode SupplyCustomRequestParameters 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 - 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_supply_custom_request_parameters_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, char *etag,
+ const uint8_t *response_payload, struct pldm_msg *msg);
+
+/**
+ * @brief Decode SupplyCustomRequestParameters Resp
+ *
+ * @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] completion_percentage - Percentage complete.
+ * @param[out] operation_status - Status of the operation.
+ * @param[out] completion_time_seconds - An estimate of the number of seconds
+ * remaining before the Operation is completed.
+ * @param[out] operation_execution_flags - Explains the result of operation.
+ * @param[out] result_transfer_handle - A data transfer handle that the MC
+ * may use to retrieve a larger response payload.
+ * @param[out] response_payload_length - Length of the response payload.
+ * @param[out] permission_flags - Indicates the access level granted to the
+ * resource targeted by the Operation.
+ * @param[out] etag - ETag.
+ * @param[out] response_payload - The response payload if the payload fits.
+ * @return pldm_completion_codes.
+ */
+int decode_supply_custom_request_parameters_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.
*
@@ -738,8 +900,8 @@ int encode_rde_operation_complete_req(uint8_t instance_id, uint32_t resource_id,
* @param[out] msg - Request will be written to this
*/
int encode_rde_operation_kill_req(uint8_t instance_id, uint32_t resource_id,
- uint16_t operation_id,
- struct pldm_msg *msg);
+ uint16_t operation_id,
+ struct pldm_msg *msg);
/**
* @brief Decode RDEOperationComplete request.
*
@@ -922,7 +1084,7 @@ int encode_rde_operation_status_resp(
* @return pldm_completion_codes.
*/
int decode_rde_operation_status_resp(
- const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+ 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,
diff --git a/include/libpldm/requester/pldm_rde_requester.h b/include/libpldm/requester/pldm_rde_requester.h
index 92ced28..1a7bc82 100644
--- a/include/libpldm/requester/pldm_rde_requester.h
+++ b/include/libpldm/requester/pldm_rde_requester.h
@@ -14,6 +14,9 @@ extern "C" {
#define DEFAULT_INIT 0
+#define MAX_HEADERS 8
+#define MAX_ETAGS 8
+
typedef enum rde_requester_return_codes {
PLDM_RDE_REQUESTER_SUCCESS = 0,
PLDM_RDE_REQUESTER_NOT_PLDM_RDE_MSG = -1,
@@ -119,6 +122,24 @@ struct rde_read_operation {
uint8_t completion_code;
};
+struct rde_query_options {
+ bool skip;
+ bool top;
+ bool expand;
+ uint16_t skip_param;
+ uint16_t top_param;
+ uint16_t expand_levels;
+ uint8_t header_count;
+ enum pldm_rde_varstring_format hdrname_formats[MAX_HEADERS];
+ char *hdrnames[MAX_HEADERS];
+ enum pldm_rde_varstring_format hdrparam_formats[MAX_HEADERS];
+ char *hdrparams[MAX_HEADERS];
+ uint8_t etag_operation;
+ uint8_t etag_count;
+ enum pldm_rde_varstring_format etag_formats[MAX_ETAGS];
+ char *etags[MAX_ETAGS];
+};
+
/**
* @brief RDE operation
*/
@@ -139,6 +160,7 @@ struct rde_operation {
uint8_t *operation_locator;
uint32_t request_payload_length;
uint8_t *request_payload;
+ struct rde_query_options *query_options;
// Response Data
uint32_t resp_payload_length;
@@ -357,9 +379,10 @@ pldm_rde_requester_rc_t pldm_rde_push_get_dictionary_response(
pldm_rde_requester_rc_t pldm_rde_init_rde_operation_context(
struct pldm_rde_requester_context *ctx, uint8_t request_id,
uint32_t resource_id, uint16_t operation_id, uint8_t operation_type,
- uint8_t op_flags_byte, uint32_t send_data_transfer_handle,
- uint8_t operation_locator_length, uint32_t request_payload_length,
- uint8_t *operation_locator, uint8_t *request_payload);
+ uint8_t op_flags_byte, struct rde_query_options *query_options,
+ 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 Get next RDE operation in sequence to cater to a RDE request
diff --git a/src/pldm_rde.c b/src/pldm_rde.c
index 7116827..de590c1 100644
--- a/src/pldm_rde.c
+++ b/src/pldm_rde.c
@@ -177,7 +177,7 @@ int decode_negotiate_medium_parameters_resp(
if (PLDM_SUCCESS != *completion_code) {
fprintf(stderr,
"Unsuccessful completion code received in neg med params: %x\n",
- (uint8_t)(*completion_code));
+ (uint8_t)(*completion_code));
return PLDM_SUCCESS;
}
@@ -694,6 +694,236 @@ int decode_rde_operation_init_resp(
return 0;
}
+LIBPLDM_ABI_STABLE
+int encode_supply_custom_request_parameters_req(
+ uint8_t instance_id, uint32_t resource_id, uint16_t operation_id,
+ uint16_t link_expand, uint16_t collection_skip, uint16_t collection_top,
+ uint16_t pagination_offset, struct pldm_msg *msg)
+{
+ struct pldm_header_info header = {0};
+ header.instance = instance_id;
+ header.pldm_type = PLDM_RDE;
+ header.msg_type = PLDM_REQUEST;
+ header.command = PLDM_SUPPLY_CUSTOM_REQUEST_PARAMETERS;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_supply_custom_request_parameters_req *req =
+ (struct pldm_supply_custom_request_parameters_req *)msg->payload;
+ req->resource_id = htole32(resource_id);
+ req->operation_id = htole16(operation_id);
+ req->link_expand = link_expand;
+ req->collection_skip = collection_skip;
+ req->collection_top = collection_top;
+ req->pagination_offset = pagination_offset;
+ req->etag_operation = PLDM_RDE_ETAG_IGNORE;
+ req->etag_count = 0;
+
+ return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_etags_in_supply_custom_request_parameters_req(
+ pldm_rde_etag_operation etag_operation,
+ uint8_t etag_count, enum pldm_rde_varstring_format *etag_formats, char **etags,
+ uint8_t *end_of_etags_offset, struct pldm_msg *msg)
+{
+ if ((etag_count > 0) && (etags == NULL)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ struct pldm_header_info header;
+ uint8_t rc = unpack_pldm_header(&msg->hdr, &header);
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ if (header.pldm_type != PLDM_RDE ||
+ header.msg_type != PLDM_REQUEST ||
+ header.command != PLDM_SUPPLY_CUSTOM_REQUEST_PARAMETERS) {
+ //Not PLDM_SUPPLY_CUSTOM_REQUEST_PARAMETERS req
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ struct pldm_supply_custom_request_parameters_req *req =
+ (struct pldm_supply_custom_request_parameters_req *)msg->payload;
+
+ req->etag_operation = etag_operation;
+ req->etag_count = etag_count;
+
+ uint8_t offset = 0;
+
+ if( req->etag_operation != PLDM_RDE_ETAG_IGNORE) {
+ for (uint8_t i = 0; i < etag_count; i++)
+ {
+ req->var_data[offset++] = etag_formats[i];
+ uint8_t len = strlen(etags[i]) + 1;
+ req->var_data[offset++] = len;
+ memcpy(req->var_data + offset, etags[i], len);
+ offset += len;
+ }
+ }
+
+ // store the end of etags offset to encode headers.
+ *end_of_etags_offset = offset;
+ return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_headers_in_supply_custom_request_parameters_req(
+ uint8_t header_count, enum pldm_rde_varstring_format *hdrname_formats, char **hdrnames,
+ enum pldm_rde_varstring_format *hdrparam_formats, char **hdrparams,
+ const uint8_t *header_offset, struct pldm_msg *msg)
+{
+ if ((header_count > 0) &&
+ (hdrnames == NULL || hdrparams == NULL )) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ struct pldm_header_info header;
+ uint8_t rc = unpack_pldm_header(&msg->hdr, &header);
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ if (header.pldm_type != PLDM_RDE ||
+ header.msg_type != PLDM_REQUEST ||
+ header.command != PLDM_SUPPLY_CUSTOM_REQUEST_PARAMETERS) {
+ //Not PLDM_SUPPLY_CUSTOM_REQUEST_PARAMETERS req
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ uint8_t offset = *header_offset;
+ struct pldm_supply_custom_request_parameters_req *req =
+ (struct pldm_supply_custom_request_parameters_req *)msg->payload;
+
+ //header count
+ req->var_data[offset++] = header_count;
+ for (uint8_t i = 0; i < header_count; i++)
+ {
+ req->var_data[offset++] = hdrname_formats[i];
+ uint8_t len = strlen(hdrnames[i]) + 1;
+ req->var_data[offset++] = len;
+ memcpy(req->var_data + offset, hdrnames[i], len);
+ offset += len;
+ }
+
+ for (uint8_t i = 0; i < header_count; i++)
+ {
+ req->var_data[offset++] = hdrparam_formats[i];
+ uint8_t len = strlen(hdrparams[i]) + 1;
+ req->var_data[offset++] = len;
+ memcpy(req->var_data + offset, hdrparams[i], len);
+ offset += len;
+ }
+ return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_supply_custom_request_parameters_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, char *etag,
+ const uint8_t *response_payload, struct pldm_msg *msg)
+{
+ if ((msg == NULL) || (operation_execution_flags == NULL) ||
+ (permission_flags == NULL) || (etag == 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_SUPPLY_CUSTOM_REQUEST_PARAMETERS;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+ struct pldm_supply_custom_request_parameters_resp *response =
+ (struct pldm_supply_custom_request_parameters_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;
+ resp_etag->string_length_bytes = strlen(etag) + 1;
+ 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) +
+ resp_etag->string_length_bytes - 1, (uint8_t *)response_payload, response_payload_length);
+ }
+ return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_supply_custom_request_parameters_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,
+ "Unsuccessful completion code received in op status: %x\n",
+ (uint8_t)(*completion_code));
+ 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_supply_custom_request_parameters_resp *response =
+ (struct pldm_supply_custom_request_parameters_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;
+
+ *resp_etag = (struct pldm_rde_varstring *)response->var_data;
+ if (*operation_status == PLDM_RDE_OPERATION_COMPLETED &&
+ (*operation_execution_flags)->bits.have_result_payload) {
+ *response_payload_length = le32toh(response->response_payload_length);
+ } else {
+ *response_payload_length = 0;
+ }
+
+ if ( *response_payload_length > 0 ) {
+ *response_payload = &(*resp_etag)->string_data[0] +
+ (*resp_etag)->string_length_bytes;
+ }
+ return 0;
+}
+
LIBPLDM_ABI_STABLE
int encode_rde_operation_complete_req(uint8_t instance_id, uint32_t resource_id,
uint16_t operation_id,
diff --git a/src/requester/pldm_rde_requester.c b/src/requester/pldm_rde_requester.c
index c7e1705..ef36a66 100644
--- a/src/requester/pldm_rde_requester.c
+++ b/src/requester/pldm_rde_requester.c
@@ -348,9 +348,10 @@ LIBPLDM_ABI_STABLE
pldm_rde_requester_rc_t pldm_rde_init_rde_operation_context(
struct pldm_rde_requester_context *ctx, uint8_t request_id,
uint32_t resource_id, uint16_t operation_id, uint8_t operation_type,
- uint8_t op_flags_byte, uint32_t send_data_transfer_handle,
- uint8_t operation_locator_length, uint32_t request_payload_length,
- uint8_t *operation_locator, uint8_t *request_payload)
+ uint8_t op_flags_byte, struct rde_query_options *query_options,
+ 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 (ctx == NULL || ctx->context_status == CONTEXT_BUSY) {
return PLDM_RDE_CONTEXT_INITIALIZATION_ERROR;
@@ -382,6 +383,27 @@ pldm_rde_requester_rc_t pldm_rde_init_rde_operation_context(
if (request_payload != NULL) {
operation->request_payload = request_payload;
}
+ operation->query_options = NULL;
+ if (operation->operation_flags.bits.contains_custom_request_parameters &&
+ query_options && query_options->expand == true) {
+ // This is freed in free_rde_op_init_context in all success/error
+ // conditions
+ operation->query_options =
+ (struct rde_query_options *) malloc(sizeof(struct rde_query_options));
+ operation->query_options->expand = true;
+ operation->query_options->skip_param = query_options->skip_param;
+ operation->query_options->top_param = query_options->top_param;
+ operation->query_options->etag_count = query_options->etag_count;
+ operation->query_options->header_count = query_options->header_count;
+ for (uint8_t i = 0; i < query_options->etag_count; i++) {
+ operation->query_options->etags[i] = query_options->etags[i];
+ }
+ for (uint8_t i = 0; i < query_options->header_count; i++) {
+ operation->query_options->hdrnames[i] = query_options->hdrnames[i];
+ operation->query_options->hdrparams[i] = query_options->hdrparams[i];
+ }
+ operation->query_options->expand_levels = query_options->expand_levels;
+ }
ctx->operation_ctx = operation;
ctx->requester_status = PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
return PLDM_RDE_REQUESTER_SUCCESS;
@@ -422,6 +444,50 @@ pldm_rde_get_next_rde_operation(uint8_t instance_id,
operation_ctx->request_payload, request);
break;
}
+ case PLDM_SUPPLY_CUSTOM_REQUEST_PARAMETERS: {
+ if(operation_ctx->operation_flags.bits.contains_custom_request_parameters) {
+ if (operation_ctx->query_options->expand) {
+
+ rc = encode_supply_custom_request_parameters_req(
+ instance_id, operation_ctx->resource_id,
+ operation_ctx->operation_id,
+ operation_ctx->query_options->expand_levels,
+ operation_ctx->query_options->skip_param,
+ operation_ctx->query_options->top_param,
+ 0, request);
+ if (rc != PLDM_SUCCESS)
+ {
+ fprintf(stderr, "Encoding of suppy custom req failed : %u\n", rc);
+ return rc;
+ }
+
+ uint8_t offset = 0;
+ rc = encode_etags_in_supply_custom_request_parameters_req (
+ operation_ctx->query_options->etag_operation,
+ operation_ctx->query_options->etag_count,
+ operation_ctx->query_options->etag_formats,
+ operation_ctx->query_options->etags, &offset, request);
+ if (rc != PLDM_SUCCESS)
+ {
+ fprintf(stderr, "Encoding of suppy custom req failed : %u\n", rc);
+ return rc;
+ }
+
+ rc = encode_headers_in_supply_custom_request_parameters_req (
+ operation_ctx->query_options->header_count,
+ operation_ctx->query_options->hdrname_formats,
+ operation_ctx->query_options->hdrnames,
+ operation_ctx->query_options->hdrparam_formats,
+ operation_ctx->query_options->hdrparams, &offset, request);
+ if (rc != PLDM_SUCCESS)
+ {
+ fprintf(stderr, "Encoding of suppy custom req failed : %u\n", rc);
+ return rc;
+ }
+ }
+ }
+ break;
+ }
case PLDM_RDE_OPERATION_STATUS: {
rc = encode_rde_operation_status_req(
instance_id, operation_ctx->resource_id,
@@ -455,6 +521,18 @@ int set_next_rde_operation(struct pldm_rde_requester_manager **manager,
int rc = PLDM_RDE_REQUESTER_SUCCESS;
switch (operation_ctx->operation_status) {
+ case PLDM_RDE_OPERATION_NEEDS_INPUT: {
+ if (operation_ctx->operation_flags.bits.contains_custom_request_parameters)
+ {
+ ctx->next_command = PLDM_SUPPLY_CUSTOM_REQUEST_PARAMETERS;
+ } else {
+ ctx->next_command = PLDM_RDE_MULTIPART_SEND;
+ }
+ ctx->context_status = CONTEXT_CONTINUE;
+ ctx->requester_status =
+ PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
+ break;
+ }
case PLDM_RDE_OPERATION_RUNNING: {
ctx->next_command = PLDM_RDE_OPERATION_STATUS;
ctx->context_status = CONTEXT_CONTINUE;
@@ -558,6 +636,42 @@ pldm_rde_requester_rc_t pldm_rde_push_read_operation_response(
PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
return PLDM_RDE_REQUESTER_SUCCESS;
}
+ case PLDM_SUPPLY_CUSTOM_REQUEST_PARAMETERS: {
+ uint8_t completion_code;
+ rc = decode_supply_custom_request_parameters_resp(
+ resp_msg, resp_size - sizeof(struct pldm_msg_hdr),
+ &completion_code, &(operation_ctx->percentage_complete),
+ &(operation_ctx->operation_status),
+ &(operation_ctx->completion_time),
+ &(operation_ctx->result_transfer_handle),
+ &(operation_ctx->resp_payload_length),
+ &(operation_ctx->resp_permission_flags),
+ &(operation_ctx->resp_operation_flags),
+ &(operation_ctx->resp_etag),
+ &(operation_ctx->response_data));
+
+ if (rc || completion_code) {
+ // If operation init failed, then there is not need to
+ // send the rest of the requests for the resource.
+ ctx->requester_status =
+ PLDM_RDE_REQUESTER_REQUEST_FAILED;
+ ctx->next_command =
+ PLDM_RDE_REQUESTER_NO_NEXT_COMMAND_FOUND;
+ ctx->context_status = CONTEXT_FREE;
+ break;
+ }
+
+ rc = set_next_rde_operation(&manager, ctx, callback);
+
+ if (rc) {
+ ctx->requester_status =
+ PLDM_RDE_REQUESTER_REQUEST_FAILED;
+ ctx->next_command = PLDM_RDE_OPERATION_COMPLETE;
+ }
+ ctx->requester_status =
+ PLDM_RDE_REQUESTER_READY_TO_PICK_NEXT_REQUEST;
+ return PLDM_RDE_REQUESTER_SUCCESS;
+ }
case PLDM_RDE_OPERATION_STATUS: {
// Same as operation init
uint8_t completion_code;
@@ -664,6 +778,11 @@ free_rde_op_init_context(struct pldm_rde_requester_context *ctx)
operation->resp_operation_flags = NULL;
}
+ if (operation->query_options != NULL) {
+ free(operation->query_options);
+ operation->query_options = NULL;
+ }
+
free(operation);
ctx->operation_ctx = NULL;
}
diff --git a/tests/libpldm_rde_test.cpp b/tests/libpldm_rde_test.cpp
index ed4625e..2f4416b 100644
--- a/tests/libpldm_rde_test.cpp
+++ b/tests/libpldm_rde_test.cpp
@@ -1158,3 +1158,178 @@ TEST(RDEOperationEnumerate, DecodeResponse)
EXPECT_EQ(respPayload2->completion_code, PLDM_ERROR);
EXPECT_EQ(respPayload2->operation_count, 0);
}
+
+TEST(SupplyCustomRequestParameters, EncodeRequestSuccess)
+{
+ uint32_t resource_id = 0x0001001;
+ uint8_t instance_id = 12;
+ uint16_t operation_id = 32770;
+ uint16_t link_expand = 0x01;
+ uint16_t collection_skip = 0x02;
+ uint16_t collection_top = 0x03;
+ uint16_t pagination_offset = 0x4;
+
+
+ pldm_rde_etag_operation etag_operation = PLDM_RDE_ETAG_IF_NONE_MATCH;
+ uint8_t etag_count = 1;
+ enum pldm_rde_varstring_format etag_formats[1] = { PLDM_RDE_VARSTRING_UTF_8};
+ char etag1[6] = "etag1";
+ char *etags[1] = { etag1 };
+
+ uint8_t header_count = 1 ;
+ enum pldm_rde_varstring_format hdrname_formats[1] = { PLDM_RDE_VARSTRING_UTF_8 };
+ char *hdrnames[1] = { PLDM_RDE_EXPAND_TYPE };
+ enum pldm_rde_varstring_format hdrparam_formats[1] = { PLDM_RDE_VARSTRING_UTF_8 };
+ char *hdrparams[1] = { EXPAND_DOT };
+
+ constexpr size_t requestSize =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_supply_custom_request_parameters_req) + 43;
+
+ std::array<uint8_t, requestSize> requestMsg{};
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+ EXPECT_EQ(encode_supply_custom_request_parameters_req(
+ instance_id, resource_id, operation_id, link_expand,
+ collection_skip, collection_top, pagination_offset, request),
+ PLDM_SUCCESS);
+
+ uint8_t encode_offset = 0;
+ EXPECT_EQ(encode_etags_in_supply_custom_request_parameters_req(
+ etag_operation, etag_count, etag_formats, etags,
+ &encode_offset, request),
+ PLDM_SUCCESS);
+
+
+ EXPECT_EQ(encode_headers_in_supply_custom_request_parameters_req(
+ header_count, hdrname_formats, hdrnames, hdrparam_formats,
+ hdrparams, &encode_offset, request),
+ PLDM_SUCCESS);
+ // Test Header values
+ EXPECT_EQ(request->hdr.instance_id, instance_id);
+ EXPECT_EQ(request->hdr.request, PLDM_REQUEST);
+ EXPECT_EQ(request->hdr.type, PLDM_RDE);
+ EXPECT_EQ(request->hdr.command, PLDM_SUPPLY_CUSTOM_REQUEST_PARAMETERS);
+
+ // Test payload values
+ auto reqPayload =
+ reinterpret_cast<pldm_supply_custom_request_parameters_req*>(
+ request->payload);
+ EXPECT_EQ(reqPayload->resource_id, resource_id);
+ EXPECT_EQ(reqPayload->operation_id, operation_id);
+ EXPECT_EQ(reqPayload->link_expand, link_expand);
+ EXPECT_EQ(reqPayload->collection_skip, collection_skip);
+ EXPECT_EQ(reqPayload->collection_top, collection_top);
+ EXPECT_EQ(reqPayload->pagination_offset, pagination_offset);
+ EXPECT_EQ(reqPayload->etag_operation, PLDM_RDE_ETAG_IF_NONE_MATCH);
+ EXPECT_EQ(reqPayload->etag_count, etag_count);
+
+
+ int offset = 0;
+ for (uint8_t i = 0; i < etag_count; i++)
+ {
+ EXPECT_EQ(reqPayload->var_data[offset++], etag_formats[i]);
+ size_t len = strlen(etags[i]) + 1;
+ EXPECT_EQ(reqPayload->var_data[offset++], len);
+ EXPECT_EQ(0, memcmp(reqPayload->var_data + offset,
+ etags[i], len));
+ offset += len;
+ }
+
+ EXPECT_EQ(reqPayload->var_data[offset++], header_count);
+ for (uint8_t i = 0; i < header_count; i++)
+ {
+ EXPECT_EQ(reqPayload->var_data[offset++], hdrname_formats[i]);
+ size_t len = strlen(hdrnames[i]) + 1;
+ EXPECT_EQ(reqPayload->var_data[offset++], len);
+ EXPECT_EQ(0, memcmp(reqPayload->var_data + offset,
+ hdrnames[i], len));
+ offset += len;
+ }
+
+ for (uint8_t i = 0; i < header_count; i++)
+ {
+ EXPECT_EQ(reqPayload->var_data[offset++], hdrparam_formats[i]);
+ size_t len = strlen(hdrparams[i]) + 1;
+ EXPECT_EQ(reqPayload->var_data[offset++], len);
+ EXPECT_EQ(0, memcmp(reqPayload->var_data + offset,
+ hdrparams[i], len));
+ offset += len;
+ }
+}
+
+TEST(SupplyCustomRequestParameters, 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 = 0x04;
+ uint32_t resultTransferHandle = 0x01;
+ union pldm_rde_permission_flags permissionFlags;
+ permissionFlags.byte = 0x02;
+ const uint32_t responsePayloadLength = 12;
+ const uint8_t* varPayload = (const uint8_t*)"TEST_PAYLOAD";
+
+ // Encode
+ enum pldm_rde_varstring_format etag_format = PLDM_RDE_VARSTRING_UTF_8;
+ char etag1[6] = "etag1";
+
+ constexpr size_t responseLength =
+ sizeof(struct pldm_msg_hdr) +
+ sizeof(struct pldm_supply_custom_request_parameters_resp) + 8 +
+ responsePayloadLength;
+ std::array<uint8_t, responseLength> responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ EXPECT_EQ(encode_supply_custom_request_parameters_resp(
+ instanceId, completionCode, operationStatus,
+ completionPercentage, completionTimeSeconds,
+ &operationExecutionFlags, resultTransferHandle,
+ &permissionFlags, responsePayloadLength, etag_format, etag1, varPayload,
+ response),
+ PLDM_SUCCESS);
+
+ // Decode
+ 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));
+
+ struct pldm_rde_varstring* returnEtag =
+ (pldm_rde_varstring*)malloc(sizeof(struct pldm_rde_varstring) + 6);
+ // auto returnEtag = std::make_unique<pldm_rde_varstring>().get();
+ auto responsePayload = std::make_unique<uint8_t>().get();
+ EXPECT_EQ(decode_supply_custom_request_parameters_resp(
+ response, responseLength, &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, responsePayloadLength);
+ EXPECT_EQ(returnPermissionFlags->byte, permissionFlags.byte);
+ EXPECT_EQ(returnExecutionFlags->byte, operationExecutionFlags.byte);
+ EXPECT_EQ(returnEtag->string_format, etag_format);
+ EXPECT_EQ(returnEtag->string_length_bytes, strlen(etag1) + 1);
+ EXPECT_EQ(0, memcmp(returnEtag->string_data, etag1,
+ strlen(etag1) + 1));
+ EXPECT_EQ(0, memcmp(responsePayload, varPayload, responsePayloadLength));
+}
+
diff --git a/tests/requester/rde_requester_test.cpp b/tests/requester/rde_requester_test.cpp
index 033fa65..d929be6 100644
--- a/tests/requester/rde_requester_test.cpp
+++ b/tests/requester/rde_requester_test.cpp
@@ -394,9 +394,7 @@ TEST_F(TestRdeRequester, PushDiscoveryResponseRedfishMediumParamSuccess)
/*device_maximum_transfer_bytes*/ 256, responsePtr);
EXPECT_EQ(rc, 0);
- manager->device = (struct pldm_rde_device_info*)malloc(
- sizeof(struct pldm_rde_device_info));
- manager->device->device_maximum_transfer_chunk_size = 256;
+ manager->device.device_maximum_transfer_chunk_size = 256;
manager->mc_transfer_size = 256;
rc = pldm_rde_discovery_push_response(manager, base_context, responsePtr,
responseMsgSize);
@@ -409,7 +407,7 @@ TEST_F(TestRdeRequester, PushDiscoveryResponseFailure)
{
struct pldm_rde_requester_manager* manager =
new pldm_rde_requester_manager();
-
+
int rc = pldm_rde_init_context(devId.c_str(), netId, manager,
mcConcurrency, mcTransferSize, &mcFeatures,
numberOfResources, &resourceIds.front(),
@@ -648,9 +646,11 @@ TEST_F(TestRdeRequester, InitRDEOperationContextSuccess)
new pldm_rde_requester_context();
rc = pldm_rde_create_context(base_context);
+ struct rde_query_options *query_options = NULL;
+
rc = pldm_rde_init_rde_operation_context(
base_context, requestId, resourceId, opId, PLDM_RDE_OPERATION_READ,
- flags, sendTransferHandle, opLocLength, payloadLength, &opLoc,
+ flags, query_options, sendTransferHandle, opLocLength, payloadLength, &opLoc,
&reqPtr);
EXPECT_EQ(rc, PLDM_RDE_REQUESTER_SUCCESS);
@@ -675,9 +675,10 @@ TEST_F(TestRdeRequester, InitRDEOperationContextFailure)
rc = pldm_rde_create_context(base_context);
base_context->context_status = CONTEXT_BUSY;
+ struct rde_query_options *query_options = NULL;
rc = pldm_rde_init_rde_operation_context(
base_context, requestId, resourceId, opId, PLDM_RDE_OPERATION_READ,
- flags, sendTransferHandle, opLocLength, payloadLength, &opLoc,
+ flags, query_options, sendTransferHandle, opLocLength, payloadLength, &opLoc,
&reqPtr);
EXPECT_EQ(rc, PLDM_RDE_CONTEXT_INITIALIZATION_ERROR);
@@ -695,10 +696,10 @@ TEST_F(TestRdeRequester, GetNextRDEOperationSuccess)
struct pldm_rde_requester_context* base_context =
new pldm_rde_requester_context();
rc = pldm_rde_create_context(base_context);
-
+ struct rde_query_options *query_options = NULL;
rc = pldm_rde_init_rde_operation_context(
base_context, requestId, resourceId, opId, PLDM_RDE_OPERATION_READ,
- flags, sendTransferHandle, opLocLength, payloadLength, &opLoc,
+ flags, query_options, sendTransferHandle, opLocLength, payloadLength, &opLoc,
&reqPtr);
size_t requestBytes = 256;
@@ -735,10 +736,10 @@ TEST_F(TestRdeRequester, GetNextRDEOperationFailure)
struct pldm_rde_requester_context* base_context =
new pldm_rde_requester_context();
rc = pldm_rde_create_context(base_context);
-
+ struct rde_query_options *query_options = NULL;
rc = pldm_rde_init_rde_operation_context(
base_context, requestId, resourceId, opId, PLDM_RDE_OPERATION_READ,
- flags, sendTransferHandle, opLocLength, payloadLength, &opLoc,
+ flags, query_options, sendTransferHandle, opLocLength, payloadLength, &opLoc,
&reqPtr);
size_t requestBytes = 256;
--
2.46.1.824.gd892dcdcdd-goog