1.11.0: [FEATURE] Add support for Q044

This commit is contained in:
Dmitri Tikhonov 2018-08-15 15:06:31 -04:00
parent c6457e4258
commit 9626cfc25b
34 changed files with 1157 additions and 279 deletions

View File

@ -1,3 +1,8 @@
2018-08-15
- 1.11.0
- [FEATURE] Add support for Q044.
2018-08-09
- 1.10.2

View File

@ -13,10 +13,10 @@ our own products: LiteSpeed Web Server and ADC. We think it is free of
major problems. Nevertheless, do not hesitate to report bugs back to us.
Even better, send us fixes and improvements!
Currently supported QUIC versions are Q035, Q039, and Q043. Support for
newer versions will be added soon after they are released. The version(s)
specified by IETF QUIC WG will be added once the IETF version of the
protocol settles down a little.
Currently supported QUIC versions are Q035, Q039, Q043, and Q044. Support
for newer versions will be added soon after they are released. The
version(s) specified by IETF QUIC WG will be added once the IETF version
of the protocol settles down a little.
Documentation
-------------

View File

@ -24,8 +24,8 @@ extern "C" {
#endif
#define LSQUIC_MAJOR_VERSION 1
#define LSQUIC_MINOR_VERSION 10
#define LSQUIC_PATCH_VERSION 2
#define LSQUIC_MINOR_VERSION 11
#define LSQUIC_PATCH_VERSION 0
/**
* Engine flags:
@ -97,23 +97,45 @@ enum lsquic_version
*/
LSQVER_043,
/**
* Q044. IETF-like packet headers are used. Frames are the same as
* in Q043. Server never includes CIDs in short packets.
*/
LSQVER_044,
#if LSQUIC_USE_Q098
/**
* Q098. This is a made-up, experimental version used to test version
* negotiation. The choice of 98 is similar to Google's choice of 99
* as the "IETF" version.
*/
LSQVER_098,
#define LSQUIC_EXPERIMENTAL_Q098 (1 << LSQVER_098)
#else
#define LSQUIC_EXPERIMENTAL_Q098 0
#endif
N_LSQVER
};
/**
* We currently support versions 35, 39, and 43.
* We currently support versions 35, 39, 43, and 44.
* @see lsquic_version
*/
#define LSQUIC_SUPPORTED_VERSIONS ((1 << N_LSQVER) - 1)
#define LSQUIC_EXPERIMENTAL_VERSIONS 0
#define LSQUIC_EXPERIMENTAL_VERSIONS (0 \
| LSQUIC_EXPERIMENTAL_Q098)
#define LSQUIC_DEPRECATED_VERSIONS 0
#define LSQUIC_GQUIC_HEADER_VERSIONS ( \
(1 << LSQVER_035) | (1 << LSQVER_039) | (1 << LSQVER_043))
/**
* List of version in which the server does not include CID in short packets.
* List of versions in which the server never includes CID in short packets.
*/
#define LSQUIC_FORCED_TCID0_VERSIONS 0
#define LSQUIC_FORCED_TCID0_VERSIONS (1 << LSQVER_044)
/**
* @struct lsquic_stream_if
@ -330,6 +352,9 @@ struct lsquic_engine_settings {
* (source-addr, dest-addr) tuple, thereby making it necessary to create
* a socket for each connection.
*
* This option has no effect in Q044, as the server never includes CIDs
* in the short packets.
*
* The default is @ref LSQUIC_DF_SUPPORT_TCID0.
*/
int es_support_tcid0;

View File

