/src/openssl36/ssl/quic/quic_lcidm.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. |
3 | | * |
4 | | * Licensed under the Apache License 2.0 (the "License"). You may not use |
5 | | * this file except in compliance with the License. You can obtain a copy |
6 | | * in the file LICENSE in the source distribution or at |
7 | | * https://www.openssl.org/source/license.html |
8 | | */ |
9 | | |
10 | | #include "internal/quic_lcidm.h" |
11 | | #include "internal/quic_types.h" |
12 | | #include "internal/quic_vlint.h" |
13 | | #include "internal/common.h" |
14 | | #include "crypto/siphash.h" |
15 | | #include <openssl/lhash.h> |
16 | | #include <openssl/rand.h> |
17 | | #include <openssl/err.h> |
18 | | |
19 | | /* |
20 | | * QUIC Local Connection ID Manager |
21 | | * ================================ |
22 | | */ |
23 | | |
24 | | typedef struct quic_lcidm_conn_st QUIC_LCIDM_CONN; |
25 | | |
26 | | enum { |
27 | | LCID_TYPE_ODCID, /* This LCID is the ODCID from the peer */ |
28 | | LCID_TYPE_INITIAL, /* This is our Initial SCID */ |
29 | | LCID_TYPE_NCID /* This LCID was issued via a NCID frame */ |
30 | | }; |
31 | | |
32 | | typedef struct quic_lcid_st { |
33 | | QUIC_CONN_ID cid; |
34 | | uint64_t seq_num; |
35 | | |
36 | | /* copy of the hash key from lcidm */ |
37 | | uint64_t *hash_key; |
38 | | |
39 | | /* Back-pointer to the owning QUIC_LCIDM_CONN structure. */ |
40 | | QUIC_LCIDM_CONN *conn; |
41 | | |
42 | | /* LCID_TYPE_* */ |
43 | | unsigned int type : 2; |
44 | | } QUIC_LCID; |
45 | | |
46 | | DEFINE_LHASH_OF_EX(QUIC_LCID); |
47 | | DEFINE_LHASH_OF_EX(QUIC_LCIDM_CONN); |
48 | | |
49 | | struct quic_lcidm_conn_st { |
50 | | size_t num_active_lcid; |
51 | | LHASH_OF(QUIC_LCID) *lcids; |
52 | | void *opaque; |
53 | | QUIC_LCID *odcid_lcid_obj; |
54 | | uint64_t next_seq_num; |
55 | | |
56 | | /* Have we enrolled an ODCID? */ |
57 | | unsigned int done_odcid : 1; |
58 | | }; |
59 | | |
60 | | struct quic_lcidm_st { |
61 | | OSSL_LIB_CTX *libctx; |
62 | | uint64_t hash_key[2]; /* random key for siphash */ |
63 | | LHASH_OF(QUIC_LCID) *lcids; /* (QUIC_CONN_ID) -> (QUIC_LCID *) */ |
64 | | LHASH_OF(QUIC_LCIDM_CONN) *conns; /* (void *opaque) -> (QUIC_LCIDM_CONN *) */ |
65 | | size_t lcid_len; /* Length in bytes for all LCIDs */ |
66 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
67 | | QUIC_CONN_ID next_lcid; |
68 | | #endif |
69 | | }; |
70 | | |
71 | | static unsigned long lcid_hash(const QUIC_LCID *lcid_obj) |
72 | 6.89M | { |
73 | 6.89M | SIPHASH siphash = { |
74 | 6.89M | 0, |
75 | 6.89M | }; |
76 | 6.89M | unsigned long hashval = 0; |
77 | | |
78 | 6.89M | if (!SipHash_set_hash_size(&siphash, sizeof(unsigned long))) |
79 | 0 | goto out; |
80 | 6.89M | if (!SipHash_Init(&siphash, (uint8_t *)lcid_obj->hash_key, 0, 0)) |
81 | 0 | goto out; |
82 | 6.89M | SipHash_Update(&siphash, lcid_obj->cid.id, lcid_obj->cid.id_len); |
83 | 6.89M | if (!SipHash_Final(&siphash, (unsigned char *)&hashval, |
84 | 6.89M | sizeof(unsigned long))) |
85 | 0 | goto out; |
86 | 6.89M | out: |
87 | 6.89M | return hashval; |
88 | 6.89M | } |
89 | | |
90 | | static int lcid_comp(const QUIC_LCID *a, const QUIC_LCID *b) |
91 | 11.0M | { |
92 | 11.0M | return !ossl_quic_conn_id_eq(&a->cid, &b->cid); |
93 | 11.0M | } |
94 | | |
95 | | static unsigned long lcidm_conn_hash(const QUIC_LCIDM_CONN *conn) |
96 | 3.47M | { |
97 | 3.47M | return (unsigned long)(uintptr_t)conn->opaque; |
98 | 3.47M | } |
99 | | |
100 | | static int lcidm_conn_comp(const QUIC_LCIDM_CONN *a, const QUIC_LCIDM_CONN *b) |
101 | 3.15M | { |
102 | 3.15M | return a->opaque != b->opaque; |
103 | 3.15M | } |
104 | | |
105 | | QUIC_LCIDM *ossl_quic_lcidm_new(OSSL_LIB_CTX *libctx, size_t lcid_len) |
106 | 33.1k | { |
107 | 33.1k | QUIC_LCIDM *lcidm = NULL; |
108 | | |
109 | 33.1k | if (lcid_len > QUIC_MAX_CONN_ID_LEN) |
110 | 0 | goto err; |
111 | | |
112 | 33.1k | if ((lcidm = OPENSSL_zalloc(sizeof(*lcidm))) == NULL) |
113 | 0 | goto err; |
114 | | |
115 | | /* generate a random key for the hash tables hash function */ |
116 | 33.1k | if (!RAND_bytes_ex(libctx, (unsigned char *)&lcidm->hash_key, |
117 | 33.1k | sizeof(uint64_t) * 2, 0)) |
118 | 0 | goto err; |
119 | | |
120 | 33.1k | if ((lcidm->lcids = lh_QUIC_LCID_new(lcid_hash, lcid_comp)) == NULL) |
121 | 0 | goto err; |
122 | | |
123 | 33.1k | if ((lcidm->conns = lh_QUIC_LCIDM_CONN_new(lcidm_conn_hash, |
124 | 33.1k | lcidm_conn_comp)) |
125 | 33.1k | == NULL) |
126 | 0 | goto err; |
127 | | |
128 | 33.1k | lcidm->libctx = libctx; |
129 | 33.1k | lcidm->lcid_len = lcid_len; |
130 | 33.1k | return lcidm; |
131 | | |
132 | 0 | err: |
133 | 0 | if (lcidm != NULL) { |
134 | 0 | lh_QUIC_LCID_free(lcidm->lcids); |
135 | 0 | lh_QUIC_LCIDM_CONN_free(lcidm->conns); |
136 | 0 | OPENSSL_free(lcidm); |
137 | 0 | } |
138 | 0 | return NULL; |
139 | 33.1k | } |
140 | | |
141 | | static void lcidm_delete_conn(QUIC_LCIDM *lcidm, QUIC_LCIDM_CONN *conn); |
142 | | |
143 | | static void lcidm_delete_conn_(QUIC_LCIDM_CONN *conn, void *arg) |
144 | 69.1k | { |
145 | 69.1k | lcidm_delete_conn((QUIC_LCIDM *)arg, conn); |
146 | 69.1k | } |
147 | | |
148 | | void ossl_quic_lcidm_free(QUIC_LCIDM *lcidm) |
149 | 56.6k | { |
150 | 56.6k | if (lcidm == NULL) |
151 | 19 | return; |
152 | | |
153 | | /* |
154 | | * Calling OPENSSL_lh_delete during a doall call is unsafe with our |
155 | | * current LHASH implementation for several reasons: |
156 | | * |
157 | | * - firstly, because deletes can cause the hashtable to be contracted, |
158 | | * resulting in rehashing which might cause items in later buckets to |
159 | | * move to earlier buckets, which might cause doall to skip an item, |
160 | | * resulting in a memory leak; |
161 | | * |
162 | | * - secondly, because doall in general is not safe across hashtable |
163 | | * size changes, as it caches hashtable size and pointer values |
164 | | * while operating. |
165 | | * |
166 | | * The fix for this is to disable hashtable contraction using the following |
167 | | * call, which guarantees that no rehashing will occur so long as we only |
168 | | * call delete and not insert. |
169 | | */ |
170 | 56.5k | lh_QUIC_LCIDM_CONN_set_down_load(lcidm->conns, 0); |
171 | | |
172 | 56.5k | lh_QUIC_LCIDM_CONN_doall_arg(lcidm->conns, lcidm_delete_conn_, lcidm); |
173 | | |
174 | 56.5k | lh_QUIC_LCID_free(lcidm->lcids); |
175 | 56.5k | lh_QUIC_LCIDM_CONN_free(lcidm->conns); |
176 | 56.5k | OPENSSL_free(lcidm); |
177 | 56.5k | } |
178 | | |
179 | | static QUIC_LCID *lcidm_get0_lcid(const QUIC_LCIDM *lcidm, const QUIC_CONN_ID *lcid) |
180 | 4.89M | { |
181 | 4.89M | QUIC_LCID key; |
182 | | |
183 | 4.89M | key.cid = *lcid; |
184 | 4.89M | key.hash_key = (uint64_t *)lcidm->hash_key; |
185 | | |
186 | 4.89M | if (key.cid.id_len > QUIC_MAX_CONN_ID_LEN) |
187 | 0 | return NULL; |
188 | | |
189 | 4.89M | return lh_QUIC_LCID_retrieve(lcidm->lcids, &key); |
190 | 4.89M | } |
191 | | |
192 | | static QUIC_LCIDM_CONN *lcidm_get0_conn(const QUIC_LCIDM *lcidm, void *opaque) |
193 | 3.01M | { |
194 | 3.01M | QUIC_LCIDM_CONN key; |
195 | | |
196 | 3.01M | key.opaque = opaque; |
197 | | |
198 | 3.01M | return lh_QUIC_LCIDM_CONN_retrieve(lcidm->conns, &key); |
199 | 3.01M | } |
200 | | |
201 | | static QUIC_LCIDM_CONN *lcidm_upsert_conn(const QUIC_LCIDM *lcidm, void *opaque) |
202 | 3.01M | { |
203 | 3.01M | QUIC_LCIDM_CONN *conn = lcidm_get0_conn(lcidm, opaque); |
204 | | |
205 | 3.01M | if (conn != NULL) |
206 | 2.88M | return conn; |
207 | | |
208 | 136k | if ((conn = OPENSSL_zalloc(sizeof(*conn))) == NULL) |
209 | 0 | goto err; |
210 | | |
211 | 136k | if ((conn->lcids = lh_QUIC_LCID_new(lcid_hash, lcid_comp)) == NULL) |
212 | 0 | goto err; |
213 | | |
214 | 136k | conn->opaque = opaque; |
215 | | |
216 | 136k | lh_QUIC_LCIDM_CONN_insert(lcidm->conns, conn); |
217 | 136k | if (lh_QUIC_LCIDM_CONN_error(lcidm->conns)) |
218 | 0 | goto err; |
219 | | |
220 | 136k | return conn; |
221 | | |
222 | 0 | err: |
223 | 0 | if (conn != NULL) { |
224 | 0 | lh_QUIC_LCID_free(conn->lcids); |
225 | 0 | OPENSSL_free(conn); |
226 | 0 | } |
227 | 0 | return NULL; |
228 | 136k | } |
229 | | |
230 | | static void lcidm_delete_conn_lcid(QUIC_LCIDM *lcidm, QUIC_LCID *lcid_obj) |
231 | 2.72M | { |
232 | 2.72M | lh_QUIC_LCID_delete(lcidm->lcids, lcid_obj); |
233 | 2.72M | lh_QUIC_LCID_delete(lcid_obj->conn->lcids, lcid_obj); |
234 | 2.72M | assert(lcid_obj->conn->num_active_lcid > 0); |
235 | 2.72M | --lcid_obj->conn->num_active_lcid; |
236 | 2.72M | OPENSSL_free(lcid_obj); |
237 | 2.72M | } |
238 | | |
239 | | /* doall_arg wrapper */ |
240 | | static void lcidm_delete_conn_lcid_(QUIC_LCID *lcid_obj, void *arg) |
241 | 2.69M | { |
242 | 2.69M | lcidm_delete_conn_lcid((QUIC_LCIDM *)arg, lcid_obj); |
243 | 2.69M | } |
244 | | |
245 | | static void lcidm_delete_conn(QUIC_LCIDM *lcidm, QUIC_LCIDM_CONN *conn) |
246 | 136k | { |
247 | | /* See comment in ossl_quic_lcidm_free */ |
248 | 136k | lh_QUIC_LCID_set_down_load(conn->lcids, 0); |
249 | | |
250 | 136k | lh_QUIC_LCID_doall_arg(conn->lcids, lcidm_delete_conn_lcid_, lcidm); |
251 | 136k | lh_QUIC_LCIDM_CONN_delete(lcidm->conns, conn); |
252 | 136k | lh_QUIC_LCID_free(conn->lcids); |
253 | 136k | OPENSSL_free(conn); |
254 | 136k | } |
255 | | |
256 | | static QUIC_LCID *lcidm_conn_new_lcid(QUIC_LCIDM *lcidm, QUIC_LCIDM_CONN *conn, |
257 | | const QUIC_CONN_ID *lcid) |
258 | 2.72M | { |
259 | 2.72M | QUIC_LCID *lcid_obj = NULL; |
260 | | |
261 | 2.72M | if (lcid->id_len > QUIC_MAX_CONN_ID_LEN) |
262 | 0 | return NULL; |
263 | | |
264 | 2.72M | if ((lcid_obj = OPENSSL_zalloc(sizeof(*lcid_obj))) == NULL) |
265 | 0 | goto err; |
266 | | |
267 | 2.72M | lcid_obj->cid = *lcid; |
268 | 2.72M | lcid_obj->conn = conn; |
269 | 2.72M | lcid_obj->hash_key = lcidm->hash_key; |
270 | | |
271 | 2.72M | lh_QUIC_LCID_insert(conn->lcids, lcid_obj); |
272 | 2.72M | if (lh_QUIC_LCID_error(conn->lcids)) |
273 | 0 | goto err; |
274 | | |
275 | 2.72M | lh_QUIC_LCID_insert(lcidm->lcids, lcid_obj); |
276 | 2.72M | if (lh_QUIC_LCID_error(lcidm->lcids)) { |
277 | 0 | lh_QUIC_LCID_delete(conn->lcids, lcid_obj); |
278 | 0 | goto err; |
279 | 0 | } |
280 | | |
281 | 2.72M | ++conn->num_active_lcid; |
282 | 2.72M | return lcid_obj; |
283 | | |
284 | 0 | err: |
285 | 0 | OPENSSL_free(lcid_obj); |
286 | 0 | return NULL; |
287 | 2.72M | } |
288 | | |
289 | | size_t ossl_quic_lcidm_get_lcid_len(const QUIC_LCIDM *lcidm) |
290 | 0 | { |
291 | 0 | return lcidm->lcid_len; |
292 | 0 | } |
293 | | |
294 | | size_t ossl_quic_lcidm_get_num_active_lcid(const QUIC_LCIDM *lcidm, |
295 | | void *opaque) |
296 | 0 | { |
297 | 0 | QUIC_LCIDM_CONN *conn; |
298 | |
|
299 | 0 | conn = lcidm_get0_conn(lcidm, opaque); |
300 | 0 | if (conn == NULL) |
301 | 0 | return 0; |
302 | | |
303 | 0 | return conn->num_active_lcid; |
304 | 0 | } |
305 | | |
306 | | static int lcidm_generate_cid(QUIC_LCIDM *lcidm, |
307 | | QUIC_CONN_ID *cid) |
308 | 3.66M | { |
309 | 3.66M | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
310 | 3.66M | int i; |
311 | | |
312 | 3.66M | lcidm->next_lcid.id_len = (unsigned char)lcidm->lcid_len; |
313 | 3.66M | *cid = lcidm->next_lcid; |
314 | | |
315 | 3.68M | for (i = lcidm->lcid_len - 1; i >= 0; --i) |
316 | 3.22M | if (++lcidm->next_lcid.id[i] != 0) |
317 | 3.21M | break; |
318 | | |
319 | 3.66M | return 1; |
320 | | #else |
321 | | return ossl_quic_gen_rand_conn_id(lcidm->libctx, lcidm->lcid_len, cid); |
322 | | #endif |
323 | 3.66M | } |
324 | | |
325 | | static int lcidm_generate(QUIC_LCIDM *lcidm, |
326 | | void *opaque, |
327 | | unsigned int type, |
328 | | QUIC_CONN_ID *lcid_out, |
329 | | uint64_t *seq_num) |
330 | 2.95M | { |
331 | 2.95M | QUIC_LCIDM_CONN *conn; |
332 | 2.95M | QUIC_LCID key, *lcid_obj; |
333 | 2.95M | size_t i; |
334 | 3.78M | #define MAX_RETRIES 8 |
335 | | |
336 | 2.95M | if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL) |
337 | 0 | return 0; |
338 | | |
339 | 2.95M | if ((type == LCID_TYPE_INITIAL && conn->next_seq_num > 0) |
340 | 2.82M | || conn->next_seq_num > OSSL_QUIC_VLINT_MAX) |
341 | 126k | return 0; |
342 | | |
343 | 2.82M | i = 0; |
344 | 3.78M | do { |
345 | 3.78M | if (i++ >= MAX_RETRIES) |
346 | | /* |
347 | | * Too many retries; should not happen but if it does, don't loop |
348 | | * endlessly. |
349 | | */ |
350 | 118k | return 0; |
351 | | |
352 | 3.66M | if (!lcidm_generate_cid(lcidm, lcid_out)) |
353 | 0 | return 0; |
354 | | |
355 | 3.66M | key.cid = *lcid_out; |
356 | 3.66M | key.hash_key = lcidm->hash_key; |
357 | | |
358 | | /* If a collision occurs, retry. */ |
359 | 3.66M | } while (lh_QUIC_LCID_retrieve(lcidm->lcids, &key) != NULL); |
360 | | |
361 | 2.70M | if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, lcid_out)) == NULL) |
362 | 0 | return 0; |
363 | | |
364 | 2.70M | lcid_obj->seq_num = conn->next_seq_num; |
365 | 2.70M | lcid_obj->type = type; |
366 | | |
367 | 2.70M | if (seq_num != NULL) |
368 | 2.63M | *seq_num = lcid_obj->seq_num; |
369 | | |
370 | 2.70M | ++conn->next_seq_num; |
371 | 2.70M | return 1; |
372 | 2.70M | } |
373 | | |
374 | | int ossl_quic_lcidm_enrol_odcid(QUIC_LCIDM *lcidm, |
375 | | void *opaque, |
376 | | const QUIC_CONN_ID *initial_odcid) |
377 | 735k | { |
378 | 735k | QUIC_LCIDM_CONN *conn; |
379 | 735k | QUIC_LCID key, *lcid_obj; |
380 | | |
381 | 735k | if (initial_odcid == NULL || initial_odcid->id_len < QUIC_MIN_ODCID_LEN |
382 | 24.9k | || initial_odcid->id_len > QUIC_MAX_CONN_ID_LEN) |
383 | 710k | return 0; |
384 | | |
385 | 24.9k | if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL) |
386 | 0 | return 0; |
387 | | |
388 | 24.9k | if (conn->done_odcid) |
389 | 8.94k | return 0; |
390 | | |
391 | 15.9k | key.cid = *initial_odcid; |
392 | 15.9k | key.hash_key = lcidm->hash_key; |
393 | 15.9k | if (lh_QUIC_LCID_retrieve(lcidm->lcids, &key) != NULL) |
394 | 3.79k | return 0; |
395 | | |
396 | 12.1k | if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, initial_odcid)) == NULL) |
397 | 0 | return 0; |
398 | | |
399 | 12.1k | lcid_obj->seq_num = LCIDM_ODCID_SEQ_NUM; |
400 | 12.1k | lcid_obj->type = LCID_TYPE_ODCID; |
401 | | |
402 | 12.1k | conn->odcid_lcid_obj = lcid_obj; |
403 | 12.1k | conn->done_odcid = 1; |
404 | 12.1k | return 1; |
405 | 12.1k | } |
406 | | |
407 | | int ossl_quic_lcidm_generate_initial(QUIC_LCIDM *lcidm, |
408 | | void *opaque, |
409 | | QUIC_CONN_ID *initial_lcid) |
410 | 214k | { |
411 | 214k | return lcidm_generate(lcidm, opaque, LCID_TYPE_INITIAL, |
412 | 214k | initial_lcid, NULL); |
413 | 214k | } |
414 | | |
415 | | int ossl_quic_lcidm_bind_channel(QUIC_LCIDM *lcidm, void *opaque, |
416 | | const QUIC_CONN_ID *lcid) |
417 | 0 | { |
418 | 0 | QUIC_LCIDM_CONN *conn; |
419 | 0 | QUIC_LCID *lcid_obj; |
420 | | |
421 | | /* |
422 | | * the plan is simple: |
423 | | * make sure the lcid is still unused. |
424 | | * do the same business as ossl_quic_lcidm_gnerate_initial() does, |
425 | | * except we will use lcid instead of generating a new one. |
426 | | */ |
427 | 0 | if (ossl_quic_lcidm_lookup(lcidm, lcid, NULL, NULL) != 0) |
428 | 0 | return 0; |
429 | | |
430 | 0 | if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL) |
431 | 0 | return 0; |
432 | | |
433 | 0 | if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, lcid)) == NULL) { |
434 | 0 | lcidm_delete_conn(lcidm, conn); |
435 | 0 | return 0; |
436 | 0 | } |
437 | | |
438 | 0 | lcid_obj->seq_num = conn->next_seq_num; |
439 | 0 | lcid_obj->type = LCID_TYPE_INITIAL; |
440 | 0 | conn->next_seq_num++; |
441 | |
|
442 | 0 | return 1; |
443 | 0 | } |
444 | | |
445 | | int ossl_quic_lcidm_generate(QUIC_LCIDM *lcidm, |
446 | | void *opaque, |
447 | | OSSL_QUIC_FRAME_NEW_CONN_ID *ncid_frame) |
448 | 2.73M | { |
449 | 2.73M | ncid_frame->seq_num = 0; |
450 | 2.73M | ncid_frame->retire_prior_to = 0; |
451 | | |
452 | 2.73M | return lcidm_generate(lcidm, opaque, LCID_TYPE_NCID, |
453 | 2.73M | &ncid_frame->conn_id, |
454 | 2.73M | &ncid_frame->seq_num); |
455 | 2.73M | } |
456 | | |
457 | | int ossl_quic_lcidm_retire_odcid(QUIC_LCIDM *lcidm, void *opaque) |
458 | 40.6k | { |
459 | 40.6k | QUIC_LCIDM_CONN *conn; |
460 | | |
461 | 40.6k | if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL) |
462 | 0 | return 0; |
463 | | |
464 | 40.6k | if (conn->odcid_lcid_obj == NULL) |
465 | 33.4k | return 0; |
466 | | |
467 | 7.19k | lcidm_delete_conn_lcid(lcidm, conn->odcid_lcid_obj); |
468 | 7.19k | conn->odcid_lcid_obj = NULL; |
469 | 7.19k | return 1; |
470 | 40.6k | } |
471 | | |
472 | | struct retire_args { |
473 | | QUIC_LCID *earliest_seq_num_lcid_obj; |
474 | | uint64_t earliest_seq_num, retire_prior_to; |
475 | | }; |
476 | | |
477 | | static void retire_for_conn(QUIC_LCID *lcid_obj, void *arg) |
478 | 9.38M | { |
479 | 9.38M | struct retire_args *args = arg; |
480 | | |
481 | | /* ODCID LCID cannot be retired via this API */ |
482 | 9.38M | if (lcid_obj->type == LCID_TYPE_ODCID |
483 | 9.37M | || lcid_obj->seq_num >= args->retire_prior_to) |
484 | 2.06M | return; |
485 | | |
486 | 7.31M | if (lcid_obj->seq_num < args->earliest_seq_num) { |
487 | 226k | args->earliest_seq_num = lcid_obj->seq_num; |
488 | 226k | args->earliest_seq_num_lcid_obj = lcid_obj; |
489 | 226k | } |
490 | 7.31M | } |
491 | | |
492 | | int ossl_quic_lcidm_retire(QUIC_LCIDM *lcidm, |
493 | | void *opaque, |
494 | | uint64_t retire_prior_to, |
495 | | const QUIC_CONN_ID *containing_pkt_dcid, |
496 | | QUIC_CONN_ID *retired_lcid, |
497 | | uint64_t *retired_seq_num, |
498 | | int *did_retire) |
499 | 85.3k | { |
500 | 85.3k | QUIC_LCIDM_CONN key, *conn; |
501 | 85.3k | struct retire_args args = { 0 }; |
502 | | |
503 | 85.3k | key.opaque = opaque; |
504 | | |
505 | 85.3k | if (did_retire == NULL) |
506 | 0 | return 0; |
507 | | |
508 | 85.3k | *did_retire = 0; |
509 | 85.3k | if ((conn = lh_QUIC_LCIDM_CONN_retrieve(lcidm->conns, &key)) == NULL) |
510 | 19.8k | return 1; |
511 | | |
512 | 65.4k | args.retire_prior_to = retire_prior_to; |
513 | 65.4k | args.earliest_seq_num = UINT64_MAX; |
514 | | |
515 | 65.4k | lh_QUIC_LCID_doall_arg(conn->lcids, retire_for_conn, &args); |
516 | 65.4k | if (args.earliest_seq_num_lcid_obj == NULL) |
517 | 47.5k | return 1; |
518 | | |
519 | 17.9k | if (containing_pkt_dcid != NULL |
520 | 0 | && ossl_quic_conn_id_eq(&args.earliest_seq_num_lcid_obj->cid, |
521 | 0 | containing_pkt_dcid)) |
522 | 0 | return 0; |
523 | | |
524 | 17.9k | *did_retire = 1; |
525 | 17.9k | if (retired_lcid != NULL) |
526 | 17.9k | *retired_lcid = args.earliest_seq_num_lcid_obj->cid; |
527 | 17.9k | if (retired_seq_num != NULL) |
528 | 17.9k | *retired_seq_num = args.earliest_seq_num_lcid_obj->seq_num; |
529 | | |
530 | 17.9k | lcidm_delete_conn_lcid(lcidm, args.earliest_seq_num_lcid_obj); |
531 | 17.9k | return 1; |
532 | 17.9k | } |
533 | | |
534 | | int ossl_quic_lcidm_cull(QUIC_LCIDM *lcidm, void *opaque) |
535 | 102k | { |
536 | 102k | QUIC_LCIDM_CONN key, *conn; |
537 | | |
538 | 102k | key.opaque = opaque; |
539 | | |
540 | 102k | if ((conn = lh_QUIC_LCIDM_CONN_retrieve(lcidm->conns, &key)) == NULL) |
541 | 35.2k | return 0; |
542 | | |
543 | 66.8k | lcidm_delete_conn(lcidm, conn); |
544 | 66.8k | return 1; |
545 | 102k | } |
546 | | |
547 | | int ossl_quic_lcidm_lookup(QUIC_LCIDM *lcidm, |
548 | | const QUIC_CONN_ID *lcid, |
549 | | uint64_t *seq_num, |
550 | | void **opaque) |
551 | 4.89M | { |
552 | 4.89M | QUIC_LCID *lcid_obj; |
553 | | |
554 | 4.89M | if (lcid == NULL) |
555 | 0 | return 0; |
556 | | |
557 | 4.89M | if ((lcid_obj = lcidm_get0_lcid(lcidm, lcid)) == NULL) |
558 | 351k | return 0; |
559 | | |
560 | 4.54M | if (seq_num != NULL) |
561 | 22.4k | *seq_num = lcid_obj->seq_num; |
562 | | |
563 | 4.54M | if (opaque != NULL) |
564 | 4.54M | *opaque = lcid_obj->conn->opaque; |
565 | | |
566 | 4.54M | return 1; |
567 | 4.89M | } |
568 | | |
569 | | int ossl_quic_lcidm_debug_remove(QUIC_LCIDM *lcidm, |
570 | | const QUIC_CONN_ID *lcid) |
571 | 0 | { |
572 | 0 | QUIC_LCID key, *lcid_obj; |
573 | |
|
574 | 0 | key.cid = *lcid; |
575 | 0 | key.hash_key = lcidm->hash_key; |
576 | 0 | if ((lcid_obj = lh_QUIC_LCID_retrieve(lcidm->lcids, &key)) == NULL) |
577 | 0 | return 0; |
578 | | |
579 | 0 | lcidm_delete_conn_lcid(lcidm, lcid_obj); |
580 | 0 | return 1; |
581 | 0 | } |
582 | | |
583 | | int ossl_quic_lcidm_debug_add(QUIC_LCIDM *lcidm, void *opaque, |
584 | | const QUIC_CONN_ID *lcid, |
585 | | uint64_t seq_num) |
586 | 0 | { |
587 | 0 | QUIC_LCIDM_CONN *conn; |
588 | 0 | QUIC_LCID key, *lcid_obj; |
589 | |
|
590 | 0 | if (lcid == NULL || lcid->id_len > QUIC_MAX_CONN_ID_LEN) |
591 | 0 | return 0; |
592 | | |
593 | 0 | if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL) |
594 | 0 | return 0; |
595 | | |
596 | 0 | key.cid = *lcid; |
597 | 0 | key.hash_key = lcidm->hash_key; |
598 | 0 | if (lh_QUIC_LCID_retrieve(lcidm->lcids, &key) != NULL) |
599 | 0 | return 0; |
600 | | |
601 | 0 | if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, lcid)) == NULL) |
602 | 0 | return 0; |
603 | | |
604 | 0 | lcid_obj->seq_num = seq_num; |
605 | 0 | lcid_obj->type = LCID_TYPE_NCID; |
606 | 0 | return 1; |
607 | 0 | } |
608 | | |
609 | | int ossl_quic_lcidm_get_unused_cid(QUIC_LCIDM *lcidm, QUIC_CONN_ID *cid) |
610 | 0 | { |
611 | 0 | int i; |
612 | |
|
613 | 0 | for (i = 0; i < 10; i++) { |
614 | 0 | if (lcidm_generate_cid(lcidm, cid) |
615 | 0 | && lcidm_get0_lcid(lcidm, cid) == NULL) |
616 | 0 | return 1; /* not found <=> radomly generated cid is unused */ |
617 | 0 | } |
618 | | |
619 | 0 | return 0; |
620 | 0 | } |