1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov/*
350aadb33SDmitri Tikhonov * lsquic_parse_gquic_common.c -- Parsing functions common to GQUIC
450aadb33SDmitri Tikhonov */
550aadb33SDmitri Tikhonov
650aadb33SDmitri Tikhonov#include <assert.h>
750aadb33SDmitri Tikhonov#include <errno.h>
850aadb33SDmitri Tikhonov#include <inttypes.h>
950aadb33SDmitri Tikhonov#include <string.h>
1050aadb33SDmitri Tikhonov#include <stdlib.h>
11461e84d8SAmol Deshpande#include <sys/queue.h>
12461e84d8SAmol Deshpande#ifndef WIN32
1350aadb33SDmitri Tikhonov#include <sys/types.h>
14461e84d8SAmol Deshpande#else
15461e84d8SAmol Deshpande#include <vc_compat.h>
16461e84d8SAmol Deshpande#endif
1750aadb33SDmitri Tikhonov
1850aadb33SDmitri Tikhonov#include "lsquic_types.h"
195392f7a3SLiteSpeed Tech#include "lsquic_int_types.h"
2050aadb33SDmitri Tikhonov#include "lsquic_packet_common.h"
219626cfc2SDmitri Tikhonov#include "lsquic_packet_out.h"
225392f7a3SLiteSpeed Tech#include "lsquic_packet_gquic.h"
2350aadb33SDmitri Tikhonov#include "lsquic_packet_in.h"
245392f7a3SLiteSpeed Tech#include "lsquic_parse_common.h"
2550aadb33SDmitri Tikhonov#include "lsquic_parse.h"
269626cfc2SDmitri Tikhonov#include "lsquic_version.h"
2750aadb33SDmitri Tikhonov#include "lsquic.h"
2850aadb33SDmitri Tikhonov
2950aadb33SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_PARSE
3050aadb33SDmitri Tikhonov#include "lsquic_logger.h"
3150aadb33SDmitri Tikhonov
3250aadb33SDmitri Tikhonov#define CHECK_SPACE(need, pstart, pend)  \
3350aadb33SDmitri Tikhonov    do { if ((intptr_t) (need) > ((pend) - (pstart))) { return -1; } } while (0)
3450aadb33SDmitri Tikhonov
3550aadb33SDmitri Tikhonov/* This partially parses `packet_in' and returns 0 if in case it succeeded and
3650aadb33SDmitri Tikhonov * -1 on failure.
3750aadb33SDmitri Tikhonov *
3850aadb33SDmitri Tikhonov * After this function returns 0, connection ID, nonce, and version fields can
3950aadb33SDmitri Tikhonov * be examined.  To finsh parsing the packet, call version-specific
4050aadb33SDmitri Tikhonov * pf_parse_packet_in_finish() routine.
4150aadb33SDmitri Tikhonov */
4250aadb33SDmitri Tikhonovint
435392f7a3SLiteSpeed Techlsquic_gquic_parse_packet_in_begin (lsquic_packet_in_t *packet_in,
445392f7a3SLiteSpeed Tech                size_t length, int is_server, unsigned cid_len,
455392f7a3SLiteSpeed Tech                struct packin_parse_state *state)
4650aadb33SDmitri Tikhonov{
4750aadb33SDmitri Tikhonov    int nbytes;
4850aadb33SDmitri Tikhonov    enum PACKET_PUBLIC_FLAGS public_flags;
4950aadb33SDmitri Tikhonov    const unsigned char *p = packet_in->pi_data;
5050aadb33SDmitri Tikhonov    const unsigned char *const pend = packet_in->pi_data + length;
5150aadb33SDmitri Tikhonov
525392f7a3SLiteSpeed Tech    if (length > GQUIC_MAX_PACKET_SZ)
535392f7a3SLiteSpeed Tech    {
545392f7a3SLiteSpeed Tech        LSQ_DEBUG("Cannot handle packet_in_size(%zd) > %d packet incoming "
555392f7a3SLiteSpeed Tech            "packet's header", length, GQUIC_MAX_PACKET_SZ);
565392f7a3SLiteSpeed Tech        return -1;
575392f7a3SLiteSpeed Tech    }
585392f7a3SLiteSpeed Tech
5950aadb33SDmitri Tikhonov    CHECK_SPACE(1, p, pend);
6050aadb33SDmitri Tikhonov
6150aadb33SDmitri Tikhonov    public_flags = *p++;
6250aadb33SDmitri Tikhonov
6350aadb33SDmitri Tikhonov    if (public_flags & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID)
6450aadb33SDmitri Tikhonov    {
6550aadb33SDmitri Tikhonov        CHECK_SPACE(8, p, pend);
665392f7a3SLiteSpeed Tech        memset(&packet_in->pi_conn_id, 0, sizeof(packet_in->pi_conn_id));
675392f7a3SLiteSpeed Tech        packet_in->pi_conn_id.len = 8;
685392f7a3SLiteSpeed Tech        memcpy(&packet_in->pi_conn_id.idbuf, p, 8);
6950aadb33SDmitri Tikhonov        packet_in->pi_flags |= PI_CONN_ID;
7050aadb33SDmitri Tikhonov        p += 8;
7150aadb33SDmitri Tikhonov    }
7250aadb33SDmitri Tikhonov
7350aadb33SDmitri Tikhonov    if (public_flags & PACKET_PUBLIC_FLAGS_VERSION)
7450aadb33SDmitri Tikhonov    {
7550aadb33SDmitri Tikhonov        /* It seems that version negotiation packets sent by Google may have
7650aadb33SDmitri Tikhonov         * NONCE bit set.  Ignore it:
7750aadb33SDmitri Tikhonov         */
7850aadb33SDmitri Tikhonov        public_flags &= ~PACKET_PUBLIC_FLAGS_NONCE;
7950aadb33SDmitri Tikhonov
8050aadb33SDmitri Tikhonov        if (is_server)
8150aadb33SDmitri Tikhonov        {
8250aadb33SDmitri Tikhonov            CHECK_SPACE(4, p, pend);
8350aadb33SDmitri Tikhonov            packet_in->pi_quic_ver = p - packet_in->pi_data;
8450aadb33SDmitri Tikhonov            p += 4;
8550aadb33SDmitri Tikhonov        }
8650aadb33SDmitri Tikhonov        else
8750aadb33SDmitri Tikhonov        {   /* OK, we have a version negotiation packet.  We need to verify
8850aadb33SDmitri Tikhonov             * that it has correct structure.  See Section 4.3 of
8950aadb33SDmitri Tikhonov             * [draft-ietf-quic-transport-00].
9050aadb33SDmitri Tikhonov             */
9150aadb33SDmitri Tikhonov            if ((public_flags & ~(PACKET_PUBLIC_FLAGS_VERSION|
9250aadb33SDmitri Tikhonov                                  PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID))
9350aadb33SDmitri Tikhonov                || ((pend - p) & 3))
9450aadb33SDmitri Tikhonov                return -1;
9550aadb33SDmitri Tikhonov            CHECK_SPACE(4, p, pend);
9650aadb33SDmitri Tikhonov            packet_in->pi_quic_ver = p - packet_in->pi_data;
9750aadb33SDmitri Tikhonov            p = pend;
9850aadb33SDmitri Tikhonov        }
9950aadb33SDmitri Tikhonov    }
10050aadb33SDmitri Tikhonov    else
10150aadb33SDmitri Tikhonov    {
10250aadb33SDmitri Tikhonov        /* From [draft-hamilton-quic-transport-protocol-01]:
10350aadb33SDmitri Tikhonov         *    0x40 = MULTIPATH. This bit is reserved for multipath use.
10450aadb33SDmitri Tikhonov         *    0x80 is currently unused, and must be set to 0.
10550aadb33SDmitri Tikhonov         *
10650aadb33SDmitri Tikhonov         * The reference implementation checks that two high bits are not set
10750aadb33SDmitri Tikhonov         * if version flag is not set or if the version is the same.  For our
10850aadb33SDmitri Tikhonov         * purposes, all GQUIC version we support so far have these bits set
10950aadb33SDmitri Tikhonov         * to zero.
11050aadb33SDmitri Tikhonov         */
11150aadb33SDmitri Tikhonov        if (public_flags & (0x80|0x40))
11250aadb33SDmitri Tikhonov            return -1;
11350aadb33SDmitri Tikhonov        packet_in->pi_quic_ver = 0;
11450aadb33SDmitri Tikhonov    }
11550aadb33SDmitri Tikhonov
11650aadb33SDmitri Tikhonov    if (!is_server && (public_flags & PACKET_PUBLIC_FLAGS_NONCE) ==
11750aadb33SDmitri Tikhonov                                            PACKET_PUBLIC_FLAGS_NONCE)
11850aadb33SDmitri Tikhonov    {
11950aadb33SDmitri Tikhonov        CHECK_SPACE(32, p, pend);
12050aadb33SDmitri Tikhonov        packet_in->pi_nonce = p - packet_in->pi_data;
12150aadb33SDmitri Tikhonov        p += 32;
12250aadb33SDmitri Tikhonov    }
12350aadb33SDmitri Tikhonov    else
12450aadb33SDmitri Tikhonov        packet_in->pi_nonce = 0;
12550aadb33SDmitri Tikhonov
12650aadb33SDmitri Tikhonov    state->pps_p = p;
12750aadb33SDmitri Tikhonov
12850aadb33SDmitri Tikhonov    packet_in->pi_packno = 0;
12950aadb33SDmitri Tikhonov    if (0 == (public_flags & (PACKET_PUBLIC_FLAGS_VERSION|PACKET_PUBLIC_FLAGS_RST))
13050aadb33SDmitri Tikhonov        || ((public_flags & PACKET_PUBLIC_FLAGS_VERSION) && is_server))
13150aadb33SDmitri Tikhonov    {
13250aadb33SDmitri Tikhonov        nbytes = twobit_to_1246((public_flags >> 4) & 3);
13350aadb33SDmitri Tikhonov        CHECK_SPACE(nbytes, p, pend);
13450aadb33SDmitri Tikhonov        p += nbytes;
13550aadb33SDmitri Tikhonov        state->pps_nbytes = nbytes;
13650aadb33SDmitri Tikhonov    }
13750aadb33SDmitri Tikhonov    else
13850aadb33SDmitri Tikhonov        state->pps_nbytes = 0;
13950aadb33SDmitri Tikhonov
14050aadb33SDmitri Tikhonov    packet_in->pi_header_sz    = p - packet_in->pi_data;
14150aadb33SDmitri Tikhonov    packet_in->pi_frame_types  = 0;
14250aadb33SDmitri Tikhonov    memset(&packet_in->pi_next, 0, sizeof(packet_in->pi_next));
14350aadb33SDmitri Tikhonov    packet_in->pi_data_sz      = length;
14450aadb33SDmitri Tikhonov    packet_in->pi_refcnt       = 0;
14550aadb33SDmitri Tikhonov    packet_in->pi_received     = 0;
1469626cfc2SDmitri Tikhonov    packet_in->pi_flags       |= PI_GQUIC;
147c7d81ce1SDmitri Tikhonov    packet_in->pi_flags       |= ((public_flags >> 4) & 3) << PIBIT_BITS_SHIFT;
14850aadb33SDmitri Tikhonov
14950aadb33SDmitri Tikhonov    return 0;
15050aadb33SDmitri Tikhonov}
15150aadb33SDmitri Tikhonov
15250aadb33SDmitri Tikhonov
1535392f7a3SLiteSpeed Techstatic const unsigned char simple_prst_payload[] = {
1545392f7a3SLiteSpeed Tech    'P', 'R', 'S', 'T',
1555392f7a3SLiteSpeed Tech    0x01, 0x00, 0x00, 0x00,
1565392f7a3SLiteSpeed Tech    'R', 'N', 'O', 'N',
1575392f7a3SLiteSpeed Tech    0x08, 0x00, 0x00, 0x00,
1585392f7a3SLiteSpeed Tech    1, 2, 3, 4, 5, 6, 7, 8,
1595392f7a3SLiteSpeed Tech};
1605392f7a3SLiteSpeed Tech
1615392f7a3SLiteSpeed Tech
1625392f7a3SLiteSpeed Techtypedef char correct_simple_prst_size[(GQUIC_RESET_SZ ==
163fb3e20e0SDmitri Tikhonov                1 + GQUIC_CID_LEN + sizeof(simple_prst_payload)) ? 1 : -1 ];
1645392f7a3SLiteSpeed Tech
1655392f7a3SLiteSpeed Tech
1665392f7a3SLiteSpeed Techssize_t
1675392f7a3SLiteSpeed Techlsquic_generate_gquic_reset (const lsquic_cid_t *cidp,
1685392f7a3SLiteSpeed Tech                                        unsigned char *buf, size_t buf_sz)
1695392f7a3SLiteSpeed Tech{
1705392f7a3SLiteSpeed Tech    lsquic_cid_t cid;
1715392f7a3SLiteSpeed Tech
1725392f7a3SLiteSpeed Tech    if (buf_sz < 1 + GQUIC_CID_LEN + sizeof(simple_prst_payload))
1735392f7a3SLiteSpeed Tech    {
1745392f7a3SLiteSpeed Tech        errno = ENOBUFS;
1755392f7a3SLiteSpeed Tech        return -1;
1765392f7a3SLiteSpeed Tech    }
1775392f7a3SLiteSpeed Tech
1785392f7a3SLiteSpeed Tech    if (cidp)
1795392f7a3SLiteSpeed Tech    {
1805392f7a3SLiteSpeed Tech        assert(GQUIC_CID_LEN == cidp->len);
1815392f7a3SLiteSpeed Tech        cid = *cidp;
1825392f7a3SLiteSpeed Tech    }
1835392f7a3SLiteSpeed Tech    else
1845392f7a3SLiteSpeed Tech    {
1855392f7a3SLiteSpeed Tech        memset(&cid, 0, sizeof(cid));
1865392f7a3SLiteSpeed Tech        cid.len = GQUIC_CID_LEN;
1875392f7a3SLiteSpeed Tech    }
1885392f7a3SLiteSpeed Tech
1895392f7a3SLiteSpeed Tech    *buf++ = PACKET_PUBLIC_FLAGS_RST | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID;
1905392f7a3SLiteSpeed Tech
1915392f7a3SLiteSpeed Tech    memcpy(buf, cid.idbuf, GQUIC_CID_LEN);
1925392f7a3SLiteSpeed Tech    buf += GQUIC_CID_LEN;
1935392f7a3SLiteSpeed Tech
1945392f7a3SLiteSpeed Tech    memcpy(buf, simple_prst_payload, sizeof(simple_prst_payload));
1955392f7a3SLiteSpeed Tech    return 1 + GQUIC_CID_LEN + sizeof(simple_prst_payload);
1965392f7a3SLiteSpeed Tech}
1975392f7a3SLiteSpeed Tech
1985392f7a3SLiteSpeed Tech
1997a8b2eceSDmitri Tikhonovstatic const enum quic_frame_type byte2frame_type_Q035_thru_Q046[0x100] =
20050aadb33SDmitri Tikhonov{
20150aadb33SDmitri Tikhonov    [0x00] = QUIC_FRAME_PADDING,
20250aadb33SDmitri Tikhonov    [0x01] = QUIC_FRAME_RST_STREAM,
20350aadb33SDmitri Tikhonov    [0x02] = QUIC_FRAME_CONNECTION_CLOSE,
20450aadb33SDmitri Tikhonov    [0x03] = QUIC_FRAME_GOAWAY,
20550aadb33SDmitri Tikhonov    [0x04] = QUIC_FRAME_WINDOW_UPDATE,
20650aadb33SDmitri Tikhonov    [0x05] = QUIC_FRAME_BLOCKED,
20750aadb33SDmitri Tikhonov    [0x06] = QUIC_FRAME_STOP_WAITING,
20850aadb33SDmitri Tikhonov    [0x07] = QUIC_FRAME_PING,
20950aadb33SDmitri Tikhonov    [0x08] = QUIC_FRAME_INVALID,
21050aadb33SDmitri Tikhonov    [0x09] = QUIC_FRAME_INVALID,
21150aadb33SDmitri Tikhonov    [0x0A] = QUIC_FRAME_INVALID,
21250aadb33SDmitri Tikhonov    [0x0B] = QUIC_FRAME_INVALID,
21350aadb33SDmitri Tikhonov    [0x0C] = QUIC_FRAME_INVALID,
21450aadb33SDmitri Tikhonov    [0x0D] = QUIC_FRAME_INVALID,
21550aadb33SDmitri Tikhonov    [0x0E] = QUIC_FRAME_INVALID,
21650aadb33SDmitri Tikhonov    [0x0F] = QUIC_FRAME_INVALID,
21750aadb33SDmitri Tikhonov    [0x10] = QUIC_FRAME_INVALID,
21850aadb33SDmitri Tikhonov    [0x11] = QUIC_FRAME_INVALID,
21950aadb33SDmitri Tikhonov    [0x12] = QUIC_FRAME_INVALID,
22050aadb33SDmitri Tikhonov    [0x13] = QUIC_FRAME_INVALID,
22150aadb33SDmitri Tikhonov    [0x14] = QUIC_FRAME_INVALID,
22250aadb33SDmitri Tikhonov    [0x15] = QUIC_FRAME_INVALID,
22350aadb33SDmitri Tikhonov    [0x16] = QUIC_FRAME_INVALID,
22450aadb33SDmitri Tikhonov    [0x17] = QUIC_FRAME_INVALID,
22550aadb33SDmitri Tikhonov    [0x18] = QUIC_FRAME_INVALID,
22650aadb33SDmitri Tikhonov    [0x19] = QUIC_FRAME_INVALID,
22750aadb33SDmitri Tikhonov    [0x1A] = QUIC_FRAME_INVALID,
22850aadb33SDmitri Tikhonov    [0x1B] = QUIC_FRAME_INVALID,
22950aadb33SDmitri Tikhonov    [0x1C] = QUIC_FRAME_INVALID,
23050aadb33SDmitri Tikhonov    [0x1D] = QUIC_FRAME_INVALID,
23150aadb33SDmitri Tikhonov    [0x1E] = QUIC_FRAME_INVALID,
23250aadb33SDmitri Tikhonov    [0x1F] = QUIC_FRAME_INVALID,
23350aadb33SDmitri Tikhonov    [0x20] = QUIC_FRAME_INVALID,
23450aadb33SDmitri Tikhonov    [0x21] = QUIC_FRAME_INVALID,
23550aadb33SDmitri Tikhonov    [0x22] = QUIC_FRAME_INVALID,
23650aadb33SDmitri Tikhonov    [0x23] = QUIC_FRAME_INVALID,
23750aadb33SDmitri Tikhonov    [0x24] = QUIC_FRAME_INVALID,
23850aadb33SDmitri Tikhonov    [0x25] = QUIC_FRAME_INVALID,
23950aadb33SDmitri Tikhonov    [0x26] = QUIC_FRAME_INVALID,
24050aadb33SDmitri Tikhonov    [0x27] = QUIC_FRAME_INVALID,
24150aadb33SDmitri Tikhonov    [0x28] = QUIC_FRAME_INVALID,
24250aadb33SDmitri Tikhonov    [0x29] = QUIC_FRAME_INVALID,
24350aadb33SDmitri Tikhonov    [0x2A] = QUIC_FRAME_INVALID,
24450aadb33SDmitri Tikhonov    [0x2B] = QUIC_FRAME_INVALID,
24550aadb33SDmitri Tikhonov    [0x2C] = QUIC_FRAME_INVALID,
24650aadb33SDmitri Tikhonov    [0x2D] = QUIC_FRAME_INVALID,
24750aadb33SDmitri Tikhonov    [0x2E] = QUIC_FRAME_INVALID,
24850aadb33SDmitri Tikhonov    [0x2F] = QUIC_FRAME_INVALID,
24950aadb33SDmitri Tikhonov    [0x30] = QUIC_FRAME_INVALID,
25050aadb33SDmitri Tikhonov    [0x31] = QUIC_FRAME_INVALID,
25150aadb33SDmitri Tikhonov    [0x32] = QUIC_FRAME_INVALID,
25250aadb33SDmitri Tikhonov    [0x33] = QUIC_FRAME_INVALID,
25350aadb33SDmitri Tikhonov    [0x34] = QUIC_FRAME_INVALID,
25450aadb33SDmitri Tikhonov    [0x35] = QUIC_FRAME_INVALID,
25550aadb33SDmitri Tikhonov    [0x36] = QUIC_FRAME_INVALID,
25650aadb33SDmitri Tikhonov    [0x37] = QUIC_FRAME_INVALID,
25750aadb33SDmitri Tikhonov    [0x38] = QUIC_FRAME_INVALID,
25850aadb33SDmitri Tikhonov    [0x39] = QUIC_FRAME_INVALID,
25950aadb33SDmitri Tikhonov    [0x3A] = QUIC_FRAME_INVALID,
26050aadb33SDmitri Tikhonov    [0x3B] = QUIC_FRAME_INVALID,
26150aadb33SDmitri Tikhonov    [0x3C] = QUIC_FRAME_INVALID,
26250aadb33SDmitri Tikhonov    [0x3D] = QUIC_FRAME_INVALID,
26350aadb33SDmitri Tikhonov    [0x3E] = QUIC_FRAME_INVALID,
26450aadb33SDmitri Tikhonov    [0x3F] = QUIC_FRAME_INVALID,
26550aadb33SDmitri Tikhonov    [0x40] = QUIC_FRAME_ACK,
26650aadb33SDmitri Tikhonov    [0x41] = QUIC_FRAME_ACK,
26750aadb33SDmitri Tikhonov    [0x42] = QUIC_FRAME_ACK,
26850aadb33SDmitri Tikhonov    [0x43] = QUIC_FRAME_ACK,
26950aadb33SDmitri Tikhonov    [0x44] = QUIC_FRAME_ACK,
27050aadb33SDmitri Tikhonov    [0x45] = QUIC_FRAME_ACK,
27150aadb33SDmitri Tikhonov    [0x46] = QUIC_FRAME_ACK,
27250aadb33SDmitri Tikhonov    [0x47] = QUIC_FRAME_ACK,
27350aadb33SDmitri Tikhonov    [0x48] = QUIC_FRAME_ACK,
27450aadb33SDmitri Tikhonov    [0x49] = QUIC_FRAME_ACK,
27550aadb33SDmitri Tikhonov    [0x4A] = QUIC_FRAME_ACK,
27650aadb33SDmitri Tikhonov    [0x4B] = QUIC_FRAME_ACK,
27750aadb33SDmitri Tikhonov    [0x4C] = QUIC_FRAME_ACK,
27850aadb33SDmitri Tikhonov    [0x4D] = QUIC_FRAME_ACK,
27950aadb33SDmitri Tikhonov    [0x4E] = QUIC_FRAME_ACK,
28050aadb33SDmitri Tikhonov    [0x4F] = QUIC_FRAME_ACK,
28150aadb33SDmitri Tikhonov    [0x50] = QUIC_FRAME_ACK,
28250aadb33SDmitri Tikhonov    [0x51] = QUIC_FRAME_ACK,
28350aadb33SDmitri Tikhonov    [0x52] = QUIC_FRAME_ACK,
28450aadb33SDmitri Tikhonov    [0x53] = QUIC_FRAME_ACK,
28550aadb33SDmitri Tikhonov    [0x54] = QUIC_FRAME_ACK,
28650aadb33SDmitri Tikhonov    [0x55] = QUIC_FRAME_ACK,
28750aadb33SDmitri Tikhonov    [0x56] = QUIC_FRAME_ACK,
28850aadb33SDmitri Tikhonov    [0x57] = QUIC_FRAME_ACK,
28950aadb33SDmitri Tikhonov    [0x58] = QUIC_FRAME_ACK,
29050aadb33SDmitri Tikhonov    [0x59] = QUIC_FRAME_ACK,
29150aadb33SDmitri Tikhonov    [0x5A] = QUIC_FRAME_ACK,
29250aadb33SDmitri Tikhonov    [0x5B] = QUIC_FRAME_ACK,
29350aadb33SDmitri Tikhonov    [0x5C] = QUIC_FRAME_ACK,
29450aadb33SDmitri Tikhonov    [0x5D] = QUIC_FRAME_ACK,
29550aadb33SDmitri Tikhonov    [0x5E] = QUIC_FRAME_ACK,
29650aadb33SDmitri Tikhonov    [0x5F] = QUIC_FRAME_ACK,
29750aadb33SDmitri Tikhonov    [0x60] = QUIC_FRAME_ACK,
29850aadb33SDmitri Tikhonov    [0x61] = QUIC_FRAME_ACK,
29950aadb33SDmitri Tikhonov    [0x62] = QUIC_FRAME_ACK,
30050aadb33SDmitri Tikhonov    [0x63] = QUIC_FRAME_ACK,
30150aadb33SDmitri Tikhonov    [0x64] = QUIC_FRAME_ACK,
30250aadb33SDmitri Tikhonov    [0x65] = QUIC_FRAME_ACK,
30350aadb33SDmitri Tikhonov    [0x66] = QUIC_FRAME_ACK,
30450aadb33SDmitri Tikhonov    [0x67] = QUIC_FRAME_ACK,
30550aadb33SDmitri Tikhonov    [0x68] = QUIC_FRAME_ACK,
30650aadb33SDmitri Tikhonov    [0x69] = QUIC_FRAME_ACK,
30750aadb33SDmitri Tikhonov    [0x6A] = QUIC_FRAME_ACK,
30850aadb33SDmitri Tikhonov    [0x6B] = QUIC_FRAME_ACK,
30950aadb33SDmitri Tikhonov    [0x6C] = QUIC_FRAME_ACK,
31050aadb33SDmitri Tikhonov    [0x6D] = QUIC_FRAME_ACK,
31150aadb33SDmitri Tikhonov    [0x6E] = QUIC_FRAME_ACK,
31250aadb33SDmitri Tikhonov    [0x6F] = QUIC_FRAME_ACK,
31350aadb33SDmitri Tikhonov    [0x70] = QUIC_FRAME_ACK,
31450aadb33SDmitri Tikhonov    [0x71] = QUIC_FRAME_ACK,
31550aadb33SDmitri Tikhonov    [0x72] = QUIC_FRAME_ACK,
31650aadb33SDmitri Tikhonov    [0x73] = QUIC_FRAME_ACK,
31750aadb33SDmitri Tikhonov    [0x74] = QUIC_FRAME_ACK,
31850aadb33SDmitri Tikhonov    [0x75] = QUIC_FRAME_ACK,
31950aadb33SDmitri Tikhonov    [0x76] = QUIC_FRAME_ACK,
32050aadb33SDmitri Tikhonov    [0x77] = QUIC_FRAME_ACK,
32150aadb33SDmitri Tikhonov    [0x78] = QUIC_FRAME_ACK,
32250aadb33SDmitri Tikhonov    [0x79] = QUIC_FRAME_ACK,
32350aadb33SDmitri Tikhonov    [0x7A] = QUIC_FRAME_ACK,
32450aadb33SDmitri Tikhonov    [0x7B] = QUIC_FRAME_ACK,
32550aadb33SDmitri Tikhonov    [0x7C] = QUIC_FRAME_ACK,
32650aadb33SDmitri Tikhonov    [0x7D] = QUIC_FRAME_ACK,
32750aadb33SDmitri Tikhonov    [0x7E] = QUIC_FRAME_ACK,
32850aadb33SDmitri Tikhonov    [0x7F] = QUIC_FRAME_ACK,
32950aadb33SDmitri Tikhonov    [0x80] = QUIC_FRAME_STREAM,
33050aadb33SDmitri Tikhonov    [0x81] = QUIC_FRAME_STREAM,
33150aadb33SDmitri Tikhonov    [0x82] = QUIC_FRAME_STREAM,
33250aadb33SDmitri Tikhonov    [0x83] = QUIC_FRAME_STREAM,
33350aadb33SDmitri Tikhonov    [0x84] = QUIC_FRAME_STREAM,
33450aadb33SDmitri Tikhonov    [0x85] = QUIC_FRAME_STREAM,
33550aadb33SDmitri Tikhonov    [0x86] = QUIC_FRAME_STREAM,
33650aadb33SDmitri Tikhonov    [0x87] = QUIC_FRAME_STREAM,
33750aadb33SDmitri Tikhonov    [0x88] = QUIC_FRAME_STREAM,
33850aadb33SDmitri Tikhonov    [0x89] = QUIC_FRAME_STREAM,
33950aadb33SDmitri Tikhonov    [0x8A] = QUIC_FRAME_STREAM,
34050aadb33SDmitri Tikhonov    [0x8B] = QUIC_FRAME_STREAM,
34150aadb33SDmitri Tikhonov    [0x8C] = QUIC_FRAME_STREAM,
34250aadb33SDmitri Tikhonov    [0x8D] = QUIC_FRAME_STREAM,
34350aadb33SDmitri Tikhonov    [0x8E] = QUIC_FRAME_STREAM,
34450aadb33SDmitri Tikhonov    [0x8F] = QUIC_FRAME_STREAM,
34550aadb33SDmitri Tikhonov    [0x90] = QUIC_FRAME_STREAM,
34650aadb33SDmitri Tikhonov    [0x91] = QUIC_FRAME_STREAM,
34750aadb33SDmitri Tikhonov    [0x92] = QUIC_FRAME_STREAM,
34850aadb33SDmitri Tikhonov    [0x93] = QUIC_FRAME_STREAM,
34950aadb33SDmitri Tikhonov    [0x94] = QUIC_FRAME_STREAM,
35050aadb33SDmitri Tikhonov    [0x95] = QUIC_FRAME_STREAM,
35150aadb33SDmitri Tikhonov    [0x96] = QUIC_FRAME_STREAM,
35250aadb33SDmitri Tikhonov    [0x97] = QUIC_FRAME_STREAM,
35350aadb33SDmitri Tikhonov    [0x98] = QUIC_FRAME_STREAM,
35450aadb33SDmitri Tikhonov    [0x99] = QUIC_FRAME_STREAM,
35550aadb33SDmitri Tikhonov    [0x9A] = QUIC_FRAME_STREAM,
35650aadb33SDmitri Tikhonov    [0x9B] = QUIC_FRAME_STREAM,
35750aadb33SDmitri Tikhonov    [0x9C] = QUIC_FRAME_STREAM,
35850aadb33SDmitri Tikhonov    [0x9D] = QUIC_FRAME_STREAM,
35950aadb33SDmitri Tikhonov    [0x9E] = QUIC_FRAME_STREAM,
36050aadb33SDmitri Tikhonov    [0x9F] = QUIC_FRAME_STREAM,
36150aadb33SDmitri Tikhonov    [0xA0] = QUIC_FRAME_STREAM,
36250aadb33SDmitri Tikhonov    [0xA1] = QUIC_FRAME_STREAM,
36350aadb33SDmitri Tikhonov    [0xA2] = QUIC_FRAME_STREAM,
36450aadb33SDmitri Tikhonov    [0xA3] = QUIC_FRAME_STREAM,
36550aadb33SDmitri Tikhonov    [0xA4] = QUIC_FRAME_STREAM,
36650aadb33SDmitri Tikhonov    [0xA5] = QUIC_FRAME_STREAM,
36750aadb33SDmitri Tikhonov    [0xA6] = QUIC_FRAME_STREAM,
36850aadb33SDmitri Tikhonov    [0xA7] = QUIC_FRAME_STREAM,
36950aadb33SDmitri Tikhonov    [0xA8] = QUIC_FRAME_STREAM,
37050aadb33SDmitri Tikhonov    [0xA9] = QUIC_FRAME_STREAM,
37150aadb33SDmitri Tikhonov    [0xAA] = QUIC_FRAME_STREAM,
37250aadb33SDmitri Tikhonov    [0xAB] = QUIC_FRAME_STREAM,
37350aadb33SDmitri Tikhonov    [0xAC] = QUIC_FRAME_STREAM,
37450aadb33SDmitri Tikhonov    [0xAD] = QUIC_FRAME_STREAM,
37550aadb33SDmitri Tikhonov    [0xAE] = QUIC_FRAME_STREAM,
37650aadb33SDmitri Tikhonov    [0xAF] = QUIC_FRAME_STREAM,
37750aadb33SDmitri Tikhonov    [0xB0] = QUIC_FRAME_STREAM,
37850aadb33SDmitri Tikhonov    [0xB1] = QUIC_FRAME_STREAM,
37950aadb33SDmitri Tikhonov    [0xB2] = QUIC_FRAME_STREAM,
38050aadb33SDmitri Tikhonov    [0xB3] = QUIC_FRAME_STREAM,
38150aadb33SDmitri Tikhonov    [0xB4] = QUIC_FRAME_STREAM,
38250aadb33SDmitri Tikhonov    [0xB5] = QUIC_FRAME_STREAM,
38350aadb33SDmitri Tikhonov    [0xB6] = QUIC_FRAME_STREAM,
38450aadb33SDmitri Tikhonov    [0xB7] = QUIC_FRAME_STREAM,
38550aadb33SDmitri Tikhonov    [0xB8] = QUIC_FRAME_STREAM,
38650aadb33SDmitri Tikhonov    [0xB9] = QUIC_FRAME_STREAM,
38750aadb33SDmitri Tikhonov    [0xBA] = QUIC_FRAME_STREAM,
38850aadb33SDmitri Tikhonov    [0xBB] = QUIC_FRAME_STREAM,
38950aadb33SDmitri Tikhonov    [0xBC] = QUIC_FRAME_STREAM,
39050aadb33SDmitri Tikhonov    [0xBD] = QUIC_FRAME_STREAM,
39150aadb33SDmitri Tikhonov    [0xBE] = QUIC_FRAME_STREAM,
39250aadb33SDmitri Tikhonov    [0xBF] = QUIC_FRAME_STREAM,
39350aadb33SDmitri Tikhonov    [0xC0] = QUIC_FRAME_STREAM,
39450aadb33SDmitri Tikhonov    [0xC1] = QUIC_FRAME_STREAM,
39550aadb33SDmitri Tikhonov    [0xC2] = QUIC_FRAME_STREAM,
39650aadb33SDmitri Tikhonov    [0xC3] = QUIC_FRAME_STREAM,
39750aadb33SDmitri Tikhonov    [0xC4] = QUIC_FRAME_STREAM,
39850aadb33SDmitri Tikhonov    [0xC5] = QUIC_FRAME_STREAM,
39950aadb33SDmitri Tikhonov    [0xC6] = QUIC_FRAME_STREAM,
40050aadb33SDmitri Tikhonov    [0xC7] = QUIC_FRAME_STREAM,
40150aadb33SDmitri Tikhonov    [0xC8] = QUIC_FRAME_STREAM,
40250aadb33SDmitri Tikhonov    [0xC9] = QUIC_FRAME_STREAM,
40350aadb33SDmitri Tikhonov    [0xCA] = QUIC_FRAME_STREAM,
40450aadb33SDmitri Tikhonov    [0xCB] = QUIC_FRAME_STREAM,
40550aadb33SDmitri Tikhonov    [0xCC] = QUIC_FRAME_STREAM,
40650aadb33SDmitri Tikhonov    [0xCD] = QUIC_FRAME_STREAM,
40750aadb33SDmitri Tikhonov    [0xCE] = QUIC_FRAME_STREAM,
40850aadb33SDmitri Tikhonov    [0xCF] = QUIC_FRAME_STREAM,
40950aadb33SDmitri Tikhonov    [0xD0] = QUIC_FRAME_STREAM,
41050aadb33SDmitri Tikhonov    [0xD1] = QUIC_FRAME_STREAM,
41150aadb33SDmitri Tikhonov    [0xD2] = QUIC_FRAME_STREAM,
41250aadb33SDmitri Tikhonov    [0xD3] = QUIC_FRAME_STREAM,
41350aadb33SDmitri Tikhonov    [0xD4] = QUIC_FRAME_STREAM,
41450aadb33SDmitri Tikhonov    [0xD5] = QUIC_FRAME_STREAM,
41550aadb33SDmitri Tikhonov    [0xD6] = QUIC_FRAME_STREAM,
41650aadb33SDmitri Tikhonov    [0xD7] = QUIC_FRAME_STREAM,
41750aadb33SDmitri Tikhonov    [0xD8] = QUIC_FRAME_STREAM,
41850aadb33SDmitri Tikhonov    [0xD9] = QUIC_FRAME_STREAM,
41950aadb33SDmitri Tikhonov    [0xDA] = QUIC_FRAME_STREAM,
42050aadb33SDmitri Tikhonov    [0xDB] = QUIC_FRAME_STREAM,
42150aadb33SDmitri Tikhonov    [0xDC] = QUIC_FRAME_STREAM,
42250aadb33SDmitri Tikhonov    [0xDD] = QUIC_FRAME_STREAM,
42350aadb33SDmitri Tikhonov    [0xDE] = QUIC_FRAME_STREAM,
42450aadb33SDmitri Tikhonov    [0xDF] = QUIC_FRAME_STREAM,
42550aadb33SDmitri Tikhonov    [0xE0] = QUIC_FRAME_STREAM,
42650aadb33SDmitri Tikhonov    [0xE1] = QUIC_FRAME_STREAM,
42750aadb33SDmitri Tikhonov    [0xE2] = QUIC_FRAME_STREAM,
42850aadb33SDmitri Tikhonov    [0xE3] = QUIC_FRAME_STREAM,
42950aadb33SDmitri Tikhonov    [0xE4] = QUIC_FRAME_STREAM,
43050aadb33SDmitri Tikhonov    [0xE5] = QUIC_FRAME_STREAM,
43150aadb33SDmitri Tikhonov    [0xE6] = QUIC_FRAME_STREAM,
43250aadb33SDmitri Tikhonov    [0xE7] = QUIC_FRAME_STREAM,
43350aadb33SDmitri Tikhonov    [0xE8] = QUIC_FRAME_STREAM,
43450aadb33SDmitri Tikhonov    [0xE9] = QUIC_FRAME_STREAM,
43550aadb33SDmitri Tikhonov    [0xEA] = QUIC_FRAME_STREAM,
43650aadb33SDmitri Tikhonov    [0xEB] = QUIC_FRAME_STREAM,
43750aadb33SDmitri Tikhonov    [0xEC] = QUIC_FRAME_STREAM,
43850aadb33SDmitri Tikhonov    [0xED] = QUIC_FRAME_STREAM,
43950aadb33SDmitri Tikhonov    [0xEE] = QUIC_FRAME_STREAM,
44050aadb33SDmitri Tikhonov    [0xEF] = QUIC_FRAME_STREAM,
44150aadb33SDmitri Tikhonov    [0xF0] = QUIC_FRAME_STREAM,
44250aadb33SDmitri Tikhonov    [0xF1] = QUIC_FRAME_STREAM,
44350aadb33SDmitri Tikhonov    [0xF2] = QUIC_FRAME_STREAM,
44450aadb33SDmitri Tikhonov    [0xF3] = QUIC_FRAME_STREAM,
44550aadb33SDmitri Tikhonov    [0xF4] = QUIC_FRAME_STREAM,
44650aadb33SDmitri Tikhonov    [0xF5] = QUIC_FRAME_STREAM,
44750aadb33SDmitri Tikhonov    [0xF6] = QUIC_FRAME_STREAM,
44850aadb33SDmitri Tikhonov    [0xF7] = QUIC_FRAME_STREAM,
44950aadb33SDmitri Tikhonov    [0xF8] = QUIC_FRAME_STREAM,
45050aadb33SDmitri Tikhonov    [0xF9] = QUIC_FRAME_STREAM,
45150aadb33SDmitri Tikhonov    [0xFA] = QUIC_FRAME_STREAM,
45250aadb33SDmitri Tikhonov    [0xFB] = QUIC_FRAME_STREAM,
45350aadb33SDmitri Tikhonov    [0xFC] = QUIC_FRAME_STREAM,
45450aadb33SDmitri Tikhonov    [0xFD] = QUIC_FRAME_STREAM,
45550aadb33SDmitri Tikhonov    [0xFE] = QUIC_FRAME_STREAM,
45650aadb33SDmitri Tikhonov    [0xFF] = QUIC_FRAME_STREAM,
45750aadb33SDmitri Tikhonov};
45850aadb33SDmitri Tikhonov
45950aadb33SDmitri Tikhonov
4606aba801dSDmitri Tikhonovenum quic_frame_type
461feca77f5SDmitri Tikhonovlsquic_parse_frame_type_gquic_Q035_thru_Q046 (const unsigned char *buf,
462feca77f5SDmitri Tikhonov                                                                size_t len)
46350aadb33SDmitri Tikhonov{
464feca77f5SDmitri Tikhonov    if (len > 0)
465feca77f5SDmitri Tikhonov        return byte2frame_type_Q035_thru_Q046[buf[0]];
466feca77f5SDmitri Tikhonov    else
467feca77f5SDmitri Tikhonov        return QUIC_FRAME_INVALID;
46850aadb33SDmitri Tikhonov}
46950aadb33SDmitri Tikhonov
47050aadb33SDmitri Tikhonov
471c51ce338SDmitri Tikhonovvoid
4727a8b2eceSDmitri Tikhonovlsquic_turn_on_fin_Q035_thru_Q046 (unsigned char *stream_header)
473c51ce338SDmitri Tikhonov{
474c51ce338SDmitri Tikhonov    /* 1fdoooss */
475c51ce338SDmitri Tikhonov    *stream_header |= 0x40;
476c51ce338SDmitri Tikhonov}
477c51ce338SDmitri Tikhonov
478c51ce338SDmitri Tikhonov
47950aadb33SDmitri Tikhonovsize_t
480a5fa05f9SDmitri Tikhonovlsquic_calc_stream_frame_header_sz_gquic (lsquic_stream_id_t stream_id,
4815392f7a3SLiteSpeed Tech                                    uint64_t offset, unsigned data_sz_IGNORED)
48250aadb33SDmitri Tikhonov{
48350aadb33SDmitri Tikhonov    return
48450aadb33SDmitri Tikhonov        /* Type */
48550aadb33SDmitri Tikhonov        1
48650aadb33SDmitri Tikhonov        /* Stream ID length */
48750aadb33SDmitri Tikhonov      + ((stream_id) > 0x0000FF)
48850aadb33SDmitri Tikhonov      + ((stream_id) > 0x00FFFF)
48950aadb33SDmitri Tikhonov      + ((stream_id) > 0xFFFFFF)
49050aadb33SDmitri Tikhonov      + 1
49150aadb33SDmitri Tikhonov        /* Offset length */
49250aadb33SDmitri Tikhonov      + ((offset) >= (1ULL << 56))
49350aadb33SDmitri Tikhonov      + ((offset) >= (1ULL << 48))
49450aadb33SDmitri Tikhonov      + ((offset) >= (1ULL << 40))
49550aadb33SDmitri Tikhonov      + ((offset) >= (1ULL << 32))
49650aadb33SDmitri Tikhonov      + ((offset) >= (1ULL << 24))
49750aadb33SDmitri Tikhonov      + ((offset) >= (1ULL << 16))
49850aadb33SDmitri Tikhonov      + (((offset) > 0) << 1)
49950aadb33SDmitri Tikhonov        /* Add data length (2) yourself, if necessary */
50050aadb33SDmitri Tikhonov    ;
50150aadb33SDmitri Tikhonov}
50250aadb33SDmitri Tikhonov
50350aadb33SDmitri Tikhonov
5045392f7a3SLiteSpeed Techstatic const char *const ecn2str[4] =
5055392f7a3SLiteSpeed Tech{
5065392f7a3SLiteSpeed Tech    [ECN_NOT_ECT]   = "",
5075392f7a3SLiteSpeed Tech    [ECN_ECT0]      = "ECT(0)",
5085392f7a3SLiteSpeed Tech    [ECN_ECT1]      = "ECT(1)",
5095392f7a3SLiteSpeed Tech    [ECN_CE]        = "CE",
5105392f7a3SLiteSpeed Tech};
5115392f7a3SLiteSpeed Tech
5125392f7a3SLiteSpeed Tech
513de46bf2fSDmitri Tikhonovvoid
514de46bf2fSDmitri Tikhonovlsquic_acki2str (const struct ack_info *acki, char *buf, size_t bufsz)
51550aadb33SDmitri Tikhonov{
516de46bf2fSDmitri Tikhonov    size_t off, nw;
5175392f7a3SLiteSpeed Tech    enum ecn ecn;
51850aadb33SDmitri Tikhonov    unsigned n;
51950aadb33SDmitri Tikhonov
52050aadb33SDmitri Tikhonov    off = 0;
52150aadb33SDmitri Tikhonov    for (n = 0; n < acki->n_ranges; ++n)
52250aadb33SDmitri Tikhonov    {
52350aadb33SDmitri Tikhonov        nw = snprintf(buf + off, bufsz - off, "[%"PRIu64"-%"PRIu64"]",
52450aadb33SDmitri Tikhonov                acki->ranges[n].high, acki->ranges[n].low);
52550aadb33SDmitri Tikhonov        if (nw > bufsz - off)
526de46bf2fSDmitri Tikhonov            return;
52750aadb33SDmitri Tikhonov        off += nw;
52850aadb33SDmitri Tikhonov    }
52950aadb33SDmitri Tikhonov
5305392f7a3SLiteSpeed Tech    if (acki->flags & AI_TRUNCATED)
5315392f7a3SLiteSpeed Tech    {
532de46bf2fSDmitri Tikhonov        nw = snprintf(buf + off, bufsz - off, RANGES_TRUNCATED_STR);
5335392f7a3SLiteSpeed Tech        if (nw > bufsz - off)
534de46bf2fSDmitri Tikhonov            return;
5355392f7a3SLiteSpeed Tech        off += nw;
5365392f7a3SLiteSpeed Tech    }
5375392f7a3SLiteSpeed Tech
5385392f7a3SLiteSpeed Tech    if (acki->flags & AI_ECN)
5395392f7a3SLiteSpeed Tech    {
5405392f7a3SLiteSpeed Tech        for (ecn = 1; ecn <= 3; ++ecn)
5415392f7a3SLiteSpeed Tech        {
5425392f7a3SLiteSpeed Tech            nw = snprintf(buf + off, bufsz - off, " %s: %"PRIu64"%.*s",
5435392f7a3SLiteSpeed Tech                        ecn2str[ecn], acki->ecn_counts[ecn], ecn < 3, ";");
5445392f7a3SLiteSpeed Tech            if (nw > bufsz - off)
545de46bf2fSDmitri Tikhonov                return;
5465392f7a3SLiteSpeed Tech            off += nw;
5475392f7a3SLiteSpeed Tech        }
5485392f7a3SLiteSpeed Tech    }
54950aadb33SDmitri Tikhonov}
5509626cfc2SDmitri Tikhonov
5519626cfc2SDmitri Tikhonov
5529626cfc2SDmitri Tikhonovsize_t
5539626cfc2SDmitri Tikhonovlsquic_gquic_po_header_sz (enum packet_out_flags flags)
5549626cfc2SDmitri Tikhonov{
5559626cfc2SDmitri Tikhonov    return 1                                                /* Type */
5569626cfc2SDmitri Tikhonov           + (!!(flags & PO_CONN_ID) << 3)                  /* Connection ID */
5579626cfc2SDmitri Tikhonov           + (!!(flags & PO_VERSION) << 2)                  /* Version */
5589626cfc2SDmitri Tikhonov           + (!!(flags & PO_NONCE)   << 5)                  /* Nonce */
559c7d81ce1SDmitri Tikhonov           + gquic_packno_bits2len((flags >> POBIT_SHIFT) & 0x3)  /* Packet number */
5609626cfc2SDmitri Tikhonov           ;
5619626cfc2SDmitri Tikhonov}
5629626cfc2SDmitri Tikhonov
5639626cfc2SDmitri Tikhonov
5649626cfc2SDmitri Tikhonovsize_t
5659626cfc2SDmitri Tikhonovlsquic_gquic_packout_size (const struct lsquic_conn *conn,
5669626cfc2SDmitri Tikhonov                                const struct lsquic_packet_out *packet_out)
5679626cfc2SDmitri Tikhonov{
5689626cfc2SDmitri Tikhonov    return lsquic_gquic_po_header_sz(packet_out->po_flags)
5699626cfc2SDmitri Tikhonov         + packet_out->po_data_sz
5705392f7a3SLiteSpeed Tech         + GQUIC_PACKET_HASH_SZ
5719626cfc2SDmitri Tikhonov         ;
5729626cfc2SDmitri Tikhonov}
5739626cfc2SDmitri Tikhonov
5749626cfc2SDmitri Tikhonov
5759626cfc2SDmitri Tikhonovsize_t
5769626cfc2SDmitri Tikhonovlsquic_gquic_packout_header_size (const struct lsquic_conn *conn,
5774429f8eaSDmitri Tikhonov                                enum packet_out_flags flags, size_t dcid_len,
5784429f8eaSDmitri Tikhonov                                enum header_type unused)
5799626cfc2SDmitri Tikhonov{
5809626cfc2SDmitri Tikhonov    return lsquic_gquic_po_header_sz(flags);
5819626cfc2SDmitri Tikhonov}
5829626cfc2SDmitri Tikhonov
5839626cfc2SDmitri Tikhonov
5845392f7a3SLiteSpeed Techint
5855392f7a3SLiteSpeed Techlsquic_gquic_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz,
5865392f7a3SLiteSpeed Tech                        const lsquic_cid_t *cid, unsigned version_bitmask)
5875392f7a3SLiteSpeed Tech{
5885392f7a3SLiteSpeed Tech    int sz;
5895392f7a3SLiteSpeed Tech    unsigned char *p = buf;
5905392f7a3SLiteSpeed Tech    unsigned char *const pend = p + bufsz;
5915392f7a3SLiteSpeed Tech
5925392f7a3SLiteSpeed Tech    CHECK_SPACE(1, p, pend);
5935392f7a3SLiteSpeed Tech    *p = PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID;
5945392f7a3SLiteSpeed Tech    ++p;
5955392f7a3SLiteSpeed Tech
5965392f7a3SLiteSpeed Tech    if (GQUIC_CID_LEN != cid->len)
5975392f7a3SLiteSpeed Tech        return -1;
5985392f7a3SLiteSpeed Tech
5995392f7a3SLiteSpeed Tech    CHECK_SPACE(GQUIC_CID_LEN, p, pend);
6005392f7a3SLiteSpeed Tech    memcpy(p, cid->idbuf, GQUIC_CID_LEN);
6015392f7a3SLiteSpeed Tech    p += GQUIC_CID_LEN;
6025392f7a3SLiteSpeed Tech
6035392f7a3SLiteSpeed Tech    sz = lsquic_gen_ver_tags(p, pend - p, version_bitmask);
6045392f7a3SLiteSpeed Tech    if (sz < 0)
6055392f7a3SLiteSpeed Tech        return -1;
6065392f7a3SLiteSpeed Tech
6075392f7a3SLiteSpeed Tech    return p + sz - buf;
6085392f7a3SLiteSpeed Tech}
6095392f7a3SLiteSpeed Tech
6105392f7a3SLiteSpeed Tech
611c7d81ce1SDmitri Tikhonovunsigned
612c7d81ce1SDmitri Tikhonovlsquic_gquic_packno_bits2len (enum packno_bits bits)
613c7d81ce1SDmitri Tikhonov{
614c7d81ce1SDmitri Tikhonov    return gquic_packno_bits2len(bits);
615c7d81ce1SDmitri Tikhonov}
616c7d81ce1SDmitri Tikhonov
617c7d81ce1SDmitri Tikhonov
618c7d81ce1SDmitri Tikhonovenum packno_bits
619c7d81ce1SDmitri Tikhonovlsquic_gquic_calc_packno_bits (lsquic_packno_t packno,
620c7d81ce1SDmitri Tikhonov                        lsquic_packno_t least_unacked, uint64_t n_in_flight)
621c7d81ce1SDmitri Tikhonov{
622c7d81ce1SDmitri Tikhonov    uint64_t delta;
623c7d81ce1SDmitri Tikhonov    unsigned bits;
624c7d81ce1SDmitri Tikhonov
625c7d81ce1SDmitri Tikhonov    delta = packno - least_unacked;
626c7d81ce1SDmitri Tikhonov    if (n_in_flight > delta)
627c7d81ce1SDmitri Tikhonov        delta = n_in_flight;
628c7d81ce1SDmitri Tikhonov
629c7d81ce1SDmitri Tikhonov    delta *= 4;
630c7d81ce1SDmitri Tikhonov    bits = (delta > (1ULL <<  8))
631c7d81ce1SDmitri Tikhonov         + (delta > (1ULL << 16))
632c7d81ce1SDmitri Tikhonov         + (delta > (1ULL << 32));
633c7d81ce1SDmitri Tikhonov
634c7d81ce1SDmitri Tikhonov    return bits;
635c7d81ce1SDmitri Tikhonov}
636de46bf2fSDmitri Tikhonov
637de46bf2fSDmitri Tikhonov
638de46bf2fSDmitri Tikhonov/* `dst' serves both as source and destination.  `src' is the new frame */
639de46bf2fSDmitri Tikhonovint
640de46bf2fSDmitri Tikhonovlsquic_merge_acks (struct ack_info *dst, const struct ack_info *src)
641de46bf2fSDmitri Tikhonov{
642de46bf2fSDmitri Tikhonov    const struct lsquic_packno_range *a, *a_end, *b, *b_end, **p;
643de46bf2fSDmitri Tikhonov    struct lsquic_packno_range *out, *out_end;
644de46bf2fSDmitri Tikhonov    unsigned i;
64549f1f4f6SDmitri Tikhonov    int ok;
646de46bf2fSDmitri Tikhonov    struct lsquic_packno_range out_ranges[256];
647de46bf2fSDmitri Tikhonov
648de46bf2fSDmitri Tikhonov    if (!(dst->n_ranges && src->n_ranges))
649de46bf2fSDmitri Tikhonov        return -1;
650de46bf2fSDmitri Tikhonov
651de46bf2fSDmitri Tikhonov    a = dst->ranges;
652de46bf2fSDmitri Tikhonov    a_end = a + dst->n_ranges;
653de46bf2fSDmitri Tikhonov    b = src->ranges;
654de46bf2fSDmitri Tikhonov    b_end = b + src->n_ranges;
655de46bf2fSDmitri Tikhonov    out = out_ranges;
656de46bf2fSDmitri Tikhonov    out_end = out + sizeof(out_ranges) / sizeof(out_ranges[0]);
657de46bf2fSDmitri Tikhonov
658de46bf2fSDmitri Tikhonov    if (a->high >= b->high)
659de46bf2fSDmitri Tikhonov        *out = *a;
660de46bf2fSDmitri Tikhonov    else
661de46bf2fSDmitri Tikhonov        *out = *b;
662de46bf2fSDmitri Tikhonov
663de46bf2fSDmitri Tikhonov    while (1)
664de46bf2fSDmitri Tikhonov    {
665de46bf2fSDmitri Tikhonov        if (a < a_end && b < b_end)
666de46bf2fSDmitri Tikhonov        {
667de46bf2fSDmitri Tikhonov            if (a->high >= b->high)
668de46bf2fSDmitri Tikhonov                p = &a;
669de46bf2fSDmitri Tikhonov            else
670de46bf2fSDmitri Tikhonov                p = &b;
671de46bf2fSDmitri Tikhonov        }
672de46bf2fSDmitri Tikhonov        else if (a < a_end)
673de46bf2fSDmitri Tikhonov            p = &a;
674de46bf2fSDmitri Tikhonov        else if (b < b_end)
675de46bf2fSDmitri Tikhonov            p = &b;
676de46bf2fSDmitri Tikhonov        else
677de46bf2fSDmitri Tikhonov        {
678de46bf2fSDmitri Tikhonov            ++out;
679de46bf2fSDmitri Tikhonov            break;
680de46bf2fSDmitri Tikhonov        }
681de46bf2fSDmitri Tikhonov
682de46bf2fSDmitri Tikhonov        if ((*p)->high + 1 >= out->low)
683de46bf2fSDmitri Tikhonov            out->low = (*p)->low;
684de46bf2fSDmitri Tikhonov        else if (out + 1 < out_end)
685de46bf2fSDmitri Tikhonov            *++out = **p;
686de46bf2fSDmitri Tikhonov        else
687de46bf2fSDmitri Tikhonov            return -1;
688de46bf2fSDmitri Tikhonov        ++*p;
689de46bf2fSDmitri Tikhonov    }
690de46bf2fSDmitri Tikhonov
691de46bf2fSDmitri Tikhonov    if (src->flags & AI_ECN)
69249f1f4f6SDmitri Tikhonov    {
69349f1f4f6SDmitri Tikhonov        /* New ACK frame (src) should not contain ECN counts that are smaller
69449f1f4f6SDmitri Tikhonov         * than previous ACK frame, otherwise we cannot merge.
69549f1f4f6SDmitri Tikhonov         */
69649f1f4f6SDmitri Tikhonov        ok = 1;
697de46bf2fSDmitri Tikhonov        for (i = 0; i < sizeof(src->ecn_counts)
698de46bf2fSDmitri Tikhonov                                        / sizeof(src->ecn_counts[0]); ++i)
69949f1f4f6SDmitri Tikhonov            ok &= dst->ecn_counts[i] <= src->ecn_counts[i];
70049f1f4f6SDmitri Tikhonov        if (ok)
70149f1f4f6SDmitri Tikhonov            for (i = 0; i < sizeof(src->ecn_counts)
70249f1f4f6SDmitri Tikhonov                                            / sizeof(src->ecn_counts[0]); ++i)
70349f1f4f6SDmitri Tikhonov                dst->ecn_counts[i] = src->ecn_counts[i];
70449f1f4f6SDmitri Tikhonov        else
70549f1f4f6SDmitri Tikhonov            return -1;
70649f1f4f6SDmitri Tikhonov    }
707de46bf2fSDmitri Tikhonov    dst->flags |= src->flags;
708de46bf2fSDmitri Tikhonov    dst->lack_delta = src->lack_delta;
709de46bf2fSDmitri Tikhonov    dst->n_ranges = out - out_ranges;
710de46bf2fSDmitri Tikhonov    memcpy(dst->ranges, out_ranges, sizeof(out_ranges[0]) * dst->n_ranges);
711de46bf2fSDmitri Tikhonov
712de46bf2fSDmitri Tikhonov    return 0;
713de46bf2fSDmitri Tikhonov}
714