@ -6,6 +6,8 @@ SET(lsquic_STAT_SRCS
lsquic_chsk_stream.c
lsquic_engine.c
lsquic_parse_gquic_common.c
lsquic_parse_iquic_common.c
lsquic_parse_common.c
lsquic_parse_gquic_le.c
lsquic_parse_gquic_be.c
lsquic_packet_in.c
@ -50,6 +52,7 @@ SET(lsquic_STAT_SRCS
lsquic_buf.c
lsquic_min_heap.c
lshpack.c
lsquic_parse_Q044.c
)

View File

@ -0,0 +1,23 @@
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
#ifndef LSQUIC_BYTESWAP_H
#define LSQUIC_BYTESWAP_H 1
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
#include <sys/endian.h>
#define bswap_16 bswap16
#define bswap_32 bswap32
#define bswap_64 bswap64
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define bswap_16 OSSwapInt16
#define bswap_32 OSSwapInt32
#define bswap_64 OSSwapInt64
#elif defined(WIN32)
#define bswap_16 _byteswap_ushort
#define bswap_32 _byteswap_ulong
#define bswap_64 _byteswap_uint64
#else
#include <byteswap.h>
#endif
#endif

View File

@ -126,8 +126,8 @@ lsquic_conn_decrypt_packet (lsquic_conn_t *lconn,
| (enc_level << PIBIT_ENC_LEV_SHIFT);
packet_in->pi_header_sz = header_len;
packet_in->pi_data_sz = out_len + header_len;
EV_LOG_CONN_EVENT(lconn->cn_cid, "decrypted packet %"PRIu64,
packet_in->pi_packno);
EV_LOG_CONN_EVENT(lconn->cn_cid, "decrypted packet %"PRIu64" crypto: %s",
packet_in->pi_packno, lsquic_enclev2str[ enc_level ]);
return 0;
}

View File

@ -27,6 +27,7 @@
#include "lsquic.h"
#include "lsquic_types.h"
#include "lsquic_alarmset.h"
#include "lsquic_parse_common.h"
#include "lsquic_parse.h"
#include "lsquic_packet_in.h"
#include "lsquic_packet_out.h"
@ -261,6 +262,18 @@ static const struct lsquic_packout_mem_if stock_pmi =
};
static int
hash_conns_by_addr (const struct lsquic_engine *engine)
{
if (engine->pub.enp_settings.es_versions & LSQUIC_FORCED_TCID0_VERSIONS)
return 1;
if ((engine->pub.enp_settings.es_versions & LSQUIC_GQUIC_HEADER_VERSIONS)
&& engine->pub.enp_settings.es_support_tcid0)
return 1;
return 0;
}
lsquic_engine_t *
lsquic_engine_new (unsigned flags,
const struct lsquic_engine_api *api)
@ -295,7 +308,7 @@ lsquic_engine_new (unsigned flags,
engine->pub.enp_settings = *api->ea_settings;
else
lsquic_engine_init_settings(&engine->pub.enp_settings, flags);
tag_buf_len = gen_ver_tags(engine->pub.enp_ver_tags_buf,
tag_buf_len = lsquic_gen_ver_tags(engine->pub.enp_ver_tags_buf,
sizeof(engine->pub.enp_ver_tags_buf),
engine->pub.enp_settings.es_versions);
if (tag_buf_len <= 0)
@ -324,8 +337,7 @@ lsquic_engine_new (unsigned flags,
}
engine->pub.enp_engine = engine;
conn_hash_init(&engine->conns_hash,
!(flags & ENG_SERVER) && engine->pub.enp_settings.es_support_tcid0 ?
CHF_USE_ADDR : 0);
hash_conns_by_addr(engine) ? CHF_USE_ADDR : 0);
engine->attq = attq_create();
eng_hist_init(&engine->history);
engine->batch_size = INITIAL_OUT_BATCH_SIZE;
@ -498,7 +510,7 @@ process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
{
lsquic_conn_t *conn;
if (lsquic_packet_in_is_prst(packet_in)
if (lsquic_packet_in_is_gquic_prst(packet_in)
&& !engine->pub.enp_settings.es_honor_prst)
{
lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in);
@ -758,44 +770,34 @@ lsquic_engine_process_conns (lsquic_engine_t *engine)
}
static int
generate_header (const lsquic_packet_out_t *packet_out,
const struct parse_funcs *pf, lsquic_cid_t cid,
unsigned char *buf, size_t bufsz)
{
return pf->pf_gen_reg_pkt_header(buf, bufsz,
packet_out->po_flags & PO_CONN_ID ? &cid : NULL,
packet_out->po_flags & PO_VERSION ? &packet_out->po_ver_tag : NULL,
packet_out->po_flags & PO_NONCE ? packet_out->po_nonce : NULL,
packet_out->po_packno, lsquic_packet_out_packno_bits(packet_out));
}
static ssize_t
really_encrypt_packet (const lsquic_conn_t *conn,
const lsquic_packet_out_t *packet_out,
struct lsquic_packet_out *packet_out,
unsigned char *buf, size_t bufsz)
{
int enc, header_sz, is_hello_packet;
int header_sz, is_hello_packet;
enum enc_level enc_level;
size_t packet_sz;
unsigned char header_buf[QUIC_MAX_PUBHDR_SZ];
header_sz = generate_header(packet_out, conn->cn_pf, conn->cn_cid,
header_sz = conn->cn_pf->pf_gen_reg_pkt_header(conn, packet_out,
header_buf, sizeof(header_buf));
if (header_sz < 0)
return -1;
is_hello_packet = !!(packet_out->po_flags & PO_HELLO);
enc = conn->cn_esf->esf_encrypt(conn->cn_enc_session, conn->cn_version, 0,
enc_level = conn->cn_esf->esf_encrypt(conn->cn_enc_session,
conn->cn_version, 0,
packet_out->po_packno, header_buf, header_sz,
packet_out->po_data, packet_out->po_data_sz,
buf, bufsz, &packet_sz, is_hello_packet);
if (0 == enc)
if ((int) enc_level >= 0)
{
LSQ_DEBUG("encrypted packet %"PRIu64"; plaintext is %u bytes, "
lsquic_packet_out_set_enc_level(packet_out, enc_level);
LSQ_DEBUG("encrypted packet %"PRIu64"; plaintext is %zu bytes, "
"ciphertext is %zd bytes",
packet_out->po_packno,
lsquic_po_header_length(packet_out->po_flags) +
conn->cn_pf->pf_packout_header_size(conn, packet_out->po_flags) +
packet_out->po_data_sz,
packet_sz);
return packet_sz;
@ -814,7 +816,7 @@ encrypt_packet (lsquic_engine_t *engine, const lsquic_conn_t *conn,
unsigned sent_sz;
unsigned char *buf;
bufsz = lsquic_po_header_length(packet_out->po_flags) +
bufsz = conn->cn_pf->pf_packout_header_size(conn, packet_out->po_flags) +
packet_out->po_data_sz + QUIC_PACKET_HASH_SZ;
buf = engine->pub.enp_pmi->pmi_allocate(engine->pub.enp_pmi_ctx, bufsz);
if (!buf)
@ -1281,6 +1283,8 @@ lsquic_engine_packet_in (lsquic_engine_t *engine,
{
struct packin_parse_state ppstate;
lsquic_packet_in_t *packet_in;
int (*parse_packet_in_begin) (struct lsquic_packet_in *, size_t length,
int is_server, struct packin_parse_state *);
if (packet_in_size > QUIC_MAX_PACKET_SZ)
{
@ -1290,6 +1294,20 @@ lsquic_engine_packet_in (lsquic_engine_t *engine,
return -1;
}
if (conn_hash_using_addr(&engine->conns_hash))
{
const struct lsquic_conn *conn;
conn = conn_hash_find_by_addr(&engine->conns_hash, sa_local);
if (!conn)
return -1;
if ((1 << conn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS)
parse_packet_in_begin = lsquic_gquic_parse_packet_in_begin;
else
parse_packet_in_begin = lsquic_iquic_parse_packet_in_begin;
}
else
parse_packet_in_begin = lsquic_parse_packet_in_begin;
packet_in = lsquic_mm_get_packet_in(&engine->pub.enp_mm);
if (!packet_in)
return -1;

View File

@ -19,6 +19,8 @@
#include "lsquic_parse.h"
#include "lsquic_frame_common.h"
#include "lsquic_frame_reader.h"
#include "lsquic_str.h"
#include "lsquic_handshake.h"
#include "lsquic_ev_log.h"
#define LSQUIC_LOGGER_MODULE LSQLM_EVENT
@ -39,7 +41,17 @@
void
lsquic_ev_log_packet_in (lsquic_cid_t cid, const lsquic_packet_in_t *packet_in)
{
LCID("packet in: %"PRIu64, packet_in->pi_packno);
switch (packet_in->pi_flags & (
PI_GQUIC))
{
case PI_GQUIC:
LCID("packet in: %"PRIu64, packet_in->pi_packno);
break;
default:
LCID("packet in: %"PRIu64", type: %s",
packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type]);
break;
}
}
@ -153,7 +165,7 @@ lsquic_ev_log_packet_sent (lsquic_cid_t cid,
packet_out->po_data_sz);
else if (lsquic_packet_out_pubres(packet_out))
LCID("sent public reset packet, size %hu", packet_out->po_data_sz);
else
else if (packet_out->po_flags & PO_GQUIC)
LCID("sent packet %"PRIu64", size %hu, frame types: %s",
packet_out->po_packno, packet_out->po_enc_data_sz,
/* Frame types is a list of different frames types contained
@ -162,6 +174,18 @@ lsquic_ev_log_packet_sent (lsquic_cid_t cid,
*/
lsquic_frame_types_to_str(frames, sizeof(frames),
packet_out->po_frame_types));
else
LCID("sent packet %"PRIu64", type %s, crypto: %s, size %hu, frame "
"types: %s",
packet_out->po_packno, lsquic_hety2str[packet_out->po_header_type],
lsquic_enclev2str[ lsquic_packet_out_enc_level(packet_out) ],
packet_out->po_enc_data_sz,
/* Frame types is a list of different frames types contained
* in the packet, no more. Count and order of frames is not
* printed.
*/
lsquic_frame_types_to_str(frames, sizeof(frames),
packet_out->po_frame_types));
}

View File

@ -383,6 +383,7 @@ set_versions (struct full_conn *conn, unsigned versions)
conn->fc_ver_neg.vn_ver = highest_bit_set(versions);
conn->fc_ver_neg.vn_buf = lsquic_ver2tag(conn->fc_ver_neg.vn_ver);
conn->fc_conn.cn_version = conn->fc_ver_neg.vn_ver;
conn->fc_conn.cn_pf = select_pf_by_ver(conn->fc_ver_neg.vn_ver);
LSQ_DEBUG("negotiating version %s",
lsquic_ver2str[conn->fc_ver_neg.vn_ver]);
}
@ -675,7 +676,6 @@ full_conn_client_new (struct lsquic_engine_public *enpub,
.stream_if = &lsquic_client_hsk_stream_if;
conn->fc_stream_ifs[STREAM_IF_HSK].stream_if_ctx = &conn->fc_hsk_ctx.client;
init_ver_neg(conn, conn->fc_settings->es_versions);
conn->fc_conn.cn_pf = select_pf_by_ver(conn->fc_ver_neg.vn_ver);
if (conn->fc_settings->es_handshake_to)
lsquic_alarmset_set(&conn->fc_alset, AL_HANDSHAKE,
lsquic_time_now() + conn->fc_settings->es_handshake_to);
@ -1872,6 +1872,18 @@ parse_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
}
static int
conn_is_stateless_reset (const struct full_conn *conn,
const struct lsquic_packet_in *packet_in)
{
return packet_in->pi_data_sz > SRST_LENGTH
&& 0 == conn->fc_conn.cn_esf->esf_verify_reset_token(
conn->fc_conn.cn_enc_session,
packet_in->pi_data + packet_in->pi_data_sz - SRST_LENGTH,
SRST_LENGTH);
}
static int
process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
{
@ -1893,11 +1905,20 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
if (0 == (packet_in->pi_flags & PI_DECRYPTED) &&
0 != conn_decrypt_packet(conn, packet_in))
{
LSQ_INFO("could not decrypt packet");
if (conn_is_stateless_reset(conn, packet_in))
{
LSQ_INFO("received public reset packet: aborting connection");
conn->fc_flags |= FC_GOT_PRST;
return -1;
}
else
{
LSQ_INFO("could not decrypt packet");
#if FULL_CONN_STATS
++conn->fc_stats.n_undec_packets;
++conn->fc_stats.n_undec_packets;
#endif
return 0;
return 0;
}
}
st = lsquic_rechist_received(&conn->fc_rechist, packet_in->pi_packno,
@ -1937,13 +1958,18 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
static int
process_incoming_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
{
int is_prst, is_verneg;
recent_packet_hist_new(conn, 0, packet_in->pi_received);
LSQ_DEBUG("Processing packet %"PRIu64, packet_in->pi_packno);
is_prst = lsquic_packet_in_is_gquic_prst(packet_in);
is_verneg = lsquic_packet_in_is_verneg(packet_in);
/* See flowchart in Section 4.1 of [draft-ietf-quic-transport-00]. We test
* for the common case first.
*/
const unsigned flags = lsquic_packet_in_public_flags(packet_in);
if (0 == (flags & (PACKET_PUBLIC_FLAGS_RST|PACKET_PUBLIC_FLAGS_VERSION)))
if (0 == is_prst && 0 == is_verneg)
{
if (conn->fc_ver_neg.vn_tag)
{
@ -1966,7 +1992,7 @@ process_incoming_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
}
return process_regular_packet(conn, packet_in);
}
else if (flags & PACKET_PUBLIC_FLAGS_RST)
else if (is_prst)
{
LSQ_INFO("received public reset packet: aborting connection");
conn->fc_flags |= FC_GOT_PRST;

View File

@ -60,6 +60,7 @@ enum enc_sess_history_event
ESHE_SET_STK = 'K',
ESHE_SET_SCID = 'D',
ESHE_SET_PROF = 'P',
ESHE_SET_SRST = 'S',
};
#endif
@ -71,6 +72,7 @@ typedef struct hs_ctx_st
HSET_SMHL = (1 << 1), /* smhl is set */
HSET_SCID = (1 << 2),
HSET_IRTT = (1 << 3),
HSET_SRST = (1 << 4),
} set;
enum {
HOPT_NSTP = (1 << 0), /* NSTP option present in COPT */
@ -95,6 +97,7 @@ typedef struct hs_ctx_st
//unsigned char chlo_hash[32]; //SHA256 HASH of CHLO
unsigned char nonc[DNONC_LENGTH]; /* 4 tm, 8 orbit ---> REJ, 20 rand */
unsigned char pubs[32];
unsigned char srst[SRST_LENGTH];
uint32_t rrej;
struct lsquic_str ccs;
@ -684,6 +687,18 @@ static int parse_hs_data (lsquic_enc_session_t *enc_session, uint32_t tag,
hs_ctx->sttl = get_tag_value_i64(val, len);
break;
case QTAG_SRST:
if (len != sizeof(hs_ctx->srst))
{
LSQ_INFO("Unexpected size of SRST: %u instead of %zu bytes",
len, sizeof(hs_ctx->srst));
return -1;
}
memcpy(hs_ctx->srst, val, len);
hs_ctx->set |= HSET_SRST;
ESHIST_APPEND(enc_session, ESHE_SET_SRST);
break;
default:
LSQ_DEBUG("Ignored tag '%.*s'", 4, (char *)&tag);
break;
@ -848,7 +863,7 @@ struct message_writer
memset(data_ptr + 4 + 2, 0, 2); \
(mw)->mw_entry = (void *) (data_ptr + 8); \
(mw)->mw_p = data_ptr + 8 + \
n_entries * sizeof((mw)->mw_entry[0]); \
(n_entries) * sizeof((mw)->mw_entry[0]); \
(mw)->mw_first_dummy_entry.tag = 0; \
(mw)->mw_first_dummy_entry.off = 0; \
(mw)->mw_prev_entry = &(mw)->mw_first_dummy_entry; \
@ -1575,7 +1590,7 @@ lsquic_enc_session_decrypt (lsquic_enc_session_t *enc_session,
}
static int
static enum enc_level
lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session,
enum lsquic_version version,
uint8_t path_id, uint64_t pack_num,
@ -1587,6 +1602,7 @@ lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session,
uint8_t md[HS_PKT_HASH_LENGTH];
uint128 hash;
int ret;
enum enc_level enc_level;
int is_chlo = (is_hello && ((IS_SERVER(enc_session)) == 0));
int is_shlo = (is_hello && (IS_SERVER(enc_session)));
@ -1620,7 +1636,7 @@ lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session,
memcpy(buf_out, header, header_len);
memcpy(buf_out + header_len, md, HS_PKT_HASH_LENGTH);
memcpy(buf_out + header_len + HS_PKT_HASH_LENGTH, data, data_len);
return 0;
return ENC_LEV_CLEAR;
}
else
{
@ -1635,12 +1651,14 @@ lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session,
{
enc_session->server_start_use_final_key = 1;
}
enc_level = ENC_LEV_INIT;
}
else
{
LSQ_DEBUG("lsquic_enc_session_encrypt using 'F' key...");
key = enc_session->enc_ctx_f;
memcpy(nonce, enc_session->enc_key_nonce_f, 4);
enc_level = ENC_LEV_FORW;
}
path_id_packet_number = combine_path_id_pack_num(path_id, pack_num);
memcpy(nonce + 4, &path_id_packet_number,
@ -1651,8 +1669,13 @@ lsquic_enc_session_encrypt (lsquic_enc_session_t *enc_session,
ret = aes_aead_enc(key, header, header_len, nonce, 12, data,
data_len, buf_out + header_len, out_len);
*out_len += header_len;
return ret;
if (ret == 0)
{
*out_len += header_len;
return enc_level;
}
else
return -1;
}
}
@ -1801,6 +1824,19 @@ lsquic_enc_session_mem_used (struct lsquic_enc_session *enc_session)
}
static int
lsquic_enc_session_verify_reset_token (lsquic_enc_session_t *enc_session,
const unsigned char *buf, size_t bufsz)
{
if (bufsz == SRST_LENGTH
&& (enc_session->hs_ctx.set & HSET_SRST)
&& 0 == memcmp(buf, enc_session->hs_ctx.srst, SRST_LENGTH))
return 0;
else
return -1;
}
#ifdef NDEBUG
const
#endif
@ -1822,4 +1858,14 @@ struct enc_session_funcs lsquic_enc_session_gquic_1 =
.esf_gen_chlo = lsquic_enc_session_gen_chlo,
.esf_handle_chlo_reply = lsquic_enc_session_handle_chlo_reply,
.esf_mem_used = lsquic_enc_session_mem_used,
.esf_verify_reset_token = lsquic_enc_session_verify_reset_token,
};
const char *const lsquic_enclev2str[] =
{
[ENC_LEV_UNSET] = "unset",
[ENC_LEV_CLEAR] = "clear",
[ENC_LEV_INIT] = "initial",
[ENC_LEV_FORW] = "forw-secure",
};

View File

@ -13,6 +13,7 @@ typedef struct lsquic_enc_session lsquic_enc_session_t;
#define DNONC_LENGTH 32
#define aes128_key_len 16
#define aes128_iv_len 4
#define SRST_LENGTH 16
enum handshake_error /* TODO: rename this enum */
{
@ -33,6 +34,8 @@ enum enc_level
ENC_LEV_FORW,
};
extern const char *const lsquic_enclev2str[];
/* client side need to store 0rtt info per STK */
typedef struct lsquic_session_cache_info_st
{
@ -86,8 +89,8 @@ struct enc_session_funcs
int (*esf_is_hsk_done)(lsquic_enc_session_t *enc_session);
/* Encrypt buffer */
int (*esf_encrypt)(lsquic_enc_session_t *enc_session, enum lsquic_version,
uint8_t path_id, uint64_t pack_num,
enum enc_level (*esf_encrypt)(lsquic_enc_session_t *enc_session,
enum lsquic_version, uint8_t path_id, uint64_t pack_num,
const unsigned char *header, size_t header_len,
const unsigned char *data, size_t data_len,
unsigned char *buf_out, size_t max_out_len, size_t *out_len,
@ -132,6 +135,10 @@ struct enc_session_funcs
size_t
(*esf_mem_used)(lsquic_enc_session_t *);
int
(*esf_verify_reset_token) (lsquic_enc_session_t *, const unsigned char *,
size_t);
};
extern

View File

@ -88,3 +88,14 @@ restore_packno (lsquic_packno_t cur_packno,
return candidates[min];
}
const char *const lsquic_hety2str[] =
{
[HETY_NOT_SET] = "Short",
[HETY_VERNEG] = "Version Negotiation",
[HETY_INITIAL] = "Initial",
[HETY_RETRY] = "Retry",
[HETY_HANDSHAKE] = "Handshake",
[HETY_0RTT] = "0-RTT",
};

View File

@ -116,10 +116,25 @@ lsquic_frame_types_to_str (char *buf, size_t bufsz, enum quic_ft_bit);
#define QFRAME_RETRANSMITTABLE(frame_type) \
((1 << (frame_type)) & QFRAME_RETRANSMITTABLE_MASK)
#define QUIC_MAX_PUBHDR_SZ (1 /* Type */ + 8 /* CID */ + 4 /* Version */ \
#define GQUIC_MAX_PUBHDR_SZ (1 /* Type */ + 8 /* CID */ + 4 /* Version */ \
+ 32 /* Nonce */ + 6 /* Packet Number */ )
#define QUIC_MIN_PUBHDR_SZ (1 /* Type */ + 1 /* Packet number */)
#define GQUIC_MIN_PUBHDR_SZ (1 /* Type */ + 1 /* Packet number */)
#define GQUIC_IETF_LONG_HEADER_SIZE (1 /* Type */ + 4 /* Version */ \
+ 1 /* DCIL/SCIL */ + 8 /* CID */ + 4 /* Packet number */)
/* XXX Nonce? */
#define IQUIC_MAX_PUBHDR_SZ GQUIC_IETF_LONG_HEADER_SIZE
#define IQUIC_MIN_PUBHDR_SZ (1 /* Type */ + 8 /* CID */ \
+ 1 /* Packet number */)
#define QUIC_MAX_PUBHDR_SZ (GQUIC_MAX_PUBHDR_SZ > IQUIC_MAX_PUBHDR_SZ \
? GQUIC_MAX_PUBHDR_SZ : IQUIC_MAX_PUBHDR_SZ)
#define QUIC_MIN_PUBHDR_SZ (GQUIC_MIN_PUBHDR_SZ < IQUIC_MIN_PUBHDR_SZ \
? GQUIC_MIN_PUBHDR_SZ : IQUIC_MIN_PUBHDR_SZ)
/* 12 bytes of FNV hash or encryption IV */
#define QUIC_PACKET_HASH_SZ 12
@ -151,6 +166,19 @@ enum lsquic_packno_bits
PACKNO_LEN_6 = 3,
};
enum header_type
{
HETY_NOT_SET, /* This value must be zero */
HETY_VERNEG,
HETY_INITIAL,
HETY_RETRY,
HETY_HANDSHAKE,
HETY_0RTT,
};
extern const char *const lsquic_hety2str[];
enum lsquic_packno_bits
calc_packno_bits (lsquic_packno_t packno, lsquic_packno_t least_unacked,
uint64_t n_in_flight);

View File

@ -60,7 +60,9 @@ typedef struct lsquic_packet_in
#define PIBIT_ENC_LEV_SHIFT 5
PI_ENC_LEV_BIT_0= (1 << 5), /* Encodes encryption level */
PI_ENC_LEV_BIT_1= (1 << 6), /* (see enum enc_level). */
PI_GQUIC = (1 << 7),
} pi_flags:8;
enum header_type pi_header_type:8;
/* If PI_OWN_DATA flag is not set, `pi_data' points to user-supplied
* packet data, which is NOT TO BE MODIFIED.
*/
@ -69,11 +71,19 @@ typedef struct lsquic_packet_in
#define lsquic_packet_in_public_flags(p) ((p)->pi_data[0])
#define lsquic_packet_in_is_prst(p) \
(lsquic_packet_in_public_flags(p) & PACKET_PUBLIC_FLAGS_RST)
#define lsquic_packet_in_is_gquic_prst(p) \
(((p)->pi_flags & PI_GQUIC) \
&& (lsquic_packet_in_public_flags(p) & PACKET_PUBLIC_FLAGS_RST))
#define lsquic_packet_in_is_verneg(p) \
(((p)->pi_flags & PI_GQUIC) ? \
lsquic_packet_in_public_flags(p) & PACKET_PUBLIC_FLAGS_VERSION : \
(p)->pi_header_type == HETY_VERNEG)
#define lsquic_packet_in_packno_bits(p) \
((lsquic_packet_in_public_flags(p) >> 4) & 3)
(((p)->pi_flags & PI_GQUIC) ? \
((lsquic_packet_in_public_flags(p) >> 4) & 3) : \
((p)->pi_data[0] & 3))
#define lsquic_packet_in_upref(p) (++(p)->pi_refcnt)

View File

@ -22,6 +22,7 @@
#include "lsquic_stream.h"
#include "lsquic_logger.h"
#include "lsquic_ev_log.h"
#include "lsquic_conn.h"
typedef char _stream_rec_arr_is_at_most_64bytes[
(sizeof(struct stream_rec_arr) <= 64)? 1: - 1];
@ -212,12 +213,12 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
lsquic_packet_out_t *
lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
unsigned short max_size, enum lsquic_packno_bits bits,
const struct lsquic_conn *lconn, enum lsquic_packno_bits bits,
const lsquic_ver_tag_t *ver_tag, const unsigned char *nonce)
{
lsquic_packet_out_t *packet_out;
enum packet_out_flags flags;
unsigned short header_size;
unsigned short header_size, max_size;
flags = bits << POBIT_SHIFT;
if (ver_tag)
@ -226,8 +227,22 @@ lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
flags |= PO_NONCE;
if (use_cid)
flags |= PO_CONN_ID;
if ((1 << lconn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS)
flags |= PO_GQUIC;
if (
0 == (lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
)
{
flags |= PO_LONGHEAD;
if (!((1 << lconn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS))
{
flags &= ~(3 << POBIT_SHIFT);
flags |= PACKNO_LEN_4 << POBIT_SHIFT;
}
}
header_size = lsquic_po_header_length(flags);
header_size = lsquic_po_header_length(lconn, flags);
max_size = lconn->cn_pack_size;
if (header_size + QUIC_PACKET_HASH_SZ >= max_size)
{
errno = EINVAL;
@ -255,6 +270,8 @@ lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
}
memcpy(packet_out->po_nonce, nonce, 32);
}
if (flags & PO_LONGHEAD)
packet_out->po_header_type = HETY_HANDSHAKE;
return packet_out;
}
@ -602,6 +619,8 @@ verify_srecs (lsquic_packet_out_t *packet_out)
assert(packet_out->po_data_sz == off);
}
#endif

View File

@ -9,6 +9,7 @@
#include <sys/queue.h>
struct malo;
struct lsquic_conn;
struct lsquic_engine_public;
struct lsquic_mm;
struct lsquic_stream;
@ -84,7 +85,12 @@ typedef struct lsquic_packet_out
*/
PO_SCHED = (1 <<14), /* On scheduled queue */
PO_SENT_SZ = (1 <<15),
} po_flags:16;
PO_LONGHEAD = (1 <<16),
PO_GQUIC = (1 <<17), /* Used for logging */
#define POLEV_SHIFT 18
PO_BITS_2 = (1 <<18), /* PO_BITS_2 and PO_BITS_3 encode the */
PO_BITS_3 = (1 <<19), /* crypto level. Used for logging. */
} po_flags;
enum quic_ft_bit po_frame_types:16; /* Bitmask of QUIC_FRAME_* */
unsigned short po_data_sz; /* Number of usable bytes in data */
unsigned short po_enc_data_sz; /* Number of usable bytes in data */
@ -95,6 +101,7 @@ typedef struct lsquic_packet_out
* frames.
*/
unsigned short po_n_alloc; /* Total number of bytes allocated in po_data */
enum header_type po_header_type:8;
unsigned char *po_data;
lsquic_packno_t po_ack2ed; /* If packet has ACK frame, value of
* largest acked in it.
@ -135,33 +142,27 @@ typedef struct lsquic_packet_out
(p)->po_flags |= ((b) & 0x3) << POBIT_SHIFT; \
} while (0)
#define lsquic_po_header_length(po_flags) ( \
1 /* Type */ \
+ (!!((po_flags) & PO_CONN_ID) << 3) /* Connection ID */ \
+ (!!((po_flags) & PO_VERSION) << 2) /* Version */ \
+ (!!((po_flags) & PO_NONCE) << 5) /* Nonce */ \
+ packno_bits2len(((po_flags) >> POBIT_SHIFT) & 0x3) /* Packet number */ \
)
#define lsquic_po_header_length(lconn, po_flags) ( \
lconn->cn_pf->pf_packout_header_size(lconn, po_flags))
#define lsquic_packet_out_total_sz(p) \
((p)->po_data_sz + lsquic_po_header_length((p)->po_flags) \
+ QUIC_PACKET_HASH_SZ)
#define lsquic_packet_out_total_sz(lconn, p) (\
lconn->cn_pf->pf_packout_size(lconn, p))
#if __GNUC__
#if LSQUIC_EXTRA_CHECKS
#define lsquic_packet_out_sent_sz(p) ( \
#define lsquic_packet_out_sent_sz(lconn, p) ( \
__builtin_expect(((p)->po_flags & PO_SENT_SZ), 1) ? \
(assert((p)->po_sent_sz == lsquic_packet_out_total_sz(p)), \
(p)->po_sent_sz) : lsquic_packet_out_total_sz(p))
(assert((p)->po_sent_sz == lsquic_packet_out_total_sz(lconn, p)), \
(p)->po_sent_sz) : lsquic_packet_out_total_sz(lconn, p))
# else
#define lsquic_packet_out_sent_sz(p) ( \
#define lsquic_packet_out_sent_sz(lconn, p) ( \
__builtin_expect(((p)->po_flags & PO_SENT_SZ), 1) ? \
(p)->po_sent_sz : lsquic_packet_out_total_sz(p))
(p)->po_sent_sz : lsquic_packet_out_total_sz(lconn, p))
#endif
#else
# define lsquic_packet_out_sent_sz(p) ( \
# define lsquic_packet_out_sent_sz(lconn, p) ( \
(p)->po_flags & PO_SENT_SZ ? \
(p)->po_sent_sz : lsquic_packet_out_total_sz(p))
(p)->po_sent_sz : lsquic_packet_out_total_sz(lconn, p))
#endif
#define lsquic_packet_out_verneg(p) \
@ -170,6 +171,13 @@ typedef struct lsquic_packet_out
#define lsquic_packet_out_pubres(p) \
(((p)->po_flags & (PO_NOENCRYPT|PO_VERNEG)) == PO_NOENCRYPT )
#define lsquic_packet_out_set_enc_level(p, level) do { \
(p)->po_flags &= ~(3 << POLEV_SHIFT); \
(p)->po_flags |= level << POLEV_SHIFT; \
} while (0)
#define lsquic_packet_out_enc_level(p) (((p)->po_flags >> POLEV_SHIFT) & 3)
struct packet_out_srec_iter {
lsquic_packet_out_t *packet_out;
struct stream_rec_arr *cur_srec_arr;
@ -185,7 +193,7 @@ posi_next (struct packet_out_srec_iter *posi);
lsquic_packet_out_t *
lsquic_packet_out_new (struct lsquic_mm *, struct malo *, int use_cid,
unsigned short size, enum lsquic_packno_bits,
const struct lsquic_conn *, enum lsquic_packno_bits,
const lsquic_ver_tag_t *, const unsigned char *nonce);
void

View File

@ -7,7 +7,10 @@
#include "lsquic_packet_common.h"
struct lsquic_packet_in;
struct lsquic_packet_out;
struct packin_parse_state;
struct stream_frame;
enum packet_out_flags;
#define LSQUIC_PARSE_ACK_TIMESTAMPS 0
@ -54,27 +57,17 @@ typedef lsquic_time_t
/* gsf_: generate stream frame */
typedef size_t (*gsf_read_f) (void *stream, void *buf, size_t len, int *fin);
struct packin_parse_state {
const unsigned char *pps_p; /* Pointer to packet number */
unsigned pps_nbytes; /* Number of bytes in packet number */
};
/* This structure contains functions that parse and generate packets and
* frames in version-specific manner. To begin with, there is difference
* between GQUIC's little-endian (Q038 and lower) and big-endian formats
* (Q039 and higher).
* (Q039 and higher). Q044 uses different format for packet headers.
*/
struct parse_funcs
{
int
(*pf_gen_ver_nego_pkt) (unsigned char *buf, size_t bufsz, uint64_t conn_id,
unsigned version_bitmask);
/* Return buf length */
int
(*pf_gen_reg_pkt_header) (unsigned char *buf, size_t bufsz,
const lsquic_cid_t *, const lsquic_ver_tag_t *,
const unsigned char *nonce, lsquic_packno_t,
enum lsquic_packno_bits);
(*pf_gen_reg_pkt_header) (const struct lsquic_conn *,
const struct lsquic_packet_out *, unsigned char *, size_t);
void
(*pf_parse_packet_in_finish) (struct lsquic_packet_in *packet_in,
struct packin_parse_state *);
@ -154,28 +147,57 @@ struct parse_funcs
(*pf_calc_stream_frame_header_sz) (uint32_t stream_id, uint64_t offset);
void
(*pf_turn_on_fin) (unsigned char *);
size_t
(*pf_packout_size) (const struct lsquic_conn *,
const struct lsquic_packet_out *);
size_t
(*pf_packout_header_size) (const struct lsquic_conn *,
enum packet_out_flags);
};
extern const struct parse_funcs lsquic_parse_funcs_gquic_le;
/* Q039 and later are big-endian: */
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q039;
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q044;
#define select_pf_by_ver(ver) ( \
((1 << (ver)) & (1 << LSQVER_035)) \
? &lsquic_parse_funcs_gquic_le \
: &lsquic_parse_funcs_gquic_Q039)
: (ver) < LSQVER_044 \
? &lsquic_parse_funcs_gquic_Q039 \
: &lsquic_parse_funcs_gquic_Q044)
/* This function is QUIC-version independent */
int
parse_packet_in_begin (struct lsquic_packet_in *, size_t length,
lsquic_gquic_parse_packet_in_begin (struct lsquic_packet_in *, size_t length,
int is_server, struct packin_parse_state *);
int
lsquic_iquic_parse_packet_in_long_begin (struct lsquic_packet_in *,
size_t length, int is_server, struct packin_parse_state *state);
int
lsquic_iquic_parse_packet_in_short_begin (struct lsquic_packet_in *,
size_t length, int is_server, struct packin_parse_state *state);
enum QUIC_FRAME_TYPE
parse_frame_type_gquic_Q035_thru_Q039 (unsigned char first_byte);
size_t
calc_stream_frame_header_sz_gquic (uint32_t stream_id, uint64_t offset);
size_t
lsquic_gquic_packout_size (const struct lsquic_conn *,
const struct lsquic_packet_out *);
size_t
lsquic_gquic_packout_header_size (const struct lsquic_conn *conn,
enum packet_out_flags flags);
size_t
lsquic_gquic_po_header_sz (enum packet_out_flags flags);
/* This maps two bits as follows:
* 00 -> 1
* 01 -> 2

View File

@ -0,0 +1,213 @@
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_parse_Q044.c -- Parsing functions specific to GQUIC Q044
*/
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <string.h>
#include <sys/queue.h>
#ifndef WIN32
#include <sys/types.h>
#else
#include <vc_compat.h>
#endif
#include "lsquic_types.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_in.h"
#include "lsquic_packet_out.h"
#include "lsquic_parse.h"
#include "lsquic_parse_common.h"
#include "lsquic_version.h"
#include "lsquic.h"
#include "lsquic_parse_gquic_be.h"
#include "lsquic_byteswap.h"
#include "lsquic_conn.h"
#define LSQUIC_LOGGER_MODULE LSQLM_PARSE
#include "lsquic_logger.h"
static int
gen_short_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
unsigned packno_len, need;
enum lsquic_packno_bits bits;
uint32_t packno;
bits = (packet_out->po_flags >> POBIT_SHIFT) & 0x3;
packno_len = packno_bits2len(bits);
need = 1 + 8 /* CID */ + packno_len;
if (need > bufsz)
return -1;
*buf++ = 0x30 | bits;
memcpy(buf, &lconn->cn_cid, 8);
buf += 8;
packno = packet_out->po_packno;
#if __BYTE_ORDER == __LITTLE_ENDIAN
packno = bswap_32(packno);
#endif
memcpy(buf, (unsigned char *) &packno + 4 - packno_len, packno_len);
return need;
}
static size_t
gquic_Q044_packout_header_size_long (const struct lsquic_conn *lconn,
enum packet_out_flags flags)
{
return GQUIC_IETF_LONG_HEADER_SIZE;
}
static const unsigned char header_type_to_bin[] = {
[HETY_NOT_SET] = 0x00,
[HETY_INITIAL] = 0x7F,
[HETY_RETRY] = 0x7E,
[HETY_HANDSHAKE] = 0x7D,
[HETY_0RTT] = 0x7C,
};
static int
gen_long_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
lsquic_ver_tag_t ver_tag;
unsigned char *p;
uint32_t packno;
size_t need;
need = gquic_Q044_packout_header_size_long(lconn, packet_out->po_flags);
if (need > bufsz)
{
errno = EINVAL;
return -1;
}
p = buf;
*p++ = 0x80 | header_type_to_bin[ packet_out->po_header_type ];
ver_tag = lsquic_ver2tag(lconn->cn_version);
memcpy(p, &ver_tag, sizeof(ver_tag));
p += sizeof(ver_tag);
*p++ = 0x50;
memcpy(p, &lconn->cn_cid, 8);
p += 8;
packno = packet_out->po_packno;
#if __BYTE_ORDER == __LITTLE_ENDIAN
packno = bswap_32(packno);
#endif
memcpy(p, &packno, 4);
p += 4;
assert(need = p - buf);
return p - buf;
}
static int
gquic_Q044_gen_reg_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
if (0 == (packet_out->po_flags & PO_LONGHEAD))
return gen_short_pkt_header(lconn, packet_out, buf, bufsz);
else
return gen_long_pkt_header(lconn, packet_out, buf, bufsz);
}
static size_t
gquic_Q044_packout_header_size_short (const struct lsquic_conn *lconn,
enum packet_out_flags flags)
{
enum lsquic_packno_bits bits;
size_t sz;
bits = (flags >> POBIT_SHIFT) & 0x3;
sz = 1; /* Type */
sz += 8; /* CID */
sz += packno_bits2len(bits);
return sz;
}
static size_t
gquic_Q044_packout_header_size (const struct lsquic_conn *lconn,
enum packet_out_flags flags)
{
if (0 == (flags & PO_LONGHEAD))
return gquic_Q044_packout_header_size_short(lconn, flags);
else
return gquic_Q044_packout_header_size_long(lconn, flags);
}
static size_t
gquic_Q044_packout_size (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out)
{
size_t sz;
if (0 == (packet_out->po_flags & PO_LONGHEAD))
sz = gquic_Q044_packout_header_size_short(lconn, packet_out->po_flags);
else
sz = gquic_Q044_packout_header_size_long(lconn, packet_out->po_flags);
sz += packet_out->po_data_sz;
sz += QUIC_PACKET_HASH_SZ;
return sz;
}
const struct parse_funcs lsquic_parse_funcs_gquic_Q044 =
{
.pf_gen_reg_pkt_header = gquic_Q044_gen_reg_pkt_header,
.pf_parse_packet_in_finish = gquic_be_parse_packet_in_finish,
.pf_gen_stream_frame = gquic_be_gen_stream_frame,
.pf_calc_stream_frame_header_sz = calc_stream_frame_header_sz_gquic,
.pf_parse_stream_frame = gquic_be_parse_stream_frame,
.pf_parse_ack_frame = gquic_be_parse_ack_frame,
.pf_gen_ack_frame = gquic_be_gen_ack_frame,
.pf_gen_stop_waiting_frame = gquic_be_gen_stop_waiting_frame,
.pf_parse_stop_waiting_frame = gquic_be_parse_stop_waiting_frame,
.pf_skip_stop_waiting_frame = gquic_be_skip_stop_waiting_frame,
.pf_gen_window_update_frame = gquic_be_gen_window_update_frame,
.pf_parse_window_update_frame = gquic_be_parse_window_update_frame,
.pf_gen_blocked_frame = gquic_be_gen_blocked_frame,
.pf_parse_blocked_frame = gquic_be_parse_blocked_frame,
.pf_gen_rst_frame = gquic_be_gen_rst_frame,
.pf_parse_rst_frame = gquic_be_parse_rst_frame,
.pf_gen_connect_close_frame = gquic_be_gen_connect_close_frame,
.pf_parse_connect_close_frame = gquic_be_parse_connect_close_frame,
.pf_gen_goaway_frame = gquic_be_gen_goaway_frame,
.pf_parse_goaway_frame = gquic_be_parse_goaway_frame,
.pf_gen_ping_frame = gquic_be_gen_ping_frame,
#ifndef NDEBUG
.pf_write_float_time16 = gquic_be_write_float_time16,
.pf_read_float_time16 = gquic_be_read_float_time16,
#endif
.pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039,
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
.pf_packout_size = gquic_Q044_packout_size,
.pf_packout_header_size = gquic_Q044_packout_header_size,
};

