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