1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
25392f7a3SLiteSpeed Tech/*
35392f7a3SLiteSpeed Tech * Parsing routines shared by all IETF QUIC versions.
45392f7a3SLiteSpeed Tech */
55392f7a3SLiteSpeed Tech
65392f7a3SLiteSpeed Tech#include <assert.h>
79626cfc2SDmitri Tikhonov#include <stddef.h>
89626cfc2SDmitri Tikhonov#include <stdint.h>
99626cfc2SDmitri Tikhonov#include <string.h>
109626cfc2SDmitri Tikhonov#include <sys/queue.h>
119626cfc2SDmitri Tikhonov#include <sys/types.h>
129626cfc2SDmitri Tikhonov
139626cfc2SDmitri Tikhonov#include <openssl/rand.h>
149626cfc2SDmitri Tikhonov
159626cfc2SDmitri Tikhonov#include "lsquic_types.h"
169626cfc2SDmitri Tikhonov#include "lsquic_int_types.h"
179626cfc2SDmitri Tikhonov#include "lsquic_packet_common.h"
189626cfc2SDmitri Tikhonov#include "lsquic_packet_in.h"
199626cfc2SDmitri Tikhonov#include "lsquic_parse_common.h"
209626cfc2SDmitri Tikhonov#include "lsquic_parse.h"
219626cfc2SDmitri Tikhonov#include "lsquic_version.h"
229626cfc2SDmitri Tikhonov#include "lsquic.h"
239626cfc2SDmitri Tikhonov#include "lsquic_logger.h"
249626cfc2SDmitri Tikhonov#include "lsquic_byteswap.h"
255392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
265392f7a3SLiteSpeed Tech#include "lsquic_enc_sess.h"
275392f7a3SLiteSpeed Tech#include "lsquic_tokgen.h"
285392f7a3SLiteSpeed Tech#include "lsquic_mm.h"
295392f7a3SLiteSpeed Tech#include "lsquic_engine_public.h"
309fc12041SDmitri Tikhonov#include "lsquic_ietf.h"
319626cfc2SDmitri Tikhonov
329626cfc2SDmitri Tikhonov
33c7d81ce1SDmitri Tikhonov/* [draft-ietf-quic-transport-17] Section-17.2 */
34c7d81ce1SDmitri Tikhonovstatic const enum header_type bits2ht[4] =
35c7d81ce1SDmitri Tikhonov{
36c7d81ce1SDmitri Tikhonov    [0] = HETY_INITIAL,
37c7d81ce1SDmitri Tikhonov    [1] = HETY_0RTT,
38c7d81ce1SDmitri Tikhonov    [2] = HETY_HANDSHAKE,
39c7d81ce1SDmitri Tikhonov    [3] = HETY_RETRY,
40c7d81ce1SDmitri Tikhonov};
41c7d81ce1SDmitri Tikhonov
42c7d81ce1SDmitri Tikhonov
439626cfc2SDmitri Tikhonovint
445392f7a3SLiteSpeed Techlsquic_Q046_parse_packet_in_long_begin (struct lsquic_packet_in *packet_in,
455392f7a3SLiteSpeed Tech                size_t length, int is_server, unsigned cid_len,
465392f7a3SLiteSpeed Tech                struct packin_parse_state *state)
479626cfc2SDmitri Tikhonov{
489626cfc2SDmitri Tikhonov    const unsigned char *p = packet_in->pi_data;
499626cfc2SDmitri Tikhonov    const unsigned char *const end = p + length;
509626cfc2SDmitri Tikhonov    lsquic_ver_tag_t tag;
519626cfc2SDmitri Tikhonov    enum header_type header_type;
52c7d81ce1SDmitri Tikhonov    unsigned dcil, scil, packet_len;
539626cfc2SDmitri Tikhonov    int verneg;
549626cfc2SDmitri Tikhonov    unsigned char first_byte;
555392f7a3SLiteSpeed Tech    lsquic_packno_t packno;
569626cfc2SDmitri Tikhonov
579626cfc2SDmitri Tikhonov    if (length < 6)
589626cfc2SDmitri Tikhonov        return -1;
599626cfc2SDmitri Tikhonov    first_byte = *p++;
609626cfc2SDmitri Tikhonov
619626cfc2SDmitri Tikhonov    memcpy(&tag, p, 4);
629626cfc2SDmitri Tikhonov    p += 4;
639626cfc2SDmitri Tikhonov    verneg = 0 == tag;
649626cfc2SDmitri Tikhonov    if (!verneg)
655392f7a3SLiteSpeed Tech        header_type = bits2ht[ (first_byte >> 4) & 3 ];
669626cfc2SDmitri Tikhonov    else
679626cfc2SDmitri Tikhonov        header_type = HETY_VERNEG;
689626cfc2SDmitri Tikhonov
699626cfc2SDmitri Tikhonov    packet_in->pi_header_type = header_type;
709626cfc2SDmitri Tikhonov
719626cfc2SDmitri Tikhonov    dcil = p[0] >> 4;
729626cfc2SDmitri Tikhonov    if (dcil)
739626cfc2SDmitri Tikhonov        dcil += 3;
749626cfc2SDmitri Tikhonov    scil = p[0] & 0xF;
759626cfc2SDmitri Tikhonov    if (scil)
769626cfc2SDmitri Tikhonov        scil += 3;
779626cfc2SDmitri Tikhonov    ++p;
789626cfc2SDmitri Tikhonov
799626cfc2SDmitri Tikhonov    /* Chromium comments state that the client sends packets with destination
809626cfc2SDmitri Tikhonov     * CID of 8 bytes and source CID of 0 bytes and the server does it the
819626cfc2SDmitri Tikhonov     * other way around.
829626cfc2SDmitri Tikhonov     */
839626cfc2SDmitri Tikhonov    if (is_server)
849626cfc2SDmitri Tikhonov    {
859626cfc2SDmitri Tikhonov        if (!(dcil == cid_len && scil == 0))
869626cfc2SDmitri Tikhonov            return -1;
879626cfc2SDmitri Tikhonov    }
889626cfc2SDmitri Tikhonov    else
895392f7a3SLiteSpeed Tech    if (!(dcil == 0 && scil == cid_len))
905392f7a3SLiteSpeed Tech        return -1;
919626cfc2SDmitri Tikhonov
92c7d81ce1SDmitri Tikhonov    if (!verneg)
93c7d81ce1SDmitri Tikhonov    {
945392f7a3SLiteSpeed Tech        packet_in->pi_flags |= (first_byte & 3) << PIBIT_BITS_SHIFT;
955392f7a3SLiteSpeed Tech        packet_len = 1 + (first_byte & 3);
96c7d81ce1SDmitri Tikhonov        if (end - p < (ptrdiff_t) (dcil + scil + packet_len))
97c7d81ce1SDmitri Tikhonov            return -1;
98c7d81ce1SDmitri Tikhonov    }
99c7d81ce1SDmitri Tikhonov    else
100c7d81ce1SDmitri Tikhonov    {
101c7d81ce1SDmitri Tikhonov        /* Need at least one version in the version array: add 4 */
102c7d81ce1SDmitri Tikhonov        if (end - p < (ptrdiff_t) (dcil + scil + 4))
103c7d81ce1SDmitri Tikhonov            return -1;
104e5d4bc6dSDmitri Tikhonov#ifdef WIN32
105e5d4bc6dSDmitri Tikhonov        /* Useless initialization: */
106e5d4bc6dSDmitri Tikhonov        packet_len = 0;
107e5d4bc6dSDmitri Tikhonov#endif
108c7d81ce1SDmitri Tikhonov    }
1099626cfc2SDmitri Tikhonov
1105392f7a3SLiteSpeed Tech    memcpy(&packet_in->pi_dcid.idbuf, p, cid_len);
1115392f7a3SLiteSpeed Tech    packet_in->pi_dcid.len = cid_len;
1129626cfc2SDmitri Tikhonov    p += cid_len;
1139626cfc2SDmitri Tikhonov    packet_in->pi_flags |= PI_CONN_ID;
1149626cfc2SDmitri Tikhonov
1159626cfc2SDmitri Tikhonov    if (!verneg)
1169626cfc2SDmitri Tikhonov    {
1175392f7a3SLiteSpeed Tech        READ_UINT(packno, 64, p, packet_len);
1185392f7a3SLiteSpeed Tech        packet_in->pi_packno = packno;
1199626cfc2SDmitri Tikhonov        p += packet_len;
1209626cfc2SDmitri Tikhonov        packet_in->pi_quic_ver = 1;
1219626cfc2SDmitri Tikhonov        if (is_server || HETY_0RTT != header_type)
1229626cfc2SDmitri Tikhonov            packet_in->pi_nonce = 0;
1239626cfc2SDmitri Tikhonov        else
1249626cfc2SDmitri Tikhonov        {
1259626cfc2SDmitri Tikhonov            packet_in->pi_nonce = p - packet_in->pi_data;
1269626cfc2SDmitri Tikhonov            p += 32;
1279626cfc2SDmitri Tikhonov        }
1289626cfc2SDmitri Tikhonov    }
1299626cfc2SDmitri Tikhonov    else
1309626cfc2SDmitri Tikhonov    {
1315392f7a3SLiteSpeed Tech        if (p >= end || (3 & (uintptr_t) (end - p)))
1329626cfc2SDmitri Tikhonov            return -1;
1339626cfc2SDmitri Tikhonov        packet_in->pi_quic_ver = p - packet_in->pi_data;
1345392f7a3SLiteSpeed Tech        p = end;
1359626cfc2SDmitri Tikhonov    }
1369626cfc2SDmitri Tikhonov
1379626cfc2SDmitri Tikhonov    packet_in->pi_header_sz    = p - packet_in->pi_data;
1389626cfc2SDmitri Tikhonov    packet_in->pi_frame_types  = 0;
1399626cfc2SDmitri Tikhonov    packet_in->pi_data_sz      = length;
1409626cfc2SDmitri Tikhonov    packet_in->pi_refcnt       = 0;
1419626cfc2SDmitri Tikhonov    packet_in->pi_received     = 0;
1429626cfc2SDmitri Tikhonov
1439626cfc2SDmitri Tikhonov    return 0;
1449626cfc2SDmitri Tikhonov}
1459626cfc2SDmitri Tikhonov
1469626cfc2SDmitri Tikhonov
1479626cfc2SDmitri Tikhonovint
1485392f7a3SLiteSpeed Techlsquic_Q046_parse_packet_in_short_begin (lsquic_packet_in_t *packet_in,
1495392f7a3SLiteSpeed Tech            size_t length, int is_server, unsigned cid_len,
1505392f7a3SLiteSpeed Tech            struct packin_parse_state *state)
1519626cfc2SDmitri Tikhonov{
1529626cfc2SDmitri Tikhonov    const unsigned char *p = packet_in->pi_data;
1539626cfc2SDmitri Tikhonov    const unsigned char *const pend = packet_in->pi_data + length;
1545392f7a3SLiteSpeed Tech    unsigned packet_len, header_len;
1555392f7a3SLiteSpeed Tech    lsquic_packno_t packno;
1569626cfc2SDmitri Tikhonov
157c7d81ce1SDmitri Tikhonov    if (*p & 0x40)  /* Q046 and higher */
158c7d81ce1SDmitri Tikhonov        packet_len = 1 + (*p & 3);
159c7d81ce1SDmitri Tikhonov    else
1605392f7a3SLiteSpeed Tech        return -1;
1615392f7a3SLiteSpeed Tech
1625392f7a3SLiteSpeed Tech    if (is_server)
1635392f7a3SLiteSpeed Tech        header_len = 1 + cid_len + packet_len;
1645392f7a3SLiteSpeed Tech    else
1655392f7a3SLiteSpeed Tech        header_len = 1 + packet_len;
1669626cfc2SDmitri Tikhonov
1675392f7a3SLiteSpeed Tech    if (pend - p < (ptrdiff_t) header_len)
1689626cfc2SDmitri Tikhonov        return -1;
1699626cfc2SDmitri Tikhonov
170c7d81ce1SDmitri Tikhonov    packet_in->pi_flags |= (*p & 3) << PIBIT_BITS_SHIFT;
1719626cfc2SDmitri Tikhonov    ++p;
1729626cfc2SDmitri Tikhonov    if (is_server)
1739626cfc2SDmitri Tikhonov    {
1745392f7a3SLiteSpeed Tech        memcpy(packet_in->pi_dcid.idbuf, packet_in->pi_data + 1, cid_len);
1755392f7a3SLiteSpeed Tech        packet_in->pi_dcid.len = cid_len;
176dee31d56SDmitri Tikhonov        packet_in->pi_flags |= PI_CONN_ID;
1775392f7a3SLiteSpeed Tech        p += cid_len;
1789626cfc2SDmitri Tikhonov    }
1799626cfc2SDmitri Tikhonov
1805392f7a3SLiteSpeed Tech    READ_UINT(packno, 64, p, packet_len);
1815392f7a3SLiteSpeed Tech    packet_in->pi_packno = packno;
1829626cfc2SDmitri Tikhonov    p += packet_len;
1839626cfc2SDmitri Tikhonov
1849626cfc2SDmitri Tikhonov    packet_in->pi_header_type  = HETY_NOT_SET;
1859626cfc2SDmitri Tikhonov    packet_in->pi_quic_ver     = 0;
1869626cfc2SDmitri Tikhonov    packet_in->pi_nonce        = 0;
1879626cfc2SDmitri Tikhonov    packet_in->pi_header_sz    = p - packet_in->pi_data;
1889626cfc2SDmitri Tikhonov    packet_in->pi_frame_types  = 0;
1899626cfc2SDmitri Tikhonov    packet_in->pi_data_sz      = length;
1909626cfc2SDmitri Tikhonov    packet_in->pi_refcnt       = 0;
1919626cfc2SDmitri Tikhonov    packet_in->pi_received     = 0;
1929626cfc2SDmitri Tikhonov
1939626cfc2SDmitri Tikhonov    return 0;
1949626cfc2SDmitri Tikhonov}
1959626cfc2SDmitri Tikhonov
1969626cfc2SDmitri Tikhonov
1975392f7a3SLiteSpeed Tech/* This is a bare-bones version of lsquic_Q046_parse_packet_in_long_begin()
1985392f7a3SLiteSpeed Tech */
1995392f7a3SLiteSpeed Techint
2005392f7a3SLiteSpeed Techlsquic_is_valid_iquic_hs_packet (const unsigned char *buf, size_t length,
2015392f7a3SLiteSpeed Tech                                                        lsquic_ver_tag_t *tagp)
2025392f7a3SLiteSpeed Tech{
2035392f7a3SLiteSpeed Tech    const unsigned char *p = buf;
2045392f7a3SLiteSpeed Tech    const unsigned char *const end = p + length;
2055392f7a3SLiteSpeed Tech    lsquic_ver_tag_t tag;
2065392f7a3SLiteSpeed Tech    unsigned dcil, scil, packet_len;
2075392f7a3SLiteSpeed Tech    unsigned char first_byte;
2085392f7a3SLiteSpeed Tech    const unsigned cid_len = 8;
2095392f7a3SLiteSpeed Tech
2105392f7a3SLiteSpeed Tech    if (length < 6)
2115392f7a3SLiteSpeed Tech        return 0;
2125392f7a3SLiteSpeed Tech    first_byte = *p++;
2135392f7a3SLiteSpeed Tech
2145392f7a3SLiteSpeed Tech    memcpy(&tag, p, 4);
2155392f7a3SLiteSpeed Tech    p += 4;
2165392f7a3SLiteSpeed Tech    if (0 == tag)
2175392f7a3SLiteSpeed Tech        return 0;   /* Client never sends version negotiation */
2185392f7a3SLiteSpeed Tech
2195392f7a3SLiteSpeed Tech    dcil = p[0] >> 4;
2205392f7a3SLiteSpeed Tech    if (dcil)
2215392f7a3SLiteSpeed Tech        dcil += 3;
2225392f7a3SLiteSpeed Tech    scil = p[0] & 0xF;
2235392f7a3SLiteSpeed Tech    if (scil)
2245392f7a3SLiteSpeed Tech        scil += 3;
2255392f7a3SLiteSpeed Tech    ++p;
2265392f7a3SLiteSpeed Tech
2275392f7a3SLiteSpeed Tech    if (!(dcil == cid_len && scil == 0))
2285392f7a3SLiteSpeed Tech        return 0;
2295392f7a3SLiteSpeed Tech
2305392f7a3SLiteSpeed Tech    packet_len = first_byte & 3;
2315392f7a3SLiteSpeed Tech
2325392f7a3SLiteSpeed Tech    if (end - p >= (ptrdiff_t) (dcil + scil + packet_len))
2335392f7a3SLiteSpeed Tech    {
2345392f7a3SLiteSpeed Tech        *tagp = tag;
2355392f7a3SLiteSpeed Tech        return 1;
2365392f7a3SLiteSpeed Tech    }
2375392f7a3SLiteSpeed Tech    else
2385392f7a3SLiteSpeed Tech        return 0;
2395392f7a3SLiteSpeed Tech}
2405392f7a3SLiteSpeed Tech
2415392f7a3SLiteSpeed Tech
242feca77f5SDmitri Tikhonovconst enum quic_frame_type lsquic_iquic_byte2type[0x40] =
2435392f7a3SLiteSpeed Tech{
2445392f7a3SLiteSpeed Tech    [0x00] = QUIC_FRAME_PADDING,
2455392f7a3SLiteSpeed Tech    [0x01] = QUIC_FRAME_PING,
2465392f7a3SLiteSpeed Tech    [0x02] = QUIC_FRAME_ACK,
2475392f7a3SLiteSpeed Tech    [0x03] = QUIC_FRAME_ACK,
2485392f7a3SLiteSpeed Tech    [0x04] = QUIC_FRAME_RST_STREAM,
2495392f7a3SLiteSpeed Tech    [0x05] = QUIC_FRAME_STOP_SENDING,
2505392f7a3SLiteSpeed Tech    [0x06] = QUIC_FRAME_CRYPTO,
2515392f7a3SLiteSpeed Tech    [0x07] = QUIC_FRAME_NEW_TOKEN,
2525392f7a3SLiteSpeed Tech    [0x08] = QUIC_FRAME_STREAM,
2535392f7a3SLiteSpeed Tech    [0x09] = QUIC_FRAME_STREAM,
2545392f7a3SLiteSpeed Tech    [0x0A] = QUIC_FRAME_STREAM,
2555392f7a3SLiteSpeed Tech    [0x0B] = QUIC_FRAME_STREAM,
2565392f7a3SLiteSpeed Tech    [0x0C] = QUIC_FRAME_STREAM,
2575392f7a3SLiteSpeed Tech    [0x0D] = QUIC_FRAME_STREAM,
2585392f7a3SLiteSpeed Tech    [0x0E] = QUIC_FRAME_STREAM,
2595392f7a3SLiteSpeed Tech    [0x0F] = QUIC_FRAME_STREAM,
2605392f7a3SLiteSpeed Tech    [0x10] = QUIC_FRAME_MAX_DATA,
2615392f7a3SLiteSpeed Tech    [0x11] = QUIC_FRAME_MAX_STREAM_DATA,
2625392f7a3SLiteSpeed Tech    [0x12] = QUIC_FRAME_MAX_STREAMS,
2635392f7a3SLiteSpeed Tech    [0x13] = QUIC_FRAME_MAX_STREAMS,
2645392f7a3SLiteSpeed Tech    [0x14] = QUIC_FRAME_BLOCKED,
2655392f7a3SLiteSpeed Tech    [0x15] = QUIC_FRAME_STREAM_BLOCKED,
2665392f7a3SLiteSpeed Tech    [0x16] = QUIC_FRAME_STREAMS_BLOCKED,
2675392f7a3SLiteSpeed Tech    [0x17] = QUIC_FRAME_STREAMS_BLOCKED,
2685392f7a3SLiteSpeed Tech    [0x18] = QUIC_FRAME_NEW_CONNECTION_ID,
2695392f7a3SLiteSpeed Tech    [0x19] = QUIC_FRAME_RETIRE_CONNECTION_ID,
2705392f7a3SLiteSpeed Tech    [0x1A] = QUIC_FRAME_PATH_CHALLENGE,
2715392f7a3SLiteSpeed Tech    [0x1B] = QUIC_FRAME_PATH_RESPONSE,
2725392f7a3SLiteSpeed Tech    [0x1C] = QUIC_FRAME_CONNECTION_CLOSE,
2735392f7a3SLiteSpeed Tech    [0x1D] = QUIC_FRAME_CONNECTION_CLOSE,
2749fc12041SDmitri Tikhonov    [0x1E] = QUIC_FRAME_HANDSHAKE_DONE,
2755392f7a3SLiteSpeed Tech    [0x1F] = QUIC_FRAME_INVALID,
2765392f7a3SLiteSpeed Tech    [0x20] = QUIC_FRAME_INVALID,
2775392f7a3SLiteSpeed Tech    [0x21] = QUIC_FRAME_INVALID,
2785392f7a3SLiteSpeed Tech    [0x22] = QUIC_FRAME_INVALID,
2795392f7a3SLiteSpeed Tech    [0x23] = QUIC_FRAME_INVALID,
2805392f7a3SLiteSpeed Tech    [0x24] = QUIC_FRAME_INVALID,
2815392f7a3SLiteSpeed Tech    [0x25] = QUIC_FRAME_INVALID,
2825392f7a3SLiteSpeed Tech    [0x26] = QUIC_FRAME_INVALID,
2835392f7a3SLiteSpeed Tech    [0x27] = QUIC_FRAME_INVALID,
2845392f7a3SLiteSpeed Tech    [0x28] = QUIC_FRAME_INVALID,
2855392f7a3SLiteSpeed Tech    [0x29] = QUIC_FRAME_INVALID,
2865392f7a3SLiteSpeed Tech    [0x2A] = QUIC_FRAME_INVALID,
2875392f7a3SLiteSpeed Tech    [0x2B] = QUIC_FRAME_INVALID,
2885392f7a3SLiteSpeed Tech    [0x2C] = QUIC_FRAME_INVALID,
2895392f7a3SLiteSpeed Tech    [0x2D] = QUIC_FRAME_INVALID,
2905392f7a3SLiteSpeed Tech    [0x2E] = QUIC_FRAME_INVALID,
2915392f7a3SLiteSpeed Tech    [0x2F] = QUIC_FRAME_INVALID,
292b1a7c3f9SDmitri Tikhonov    [0x30] = QUIC_FRAME_DATAGRAM,
293b1a7c3f9SDmitri Tikhonov    [0x31] = QUIC_FRAME_DATAGRAM,
2945392f7a3SLiteSpeed Tech    [0x32] = QUIC_FRAME_INVALID,
2955392f7a3SLiteSpeed Tech    [0x33] = QUIC_FRAME_INVALID,
2965392f7a3SLiteSpeed Tech    [0x34] = QUIC_FRAME_INVALID,
2975392f7a3SLiteSpeed Tech    [0x35] = QUIC_FRAME_INVALID,
2985392f7a3SLiteSpeed Tech    [0x36] = QUIC_FRAME_INVALID,
2995392f7a3SLiteSpeed Tech    [0x37] = QUIC_FRAME_INVALID,
3005392f7a3SLiteSpeed Tech    [0x38] = QUIC_FRAME_INVALID,
3015392f7a3SLiteSpeed Tech    [0x39] = QUIC_FRAME_INVALID,
3025392f7a3SLiteSpeed Tech    [0x3A] = QUIC_FRAME_INVALID,
3035392f7a3SLiteSpeed Tech    [0x3B] = QUIC_FRAME_INVALID,
3045392f7a3SLiteSpeed Tech    [0x3C] = QUIC_FRAME_INVALID,
3055392f7a3SLiteSpeed Tech    [0x3D] = QUIC_FRAME_INVALID,
3065392f7a3SLiteSpeed Tech    [0x3E] = QUIC_FRAME_INVALID,
3075392f7a3SLiteSpeed Tech    [0x3F] = QUIC_FRAME_INVALID,
3085392f7a3SLiteSpeed Tech};
3095392f7a3SLiteSpeed Tech
3105392f7a3SLiteSpeed Tech
3115392f7a3SLiteSpeed Tech#if __GNUC__
3125392f7a3SLiteSpeed Tech#   define popcount __builtin_popcount
3135392f7a3SLiteSpeed Tech#else
3145392f7a3SLiteSpeed Techstatic int
3155392f7a3SLiteSpeed Techpopcount (unsigned v)
3165392f7a3SLiteSpeed Tech{
3175392f7a3SLiteSpeed Tech    int count, i;
3185392f7a3SLiteSpeed Tech    for (i = 0, count = 0; i < sizeof(v) * 8; ++i)
3195392f7a3SLiteSpeed Tech        if (v & (1 << i))
3205392f7a3SLiteSpeed Tech            ++count;
3215392f7a3SLiteSpeed Tech    return count;
3225392f7a3SLiteSpeed Tech}
3235392f7a3SLiteSpeed Tech
3245392f7a3SLiteSpeed Tech
3255392f7a3SLiteSpeed Tech#endif
3265392f7a3SLiteSpeed Tech
3275392f7a3SLiteSpeed Tech
3285392f7a3SLiteSpeed Techint
3295392f7a3SLiteSpeed Techlsquic_Q046_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz,
330a0e1aeeeSDmitri Tikhonov         const lsquic_cid_t *scid, const lsquic_cid_t *dcid, unsigned versions,
331a0e1aeeeSDmitri Tikhonov         uint8_t rand)
3325392f7a3SLiteSpeed Tech{
3335392f7a3SLiteSpeed Tech    unsigned slen, dlen;
3345392f7a3SLiteSpeed Tech    size_t need;
3355392f7a3SLiteSpeed Tech    int r;
3365392f7a3SLiteSpeed Tech
3375392f7a3SLiteSpeed Tech    need = 1 /* Type */ + 4 /* Packet number */ + 1 /* SCIL */
3385392f7a3SLiteSpeed Tech                        + scid->len + dcid->len + popcount(versions) * 4;
3395392f7a3SLiteSpeed Tech
3405392f7a3SLiteSpeed Tech    if (need > bufsz)
3415392f7a3SLiteSpeed Tech        return -1;
3425392f7a3SLiteSpeed Tech
3431c9cee3eSDmitri Tikhonov    *buf++ = 0x80 | 0x40 | rand;
3445392f7a3SLiteSpeed Tech    memset(buf, 0, 4);
3455392f7a3SLiteSpeed Tech    buf += 4;
3465392f7a3SLiteSpeed Tech
3475392f7a3SLiteSpeed Tech    /* From [draft-ietf-quic-transport-11], Section 4.3:
3485392f7a3SLiteSpeed Tech     *
3495392f7a3SLiteSpeed Tech     *  The server MUST include the value from the Source Connection ID field
3505392f7a3SLiteSpeed Tech     *  of the packet it receives in the Destination Connection ID field.
3515392f7a3SLiteSpeed Tech     *  The value for Source Connection ID MUST be copied from the
3525392f7a3SLiteSpeed Tech     *  Destination Connection ID of the received packet, which is initially
3535392f7a3SLiteSpeed Tech     *  randomly selected by a client.  Echoing both connection IDs gives
3545392f7a3SLiteSpeed Tech     *  clients some assurance that the server received the packet and that
3555392f7a3SLiteSpeed Tech     *  the Version Negotiation packet was not generated by an off-path
3565392f7a3SLiteSpeed Tech     *  attacker.
3575392f7a3SLiteSpeed Tech     */
3585392f7a3SLiteSpeed Tech
3595392f7a3SLiteSpeed Tech    dlen = dcid->len;
3605392f7a3SLiteSpeed Tech    if (dlen)
3615392f7a3SLiteSpeed Tech        dlen -= 3;
3625392f7a3SLiteSpeed Tech    slen = scid->len;
3635392f7a3SLiteSpeed Tech    if (slen)
3645392f7a3SLiteSpeed Tech        slen -= 3;
3655392f7a3SLiteSpeed Tech    *buf++ = (dlen << 4) | slen;
3665392f7a3SLiteSpeed Tech
3675392f7a3SLiteSpeed Tech    memcpy(buf, dcid->idbuf, dcid->len);
3685392f7a3SLiteSpeed Tech    buf += dcid->len;
3695392f7a3SLiteSpeed Tech    memcpy(buf, scid->idbuf, scid->len);
3705392f7a3SLiteSpeed Tech    buf += scid->len;
3715392f7a3SLiteSpeed Tech
3725392f7a3SLiteSpeed Tech    r = lsquic_gen_ver_tags(buf, bufsz - 1 - 4 - 1 - dcid->len - scid->len,
3735392f7a3SLiteSpeed Tech                                                                    versions);
3745392f7a3SLiteSpeed Tech    if (r < 0)
3755392f7a3SLiteSpeed Tech        return -1;
3765392f7a3SLiteSpeed Tech    assert((unsigned) r == popcount(versions) * 4u);
3775392f7a3SLiteSpeed Tech
3785392f7a3SLiteSpeed Tech    return need;
3795392f7a3SLiteSpeed Tech}
3805392f7a3SLiteSpeed Tech
3815392f7a3SLiteSpeed Tech
382