Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2023-2024 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_requester_lib.h"
8 :
9 : #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
10 :
11 : #define SPDM_MAX_VENDOR_PAYLOAD_LEN (SPDM_MAX_VENDOR_ID_LENGTH + 2 + \
12 : SPDM_MAX_VENDOR_DEFINED_DATA_LEN)
13 :
14 : #pragma pack(1)
15 : typedef struct {
16 : spdm_message_header_t header;
17 : uint16_t standard_id;
18 : uint8_t vendor_id_len;
19 : uint8_t vendor_plus_request[SPDM_MAX_VENDOR_PAYLOAD_LEN];
20 : } libspdm_vendor_defined_response_msg_max_t;
21 : #pragma pack()
22 :
23 5 : libspdm_return_t libspdm_try_vendor_send_request_receive_response(
24 : libspdm_context_t *spdm_context,
25 : const uint32_t *session_id,
26 : uint16_t req_standard_id,
27 : uint8_t req_vendor_id_len,
28 : const void *req_vendor_id,
29 : uint16_t req_size,
30 : const void *req_data,
31 : uint16_t *resp_standard_id,
32 : uint8_t *resp_vendor_id_len,
33 : void *resp_vendor_id,
34 : uint16_t *resp_size,
35 : void *resp_data)
36 : {
37 : libspdm_return_t status;
38 : spdm_vendor_defined_request_msg_t *spdm_request;
39 : size_t spdm_request_size;
40 : libspdm_vendor_defined_response_msg_max_t *spdm_response;
41 : size_t spdm_response_size;
42 : uint8_t *message;
43 5 : size_t message_size = 0;
44 : size_t transport_header_size;
45 5 : size_t max_payload = 0;
46 5 : uint8_t* vendor_request = NULL;
47 5 : uint8_t *response_ptr = NULL;
48 5 : uint16_t response_size = 0;
49 :
50 : /* -=[Check Parameters Phase]=- */
51 5 : if (spdm_context == NULL ||
52 5 : (req_size != 0 && req_data == NULL) ||
53 5 : resp_standard_id == NULL ||
54 5 : resp_vendor_id_len == NULL ||
55 5 : resp_vendor_id == NULL ||
56 5 : resp_size == NULL ||
57 5 : (*resp_size != 0 && resp_data == NULL)
58 : ) {
59 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
60 : }
61 :
62 5 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
63 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
64 : }
65 :
66 5 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
67 :
68 : /* -=[Construct Request Phase]=- */
69 5 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
70 5 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
71 0 : return status;
72 : }
73 :
74 : /* calculate useful payload the sender buffer can hold after
75 : * removing all protocol, spdm and vendor defined message headers
76 : * -3 bytes is for the standard_id and vendor_id_len fields in the vendor header
77 : * -2 bytes is for the payload length field */
78 5 : max_payload = message_size - transport_header_size -
79 5 : spdm_context->local_context.capability.transport_tail_size
80 5 : - sizeof(spdm_request->header) - 3 - req_vendor_id_len - 2;
81 :
82 5 : LIBSPDM_ASSERT (message_size >= transport_header_size +
83 : spdm_context->local_context.capability.transport_tail_size);
84 :
85 : /* do not accept requests exceeding maximum allowed payload */
86 5 : if ((size_t)req_size > max_payload) {
87 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
88 : }
89 :
90 5 : spdm_request = (void *)(message + transport_header_size);
91 5 : spdm_request_size = message_size - transport_header_size -
92 5 : spdm_context->local_context.capability.transport_tail_size;
93 :
94 5 : LIBSPDM_ASSERT(spdm_request_size >= sizeof(spdm_vendor_defined_request_msg_t) +
95 : req_vendor_id_len + sizeof(uint16_t) + req_size);
96 5 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
97 5 : spdm_request->header.request_response_code = SPDM_VENDOR_DEFINED_REQUEST;
98 5 : spdm_request->header.param1 = 0;
99 5 : spdm_request->header.param2 = 0;
100 : /* Message header here */
101 5 : spdm_request->standard_id = req_standard_id;
102 5 : spdm_request->len = req_vendor_id_len;
103 :
104 : /* Copy Vendor id */
105 5 : vendor_request = ((uint8_t *)spdm_request) + sizeof(spdm_vendor_defined_request_msg_t);
106 5 : if (req_vendor_id_len != 0) {
107 5 : libspdm_copy_mem(vendor_request, req_vendor_id_len, req_vendor_id, req_vendor_id_len);
108 5 : vendor_request += req_vendor_id_len;
109 : }
110 :
111 : /* Copy request_len */
112 5 : libspdm_copy_mem(vendor_request, sizeof(uint16_t), &req_size, sizeof(uint16_t));
113 5 : vendor_request += sizeof(uint16_t);
114 :
115 : /* Copy payload */
116 5 : if (req_size != 0) {
117 5 : libspdm_copy_mem(vendor_request, req_size, req_data, req_size);
118 : }
119 :
120 5 : spdm_request_size = sizeof(spdm_vendor_defined_request_msg_t) +
121 5 : req_vendor_id_len + sizeof(uint16_t) + req_size;
122 :
123 : /* -=[Send Request Phase]=- */
124 : status =
125 5 : libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
126 5 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
127 1 : libspdm_release_sender_buffer (spdm_context);
128 1 : return LIBSPDM_STATUS_SEND_FAIL;
129 : }
130 4 : libspdm_release_sender_buffer (spdm_context);
131 4 : spdm_request = (void *)spdm_context->last_spdm_request;
132 :
133 : /* -=[Receive Response Phase]=- */
134 4 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
135 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
136 0 : return status;
137 : }
138 4 : LIBSPDM_ASSERT (message_size >= transport_header_size);
139 4 : spdm_response = (void *)(message);
140 4 : spdm_response_size = message_size;
141 :
142 4 : status = libspdm_receive_spdm_response(spdm_context, session_id,
143 : &spdm_response_size,
144 : (void **)&spdm_response);
145 :
146 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
147 3 : status = LIBSPDM_STATUS_RECEIVE_FAIL;
148 3 : goto done;
149 : }
150 :
151 : /* -=[Validate Response Phase]=- */
152 1 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
153 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
154 0 : goto done;
155 : }
156 1 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
157 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
158 0 : goto done;
159 : }
160 1 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
161 0 : status = libspdm_handle_error_response_main(
162 : spdm_context, session_id,
163 : &spdm_response_size,
164 : (void **)&spdm_response, SPDM_VENDOR_DEFINED_REQUEST,
165 : SPDM_VENDOR_DEFINED_RESPONSE);
166 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
167 0 : goto done;
168 : }
169 1 : } else if (spdm_response->header.request_response_code != SPDM_VENDOR_DEFINED_RESPONSE) {
170 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
171 0 : goto done;
172 : }
173 :
174 1 : if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t)) {
175 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
176 0 : goto done;
177 : }
178 : /* check response buffer size at least spdm response default header plus
179 : * number of bytes required by vendor id and 2 bytes for response payload size */
180 1 : if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t) +
181 1 : spdm_response->vendor_id_len + sizeof(uint16_t)) {
182 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
183 0 : goto done;
184 : }
185 :
186 1 : *resp_standard_id = spdm_response->standard_id;
187 1 : if (*resp_vendor_id_len < spdm_response->vendor_id_len) {
188 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
189 0 : goto done;
190 : }
191 1 : *resp_vendor_id_len = spdm_response->vendor_id_len;
192 1 : if ((*resp_vendor_id_len) != 0) {
193 1 : libspdm_copy_mem(resp_vendor_id, *resp_vendor_id_len, spdm_response->vendor_plus_request,
194 1 : *resp_vendor_id_len);
195 : }
196 :
197 : /* -=[Process Response Phase]=- */
198 1 : response_ptr = spdm_response->vendor_plus_request + spdm_response->vendor_id_len;
199 1 : response_size = *((uint16_t*)response_ptr);
200 1 : if (spdm_response_size < response_size +
201 1 : sizeof(spdm_vendor_defined_response_msg_t) +
202 1 : spdm_response->vendor_id_len + sizeof(uint16_t)) {
203 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
204 0 : goto done;
205 : }
206 1 : response_ptr += sizeof(uint16_t);
207 1 : if (*resp_size < response_size) {
208 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
209 0 : goto done;
210 : }
211 1 : libspdm_copy_mem(resp_data, *resp_size, response_ptr, response_size);
212 1 : *resp_size = response_size;
213 :
214 : /* -=[Log Message Phase]=- */
215 : #if LIBSPDM_ENABLE_MSG_LOG
216 1 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
217 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
218 :
219 1 : status = LIBSPDM_STATUS_SUCCESS;
220 4 : done:
221 4 : libspdm_release_receiver_buffer (spdm_context); /* this will free up response-message, need to find workaround */
222 4 : return status;
223 : }
224 :
225 5 : libspdm_return_t libspdm_vendor_send_request_receive_response(
226 : void *spdm_context,
227 : const uint32_t *session_id,
228 : uint16_t req_standard_id,
229 : uint8_t req_vendor_id_len,
230 : const void *req_vendor_id,
231 : uint16_t req_size,
232 : const void *req_data,
233 : uint16_t *resp_standard_id,
234 : uint8_t *resp_vendor_id_len,
235 : void *resp_vendor_id,
236 : uint16_t *resp_size,
237 : void *resp_data)
238 : {
239 : libspdm_context_t *context;
240 : size_t retry;
241 : uint64_t retry_delay_time;
242 : libspdm_return_t status;
243 :
244 5 : context = spdm_context;
245 5 : context->crypto_request = true;
246 5 : retry = context->retry_times;
247 5 : retry_delay_time = context->retry_delay_time;
248 : do {
249 5 : status = libspdm_try_vendor_send_request_receive_response(
250 : context,
251 : session_id,
252 : req_standard_id,
253 : req_vendor_id_len,
254 : req_vendor_id,
255 : req_size,
256 : req_data,
257 : resp_standard_id,
258 : resp_vendor_id_len,
259 : resp_vendor_id,
260 : resp_size,
261 : resp_data);
262 5 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
263 5 : return status;
264 : }
265 :
266 0 : libspdm_sleep(retry_delay_time);
267 0 : } while (retry-- != 0);
268 :
269 0 : return status;
270 : }
271 :
272 : #endif /* LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES */
|