Coverage Report

Created: 2026-07-23 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl36/ssl/quic/quic_lcidm.c
Line
Count
Source
1
/*
2
 * Copyright 2023-2026 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.63M
{
73
6.63M
    SIPHASH siphash = {
74
6.63M
        0,
75
6.63M
    };
76
6.63M
    unsigned long hashval = 0;
77
6.63M
    unsigned char digest[SIPHASH_MIN_DIGEST_SIZE];
78
79
    /* Use a supported SipHash digest size (8 or 16); 8 is sufficient here. */
80
6.63M
    if (!SipHash_set_hash_size(&siphash, SIPHASH_MIN_DIGEST_SIZE))
81
0
        goto out;
82
6.63M
    if (!SipHash_Init(&siphash, (uint8_t *)lcid_obj->hash_key, 0, 0))
83
0
        goto out;
84
6.63M
    SipHash_Update(&siphash, lcid_obj->cid.id, lcid_obj->cid.id_len);
85
6.63M
    if (!SipHash_Final(&siphash, digest, SIPHASH_MIN_DIGEST_SIZE))
86
0
        goto out;
87
88
    /*
89
     * Truncate the 64-bit SipHash digest into an unsigned long.
90
     */
91
6.63M
    memcpy(&hashval, digest, sizeof(hashval) < sizeof(digest) ? sizeof(hashval) : sizeof(digest));
92
6.63M
out:
93
6.63M
    return hashval;
