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