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