Coverage Report

Created: 2025-08-28 07:07

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