QUIC Demuxer and Record Layer (RX Side)
[openssl.git] / include / internal / quic_demux.h
1 /*
2  * Copyright 2022 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 #ifndef OSSL_QUIC_DEMUX_H
11 # define OSSL_QUIC_DEMUX_H
12
13 # include <openssl/ssl.h>
14 # include "internal/quic_types.h"
15 # include "internal/bio_addr.h"
16
17 /*
18  * QUIC Demuxer
19  * ============
20  *
21  * The QUIC connection demuxer is the entity responsible for receiving datagrams
22  * from the network via a datagram BIO. It parses packet headers to determine
23  * each packet's destination connection ID (DCID) and hands off processing of
24  * the packet to the correct QUIC Record Layer (QRL)'s RX side.
25  *
26  * A QRL is instantiated per QUIC connection and contains the cryptographic
27  * resources needed to decrypt QUIC packets for that connection. Received
28  * datagrams are passed from the demuxer to the QRL via a callback registered
29  * for a specific DCID by the QRL; thus the demuxer has no specific knowledge of
30  * the QRL and is not coupled to it.
31  *
32  * A connection may have multiple connection IDs associated with it; a QRL
33  * handles this simply by registering multiple connection IDs with the demuxer
34  * via multiple register calls.
35  *
36  * URX Queue
37  * ---------
38  *
39  * Since the demuxer must handle the initial reception of datagrams from the OS,
40  * RX queue management for new, unprocessed datagrams is also handled by the
41  * demuxer.
42  *
43  * The demuxer maintains a queue of Unprocessed RX Entries (URXEs), which store
44  * unprocessed (i.e., encrypted, unvalidated) data received from the network.
45  * The URXE queue is designed to allow multiple datagrams to be received in a
46  * single call to BIO_recvmmsg, where supported.
47  *
48  * One URXE is used per received datagram. Each datagram may contain multiple
49  * packets, however, this is not the demuxer's concern. QUIC prohibits different
50  * packets in the same datagram from containing different DCIDs; the demuxer
51  * only considers the DCID of the first packet in a datagram when deciding how
52  * to route a received datagram, and it is the responsibility of the QRL to
53  * enforce this rule. Packets other than the first packet in a datagram are not
54  * examined by the demuxer, and the demuxer does not perform validation of
55  * packet headers other than to the minimum extent necessary to extract the
56  * DCID; further parsing and validation of packet headers is the responsibility
57  * of the QRL.
58  *
59  * Rather than defining an opaque interface, the URXE structure internals
60  * are exposed. Since the demuxer is only exposed to other parts of the QUIC
61  * implementation internals, this poses no problem, and has a number of
62  * advantages:
63  *
64  *   - Fields in the URXE can be allocated to support requirements in other
65  *     components, like the QRL, which would otherwise have to allocate extra
66  *     memory corresponding to each URXE.
67  *
68  *   - Other components, like the QRL, can keep the URXE in queues of its own
69  *     when it is not being managed by the demuxer.
70  *
71  * URX Queue Structure
72  * -------------------
73  *
74  * The URXE queue is maintained as a simple doubly-linked list. URXE entries are
75  * moved between different lists in their lifecycle (for example, from a free
76  * list to a pending list and vice versa). The buffer into which datagrams are
77  * received immediately follows this URXE header structure and is part of the
78  * same allocation.
79  */
80
81 typedef struct quic_urxe_st QUIC_URXE;
82
83 /* Maximum number of packets we allow to exist in one datagram. */
84 #define QUIC_MAX_PKT_PER_URXE       (sizeof(uint64_t) * 8)
85
86 struct quic_urxe_st {
87     QUIC_URXE *prev, *next;
88
89     /*
90      * The URXE data starts after this structure so we don't need a pointer.
91      * data_len stores the current length (i.e., the length of the received
92      * datagram) and alloc_len stores the allocation length. The URXE will be
93      * reallocated if we need a larger allocation than is available, though this
94      * should not be common as we will have a good idea of worst-case MTUs up
95      * front.
96      */
97     size_t          data_len, alloc_len;
98
99     /*
100      * Bitfields per packet. processed indicates the packet has been processed
101      * and must not be processed again, hpr_removed indicates header protection
102      * has already been removed. Used by QRL only; not used by the demuxer.
103      */
104     uint64_t        processed, hpr_removed;
105
106     /*
107      * Address of peer we received the datagram from, and the local interface
108      * address we received it on. If local address support is not enabled, local
109      * is zeroed.
110      */
111     BIO_ADDR        peer, local;
112 };
113
114 /* Accessors for URXE buffer. */
115 static ossl_unused ossl_inline unsigned char *
116 ossl_quic_urxe_data(const QUIC_URXE *e)
117 {
118     return (unsigned char *)&e[1];
119 }
120
121 static ossl_unused ossl_inline unsigned char *
122 ossl_quic_urxe_data_end(const QUIC_URXE *e)
123 {
124     return ossl_quic_urxe_data(e) + e->data_len;
125 }
126
127 /* List structure tracking a queue of URXEs. */
128 typedef struct quic_urxe_list_st {
129     QUIC_URXE *head, *tail;
130 } QUIC_URXE_LIST;
131
132 /*
133  * List management helpers. These are used by the demuxer but can also be used
134  * by users of the demuxer to manage URXEs.
135  */
136 void ossl_quic_urxe_remove(QUIC_URXE_LIST *l, QUIC_URXE *e);
137 void ossl_quic_urxe_insert_head(QUIC_URXE_LIST *l, QUIC_URXE *e);
138 void ossl_quic_urxe_insert_tail(QUIC_URXE_LIST *l, QUIC_URXE *e);
139
140 /* Opaque type representing a demuxer. */
141 typedef struct quic_demux_st QUIC_DEMUX;
142
143 /*
144  * Called when a datagram is received for a given connection ID.
145  *
146  * e is a URXE containing the datagram payload. It is permissible for the callee
147  * to mutate this buffer; once the demuxer calls this callback, it will never
148  * read the buffer again.
149  *
150  * The callee must arrange for ossl_quic_demux_release_urxe to be called on the URXE
151  * at some point in the future (this need not be before the callback returns).
152  *
153  * At the time the callback is made, the URXE will not be in any queue,
154  * therefore the callee can use the prev and next fields as it wishes.
155  */
156 typedef void (ossl_quic_demux_cb_fn)(QUIC_URXE *e, void *arg);
157
158 /*
159  * Creates a new demuxer. The given BIO is used to receive datagrams from the
160  * network using BIO_recvmmsg. short_conn_id_len is the length of destination
161  * connection IDs used in RX'd packets; it must have the same value for all
162  * connections used on a socket. default_urxe_alloc_len is the buffer size to
163  * receive datagrams into; it should be a value large enough to contain any
164  * received datagram according to local MTUs, etc.
165  */
166 QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio,
167                                 size_t short_conn_id_len,
168                                 size_t default_urxe_alloc_len);
169
170 /*
171  * Destroy a demuxer. All URXEs must have been released back to the demuxer
172  * before calling this. No-op if demux is NULL.
173  */
174 void ossl_quic_demux_free(QUIC_DEMUX *demux);
175
176 /*
177  * Register a datagram handler callback for a connection ID.
178  *
179  * ossl_quic_demux_pump will call the specified function if it receives a datagram
180  * the first packet of which has the specified destination connection ID.
181  *
182  * It is assumed all packets in a datagram have the same destination connection
183  * ID (as QUIC mandates this), but it is the user's responsibility to check for
184  * this and reject subsequent packets in a datagram that violate this rule.
185  *
186  * dst_conn_id is a destination connection ID; it is copied and need not remain
187  * valid after this function returns.
188  *
189  * cb_arg is passed to cb when it is called. For information on the callback,
190  * see its typedef above.
191  *
192  * Only one handler can be set for a given connection ID. If a handler is
193  * already set for the given connection ID, returns 0.
194  *
195  * Returns 1 on success or 0 on failure.
196  */
197 int ossl_quic_demux_register(QUIC_DEMUX *demux,
198                              const QUIC_CONN_ID *dst_conn_id,
199                              ossl_quic_demux_cb_fn *cb,
200                              void *cb_arg);
201
202 /*
203  * Unregisters any datagram handler callback set for the given connection ID.
204  * Fails if no handler is registered for the given connection ID.
205  *
206  * Returns 1 on success or 0 on failure.
207  */
208 int ossl_quic_demux_unregister(QUIC_DEMUX *demux,
209                                const QUIC_CONN_ID *dst_conn_id);
210
211 /*
212  * Unregisters any datagram handler callback from all connection IDs it is used
213  * for. cb and cb_arg must both match the values passed to
214  * ossl_quic_demux_register.
215  */
216 void ossl_quic_demux_unregister_by_cb(QUIC_DEMUX *demux,
217                                       ossl_quic_demux_cb_fn *cb,
218                                       void *cb_arg);
219
220 /*
221  * Releases a URXE back to the demuxer. No reference must be made to the URXE or
222  * its buffer after calling this function. The URXE must not be in any queue;
223  * that is, its prev and next pointers must be NULL.
224  */
225 void ossl_quic_demux_release_urxe(QUIC_DEMUX *demux,
226                                   QUIC_URXE *e);
227
228 /*
229  * Process any unprocessed RX'd datagrams, by calling registered callbacks by
230  * connection ID, reading more datagrams from the BIO if necessary.
231  *
232  * Returns 1 on success or 0 on failure.
233  */
234 int ossl_quic_demux_pump(QUIC_DEMUX *demux);
235
236 /*
237  * Artificially inject a packet into the demuxer for testing purposes. The
238  * buffer must not exceed the URXE size being used by the demuxer.
239  *
240  * If peer or local are NULL, their respective fields are zeroed in the injected
241  * URXE.
242  *
243  * Returns 1 on success or 0 on failure.
244  */
245 int ossl_quic_demux_inject(QUIC_DEMUX *demux,
246                            const unsigned char *buf,
247                            size_t buf_len,
248                            const BIO_ADDR *peer,
249                            const BIO_ADDR *local);
250
251 #endif