94
6.63M
}
95
96
static int lcid_comp(const QUIC_LCID *a, const QUIC_LCID *b)
97
12.2M
{
98
12.2M
    return !ossl_quic_conn_id_eq(&a->cid, &b->cid);
99
12.2M
}
100
101
static unsigned long lcidm_conn_hash(const QUIC_LCIDM_CONN *conn)
102
4.29M
{
103
4.29M
    return (unsigned long)(uintptr_t)conn->opaque;
104
4.29M
}
105
106
static int lcidm_conn_comp(const QUIC_LCIDM_CONN *a, const QUIC_LCIDM_CONN *b)
107
3.76M
{
108
3.76M
    return a->opaque != b->opaque;
109
3.76M
}
110
111
QUIC_LCIDM *ossl_quic_lcidm_new(OSSL_LIB_CTX *libctx, size_t lcid_len)
112
31.5k
{
113
31.5k
    QUIC_LCIDM *lcidm = NULL;
114
115
31.5k
    if (lcid_len > QUIC_MAX_CONN_ID_LEN)
116
0
        goto err;
117
118
31.5k
    if ((lcidm = OPENSSL_zalloc(sizeof(*lcidm))) == NULL)
119
0
        goto err;
120
121
    /* generate a random key for the hash tables hash function */
122
31.5k
    if (!RAND_bytes_ex(libctx, (unsigned char *)&lcidm->hash_key,
123
31.5k
            sizeof(uint64_t) * 2, 0))
124
0
        goto err;
125
126
31.5k
    if ((lcidm->lcids = lh_QUIC_LCID_new(lcid_hash, lcid_comp)) == NULL)
127
0
        goto err;
128
129
31.5k
    if ((lcidm->conns = lh_QUIC_LCIDM_CONN_new(lcidm_conn_hash,
130
31.5k
             lcidm_conn_comp))
131
31.5k
        == NULL)
132
0
        goto err;
133
134
31.5k
    lcidm->libctx = libctx;
135
31.5k
    lcidm->lcid_len = lcid_len;
136
31.5k
    return lcidm;
137
138
0
err:
139
0
    if (lcidm != NULL) {
140
0
        lh_QUIC_LCID_free(lcidm->lcids);
141
0
        lh_QUIC_LCIDM_CONN_free(lcidm->conns);
142
0
        OPENSSL_free(lcidm);
143
0
    }
144
0
    return NULL;
145
31.5k
}
146
147
static void lcidm_delete_conn(QUIC_LCIDM *lcidm, QUIC_LCIDM_CONN *conn);
148
149
static void lcidm_delete_conn_(QUIC_LCIDM_CONN *conn, void *arg)
150
73.5k
{
151
73.5k
    lcidm_delete_conn((QUIC_LCIDM *)arg, conn);
152
73.5k
}
153
154
void ossl_quic_lcidm_free(QUIC_LCIDM *lcidm)
155
56.2k
{
156
56.2k
    if (lcidm == NULL)
157
18
        return;
158
159
    /*
160
     * Calling OPENSSL_lh_delete during a doall call is unsafe with our
161
     * current LHASH implementation for several reasons:
162
     *
163
     * - firstly, because deletes can cause the hashtable to be contracted,
164
     *   resulting in rehashing which might cause items in later buckets to
165
     *   move to earlier buckets, which might cause doall to skip an item,
166
     *   resulting in a memory leak;
167
     *
168
     * - secondly, because doall in general is not safe across hashtable
169
     *   size changes, as it caches hashtable size and pointer values
170
     *   while operating.
171
     *
172
     * The fix for this is to disable hashtable contraction using the following
173
     * call, which guarantees that no rehashing will occur so long as we only
174
     * call delete and not insert.
175
     */
176
56.2k
    lh_QUIC_LCIDM_CONN_set_down_load(lcidm->conns, 0);
177
178
56.2k
    lh_QUIC_LCIDM_CONN_doall_arg(lcidm->conns, lcidm_delete_conn_, lcidm);
179
180
56.2k
    lh_QUIC_LCID_free(lcidm->lcids);
181
56.2k
    lh_QUIC_LCIDM_CONN_free(lcidm->conns);
182
56.2k
    OPENSSL_free(lcidm);
183
56.2k
}
184
185
static QUIC_LCID *lcidm_get0_lcid(const QUIC_LCIDM *lcidm, const QUIC_CONN_ID *lcid)
186
4.51M
{
187
4.51M
    QUIC_LCID key;
188
189
4.51M
    key.cid = *lcid;
190
4.51M
    key.hash_key = (uint64_t *)lcidm->hash_key;
191
192
4.51M
    if (key.cid.id_len > QUIC_MAX_CONN_ID_LEN)
193
0
        return NULL;
194
195
4.51M
    return lh_QUIC_LCID_retrieve(lcidm->lcids, &key);
196
4.51M
}
197
198
static QUIC_LCIDM_CONN *lcidm_get0_conn(const QUIC_LCIDM *lcidm, void *opaque)
199
3.59M
{
200
3.59M
    QUIC_LCIDM_CONN key;
201
202
3.59M
    key.opaque = opaque;
203
204
3.59M
    return lh_QUIC_LCIDM_CONN_retrieve(lcidm->conns, &key);
205
3.59M
}
206
207
static QUIC_LCIDM_CONN *lcidm_upsert_conn(const QUIC_LCIDM *lcidm, void *opaque)
208
3.59M
{
209
3.59M
    QUIC_LCIDM_CONN *conn = lcidm_get0_conn(lcidm, opaque);
210
211
3.59M
    if (conn != NULL)
212
3.45M
        return conn;
213
214
136k
    if ((conn = OPENSSL_zalloc(sizeof(*conn))) == NULL)
215
0
        goto err;
216
217
136k
    if ((conn->lcids = lh_QUIC_LCID_new(lcid_hash, lcid_comp)) == NULL)
218
0
        goto err;
219
220
136k
    conn->opaque = opaque;
221
222
136k
    lh_QUIC_LCIDM_CONN_insert(lcidm->conns, conn);
223
136k
    if (lh_QUIC_LCIDM_CONN_error(lcidm->conns))
224
0
        goto err;
225
226
136k
    return conn;
227
228
0
err:
229
0
    if (conn != NULL) {
230
0
        lh_QUIC_LCID_free(conn->lcids);
231
0
        OPENSSL_free(conn);
232
0
    }
233
0
    return NULL;
234
136k
}
235
236
static void lcidm_delete_conn_lcid(QUIC_LCIDM *lcidm, QUIC_LCID *lcid_obj)
237
3.27M
{
238
3.27M
    lh_QUIC_LCID_delete(lcidm->lcids, lcid_obj);
239
3.27M
    lh_QUIC_LCID_delete(lcid_obj->conn->lcids, lcid_obj);
240
3.27M
    assert(lcid_obj->conn->num_active_lcid > 0);
241
3.27M
    --lcid_obj->conn->num_active_lcid;
242
3.27M
    OPENSSL_free(lcid_obj);
243
3.27M
}
244
245
/* doall_arg wrapper */
246
static void lcidm_delete_conn_lcid_(QUIC_LCID *lcid_obj, void *arg)
247
3.24M
{
248
3.24M
    lcidm_delete_conn_lcid((QUIC_LCIDM *)arg, lcid_obj);
249
3.24M
}
250
251
static void lcidm_delete_conn(QUIC_LCIDM *lcidm, QUIC_LCIDM_CONN *conn)
252
136k
{
253
    /* See comment in ossl_quic_lcidm_free */
254
136k
    lh_QUIC_LCID_set_down_load(conn->lcids, 0);
255
256
136k
    lh_QUIC_LCID_doall_arg(conn->lcids, lcidm_delete_conn_lcid_, lcidm);
257
136k
    lh_QUIC_LCIDM_CONN_delete(lcidm->conns, conn);
258
136k
    lh_QUIC_LCID_free(conn->lcids);
259
136k
    OPENSSL_free(conn);
260
136k
}
261
262
static QUIC_LCID *lcidm_conn_new_lcid(QUIC_LCIDM *lcidm, QUIC_LCIDM_CONN *conn,
263
    const QUIC_CONN_ID *lcid)