View File

@ -0,0 +1,56 @@
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
#include <string.h>
#include <sys/queue.h>
#include <sys/types.h>
#include "lsquic_types.h"
#include "lsquic_int_types.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_in.h"
#include "lsquic_parse_common.h"
#include "lsquic_parse.h"
int
lsquic_parse_packet_in_begin (lsquic_packet_in_t *packet_in, size_t length,
int is_server, struct packin_parse_state *state)
{
if (length > 0)
{
switch (packet_in->pi_data[0] & 0x88)
{
case 0x88:
case 0x80:
return lsquic_iquic_parse_packet_in_long_begin(packet_in, length,
is_server, state);
case 0x08:
return lsquic_gquic_parse_packet_in_begin(packet_in, length,
is_server, state);
default:
return lsquic_iquic_parse_packet_in_short_begin(packet_in, length,
is_server, state);
}
}
else
return -1;
}
int
lsquic_iquic_parse_packet_in_begin (struct lsquic_packet_in *packet_in,
size_t length, int is_server, struct packin_parse_state *state)
{
if (length > 0)
{
if (0 == (packet_in->pi_data[0] & 0x80))
return lsquic_iquic_parse_packet_in_short_begin(packet_in, length,
is_server, state);
else
return lsquic_iquic_parse_packet_in_long_begin(packet_in, length,
is_server, state);
}
else
return -1;
}

