| 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 |
| |