264
3.27M
{
265
3.27M
    QUIC_LCID *lcid_obj = NULL;
266
267
3.27M
    if (lcid->id_len > QUIC_MAX_CONN_ID_LEN)
268
0
        return NULL;
269
270
3.27M
    if ((lcid_obj = OPENSSL_zalloc(sizeof(*lcid_obj))) == NULL)
271
0
        goto err;
272
273
3.27M
    lcid_obj->cid = *lcid;
274
3.27M
    lcid_obj->conn = conn;
275
3.27M
    lcid_obj->hash_key = lcidm->hash_key;
276
277
3.27M
    lh_QUIC_LCID_insert(conn->lcids, lcid_obj);
278
3.27M
    if (lh_QUIC_LCID_error(conn->lcids))
279
0
        goto err;
280
281
3.27M
    lh_QUIC_LCID_insert(lcidm->lcids, lcid_obj);
282
3.27M
    if (lh_QUIC_LCID_error(lcidm->lcids)) {
283
0
        lh_QUIC_LCID_delete(conn->lcids, lcid_obj);
284
0
        goto err;
285
0
    }
286
287
3.27M
    ++conn->num_active_lcid;
288
3.27M
    return lcid_obj;
289
290
0
err:
291
0
    OPENSSL_free(lcid_obj);
292
0
    return NULL;
293
3.27M
}
294
295
size_t ossl_quic_lcidm_get_lcid_len(const QUIC_LCIDM *lcidm)
296
0
{
297
0
    return lcidm->lcid_len;
298
0
}
299
300
size_t ossl_quic_lcidm_get_num_active_lcid(const QUIC_LCIDM *lcidm,
301
    void *opaque)
302
0
{
303
0
    QUIC_LCIDM_CONN *conn;
304
305
0
    conn = lcidm_get0_conn(lcidm, opaque);
306
0
    if (conn == NULL)
307
0
        return 0;
308
309
0
    return conn->num_active_lcid;
310
0
}
311
312
static int lcidm_generate_cid(QUIC_LCIDM *lcidm,
313
    QUIC_CONN_ID *cid)
314
4.67M
{
315
4.67M
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
316
4.67M
    int i;
317
318
4.67M
    lcidm->next_lcid.id_len = (unsigned char)lcidm->lcid_len;
319
4.67M
    *cid = lcidm->next_lcid;
320
321
4.68M
    for (i = lcidm->lcid_len - 1; i >= 0; --i)
322
3.72M
        if (++lcidm->next_lcid.id[i] != 0)
323
3.71M
            break;
324
325
4.67M
    return 1;
326
#else
327
    return ossl_quic_gen_rand_conn_id(lcidm->libctx, lcidm->lcid_len, cid);
328
#endif
329
4.67M
}
330
331
static int lcidm_generate(QUIC_LCIDM *lcidm,
332
    void *opaque,
333
    unsigned int type,
334
    QUIC_CONN_ID *lcid_out,
335
    uint64_t *seq_num)