View File

@ -0,0 +1,24 @@
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_parse_common.h
*/
#ifndef LSQUIC_PARSE_COMMON_H
#define LSQUIC_PARSE_COMMON_H 1
struct lsquic_packet_in;
struct packin_parse_state {
const unsigned char *pps_p; /* Pointer to packet number */
unsigned pps_nbytes; /* Number of bytes in packet number */
};
int
lsquic_parse_packet_in_begin (struct lsquic_packet_in *,
size_t length, int is_server, struct packin_parse_state *);
int
lsquic_iquic_parse_packet_in_begin (struct lsquic_packet_in *,
size_t length, int is_server, struct packin_parse_state *);
#endif

View File

@ -20,7 +20,9 @@
#include "lsquic_alarmset.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_in.h"
#include "lsquic_packet_out.h"
#include "lsquic_parse.h"
#include "lsquic_parse_common.h"
#include "lsquic_rechist.h"
#include "lsquic_sfcw.h"
#include "lsquic_stream.h"
@ -28,7 +30,9 @@
#include "lsquic_malo.h"
#include "lsquic_version.h"
#include "lsquic.h"
#include "lsquic_conn.h"
#include "lsquic_parse_gquic_be.h" /* Include to catch mismatches */
#include "lsquic_byteswap.h"
#define LSQUIC_LOGGER_MODULE LSQLM_PARSE
#include "lsquic_logger.h"
@ -98,41 +102,20 @@ gquic_be_parse_packet_in_finish (lsquic_packet_in_t *packet_in,
}
int
gquic_be_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz, uint64_t conn_id,
unsigned version_bitmask)
{
int sz;
unsigned char *p = buf;
unsigned char *const pend = p + bufsz;
CHECK_SPACE(1, p, pend);
*p = PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID;
++p;
CHECK_SPACE(8, p, pend);
memcpy(p, &conn_id, 8);
p += 8;
sz = gen_ver_tags(p, pend - p, version_bitmask);
if (sz < 0)
return -1;
return p + sz - buf;
}
int
gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_t *conn_id,
const lsquic_ver_tag_t *ver, const unsigned char *nonce,
lsquic_packno_t packno, enum lsquic_packno_bits bits)
static int
gquic_be_gen_reg_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
unsigned packnum_len, header_len;
enum lsquic_packno_bits bits;
lsquic_packno_t packno;
unsigned char *p;
bits = lsquic_packet_out_packno_bits(packet_out);
packnum_len = packno_bits2len(bits);
if (!(conn_id || ver || nonce))
if (0 == (packet_out->po_flags & (PO_CONN_ID|PO_VERSION|PO_NONCE)))
{
header_len = 1 + packnum_len;
if (header_len > bufsz)
@ -146,8 +129,16 @@ gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_
}
else
{
header_len = 1 + (!!conn_id << 3) + (!!ver << 2) + ((!!nonce) << 5)
+ packnum_len;
const int
have_cid = packet_out->po_flags & PO_CONN_ID,
have_ver = packet_out->po_flags & PO_VERSION,
have_nonce = packet_out->po_flags & PO_NONCE;
header_len = 1
+ (!!have_cid << 3)
+ (!!have_ver << 2)
+ (!!have_nonce << 5)
+ packnum_len
;
if (header_len > bufsz)
{
errno = ENOBUFS;
@ -156,31 +147,32 @@ gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_
p = buf;
*p = (!!conn_id << 3)
*p = (!!have_cid << 3)
| (bits << 4)
| ((!!nonce) << 2)
| !!ver;
| ((!!have_nonce) << 2)
| !!have_ver;
++p;
if (conn_id)
if (have_cid)
{
memcpy(p, conn_id , sizeof(*conn_id));
p += sizeof(*conn_id);
memcpy(p, &lconn->cn_cid, sizeof(lconn->cn_cid));
p += sizeof(lconn->cn_cid);
}
if (ver)
if (have_ver)
{
memcpy(p, ver, 4);
memcpy(p, &packet_out->po_ver_tag, 4);
p += 4;
}
if (nonce)
if (have_nonce)
{
memcpy(p, nonce , 32);
memcpy(p, packet_out->po_nonce , 32);
p += 32;
}
}
packno = packet_out->po_packno;
#if __BYTE_ORDER == __LITTLE_ENDIAN
packno = bswap_64(packno);
#endif
@ -955,7 +947,6 @@ gquic_be_gen_ack_frame (unsigned char *outbuf, size_t outbuf_sz,
const struct parse_funcs lsquic_parse_funcs_gquic_Q039 =
{
.pf_gen_ver_nego_pkt = gquic_be_gen_ver_nego_pkt,
.pf_gen_reg_pkt_header = gquic_be_gen_reg_pkt_header,
.pf_parse_packet_in_finish = gquic_be_parse_packet_in_finish,
.pf_gen_stream_frame = gquic_be_gen_stream_frame,
@ -983,4 +974,6 @@ const struct parse_funcs lsquic_parse_funcs_gquic_Q039 =
#endif
.pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039,
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
.pf_packout_size = lsquic_gquic_packout_size,
.pf_packout_header_size = lsquic_gquic_packout_header_size,
};

View File

@ -8,24 +8,6 @@
* and that would be a mess.
*/
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
#include <sys/endian.h>
#define bswap_16 bswap16
#define bswap_32 bswap32
#define bswap_64 bswap64
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define bswap_16 OSSwapInt16
#define bswap_32 OSSwapInt32
#define bswap_64 OSSwapInt64
#elif defined(WIN32)
#define bswap_16 _byteswap_ushort
#define bswap_32 _byteswap_ulong
#define bswap_64 _byteswap_uint64
#else
#include <byteswap.h>
#endif
#define CHECK_SPACE(need, pstart, pend) \
do { if ((intptr_t) (need) > ((pend) - (pstart))) { return -1; } } while (0)
@ -58,11 +40,6 @@ int
gquic_be_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz, uint64_t conn_id,
unsigned version_bitmask);
int
gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_t *conn_id,
const lsquic_ver_tag_t *ver, const unsigned char *nonce,
lsquic_packno_t packno, enum lsquic_packno_bits bits);
int
gquic_be_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_id,
uint64_t offset, int fin, size_t size,

