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_requester_lib.h"
8 :
9 : #if LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP
10 :
11 13 : void libspdm_register_get_encap_response_func(void *spdm_context,
12 : const libspdm_get_encap_response_func
13 : get_encap_response_func)
14 : {
15 : libspdm_context_t *context;
16 :
17 13 : context = spdm_context;
18 13 : context->get_encap_response_func = (void *)get_encap_response_func;
19 13 : }
20 :
21 : /**
22 : * Return the GET_ENCAP_RESPONSE function via request code.
23 : *
24 : * @param request_code The SPDM request code.
25 : *
26 : * @return GET_ENCAP_RESPONSE function according to the request code.
27 : **/
28 : static libspdm_get_encap_response_func
29 8 : libspdm_get_encap_response_func_via_request_code(uint8_t request_response_code)
30 : {
31 : typedef struct {
32 : uint8_t request_response_code;
33 : libspdm_get_encap_response_func get_encap_response_func;
34 : } libspdm_get_encap_response_struct_t;
35 :
36 : size_t index;
37 :
38 8 : libspdm_get_encap_response_struct_t get_encap_response_struct[] = {
39 : #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP
40 : #if LIBSPDM_ENABLE_CAPABILITY_CERT_CAP
41 : { SPDM_GET_DIGESTS, libspdm_get_encap_response_digest },
42 : { SPDM_GET_CERTIFICATE, libspdm_get_encap_response_certificate },
43 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CERT_CAP */
44 :
45 : #if LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP
46 : { SPDM_CHALLENGE, libspdm_get_encap_response_challenge_auth },
47 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP */
48 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */
49 :
50 : { SPDM_KEY_UPDATE, libspdm_get_encap_response_key_update },
51 :
52 : #if LIBSPDM_EVENT_RECIPIENT_SUPPORT
53 : { SPDM_SEND_EVENT, libspdm_get_encap_response_event_ack },
54 : #endif /* LIBSPDM_EVENT_RECIPIENT_SUPPORT */
55 :
56 : #if LIBSPDM_ENABLE_CAPABILITY_ENDPOINT_INFO_CAP
57 : { SPDM_GET_ENDPOINT_INFO, libspdm_get_encap_response_endpoint_info },
58 : #endif /* LIBSPDM_ENABLE_CAPABILITY_ENDPOINT_INFO_CAP */
59 : };
60 :
61 23 : for (index = 0; index < LIBSPDM_ARRAY_SIZE(get_encap_response_struct); index++) {
62 22 : if (request_response_code == get_encap_response_struct[index].request_response_code) {
63 7 : return get_encap_response_struct[index].get_encap_response_func;
64 : }
65 : }
66 1 : return NULL;
67 : }
68 :
69 : /**
70 : * This function processes encapsulated request.
71 : *
72 : * @param spdm_context A pointer to the SPDM context.
73 : * @param encap_request_size Size, in bytes, of the request data buffer.
74 : * @param encap_request A pointer to a destination buffer to store the request.
75 : * @param encap_response_size Size, in bytes, of the response data buffer.
76 : * @param encap_response A pointer to a destination buffer to store the response.
77 : **/
78 8 : static libspdm_return_t libspdm_process_encapsulated_request(libspdm_context_t *spdm_context,
79 : size_t encap_request_size,
80 : void *encap_request,
81 : size_t *encap_response_size,
82 : void *encap_response)
83 : {
84 : libspdm_get_encap_response_func get_encap_response_func;
85 : spdm_message_header_t *spdm_requester;
86 :
87 8 : spdm_requester = encap_request;
88 8 : if (encap_request_size < sizeof(spdm_message_header_t)) {
89 0 : return libspdm_generate_encap_error_response(
90 : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
91 0 : spdm_requester->request_response_code,
92 : encap_response_size, encap_response);
93 : }
94 :
95 8 : get_encap_response_func = libspdm_get_encap_response_func_via_request_code(
96 8 : spdm_requester->request_response_code);
97 8 : if (get_encap_response_func == NULL) {
98 1 : get_encap_response_func =
99 1 : (libspdm_get_encap_response_func)spdm_context->get_encap_response_func;
100 : }
101 8 : if (get_encap_response_func != NULL) {
102 7 : return get_encap_response_func(
103 : spdm_context, encap_request_size, encap_request,
104 : encap_response_size, encap_response);
105 : } else {
106 1 : return libspdm_generate_encap_error_response(
107 : spdm_context, SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
108 : 0, encap_response_size, encap_response);
109 : }
110 : }
111 :
112 13 : libspdm_return_t libspdm_encapsulated_request(libspdm_context_t *spdm_context,
113 : const uint32_t *session_id,
114 : uint8_t mut_auth_requested,
115 : uint8_t *req_slot_id_param)
116 : {
117 : libspdm_return_t status;
118 : uint8_t *spdm_request;
119 : size_t spdm_request_size;
120 : spdm_get_encapsulated_request_request_t
121 : *spdm_get_encapsulated_request_request;
122 : spdm_deliver_encapsulated_response_request_t
123 : *spdm_deliver_encapsulated_response_request;
124 : uint8_t *spdm_response;
125 : size_t spdm_response_size;
126 : spdm_encapsulated_request_response_t *libspdm_encapsulated_request_response;
127 : spdm_encapsulated_response_ack_response_t
128 : *spdm_encapsulated_response_ack_response;
129 : libspdm_session_info_t *session_info;
130 : uint8_t request_id;
131 : void *encapsulated_request;
132 : size_t encapsulated_request_size;
133 : void *encapsulated_response;
134 : size_t encapsulated_response_size;
135 : size_t ack_header_size;
136 :
137 : uint8_t *message;
138 : size_t message_size;
139 : size_t transport_header_size;
140 :
141 : #if LIBSPDM_ENABLE_CAPABILITY_CERT_CAP
142 : spdm_get_digest_request_t *get_digests;
143 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CERT_CAP */
144 :
145 13 : if (!libspdm_is_encap_supported(spdm_context)) {
146 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
147 : }
148 :
149 13 : if (session_id != NULL) {
150 0 : session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
151 0 : if (session_info == NULL) {
152 0 : LIBSPDM_ASSERT(false);
153 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
154 : }
155 0 : LIBSPDM_ASSERT((mut_auth_requested == 0) ||
156 : (mut_auth_requested ==
157 : SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST) ||
158 : (mut_auth_requested ==
159 : SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS));
160 : } else {
161 13 : LIBSPDM_ASSERT(mut_auth_requested == 0);
162 : }
163 :
164 :
165 : /* Cache */
166 13 : libspdm_reset_message_mut_b(spdm_context);
167 13 : libspdm_reset_message_mut_c(spdm_context);
168 :
169 13 : if (session_id == NULL) {
170 13 : spdm_context->last_spdm_request_session_id_valid = false;
171 13 : spdm_context->last_spdm_request_session_id = 0;
172 : } else {
173 0 : spdm_context->last_spdm_request_session_id_valid = true;
174 0 : spdm_context->last_spdm_request_session_id = *session_id;
175 : }
176 :
177 13 : if (mut_auth_requested == SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS) {
178 : #if LIBSPDM_ENABLE_CAPABILITY_CERT_CAP
179 0 : get_digests = (void *)spdm_context->last_spdm_request;
180 0 : get_digests->header.spdm_version = libspdm_get_connection_version (spdm_context);
181 0 : get_digests->header.request_response_code = SPDM_GET_DIGESTS;
182 0 : get_digests->header.param1 = 0;
183 0 : get_digests->header.param2 = 0;
184 0 : spdm_context->last_spdm_request_size = sizeof(spdm_get_digest_request_t);
185 0 : encapsulated_request = (void *)spdm_context->last_spdm_request;
186 0 : encapsulated_request_size = spdm_context->last_spdm_request_size;
187 0 : request_id = 0;
188 : #else /* LIBSPDM_ENABLE_CAPABILITY_CERT_CAP */
189 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
190 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CERT_CAP */
191 : } else {
192 13 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
193 13 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
194 13 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
195 0 : return status;
196 : }
197 13 : LIBSPDM_ASSERT (message_size >= transport_header_size +
198 : spdm_context->local_context.capability.transport_tail_size);
199 13 : spdm_request = (void *)(message + transport_header_size);
200 13 : spdm_request_size = message_size - transport_header_size -
201 13 : spdm_context->local_context.capability.transport_tail_size;
202 :
203 13 : spdm_context->crypto_request = true;
204 13 : spdm_get_encapsulated_request_request = (void *)spdm_request;
205 13 : spdm_get_encapsulated_request_request->header.spdm_version =
206 13 : libspdm_get_connection_version (spdm_context);
207 : spdm_get_encapsulated_request_request->header
208 13 : .request_response_code = SPDM_GET_ENCAPSULATED_REQUEST;
209 13 : spdm_get_encapsulated_request_request->header.param1 = 0;
210 13 : spdm_get_encapsulated_request_request->header.param2 = 0;
211 13 : spdm_request_size = sizeof(spdm_get_encapsulated_request_request_t);
212 13 : libspdm_reset_message_buffer_via_request_code
213 : (spdm_context, NULL,
214 13 : spdm_get_encapsulated_request_request->header.request_response_code);
215 13 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size,
216 : spdm_request);
217 13 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
218 1 : libspdm_release_sender_buffer (spdm_context);
219 1 : return status;
220 : }
221 12 : libspdm_release_sender_buffer (spdm_context);
222 12 : spdm_get_encapsulated_request_request = (void *)spdm_context->last_spdm_request;
223 :
224 : /* receive */
225 :
226 12 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
227 12 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
228 0 : return status;
229 : }
230 12 : LIBSPDM_ASSERT (message_size >= transport_header_size);
231 12 : spdm_response = (void *)(message);
232 12 : spdm_response_size = message_size;
233 :
234 12 : status = libspdm_receive_spdm_response(
235 : spdm_context, session_id, &spdm_response_size,
236 : (void **)&spdm_response);
237 12 : libspdm_encapsulated_request_response = (void *)spdm_response;
238 12 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
239 0 : libspdm_release_receiver_buffer (spdm_context);
240 0 : return status;
241 : }
242 12 : if (libspdm_encapsulated_request_response->header.request_response_code == SPDM_ERROR) {
243 3 : const uint8_t error_code = libspdm_encapsulated_request_response->header.param1;
244 :
245 3 : libspdm_release_receiver_buffer(spdm_context);
246 :
247 3 : if (spdm_response_size < sizeof(spdm_error_response_t)) {
248 0 : libspdm_release_receiver_buffer (spdm_context);
249 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
250 : }
251 :
252 3 : if (mut_auth_requested == 0) {
253 : /* Responder can send NoPendingRequests or UnexpectedRequest if it has no
254 : * encapsulated request for the Requester. */
255 3 : if ((libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_13) &&
256 : (error_code == SPDM_ERROR_CODE_NO_PENDING_REQUESTS)) {
257 :
258 1 : return LIBSPDM_STATUS_SUCCESS;
259 : }
260 2 : if ((libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_13) &&
261 : (error_code == SPDM_ERROR_CODE_UNEXPECTED_REQUEST)) {
262 1 : return LIBSPDM_STATUS_SUCCESS;
263 : }
264 : }
265 1 : status = libspdm_handle_error_response_main(
266 : spdm_context, session_id,
267 : &spdm_response_size, (void **)&spdm_response,
268 : SPDM_GET_ENCAPSULATED_REQUEST, SPDM_ENCAPSULATED_REQUEST);
269 1 : return status;
270 : }
271 9 : if (libspdm_encapsulated_request_response->header.spdm_version !=
272 9 : spdm_get_encapsulated_request_request->header.spdm_version) {
273 0 : libspdm_release_receiver_buffer (spdm_context);
274 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
275 : }
276 :
277 9 : if (libspdm_encapsulated_request_response->header.request_response_code !=
278 : SPDM_ENCAPSULATED_REQUEST) {
279 0 : libspdm_release_receiver_buffer (spdm_context);
280 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
281 : }
282 9 : if (spdm_response_size <= sizeof(spdm_encapsulated_request_response_t)) {
283 1 : libspdm_release_receiver_buffer (spdm_context);
284 1 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
285 : }
286 :
287 8 : request_id = libspdm_encapsulated_request_response->header.param1;
288 :
289 8 : encapsulated_request = (void *)(libspdm_encapsulated_request_response + 1);
290 8 : encapsulated_request_size =
291 8 : spdm_response_size - sizeof(spdm_encapsulated_request_response_t);
292 :
293 8 : libspdm_copy_mem (spdm_context->last_spdm_request,
294 8 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
295 : encapsulated_request,
296 : encapsulated_request_size);
297 8 : spdm_context->last_spdm_request_size = encapsulated_request_size;
298 8 : encapsulated_request = (void *)spdm_context->last_spdm_request;
299 :
300 8 : libspdm_release_receiver_buffer (spdm_context);
301 : }
302 :
303 : while (true) {
304 : /* Process request. */
305 8 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
306 8 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
307 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
308 0 : return status;
309 : }
310 8 : LIBSPDM_ASSERT (message_size >= transport_header_size +
311 : spdm_context->local_context.capability.transport_tail_size);
312 8 : spdm_request = (void *)(message + transport_header_size);
313 8 : spdm_request_size = message_size - transport_header_size -
314 8 : spdm_context->local_context.capability.transport_tail_size;
315 :
316 8 : spdm_context->crypto_request = true;
317 8 : spdm_deliver_encapsulated_response_request = (void *)spdm_request;
318 8 : spdm_deliver_encapsulated_response_request->header.spdm_version =
319 8 : libspdm_get_connection_version (spdm_context);
320 8 : spdm_deliver_encapsulated_response_request->header.request_response_code =
321 : SPDM_DELIVER_ENCAPSULATED_RESPONSE;
322 8 : spdm_deliver_encapsulated_response_request->header.param1 = request_id;
323 8 : spdm_deliver_encapsulated_response_request->header.param2 = 0;
324 8 : encapsulated_response = (void *)(spdm_deliver_encapsulated_response_request + 1);
325 8 : encapsulated_response_size =
326 8 : spdm_request_size - sizeof(spdm_deliver_encapsulated_response_request_t);
327 :
328 8 : status = libspdm_process_encapsulated_request(
329 : spdm_context, encapsulated_request_size,
330 : encapsulated_request, &encapsulated_response_size,
331 : encapsulated_response);
332 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
333 0 : libspdm_release_sender_buffer (spdm_context);
334 0 : return status;
335 : }
336 :
337 8 : spdm_request_size =
338 8 : sizeof(spdm_deliver_encapsulated_response_request_t) + encapsulated_response_size;
339 8 : status = libspdm_send_spdm_request(
340 : spdm_context, session_id, spdm_request_size,
341 : spdm_request);
342 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
343 0 : libspdm_release_sender_buffer (spdm_context);
344 0 : return status;
345 : }
346 8 : libspdm_release_sender_buffer (spdm_context);
347 8 : spdm_deliver_encapsulated_response_request = (void *)spdm_context->last_spdm_request;
348 :
349 : /* Receive. */
350 8 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
351 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
352 0 : return status;
353 : }
354 8 : LIBSPDM_ASSERT (message_size >= transport_header_size);
355 8 : spdm_response = (void *)(message);
356 8 : spdm_response_size = message_size;
357 :
358 8 : status = libspdm_receive_spdm_response(
359 : spdm_context, session_id, &spdm_response_size,
360 : (void **)&spdm_response);
361 8 : spdm_encapsulated_response_ack_response = (void *)spdm_response;
362 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
363 0 : libspdm_release_receiver_buffer (spdm_context);
364 0 : return status;
365 : }
366 8 : if (spdm_encapsulated_response_ack_response->header.request_response_code == SPDM_ERROR) {
367 1 : libspdm_release_receiver_buffer(spdm_context);
368 :
369 1 : if (spdm_response_size < sizeof(spdm_error_response_t)) {
370 0 : libspdm_release_receiver_buffer (spdm_context);
371 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
372 : }
373 :
374 1 : status = libspdm_handle_error_response_main(
375 : spdm_context, session_id,
376 : &spdm_response_size, (void **)&spdm_response,
377 : SPDM_DELIVER_ENCAPSULATED_RESPONSE,
378 : SPDM_ENCAPSULATED_RESPONSE_ACK);
379 1 : return status;
380 7 : } else if (spdm_encapsulated_response_ack_response->header.request_response_code !=
381 : SPDM_ENCAPSULATED_RESPONSE_ACK) {
382 1 : libspdm_release_receiver_buffer (spdm_context);
383 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
384 : }
385 6 : if (spdm_encapsulated_response_ack_response->header.spdm_version !=
386 6 : spdm_deliver_encapsulated_response_request->header.spdm_version) {
387 0 : libspdm_release_receiver_buffer (spdm_context);
388 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
389 : }
390 6 : if (spdm_encapsulated_response_ack_response->header.spdm_version >=
391 : SPDM_MESSAGE_VERSION_12) {
392 1 : ack_header_size = sizeof(spdm_encapsulated_response_ack_response_t);
393 : } else {
394 5 : ack_header_size = sizeof(spdm_message_header_t);
395 : }
396 6 : if (spdm_response_size < ack_header_size) {
397 0 : libspdm_release_receiver_buffer (spdm_context);
398 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
399 : }
400 :
401 6 : if (spdm_encapsulated_response_ack_response->header.spdm_version >=
402 : SPDM_MESSAGE_VERSION_12) {
403 1 : if (spdm_encapsulated_response_ack_response->ack_request_id !=
404 1 : spdm_deliver_encapsulated_response_request->header.param1) {
405 0 : libspdm_release_receiver_buffer (spdm_context);
406 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
407 : }
408 : }
409 :
410 6 : switch (spdm_encapsulated_response_ack_response->header.param2) {
411 5 : case SPDM_ENCAPSULATED_RESPONSE_ACK_RESPONSE_PAYLOAD_TYPE_ABSENT:
412 5 : libspdm_release_receiver_buffer (spdm_context);
413 5 : return LIBSPDM_STATUS_SUCCESS;
414 0 : case SPDM_ENCAPSULATED_RESPONSE_ACK_RESPONSE_PAYLOAD_TYPE_PRESENT:
415 0 : break;
416 1 : case SPDM_ENCAPSULATED_RESPONSE_ACK_RESPONSE_PAYLOAD_TYPE_REQ_SLOT_NUMBER:
417 1 : if (spdm_response_size >= ack_header_size + sizeof(uint8_t)) {
418 1 : if ((req_slot_id_param != NULL) && (*req_slot_id_param == 0)) {
419 0 : *req_slot_id_param =
420 0 : *((uint8_t *)spdm_encapsulated_response_ack_response + ack_header_size);
421 : /* 0xFF or 0xF slot is not allowed. */
422 0 : if (*req_slot_id_param >= SPDM_MAX_SLOT_COUNT) {
423 0 : libspdm_release_receiver_buffer (spdm_context);
424 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
425 : }
426 :
427 0 : if ((spdm_encapsulated_response_ack_response->header.spdm_version >=
428 0 : SPDM_MESSAGE_VERSION_13) &&
429 0 : spdm_context->connection_info.multi_key_conn_req) {
430 0 : if ((spdm_context->local_context.local_key_usage_bit_mask[*req_slot_id_param
431 0 : ] & SPDM_KEY_USAGE_BIT_MASK_KEY_EX_USE) == 0) {
432 0 : libspdm_release_receiver_buffer (spdm_context);
433 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
434 : }
435 : }
436 : }
437 1 : libspdm_release_receiver_buffer (spdm_context);
438 1 : return LIBSPDM_STATUS_SUCCESS;
439 : } else {
440 0 : libspdm_release_receiver_buffer (spdm_context);
441 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
442 : }
443 : break;
444 0 : default:
445 0 : libspdm_release_receiver_buffer (spdm_context);
446 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
447 : }
448 0 : request_id = spdm_encapsulated_response_ack_response->header.param1;
449 :
450 0 : encapsulated_request =
451 : ((uint8_t *)spdm_encapsulated_response_ack_response + ack_header_size);
452 0 : encapsulated_request_size = spdm_response_size - ack_header_size;
453 :
454 0 : libspdm_copy_mem (spdm_context->last_spdm_request,
455 0 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
456 : encapsulated_request,
457 : encapsulated_request_size);
458 0 : spdm_context->last_spdm_request_size = encapsulated_request_size;
459 0 : encapsulated_request = (void *)spdm_context->last_spdm_request;
460 :
461 0 : libspdm_release_receiver_buffer (spdm_context);
462 : }
463 :
464 : return LIBSPDM_STATUS_SUCCESS;
465 : }
466 :
467 0 : libspdm_return_t libspdm_send_receive_encap_request(void *spdm_context, const uint32_t *session_id)
468 : {
469 0 : return libspdm_encapsulated_request(spdm_context, session_id, 0, NULL);
470 : }
471 :
472 : #endif /* LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP */
|