336
3.53M
{
337
3.53M
    QUIC_LCIDM_CONN *conn;
338
3.53M
    QUIC_LCID key, *lcid_obj;
339
3.53M
    size_t i;
340
4.84M
#define MAX_RETRIES 8
341
342
3.53M
    if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL)
343
0
        return 0;
344
345
3.53M
    if ((type == LCID_TYPE_INITIAL && conn->next_seq_num > 0)
346
3.43M
        || conn->next_seq_num > OSSL_QUIC_VLINT_MAX)
347
99.4k
        return 0;
348
349
3.43M
    i = 0;
350
4.84M
    do {
351
4.84M
        if (i++ >= MAX_RETRIES)
352
            /*
353
             * Too many retries; should not happen but if it does, don't loop
354
             * endlessly.
355
             */
356
175k
            return 0;
357
358
4.67M
        if (!lcidm_generate_cid(lcidm, lcid_out))
359
0
            return 0;
360
361
4.67M
        key.cid = *lcid_out;
362
4.67M
        key.hash_key = lcidm->hash_key;
363
364
        /* If a collision occurs, retry. */
365
4.67M
    } while (lh_QUIC_LCID_retrieve(lcidm->lcids, &key) != NULL);
366
367
3.26M
    if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, lcid_out)) == NULL)
368
0
        return 0;
369
370
3.26M
    lcid_obj->seq_num = conn->next_seq_num;
371
3.26M
    lcid_obj->type = type;
372
373
3.26M
    if (seq_num != NULL)
374
3.18M
        *seq_num = lcid_obj->seq_num;
375
376
3.26M
    ++conn->next_seq_num;
377
3.26M
    return 1;
378
3.26M
}
379
380
int ossl_quic_lcidm_enrol_odcid(QUIC_LCIDM *lcidm,
381
    void *opaque,
382
    const QUIC_CONN_ID *initial_odcid)
383
888k
{
384
888k
    QUIC_LCIDM_CONN *conn;
385
888k
    QUIC_LCID key, *lcid_obj;
386
387
888k
    if (initial_odcid == NULL || initial_odcid->id_len < QUIC_MIN_ODCID_LEN
388
18.4k
        || initial_odcid->id_len > QUIC_MAX_CONN_ID_LEN)
389
869k
        return 0;
390
391
18.4k
    if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL)
392
0
        return 0;
393
394
18.4k
    if (conn->done_odcid)
395
7.84k
        return 0;
396
397
10.6k
    key.cid = *initial_odcid;
398
10.6k
    key.hash_key = lcidm->hash_key;
399
10.6k
    if (lh_QUIC_LCID_retrieve(lcidm->lcids, &key) != NULL)
400
2.38k
        return 0;
401
402
8.24k
    if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, initial_odcid)) == NULL)
403
0
        return 0;
404
405
8.24k
    lcid_obj->seq_num = LCIDM_ODCID_SEQ_NUM;
406
8.24k
    lcid_obj->type = LCID_TYPE_ODCID;
407
408
8.24k
    conn->odcid_lcid_obj = lcid_obj;
409
8.24k
    conn->done_odcid = 1;
410
8.24k
    return 1;
411
8.24k
}
412
413
int ossl_quic_lcidm_generate_initial(QUIC_LCIDM *lcidm,
414
    void *opaque,
415
    QUIC_CONN_ID *initial_lcid)
416
206k
{
417
206k
    return lcidm_generate(lcidm, opaque, LCID_TYPE_INITIAL,
418
206k
        initial_lcid, NULL);
419
206k
}
420
421
int ossl_quic_lcidm_bind_channel(QUIC_LCIDM *lcidm, void *opaque,
422
    const QUIC_CONN_ID *lcid)