View File

@ -17,8 +17,11 @@
#include "lsquic_types.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_out.h"
#include "lsquic_packet_in.h"
#include "lsquic_parse.h"
#include "lsquic_parse_common.h"
#include "lsquic_version.h"
#include "lsquic.h"
#define LSQUIC_LOGGER_MODULE LSQLM_PARSE
@ -35,8 +38,8 @@
* pf_parse_packet_in_finish() routine.
*/
int
parse_packet_in_begin (lsquic_packet_in_t *packet_in, size_t length,
int is_server, struct packin_parse_state *state)
lsquic_gquic_parse_packet_in_begin (struct lsquic_packet_in *packet_in,
size_t length, int is_server, struct packin_parse_state *state)
{
int nbytes;
enum PACKET_PUBLIC_FLAGS public_flags;
@ -128,6 +131,7 @@ parse_packet_in_begin (lsquic_packet_in_t *packet_in, size_t length,
packet_in->pi_data_sz = length;
packet_in->pi_refcnt = 0;
packet_in->pi_received = 0;
packet_in->pi_flags |= PI_GQUIC;
return 0;
}
@ -462,3 +466,36 @@ acki2str (const struct ack_info *acki, size_t *sz)
*sz = off;
return buf;
}
size_t
lsquic_gquic_po_header_sz (enum packet_out_flags flags)
{
return 1 /* Type */
+ (!!(flags & PO_CONN_ID) << 3) /* Connection ID */
+ (!!(flags & PO_VERSION) << 2) /* Version */
+ (!!(flags & PO_NONCE) << 5) /* Nonce */
+ packno_bits2len((flags >> POBIT_SHIFT) & 0x3) /* Packet number */
;
}
size_t
lsquic_gquic_packout_size (const struct lsquic_conn *conn,
const struct lsquic_packet_out *packet_out)
{
return lsquic_gquic_po_header_sz(packet_out->po_flags)
+ packet_out->po_data_sz
+ QUIC_PACKET_HASH_SZ
;
}
size_t
lsquic_gquic_packout_header_size (const struct lsquic_conn *conn,
enum packet_out_flags flags)
{
return lsquic_gquic_po_header_sz(flags);
}

