lsquic_pr_queue.c revision 7ee41525
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_pr_queue.c -- packet request queue.
4 */
5
6#include <assert.h>
7#include <errno.h>
8#include <inttypes.h>
9#include <netinet/in.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/queue.h>
13#include <sys/socket.h>
14
15#include <openssl/aead.h>
16#include <openssl/rand.h>
17
18#include "lsquic.h"
19#include "lsquic_types.h"
20#include "lsquic_int_types.h"
21#include "lsquic_packet_common.h"
22#include "lsquic_packet_gquic.h"
23#include "lsquic_packet_out.h"
24#include "lsquic_packet_in.h"
25#include "lsquic_hash.h"
26#include "lsquic_conn.h"
27#include "lsquic_parse.h"
28#include "lsquic_malo.h"
29#include "lsquic_pr_queue.h"
30#include "lsquic_parse_common.h"
31#include "lsquic_tokgen.h"
32#include "lsquic_version.h"
33#include "lsquic_mm.h"
34#include "lsquic_engine_public.h"
35#include "lsquic_sizes.h"
36#include "lsquic_handshake.h"
37#include "lsquic_xxhash.h"
38
39#define LSQUIC_LOGGER_MODULE LSQLM_PRQ
40#include "lsquic_logger.h"
41
42#define MAX(a, b) ((a) > (b) ? (a) : (b))
43#define MIN(a, b) ((a) < (b) ? (a) : (b))
44
45
46static const struct conn_iface evanescent_conn_iface;
47
48
49struct packet_req
50{
51    struct lsquic_hash_elem     pr_hash_el;
52    lsquic_cid_t                pr_scid;
53    lsquic_cid_t                pr_dcid;
54    enum packet_req_type        pr_type;
55    enum pr_flags {
56        PR_GQUIC    = 1 << 0,
57    }                           pr_flags;
58    enum lsquic_version         pr_version;
59    unsigned                    pr_rst_sz;
60    struct network_path         pr_path;
61};
62
63
64struct evanescent_conn
65{
66    struct lsquic_conn          evc_conn;
67    struct packet_req          *evc_req;
68    struct pr_queue            *evc_queue;
69    struct lsquic_packet_out    evc_packet_out;
70    struct conn_cid_elem        evc_cces[1];
71    enum {
72        EVC_DROP    = 1 << 0,
73    }                           evc_flags;
74    unsigned char               evc_buf[0];
75};
76
77
78/* [draft-ietf-quic-transport-22], Section 17.2.1 */
79#define IQUIC_VERNEG_SIZE (1 /* Type */ + 4 /* Version (zero tag) */ \
80                + 1 /* DCIL */ + MAX_CID_LEN + 1 /* SCIL */ + MAX_CID_LEN + \
81                4 * N_LSQVER)
82
83
84struct pr_queue
85{
86    TAILQ_HEAD(, lsquic_conn)   prq_free_conns,
87                                prq_returned_conns;
88    struct malo                *prq_reqs_pool;
89    const struct lsquic_engine_public
90                               *prq_enpub;
91    struct lsquic_hash         *prq_reqs_hash;
92    unsigned                    prq_max_reqs;
93    unsigned                    prq_nreqs;
94    unsigned                    prq_max_conns;
95    unsigned                    prq_nconns;
96    unsigned                    prq_verneg_g_sz;  /* Size of prq_verneg_g_buf */
97    unsigned                    prq_pubres_g_sz;  /* Size of prq_pubres_g_buf */
98
99    /* GQUIC version negotiation and stateless reset packets are generated
100     * once, when the Packet Request Queue is created.  For each request,
101     * these buffers are simply copied and the connection ID is replaced.
102     *
103     * Since IETF QUIC uses variable-length connections IDs, we have to
104     * generate packets every time.
105     */
106    unsigned char               prq_pubres_g_buf[GQUIC_RESET_SZ];
107    unsigned char               prq_verneg_g_buf[1 + GQUIC_CID_LEN
108                                                                + N_LSQVER * 4];
109    /* We generate random nybbles in batches */
110#define NYBBLE_COUNT_BITS 4
111#define NYBBLE_COUNT (1 << NYBBLE_COUNT_BITS)
112#define NYBBLE_MASK (NYBBLE_COUNT - 1)
113    unsigned                    prq_rand_nybble_off;
114    uint8_t                     prq_rand_nybble_buf[NYBBLE_COUNT * 2];
115};
116
117
118static uint8_t
119get_rand_byte (struct pr_queue *);
120
121
122static int
123comp_reqs (const void *s1, const void *s2, size_t n)
124{
125    const struct packet_req *a, *b;
126
127    a = s1;
128    b = s2;
129    if (a->pr_type == b->pr_type && LSQUIC_CIDS_EQ(&a->pr_dcid, &b->pr_dcid))
130        return 0;
131    else
132        return -1;
133}
134
135
136static unsigned
137hash_req (const void *p, size_t len, unsigned seed)
138{
139    const struct packet_req *req;
140
141    req = p;
142    return XXH32(req->pr_dcid.idbuf, req->pr_dcid.len, seed);
143}
144
145
146struct pr_queue *
147prq_create (unsigned max_elems, unsigned max_conns,
148                        const struct lsquic_engine_public *enpub)
149{
150    const struct parse_funcs *pf;
151    struct pr_queue *prq;
152    struct malo *malo;
153    struct lsquic_hash *hash;
154    unsigned verneg_g_sz;
155    ssize_t prst_g_sz;
156    int len;
157
158    malo = lsquic_malo_create(sizeof(struct packet_req));
159    if (!malo)
160    {
161        LSQ_WARN("malo_create failed: %s", strerror(errno));
162        goto err0;
163    }
164
165
166    hash = lsquic_hash_create_ext(comp_reqs, hash_req);
167    if (!hash)
168    {
169        LSQ_WARN("cannot create hash");
170        goto err1;
171    }
172
173    prq = malloc(sizeof(*prq));
174    if (!prq)
175    {
176        LSQ_WARN("malloc failed: %s", strerror(errno));
177        goto err2;
178    }
179
180    const lsquic_cid_t cid = { .len = 8, };
181    pf = select_pf_by_ver(LSQVER_039);
182    len = lsquic_gquic_gen_ver_nego_pkt(prq->prq_verneg_g_buf,
183                    sizeof(prq->prq_verneg_g_buf), &cid,
184                    enpub->enp_settings.es_versions);
185    assert(len > 0);
186    if (len <= 0)
187    {
188        LSQ_ERROR("cannot generate version negotiation packet");
189        goto err3;
190    }
191    verneg_g_sz = (unsigned) len;
192
193    prst_g_sz = pf->pf_generate_simple_prst(0 /* This is just placeholder */,
194                                prq->prq_pubres_g_buf, sizeof(prq->prq_pubres_g_buf));
195    if (prst_g_sz < 0)
196    {
197        LSQ_ERROR("cannot generate public reset packet");
198        goto err3;
199    }
200
201    TAILQ_INIT(&prq->prq_free_conns);
202    TAILQ_INIT(&prq->prq_returned_conns);
203    prq->prq_reqs_hash = hash;
204    prq->prq_reqs_pool = malo;
205    prq->prq_max_reqs = max_elems;
206    prq->prq_nreqs = 0;
207    prq->prq_max_conns = max_conns;
208    prq->prq_nconns = 0;
209    prq->prq_verneg_g_sz = verneg_g_sz;
210    prq->prq_pubres_g_sz = (unsigned) prst_g_sz;
211    prq->prq_enpub       = enpub;
212    prq->prq_rand_nybble_off = 0;
213
214    LSQ_INFO("initialized queue of size %d", max_elems);
215
216    return prq;
217
218  err3:
219    free(prq);
220  err2:
221    lsquic_hash_destroy(hash);
222  err1:
223    lsquic_malo_destroy(malo);
224  err0:
225    return NULL;
226}
227
228
229void
230prq_destroy (struct pr_queue *prq)
231{
232    struct lsquic_conn *conn;
233
234    LSQ_INFO("destroy");
235    while ((conn = TAILQ_FIRST(&prq->prq_free_conns)))
236    {
237        TAILQ_REMOVE(&prq->prq_free_conns, conn, cn_next_pr);
238        free(conn);
239    }
240    lsquic_hash_destroy(prq->prq_reqs_hash);
241    lsquic_malo_destroy(prq->prq_reqs_pool);
242    free(prq);
243}
244
245
246static struct packet_req *
247get_req (struct pr_queue *prq)
248{
249    struct packet_req *req;
250    if (prq->prq_nreqs < prq->prq_max_reqs)
251    {
252        req = lsquic_malo_get(prq->prq_reqs_pool);
253        if (req)
254            ++prq->prq_nreqs;
255        else
256            LSQ_WARN("malo_get failed: %s", strerror(errno));
257        return req;
258    }
259    else
260        return NULL;
261}
262
263
264static void
265put_req (struct pr_queue *prq, struct packet_req *req)
266{
267    lsquic_malo_put(req);
268    --prq->prq_nreqs;
269}
270
271
272int
273lsquic_prq_new_req (struct pr_queue *prq, enum packet_req_type type,
274    unsigned flags, enum lsquic_version version, unsigned short data_sz,
275    const lsquic_cid_t *dcid, const lsquic_cid_t *scid, void *peer_ctx,
276    const struct sockaddr *local_addr, const struct sockaddr *peer_addr)
277{
278    struct packet_req *req;
279    unsigned max, size, rand;
280
281    if (type == PACKET_REQ_PUBRES && !(flags & PR_GQUIC))
282    {
283        if (data_sz <= IQUIC_MIN_SRST_SIZE)
284        {
285            LSQ_DEBUGC("not scheduling public reset: incoming packet for CID "
286                "%"CID_FMT" too small: %hu bytes", CID_BITS(dcid), data_sz);
287            return -1;
288        }
289        /* Use a random stateless reset size */
290        max = MIN(IQUIC_MAX_SRST_SIZE, data_sz - 1u);
291        if (max > IQUIC_MIN_SRST_SIZE)
292        {
293            rand = get_rand_byte(prq);
294            size = IQUIC_MIN_SRST_SIZE + rand % (max - IQUIC_MIN_SRST_SIZE);
295        }
296        else
297            size = IQUIC_MIN_SRST_SIZE;
298        LSQ_DEBUGC("selected %u-byte reset size for CID %"CID_FMT
299            " (range is [%u, %u])", size, CID_BITS(dcid),
300            IQUIC_MIN_SRST_SIZE, max);
301    }
302    else
303        size = 0;
304
305    req = get_req(prq);
306    if (!req)
307    {
308        LSQ_DEBUG("out of reqs: cannot allocated another one");
309        return -1;
310    }
311
312    req->pr_type     = type;
313    req->pr_dcid     = *dcid;
314    if (lsquic_hash_find(prq->prq_reqs_hash, req, sizeof(req)))
315    {
316        LSQ_DEBUG("request for this DCID and type already exists");
317        put_req(prq, req);
318        return -1;
319    }
320
321    req->pr_hash_el.qhe_flags = 0;
322    if (!lsquic_hash_insert(prq->prq_reqs_hash, req, sizeof(req),
323                                                    req, &req->pr_hash_el))
324    {
325        LSQ_DEBUG("could not insert req into hash");
326        put_req(prq, req);
327        return -1;
328    }
329
330    req->pr_flags    = flags;
331    req->pr_rst_sz   = size;
332    req->pr_version  = version;
333    req->pr_scid     = *scid;
334    req->pr_path.np_peer_ctx = peer_ctx;
335    memcpy(NP_LOCAL_SA(&req->pr_path), local_addr,
336                                            sizeof(req->pr_path.np_local_addr));
337    memcpy(NP_PEER_SA(&req->pr_path), peer_addr,
338                                            sizeof(req->pr_path.np_peer_addr));
339
340    LSQ_DEBUGC("scheduled %s packet for connection %"CID_FMT,
341                            lsquic_preqt2str[type], CID_BITS(&req->pr_dcid));
342    return 0;
343}
344
345
346int
347prq_new_req (struct pr_queue *prq, enum packet_req_type type,
348         const struct lsquic_packet_in *packet_in, void *peer_ctx,
349         const struct sockaddr *local_addr, const struct sockaddr *peer_addr)
350{
351    lsquic_ver_tag_t ver_tag;
352    enum lsquic_version version;
353    enum pr_flags flags;
354    lsquic_cid_t scid;
355
356    if (packet_in->pi_flags & PI_GQUIC)
357        flags = PR_GQUIC;
358    else
359        flags = 0;
360
361    if (packet_in->pi_quic_ver)
362    {
363        memcpy(&ver_tag, packet_in->pi_data + packet_in->pi_quic_ver,
364                                                            sizeof(ver_tag));
365        version = lsquic_tag2ver(ver_tag);
366    }
367    else /* Got to set it to something sensible... */
368        version = LSQVER_ID24;
369
370    lsquic_scid_from_packet_in(packet_in, &scid);
371    return lsquic_prq_new_req(prq, type, flags, version, packet_in->pi_data_sz,
372                &packet_in->pi_dcid, &scid, peer_ctx, local_addr, peer_addr);
373}
374
375
376static size_t
377max_bufsz (const struct pr_queue *prq)
378{
379    return  MAX(MAX(MAX(IQUIC_VERNEG_SIZE,
380                        IQUIC_MIN_SRST_SIZE),
381                        sizeof(prq->prq_verneg_g_buf)),
382                        sizeof(prq->prq_pubres_g_buf));
383}
384
385
386static struct evanescent_conn *
387get_evconn (struct pr_queue *prq)
388{
389    struct evanescent_conn *evconn;
390    struct lsquic_conn *lconn;
391    struct lsquic_packet_out *packet_out;
392    size_t bufsz;
393
394    if (prq->prq_nconns >= prq->prq_max_conns)
395    {   /* This deserves a warning */
396        LSQ_WARN("tried to get connection past limit of %u", prq->prq_max_conns);
397        return NULL;
398    }
399
400    lconn = TAILQ_FIRST(&prq->prq_free_conns);
401    if (lconn)
402    {
403        TAILQ_REMOVE(&prq->prq_free_conns, lconn, cn_next_pr);
404        evconn = (struct evanescent_conn *) lconn;
405        evconn->evc_flags = 0;
406        return evconn;
407    }
408
409    bufsz = max_bufsz(prq);
410    evconn = calloc(1, sizeof(*evconn) + bufsz);
411    if (!evconn)
412    {
413        LSQ_WARN("calloc failed: %s", strerror(errno));
414        return NULL;
415    }
416
417    /* These values stay the same between connection usages: */
418    evconn->evc_queue = prq;
419    lconn = &evconn->evc_conn;
420    lconn->cn_cces = evconn->evc_cces;
421    lconn->cn_cces_mask = 1;
422    lconn->cn_n_cces = sizeof(evconn->evc_cces) / sizeof(evconn->evc_cces[0]);
423    lconn->cn_if = &evanescent_conn_iface;
424    lconn->cn_flags = LSCONN_EVANESCENT;
425    packet_out = &evconn->evc_packet_out;
426    packet_out->po_flags = PO_NOENCRYPT;
427    packet_out->po_data = evconn->evc_buf;
428
429    return evconn;
430}
431
432
433static uint8_t
434get_rand_nybble (struct pr_queue *prq)
435{
436    uint8_t byte;
437
438    if (prq->prq_rand_nybble_off == 0)
439        RAND_bytes(prq->prq_rand_nybble_buf, sizeof(prq->prq_rand_nybble_buf));
440
441    byte = prq->prq_rand_nybble_buf[prq->prq_rand_nybble_off / 2];
442    if (prq->prq_rand_nybble_off & 1)
443        byte >>= 4;
444    else
445        byte &= 0xF;
446    prq->prq_rand_nybble_off = (prq->prq_rand_nybble_off + 1) & NYBBLE_MASK;
447    return byte;
448}
449
450
451static uint8_t
452get_rand_byte (struct pr_queue *prq)
453{
454    return (get_rand_nybble(prq) << 4) | get_rand_nybble(prq);
455}
456
457
458struct lsquic_conn *
459prq_next_conn (struct pr_queue *prq)
460{
461    struct evanescent_conn *evconn;
462    struct lsquic_conn *lconn;
463    struct lsquic_hash_elem *el;
464    struct packet_req *req;
465    struct lsquic_packet_out *packet_out;
466    int (*gen_verneg) (unsigned char *, size_t, const lsquic_cid_t *,
467                                    const lsquic_cid_t *, unsigned, uint8_t);
468    int len;
469
470    lconn = TAILQ_FIRST(&prq->prq_returned_conns);
471    if (lconn)
472    {
473        TAILQ_REMOVE(&prq->prq_returned_conns, lconn, cn_next_pr);
474        return lconn;
475    }
476
477    el = lsquic_hash_first(prq->prq_reqs_hash);
478    if (!el)           /* Nothing is queued */
479        return NULL;
480
481    evconn = get_evconn(prq);
482    if (!evconn)         /* Reached limit or malloc failed */
483        return NULL;
484
485    req = lsquic_hashelem_getdata(el);
486    packet_out = &evconn->evc_packet_out;
487    switch ((req->pr_type << 29) | req->pr_flags)
488    {
489    case (PACKET_REQ_VERNEG << 29) | PR_GQUIC:
490        packet_out->po_data_sz = prq->prq_verneg_g_sz;
491        packet_out->po_flags |= PO_VERNEG;
492        memcpy(packet_out->po_data, prq->prq_verneg_g_buf,
493                                                    prq->prq_verneg_g_sz);
494        memcpy(packet_out->po_data + 1, req->pr_dcid.idbuf, GQUIC_CID_LEN);
495        break;
496    case (PACKET_REQ_PUBRES << 29) | PR_GQUIC:
497        packet_out->po_flags &= ~PO_VERNEG;
498        packet_out->po_data_sz = prq->prq_pubres_g_sz;
499        memcpy(packet_out->po_data, prq->prq_pubres_g_buf,
500                                                    prq->prq_pubres_g_sz);
501        memcpy(packet_out->po_data + 1, req->pr_dcid.idbuf, GQUIC_CID_LEN);
502        break;
503    case (PACKET_REQ_VERNEG << 29) | 0:
504        packet_out->po_flags |= PO_VERNEG;
505        if (req->pr_version == LSQVER_046)
506            gen_verneg = lsquic_Q046_gen_ver_nego_pkt;
507        else
508            gen_verneg = lsquic_ietf_v1_gen_ver_nego_pkt;
509        len = gen_verneg(packet_out->po_data, max_bufsz(prq),
510                    /* Flip SCID/DCID here: */ &req->pr_dcid, &req->pr_scid,
511                    prq->prq_enpub->enp_settings.es_versions,
512                    get_rand_byte(prq));
513        if (len > 0)
514            packet_out->po_data_sz = len;
515        else
516            packet_out->po_data_sz = 0;
517        break;
518    default:
519        packet_out->po_flags &= ~PO_VERNEG;
520        packet_out->po_data_sz = req->pr_rst_sz;
521        RAND_bytes(packet_out->po_data, req->pr_rst_sz - IQUIC_SRESET_TOKEN_SZ);
522        packet_out->po_data[0] &= ~0x80;
523        packet_out->po_data[0] |=  0x40;
524        lsquic_tg_generate_sreset(prq->prq_enpub->enp_tokgen, &req->pr_dcid,
525            packet_out->po_data + req->pr_rst_sz - IQUIC_SRESET_TOKEN_SZ);
526        break;
527    }
528
529    lsquic_hash_erase(prq->prq_reqs_hash, el);
530    evconn->evc_req = req;
531
532    lconn= &evconn->evc_conn;
533    evconn->evc_cces[0].cce_cid = req->pr_dcid;
534    packet_out->po_path = &req->pr_path;
535
536    ++prq->prq_nconns;
537    return lconn;
538}
539
540
541int
542prq_have_pending (const struct pr_queue *prq)
543{
544    return lsquic_hash_count(prq->prq_reqs_hash) > 0;
545}
546
547
548static struct lsquic_packet_out *
549evanescent_conn_ci_next_packet_to_send (struct lsquic_conn *lconn, size_t size)
550{
551    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
552    assert(size == 0);
553    return &evconn->evc_packet_out;
554}
555
556
557static void
558prq_free_conn (struct pr_queue *prq, struct lsquic_conn *lconn)
559{
560    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
561
562    TAILQ_INSERT_HEAD(&prq->prq_free_conns, lconn, cn_next_pr);
563    put_req(prq, evconn->evc_req);
564    --prq->prq_nconns;
565}
566
567
568static void
569evanescent_conn_ci_packet_sent (struct lsquic_conn *lconn,
570                            struct lsquic_packet_out *packet_out)
571{
572    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
573    struct pr_queue *const prq = evconn->evc_queue;
574
575    assert(packet_out == &evconn->evc_packet_out);
576    assert(prq->prq_nconns > 0);
577
578    LSQ_DEBUGC("sent %s packet for connection %"CID_FMT"; free resources",
579        lsquic_preqt2str[ evconn->evc_req->pr_type ],
580        CID_BITS(&evconn->evc_req->pr_dcid));
581    prq_free_conn(prq, lconn);
582}
583
584
585static void
586evanescent_conn_ci_packet_not_sent (struct lsquic_conn *lconn,
587                                struct lsquic_packet_out *packet_out)
588{
589    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
590    struct pr_queue *const prq = evconn->evc_queue;
591
592    assert(packet_out == &evconn->evc_packet_out);
593    assert(prq->prq_nconns > 0);
594
595    if (evconn->evc_flags & EVC_DROP)
596    {
597        LSQ_DEBUGC("packet not sent; drop connection %"CID_FMT,
598                                        CID_BITS(&evconn->evc_req->pr_dcid));
599        prq_free_conn(prq, lconn);
600    }
601    else
602    {
603        LSQ_DEBUG("packet not sent; put connection onto used list");
604        TAILQ_INSERT_HEAD(&prq->prq_returned_conns, lconn, cn_next_pr);
605    }
606}
607
608
609static enum tick_st
610evanescent_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
611{
612    assert(0);
613    return TICK_CLOSE;
614}
615
616
617static void
618evanescent_conn_ci_destroy (struct lsquic_conn *lconn)
619{
620    assert(0);
621}
622
623
624static struct lsquic_engine *
625evanescent_conn_ci_get_engine (struct lsquic_conn *lconn)
626{
627    assert(0);
628    return NULL;
629}
630
631
632static void
633evanescent_conn_ci_hsk_done (struct lsquic_conn *lconn,
634                                                enum lsquic_hsk_status status)
635{
636    assert(0);
637}
638
639
640static void
641evanescent_conn_ci_packet_in (struct lsquic_conn *lconn,
642                          struct lsquic_packet_in *packet_in)
643{
644    assert(0);
645}
646
647
648static void
649evanescent_conn_ci_client_call_on_new (struct lsquic_conn *lconn)
650{
651    assert(0);
652}
653
654
655static struct network_path *
656evanescent_conn_ci_get_path (struct lsquic_conn *lconn,
657                                                    const struct sockaddr *sa)
658{
659    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
660
661    return &evconn->evc_req->pr_path;
662}
663
664
665static unsigned char
666evanescent_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
667            const struct sockaddr *local_sa, const struct sockaddr *peer_sa)
668{
669    assert(0);
670    return 0;
671}
672
673
674static const struct conn_iface evanescent_conn_iface = {
675    .ci_client_call_on_new   =  evanescent_conn_ci_client_call_on_new,
676    .ci_destroy              =  evanescent_conn_ci_destroy,
677    .ci_get_engine           =  evanescent_conn_ci_get_engine,
678    .ci_get_path             =  evanescent_conn_ci_get_path,
679    .ci_hsk_done             =  evanescent_conn_ci_hsk_done,
680    .ci_next_packet_to_send  =  evanescent_conn_ci_next_packet_to_send,
681    .ci_packet_in            =  evanescent_conn_ci_packet_in,
682    .ci_packet_not_sent      =  evanescent_conn_ci_packet_not_sent,
683    .ci_packet_sent          =  evanescent_conn_ci_packet_sent,
684    .ci_record_addrs         =  evanescent_conn_ci_record_addrs,
685    .ci_tick                 =  evanescent_conn_ci_tick,
686};
687
688
689const char *const lsquic_preqt2str[] =
690{
691    [PACKET_REQ_VERNEG] = "version negotiation",
692    [PACKET_REQ_PUBRES] = "stateless reset",
693};
694
695
696void
697lsquic_prq_drop (struct lsquic_conn *lconn)
698{
699    struct evanescent_conn *const evconn = (void *) lconn;
700
701    evconn->evc_flags |= EVC_DROP;
702    LSQ_DEBUGC("mark for connection %"CID_FMT" for dropping",
703                                        CID_BITS(&evconn->evc_req->pr_dcid));
704}
705