Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2025 DMTF. All rights reserved.
4 : * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
5 : **/
6 :
7 : #include "internal/libspdm_responder_lib.h"
8 :
9 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
10 :
11 14 : libspdm_return_t libspdm_get_response_chunk_get(
12 : libspdm_context_t *spdm_context,
13 : size_t request_size,
14 : const void* request,
15 : size_t* response_size,
16 : void* response)
17 : {
18 : libspdm_chunk_info_t* get_info;
19 : uint32_t min_data_transfer_size;
20 : uint64_t max_chunk_data_transfer_size;
21 :
22 : const spdm_chunk_get_request_t* spdm_request;
23 : spdm_chunk_response_response_t* spdm_response;
24 :
25 : uint8_t* spdm_chunk;
26 :
27 14 : spdm_request = (const spdm_chunk_get_request_t*) request;
28 14 : spdm_response = (spdm_chunk_response_response_t*) response;
29 14 : get_info = &spdm_context->chunk_context.get;
30 :
31 14 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) {
32 0 : return libspdm_generate_error_response(spdm_context,
33 : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
34 : SPDM_CHUNK_GET,
35 : response_size, response);
36 : }
37 :
38 14 : if (!libspdm_is_capabilities_flag_supported(
39 : spdm_context, false, SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
40 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
41 1 : return libspdm_generate_error_response(
42 : spdm_context,
43 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
44 : response_size, response);
45 : }
46 :
47 : /*chunk mechanism can be used for normal or encap state*/
48 13 : if ((spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) &&
49 1 : (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_PROCESSING_ENCAP)) {
50 1 : return libspdm_responder_handle_response_state(
51 : spdm_context,
52 1 : spdm_request->header.request_response_code,
53 : response_size, response);
54 : }
55 :
56 12 : if (spdm_context->connection_info.connection_state <
57 : LIBSPDM_CONNECTION_STATE_AFTER_CAPABILITIES) {
58 1 : return libspdm_generate_error_response(
59 : spdm_context,
60 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
61 : response_size, response);
62 : }
63 :
64 11 : if (request_size < sizeof(spdm_chunk_get_request_t)) {
65 1 : return libspdm_generate_error_response(
66 : spdm_context,
67 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
68 : response_size, response);
69 : }
70 :
71 10 : if (spdm_request->header.spdm_version < SPDM_MESSAGE_VERSION_12) {
72 1 : return libspdm_generate_error_response(
73 : spdm_context,
74 : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST, SPDM_CHUNK_GET,
75 : response_size, response);
76 : }
77 :
78 9 : if (spdm_request->header.spdm_version
79 9 : != libspdm_get_connection_version(spdm_context)) {
80 0 : return libspdm_generate_error_response(
81 : spdm_context,
82 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
83 : response_size, response);
84 : }
85 :
86 9 : if (get_info->chunk_in_use == false) {
87 1 : return libspdm_generate_error_response(
88 : spdm_context,
89 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
90 : response_size, response);
91 : }
92 :
93 8 : if (spdm_request->header.param2 != get_info->chunk_handle) {
94 1 : return libspdm_generate_error_response(
95 : spdm_context,
96 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
97 : response_size, response);
98 : }
99 :
100 7 : if (spdm_request->chunk_seq_no != get_info->chunk_seq_no) {
101 2 : return libspdm_generate_error_response(
102 : spdm_context,
103 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
104 : response_size, response);
105 : }
106 :
107 5 : min_data_transfer_size = LIBSPDM_MIN(
108 : spdm_context->connection_info.capability.data_transfer_size,
109 : spdm_context->local_context.capability.sender_data_transfer_size);
110 :
111 : /* Fail if exceed max chunks */
112 5 : max_chunk_data_transfer_size =
113 5 : ((size_t) min_data_transfer_size - sizeof(spdm_chunk_response_response_t)) * 65536 -
114 : sizeof(uint32_t);
115 : /* max_spdm_msg_size already checked in caller */
116 :
117 5 : if (get_info->large_message_size > max_chunk_data_transfer_size) {
118 1 : return libspdm_generate_error_response(
119 : spdm_context,
120 : SPDM_ERROR_CODE_RESPONSE_TOO_LARGE, 0,
121 : response_size, response);
122 : }
123 :
124 4 : libspdm_zero_mem(response, *response_size);
125 :
126 : /* Assert the data transfer size is smaller than the response size.
127 : * Otherwise there is no reason to chunk this response. */
128 4 : LIBSPDM_ASSERT(min_data_transfer_size < *response_size);
129 :
130 4 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
131 4 : spdm_response->header.request_response_code = SPDM_CHUNK_RESPONSE;
132 4 : spdm_response->header.param1 = 0;
133 4 : spdm_response->header.param2 = get_info->chunk_handle;
134 4 : spdm_response->chunk_seq_no = get_info->chunk_seq_no;
135 :
136 4 : if (spdm_request->chunk_seq_no == 0) {
137 1 : spdm_response->chunk_size =
138 : min_data_transfer_size
139 : - sizeof(spdm_chunk_response_response_t)
140 1 : - sizeof(uint32_t);
141 :
142 : /* No reason to do chunking if message is smaller than largest chunk size. */
143 1 : LIBSPDM_ASSERT(spdm_response->chunk_size < get_info->large_message_size);
144 :
145 1 : spdm_chunk = (uint8_t*) (spdm_response + 1);
146 :
147 : /* Set LargeMessageSize only in first chunk. */
148 1 : *((uint32_t*) (spdm_chunk)) = (uint32_t)get_info->large_message_size;
149 1 : spdm_chunk += sizeof(uint32_t);
150 :
151 1 : *response_size = sizeof(spdm_chunk_response_response_t)
152 : + sizeof(uint32_t)
153 1 : + spdm_response->chunk_size;
154 : } else {
155 3 : spdm_response->chunk_size =
156 3 : LIBSPDM_MIN(min_data_transfer_size
157 : - sizeof(spdm_chunk_response_response_t),
158 : (uint32_t) (get_info->large_message_size
159 : - get_info->chunk_bytes_transferred));
160 :
161 3 : spdm_chunk = (uint8_t*) (spdm_response + 1);
162 :
163 3 : *response_size = sizeof(spdm_chunk_response_response_t)
164 3 : + spdm_response->chunk_size;
165 : }
166 :
167 4 : libspdm_copy_mem(spdm_chunk, spdm_response->chunk_size,
168 4 : (uint8_t*) get_info->large_message + get_info->chunk_bytes_transferred,
169 4 : spdm_response->chunk_size);
170 :
171 4 : get_info->chunk_seq_no++;
172 4 : get_info->chunk_bytes_transferred += spdm_response->chunk_size;
173 :
174 4 : LIBSPDM_ASSERT(get_info->chunk_bytes_transferred <= get_info->large_message_size);
175 4 : if (get_info->chunk_bytes_transferred == get_info->large_message_size) {
176 2 : get_info->chunk_in_use = false;
177 2 : get_info->chunk_handle++; /* implicit wrap - around to 0. */
178 2 : get_info->chunk_seq_no = 0;
179 2 : get_info->large_message = NULL;
180 2 : get_info->large_message_size = 0;
181 2 : get_info->chunk_bytes_transferred = 0;
182 :
183 2 : spdm_response->header.param1 |= SPDM_CHUNK_GET_RESPONSE_ATTRIBUTE_LAST_CHUNK;
184 : }
185 :
186 4 : return LIBSPDM_STATUS_SUCCESS;
187 : }
188 :
189 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
|