View File

@ -20,7 +20,9 @@
#include "lsquic_alarmset.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_in.h"
#include "lsquic_packet_out.h"
#include "lsquic_parse.h"
#include "lsquic_parse_common.h"
#include "lsquic_rechist.h"
#include "lsquic_sfcw.h"
#include "lsquic_stream.h"
@ -28,6 +30,7 @@
#include "lsquic_malo.h"
#include "lsquic_version.h"
#include "lsquic.h"
#include "lsquic_conn.h"
#define LSQUIC_LOGGER_MODULE LSQLM_PARSE
#include "lsquic_logger.h"
@ -118,41 +121,23 @@ gquic_le_parse_packet_in_finish (lsquic_packet_in_t *packet_in,
static int
gquic_le_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz, uint64_t conn_id,
unsigned version_bitmask)
{
int sz;
unsigned char *p = buf;
unsigned char *const pend = p + bufsz;
CHECK_SPACE(1, p, pend);
*p = PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID;
++p;
CHECK_SPACE(8, p, pend);
memcpy(p, &conn_id, 8);
p += 8;
sz = gen_ver_tags(p, pend - p, version_bitmask);
if (sz < 0)
return -1;
return p + sz - buf;
}
static int
gquic_le_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_t *conn_id,
const lsquic_ver_tag_t *ver, const unsigned char *nonce,
lsquic_packno_t packno, enum lsquic_packno_bits bits)
gquic_le_gen_reg_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
unsigned packnum_len, header_len;
unsigned char *p;
enum lsquic_packno_bits bits;
bits = lsquic_packet_out_packno_bits(packet_out);
packnum_len = packno_bits2len(bits);
header_len = 1 + (!!conn_id << 3) + (!!ver << 2) + ((!!nonce) << 5)
+ packnum_len;
header_len = 1
+ (!!(packet_out->po_flags & PO_CONN_ID) << 3)
+ (!!(packet_out->po_flags & PO_VERSION) << 2)
+ (!!(packet_out->po_flags & PO_NONCE) << 5)
+ packnum_len
;
if (header_len > bufsz)
{
errno = ENOBUFS;
@ -161,32 +146,32 @@ gquic_le_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_
p = buf;
*p = (!!conn_id << 3)
*p = (!!(packet_out->po_flags & PO_CONN_ID) << 3)
| (bits << 4)
| ((!!nonce) << 2)
| !!ver;
| ((!!(packet_out->po_flags & PO_NONCE)) << 2)
| !!(packet_out->po_flags & PO_VERSION);
++p;
if (conn_id)
if (packet_out->po_flags & PO_CONN_ID)
{
memcpy(p, conn_id , sizeof(*conn_id));
p += sizeof(*conn_id);
memcpy(p, &lconn->cn_cid, sizeof(lconn->cn_cid));
p += sizeof(lconn->cn_cid);
}
if (ver)
if (packet_out->po_flags & PO_VERSION)
{
memcpy(p, ver, 4);
memcpy(p, &packet_out->po_ver_tag, 4);
p += 4;
}
if (nonce)
if (packet_out->po_flags & PO_NONCE)
{
memcpy(p, nonce , 32);
memcpy(p, packet_out->po_nonce, 32);
p += 32;
}
/* ENDIAN */
memcpy(p, &packno, packnum_len);
memcpy(p, &packet_out->po_packno, packnum_len);
p += packnum_len;
assert(p - buf == (intptr_t) header_len);
@ -832,7 +817,6 @@ gquic_le_gen_ack_frame (unsigned char *outbuf, size_t outbuf_sz,
const struct parse_funcs lsquic_parse_funcs_gquic_le =
{
.pf_gen_ver_nego_pkt = gquic_le_gen_ver_nego_pkt,
.pf_gen_reg_pkt_header = gquic_le_gen_reg_pkt_header,
.pf_parse_packet_in_finish = gquic_le_parse_packet_in_finish,
.pf_gen_stream_frame = gquic_le_gen_stream_frame,
@ -860,4 +844,6 @@ const struct parse_funcs lsquic_parse_funcs_gquic_le =
#endif
.pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039,
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
.pf_packout_size = lsquic_gquic_packout_size,
.pf_packout_header_size = lsquic_gquic_packout_header_size,
};

View File

@ -0,0 +1,185 @@
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <openssl/rand.h>
#include "lsquic_types.h"
#include "lsquic_int_types.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_in.h"
#include "lsquic_parse_common.h"
#include "lsquic_parse.h"
#include "lsquic_version.h"
#include "lsquic.h"
#include "lsquic_logger.h"
#include "lsquic_byteswap.h"
#include "lsquic_str.h"
#include "lsquic_handshake.h"
static const enum header_type bin_2_header_type[0x100] =
{
[0x80 | 0x7F] = HETY_INITIAL,
[0x80 | 0x7E] = HETY_RETRY,
[0x80 | 0x7D] = HETY_HANDSHAKE,
[0x80 | 0x7C] = HETY_0RTT,
};
int
lsquic_iquic_parse_packet_in_long_begin (lsquic_packet_in_t *packet_in,
size_t length, int is_server, struct packin_parse_state *state)
{
const unsigned char *p = packet_in->pi_data;
const unsigned char *const end = p + length;
lsquic_ver_tag_t tag;
enum header_type header_type;
unsigned dcil, scil;
int verneg;
unsigned char first_byte;
const unsigned cid_len = 8;
if (length < 6)
return -1;
first_byte = *p++;
memcpy(&tag, p, 4);
p += 4;
verneg = 0 == tag;
if (!verneg)
{
header_type = bin_2_header_type[ first_byte ];
if (!header_type)
return -1;
}
else
header_type = HETY_VERNEG;
packet_in->pi_header_type = header_type;
dcil = p[0] >> 4;
if (dcil)
dcil += 3;
scil = p[0] & 0xF;
if (scil)
scil += 3;
++p;
/* Chromium comments state that the client sends packets with destination
* CID of 8 bytes and source CID of 0 bytes and the server does it the
* other way around.
*
* XXX When IETF branch is merged, this check for Q044 will have to be
* moved to the pf_parse_packet_in_finish().
*/
if (is_server)
{
if (!(dcil == cid_len && scil == 0))
return -1;
}
else
{
if (!(dcil == 0 && scil == cid_len))
return -1;
}
const unsigned packet_len = 4;
/* XXX This checks both packet length or the first version of the version
* array in a version negotiation packet. This is because the sizes of
* the packet number field and the version tag are the same. The check
* will probably have to be split in the future.
*/
if (end - p < dcil + scil + packet_len)
return -1;
memcpy(&packet_in->pi_conn_id, p, cid_len);
p += cid_len;
packet_in->pi_flags |= PI_CONN_ID;
packet_in->pi_packno = 0;
if (!verneg)
{
state->pps_p = p;
state->pps_nbytes = packet_len;
p += packet_len;
packet_in->pi_quic_ver = 1;
if (is_server || HETY_0RTT != header_type)
packet_in->pi_nonce = 0;
else
{
packet_in->pi_nonce = p - packet_in->pi_data;
p += 32;
}
}
else
{
if ((end - p) & 3)
return -1;
state->pps_p = NULL;
state->pps_nbytes = 0;
packet_in->pi_quic_ver = p - packet_in->pi_data;
p = packet_in->pi_data + length;
packet_in->pi_nonce = 0;
}
packet_in->pi_header_sz = p - packet_in->pi_data;
packet_in->pi_frame_types = 0;
packet_in->pi_data_sz = length;
packet_in->pi_refcnt = 0;
packet_in->pi_received = 0;
return 0;
}
int
lsquic_iquic_parse_packet_in_short_begin (lsquic_packet_in_t *packet_in,
size_t length, int is_server, struct packin_parse_state *state)
{
const unsigned char *p = packet_in->pi_data;
const unsigned char *const pend = packet_in->pi_data + length;
unsigned cid_len = 8; /* XXX this will need to be passed in */
unsigned packet_len;
if ((*p & 0x30) != 0x30 || (*p & 3) == 3)
return -1;
packet_len = 1 << (*p & 3);
if (pend - p < 1 + cid_len + packet_len)
return -1;
++p;
if (is_server)
{
memcpy(&packet_in->pi_conn_id, p, cid_len);
p += cid_len;
packet_in->pi_flags = PI_CONN_ID;
}
/* We could read in the packet number here, but we choose to do it in
* the finish() call instead.
*/
packet_in->pi_packno = 0;
state->pps_p = p;
state->pps_nbytes = packet_len;
p += packet_len;
packet_in->pi_header_type = HETY_NOT_SET;
packet_in->pi_quic_ver = 0;
packet_in->pi_nonce = 0;
packet_in->pi_header_sz = p - packet_in->pi_data;
packet_in->pi_frame_types = 0;
packet_in->pi_data_sz = length;
packet_in->pi_refcnt = 0;
packet_in->pi_received = 0;
return 0;
}

View File

@ -56,4 +56,7 @@
*/
#define QTAG_NSTP TAG('N', 'S', 'T', 'P')
/* Stateless reset token. Used in Q044 and later. */
#define QTAG_SRST TAG('S', 'R', 'S', 'T')
#endif

View File

@ -45,6 +45,10 @@
#define MIN_RTO_DELAY 1000000 /* Microseconds */
#define N_NACKS_BEFORE_RETX 3
#define packet_out_total_sz(p) \
lsquic_packet_out_total_sz(ctl->sc_conn_pub->lconn, p)
#define packet_out_sent_sz(p) \
lsquic_packet_out_sent_sz(ctl->sc_conn_pub->lconn, p)
enum retx_mode {
RETX_MODE_HANDSHAKE,
@ -402,11 +406,11 @@ send_ctl_unacked_append (struct lsquic_send_ctl *ctl,
struct lsquic_packet_out *packet_out)
{
TAILQ_INSERT_TAIL(&ctl->sc_unacked_packets, packet_out, po_next);
ctl->sc_bytes_unacked_all += lsquic_packet_out_total_sz(packet_out);
ctl->sc_bytes_unacked_all += packet_out_total_sz(packet_out);
ctl->sc_n_in_flight_all += 1;
if (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK)
{
ctl->sc_bytes_unacked_retx += lsquic_packet_out_total_sz(packet_out);
ctl->sc_bytes_unacked_retx += packet_out_total_sz(packet_out);
++ctl->sc_n_in_flight_retx;
}
}
@ -434,7 +438,7 @@ send_ctl_sched_Xpend_common (struct lsquic_send_ctl *ctl,
{
packet_out->po_flags |= PO_SCHED;
++ctl->sc_n_scheduled;
ctl->sc_bytes_scheduled += lsquic_packet_out_total_sz(packet_out);
ctl->sc_bytes_scheduled += packet_out_total_sz(packet_out);
lsquic_send_ctl_sanity_check(ctl);
}
@ -465,7 +469,7 @@ send_ctl_sched_remove (struct lsquic_send_ctl *ctl,
packet_out->po_flags &= ~PO_SCHED;
assert(ctl->sc_n_scheduled);
--ctl->sc_n_scheduled;
ctl->sc_bytes_scheduled -= lsquic_packet_out_total_sz(packet_out);
ctl->sc_bytes_scheduled -= packet_out_total_sz(packet_out);
lsquic_send_ctl_sanity_check(ctl);
}
@ -479,7 +483,7 @@ lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl,
packet_out->po_packno, lsquic_frame_types_to_str(frames,
sizeof(frames), packet_out->po_frame_types));
if (account)
ctl->sc_bytes_out -= lsquic_packet_out_total_sz(packet_out);
ctl->sc_bytes_out -= packet_out_total_sz(packet_out);
lsquic_senhist_add(&ctl->sc_senhist, packet_out->po_packno);
send_ctl_unacked_append(ctl, packet_out);
if (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK)
@ -540,7 +544,7 @@ send_ctl_handle_lost_packet (lsquic_send_ctl_t *ctl,
unsigned packet_sz;
assert(ctl->sc_n_in_flight_all);
packet_sz = lsquic_packet_out_sent_sz(packet_out);
packet_sz = packet_out_sent_sz(packet_out);
send_ctl_unacked_remove(ctl, packet_out, packet_sz);
if (packet_out->po_flags & PO_ENCRYPTED)
send_ctl_release_enc_data(ctl, packet_out);
@ -740,7 +744,7 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
if (!now)
now = lsquic_time_now();
after_checks:
packet_sz = lsquic_packet_out_sent_sz(packet_out);
packet_sz = packet_out_sent_sz(packet_out);
ctl->sc_largest_acked_packno = packet_out->po_packno;
ctl->sc_largest_acked_sent_time = packet_out->po_sent;
send_ctl_unacked_remove(ctl, packet_out, packet_sz);
@ -856,7 +860,7 @@ lsquic_send_ctl_cleanup (lsquic_send_ctl_t *ctl)
while ((packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets)))
{
TAILQ_REMOVE(&ctl->sc_unacked_packets, packet_out, po_next);
ctl->sc_bytes_unacked_all -= lsquic_packet_out_total_sz(packet_out);
ctl->sc_bytes_unacked_all -= packet_out_total_sz(packet_out);
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
--ctl->sc_n_in_flight_all;
}
@ -1008,7 +1012,7 @@ lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl)
count = 0, bytes = 0;
TAILQ_FOREACH(packet_out, &ctl->sc_unacked_packets, po_next)
{
bytes += lsquic_packet_out_sent_sz(packet_out);
bytes += packet_out_sent_sz(packet_out);
++count;
}
assert(count == ctl->sc_n_in_flight_all);
@ -1018,7 +1022,7 @@ lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl)
TAILQ_FOREACH(packet_out, &ctl->sc_scheduled_packets, po_next)
{
assert(packet_out->po_flags & PO_SCHED);
bytes += lsquic_packet_out_total_sz(packet_out);
bytes += packet_out_total_sz(packet_out);
++count;
}
assert(count == ctl->sc_n_scheduled);
@ -1090,7 +1094,7 @@ lsquic_send_ctl_next_packet_to_send (lsquic_send_ctl_t *ctl)
}
send_ctl_sched_remove(ctl, packet_out);
ctl->sc_bytes_out += lsquic_packet_out_total_sz(packet_out);
ctl->sc_bytes_out += packet_out_total_sz(packet_out);
return packet_out;
}
@ -1100,7 +1104,7 @@ lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *ctl,
lsquic_packet_out_t *packet_out)
{
send_ctl_sched_prepend(ctl, packet_out);
ctl->sc_bytes_out -= lsquic_packet_out_total_sz(packet_out);
ctl->sc_bytes_out -= packet_out_total_sz(packet_out);
LSQ_DEBUG("packet %"PRIu64" has been delayed", packet_out->po_packno);
#if LSQUIC_SEND_STATS
++ctl->sc_stats.n_delayed;
@ -1139,7 +1143,7 @@ send_ctl_allocate_packet (lsquic_send_ctl_t *ctl, enum lsquic_packno_bits bits,
packet_out = lsquic_packet_out_new(&ctl->sc_enpub->enp_mm,
ctl->sc_conn_pub->packet_out_malo,
!(ctl->sc_flags & SC_TCID0), ctl->sc_pack_size, bits,
!(ctl->sc_flags & SC_TCID0), ctl->sc_conn_pub->lconn, bits,
ctl->sc_ver_neg->vn_tag, NULL);
if (!packet_out)
return NULL;

View File

@ -1369,8 +1369,10 @@ lsquic_stream_flush_threshold (const struct lsquic_stream *stream)
flags = bits << POBIT_SHIFT;
if (!(stream->conn_pub->lconn->cn_flags & LSCONN_TCID0))
flags |= PO_CONN_ID;
if (LSQUIC_STREAM_HANDSHAKE == stream->id)
flags |= PO_LONGHEAD;
packet_header_sz = lsquic_po_header_length(flags);
packet_header_sz = lsquic_po_header_length(stream->conn_pub->lconn, flags);
stream_header_sz = stream->conn_pub->lconn->cn_pf
->pf_calc_stream_frame_header_sz(stream->id, stream->tosend_off);
@ -1542,6 +1544,9 @@ stream_write_to_packet (struct frame_gen_ctx *fg_ctx, const size_t size)
packet_out = get_packet[hsk](send_ctl, need_at_least, stream);
if (!packet_out)
return SWTP_STOP;
if (hsk)
packet_out->po_header_type = stream->tosend_off == 0
? HETY_INITIAL : HETY_HANDSHAKE;
off = packet_out->po_data_sz;
len = pf->pf_gen_stream_frame(

View File

@ -11,6 +11,10 @@ static const unsigned char version_tags[N_LSQVER][4] =
[LSQVER_035] = { 'Q', '0', '3', '5', },
[LSQVER_039] = { 'Q', '0', '3', '9', },
[LSQVER_043] = { 'Q', '0', '4', '3', },
[LSQVER_044] = { 'Q', '0', '4', '4', },
#if LSQUIC_USE_Q098
[LSQVER_098] = { 'Q', '0', '9', '8', },
#endif
};
@ -58,11 +62,15 @@ const char *const lsquic_ver2str[N_LSQVER] = {
[LSQVER_035] = "Q035",
[LSQVER_039] = "Q039",
[LSQVER_043] = "Q043",
[LSQVER_044] = "Q044",
#if LSQUIC_USE_Q098
[LSQVER_098] = "Q098",
#endif
};
int
gen_ver_tags (unsigned char *buf, size_t bufsz, unsigned version_bitmask)
lsquic_gen_ver_tags (unsigned char *buf, size_t bufsz, unsigned version_bitmask)
{
unsigned n;
lsquic_ver_tag_t tag;

View File

@ -17,6 +17,6 @@ lsquic_tag2ver (uint32_t ver_tag);
extern const char *const lsquic_ver2str[];
int
gen_ver_tags (unsigned char *buf, size_t bufsz, unsigned versions);
lsquic_gen_ver_tags (unsigned char *buf, size_t bufsz, unsigned versions);
#endif

View File

@ -11,8 +11,10 @@
#include "lsquic_int_types.h"
#include "lsquic_packet_common.h"
#include "lsquic_parse.h"
#include "lsquic_parse_common.h"
#include "lsquic_packet_in.h"
#include "lsquic_engine_public.h"
#include "lsquic_version.h"
struct parse_packet_in_test
@ -22,8 +24,7 @@ struct parse_packet_in_test
unsigned char ppit_buf[0x100];
unsigned ppit_bufsz;
int ppit_is_server;
const struct parse_funcs *
ppit_pf;
enum lsquic_version ppit_version;
/* Output */
int ppit_retval;
int ppit_pi_flags;
@ -49,7 +50,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 1 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -72,7 +73,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 2 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -95,7 +96,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 4 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -118,7 +119,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 6 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -138,7 +139,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 0 + 4 + 1 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = 0,
.ppit_conn_id = 0,
@ -157,7 +158,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 0 + 0 + 1 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = 0,
.ppit_conn_id = 0,
@ -179,7 +180,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = -1,
},
@ -198,7 +199,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 32+ 2 + 7,
.ppit_is_server = 0,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -223,7 +224,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 32+ 1 + 7,
.ppit_is_server = 0,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -247,7 +248,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 4 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -270,7 +271,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 1 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -294,7 +295,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 6 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -315,7 +316,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 8,
.ppit_is_server = 0,
.ppit_pf = select_pf_by_ver(LSQVER_035),
.ppit_version = LSQVER_035,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -340,7 +341,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 1 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -363,7 +364,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 2 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -386,7 +387,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 4 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -409,7 +410,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 6 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -429,7 +430,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 0 + 4 + 1 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = 0,
.ppit_conn_id = 0,
@ -448,7 +449,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 0 + 0 + 1 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = 0,
.ppit_conn_id = 0,
@ -470,7 +471,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = -1,
},
@ -489,7 +490,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 32+ 2 + 7,
.ppit_is_server = 0,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -514,7 +515,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 32+ 1 + 7,
.ppit_is_server = 0,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -538,7 +539,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 4 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -561,7 +562,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 1 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -585,7 +586,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 4 + 6 + 7,
.ppit_is_server = 1,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -606,7 +607,7 @@ static const struct parse_packet_in_test tests[] = {
},
.ppit_bufsz = 1 + 8 + 8,
.ppit_is_server = 0,
.ppit_pf = select_pf_by_ver(LSQVER_039),
.ppit_version = LSQVER_039,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x5500000000000000,
@ -616,6 +617,83 @@ static const struct parse_packet_in_test tests[] = {
.ppit_quic_ver = 1 + 8,
.ppit_nonce = 0,
},
{ .ppit_lineno = __LINE__,
.ppit_buf = {
/* Flags: */ 0x30,
/* CID: */ 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80,
/* Packet number: */0x9B,
/* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D',
},
.ppit_bufsz = 1 + 8 + 1 + 7,
.ppit_is_server = 1,
.ppit_version = LSQVER_044,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x8070605004030201,
.ppit_packno = 0x9B,
.ppit_header_sz = 1 + 8 + 1,
.ppit_data_sz = 1 + 8 + 1 + 7,
.ppit_quic_ver = 0,
.ppit_nonce = 0,
},
{ .ppit_lineno = __LINE__,
.ppit_buf = {
/* Flags: */ 0x32,
/* CID: */ 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80,
/* Packet number: */0x9B, 0x03, 0x02, 0x01,
/* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D',
},
.ppit_bufsz = 1 + 8 + 4 + 7,
.ppit_is_server = 1,
.ppit_version = LSQVER_044,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x8070605004030201,
.ppit_packno = 0x9B030201,
.ppit_header_sz = 1 + 8 + 4,
.ppit_data_sz = 1 + 8 + 4 + 7,
.ppit_quic_ver = 0,
.ppit_nonce = 0,
},
{ .ppit_lineno = __LINE__,
.ppit_buf = {
/* Flags: */ 0x30
| 0x3 /* <--- Invalid type */,
/* CID: */ 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80,
/* Packet number: */0x9B,
/* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D',
},
.ppit_bufsz = 1 + 8 + 1 + 7,
.ppit_is_server = 1,
.ppit_version = LSQVER_044,
.ppit_retval = -1,
},
{ .ppit_lineno = __LINE__,
.ppit_buf = {
/* Type: */ 0xFF /* Initial */,
/* Version: */ 'Q', '0', '4', '4',
/* DCIL/SCIL: */ 0x5 /* DCIL */ << 4 | 0x0 /* SCIL */,
/* CID: */ 0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80,
/* Packet number: */0x21, 0x22, 0x23, 0x34,
/* Payload: */ 'P', 'A', 'Y', 'L', 'O', 'A', 'D',
},
.ppit_bufsz = 1 + 4 + 1 + 8 + 4 + 7,
.ppit_is_server = 1,
.ppit_version = LSQVER_044,
.ppit_retval = 0,
.ppit_pi_flags = PI_CONN_ID,
.ppit_conn_id = 0x8070605004030201,
.ppit_packno = 0x21222334,
.ppit_header_sz = 1 + 4 + 1 + 8 + 4,
.ppit_data_sz = 1 + 4 + 1 + 8 + 4 + 7,
.ppit_quic_ver = 1,
.ppit_nonce = 0,
},
};
@ -630,10 +708,47 @@ run_ppi_test (struct lsquic_mm *mm, const struct parse_packet_in_test *ppit)
packet_in->pi_data = lsquic_mm_get_1370(mm);
packet_in->pi_flags |= PI_OWN_DATA;
memcpy(packet_in->pi_data, ppit->ppit_buf, ppit->ppit_bufsz);
s = parse_packet_in_begin(packet_in, ppit->ppit_bufsz, ppit->ppit_is_server, &ppstate);
/* Server should be able to differentiate different header formats
* because it expect the connection ID to be there, while the client
* needs help.
*/
if (ppit->ppit_is_server &&
/* In addition, some tests verify parsing of GQUIC packets in
* server mode where there is no connection ID. This is for
* completeness and does not represent a real-life scenario,
* as the server will always require the client to send the
* connection ID.
*/
!(!(ppit->ppit_pi_flags & PI_CONN_ID)
&& ppit->ppit_version < LSQVER_044))
s = lsquic_parse_packet_in_begin(packet_in, ppit->ppit_bufsz,
ppit->ppit_is_server, &ppstate);
else if (ppit->ppit_version < LSQVER_044)
s = lsquic_gquic_parse_packet_in_begin(packet_in, ppit->ppit_bufsz,
ppit->ppit_is_server, &ppstate);
else
s = lsquic_iquic_parse_packet_in_begin(packet_in, ppit->ppit_bufsz,
ppit->ppit_is_server, &ppstate);
assert(s == ppit->ppit_retval);
if (0 == s)
ppit->ppit_pf->pf_parse_packet_in_finish(packet_in, &ppstate);
{
const struct parse_funcs *pf;
if (ppit->ppit_quic_ver && ppit->ppit_is_server /* Server packets
with version are version negotiation packets. */)
{
uint32_t tag;
enum lsquic_version ver;
assert(packet_in->pi_quic_ver);
memcpy(&tag, packet_in->pi_data + packet_in->pi_quic_ver, 4);
ver = lsquic_tag2ver(tag);
assert((enum lsquic_version) -1 != ver);
assert(ver == ppit->ppit_version);
}
pf = select_pf_by_ver(ppit->ppit_version);
pf->pf_parse_packet_in_finish(packet_in, &ppstate);
}
if (0 == s)
{

View File

@ -8,10 +8,12 @@
#endif
#include "lsquic_types.h"
#include "lsquic.h"
#include "lsquic_alarmset.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_out.h"
#include "lsquic_conn.h"
#include "lsquic_parse.h"
#include "lsquic.h"
struct test {
/* Inputs. */
@ -232,11 +234,23 @@ run_test (int i)
{
const struct test *const test = &tests[i];
struct lsquic_packet_out packet_out =
{
.po_flags = (test->cid ? PO_CONN_ID : 0)
| (test->ver.val ? PO_VERSION : 0)
| (test->nonce ? PO_NONCE: 0)
,
.po_nonce = (unsigned char *) test->nonce,
.po_ver_tag = test->ver.val,
.po_packno = test->packno,
};
lsquic_packet_out_set_packno_bits(&packet_out, test->bits);
struct lsquic_conn lconn = { .cn_cid = test->cid, };
unsigned char out[QUIC_MAX_PUBHDR_SZ];
int len = test->pf->pf_gen_reg_pkt_header(out, sizeof(out),
(test->cid ? &test->cid : NULL),
(test->ver.val ? &test->ver.val : NULL),
(unsigned char *) test->nonce, test->packno, test->bits);
int len = test->pf->pf_gen_reg_pkt_header(&lconn, &packet_out, out,
sizeof(out));
assert(("Packet length is correct", len == test->len));

View File

@ -62,6 +62,7 @@ lsquic_stream_tosend_sz (const lsquic_stream_t *stream)
static int make_complex_packet(unsigned char *pkt_buf, int max_buf_len)
{
#if 0 /* What is this function testing? Seems useless. */
unsigned char *p = pkt_buf;
unsigned char *const pend = p + 1500;
lsquic_stream_t *stream = lsquic_stream_new(12345, NULL, NULL, NULL, 0, 0);
@ -90,6 +91,8 @@ static int make_complex_packet(unsigned char *pkt_buf, int max_buf_len)
free(stream);
return p - pkt_buf;
#endif
return 0;
}

View File

@ -13,12 +13,12 @@
#include "lsquic_alarmset.h"
#include "lsquic_packet_common.h"
#include "lsquic_parse.h"
#include "lsquic_parse_common.h"
#include "lsquic_mm.h"
#include "lsquic_packet_in.h"
#include "lsquic_engine_public.h"
#include "lsquic_version.h"
static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_035);
/* The struct is used to test both generation and parsing of version
@ -100,7 +100,7 @@ test_parsing_ver_nego (const struct gen_ver_nego_test *gvnt)
packet_in->pi_data = lsquic_mm_get_1370(&mm);
packet_in->pi_flags |= PI_OWN_DATA;
memcpy(packet_in->pi_data, gvnt->gvnt_buf, gvnt->gvnt_len);
s = parse_packet_in_begin(packet_in, gvnt->gvnt_len, 0, &ppstate);
s = lsquic_parse_packet_in_begin(packet_in, gvnt->gvnt_len, 0, &ppstate);
assert(s == 0);
for (s = packet_in_ver_first(packet_in, &vi, &ver_tag); s;
@ -119,32 +119,12 @@ test_parsing_ver_nego (const struct gen_ver_nego_test *gvnt)
}
static void
run_gvnt (int i)
{
const struct gen_ver_nego_test *const gvnt = &tests[i];
unsigned char out[0x40];
assert(sizeof(out) <= sizeof(gvnt->gvnt_buf)); /* Internal sanity check */
int len = pf->pf_gen_ver_nego_pkt(out, gvnt->gvnt_bufsz, gvnt->gvnt_cid,
gvnt->gvnt_versions);
assert(("Packet length is correct", len == gvnt->gvnt_len));
if (gvnt->gvnt_len > 0)
{
assert(("Packet contents are correct",
0 == memcmp(out, gvnt->gvnt_buf, gvnt->gvnt_len)));
test_parsing_ver_nego(gvnt);
}
}
int
main (void)
{
unsigned i;
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i)
run_gvnt(i);
if (tests[i].gvnt_len > 0)
test_parsing_ver_nego(&tests[i]);
return 0;
}