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 18 : 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 : const spdm_chunk_get_request_14_t* spdm_request_14;
24 : spdm_chunk_response_response_t* spdm_response;
25 : spdm_chunk_response_response_14_t* spdm_response_14;
26 : uint32_t chunk_seq_no;
27 :
28 : uint8_t* spdm_chunk;
29 :
30 18 : spdm_request = (const spdm_chunk_get_request_t*) request;
31 18 : spdm_response = (spdm_chunk_response_response_t*) response;
32 18 : get_info = &spdm_context->chunk_context.get;
33 :
34 18 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) {
35 0 : return libspdm_generate_error_response(spdm_context,
36 : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
37 : SPDM_CHUNK_GET,
38 : response_size, response);
39 : }
40 :
41 18 : if (!libspdm_is_capabilities_flag_supported(
42 : spdm_context, false, SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
43 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
44 1 : return libspdm_generate_error_response(
45 : spdm_context,
46 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
47 : response_size, response);
48 : }
49 :
50 : /*chunk mechanism can be used for normal or encap state*/
51 17 : if ((spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) &&
52 1 : (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_PROCESSING_ENCAP)) {
53 1 : return libspdm_responder_handle_response_state(
54 : spdm_context,
55 1 : spdm_request->header.request_response_code,
56 : response_size, response);
57 : }
58 :
59 16 : if (spdm_context->connection_info.connection_state <
60 : LIBSPDM_CONNECTION_STATE_AFTER_CAPABILITIES) {
61 1 : return libspdm_generate_error_response(
62 : spdm_context,
63 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
64 : response_size, response);
65 : }
66 :
67 15 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
68 11 : if (request_size < sizeof(spdm_chunk_get_request_t)) {
69 1 : return libspdm_generate_error_response(
70 : spdm_context,
71 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
72 : response_size, response);
73 : }
74 : } else {
75 4 : if (request_size < sizeof(spdm_chunk_get_request_14_t)) {
76 0 : return libspdm_generate_error_response(
77 : spdm_context,
78 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
79 : response_size, response);
80 : }
81 : }
82 :
83 14 : if (spdm_request->header.spdm_version < SPDM_MESSAGE_VERSION_12) {
84 1 : return libspdm_generate_error_response(
85 : spdm_context,
86 : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST, SPDM_CHUNK_GET,
87 : response_size, response);
88 : }
89 :
90 13 : if (spdm_request->header.spdm_version
91 13 : != libspdm_get_connection_version(spdm_context)) {
92 0 : return libspdm_generate_error_response(
93 : spdm_context,
94 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
95 : response_size, response);
96 : }
97 :
98 13 : if (get_info->chunk_in_use == false) {
99 1 : return libspdm_generate_error_response(
100 : spdm_context,
101 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
102 : response_size, response);
103 : }
104 :
105 12 : if (spdm_request->header.param2 != get_info->chunk_handle) {
106 1 : return libspdm_generate_error_response(
107 : spdm_context,
108 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
109 : response_size, response);
110 : }
111 :
112 11 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
113 7 : if (spdm_request->chunk_seq_no != (uint16_t) get_info->chunk_seq_no) {
114 2 : return libspdm_generate_error_response(
115 : spdm_context,
116 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
117 : response_size, response);
118 : }
119 5 : chunk_seq_no = spdm_request->chunk_seq_no;
120 : } else {
121 4 : spdm_request_14 = (const spdm_chunk_get_request_14_t*) request;
122 4 : if (spdm_request_14->chunk_seq_no != get_info->chunk_seq_no) {
123 0 : return libspdm_generate_error_response(
124 : spdm_context,
125 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
126 : response_size, response);
127 : }
128 4 : chunk_seq_no = spdm_request_14->chunk_seq_no;
129 : }
130 :
131 9 : min_data_transfer_size = LIBSPDM_MIN(
132 : spdm_context->connection_info.capability.data_transfer_size,
133 : spdm_context->local_context.capability.sender_data_transfer_size);
134 :
135 9 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
136 : /* chunk seq no wrap not considered in spdm 1.4+ */
137 :
138 : /* Fail if exceed max chunks */
139 5 : max_chunk_data_transfer_size =
140 5 : ((size_t) min_data_transfer_size - sizeof(spdm_chunk_response_response_t)) * 65536 -
141 : sizeof(uint32_t);
142 :
143 : /* max_spdm_msg_size already checked in caller */
144 5 : if (get_info->large_message_size > max_chunk_data_transfer_size) {
145 1 : return libspdm_generate_error_response(
146 : spdm_context,
147 : SPDM_ERROR_CODE_RESPONSE_TOO_LARGE, 0,
148 : response_size, response);
149 : }
150 : }
151 :
152 8 : libspdm_zero_mem(response, *response_size);
153 :
154 : /* Assert the data transfer size is smaller than the response size.
155 : * Otherwise there is no reason to chunk this response. */
156 8 : LIBSPDM_ASSERT(min_data_transfer_size < *response_size);
157 :
158 8 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
159 8 : spdm_response->header.request_response_code = SPDM_CHUNK_RESPONSE;
160 8 : spdm_response->header.param1 = 0;
161 8 : spdm_response->header.param2 = get_info->chunk_handle;
162 8 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
163 4 : spdm_response->chunk_seq_no = (uint16_t) get_info->chunk_seq_no;
164 : } else {
165 4 : spdm_response_14 = (spdm_chunk_response_response_14_t*) response;
166 4 : spdm_response_14->chunk_seq_no = get_info->chunk_seq_no;
167 : }
168 :
169 : LIBSPDM_ASSERT(sizeof(spdm_chunk_response_response_t) == sizeof(spdm_chunk_response_response_14_t));
170 :
171 8 : if (chunk_seq_no == 0) {
172 2 : spdm_response->chunk_size =
173 : min_data_transfer_size
174 : - sizeof(spdm_chunk_response_response_t)
175 2 : - sizeof(uint32_t);
176 :
177 : /* No reason to do chunking if message is smaller than largest chunk size. */
178 2 : LIBSPDM_ASSERT(spdm_response->chunk_size < get_info->large_message_size);
179 :
180 2 : spdm_chunk = (uint8_t*) (spdm_response + 1);
181 :
182 : /* Set LargeMessageSize only in first chunk. */
183 2 : *((uint32_t*) (spdm_chunk)) = (uint32_t)get_info->large_message_size;
184 2 : spdm_chunk += sizeof(uint32_t);
185 :
186 2 : *response_size = sizeof(spdm_chunk_response_response_t)
187 : + sizeof(uint32_t)
188 2 : + spdm_response->chunk_size;
189 : } else {
190 6 : spdm_response->chunk_size =
191 6 : LIBSPDM_MIN(min_data_transfer_size
192 : - sizeof(spdm_chunk_response_response_t),
193 : (uint32_t) (get_info->large_message_size
194 : - get_info->chunk_bytes_transferred));
195 :
196 6 : spdm_chunk = (uint8_t*) (spdm_response + 1);
197 :
198 6 : *response_size = sizeof(spdm_chunk_response_response_t)
199 6 : + spdm_response->chunk_size;
200 : }
201 :
202 8 : libspdm_copy_mem(spdm_chunk, spdm_response->chunk_size,
203 8 : (uint8_t*) get_info->large_message + get_info->chunk_bytes_transferred,
204 8 : spdm_response->chunk_size);
205 :
206 8 : get_info->chunk_seq_no++;
207 8 : get_info->chunk_bytes_transferred += spdm_response->chunk_size;
208 :
209 8 : LIBSPDM_ASSERT(get_info->chunk_bytes_transferred <= get_info->large_message_size);
210 8 : if (get_info->chunk_bytes_transferred == get_info->large_message_size) {
211 4 : get_info->chunk_in_use = false;
212 4 : get_info->chunk_handle++; /* implicit wrap - around to 0. */
213 4 : get_info->chunk_seq_no = 0;
214 4 : get_info->large_message = NULL;
215 4 : get_info->large_message_size = 0;
216 4 : get_info->chunk_bytes_transferred = 0;
217 :
218 4 : spdm_response->header.param1 |= SPDM_CHUNK_GET_RESPONSE_ATTRIBUTE_LAST_CHUNK;
219 : }
220 :
221 8 : return LIBSPDM_STATUS_SUCCESS;
222 : }
223 :
224 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
|