423
0
{
424
0
    QUIC_LCIDM_CONN *conn;
425
0
    QUIC_LCID *lcid_obj;
426
427
    /*
428
     * the plan is simple:
429
     *   make sure the lcid is still unused.
430
     *   do the same business as ossl_quic_lcidm_gnerate_initial() does,
431
     *   except we will use lcid instead of generating a new one.
432
     */
433
0
    if (ossl_quic_lcidm_lookup(lcidm, lcid, NULL, NULL) != 0)
434
0
        return 0;
435
436
0
    if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL)
437
0
        return 0;
438
439
0
    if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, lcid)) == NULL) {
440
0
        lcidm_delete_conn(lcidm, conn);
441
0
        return 0;
442
0
    }
443
444
0
    lcid_obj->seq_num = conn->next_seq_num;
445
0
    lcid_obj->type = LCID_TYPE_INITIAL;
446
0
    conn->next_seq_num++;
447
448
0
    return 1;
449
0
}
450
451
int ossl_quic_lcidm_generate(QUIC_LCIDM *lcidm,
452
    void *opaque,
453
    OSSL_QUIC_FRAME_NEW_CONN_ID *ncid_frame)
454
3.33M
{
455
3.33M
    ncid_frame->seq_num = 0;
456
3.33M
    ncid_frame->retire_prior_to = 0;
457
458
3.33M
    return lcidm_generate(lcidm, opaque, LCID_TYPE_NCID,
459
3.33M
        &ncid_frame->conn_id,
460
3.33M
        &ncid_frame->seq_num);
461
3.33M
}
462
463
int ossl_quic_lcidm_retire_odcid(QUIC_LCIDM *lcidm, void *opaque)
464
38.1k
{
465
38.1k
    QUIC_LCIDM_CONN *conn;
466
467
38.1k
    if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL)
468
0
        return 0;
469
470
38.1k
    if (conn->odcid_lcid_obj == NULL)
471
33.9k
        return 0;
472
473
4.13k
    lcidm_delete_conn_lcid(lcidm, conn->odcid_lcid_obj);
474
4.13k
    conn->odcid_lcid_obj = NULL;
475
4.13k
    return 1;
476
38.1k
}
477
478
struct retire_args {
479
    QUIC_LCID *earliest_seq_num_lcid_obj;
480
    uint64_t earliest_seq_num, retire_prior_to;
481
};
482
483
static void retire_for_conn(QUIC_LCID *lcid_obj, void *arg)
484
8.77M
{
485
8.77M
    struct retire_args *args = arg;
486
487
    /* ODCID LCID cannot be retired via this API */
488
8.77M
    if (lcid_obj->type == LCID_TYPE_ODCID
489
8.75M
        || lcid_obj->seq_num >= args->retire_prior_to)
490
2.51M
        return;
491
492
6.26M
    if (lcid_obj->seq_num < args->earliest_seq_num) {
493
438k
        args->earliest_seq_num = lcid_obj->seq_num;
494
438k
        args->earliest_seq_num_lcid_obj = lcid_obj;
495
438k
    }
496
6.26M
}
497
498
int ossl_quic_lcidm_retire(QUIC_LCIDM *lcidm,
499
    void *opaque,
500
    uint64_t retire_prior_to,
501
    const QUIC_CONN_ID *containing_pkt_dcid,
502
    QUIC_CONN_ID *retired_lcid,
503
    uint64_t *retired_seq_num,
504
    int *did_retire)
