xref: /freebsd/crypto/openssl/ssl/quic/quic_rcidm.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery  * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery  *
4*e7be843bSPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*e7be843bSPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6*e7be843bSPierre Pronchery  * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery  * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery  */
9*e7be843bSPierre Pronchery 
10*e7be843bSPierre Pronchery #include "internal/quic_rcidm.h"
11*e7be843bSPierre Pronchery #include "internal/priority_queue.h"
12*e7be843bSPierre Pronchery #include "internal/list.h"
13*e7be843bSPierre Pronchery #include "internal/common.h"
14*e7be843bSPierre Pronchery 
15*e7be843bSPierre Pronchery /*
16*e7be843bSPierre Pronchery  * QUIC Remote Connection ID Manager
17*e7be843bSPierre Pronchery  * =================================
18*e7be843bSPierre Pronchery  *
19*e7be843bSPierre Pronchery  * We can receive an arbitrary number of RCIDs via NCID frames. Periodically, we
20*e7be843bSPierre Pronchery  * may desire (for example for anti-connection fingerprinting reasons, etc.)
21*e7be843bSPierre Pronchery  * to switch to a new RCID according to some arbitrary policy such as the number
22*e7be843bSPierre Pronchery  * of packets we have sent.
23*e7be843bSPierre Pronchery  *
24*e7be843bSPierre Pronchery  * When we do this we should move to the next RCID in the sequence of received
25*e7be843bSPierre Pronchery  * RCIDs ordered by sequence number. For example, if a peer sends us three NCID
26*e7be843bSPierre Pronchery  * frames with sequence numbers 10, 11, 12, we should seek to consume these
27*e7be843bSPierre Pronchery  * RCIDs in order.
28*e7be843bSPierre Pronchery  *
29*e7be843bSPierre Pronchery  * However, due to the possibility of packet reordering in the network, NCID
30*e7be843bSPierre Pronchery  * frames might be received out of order. Thus if a peer sends us NCID frames
31*e7be843bSPierre Pronchery  * with sequence numbers 12, 10, 11, we should still consume the RCID with
32*e7be843bSPierre Pronchery  * sequence number 10 before consuming the RCIDs with sequence numbers 11 or 12.
33*e7be843bSPierre Pronchery  *
34*e7be843bSPierre Pronchery  * We use a priority queue for this purpose.
35*e7be843bSPierre Pronchery  */
36*e7be843bSPierre Pronchery static void rcidm_update(QUIC_RCIDM *rcidm);
37*e7be843bSPierre Pronchery static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm,
38*e7be843bSPierre Pronchery                                      const QUIC_CONN_ID *rcid);
39*e7be843bSPierre Pronchery 
40*e7be843bSPierre Pronchery #define PACKETS_PER_RCID        10000
41*e7be843bSPierre Pronchery 
42*e7be843bSPierre Pronchery #define INITIAL_SEQ_NUM         0
43*e7be843bSPierre Pronchery #define PREF_ADDR_SEQ_NUM       1
44*e7be843bSPierre Pronchery 
45*e7be843bSPierre Pronchery /*
46*e7be843bSPierre Pronchery  * RCID
47*e7be843bSPierre Pronchery  * ====
48*e7be843bSPierre Pronchery  *
49*e7be843bSPierre Pronchery  * The RCID structure is used to track RCIDs which have sequence numbers (i.e.,
50*e7be843bSPierre Pronchery  * INITIAL, PREF_ADDR and NCID type RCIDs). The RCIDs without sequence numbers
51*e7be843bSPierre Pronchery  * (Initial ODCIDs and Retry ODCIDs), hereafter referred to as unnumbered RCIDs,
52*e7be843bSPierre Pronchery  * can logically be viewed as their own type of RCID but are tracked separately
53*e7be843bSPierre Pronchery  * as singletons without needing a discrete structure.
54*e7be843bSPierre Pronchery  *
55*e7be843bSPierre Pronchery  * At any given time an RCID object is in one of these states:
56*e7be843bSPierre Pronchery  *
57*e7be843bSPierre Pronchery  *
58*e7be843bSPierre Pronchery  *      (start)
59*e7be843bSPierre Pronchery  *         |
60*e7be843bSPierre Pronchery  *       [add]
61*e7be843bSPierre Pronchery  *         |
62*e7be843bSPierre Pronchery  *    _____v_____                 ___________                 ____________
63*e7be843bSPierre Pronchery  *   |           |               |           |               |            |
64*e7be843bSPierre Pronchery  *   |  PENDING  | --[select]--> |  CURRENT  | --[retire]--> |  RETIRING  |
65*e7be843bSPierre Pronchery  *   |___________|               |___________|               |____________|
66*e7be843bSPierre Pronchery  *                                                                  |
67*e7be843bSPierre Pronchery  *                                                                [pop]
68*e7be843bSPierre Pronchery  *                                                                  |
69*e7be843bSPierre Pronchery  *                                                                  v
70*e7be843bSPierre Pronchery  *                                                                (fin)
71*e7be843bSPierre Pronchery  *
72*e7be843bSPierre Pronchery  *   The transition through the states is monotonic and irreversible.
73*e7be843bSPierre Pronchery  *   The RCID object is freed when it is popped.
74*e7be843bSPierre Pronchery  *
75*e7be843bSPierre Pronchery  *   PENDING
76*e7be843bSPierre Pronchery  *     Invariants:
77*e7be843bSPierre Pronchery  *       rcid->state == RCID_STATE_PENDING;
78*e7be843bSPierre Pronchery  *       rcid->pq_idx != SIZE_MAX (debug assert only);
79*e7be843bSPierre Pronchery  *       the RCID is not the current RCID, rcidm->cur_rcid != rcid;
80*e7be843bSPierre Pronchery  *       the RCID is in the priority queue;
81*e7be843bSPierre Pronchery  *       the RCID is not in the retiring_list.
82*e7be843bSPierre Pronchery  *
83*e7be843bSPierre Pronchery  *   CURRENT
84*e7be843bSPierre Pronchery  *     Invariants:
85*e7be843bSPierre Pronchery  *       rcid->state == RCID_STATE_CUR;
86*e7be843bSPierre Pronchery  *       rcid->pq_idx == SIZE_MAX (debug assert only);
87*e7be843bSPierre Pronchery  *       the RCID is the current RCID, rcidm->cur_rcid == rcid;
88*e7be843bSPierre Pronchery  *       the RCID is not in the priority queue;
89*e7be843bSPierre Pronchery  *       the RCID is not in the retiring_list.
90*e7be843bSPierre Pronchery  *
91*e7be843bSPierre Pronchery  *   RETIRING
92*e7be843bSPierre Pronchery  *     Invariants:
93*e7be843bSPierre Pronchery  *       rcid->state == RCID_STATE_RETIRING;
94*e7be843bSPierre Pronchery  *       rcid->pq_idx == SIZE_MAX (debug assert only);
95*e7be843bSPierre Pronchery  *       the RCID is not the current RCID, rcidm->cur_rcid != rcid;
96*e7be843bSPierre Pronchery  *       the RCID is not in the priority queue;
97*e7be843bSPierre Pronchery  *       the RCID is in the retiring_list.
98*e7be843bSPierre Pronchery  *
99*e7be843bSPierre Pronchery  *   Invariant: At most one RCID object is in the CURRENT state at any one time.
100*e7be843bSPierre Pronchery  *
101*e7be843bSPierre Pronchery  *      (If no RCID object is in the CURRENT state, this means either
102*e7be843bSPierre Pronchery  *       an unnumbered RCID is being used as the preferred RCID
103*e7be843bSPierre Pronchery  *       or we currently have no preferred RCID.)
104*e7be843bSPierre Pronchery  *
105*e7be843bSPierre Pronchery  *   All of the above states can be considered substates of the 'ACTIVE' state
106*e7be843bSPierre Pronchery  *   for an RCID as specified in RFC 9000. A CID only ceases to be active
107*e7be843bSPierre Pronchery  *   when we send a RETIRE_CONN_ID frame, which is the responsibility of the
108*e7be843bSPierre Pronchery  *   user of the RCIDM and happens after the above state machine is terminated.
109*e7be843bSPierre Pronchery  */
110*e7be843bSPierre Pronchery enum {
111*e7be843bSPierre Pronchery     RCID_STATE_PENDING,
112*e7be843bSPierre Pronchery     RCID_STATE_CUR,
113*e7be843bSPierre Pronchery     RCID_STATE_RETIRING
114*e7be843bSPierre Pronchery };
115*e7be843bSPierre Pronchery 
116*e7be843bSPierre Pronchery enum {
117*e7be843bSPierre Pronchery     RCID_TYPE_INITIAL,      /* CID is from an peer INITIAL packet     (seq 0) */
118*e7be843bSPierre Pronchery     RCID_TYPE_PREF_ADDR,    /* CID is from a preferred_address TPARAM (seq 1) */
119*e7be843bSPierre Pronchery     RCID_TYPE_NCID          /* CID is from a NCID frame */
120*e7be843bSPierre Pronchery     /*
121*e7be843bSPierre Pronchery      * INITIAL_ODCID and RETRY_ODCID also conceptually exist but are tracked
122*e7be843bSPierre Pronchery      * separately.
123*e7be843bSPierre Pronchery      */
124*e7be843bSPierre Pronchery };
125*e7be843bSPierre Pronchery 
126*e7be843bSPierre Pronchery typedef struct rcid_st {
127*e7be843bSPierre Pronchery     OSSL_LIST_MEMBER(retiring, struct rcid_st); /* valid iff RETIRING */
128*e7be843bSPierre Pronchery 
129*e7be843bSPierre Pronchery     QUIC_CONN_ID    cid;        /* The actual CID string for this RCID */
130*e7be843bSPierre Pronchery     uint64_t        seq_num;
131*e7be843bSPierre Pronchery     size_t          pq_idx;     /* Index of entry into priority queue */
132*e7be843bSPierre Pronchery     unsigned int    state  : 2; /* RCID_STATE_* */
133*e7be843bSPierre Pronchery     unsigned int    type   : 2; /* RCID_TYPE_* */
134*e7be843bSPierre Pronchery } RCID;
135*e7be843bSPierre Pronchery 
136*e7be843bSPierre Pronchery DEFINE_PRIORITY_QUEUE_OF(RCID);
137*e7be843bSPierre Pronchery DEFINE_LIST_OF(retiring, RCID);
138*e7be843bSPierre Pronchery 
139*e7be843bSPierre Pronchery /*
140*e7be843bSPierre Pronchery  * RCID Manager
141*e7be843bSPierre Pronchery  * ============
142*e7be843bSPierre Pronchery  *
143*e7be843bSPierre Pronchery  * The following "business logic" invariants also apply to the RCIDM
144*e7be843bSPierre Pronchery  * as a whole:
145*e7be843bSPierre Pronchery  *
146*e7be843bSPierre Pronchery  *   Invariant: An RCID of INITIAL   type has a sequence number of 0.
147*e7be843bSPierre Pronchery  *   Invariant: An RCID of PREF_ADDR type has a sequence number of 1.
148*e7be843bSPierre Pronchery  *
149*e7be843bSPierre Pronchery  *   Invariant: There is never more than one Initial ODCID
150*e7be843bSPierre Pronchery  *              added throughout the lifetime of an RCIDM.
151*e7be843bSPierre Pronchery  *   Invariant: There is never more than one Retry ODCID
152*e7be843bSPierre Pronchery  *              added throughout the lifetime of an RCIDM.
153*e7be843bSPierre Pronchery  *   Invariant: There is never more than one INITIAL RCID created
154*e7be843bSPierre Pronchery  *              throughout the lifetime of an RCIDM.
155*e7be843bSPierre Pronchery  *   Invariant: There is never more than one PREF_ADDR RCID created
156*e7be843bSPierre Pronchery  *              throughout the lifetime of an RCIDM.
157*e7be843bSPierre Pronchery  *   Invariant: No INITIAL or PREF_ADDR RCID may be added after
158*e7be843bSPierre Pronchery  *              the handshake is completed.
159*e7be843bSPierre Pronchery  *
160*e7be843bSPierre Pronchery  */
161*e7be843bSPierre Pronchery struct quic_rcidm_st {
162*e7be843bSPierre Pronchery     /*
163*e7be843bSPierre Pronchery      * The current RCID we prefer to use (value undefined if
164*e7be843bSPierre Pronchery      * !have_preferred_rcid).
165*e7be843bSPierre Pronchery      *
166*e7be843bSPierre Pronchery      * This is preferentially set to a numbered RCID (represented by an RCID
167*e7be843bSPierre Pronchery      * object) if we have one (in which case preferred_rcid == cur_rcid->cid);
168*e7be843bSPierre Pronchery      * otherwise it is set to one of the unnumbered RCIDs (the Initial ODCID or
169*e7be843bSPierre Pronchery      * Retry ODCID) if available (and cur_rcid == NULL).
170*e7be843bSPierre Pronchery      */
171*e7be843bSPierre Pronchery     QUIC_CONN_ID                preferred_rcid;
172*e7be843bSPierre Pronchery 
173*e7be843bSPierre Pronchery     /*
174*e7be843bSPierre Pronchery      * These are initialized if the corresponding added_ flags are set.
175*e7be843bSPierre Pronchery      */
176*e7be843bSPierre Pronchery     QUIC_CONN_ID                initial_odcid, retry_odcid;
177*e7be843bSPierre Pronchery 
178*e7be843bSPierre Pronchery     /*
179*e7be843bSPierre Pronchery      * Total number of packets sent since we last made a packet count-based RCID
180*e7be843bSPierre Pronchery      * update decision.
181*e7be843bSPierre Pronchery      */
182*e7be843bSPierre Pronchery     uint64_t                    packets_sent;
183*e7be843bSPierre Pronchery 
184*e7be843bSPierre Pronchery     /* Number of post-handshake RCID changes we have performed. */
185*e7be843bSPierre Pronchery     uint64_t                    num_changes;
186*e7be843bSPierre Pronchery 
187*e7be843bSPierre Pronchery     /*
188*e7be843bSPierre Pronchery      * The Retire Prior To watermark value; max(retire_prior_to) of all received
189*e7be843bSPierre Pronchery      * NCID frames.
190*e7be843bSPierre Pronchery      */
191*e7be843bSPierre Pronchery     uint64_t                    retire_prior_to;
192*e7be843bSPierre Pronchery 
193*e7be843bSPierre Pronchery     /* (SORT BY seq_num ASC) -> (RCID *) */
194*e7be843bSPierre Pronchery     PRIORITY_QUEUE_OF(RCID)     *rcids;
195*e7be843bSPierre Pronchery 
196*e7be843bSPierre Pronchery     /*
197*e7be843bSPierre Pronchery      * Current RCID object we are using. This may differ from the first item in
198*e7be843bSPierre Pronchery      * the priority queue if we received NCID frames out of order. For example
199*e7be843bSPierre Pronchery      * if we get seq 5, switch to it immediately, then get seq 4, we want to
200*e7be843bSPierre Pronchery      * keep using seq 5 until we decide to roll again rather than immediately
201*e7be843bSPierre Pronchery      * switch to seq 4. Never points to an object on the retiring_list.
202*e7be843bSPierre Pronchery      */
203*e7be843bSPierre Pronchery     RCID                        *cur_rcid;
204*e7be843bSPierre Pronchery 
205*e7be843bSPierre Pronchery     /*
206*e7be843bSPierre Pronchery      * When a RCID becomes pending-retirement, it is moved to the retiring_list,
207*e7be843bSPierre Pronchery      * then freed when it is popped from the retired queue. We use a list for
208*e7be843bSPierre Pronchery      * this rather than a priority queue as the order in which items are freed
209*e7be843bSPierre Pronchery      * does not matter. We always append to the tail of the list in order to
210*e7be843bSPierre Pronchery      * maintain the guarantee that the head (if present) only changes when a
211*e7be843bSPierre Pronchery      * caller calls pop().
212*e7be843bSPierre Pronchery      */
213*e7be843bSPierre Pronchery     OSSL_LIST(retiring)         retiring_list;
214*e7be843bSPierre Pronchery 
215*e7be843bSPierre Pronchery     /* Number of entries on the retiring_list. */
216*e7be843bSPierre Pronchery     size_t                      num_retiring;
217*e7be843bSPierre Pronchery 
218*e7be843bSPierre Pronchery     /* preferred_rcid has been changed? */
219*e7be843bSPierre Pronchery     unsigned int    preferred_rcid_changed          : 1;
220*e7be843bSPierre Pronchery 
221*e7be843bSPierre Pronchery     /* Do we have any RCID we can use currently? */
222*e7be843bSPierre Pronchery     unsigned int    have_preferred_rcid             : 1;
223*e7be843bSPierre Pronchery 
224*e7be843bSPierre Pronchery     /* QUIC handshake has been completed? */
225*e7be843bSPierre Pronchery     unsigned int    handshake_complete              : 1;
226*e7be843bSPierre Pronchery 
227*e7be843bSPierre Pronchery     /* odcid was set (not necessarily still valid as a RCID)? */
228*e7be843bSPierre Pronchery     unsigned int    added_initial_odcid             : 1;
229*e7be843bSPierre Pronchery     /* retry_odcid was set (not necessarily still valid as a RCID?) */
230*e7be843bSPierre Pronchery     unsigned int    added_retry_odcid               : 1;
231*e7be843bSPierre Pronchery     /* An initial RCID was added as an RCID structure? */
232*e7be843bSPierre Pronchery     unsigned int    added_initial_rcid              : 1;
233*e7be843bSPierre Pronchery     /* Has a RCID roll been manually requested? */
234*e7be843bSPierre Pronchery     unsigned int    roll_requested                  : 1;
235*e7be843bSPierre Pronchery };
236*e7be843bSPierre Pronchery 
237*e7be843bSPierre Pronchery /*
238*e7be843bSPierre Pronchery  * Caller must periodically pop retired RCIDs and handle them. If the caller
239*e7be843bSPierre Pronchery  * fails to do so, fail safely rather than start exhibiting integer rollover.
240*e7be843bSPierre Pronchery  * Limit the total number of numbered RCIDs to an implausibly large but safe
241*e7be843bSPierre Pronchery  * value.
242*e7be843bSPierre Pronchery  */
243*e7be843bSPierre Pronchery #define MAX_NUMBERED_RCIDS      (SIZE_MAX / 2)
244*e7be843bSPierre Pronchery 
245*e7be843bSPierre Pronchery static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid,
246*e7be843bSPierre Pronchery                                   unsigned int state);
247*e7be843bSPierre Pronchery 
248*e7be843bSPierre Pronchery /* Check invariants of an RCID */
rcidm_check_rcid(QUIC_RCIDM * rcidm,RCID * rcid)249*e7be843bSPierre Pronchery static void rcidm_check_rcid(QUIC_RCIDM *rcidm, RCID *rcid)
250*e7be843bSPierre Pronchery {
251*e7be843bSPierre Pronchery     assert(rcid->state == RCID_STATE_PENDING
252*e7be843bSPierre Pronchery            || rcid->state == RCID_STATE_CUR
253*e7be843bSPierre Pronchery            || rcid->state == RCID_STATE_RETIRING);
254*e7be843bSPierre Pronchery     assert((rcid->state == RCID_STATE_PENDING)
255*e7be843bSPierre Pronchery            == (rcid->pq_idx != SIZE_MAX));
256*e7be843bSPierre Pronchery     assert((rcid->state == RCID_STATE_CUR)
257*e7be843bSPierre Pronchery            == (rcidm->cur_rcid == rcid));
258*e7be843bSPierre Pronchery     assert((ossl_list_retiring_next(rcid) != NULL
259*e7be843bSPierre Pronchery             || ossl_list_retiring_prev(rcid) != NULL
260*e7be843bSPierre Pronchery             || ossl_list_retiring_head(&rcidm->retiring_list) == rcid)
261*e7be843bSPierre Pronchery            == (rcid->state == RCID_STATE_RETIRING));
262*e7be843bSPierre Pronchery     assert(rcid->type != RCID_TYPE_INITIAL || rcid->seq_num == 0);
263*e7be843bSPierre Pronchery     assert(rcid->type != RCID_TYPE_PREF_ADDR || rcid->seq_num == 1);
264*e7be843bSPierre Pronchery     assert(rcid->seq_num <= OSSL_QUIC_VLINT_MAX);
265*e7be843bSPierre Pronchery     assert(rcid->cid.id_len > 0 && rcid->cid.id_len <= QUIC_MAX_CONN_ID_LEN);
266*e7be843bSPierre Pronchery     assert(rcid->seq_num >= rcidm->retire_prior_to
267*e7be843bSPierre Pronchery             || rcid->state == RCID_STATE_RETIRING);
268*e7be843bSPierre Pronchery     assert(rcidm->num_changes == 0 || rcidm->handshake_complete);
269*e7be843bSPierre Pronchery     assert(rcid->state != RCID_STATE_RETIRING || rcidm->num_retiring > 0);
270*e7be843bSPierre Pronchery }
271*e7be843bSPierre Pronchery 
rcid_cmp(const RCID * a,const RCID * b)272*e7be843bSPierre Pronchery static int rcid_cmp(const RCID *a, const RCID *b)
273*e7be843bSPierre Pronchery {
274*e7be843bSPierre Pronchery     if (a->seq_num < b->seq_num)
275*e7be843bSPierre Pronchery         return -1;
276*e7be843bSPierre Pronchery     if (a->seq_num > b->seq_num)
277*e7be843bSPierre Pronchery         return 1;
278*e7be843bSPierre Pronchery     return 0;
279*e7be843bSPierre Pronchery }
280*e7be843bSPierre Pronchery 
ossl_quic_rcidm_new(const QUIC_CONN_ID * initial_odcid)281*e7be843bSPierre Pronchery QUIC_RCIDM *ossl_quic_rcidm_new(const QUIC_CONN_ID *initial_odcid)
282*e7be843bSPierre Pronchery {
283*e7be843bSPierre Pronchery     QUIC_RCIDM *rcidm;
284*e7be843bSPierre Pronchery 
285*e7be843bSPierre Pronchery     if ((rcidm = OPENSSL_zalloc(sizeof(*rcidm))) == NULL)
286*e7be843bSPierre Pronchery         return NULL;
287*e7be843bSPierre Pronchery 
288*e7be843bSPierre Pronchery     if ((rcidm->rcids = ossl_pqueue_RCID_new(rcid_cmp)) == NULL) {
289*e7be843bSPierre Pronchery         OPENSSL_free(rcidm);
290*e7be843bSPierre Pronchery         return NULL;
291*e7be843bSPierre Pronchery     }
292*e7be843bSPierre Pronchery 
293*e7be843bSPierre Pronchery     if (initial_odcid != NULL) {
294*e7be843bSPierre Pronchery         rcidm->initial_odcid        = *initial_odcid;
295*e7be843bSPierre Pronchery         rcidm->added_initial_odcid  = 1;
296*e7be843bSPierre Pronchery     }
297*e7be843bSPierre Pronchery 
298*e7be843bSPierre Pronchery     rcidm_update(rcidm);
299*e7be843bSPierre Pronchery     return rcidm;
300*e7be843bSPierre Pronchery }
301*e7be843bSPierre Pronchery 
ossl_quic_rcidm_free(QUIC_RCIDM * rcidm)302*e7be843bSPierre Pronchery void ossl_quic_rcidm_free(QUIC_RCIDM *rcidm)
303*e7be843bSPierre Pronchery {
304*e7be843bSPierre Pronchery     RCID *rcid, *rnext;
305*e7be843bSPierre Pronchery 
306*e7be843bSPierre Pronchery     if (rcidm == NULL)
307*e7be843bSPierre Pronchery         return;
308*e7be843bSPierre Pronchery 
309*e7be843bSPierre Pronchery     OPENSSL_free(rcidm->cur_rcid);
310*e7be843bSPierre Pronchery     while ((rcid = ossl_pqueue_RCID_pop(rcidm->rcids)) != NULL)
311*e7be843bSPierre Pronchery         OPENSSL_free(rcid);
312*e7be843bSPierre Pronchery 
313*e7be843bSPierre Pronchery     OSSL_LIST_FOREACH_DELSAFE(rcid, rnext, retiring, &rcidm->retiring_list)
314*e7be843bSPierre Pronchery         OPENSSL_free(rcid);
315*e7be843bSPierre Pronchery 
316*e7be843bSPierre Pronchery     ossl_pqueue_RCID_free(rcidm->rcids);
317*e7be843bSPierre Pronchery     OPENSSL_free(rcidm);
318*e7be843bSPierre Pronchery }
319*e7be843bSPierre Pronchery 
rcidm_set_preferred_rcid(QUIC_RCIDM * rcidm,const QUIC_CONN_ID * rcid)320*e7be843bSPierre Pronchery static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm,
321*e7be843bSPierre Pronchery                                      const QUIC_CONN_ID *rcid)
322*e7be843bSPierre Pronchery {
323*e7be843bSPierre Pronchery     if (rcid == NULL) {
324*e7be843bSPierre Pronchery         rcidm->preferred_rcid_changed   = 1;
325*e7be843bSPierre Pronchery         rcidm->have_preferred_rcid      = 0;
326*e7be843bSPierre Pronchery         return;
327*e7be843bSPierre Pronchery     }
328*e7be843bSPierre Pronchery 
329*e7be843bSPierre Pronchery     if (ossl_quic_conn_id_eq(&rcidm->preferred_rcid, rcid))
330*e7be843bSPierre Pronchery         return;
331*e7be843bSPierre Pronchery 
332*e7be843bSPierre Pronchery     rcidm->preferred_rcid           = *rcid;
333*e7be843bSPierre Pronchery     rcidm->preferred_rcid_changed   = 1;
334*e7be843bSPierre Pronchery     rcidm->have_preferred_rcid      = 1;
335*e7be843bSPierre Pronchery }
336*e7be843bSPierre Pronchery 
337*e7be843bSPierre Pronchery /*
338*e7be843bSPierre Pronchery  * RCID Lifecycle Management
339*e7be843bSPierre Pronchery  * =========================
340*e7be843bSPierre Pronchery  */
rcidm_create_rcid(QUIC_RCIDM * rcidm,uint64_t seq_num,const QUIC_CONN_ID * cid,unsigned int type)341*e7be843bSPierre Pronchery static RCID *rcidm_create_rcid(QUIC_RCIDM *rcidm, uint64_t seq_num,
342*e7be843bSPierre Pronchery                                const QUIC_CONN_ID *cid,
343*e7be843bSPierre Pronchery                                unsigned int type)
344*e7be843bSPierre Pronchery {
345*e7be843bSPierre Pronchery     RCID *rcid;
346*e7be843bSPierre Pronchery 
347*e7be843bSPierre Pronchery     if (cid->id_len < 1 || cid->id_len > QUIC_MAX_CONN_ID_LEN
348*e7be843bSPierre Pronchery         || seq_num > OSSL_QUIC_VLINT_MAX
349*e7be843bSPierre Pronchery         || ossl_pqueue_RCID_num(rcidm->rcids) + rcidm->num_retiring
350*e7be843bSPierre Pronchery             > MAX_NUMBERED_RCIDS)
351*e7be843bSPierre Pronchery         return NULL;
352*e7be843bSPierre Pronchery 
353*e7be843bSPierre Pronchery     if ((rcid = OPENSSL_zalloc(sizeof(*rcid))) == NULL)
354*e7be843bSPierre Pronchery         return NULL;
355*e7be843bSPierre Pronchery 
356*e7be843bSPierre Pronchery     rcid->seq_num           = seq_num;
357*e7be843bSPierre Pronchery     rcid->cid               = *cid;
358*e7be843bSPierre Pronchery     rcid->type              = type;
359*e7be843bSPierre Pronchery 
360*e7be843bSPierre Pronchery     if (rcid->seq_num >= rcidm->retire_prior_to) {
361*e7be843bSPierre Pronchery         rcid->state = RCID_STATE_PENDING;
362*e7be843bSPierre Pronchery 
363*e7be843bSPierre Pronchery         if (!ossl_pqueue_RCID_push(rcidm->rcids, rcid, &rcid->pq_idx)) {
364*e7be843bSPierre Pronchery             OPENSSL_free(rcid);
365*e7be843bSPierre Pronchery             return NULL;
366*e7be843bSPierre Pronchery         }
367*e7be843bSPierre Pronchery     } else {
368*e7be843bSPierre Pronchery         /* RCID is immediately retired upon creation. */
369*e7be843bSPierre Pronchery         rcid->state     = RCID_STATE_RETIRING;
370*e7be843bSPierre Pronchery         rcid->pq_idx    = SIZE_MAX;
371*e7be843bSPierre Pronchery         ossl_list_retiring_insert_tail(&rcidm->retiring_list, rcid);
372*e7be843bSPierre Pronchery         ++rcidm->num_retiring;
373*e7be843bSPierre Pronchery     }
374*e7be843bSPierre Pronchery 
375*e7be843bSPierre Pronchery     rcidm_check_rcid(rcidm, rcid);
376*e7be843bSPierre Pronchery     return rcid;
377*e7be843bSPierre Pronchery }
378*e7be843bSPierre Pronchery 
rcidm_transition_rcid(QUIC_RCIDM * rcidm,RCID * rcid,unsigned int state)379*e7be843bSPierre Pronchery static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid,
380*e7be843bSPierre Pronchery                                   unsigned int state)
381*e7be843bSPierre Pronchery {
382*e7be843bSPierre Pronchery     unsigned int old_state = rcid->state;
383*e7be843bSPierre Pronchery 
384*e7be843bSPierre Pronchery     assert(state >= old_state && state <= RCID_STATE_RETIRING);
385*e7be843bSPierre Pronchery     rcidm_check_rcid(rcidm, rcid);
386*e7be843bSPierre Pronchery     if (state == old_state)
387*e7be843bSPierre Pronchery         return;
388*e7be843bSPierre Pronchery 
389*e7be843bSPierre Pronchery     if (rcidm->cur_rcid != NULL && state == RCID_STATE_CUR) {
390*e7be843bSPierre Pronchery         rcidm_transition_rcid(rcidm, rcidm->cur_rcid, RCID_STATE_RETIRING);
391*e7be843bSPierre Pronchery         assert(rcidm->cur_rcid == NULL);
392*e7be843bSPierre Pronchery     }
393*e7be843bSPierre Pronchery 
394*e7be843bSPierre Pronchery     if (old_state == RCID_STATE_PENDING) {
395*e7be843bSPierre Pronchery         ossl_pqueue_RCID_remove(rcidm->rcids, rcid->pq_idx);
396*e7be843bSPierre Pronchery         rcid->pq_idx = SIZE_MAX;
397*e7be843bSPierre Pronchery     }
398*e7be843bSPierre Pronchery 
399*e7be843bSPierre Pronchery     rcid->state = state;
400*e7be843bSPierre Pronchery 
401*e7be843bSPierre Pronchery     if (state == RCID_STATE_CUR) {
402*e7be843bSPierre Pronchery         rcidm->cur_rcid = rcid;
403*e7be843bSPierre Pronchery     } else if (state == RCID_STATE_RETIRING) {
404*e7be843bSPierre Pronchery         if (old_state == RCID_STATE_CUR)
405*e7be843bSPierre Pronchery             rcidm->cur_rcid = NULL;
406*e7be843bSPierre Pronchery 
407*e7be843bSPierre Pronchery         ossl_list_retiring_insert_tail(&rcidm->retiring_list, rcid);
408*e7be843bSPierre Pronchery         ++rcidm->num_retiring;
409*e7be843bSPierre Pronchery     }
410*e7be843bSPierre Pronchery 
411*e7be843bSPierre Pronchery     rcidm_check_rcid(rcidm, rcid);
412*e7be843bSPierre Pronchery }
413*e7be843bSPierre Pronchery 
rcidm_free_rcid(QUIC_RCIDM * rcidm,RCID * rcid)414*e7be843bSPierre Pronchery static void rcidm_free_rcid(QUIC_RCIDM *rcidm, RCID *rcid)
415*e7be843bSPierre Pronchery {
416*e7be843bSPierre Pronchery     if (rcid == NULL)
417*e7be843bSPierre Pronchery         return;
418*e7be843bSPierre Pronchery 
419*e7be843bSPierre Pronchery     rcidm_check_rcid(rcidm, rcid);
420*e7be843bSPierre Pronchery 
421*e7be843bSPierre Pronchery     switch (rcid->state) {
422*e7be843bSPierre Pronchery     case RCID_STATE_PENDING:
423*e7be843bSPierre Pronchery         ossl_pqueue_RCID_remove(rcidm->rcids, rcid->pq_idx);
424*e7be843bSPierre Pronchery         break;
425*e7be843bSPierre Pronchery     case RCID_STATE_CUR:
426*e7be843bSPierre Pronchery         rcidm->cur_rcid = NULL;
427*e7be843bSPierre Pronchery         break;
428*e7be843bSPierre Pronchery     case RCID_STATE_RETIRING:
429*e7be843bSPierre Pronchery         ossl_list_retiring_remove(&rcidm->retiring_list, rcid);
430*e7be843bSPierre Pronchery         --rcidm->num_retiring;
431*e7be843bSPierre Pronchery         break;
432*e7be843bSPierre Pronchery     default:
433*e7be843bSPierre Pronchery         assert(0);
434*e7be843bSPierre Pronchery         break;
435*e7be843bSPierre Pronchery     }
436*e7be843bSPierre Pronchery 
437*e7be843bSPierre Pronchery     OPENSSL_free(rcid);
438*e7be843bSPierre Pronchery }
439*e7be843bSPierre Pronchery 
rcidm_handle_retire_prior_to(QUIC_RCIDM * rcidm,uint64_t retire_prior_to)440*e7be843bSPierre Pronchery static void rcidm_handle_retire_prior_to(QUIC_RCIDM *rcidm,
441*e7be843bSPierre Pronchery                                          uint64_t retire_prior_to)
442*e7be843bSPierre Pronchery {
443*e7be843bSPierre Pronchery     RCID *rcid;
444*e7be843bSPierre Pronchery 
445*e7be843bSPierre Pronchery     if (retire_prior_to <= rcidm->retire_prior_to)
446*e7be843bSPierre Pronchery         return;
447*e7be843bSPierre Pronchery 
448*e7be843bSPierre Pronchery     /*
449*e7be843bSPierre Pronchery      * Retire the current RCID (if any) if it is affected.
450*e7be843bSPierre Pronchery      */
451*e7be843bSPierre Pronchery     if (rcidm->cur_rcid != NULL && rcidm->cur_rcid->seq_num < retire_prior_to)
452*e7be843bSPierre Pronchery         rcidm_transition_rcid(rcidm, rcidm->cur_rcid, RCID_STATE_RETIRING);
453*e7be843bSPierre Pronchery 
454*e7be843bSPierre Pronchery     /*
455*e7be843bSPierre Pronchery      * Any other RCIDs needing retirement will be at the start of the priority
456*e7be843bSPierre Pronchery      * queue, so just stop once we see a higher sequence number exceeding the
457*e7be843bSPierre Pronchery      * threshold.
458*e7be843bSPierre Pronchery      */
459*e7be843bSPierre Pronchery     while ((rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) != NULL
460*e7be843bSPierre Pronchery            && rcid->seq_num < retire_prior_to)
461*e7be843bSPierre Pronchery         rcidm_transition_rcid(rcidm, rcid, RCID_STATE_RETIRING);
462*e7be843bSPierre Pronchery 
463*e7be843bSPierre Pronchery     rcidm->retire_prior_to = retire_prior_to;
464*e7be843bSPierre Pronchery }
465*e7be843bSPierre Pronchery 
466*e7be843bSPierre Pronchery /*
467*e7be843bSPierre Pronchery  * Decision Logic
468*e7be843bSPierre Pronchery  * ==============
469*e7be843bSPierre Pronchery  */
470*e7be843bSPierre Pronchery 
rcidm_roll(QUIC_RCIDM * rcidm)471*e7be843bSPierre Pronchery static void rcidm_roll(QUIC_RCIDM *rcidm)
472*e7be843bSPierre Pronchery {
473*e7be843bSPierre Pronchery     RCID *rcid;
474*e7be843bSPierre Pronchery 
475*e7be843bSPierre Pronchery     if ((rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) == NULL)
476*e7be843bSPierre Pronchery         return;
477*e7be843bSPierre Pronchery 
478*e7be843bSPierre Pronchery     rcidm_transition_rcid(rcidm, rcid, RCID_STATE_CUR);
479*e7be843bSPierre Pronchery 
480*e7be843bSPierre Pronchery     ++rcidm->num_changes;
481*e7be843bSPierre Pronchery     rcidm->roll_requested = 0;
482*e7be843bSPierre Pronchery 
483*e7be843bSPierre Pronchery     if (rcidm->packets_sent >= PACKETS_PER_RCID)
484*e7be843bSPierre Pronchery         rcidm->packets_sent %= PACKETS_PER_RCID;
485*e7be843bSPierre Pronchery     else
486*e7be843bSPierre Pronchery         rcidm->packets_sent = 0;
487*e7be843bSPierre Pronchery }
488*e7be843bSPierre Pronchery 
rcidm_update(QUIC_RCIDM * rcidm)489*e7be843bSPierre Pronchery static void rcidm_update(QUIC_RCIDM *rcidm)
490*e7be843bSPierre Pronchery {
491*e7be843bSPierre Pronchery     RCID *rcid;
492*e7be843bSPierre Pronchery 
493*e7be843bSPierre Pronchery     /*
494*e7be843bSPierre Pronchery      * If we have no current numbered RCID but have one or more pending, use it.
495*e7be843bSPierre Pronchery      */
496*e7be843bSPierre Pronchery     if (rcidm->cur_rcid == NULL
497*e7be843bSPierre Pronchery         && (rcid = ossl_pqueue_RCID_peek(rcidm->rcids)) != NULL) {
498*e7be843bSPierre Pronchery         rcidm_transition_rcid(rcidm, rcid, RCID_STATE_CUR);
499*e7be843bSPierre Pronchery         assert(rcidm->cur_rcid != NULL);
500*e7be843bSPierre Pronchery     }
501*e7be843bSPierre Pronchery 
502*e7be843bSPierre Pronchery     /* Prefer use of any current numbered RCID we have, if possible. */
503*e7be843bSPierre Pronchery     if (rcidm->cur_rcid != NULL) {
504*e7be843bSPierre Pronchery         rcidm_check_rcid(rcidm, rcidm->cur_rcid);
505*e7be843bSPierre Pronchery         rcidm_set_preferred_rcid(rcidm, &rcidm->cur_rcid->cid);
506*e7be843bSPierre Pronchery         return;
507*e7be843bSPierre Pronchery     }
508*e7be843bSPierre Pronchery 
509*e7be843bSPierre Pronchery     /*
510*e7be843bSPierre Pronchery      * If there are no RCIDs from NCID frames we can use, go through the various
511*e7be843bSPierre Pronchery      * kinds of bootstrapping RCIDs we can use in order of priority.
512*e7be843bSPierre Pronchery      */
513*e7be843bSPierre Pronchery     if (rcidm->added_retry_odcid && !rcidm->handshake_complete) {
514*e7be843bSPierre Pronchery         rcidm_set_preferred_rcid(rcidm, &rcidm->retry_odcid);
515*e7be843bSPierre Pronchery         return;
516*e7be843bSPierre Pronchery     }
517*e7be843bSPierre Pronchery 
518*e7be843bSPierre Pronchery     if (rcidm->added_initial_odcid && !rcidm->handshake_complete) {
519*e7be843bSPierre Pronchery         rcidm_set_preferred_rcid(rcidm, &rcidm->initial_odcid);
520*e7be843bSPierre Pronchery         return;
521*e7be843bSPierre Pronchery     }
522*e7be843bSPierre Pronchery 
523*e7be843bSPierre Pronchery     /* We don't know of any usable RCIDs */
524*e7be843bSPierre Pronchery     rcidm_set_preferred_rcid(rcidm, NULL);
525*e7be843bSPierre Pronchery }
526*e7be843bSPierre Pronchery 
rcidm_should_roll(QUIC_RCIDM * rcidm)527*e7be843bSPierre Pronchery static int rcidm_should_roll(QUIC_RCIDM *rcidm)
528*e7be843bSPierre Pronchery {
529*e7be843bSPierre Pronchery     /*
530*e7be843bSPierre Pronchery      * Always switch as soon as possible if handshake completes;
531*e7be843bSPierre Pronchery      * and every n packets after handshake completes or the last roll; and
532*e7be843bSPierre Pronchery      * whenever manually requested.
533*e7be843bSPierre Pronchery      */
534*e7be843bSPierre Pronchery     return rcidm->handshake_complete
535*e7be843bSPierre Pronchery         && (rcidm->num_changes == 0
536*e7be843bSPierre Pronchery             || rcidm->packets_sent >= PACKETS_PER_RCID
537*e7be843bSPierre Pronchery             || rcidm->roll_requested);
538*e7be843bSPierre Pronchery }
539*e7be843bSPierre Pronchery 
rcidm_tick(QUIC_RCIDM * rcidm)540*e7be843bSPierre Pronchery static void rcidm_tick(QUIC_RCIDM *rcidm)
541*e7be843bSPierre Pronchery {
542*e7be843bSPierre Pronchery     if (rcidm_should_roll(rcidm))
543*e7be843bSPierre Pronchery         rcidm_roll(rcidm);
544*e7be843bSPierre Pronchery 
545*e7be843bSPierre Pronchery     rcidm_update(rcidm);
546*e7be843bSPierre Pronchery }
547*e7be843bSPierre Pronchery 
548*e7be843bSPierre Pronchery /*
549*e7be843bSPierre Pronchery  * Events
550*e7be843bSPierre Pronchery  * ======
551*e7be843bSPierre Pronchery  */
ossl_quic_rcidm_on_handshake_complete(QUIC_RCIDM * rcidm)552*e7be843bSPierre Pronchery void ossl_quic_rcidm_on_handshake_complete(QUIC_RCIDM *rcidm)
553*e7be843bSPierre Pronchery {
554*e7be843bSPierre Pronchery     if (rcidm->handshake_complete)
555*e7be843bSPierre Pronchery         return;
556*e7be843bSPierre Pronchery 
557*e7be843bSPierre Pronchery     rcidm->handshake_complete = 1;
558*e7be843bSPierre Pronchery     rcidm_tick(rcidm);
559*e7be843bSPierre Pronchery }
560*e7be843bSPierre Pronchery 
ossl_quic_rcidm_on_packet_sent(QUIC_RCIDM * rcidm,uint64_t num_packets)561*e7be843bSPierre Pronchery void ossl_quic_rcidm_on_packet_sent(QUIC_RCIDM *rcidm, uint64_t num_packets)
562*e7be843bSPierre Pronchery {
563*e7be843bSPierre Pronchery     if (num_packets == 0)
564*e7be843bSPierre Pronchery         return;
565*e7be843bSPierre Pronchery 
566*e7be843bSPierre Pronchery     rcidm->packets_sent += num_packets;
567*e7be843bSPierre Pronchery     rcidm_tick(rcidm);
568*e7be843bSPierre Pronchery }
569*e7be843bSPierre Pronchery 
ossl_quic_rcidm_request_roll(QUIC_RCIDM * rcidm)570*e7be843bSPierre Pronchery void ossl_quic_rcidm_request_roll(QUIC_RCIDM *rcidm)
571*e7be843bSPierre Pronchery {
572*e7be843bSPierre Pronchery     rcidm->roll_requested = 1;
573*e7be843bSPierre Pronchery     rcidm_tick(rcidm);
574*e7be843bSPierre Pronchery }
575*e7be843bSPierre Pronchery 
576*e7be843bSPierre Pronchery /*
577*e7be843bSPierre Pronchery  * Mutation Operations
578*e7be843bSPierre Pronchery  * ===================
579*e7be843bSPierre Pronchery  */
ossl_quic_rcidm_add_from_initial(QUIC_RCIDM * rcidm,const QUIC_CONN_ID * rcid)580*e7be843bSPierre Pronchery int ossl_quic_rcidm_add_from_initial(QUIC_RCIDM *rcidm,
581*e7be843bSPierre Pronchery                                      const QUIC_CONN_ID *rcid)
582*e7be843bSPierre Pronchery {
583*e7be843bSPierre Pronchery     RCID *rcid_obj;
584*e7be843bSPierre Pronchery 
585*e7be843bSPierre Pronchery     if (rcidm->added_initial_rcid || rcidm->handshake_complete)
586*e7be843bSPierre Pronchery         return 0;
587*e7be843bSPierre Pronchery 
588*e7be843bSPierre Pronchery     rcid_obj = rcidm_create_rcid(rcidm, INITIAL_SEQ_NUM,
589*e7be843bSPierre Pronchery                                  rcid, RCID_TYPE_INITIAL);
590*e7be843bSPierre Pronchery     if (rcid_obj == NULL)
591*e7be843bSPierre Pronchery         return 0;
592*e7be843bSPierre Pronchery 
593*e7be843bSPierre Pronchery     rcidm->added_initial_rcid = 1;
594*e7be843bSPierre Pronchery     rcidm_tick(rcidm);
595*e7be843bSPierre Pronchery     return 1;
596*e7be843bSPierre Pronchery }
597*e7be843bSPierre Pronchery 
ossl_quic_rcidm_add_from_server_retry(QUIC_RCIDM * rcidm,const QUIC_CONN_ID * retry_odcid)598*e7be843bSPierre Pronchery int ossl_quic_rcidm_add_from_server_retry(QUIC_RCIDM *rcidm,
599*e7be843bSPierre Pronchery                                           const QUIC_CONN_ID *retry_odcid)
600*e7be843bSPierre Pronchery {
601*e7be843bSPierre Pronchery     if (rcidm->added_retry_odcid || rcidm->handshake_complete)
602*e7be843bSPierre Pronchery         return 0;
603*e7be843bSPierre Pronchery 
604*e7be843bSPierre Pronchery     rcidm->retry_odcid          = *retry_odcid;
605*e7be843bSPierre Pronchery     rcidm->added_retry_odcid    = 1;
606*e7be843bSPierre Pronchery     rcidm_tick(rcidm);
607*e7be843bSPierre Pronchery     return 1;
608*e7be843bSPierre Pronchery }
609*e7be843bSPierre Pronchery 
ossl_quic_rcidm_add_from_ncid(QUIC_RCIDM * rcidm,const OSSL_QUIC_FRAME_NEW_CONN_ID * ncid)610*e7be843bSPierre Pronchery int ossl_quic_rcidm_add_from_ncid(QUIC_RCIDM *rcidm,
611*e7be843bSPierre Pronchery                                   const OSSL_QUIC_FRAME_NEW_CONN_ID *ncid)
612*e7be843bSPierre Pronchery {
613*e7be843bSPierre Pronchery     RCID *rcid;
614*e7be843bSPierre Pronchery 
615*e7be843bSPierre Pronchery     rcid = rcidm_create_rcid(rcidm, ncid->seq_num, &ncid->conn_id, RCID_TYPE_NCID);
616*e7be843bSPierre Pronchery     if (rcid == NULL)
617*e7be843bSPierre Pronchery         return 0;
618*e7be843bSPierre Pronchery 
619*e7be843bSPierre Pronchery     rcidm_handle_retire_prior_to(rcidm, ncid->retire_prior_to);
620*e7be843bSPierre Pronchery     rcidm_tick(rcidm);
621*e7be843bSPierre Pronchery     return 1;
622*e7be843bSPierre Pronchery }
623*e7be843bSPierre Pronchery 
624*e7be843bSPierre Pronchery /*
625*e7be843bSPierre Pronchery  * Queries
626*e7be843bSPierre Pronchery  * =======
627*e7be843bSPierre Pronchery  */
628*e7be843bSPierre Pronchery 
rcidm_get_retire(QUIC_RCIDM * rcidm,uint64_t * seq_num,int peek)629*e7be843bSPierre Pronchery static int rcidm_get_retire(QUIC_RCIDM *rcidm, uint64_t *seq_num, int peek)
630*e7be843bSPierre Pronchery {
631*e7be843bSPierre Pronchery     RCID *rcid = ossl_list_retiring_head(&rcidm->retiring_list);
632*e7be843bSPierre Pronchery 
633*e7be843bSPierre Pronchery     if (rcid == NULL)
634*e7be843bSPierre Pronchery         return 0;
635*e7be843bSPierre Pronchery 
636*e7be843bSPierre Pronchery     if (seq_num != NULL)
637*e7be843bSPierre Pronchery         *seq_num = rcid->seq_num;
638*e7be843bSPierre Pronchery 
639*e7be843bSPierre Pronchery     if (!peek)
640*e7be843bSPierre Pronchery         rcidm_free_rcid(rcidm, rcid);
641*e7be843bSPierre Pronchery 
642*e7be843bSPierre Pronchery     return 1;
643*e7be843bSPierre Pronchery }
644*e7be843bSPierre Pronchery 
ossl_quic_rcidm_pop_retire_seq_num(QUIC_RCIDM * rcidm,uint64_t * seq_num)645*e7be843bSPierre Pronchery int ossl_quic_rcidm_pop_retire_seq_num(QUIC_RCIDM *rcidm,
646*e7be843bSPierre Pronchery                                        uint64_t *seq_num)
647*e7be843bSPierre Pronchery {
648*e7be843bSPierre Pronchery     return rcidm_get_retire(rcidm, seq_num, /*peek=*/0);
649*e7be843bSPierre Pronchery }
650*e7be843bSPierre Pronchery 
ossl_quic_rcidm_peek_retire_seq_num(QUIC_RCIDM * rcidm,uint64_t * seq_num)651*e7be843bSPierre Pronchery int ossl_quic_rcidm_peek_retire_seq_num(QUIC_RCIDM *rcidm,
652*e7be843bSPierre Pronchery                                         uint64_t *seq_num)
653*e7be843bSPierre Pronchery {
654*e7be843bSPierre Pronchery     return rcidm_get_retire(rcidm, seq_num, /*peek=*/1);
655*e7be843bSPierre Pronchery }
656*e7be843bSPierre Pronchery 
ossl_quic_rcidm_get_preferred_tx_dcid(QUIC_RCIDM * rcidm,QUIC_CONN_ID * tx_dcid)657*e7be843bSPierre Pronchery int ossl_quic_rcidm_get_preferred_tx_dcid(QUIC_RCIDM *rcidm,
658*e7be843bSPierre Pronchery                                           QUIC_CONN_ID *tx_dcid)
659*e7be843bSPierre Pronchery {
660*e7be843bSPierre Pronchery     if (!rcidm->have_preferred_rcid)
661*e7be843bSPierre Pronchery         return 0;
662*e7be843bSPierre Pronchery 
663*e7be843bSPierre Pronchery     *tx_dcid = rcidm->preferred_rcid;
664*e7be843bSPierre Pronchery     return 1;
665*e7be843bSPierre Pronchery }
666*e7be843bSPierre Pronchery 
ossl_quic_rcidm_get_preferred_tx_dcid_changed(QUIC_RCIDM * rcidm,int clear)667*e7be843bSPierre Pronchery int ossl_quic_rcidm_get_preferred_tx_dcid_changed(QUIC_RCIDM *rcidm,
668*e7be843bSPierre Pronchery                                                   int clear)
669*e7be843bSPierre Pronchery {
670*e7be843bSPierre Pronchery     int r = rcidm->preferred_rcid_changed;
671*e7be843bSPierre Pronchery 
672*e7be843bSPierre Pronchery     if (clear)
673*e7be843bSPierre Pronchery         rcidm->preferred_rcid_changed = 0;
674*e7be843bSPierre Pronchery 
675*e7be843bSPierre Pronchery     return r;
676*e7be843bSPierre Pronchery }
677*e7be843bSPierre Pronchery 
ossl_quic_rcidm_get_num_active(const QUIC_RCIDM * rcidm)678*e7be843bSPierre Pronchery size_t ossl_quic_rcidm_get_num_active(const QUIC_RCIDM *rcidm)
679*e7be843bSPierre Pronchery {
680*e7be843bSPierre Pronchery     return ossl_pqueue_RCID_num(rcidm->rcids)
681*e7be843bSPierre Pronchery         + (rcidm->cur_rcid != NULL ? 1 : 0)
682*e7be843bSPierre Pronchery         + ossl_quic_rcidm_get_num_retiring(rcidm);
683*e7be843bSPierre Pronchery }
684*e7be843bSPierre Pronchery 
ossl_quic_rcidm_get_num_retiring(const QUIC_RCIDM * rcidm)685*e7be843bSPierre Pronchery size_t ossl_quic_rcidm_get_num_retiring(const QUIC_RCIDM *rcidm)
686*e7be843bSPierre Pronchery {
687*e7be843bSPierre Pronchery     return rcidm->num_retiring;
688*e7be843bSPierre Pronchery }
689