]>
Commit | Line | Data |
---|---|---|
83022590 | 1 | /* |
da1c088f | 2 | * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. |
83022590 HL |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
ec279ac2 HL |
10 | #include "internal/quic_demux.h" |
11 | #include "internal/quic_wire_pkt.h" | |
12 | #include "internal/common.h" | |
13 | #include <openssl/lhash.h> | |
66eab5e0 | 14 | #include <openssl/err.h> |
ec279ac2 | 15 | |
d7668ff2 HL |
16 | #define URXE_DEMUX_STATE_FREE 0 /* on urx_free list */ |
17 | #define URXE_DEMUX_STATE_PENDING 1 /* on urx_pending list */ | |
18 | #define URXE_DEMUX_STATE_ISSUED 2 /* on neither list */ | |
19 | ||
948c656c | 20 | #define DEMUX_MAX_MSGS_PER_CALL 32 |
ec279ac2 | 21 | |
d7668ff2 HL |
22 | #define DEMUX_DEFAULT_MTU 1500 |
23 | ||
ec279ac2 HL |
24 | /* Structure used to track a given connection ID. */ |
25 | typedef struct quic_demux_conn_st QUIC_DEMUX_CONN; | |
26 | ||
27 | struct quic_demux_conn_st { | |
93e9b6cc HL |
28 | QUIC_DEMUX_CONN *next; /* used when unregistering only */ |
29 | QUIC_CONN_ID dst_conn_id; | |
30 | ossl_quic_demux_cb_fn *cb; | |
31 | void *cb_arg; | |
ec279ac2 HL |
32 | }; |
33 | ||
34 | DEFINE_LHASH_OF_EX(QUIC_DEMUX_CONN); | |
35 | ||
36 | static unsigned long demux_conn_hash(const QUIC_DEMUX_CONN *conn) | |
37 | { | |
38 | size_t i; | |
39 | unsigned long v = 0; | |
40 | ||
41 | assert(conn->dst_conn_id.id_len <= QUIC_MAX_CONN_ID_LEN); | |
42 | ||
43 | for (i = 0; i < conn->dst_conn_id.id_len; ++i) | |
44 | v ^= ((unsigned long)conn->dst_conn_id.id[i]) | |
45 | << ((i * 8) % (sizeof(unsigned long) * 8)); | |
46 | ||
47 | return v; | |
48 | } | |
49 | ||
50 | static int demux_conn_cmp(const QUIC_DEMUX_CONN *a, const QUIC_DEMUX_CONN *b) | |
51 | { | |
52 | return !ossl_quic_conn_id_eq(&a->dst_conn_id, &b->dst_conn_id); | |
53 | } | |
54 | ||
55 | struct quic_demux_st { | |
56 | /* The underlying transport BIO with datagram semantics. */ | |
57 | BIO *net_bio; | |
58 | ||
59 | /* | |
60 | * QUIC short packets do not contain the length of the connection ID field, | |
61 | * therefore it must be known contextually. The demuxer requires connection | |
62 | * IDs of the same length to be used for all incoming packets. | |
63 | */ | |
64 | size_t short_conn_id_len; | |
65 | ||
d7668ff2 HL |
66 | /* |
67 | * Our current understanding of the upper bound on an incoming datagram size | |
68 | * in bytes. | |
69 | */ | |
70 | size_t mtu; | |
ec279ac2 | 71 | |
948c656c HL |
72 | /* Time retrieval callback. */ |
73 | OSSL_TIME (*now)(void *arg); | |
74 | void *now_arg; | |
75 | ||
ec279ac2 HL |
76 | /* Hashtable mapping connection IDs to QUIC_DEMUX_CONN structures. */ |
77 | LHASH_OF(QUIC_DEMUX_CONN) *conns_by_id; | |
78 | ||
93e9b6cc HL |
79 | /* The default packet handler, if any. */ |
80 | ossl_quic_demux_cb_fn *default_cb; | |
81 | void *default_cb_arg; | |
82 | ||
cdd91631 P |
83 | /* The stateless reset token checker handler, if any. */ |
84 | ossl_quic_stateless_reset_cb_fn *reset_token_cb; | |
85 | void *reset_token_cb_arg; | |
86 | ||
ec279ac2 HL |
87 | /* |
88 | * List of URXEs which are not currently in use (i.e., not filled with | |
89 | * unconsumed data). These are moved to the pending list as they are filled. | |
90 | */ | |
91 | QUIC_URXE_LIST urx_free; | |
ec279ac2 HL |
92 | |
93 | /* | |
94 | * List of URXEs which are filled with received encrypted data. These are | |
95 | * removed from this list as we invoke the callbacks for each of them. They | |
96 | * are then not on any list managed by us; we forget about them until our | |
97 | * user calls ossl_quic_demux_release_urxe to return the URXE to us, at | |
98 | * which point we add it to the free list. | |
99 | */ | |
100 | QUIC_URXE_LIST urx_pending; | |
101 | ||
102 | /* Whether to use local address support. */ | |
103 | char use_local_addr; | |
104 | }; | |
105 | ||
106 | QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio, | |
107 | size_t short_conn_id_len, | |
948c656c HL |
108 | OSSL_TIME (*now)(void *arg), |
109 | void *now_arg) | |
ec279ac2 HL |
110 | { |
111 | QUIC_DEMUX *demux; | |
112 | ||
113 | demux = OPENSSL_zalloc(sizeof(QUIC_DEMUX)); | |
114 | if (demux == NULL) | |
115 | return NULL; | |
116 | ||
117 | demux->net_bio = net_bio; | |
118 | demux->short_conn_id_len = short_conn_id_len; | |
d7668ff2 HL |
119 | /* We update this if possible when we get a BIO. */ |
120 | demux->mtu = DEMUX_DEFAULT_MTU; | |
948c656c HL |
121 | demux->now = now; |
122 | demux->now_arg = now_arg; | |
ec279ac2 HL |
123 | |
124 | demux->conns_by_id | |
125 | = lh_QUIC_DEMUX_CONN_new(demux_conn_hash, demux_conn_cmp); | |
126 | if (demux->conns_by_id == NULL) { | |
127 | OPENSSL_free(demux); | |
128 | return NULL; | |
129 | } | |
130 | ||
131 | if (net_bio != NULL | |
132 | && BIO_dgram_get_local_addr_cap(net_bio) | |
133 | && BIO_dgram_set_local_addr_enable(net_bio, 1)) | |
134 | demux->use_local_addr = 1; | |
135 | ||
136 | return demux; | |
137 | } | |
138 | ||
139 | static void demux_free_conn_it(QUIC_DEMUX_CONN *conn, void *arg) | |
140 | { | |
141 | OPENSSL_free(conn); | |
142 | } | |
143 | ||
144 | static void demux_free_urxl(QUIC_URXE_LIST *l) | |
145 | { | |
146 | QUIC_URXE *e, *enext; | |
147 | ||
3fb172ef P |
148 | for (e = ossl_list_urxe_head(l); e != NULL; e = enext) { |
149 | enext = ossl_list_urxe_next(e); | |
150 | ossl_list_urxe_remove(l, e); | |
ec279ac2 HL |
151 | OPENSSL_free(e); |
152 | } | |
ec279ac2 HL |
153 | } |
154 | ||
155 | void ossl_quic_demux_free(QUIC_DEMUX *demux) | |
156 | { | |
157 | if (demux == NULL) | |
158 | return; | |
159 | ||
160 | /* Free all connection structures. */ | |
161 | lh_QUIC_DEMUX_CONN_doall_arg(demux->conns_by_id, demux_free_conn_it, NULL); | |
162 | lh_QUIC_DEMUX_CONN_free(demux->conns_by_id); | |
163 | ||
164 | /* Free all URXEs we are holding. */ | |
165 | demux_free_urxl(&demux->urx_free); | |
166 | demux_free_urxl(&demux->urx_pending); | |
167 | ||
168 | OPENSSL_free(demux); | |
169 | } | |
170 | ||
964f0deb HL |
171 | void ossl_quic_demux_set_bio(QUIC_DEMUX *demux, BIO *net_bio) |
172 | { | |
d7668ff2 HL |
173 | unsigned int mtu; |
174 | ||
964f0deb | 175 | demux->net_bio = net_bio; |
d7668ff2 HL |
176 | |
177 | if (net_bio != NULL) { | |
178 | /* | |
179 | * Try to determine our MTU if possible. The BIO is not required to | |
180 | * support this, in which case we remain at the last known MTU, or our | |
181 | * initial default. | |
182 | */ | |
183 | mtu = BIO_dgram_get_mtu(net_bio); | |
184 | if (mtu >= QUIC_MIN_INITIAL_DGRAM_LEN) | |
185 | ossl_quic_demux_set_mtu(demux, mtu); /* best effort */ | |
186 | } | |
187 | } | |
188 | ||
189 | int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu) | |
190 | { | |
191 | if (mtu < QUIC_MIN_INITIAL_DGRAM_LEN) | |
192 | return 0; | |
193 | ||
194 | demux->mtu = mtu; | |
195 | return 1; | |
964f0deb HL |
196 | } |
197 | ||
ec279ac2 HL |
198 | static QUIC_DEMUX_CONN *demux_get_by_conn_id(QUIC_DEMUX *demux, |
199 | const QUIC_CONN_ID *dst_conn_id) | |
200 | { | |
201 | QUIC_DEMUX_CONN key; | |
202 | ||
203 | if (dst_conn_id->id_len > QUIC_MAX_CONN_ID_LEN) | |
948c656c | 204 | return NULL; |
ec279ac2 HL |
205 | |
206 | key.dst_conn_id = *dst_conn_id; | |
207 | return lh_QUIC_DEMUX_CONN_retrieve(demux->conns_by_id, &key); | |
208 | } | |
209 | ||
210 | int ossl_quic_demux_register(QUIC_DEMUX *demux, | |
211 | const QUIC_CONN_ID *dst_conn_id, | |
212 | ossl_quic_demux_cb_fn *cb, void *cb_arg) | |
213 | { | |
214 | QUIC_DEMUX_CONN *conn; | |
215 | ||
216 | if (dst_conn_id == NULL | |
217 | || dst_conn_id->id_len > QUIC_MAX_CONN_ID_LEN | |
218 | || cb == NULL) | |
219 | return 0; | |
220 | ||
221 | /* Ensure not already registered. */ | |
222 | if (demux_get_by_conn_id(demux, dst_conn_id) != NULL) | |
223 | /* Handler already registered with this connection ID. */ | |
224 | return 0; | |
225 | ||
226 | conn = OPENSSL_zalloc(sizeof(QUIC_DEMUX_CONN)); | |
227 | if (conn == NULL) | |
228 | return 0; | |
229 | ||
230 | conn->dst_conn_id = *dst_conn_id; | |
231 | conn->cb = cb; | |
232 | conn->cb_arg = cb_arg; | |
233 | ||
234 | lh_QUIC_DEMUX_CONN_insert(demux->conns_by_id, conn); | |
235 | return 1; | |
236 | } | |
237 | ||
238 | static void demux_unregister(QUIC_DEMUX *demux, | |
239 | QUIC_DEMUX_CONN *conn) | |
240 | { | |
241 | lh_QUIC_DEMUX_CONN_delete(demux->conns_by_id, conn); | |
242 | OPENSSL_free(conn); | |
243 | } | |
244 | ||
245 | int ossl_quic_demux_unregister(QUIC_DEMUX *demux, | |
246 | const QUIC_CONN_ID *dst_conn_id) | |
247 | { | |
248 | QUIC_DEMUX_CONN *conn; | |
249 | ||
250 | if (dst_conn_id == NULL | |
251 | || dst_conn_id->id_len > QUIC_MAX_CONN_ID_LEN) | |
252 | return 0; | |
253 | ||
254 | conn = demux_get_by_conn_id(demux, dst_conn_id); | |
255 | if (conn == NULL) | |
256 | return 0; | |
257 | ||
258 | demux_unregister(demux, conn); | |
259 | return 1; | |
260 | } | |
261 | ||
262 | struct unreg_arg { | |
263 | ossl_quic_demux_cb_fn *cb; | |
264 | void *cb_arg; | |
265 | QUIC_DEMUX_CONN *head; | |
266 | }; | |
267 | ||
268 | static void demux_unregister_by_cb(QUIC_DEMUX_CONN *conn, void *arg_) | |
269 | { | |
270 | struct unreg_arg *arg = arg_; | |
271 | ||
272 | if (conn->cb == arg->cb && conn->cb_arg == arg->cb_arg) { | |
273 | conn->next = arg->head; | |
274 | arg->head = conn; | |
275 | } | |
276 | } | |
277 | ||
278 | void ossl_quic_demux_unregister_by_cb(QUIC_DEMUX *demux, | |
279 | ossl_quic_demux_cb_fn *cb, | |
280 | void *cb_arg) | |
281 | { | |
282 | QUIC_DEMUX_CONN *conn, *cnext; | |
283 | struct unreg_arg arg = {0}; | |
284 | arg.cb = cb; | |
285 | arg.cb_arg = cb_arg; | |
286 | ||
287 | lh_QUIC_DEMUX_CONN_doall_arg(demux->conns_by_id, | |
288 | demux_unregister_by_cb, &arg); | |
289 | ||
290 | for (conn = arg.head; conn != NULL; conn = cnext) { | |
291 | cnext = conn->next; | |
292 | demux_unregister(demux, conn); | |
293 | } | |
294 | } | |
295 | ||
93e9b6cc HL |
296 | void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux, |
297 | ossl_quic_demux_cb_fn *cb, | |
298 | void *cb_arg) | |
299 | { | |
300 | demux->default_cb = cb; | |
301 | demux->default_cb_arg = cb_arg; | |
302 | } | |
303 | ||
cdd91631 P |
304 | void ossl_quic_demux_set_stateless_reset_handler( |
305 | QUIC_DEMUX *demux, | |
306 | ossl_quic_stateless_reset_cb_fn *cb, void *cb_arg) | |
307 | { | |
308 | demux->reset_token_cb = cb; | |
309 | demux->reset_token_cb_arg = cb_arg; | |
310 | } | |
311 | ||
ec279ac2 HL |
312 | static QUIC_URXE *demux_alloc_urxe(size_t alloc_len) |
313 | { | |
314 | QUIC_URXE *e; | |
315 | ||
316 | if (alloc_len >= SIZE_MAX - sizeof(QUIC_URXE)) | |
317 | return NULL; | |
318 | ||
319 | e = OPENSSL_malloc(sizeof(QUIC_URXE) + alloc_len); | |
320 | if (e == NULL) | |
321 | return NULL; | |
322 | ||
3fb172ef | 323 | ossl_list_urxe_init_elem(e); |
d7668ff2 HL |
324 | e->alloc_len = alloc_len; |
325 | e->data_len = 0; | |
ec279ac2 HL |
326 | return e; |
327 | } | |
328 | ||
d7668ff2 HL |
329 | static QUIC_URXE *demux_resize_urxe(QUIC_DEMUX *demux, QUIC_URXE *e, |
330 | size_t new_alloc_len) | |
331 | { | |
332 | QUIC_URXE *e2, *prev; | |
333 | ||
334 | if (!ossl_assert(e->demux_state == URXE_DEMUX_STATE_FREE)) | |
335 | /* Never attempt to resize a URXE which is not on the free list. */ | |
336 | return NULL; | |
337 | ||
338 | prev = ossl_list_urxe_prev(e); | |
339 | ossl_list_urxe_remove(&demux->urx_free, e); | |
340 | ||
341 | e2 = OPENSSL_realloc(e, sizeof(QUIC_URXE) + new_alloc_len); | |
342 | if (e2 == NULL) { | |
343 | /* Failed to resize, abort. */ | |
344 | if (prev == NULL) | |
345 | ossl_list_urxe_insert_head(&demux->urx_free, e); | |
346 | else | |
347 | ossl_list_urxe_insert_after(&demux->urx_free, prev, e); | |
348 | ||
349 | return NULL; | |
350 | } | |
351 | ||
352 | if (prev == NULL) | |
353 | ossl_list_urxe_insert_head(&demux->urx_free, e2); | |
354 | else | |
355 | ossl_list_urxe_insert_after(&demux->urx_free, prev, e2); | |
356 | ||
357 | e2->alloc_len = new_alloc_len; | |
358 | return e2; | |
359 | } | |
360 | ||
361 | static QUIC_URXE *demux_reserve_urxe(QUIC_DEMUX *demux, QUIC_URXE *e, | |
362 | size_t alloc_len) | |
363 | { | |
364 | return e->alloc_len < alloc_len ? demux_resize_urxe(demux, e, alloc_len) : e; | |
365 | } | |
366 | ||
ec279ac2 HL |
367 | static int demux_ensure_free_urxe(QUIC_DEMUX *demux, size_t min_num_free) |
368 | { | |
369 | QUIC_URXE *e; | |
370 | ||
3fb172ef | 371 | while (ossl_list_urxe_num(&demux->urx_free) < min_num_free) { |
d7668ff2 | 372 | e = demux_alloc_urxe(demux->mtu); |
ec279ac2 HL |
373 | if (e == NULL) |
374 | return 0; | |
375 | ||
3fb172ef | 376 | ossl_list_urxe_insert_tail(&demux->urx_free, e); |
d7668ff2 | 377 | e->demux_state = URXE_DEMUX_STATE_FREE; |
ec279ac2 HL |
378 | } |
379 | ||
380 | return 1; | |
381 | } | |
382 | ||
383 | /* | |
384 | * Receive datagrams from network, placing them into URXEs. | |
385 | * | |
386 | * Returns 1 on success or 0 on failure. | |
387 | * | |
388 | * Precondition: at least one URXE is free | |
389 | * Precondition: there are no pending URXEs | |
390 | */ | |
391 | static int demux_recv(QUIC_DEMUX *demux) | |
392 | { | |
948c656c HL |
393 | BIO_MSG msg[DEMUX_MAX_MSGS_PER_CALL]; |
394 | size_t rd, i; | |
3fb172ef | 395 | QUIC_URXE *urxe = ossl_list_urxe_head(&demux->urx_free), *unext; |
948c656c | 396 | OSSL_TIME now; |
ec279ac2 HL |
397 | |
398 | /* This should never be called when we have any pending URXE. */ | |
3fb172ef | 399 | assert(ossl_list_urxe_head(&demux->urx_pending) == NULL); |
d7668ff2 | 400 | assert(urxe->demux_state == URXE_DEMUX_STATE_FREE); |
ec279ac2 HL |
401 | |
402 | if (demux->net_bio == NULL) | |
66eab5e0 HL |
403 | /* |
404 | * If no BIO is plugged in, treat this as no datagram being available. | |
405 | */ | |
406 | return QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL; | |
ec279ac2 HL |
407 | |
408 | /* | |
409 | * Opportunistically receive as many messages as possible in a single | |
410 | * syscall, determined by how many free URXEs are available. | |
411 | */ | |
3fb172ef P |
412 | for (i = 0; i < (ossl_ssize_t)OSSL_NELEM(msg); |
413 | ++i, urxe = ossl_list_urxe_next(urxe)) { | |
ec279ac2 HL |
414 | if (urxe == NULL) { |
415 | /* We need at least one URXE to receive into. */ | |
416 | if (!ossl_assert(i > 0)) | |
66eab5e0 | 417 | return QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL; |
ec279ac2 HL |
418 | |
419 | break; | |
420 | } | |
421 | ||
d7668ff2 HL |
422 | /* Ensure the URXE is big enough. */ |
423 | urxe = demux_reserve_urxe(demux, urxe, demux->mtu); | |
424 | if (urxe == NULL) | |
425 | /* Allocation error, fail. */ | |
66eab5e0 | 426 | return QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL; |
d7668ff2 | 427 | |
ec279ac2 HL |
428 | /* Ensure we zero any fields added to BIO_MSG at a later date. */ |
429 | memset(&msg[i], 0, sizeof(BIO_MSG)); | |
430 | msg[i].data = ossl_quic_urxe_data(urxe); | |
431 | msg[i].data_len = urxe->alloc_len; | |
432 | msg[i].peer = &urxe->peer; | |
93e9b6cc | 433 | BIO_ADDR_clear(&urxe->peer); |
ec279ac2 HL |
434 | if (demux->use_local_addr) |
435 | msg[i].local = &urxe->local; | |
436 | else | |
437 | BIO_ADDR_clear(&urxe->local); | |
438 | } | |
439 | ||
66eab5e0 HL |
440 | ERR_set_mark(); |
441 | if (!BIO_recvmmsg(demux->net_bio, msg, sizeof(BIO_MSG), i, 0, &rd)) { | |
442 | if (BIO_err_is_non_fatal(ERR_peek_last_error())) { | |
443 | /* Transient error, clear the error and stop. */ | |
444 | ERR_pop_to_mark(); | |
445 | return QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL; | |
446 | } else { | |
447 | /* Non-transient error, do not clear the error. */ | |
448 | ERR_clear_last_mark(); | |
449 | return QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL; | |
450 | } | |
451 | } | |
ec279ac2 | 452 | |
66eab5e0 | 453 | ERR_clear_last_mark(); |
948c656c HL |
454 | now = demux->now != NULL ? demux->now(demux->now_arg) : ossl_time_zero(); |
455 | ||
3fb172ef | 456 | urxe = ossl_list_urxe_head(&demux->urx_free); |
ec279ac2 | 457 | for (i = 0; i < rd; ++i, urxe = unext) { |
3fb172ef | 458 | unext = ossl_list_urxe_next(urxe); |
ec279ac2 HL |
459 | /* Set URXE with actual length of received datagram. */ |
460 | urxe->data_len = msg[i].data_len; | |
948c656c HL |
461 | /* Time we received datagram. */ |
462 | urxe->time = now; | |
ec279ac2 | 463 | /* Move from free list to pending list. */ |
3fb172ef P |
464 | ossl_list_urxe_remove(&demux->urx_free, urxe); |
465 | ossl_list_urxe_insert_tail(&demux->urx_pending, urxe); | |
d7668ff2 | 466 | urxe->demux_state = URXE_DEMUX_STATE_PENDING; |
ec279ac2 HL |
467 | } |
468 | ||
66eab5e0 | 469 | return QUIC_DEMUX_PUMP_RES_OK; |
ec279ac2 HL |
470 | } |
471 | ||
472 | /* Extract destination connection ID from the first packet in a datagram. */ | |
473 | static int demux_identify_conn_id(QUIC_DEMUX *demux, | |
474 | QUIC_URXE *e, | |
475 | QUIC_CONN_ID *dst_conn_id) | |
476 | { | |
477 | return ossl_quic_wire_get_pkt_hdr_dst_conn_id(ossl_quic_urxe_data(e), | |
478 | e->data_len, | |
479 | demux->short_conn_id_len, | |
480 | dst_conn_id); | |
481 | } | |
482 | ||
483 | /* Identify the connection structure corresponding to a given URXE. */ | |
484 | static QUIC_DEMUX_CONN *demux_identify_conn(QUIC_DEMUX *demux, QUIC_URXE *e) | |
485 | { | |
486 | QUIC_CONN_ID dst_conn_id; | |
487 | ||
488 | if (!demux_identify_conn_id(demux, e, &dst_conn_id)) | |
489 | /* | |
490 | * Datagram is so badly malformed we can't get the DCID from the first | |
491 | * packet in it, so just give up. | |
492 | */ | |
493 | return NULL; | |
494 | ||
495 | return demux_get_by_conn_id(demux, &dst_conn_id); | |
496 | } | |
497 | ||
cdd91631 P |
498 | /* |
499 | * Process a single pending URXE. | |
500 | * Returning 1 on success, 0 on failure and -1 on stateless reset. | |
501 | */ | |
ec279ac2 HL |
502 | static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e) |
503 | { | |
504 | QUIC_DEMUX_CONN *conn; | |
cdd91631 | 505 | int r; |
ec279ac2 HL |
506 | |
507 | /* The next URXE we process should be at the head of the pending list. */ | |
3fb172ef | 508 | if (!ossl_assert(e == ossl_list_urxe_head(&demux->urx_pending))) |
948c656c | 509 | return 0; |
ec279ac2 | 510 | |
d7668ff2 HL |
511 | assert(e->demux_state == URXE_DEMUX_STATE_PENDING); |
512 | ||
cdd91631 P |
513 | /* |
514 | * Check if the packet ends with a stateless reset token and if it does | |
515 | * skip it after dropping the connection. | |
516 | * | |
517 | * RFC 9000 s. 10.3.1 Detecting a Stateless Reset | |
518 | * If the last 16 bytes of the datagram are identical in value to | |
519 | * a stateless reset token, the endpoint MUST enter the draining | |
520 | * period and not send any further packets on this connection. | |
521 | * | |
522 | * Returning a failure here causes the connection to enter the terminating | |
523 | * state which achieves the desired outcome. | |
524 | * | |
525 | * TODO(QUIC FUTURE): only try to match unparsable packets | |
526 | */ | |
527 | if (demux->reset_token_cb != NULL) { | |
528 | r = demux->reset_token_cb(ossl_quic_urxe_data(e), e->data_len, | |
529 | demux->reset_token_cb_arg); | |
530 | if (r > 0) /* Received a stateless reset */ | |
531 | return -1; | |
532 | if (r < 0) /* Error during stateless reset detection */ | |
533 | return 0; | |
534 | } | |
535 | ||
ec279ac2 HL |
536 | conn = demux_identify_conn(demux, e); |
537 | if (conn == NULL) { | |
538 | /* | |
93e9b6cc HL |
539 | * We could not identify a connection. If we have a default packet |
540 | * handler, pass it to the handler. Otherwise, we will never be able to | |
541 | * process this datagram, so get rid of it. | |
ec279ac2 | 542 | */ |
64222fc0 | 543 | ossl_list_urxe_remove(&demux->urx_pending, e); |
93e9b6cc HL |
544 | if (demux->default_cb != NULL) { |
545 | /* Pass to default handler. */ | |
93e9b6cc HL |
546 | e->demux_state = URXE_DEMUX_STATE_ISSUED; |
547 | demux->default_cb(e, demux->default_cb_arg); | |
548 | } else { | |
549 | /* Discard. */ | |
93e9b6cc HL |
550 | ossl_list_urxe_insert_tail(&demux->urx_free, e); |
551 | e->demux_state = URXE_DEMUX_STATE_FREE; | |
552 | } | |
ec279ac2 HL |
553 | return 1; /* keep processing pending URXEs */ |
554 | } | |
555 | ||
556 | /* | |
557 | * Remove from list and invoke callback. The URXE now belongs to the | |
558 | * callback. (QUIC_DEMUX_CONN never has non-NULL cb.) | |
559 | */ | |
3fb172ef | 560 | ossl_list_urxe_remove(&demux->urx_pending, e); |
d7668ff2 | 561 | e->demux_state = URXE_DEMUX_STATE_ISSUED; |
ec279ac2 HL |
562 | conn->cb(e, conn->cb_arg); |
563 | return 1; | |
564 | } | |
565 | ||
566 | /* Process pending URXEs to generate callbacks. */ | |
567 | static int demux_process_pending_urxl(QUIC_DEMUX *demux) | |
568 | { | |
569 | QUIC_URXE *e; | |
cdd91631 | 570 | int ret; |
ec279ac2 | 571 | |
3fb172ef | 572 | while ((e = ossl_list_urxe_head(&demux->urx_pending)) != NULL) |
cdd91631 P |
573 | if ((ret = demux_process_pending_urxe(demux, e)) <= 0) |
574 | return ret; | |
ec279ac2 HL |
575 | |
576 | return 1; | |
577 | } | |
578 | ||
579 | /* | |
580 | * Drain the pending URXE list, processing any pending URXEs by making their | |
581 | * callbacks. If no URXEs are pending, a network read is attempted first. | |
582 | */ | |
583 | int ossl_quic_demux_pump(QUIC_DEMUX *demux) | |
584 | { | |
585 | int ret; | |
586 | ||
3fb172ef | 587 | if (ossl_list_urxe_head(&demux->urx_pending) == NULL) { |
948c656c | 588 | ret = demux_ensure_free_urxe(demux, DEMUX_MAX_MSGS_PER_CALL); |
ec279ac2 | 589 | if (ret != 1) |
66eab5e0 | 590 | return QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL; |
ec279ac2 HL |
591 | |
592 | ret = demux_recv(demux); | |
66eab5e0 HL |
593 | if (ret != QUIC_DEMUX_PUMP_RES_OK) |
594 | return ret; | |
ec279ac2 HL |
595 | |
596 | /* | |
597 | * If demux_recv returned successfully, we should always have something. | |
598 | */ | |
3fb172ef | 599 | assert(ossl_list_urxe_head(&demux->urx_pending) != NULL); |
ec279ac2 HL |
600 | } |
601 | ||
cdd91631 P |
602 | if ((ret = demux_process_pending_urxl(demux)) <= 0) |
603 | return ret == 0 ? QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL | |
604 | : QUIC_DEMUX_PUMP_RES_STATELESS_RESET; | |
66eab5e0 HL |
605 | |
606 | return QUIC_DEMUX_PUMP_RES_OK; | |
ec279ac2 HL |
607 | } |
608 | ||
609 | /* Artificially inject a packet into the demuxer for testing purposes. */ | |
610 | int ossl_quic_demux_inject(QUIC_DEMUX *demux, | |
611 | const unsigned char *buf, | |
612 | size_t buf_len, | |
613 | const BIO_ADDR *peer, | |
614 | const BIO_ADDR *local) | |
615 | { | |
616 | int ret; | |
617 | QUIC_URXE *urxe; | |
618 | ||
619 | ret = demux_ensure_free_urxe(demux, 1); | |
620 | if (ret != 1) | |
621 | return 0; | |
622 | ||
3fb172ef | 623 | urxe = ossl_list_urxe_head(&demux->urx_free); |
ec279ac2 | 624 | |
d7668ff2 HL |
625 | assert(urxe->demux_state == URXE_DEMUX_STATE_FREE); |
626 | ||
627 | urxe = demux_reserve_urxe(demux, urxe, buf_len); | |
628 | if (urxe == NULL) | |
629 | return 0; | |
630 | ||
ec279ac2 HL |
631 | memcpy(ossl_quic_urxe_data(urxe), buf, buf_len); |
632 | urxe->data_len = buf_len; | |
633 | ||
634 | if (peer != NULL) | |
635 | urxe->peer = *peer; | |
636 | else | |
93e9b6cc | 637 | BIO_ADDR_clear(&urxe->peer); |
ec279ac2 HL |
638 | |
639 | if (local != NULL) | |
640 | urxe->local = *local; | |
641 | else | |
642 | BIO_ADDR_clear(&urxe->local); | |
643 | ||
29fb7f08 HL |
644 | urxe->time |
645 | = demux->now != NULL ? demux->now(demux->now_arg) : ossl_time_zero(); | |
646 | ||
ec279ac2 | 647 | /* Move from free list to pending list. */ |
3fb172ef P |
648 | ossl_list_urxe_remove(&demux->urx_free, urxe); |
649 | ossl_list_urxe_insert_tail(&demux->urx_pending, urxe); | |
d7668ff2 | 650 | urxe->demux_state = URXE_DEMUX_STATE_PENDING; |
ec279ac2 | 651 | |
cdd91631 | 652 | return demux_process_pending_urxl(demux) > 0; |
ec279ac2 HL |
653 | } |
654 | ||
655 | /* Called by our user to return a URXE to the free list. */ | |
656 | void ossl_quic_demux_release_urxe(QUIC_DEMUX *demux, | |
657 | QUIC_URXE *e) | |
658 | { | |
3fb172ef | 659 | assert(ossl_list_urxe_prev(e) == NULL && ossl_list_urxe_next(e) == NULL); |
d7668ff2 | 660 | assert(e->demux_state == URXE_DEMUX_STATE_ISSUED); |
3fb172ef | 661 | ossl_list_urxe_insert_tail(&demux->urx_free, e); |
d7668ff2 | 662 | e->demux_state = URXE_DEMUX_STATE_FREE; |
ec279ac2 | 663 | } |
93e9b6cc HL |
664 | |
665 | void ossl_quic_demux_reinject_urxe(QUIC_DEMUX *demux, | |
666 | QUIC_URXE *e) | |
667 | { | |
668 | assert(ossl_list_urxe_prev(e) == NULL && ossl_list_urxe_next(e) == NULL); | |
669 | assert(e->demux_state == URXE_DEMUX_STATE_ISSUED); | |
670 | ossl_list_urxe_insert_head(&demux->urx_pending, e); | |
671 | e->demux_state = URXE_DEMUX_STATE_PENDING; | |
672 | } | |
9280d26a HL |
673 | |
674 | int ossl_quic_demux_has_pending(const QUIC_DEMUX *demux) | |
675 | { | |
676 | return ossl_list_urxe_head(&demux->urx_pending) != NULL; | |
677 | } |