505
146k
{
506
146k
    QUIC_LCIDM_CONN key, *conn;
507
146k
    struct retire_args args = { 0 };
508
509
146k
    key.opaque = opaque;
510
511
146k
    if (did_retire == NULL)
512
0
        return 0;
513
514
146k
    *did_retire = 0;
515
146k
    if ((conn = lh_QUIC_LCIDM_CONN_retrieve(lcidm->conns, &key)) == NULL)
516
36.4k
        return 1;
517
518
110k
    args.retire_prior_to = retire_prior_to;
519
110k
    args.earliest_seq_num = UINT64_MAX;
520
521
110k
    lh_QUIC_LCID_doall_arg(conn->lcids, retire_for_conn, &args);
522
110k
    if (args.earliest_seq_num_lcid_obj == NULL)
523
89.0k
        return 1;
524
525
21.4k
    if (containing_pkt_dcid != NULL
526
0
        && ossl_quic_conn_id_eq(&args.earliest_seq_num_lcid_obj->cid,
527
0
            containing_pkt_dcid))
528
0
        return 0;
529
530
21.4k
    *did_retire = 1;
531
21.4k
    if (retired_lcid != NULL)
532
21.4k
        *retired_lcid = args.earliest_seq_num_lcid_obj->cid;
533
21.4k
    if (retired_seq_num != NULL)
534
21.4k
        *retired_seq_num = args.earliest_seq_num_lcid_obj->seq_num;
535
536
21.4k
    lcidm_delete_conn_lcid(lcidm, args.earliest_seq_num_lcid_obj);
537
21.4k
    return 1;
538
21.4k
}
539
540
int ossl_quic_lcidm_cull(QUIC_LCIDM *lcidm, void *opaque)
541
282k
{
542
282k
    QUIC_LCIDM_CONN key, *conn;
543
544
282k
    key.opaque = opaque;
545
546
282k
    if ((conn = lh_QUIC_LCIDM_CONN_retrieve(lcidm->conns, &key)) == NULL)
547
219k
        return 0;
548
549
62.7k
    lcidm_delete_conn(lcidm, conn);
550
62.7k
    return 1;
551
282k
}
552
553
int ossl_quic_lcidm_lookup(QUIC_LCIDM *lcidm,
554
    const QUIC_CONN_ID *lcid,
555
    uint64_t *seq_num,
556
    void **opaque)
557
4.51M
{
558
4.51M
    QUIC_LCID *lcid_obj;
559
560
4.51M
    if (lcid == NULL)
561
0
        return 0;
562
563
4.51M
    if ((lcid_obj = lcidm_get0_lcid(lcidm, lcid)) == NULL)
564
343k
        return 0;
565
566
4.17M
    if (seq_num != NULL)
567
31.6k
        *seq_num = lcid_obj->seq_num;
568
569
4.17M
    if (opaque != NULL)
570
4.17M
        *opaque = lcid_obj->conn->opaque;
571
572
4.17M
    return 1;
573
4.51M
}
574
575
int ossl_quic_lcidm_debug_remove(QUIC_LCIDM *lcidm,
576
    const QUIC_CONN_ID *lcid)
577
0
{
578
0
    QUIC_LCID key, *lcid_obj;
579
580
0
    key.cid = *lcid;
581
0
    key.hash_key = lcidm->hash_key;
582
0
    if ((lcid_obj = lh_QUIC_LCID_retrieve(lcidm->lcids, &key)) == NULL)
583
0
        return 0;
584
585
0
    lcidm_delete_conn_lcid(lcidm, lcid_obj);
586
0
    return 1;
587
0
}
588
589
int ossl_quic_lcidm_debug_add(QUIC_LCIDM *lcidm, void *opaque,
590
    const QUIC_CONN_ID *lcid,
591
    uint64_t seq_num)
592
0
{
593
0
    QUIC_LCIDM_CONN *conn;
594
0
    QUIC_LCID key, *lcid_obj;
595
596
0
    if (lcid == NULL || lcid->id_len > QUIC_MAX_CONN_ID_LEN)
597
0
        return 0;
598
599
0
    if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL)
600
0
        return 0;
601
602
0
    key.cid = *lcid;
603
0
    key.hash_key = lcidm->hash_key;
604
0
    if (lh_QUIC_LCID_retrieve(lcidm->lcids, &key) != NULL)
605
0
        return 0;
606
607
0
    if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, lcid)) == NULL)
608
0
        return 0;
609
610
0
    lcid_obj->seq_num = seq_num;
611
0
    lcid_obj->type = LCID_TYPE_NCID;
612
0
    return 1;
613
0
}
614
615
int ossl_quic_lcidm_get_unused_cid(QUIC_LCIDM *lcidm, QUIC_CONN_ID *cid)
616
0
{
617
0
    int i;
618
619
0
    for (i = 0; i < 10; i++) {
620
0
        if (lcidm_generate_cid(lcidm, cid)
621
0
            && lcidm_get0_lcid(lcidm, cid) == NULL)
622
0
            return 1; /* not found <=> radomly generated cid is unused */
623
0
    }
624
625
0
    return 0;
626
0
}