/src/openssl/ssl/quic/quic_demux.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved. |
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 | | |
10 | | #include "internal/quic_demux.h" |
11 | | #include "internal/quic_wire_pkt.h" |
12 | | #include "internal/dgram_demux.h" |
13 | | #include "internal/common.h" |
14 | | #include <openssl/lhash.h> |
15 | | #include <openssl/err.h> |
16 | | |
17 | | /* |
18 | | * QUIC Demuxer Implementation |
19 | | * =========================== |
20 | | * |
21 | | * The QUIC demuxer wraps the generic DGRAM_DEMUX to add QUIC-specific |
22 | | * functionality: |
23 | | * - Extraction of DCID from the first packet in each datagram |
24 | | * - QUIC-specific callback signature that includes the DCID |
25 | | * |
26 | | * QUIC_URXE is a typedef to DGRAM_URXE, so all URXE management is delegated |
27 | | * to the underlying DGRAM_DEMUX. |
28 | | */ |
29 | | struct quic_demux_st { |
30 | | /* The underlying generic datagram demuxer. */ |
31 | | DGRAM_DEMUX *dgram_demux; |
32 | | |
33 | | /* |
34 | | * QUIC short packets do not contain the length of the connection ID field, |
35 | | * therefore it must be known contextually. The demuxer requires connection |
36 | | * IDs of the same length to be used for all incoming packets. |
37 | | */ |
38 | | size_t short_conn_id_len; |
39 | | |
40 | | /* The QUIC-specific packet handler callback (includes DCID). */ |
41 | | ossl_quic_demux_cb_fn *default_cb; |
42 | | void *default_cb_arg; |
43 | | }; |
44 | | |
45 | | /* |
46 | | * Internal callback that wraps the QUIC callback. This is called by |
47 | | * DGRAM_DEMUX for each received datagram. We extract the DCID and forward |
48 | | * to the QUIC-specific callback. |
49 | | */ |
50 | | static void quic_demux_dgram_cb(DGRAM_URXE *e, void *arg) |
51 | 0 | { |
52 | 0 | QUIC_DEMUX *demux = arg; |
53 | |
|
54 | 0 | if (demux->default_cb != NULL) { |
55 | 0 | QUIC_CONN_ID dst_conn_id; |
56 | 0 | int dst_conn_id_ok; |
57 | | |
58 | | /* Extract DCID from the first packet in the datagram. */ |
59 | 0 | dst_conn_id_ok = ossl_quic_wire_get_pkt_hdr_dst_conn_id( |
60 | 0 | ossl_quic_urxe_data(e), |
61 | 0 | e->data_len, |
62 | 0 | demux->short_conn_id_len, |
63 | 0 | &dst_conn_id); |
64 | |
|
65 | 0 | demux->default_cb(e, demux->default_cb_arg, |
66 | 0 | dst_conn_id_ok ? &dst_conn_id : NULL); |
67 | 0 | } else { |
68 | | /* No handler set, release the URXE back to the demuxer. */ |
69 | 0 | ossl_dgram_demux_release_urxe(demux->dgram_demux, e); |
70 | 0 | } |
71 | 0 | } |
72 | | |
73 | | QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio, |
74 | | size_t short_conn_id_len, |
75 | | OSSL_TIME (*now)(void *arg), |
76 | | void *now_arg) |
77 | 0 | { |
78 | 0 | QUIC_DEMUX *demux; |
79 | |
|
80 | 0 | demux = OPENSSL_zalloc(sizeof(QUIC_DEMUX)); |
81 | 0 | if (demux == NULL) |
82 | 0 | return NULL; |
83 | | |
84 | 0 | demux->short_conn_id_len = short_conn_id_len; |
85 | | |
86 | | /* Create the underlying generic demuxer (no internal locking for QUIC). */ |
87 | 0 | demux->dgram_demux = ossl_dgram_demux_new(net_bio, 0, now, now_arg); |
88 | 0 | if (demux->dgram_demux == NULL) { |
89 | 0 | OPENSSL_free(demux); |
90 | 0 | return NULL; |
91 | 0 | } |
92 | | |
93 | | /* |
94 | | * Set our internal wrapper callback on the DGRAM_DEMUX. This will be |
95 | | * called for every received datagram, and we'll extract the DCID and |
96 | | * forward to the QUIC-specific callback. |
97 | | */ |
98 | 0 | ossl_dgram_demux_set_default_handler(demux->dgram_demux, |
99 | 0 | quic_demux_dgram_cb, demux); |
100 | |
|
101 | 0 | return demux; |
102 | 0 | } |
103 | | |
104 | | void ossl_quic_demux_free(QUIC_DEMUX *demux) |
105 | 0 | { |
106 | 0 | if (demux == NULL) |
107 | 0 | return; |
108 | | |
109 | 0 | ossl_dgram_demux_free(demux->dgram_demux); |
110 | 0 | OPENSSL_free(demux); |
111 | 0 | } |
112 | | |
113 | | void ossl_quic_demux_set_bio(QUIC_DEMUX *demux, BIO *net_bio) |
114 | 0 | { |
115 | 0 | ossl_dgram_demux_set_bio(demux->dgram_demux, net_bio); |
116 | 0 | } |
117 | | |
118 | | int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu) |
119 | 0 | { |
120 | 0 | return ossl_dgram_demux_set_mtu(demux->dgram_demux, mtu); |
121 | 0 | } |
122 | | |
123 | | void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux, |
124 | | ossl_quic_demux_cb_fn *cb, |
125 | | void *cb_arg) |
126 | 0 | { |
127 | 0 | demux->default_cb = cb; |
128 | 0 | demux->default_cb_arg = cb_arg; |
129 | 0 | } |
130 | | |
131 | | int ossl_quic_demux_pump(QUIC_DEMUX *demux) |
132 | 0 | { |
133 | 0 | int ret; |
134 | |
|
135 | 0 | ret = ossl_dgram_demux_pump(demux->dgram_demux); |
136 | | |
137 | | /* |
138 | | * Map DGRAM_DEMUX_PUMP_RES_* to QUIC_DEMUX_PUMP_RES_*. The values are |
139 | | * identical, but this provides documentation and future-proofing. |
140 | | */ |
141 | 0 | switch (ret) { |
142 | 0 | case DGRAM_DEMUX_PUMP_RES_OK: |
143 | 0 | return QUIC_DEMUX_PUMP_RES_OK; |
144 | 0 | case DGRAM_DEMUX_PUMP_RES_TRANSIENT_FAIL: |
145 | 0 | return QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL; |
146 | 0 | case DGRAM_DEMUX_PUMP_RES_PERMANENT_FAIL: |
147 | 0 | default: |
148 | 0 | return QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL; |
149 | 0 | } |
150 | 0 | } |
151 | | |
152 | | /* Artificially inject a packet into the demuxer for testing purposes. */ |
153 | | int ossl_quic_demux_inject(QUIC_DEMUX *demux, |
154 | | const unsigned char *buf, |
155 | | size_t buf_len, |
156 | | const BIO_ADDR *peer, |
157 | | const BIO_ADDR *local) |
158 | 0 | { |
159 | 0 | return ossl_dgram_demux_inject(demux->dgram_demux, buf, buf_len, |
160 | 0 | peer, local); |
161 | 0 | } |
162 | | |
163 | | /* Called by our user to return a URXE to the free list. */ |
164 | | void ossl_quic_demux_release_urxe(QUIC_DEMUX *demux, QUIC_URXE *e) |
165 | 0 | { |
166 | 0 | ossl_dgram_demux_release_urxe(demux->dgram_demux, e); |
167 | 0 | } |
168 | | |
169 | | void ossl_quic_demux_reinject_urxe(QUIC_DEMUX *demux, QUIC_URXE *e) |
170 | 0 | { |
171 | 0 | ossl_dgram_demux_reinject_urxe(demux->dgram_demux, e); |
172 | 0 | } |
173 | | |
174 | | int ossl_quic_demux_has_pending(const QUIC_DEMUX *demux) |
175 | 0 | { |
176 | 0 | return ossl_dgram_demux_has_pending(demux->dgram_demux); |
177 | 0 | } |