Release 2.10.5

- [BUGFIX] BBR: call cci_sent() with correct arguments and at correct time.
- Refactor transport parameters module.
- Minor code cleanup.
This commit is contained in:
Dmitri Tikhonov 2020-02-13 09:36:04 -05:00
parent e68b045258
commit 1bdb91d191
12 changed files with 460 additions and 458 deletions

View file

@ -1,3 +1,10 @@
2020-02-13
- 2.10.5
- [BUGFIX] BBR: call cci_sent() with correct arguments and at correct
time.
- Refactor transport parameters module.
- Minor code cleanup.
2020-02-11 2020-02-11
- 2.10.4 - 2.10.4
- [BUGFIX] Send HANDSHAKE_DONE only after Finished is received. - [BUGFIX] Send HANDSHAKE_DONE only after Finished is received.

View file

@ -25,7 +25,7 @@ extern "C" {
#define LSQUIC_MAJOR_VERSION 2 #define LSQUIC_MAJOR_VERSION 2
#define LSQUIC_MINOR_VERSION 10 #define LSQUIC_MINOR_VERSION 10
#define LSQUIC_PATCH_VERSION 4 #define LSQUIC_PATCH_VERSION 5
/** /**
* Engine flags: * Engine flags:
@ -757,7 +757,6 @@ struct lsquic_engine_settings {
* 0: Do not use loss bits * 0: Do not use loss bits
* 1: Allow loss bits * 1: Allow loss bits
* 2: Allow and send loss bits * 2: Allow and send loss bits
* -1: Allow and send loss bits, sending old-style boolean loss_bits TP
* *
* Default value is @ref LSQUIC_DF_QL_BITS * Default value is @ref LSQUIC_DF_QL_BITS
*/ */

View file

@ -436,15 +436,14 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
{ {
const struct lsquic_conn *const lconn = enc_sess->esi_conn; const struct lsquic_conn *const lconn = enc_sess->esi_conn;
params.tp_flags |= TRAPA_SERVER|TRAPA_RESET_TOKEN; params.tp_set |= 1 << TPI_STATELESS_RESET_TOKEN;
lsquic_tg_generate_sreset(enc_sess->esi_enpub->enp_tokgen, lsquic_tg_generate_sreset(enc_sess->esi_enpub->enp_tokgen,
CN_SCID(lconn), params.tp_stateless_reset_token); CN_SCID(lconn), params.tp_stateless_reset_token);
if (enc_sess->esi_flags & ESI_ODCID) if (enc_sess->esi_flags & ESI_ODCID)
{ {
params.tp_original_cid = enc_sess->esi_odcid; params.tp_original_cid = enc_sess->esi_odcid;
params.tp_flags |= TRAPA_ORIGINAL_CID; params.tp_set |= 1 << TPI_ORIGINAL_CONNECTION_ID;
} }
#if LSQUIC_PREFERRED_ADDR #if LSQUIC_PREFERRED_ADDR
char addr_buf[INET6_ADDRSTRLEN + 6 /* port */ + 1]; char addr_buf[INET6_ADDRSTRLEN + 6 /* port */ + 1];
@ -459,7 +458,7 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
addr_buf[colon - s] = '\0'; addr_buf[colon - s] = '\0';
inet_pton(AF_INET, addr_buf, params.tp_preferred_address.ipv4_addr); inet_pton(AF_INET, addr_buf, params.tp_preferred_address.ipv4_addr);
params.tp_preferred_address.ipv4_port = atoi(colon + 1); params.tp_preferred_address.ipv4_port = atoi(colon + 1);
params.tp_flags |= TRAPA_PREFADDR_IPv4; params.tp_set |= 1 << TPI_PREFERRED_ADDRESS;
} }
s = getenv("LSQUIC_PREFERRED_ADDR6"); s = getenv("LSQUIC_PREFERRED_ADDR6");
if (s && strlen(s) < sizeof(addr_buf) && (colon = strrchr(s, ':'))) if (s && strlen(s) < sizeof(addr_buf) && (colon = strrchr(s, ':')))
@ -469,10 +468,10 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
inet_pton(AF_INET6, addr_buf, inet_pton(AF_INET6, addr_buf,
params.tp_preferred_address.ipv6_addr); params.tp_preferred_address.ipv6_addr);
params.tp_preferred_address.ipv6_port = atoi(colon + 1); params.tp_preferred_address.ipv6_port = atoi(colon + 1);
params.tp_flags |= TRAPA_PREFADDR_IPv6; params.tp_set |= 1 << TPI_PREFERRED_ADDRESS;
} }
conn = enc_sess->esi_conn; conn = enc_sess->esi_conn;
if ((params.tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6)) if ((params.tp_set & (1 << TPI_PREFERRED_ADDRESS))
&& (1 << conn->cn_n_cces) - 1 != conn->cn_cces_mask) && (1 << conn->cn_n_cces) - 1 != conn->cn_cces_mask)
{ {
seqno = 0; seqno = 0;
@ -506,7 +505,7 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
else else
{ {
cant_use_prefaddr: cant_use_prefaddr:
params.tp_flags &= ~(TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6); params.tp_set &= ~(1 << TPI_PREFERRED_ADDRESS);
} }
#endif #endif
} }
@ -515,7 +514,7 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
{ {
const char *s = getenv("LSQUIC_TEST_QUANTUM_READINESS"); const char *s = getenv("LSQUIC_TEST_QUANTUM_READINESS");
if (s && atoi(s)) if (s && atoi(s))
params.tp_flags |= TRAPA_QUANTUM_READY; params.tp_set |= 1 << TPI_QUANTUM_READINESS;
} }
#endif #endif
params.tp_init_max_data = settings->es_init_max_data; params.tp_init_max_data = settings->es_init_max_data;
@ -535,23 +534,33 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
params.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY; params.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY;
params.tp_max_packet_size = 1370 /* XXX: based on socket */; params.tp_max_packet_size = 1370 /* XXX: based on socket */;
params.tp_active_connection_id_limit = MAX_IETF_CONN_DCIDS; params.tp_active_connection_id_limit = MAX_IETF_CONN_DCIDS;
params.tp_set |= (1 << TPI_INIT_MAX_DATA)
| (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL)
| (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE)
| (1 << TPI_INIT_MAX_STREAM_DATA_UNI)
| (1 << TPI_INIT_MAX_STREAMS_UNI)
| (1 << TPI_INIT_MAX_STREAMS_BIDI)
| (1 << TPI_ACK_DELAY_EXPONENT)
| (1 << TPI_MAX_IDLE_TIMEOUT)
| (1 << TPI_MAX_ACK_DELAY)
| (1 << TPI_MAX_PACKET_SIZE)
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT)
;
if (enc_sess->esi_conn->cn_version == LSQVER_ID24) if (enc_sess->esi_conn->cn_version == LSQVER_ID24)
{ {
params.tp_active_connection_id_limit = params.tp_active_connection_id_limit params.tp_active_connection_id_limit = params.tp_active_connection_id_limit
- 1 /* One slot is used by peer's SCID */ - 1 /* One slot is used by peer's SCID */
- !!(params.tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6)); - !!(params.tp_set & (1 << TPI_PREFERRED_ADDRESS));
} }
if (!settings->es_allow_migration) if (!settings->es_allow_migration)
params.tp_disable_active_migration = 1; params.tp_set |= 1 << TPI_DISABLE_ACTIVE_MIGRATION;
if (settings->es_ql_bits == -1) if (settings->es_ql_bits)
params.tp_flags |= TRAPA_QL_BITS_OLD;
else if (settings->es_ql_bits)
{ {
params.tp_loss_bits = settings->es_ql_bits - 1; params.tp_loss_bits = settings->es_ql_bits - 1;
params.tp_flags |= TRAPA_QL_BITS; params.tp_set |= 1 << TPI_LOSS_BITS;
} }
len = lsquic_tp_encode(&params, buf, bufsz); len = lsquic_tp_encode(&params, enc_sess->esi_flags & ESI_SERVER, buf, bufsz);
if (len >= 0) if (len >= 0)
LSQ_DEBUG("generated transport parameters buffer of %d bytes", len); LSQ_DEBUG("generated transport parameters buffer of %d bytes", len);
else else
@ -1458,7 +1467,7 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
if ((enc_sess->esi_flags & (ESI_ODCID|ESI_SERVER)) == ESI_ODCID) if ((enc_sess->esi_flags & (ESI_ODCID|ESI_SERVER)) == ESI_ODCID)
{ {
if (!(trans_params->tp_flags & TRAPA_ORIGINAL_CID)) if (!(trans_params->tp_set & (1 << TPI_ORIGINAL_CONNECTION_ID)))
{ {
LSQ_DEBUG("server did not produce original DCID (ODCID)"); LSQ_DEBUG("server did not produce original DCID (ODCID)");
return -1; return -1;
@ -1480,15 +1489,11 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
} }
} }
if ((trans_params->tp_flags & TRAPA_QL_BITS) if ((trans_params->tp_set & (1 << TPI_LOSS_BITS))
&& enc_sess->esi_enpub->enp_settings.es_ql_bits) && enc_sess->esi_enpub->enp_settings.es_ql_bits)
{ {
unsigned our_loss_bits; const unsigned our_loss_bits
if (enc_sess->esi_enpub->enp_settings.es_ql_bits == -1) = enc_sess->esi_enpub->enp_settings.es_ql_bits - 1;
our_loss_bits = 1;
else
our_loss_bits = enc_sess->esi_enpub->enp_settings.es_ql_bits - 1;
switch ((our_loss_bits << 1) | trans_params->tp_loss_bits) switch ((our_loss_bits << 1) | trans_params->tp_loss_bits)
{ {
case (0 << 1) | 0: case (0 << 1) | 0:

View file

@ -403,7 +403,7 @@ lsquic_engine_check_settings (const struct lsquic_engine_settings *settings,
return -1; return -1;
} }
if (!(settings->es_ql_bits >= -1 && settings->es_ql_bits <= 2)) if (!(settings->es_ql_bits >= 0 && settings->es_ql_bits <= 2))
{ {
if (err_buf) if (err_buf)
snprintf(err_buf, err_buf_sz, "Invalid QL bits value %d ", snprintf(err_buf, err_buf_sz, "Invalid QL bits value %d ",

View file

@ -2592,10 +2592,10 @@ begin_migra_or_retire_cid (struct id24_full_conn *conn,
struct sockaddr_in6 v6; struct sockaddr_in6 v6;
} sockaddr; } sockaddr;
if (params->tp_disable_active_migration if ((params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION))
|| !conn->ifc_settings->es_allow_migration) || !conn->ifc_settings->es_allow_migration)
{ {
if (params->tp_disable_active_migration) if (params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION))
LSQ_DEBUG("TP disables migration: retire PreferredAddress CID"); LSQ_DEBUG("TP disables migration: retire PreferredAddress CID");
else else
LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID"); LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID");
@ -2604,8 +2604,8 @@ begin_migra_or_retire_cid (struct id24_full_conn *conn,
} }
is_ipv6 = NP_IS_IPv6(CUR_NPATH(conn)); is_ipv6 = NP_IS_IPv6(CUR_NPATH(conn));
if ((is_ipv6 && !(params->tp_flags & TRAPA_PREFADDR_IPv6)) if ((is_ipv6 && !lsquic_tp_has_pref_ipv6(params))
|| (!is_ipv6 && !(params->tp_flags & TRAPA_PREFADDR_IPv4))) || (!is_ipv6 && !lsquic_tp_has_pref_ipv4(params)))
{ {
/* XXX This is a limitation in the client code outside of the library. /* XXX This is a limitation in the client code outside of the library.
* To support cross-IP-version migration, we need to add some callbacks * To support cross-IP-version migration, we need to add some callbacks
@ -2683,7 +2683,7 @@ maybe_start_migration (struct id24_full_conn *conn)
params = lconn->cn_esf.i->esfi_get_peer_transport_params( params = lconn->cn_esf.i->esfi_get_peer_transport_params(
lconn->cn_enc_session); lconn->cn_enc_session);
if (params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6)) if (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
{ {
if (0 != begin_migra_or_retire_cid(conn, params)) if (0 != begin_migra_or_retire_cid(conn, params))
ABORT_QUIETLY(0, TEC_INTERNAL_ERROR, "error initiating migration"); ABORT_QUIETLY(0, TEC_INTERNAL_ERROR, "error initiating migration");
@ -2721,9 +2721,8 @@ handshake_ok (struct lsquic_conn *lconn)
LSQ_DEBUG("peer transport parameters: %s", LSQ_DEBUG("peer transport parameters: %s",
(lsquic_tp_to_str(params, buf, sizeof(buf)), buf)); (lsquic_tp_to_str(params, buf, sizeof(buf)), buf));
if ((params->tp_flags & TRAPA_QL_BITS) if ((params->tp_set & (1 << TPI_LOSS_BITS))
&& (conn->ifc_settings->es_ql_bits == 2 && conn->ifc_settings->es_ql_bits == 2)
|| conn->ifc_settings->es_ql_bits == -1))
{ {
LSQ_DEBUG("turn on QL loss bits"); LSQ_DEBUG("turn on QL loss bits");
lsquic_send_ctl_do_ql_bits(&conn->ifc_send_ctl); lsquic_send_ctl_do_ql_bits(&conn->ifc_send_ctl);
@ -2797,7 +2796,7 @@ handshake_ok (struct lsquic_conn *lconn)
memset(dce, 0, sizeof(*dce)); memset(dce, 0, sizeof(*dce));
dce->de_cid = *CUR_DCID(conn); dce->de_cid = *CUR_DCID(conn);
dce->de_seqno = 0; dce->de_seqno = 0;
if (params->tp_flags & TRAPA_RESET_TOKEN) if (params->tp_set & (1 << TPI_STATELESS_RESET_TOKEN))
{ {
memcpy(dce->de_srst, params->tp_stateless_reset_token, memcpy(dce->de_srst, params->tp_stateless_reset_token,
sizeof(dce->de_srst)); sizeof(dce->de_srst));
@ -4795,7 +4794,7 @@ must_reserve_one_dce_slot (struct id24_full_conn *conn)
params = lconn->cn_esf.i->esfi_get_peer_transport_params( params = lconn->cn_esf.i->esfi_get_peer_transport_params(
lconn->cn_enc_session); lconn->cn_enc_session);
if (params) /* Just in case */ if (params) /* Just in case */
return !!(params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6)); return !!(params->tp_set & (1 << TPI_PREFERRED_ADDRESS));
else else
return 0; return 0;
} }

View file

@ -2765,10 +2765,10 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
struct sockaddr_in6 v6; struct sockaddr_in6 v6;
} sockaddr; } sockaddr;
if (params->tp_disable_active_migration if ((params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION))
|| !conn->ifc_settings->es_allow_migration) || !conn->ifc_settings->es_allow_migration)
{ {
if (params->tp_disable_active_migration) if (params->tp_set & (1 << TPI_DISABLE_ACTIVE_MIGRATION))
LSQ_DEBUG("TP disables migration: retire PreferredAddress CID"); LSQ_DEBUG("TP disables migration: retire PreferredAddress CID");
else else
LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID"); LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID");
@ -2777,8 +2777,8 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
} }
is_ipv6 = NP_IS_IPv6(CUR_NPATH(conn)); is_ipv6 = NP_IS_IPv6(CUR_NPATH(conn));
if ((is_ipv6 && !(params->tp_flags & TRAPA_PREFADDR_IPv6)) if ((is_ipv6 && !lsquic_tp_has_pref_ipv6(params))
|| (!is_ipv6 && !(params->tp_flags & TRAPA_PREFADDR_IPv4))) || (!is_ipv6 && !lsquic_tp_has_pref_ipv4(params)))
{ {
/* XXX This is a limitation in the client code outside of the library. /* XXX This is a limitation in the client code outside of the library.
* To support cross-IP-version migration, we need to add some callbacks * To support cross-IP-version migration, we need to add some callbacks
@ -2856,7 +2856,7 @@ maybe_start_migration (struct ietf_full_conn *conn)
params = lconn->cn_esf.i->esfi_get_peer_transport_params( params = lconn->cn_esf.i->esfi_get_peer_transport_params(
lconn->cn_enc_session); lconn->cn_enc_session);
if (params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6)) if (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
{ {
if (0 != begin_migra_or_retire_cid(conn, params)) if (0 != begin_migra_or_retire_cid(conn, params))
ABORT_QUIETLY(0, TEC_INTERNAL_ERROR, "error initiating migration"); ABORT_QUIETLY(0, TEC_INTERNAL_ERROR, "error initiating migration");
@ -2894,9 +2894,8 @@ handshake_ok (struct lsquic_conn *lconn)
LSQ_DEBUG("peer transport parameters: %s", LSQ_DEBUG("peer transport parameters: %s",
(lsquic_tp_to_str(params, buf, sizeof(buf)), buf)); (lsquic_tp_to_str(params, buf, sizeof(buf)), buf));
if ((params->tp_flags & TRAPA_QL_BITS) if ((params->tp_set & (1 << TPI_LOSS_BITS))
&& (conn->ifc_settings->es_ql_bits == 2 && conn->ifc_settings->es_ql_bits == 2)
|| conn->ifc_settings->es_ql_bits == -1))
{ {
LSQ_DEBUG("turn on QL loss bits"); LSQ_DEBUG("turn on QL loss bits");
lsquic_send_ctl_do_ql_bits(&conn->ifc_send_ctl); lsquic_send_ctl_do_ql_bits(&conn->ifc_send_ctl);
@ -3005,7 +3004,7 @@ handshake_ok (struct lsquic_conn *lconn)
memset(dce, 0, sizeof(*dce)); memset(dce, 0, sizeof(*dce));
dce->de_cid = *CUR_DCID(conn); dce->de_cid = *CUR_DCID(conn);
dce->de_seqno = 0; dce->de_seqno = 0;
if (params->tp_flags & TRAPA_RESET_TOKEN) if (params->tp_set & (1 << TPI_STATELESS_RESET_TOKEN))
{ {
memcpy(dce->de_srst, params->tp_stateless_reset_token, memcpy(dce->de_srst, params->tp_stateless_reset_token,
sizeof(dce->de_srst)); sizeof(dce->de_srst));

View file

@ -887,9 +887,10 @@ gquic_be_gen_ack_frame (unsigned char *outbuf, size_t outbuf_sz,
*type |= bits; *type |= bits;
CHECKOUT(largest_acked_len); CHECKOUT(largest_acked_len);
tmp_packno = maxno;
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
tmp_packno = bswap_64(maxno); tmp_packno = bswap_64(maxno);
#else
tmp_packno = maxno;
#endif #endif
memcpy(p, (unsigned char *) &tmp_packno + 8 - largest_acked_len, memcpy(p, (unsigned char *) &tmp_packno + 8 - largest_acked_len,
largest_acked_len); largest_acked_len);

View file

@ -655,6 +655,9 @@ lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl,
packet_out->po_packno, lsquic_frame_types_to_str(frames, packet_out->po_packno, lsquic_frame_types_to_str(frames,
sizeof(frames), packet_out->po_frame_types)); sizeof(frames), packet_out->po_frame_types));
lsquic_senhist_add(&ctl->sc_senhist, packet_out->po_packno); lsquic_senhist_add(&ctl->sc_senhist, packet_out->po_packno);
if (ctl->sc_ci->cci_sent)
ctl->sc_ci->cci_sent(CGP(ctl), packet_out, ctl->sc_bytes_unacked_all,
ctl->sc_flags & SC_APP_LIMITED);
send_ctl_unacked_append(ctl, packet_out); send_ctl_unacked_append(ctl, packet_out);
if (packet_out->po_frame_types & ctl->sc_retx_frames) if (packet_out->po_frame_types & ctl->sc_retx_frames)
{ {
@ -670,9 +673,6 @@ lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl,
#if LSQUIC_SEND_STATS #if LSQUIC_SEND_STATS
++ctl->sc_stats.n_total_sent; ++ctl->sc_stats.n_total_sent;
#endif #endif
if (ctl->sc_ci->cci_sent)
ctl->sc_ci->cci_sent(CGP(ctl), packet_out, ctl->sc_n_in_flight_all,
ctl->sc_flags & SC_APP_LIMITED);
lsquic_send_ctl_sanity_check(ctl); lsquic_send_ctl_sanity_check(ctl);
return 0; return 0;
} }

View file

@ -3407,10 +3407,10 @@ lsquic_stream_writef (lsquic_stream_t *stream, struct lsquic_reader *reader)
static ssize_t static ssize_t
stream_write_buf (struct lsquic_stream *stream, const void *buf, size_t sz) stream_write_buf (struct lsquic_stream *stream, const void *buf, size_t sz)
{ {
struct iovec iov = { (void *) buf, sz, }; const struct iovec iov[1] = {{ (void *) buf, sz, }};
struct inner_reader_iovec iro = { struct inner_reader_iovec iro = {
.iov = &iov, .iov = iov,
.end = &iov + 1, .end = iov + 1,
.cur_iovec_off = 0, .cur_iovec_off = 0,
}; };
struct lsquic_reader reader = { struct lsquic_reader reader = {

View file

@ -6,6 +6,7 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -26,7 +27,84 @@
#include "lsquic_logger.h" #include "lsquic_logger.h"
static const uint64_t def_vals[MAX_TPI + 1] = static enum transport_param_id
tpi_val_2_enum (uint64_t tpi_val)
{
switch (tpi_val)
{
case 0: return TPI_ORIGINAL_CONNECTION_ID;
case 1: return TPI_MAX_IDLE_TIMEOUT;
case 2: return TPI_STATELESS_RESET_TOKEN;
case 3: return TPI_MAX_PACKET_SIZE;
case 4: return TPI_INIT_MAX_DATA;
case 5: return TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL;
case 6: return TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE;
case 7: return TPI_INIT_MAX_STREAM_DATA_UNI;
case 8: return TPI_INIT_MAX_STREAMS_BIDI;
case 9: return TPI_INIT_MAX_STREAMS_UNI;
case 10: return TPI_ACK_DELAY_EXPONENT;
case 11: return TPI_MAX_ACK_DELAY;
case 12: return TPI_DISABLE_ACTIVE_MIGRATION;
case 13: return TPI_PREFERRED_ADDRESS;
case 14: return TPI_ACTIVE_CONNECTION_ID_LIMIT;
#if LSQUIC_TEST_QUANTUM_READINESS
case 0xC37: return TPI_QUANTUM_READINESS;
#endif
case 0x1057: return TPI_LOSS_BITS;
default: return INT_MAX;
}
}
static const unsigned short enum_2_tpi_val[LAST_TPI + 1] =
{
[TPI_ORIGINAL_CONNECTION_ID] = 0x0,
[TPI_MAX_IDLE_TIMEOUT] = 0x1,
[TPI_STATELESS_RESET_TOKEN] = 0x2,
[TPI_MAX_PACKET_SIZE] = 0x3,
[TPI_INIT_MAX_DATA] = 0x4,
[TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL] = 0x5,
[TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE] = 0x6,
[TPI_INIT_MAX_STREAM_DATA_UNI] = 0x7,
[TPI_INIT_MAX_STREAMS_BIDI] = 0x8,
[TPI_INIT_MAX_STREAMS_UNI] = 0x9,
[TPI_ACK_DELAY_EXPONENT] = 0xA,
[TPI_MAX_ACK_DELAY] = 0xB,
[TPI_DISABLE_ACTIVE_MIGRATION] = 0xC,
[TPI_PREFERRED_ADDRESS] = 0xD,
[TPI_ACTIVE_CONNECTION_ID_LIMIT] = 0xE,
#if LSQUIC_TEST_QUANTUM_READINESS
[TPI_QUANTUM_READINESS] = 0xC37,
#endif
[TPI_LOSS_BITS] = 0x1057,
};
static const char * const tpi2str[LAST_TPI + 1] =
{
[TPI_ORIGINAL_CONNECTION_ID] = "original_connection_id",
[TPI_MAX_IDLE_TIMEOUT] = "max_idle_timeout",
[TPI_STATELESS_RESET_TOKEN] = "stateless_reset_token",
[TPI_MAX_PACKET_SIZE] = "max_packet_size",
[TPI_INIT_MAX_DATA] = "init_max_data",
[TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL] = "init_max_stream_data_bidi_local",
[TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE] = "init_max_stream_data_bidi_remote",
[TPI_INIT_MAX_STREAM_DATA_UNI] = "init_max_stream_data_uni",
[TPI_INIT_MAX_STREAMS_BIDI] = "init_max_streams_bidi",
[TPI_INIT_MAX_STREAMS_UNI] = "init_max_streams_uni",
[TPI_ACK_DELAY_EXPONENT] = "ack_delay_exponent",
[TPI_MAX_ACK_DELAY] = "max_ack_delay",
[TPI_DISABLE_ACTIVE_MIGRATION] = "disable_active_migration",
[TPI_PREFERRED_ADDRESS] = "preferred_address",
[TPI_ACTIVE_CONNECTION_ID_LIMIT] = "active_connection_id_limit",
#if LSQUIC_TEST_QUANTUM_READINESS
[TPI_QUANTUM_READINESS] = "quantum_readiness",
#endif
[TPI_LOSS_BITS] = "loss_bits",
};
static const uint64_t def_vals[MAX_NUM_WITH_DEF_TPI + 1] =
{ {
[TPI_MAX_PACKET_SIZE] = TP_DEF_MAX_PACKET_SIZE, [TPI_MAX_PACKET_SIZE] = TP_DEF_MAX_PACKET_SIZE,
[TPI_ACK_DELAY_EXPONENT] = TP_DEF_ACK_DELAY_EXP, [TPI_ACK_DELAY_EXPONENT] = TP_DEF_ACK_DELAY_EXP,
@ -42,7 +120,7 @@ static const uint64_t def_vals[MAX_TPI + 1] =
}; };
static const uint64_t max_vals[MAX_TPI + 1] = static const uint64_t max_vals[MAX_NUMERIC_TPI + 1] =
{ {
[TPI_MAX_PACKET_SIZE] = VINT_MAX_VALUE, [TPI_MAX_PACKET_SIZE] = VINT_MAX_VALUE,
[TPI_ACK_DELAY_EXPONENT] = VINT_MAX_VALUE, [TPI_ACK_DELAY_EXPONENT] = VINT_MAX_VALUE,
@ -55,27 +133,7 @@ static const uint64_t max_vals[MAX_TPI + 1] =
[TPI_MAX_IDLE_TIMEOUT] = VINT_MAX_VALUE, [TPI_MAX_IDLE_TIMEOUT] = VINT_MAX_VALUE,
[TPI_MAX_ACK_DELAY] = TP_MAX_MAX_ACK_DELAY, [TPI_MAX_ACK_DELAY] = TP_MAX_MAX_ACK_DELAY,
[TPI_ACTIVE_CONNECTION_ID_LIMIT] = VINT_MAX_VALUE, [TPI_ACTIVE_CONNECTION_ID_LIMIT] = VINT_MAX_VALUE,
}; [TPI_LOSS_BITS] = 1,
#define TP_OFF(name_) ((uint64_t *) &((struct transport_params *) 0 \
)->tp_numerics_u.s.name_ - (uint64_t *) &((struct transport_params *) \
0)->tp_numerics_u.s)
/* Map enum transport_params to index of tp_numerics_u.a; for numeric values only */
static const unsigned tpi2idx[MAX_TPI + 1] =
{
[TPI_MAX_PACKET_SIZE] = TP_OFF(max_packet_size),
[TPI_ACK_DELAY_EXPONENT] = TP_OFF(ack_delay_exponent),
[TPI_INIT_MAX_STREAMS_UNI] = TP_OFF(init_max_streams_uni),
[TPI_INIT_MAX_STREAMS_BIDI] = TP_OFF(init_max_streams_bidi),
[TPI_INIT_MAX_DATA] = TP_OFF(init_max_data),
[TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL] = TP_OFF(init_max_stream_data_bidi_local),
[TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE] = TP_OFF(init_max_stream_data_bidi_remote),
[TPI_INIT_MAX_STREAM_DATA_UNI] = TP_OFF(init_max_stream_data_uni),
[TPI_MAX_IDLE_TIMEOUT] = TP_OFF(max_idle_timeout),
[TPI_MAX_ACK_DELAY] = TP_OFF(max_ack_delay),
[TPI_ACTIVE_CONNECTION_ID_LIMIT] = TP_OFF(active_connection_id_limit),
}; };
@ -93,54 +151,78 @@ preferred_address_size (const struct transport_params *params)
int int
lsquic_tp_encode (const struct transport_params *params, lsquic_tp_has_pref_ipv4 (const struct transport_params *params)
{
return (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
&& params->tp_preferred_address.ipv4_port
&& !lsquic_is_zero(params->tp_preferred_address.ipv4_addr,
sizeof(params->tp_preferred_address.ipv4_addr));
}
int
lsquic_tp_has_pref_ipv6 (const struct transport_params *params)
{
return (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
&& params->tp_preferred_address.ipv6_port
&& !lsquic_is_zero(params->tp_preferred_address.ipv6_addr,
sizeof(params->tp_preferred_address.ipv6_addr));
}
int
lsquic_tp_encode (const struct transport_params *params, int is_server,
unsigned char *const buf, size_t bufsz) unsigned char *const buf, size_t bufsz)
{ {
unsigned char *p; unsigned char *p;
size_t need = 2; size_t need = 2;
uint16_t u16; uint16_t u16;
enum transport_param_id tpi; enum transport_param_id tpi;
unsigned bits[MAX_TPI + 1]; unsigned set;
unsigned bits[MAX_NUMERIC_TPI + 1];
if (params->tp_flags & TRAPA_SERVER) set = params->tp_set; /* Will turn bits off for default values */
if (is_server)
{ {
if (params->tp_flags & TRAPA_ORIGINAL_CID) if (set & (1 << TPI_ORIGINAL_CONNECTION_ID))
need += 4 + params->tp_original_cid.len; need += 4 + params->tp_original_cid.len;
if (params->tp_flags & TRAPA_RESET_TOKEN) if (set & (1 << TPI_STATELESS_RESET_TOKEN))
need += 4 + sizeof(params->tp_stateless_reset_token); need += 4 + sizeof(params->tp_stateless_reset_token);
if (params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6)) if (set & (1 << TPI_PREFERRED_ADDRESS))
need += 4 + preferred_address_size(params); need += 4 + preferred_address_size(params);
} }
#if LSQUIC_TEST_QUANTUM_READINESS #if LSQUIC_TEST_QUANTUM_READINESS
else if (params->tp_flags & TRAPA_QUANTUM_READY) else if (set & (1 << TPI_QUANTUM_READINESS))
need += 4 + QUANTUM_READY_SZ; need += 4 + QUANTUM_READY_SZ;
#endif #endif
for (tpi = 0; tpi <= MAX_TPI; ++tpi) for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
if ((NUMERIC_TRANS_PARAMS & (1 << tpi)) if (set & (1 << tpi))
&& params->tp_numerics_u.a[tpi2idx[tpi]] != def_vals[tpi])
{ {
if (params->tp_numerics_u.a[tpi2idx[tpi]] < max_vals[tpi]) if (tpi > MAX_NUM_WITH_DEF_TPI
|| params->tp_numerics[tpi] != def_vals[tpi])
{ {
bits[tpi] = vint_val2bits(params->tp_numerics_u.a[tpi2idx[tpi]]); if (params->tp_numerics[tpi] <= max_vals[tpi])
need += 4 + (1 << bits[tpi]); {
bits[tpi] = vint_val2bits(params->tp_numerics[tpi]);
need += 4 + (1 << bits[tpi]);
}
else
{
LSQ_DEBUG("numeric value is too large (%"PRIu64" vs maximum "
"of %"PRIu64")", params->tp_numerics[tpi],
max_vals[tpi]);
return -1;
}
} }
else else
{ set &= ~(1 << tpi); /* Don't write default value */
LSQ_DEBUG("numeric value is too large (%"PRIu64" vs maximum "
"of %"PRIu64")", params->tp_numerics_u.a[tpi2idx[tpi]],
max_vals[tpi]);
return -1;
}
} }
if (params->tp_disable_active_migration != TP_DEF_DISABLE_ACTIVE_MIGRATION) for (; tpi <= MAX_EMPTY_TPI; ++tpi)
need += 4 + 0; if (set & (1 << tpi))
need += 4 + 0;
if (params->tp_flags & TRAPA_QL_BITS_OLD)
need += 4 + 0;
else if (params->tp_flags & TRAPA_QL_BITS)
need += 4 + 1;
if (need > bufsz || need > UINT16_MAX) if (need > bufsz || need > UINT16_MAX)
{ {
@ -178,110 +260,65 @@ lsquic_tp_encode (const struct transport_params *params,
WRITE_UINT_TO_P(need - 2 + buf - p, 16); WRITE_UINT_TO_P(need - 2 + buf - p, 16);
for (tpi = 0; tpi <= MAX_TPI; ++tpi) for (tpi = 0; tpi <= LAST_TPI; ++tpi)
if (NUMERIC_TRANS_PARAMS & (1 << tpi)) if (set & (1 << tpi))
{ {
if (params->tp_numerics_u.a[tpi2idx[tpi]] != def_vals[tpi]) WRITE_UINT_TO_P(enum_2_tpi_val[tpi], 16);
{
WRITE_UINT_TO_P(tpi, 16);
WRITE_UINT_TO_P(1 << bits[tpi], 16);
vint_write(p, params->tp_numerics_u.a[tpi2idx[tpi]], bits[tpi],
1 << bits[tpi]);
p += 1 << bits[tpi];
}
}
else
switch (tpi) switch (tpi)
{ {
case TPI_MAX_IDLE_TIMEOUT:
case TPI_MAX_PACKET_SIZE:
case TPI_INIT_MAX_DATA:
case TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL:
case TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE:
case TPI_INIT_MAX_STREAM_DATA_UNI:
case TPI_INIT_MAX_STREAMS_BIDI:
case TPI_INIT_MAX_STREAMS_UNI:
case TPI_ACK_DELAY_EXPONENT:
case TPI_MAX_ACK_DELAY:
case TPI_ACTIVE_CONNECTION_ID_LIMIT:
case TPI_LOSS_BITS:
WRITE_UINT_TO_P(1 << bits[tpi], 16);
vint_write(p, params->tp_numerics[tpi], bits[tpi],
1 << bits[tpi]);
p += 1 << bits[tpi];
break;
case TPI_ORIGINAL_CONNECTION_ID: case TPI_ORIGINAL_CONNECTION_ID:
if (params->tp_flags & TRAPA_ORIGINAL_CID) WRITE_UINT_TO_P(params->tp_original_cid.len, 16);
{ WRITE_TO_P(params->tp_original_cid.idbuf,
WRITE_UINT_TO_P(TPI_ORIGINAL_CONNECTION_ID, 16); params->tp_original_cid.len);
WRITE_UINT_TO_P(params->tp_original_cid.len, 16);
WRITE_TO_P(params->tp_original_cid.idbuf,
params->tp_original_cid.len);
}
break; break;
case TPI_STATELESS_RESET_TOKEN: case TPI_STATELESS_RESET_TOKEN:
if (params->tp_flags & TRAPA_RESET_TOKEN) WRITE_UINT_TO_P(sizeof(params->tp_stateless_reset_token), 16);
{ WRITE_TO_P(params->tp_stateless_reset_token,
WRITE_UINT_TO_P(TPI_STATELESS_RESET_TOKEN, 16); sizeof(params->tp_stateless_reset_token));
WRITE_UINT_TO_P(sizeof(params->tp_stateless_reset_token),
16);
WRITE_TO_P(params->tp_stateless_reset_token,
sizeof(params->tp_stateless_reset_token));
}
break; break;
case TPI_PREFERRED_ADDRESS: case TPI_PREFERRED_ADDRESS:
if (params->tp_flags WRITE_UINT_TO_P(preferred_address_size(params), 16);
& (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6)) WRITE_TO_P(&params->tp_preferred_address.ipv4_addr,
{ sizeof(params->tp_preferred_address.ipv4_addr));
WRITE_UINT_TO_P(TPI_PREFERRED_ADDRESS, 16); WRITE_UINT_TO_P(params->tp_preferred_address.ipv4_port, 16);
WRITE_UINT_TO_P(preferred_address_size(params), 16); WRITE_TO_P(&params->tp_preferred_address.ipv6_addr,
if (params->tp_flags & TRAPA_PREFADDR_IPv4) sizeof(params->tp_preferred_address.ipv6_addr));
{ WRITE_UINT_TO_P(params->tp_preferred_address.ipv6_port, 16);
WRITE_TO_P(&params->tp_preferred_address.ipv4_addr, *p++ = params->tp_preferred_address.cid.len;
sizeof(params->tp_preferred_address.ipv4_addr)); WRITE_TO_P(params->tp_preferred_address.cid.idbuf,
WRITE_UINT_TO_P(params->tp_preferred_address.ipv4_port, params->tp_preferred_address.cid.len);
16); WRITE_TO_P(params->tp_preferred_address.srst,
} sizeof(params->tp_preferred_address.srst));
else
{
memset(p, 0, 6);
p += 6;
}
if (params->tp_flags & TRAPA_PREFADDR_IPv6)
{
WRITE_TO_P(&params->tp_preferred_address.ipv6_addr,
sizeof(params->tp_preferred_address.ipv6_addr));
WRITE_UINT_TO_P(params->tp_preferred_address.ipv6_port,
16);
}
else
{
memset(p, 0, 18);
p += 18;
}
*p++ = params->tp_preferred_address.cid.len;
WRITE_TO_P(params->tp_preferred_address.cid.idbuf,
params->tp_preferred_address.cid.len);
WRITE_TO_P(params->tp_preferred_address.srst,
sizeof(params->tp_preferred_address.srst));
}
break; break;
case TPI_DISABLE_ACTIVE_MIGRATION: case TPI_DISABLE_ACTIVE_MIGRATION:
if (params->tp_disable_active_migration != TP_DEF_DISABLE_ACTIVE_MIGRATION) WRITE_UINT_TO_P(0, 16);
{
WRITE_UINT_TO_P(TPI_DISABLE_ACTIVE_MIGRATION, 16);
WRITE_UINT_TO_P(0, 16);
}
break; break;
default:
assert(0);
return -1;
}
if (params->tp_flags & TRAPA_QL_BITS_OLD)
{
WRITE_UINT_TO_P(TPI_QL_BITS, 16);
WRITE_UINT_TO_P(0, 16);
}
else if (params->tp_flags & TRAPA_QL_BITS)
{
WRITE_UINT_TO_P(TPI_QL_BITS, 16);
WRITE_UINT_TO_P(1, 16);
*p++ = !!params->tp_loss_bits;
}
#if LSQUIC_TEST_QUANTUM_READINESS #if LSQUIC_TEST_QUANTUM_READINESS
if (params->tp_flags & TRAPA_QUANTUM_READY) case TPI_QUANTUM_READINESS:
{ WRITE_UINT_TO_P(QUANTUM_READY_SZ, 16);
WRITE_UINT_TO_P(TPI_QUANTUM_READINESS, 16); memset(p, 'Q', QUANTUM_READY_SZ);
WRITE_UINT_TO_P(QUANTUM_READY_SZ, 16); p += QUANTUM_READY_SZ;
memset(p, 'Q', QUANTUM_READY_SZ); break;
p += QUANTUM_READY_SZ;
}
#endif #endif
}
}
assert(buf + need == p); assert(buf + need == p);
return (int) (p - buf); return (int) (p - buf);
@ -298,18 +335,15 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
{ {
const unsigned char *p, *end, *q; const unsigned char *p, *end, *q;
uint16_t len, param_id, tlen; uint16_t len, param_id, tlen;
enum transport_param_id tpi;
unsigned set_of_ids; unsigned set_of_ids;
int s; int s;
uint64_t tmp64;
p = buf; p = buf;
end = buf + bufsz; end = buf + bufsz;
*params = TP_INITIALIZER(); *params = TP_INITIALIZER();
if (is_server)
params->tp_flags |= TRAPA_SERVER;
if (end - p < 2) if (end - p < 2)
return -1; return -1;
READ_UINT(len, 16, p, 2); READ_UINT(len, 16, p, 2);
@ -337,43 +371,43 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
p += 2; p += 2;
if (len > end - p) if (len > end - p)
return -1; return -1;
/* If we need to support parameter IDs 31 and up, we will need to tpi = tpi_val_2_enum(param_id);
* change this code: if (tpi <= LAST_TPI)
*/
if (param_id < sizeof(set_of_ids) * 8)
{ {
/* Only check duplicates for IDs <= 31: all standard parameters if (set_of_ids & (1 << tpi))
* fit in a bitmask 32 bits wide.
*/
if (set_of_ids & (1 << param_id))
return -1; return -1;
set_of_ids |= 1 << param_id; set_of_ids |= 1 << tpi;
} }
else switch (tpi)
goto gt32;
if (NUMERIC_TRANS_PARAMS & (1u << param_id))
{ {
case TPI_MAX_IDLE_TIMEOUT:
case TPI_MAX_PACKET_SIZE:
case TPI_INIT_MAX_DATA:
case TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL:
case TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE:
case TPI_INIT_MAX_STREAM_DATA_UNI:
case TPI_INIT_MAX_STREAMS_BIDI:
case TPI_INIT_MAX_STREAMS_UNI:
case TPI_ACK_DELAY_EXPONENT:
case TPI_MAX_ACK_DELAY:
case TPI_ACTIVE_CONNECTION_ID_LIMIT:
case TPI_LOSS_BITS:
switch (len) switch (len)
{ {
case 1: case 1:
case 2: case 2:
case 4: case 4:
case 8: case 8:
s = vint_read(p, p + len, s = vint_read(p, p + len, &params->tp_numerics[tpi]);
&params->tp_numerics_u.a[tpi2idx[param_id]]);
if (s == len) if (s == len)
{ {
if (params->tp_numerics_u.a[tpi2idx[param_id]] if (params->tp_numerics[tpi] > max_vals[tpi])
> max_vals[param_id])
{ {
LSQ_DEBUG("numeric value of parameter 0x%X is too " LSQ_DEBUG("numeric value of parameter 0x%X is too "
"large (%"PRIu64" vs maximum of %"PRIu64, "large (%"PRIu64" vs maximum of %"PRIu64,
param_id, param_id, params->tp_numerics[tpi], max_vals[tpi]);
params->tp_numerics_u.a[tpi2idx[param_id]],
max_vals[param_id]);
return -1; return -1;
} }
p += s;
break; break;
} }
else else
@ -383,125 +417,85 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
return -1; return -1;
} }
default: default:
LSQ_DEBUG("invalid length=%u for numeric transport parameter", LSQ_DEBUG("invalid length=%u for numeric transport "
len); "parameter 0x%X", len, param_id);
return -1; return -1;
} }
} break;
else case TPI_DISABLE_ACTIVE_MIGRATION:
{ EXPECT_LEN(0);
gt32: switch (param_id) break;
case TPI_STATELESS_RESET_TOKEN:
/* Client MUST not include reset token,
* see [draft-ietf-quic-transport-11], Section 6.4.1
*/
if (!is_server)
return -1;
EXPECT_LEN(sizeof(params->tp_stateless_reset_token));
memcpy(params->tp_stateless_reset_token, p,
sizeof(params->tp_stateless_reset_token));
break;
case TPI_ORIGINAL_CONNECTION_ID:
/* Client MUST not original connecti ID,
* see [draft-ietf-quic-transport-15], Section 6.6.1
*/
if (!is_server)
return -1;
if (len > MAX_CID_LEN)
return -1;
memcpy(params->tp_original_cid.idbuf, p, len);
params->tp_original_cid.len = len;
break;
case TPI_PREFERRED_ADDRESS:
/* Client MUST not include preferred address,
* see [draft-ietf-quic-transport-12], Section 6.4.1
*/
if (!is_server)
return -1;
q = p;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_addr));
memcpy(params->tp_preferred_address.ipv4_addr, q,
sizeof(params->tp_preferred_address.ipv4_addr));
q += sizeof(params->tp_preferred_address.ipv4_addr);
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_port));
READ_UINT(params->tp_preferred_address.ipv4_port, 16, q, 2);
q += 2;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_addr));
memcpy(params->tp_preferred_address.ipv6_addr, q,
sizeof(params->tp_preferred_address.ipv6_addr));
q += sizeof(params->tp_preferred_address.ipv6_addr);
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_port));
READ_UINT(params->tp_preferred_address.ipv6_port, 16, q, 2);
q += 2;
EXPECT_AT_LEAST(1);
tlen = *q;
q += 1;
if (tlen < 4 || tlen > MAX_CID_LEN)
{ {
case TPI_DISABLE_ACTIVE_MIGRATION: LSQ_DEBUG("preferred server address contains invalid "
EXPECT_LEN(0); "CID length of %"PRIu16" bytes", tlen);
params->tp_disable_active_migration = 1; return -1;
break;
case TPI_STATELESS_RESET_TOKEN:
/* Client MUST not include reset token,
* see [draft-ietf-quic-transport-11], Section 6.4.1
*/
if (!is_server)
return -1;
EXPECT_LEN(sizeof(params->tp_stateless_reset_token));
memcpy(params->tp_stateless_reset_token, p,
sizeof(params->tp_stateless_reset_token));
params->tp_flags |= TRAPA_RESET_TOKEN;
break;
case TPI_ORIGINAL_CONNECTION_ID:
/* Client MUST not original connecti ID,
* see [draft-ietf-quic-transport-15], Section 6.6.1
*/
if (!is_server)
return -1;
if (len > MAX_CID_LEN)
return -1;
memcpy(params->tp_original_cid.idbuf, p, len);
params->tp_original_cid.len = len;
params->tp_flags |= TRAPA_ORIGINAL_CID;
break;
case TPI_PREFERRED_ADDRESS:
/* Client MUST not include preferred address,
* see [draft-ietf-quic-transport-12], Section 6.4.1
*/
if (!is_server)
return -1;
q = p;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_addr));
memcpy(params->tp_preferred_address.ipv4_addr, q,
sizeof(params->tp_preferred_address.ipv4_addr));
q += sizeof(params->tp_preferred_address.ipv4_addr);
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_port));
READ_UINT(params->tp_preferred_address.ipv4_port, 16, q, 2);
q += 2;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_addr));
memcpy(params->tp_preferred_address.ipv6_addr, q,
sizeof(params->tp_preferred_address.ipv6_addr));
q += sizeof(params->tp_preferred_address.ipv6_addr);
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_port));
READ_UINT(params->tp_preferred_address.ipv6_port, 16, q, 2);
q += 2;
EXPECT_AT_LEAST(1);
tlen = *q;
q += 1;
if (tlen < 4 || tlen > MAX_CID_LEN)
{
LSQ_DEBUG("preferred server address contains invalid "
"CID length of %"PRIu16" bytes", tlen);
return -1;
}
EXPECT_AT_LEAST(tlen);
memcpy(params->tp_preferred_address.cid.idbuf, q, tlen);
params->tp_preferred_address.cid.len = tlen;
q += tlen;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.srst));
memcpy(params->tp_preferred_address.srst, q,
sizeof(params->tp_preferred_address.srst));
q += sizeof(params->tp_preferred_address.srst);
if (q != p + len)
return -1;
if (params->tp_preferred_address.ipv4_port
&& !lsquic_is_zero(params->tp_preferred_address.ipv4_addr,
sizeof(params->tp_preferred_address.ipv4_addr)))
params->tp_flags |= TRAPA_PREFADDR_IPv4;
if (params->tp_preferred_address.ipv6_port
&& !lsquic_is_zero(params->tp_preferred_address.ipv6_addr,
sizeof(params->tp_preferred_address.ipv6_addr)))
params->tp_flags |= TRAPA_PREFADDR_IPv6;
break;
case TPI_QL_BITS:
switch (len)
{
case 0:
/* Old-school boolean */
params->tp_flags |= TRAPA_QL_BITS;
params->tp_loss_bits = 1;
break;
case 1:
case 2:
case 4:
case 8:
s = vint_read(p, p + len, &tmp64);
if (s != len)
{
LSQ_DEBUG("cannot read the value of numeric transport "
"param loss_bits of length %u", len);
return -1;
}
if (!(tmp64 == 0 || tmp64 == 1))
{
LSQ_DEBUG("unexpected value of loss_bits TP: %"PRIu64,
tmp64);
return -1;
}
params->tp_loss_bits = tmp64;
params->tp_flags |= TRAPA_QL_BITS;
break;
default:
return -1;
}
break;
} }
p += len; EXPECT_AT_LEAST(tlen);
memcpy(params->tp_preferred_address.cid.idbuf, q, tlen);
params->tp_preferred_address.cid.len = tlen;
q += tlen;
EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.srst));
memcpy(params->tp_preferred_address.srst, q,
sizeof(params->tp_preferred_address.srst));
q += sizeof(params->tp_preferred_address.srst);
if (q != p + len)
return -1;
break;
default:
/* Do nothing: skip this transport parameter */
break;
}
p += len;
if (tpi <= LAST_TPI)
{
params->tp_set |= 1 << tpi;
params->tp_decoded |= 1 << tpi;
} }
} }
@ -518,32 +512,40 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
{ {
char *const end = buf + sz; char *const end = buf + sz;
int nw; int nw;
enum transport_param_id tpi;
char tok_str[sizeof(params->tp_stateless_reset_token) * 2 + 1]; char tok_str[sizeof(params->tp_stateless_reset_token) * 2 + 1];
char addr_str[INET6_ADDRSTRLEN]; char addr_str[INET6_ADDRSTRLEN];
#define SEMICOLON "; " for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
#define WRITE_ONE_PARAM(name, fmt) do { \ if (params->tp_set & (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL))
nw = snprintf(buf, end - buf, #name ": " fmt SEMICOLON, params->tp_##name); \ {
buf += nw; \ nw = snprintf(buf, end - buf, "%.*s%s: %"PRIu64,
if (buf >= end) \ (buf + sz > end) << 1, "; ", tpi2str[tpi],
return; \ params->tp_numerics[tpi]);
} while (0) buf += nw;
if (buf >= end)
WRITE_ONE_PARAM(init_max_stream_data_bidi_local, "%"PRIu64); return;
WRITE_ONE_PARAM(init_max_stream_data_bidi_remote, "%"PRIu64); }
WRITE_ONE_PARAM(init_max_stream_data_uni, "%"PRIu64); for (; tpi <= MAX_EMPTY_TPI; ++tpi)
WRITE_ONE_PARAM(init_max_data, "%"PRIu64); if (params->tp_set & (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL))
WRITE_ONE_PARAM(max_idle_timeout, "%"PRIu64); {
WRITE_ONE_PARAM(init_max_streams_bidi, "%"PRIu64); nw = snprintf(buf, end - buf, "%.*s%s",
WRITE_ONE_PARAM(init_max_streams_uni, "%"PRIu64); (buf + sz > end) << 1, "; ", tpi2str[tpi]);
WRITE_ONE_PARAM(max_packet_size, "%"PRIu64); buf += nw;
WRITE_ONE_PARAM(ack_delay_exponent, "%"PRIu64); if (buf >= end)
WRITE_ONE_PARAM(active_connection_id_limit, "%"PRIu64); return;
WRITE_ONE_PARAM(disable_active_migration, "%hhd"); }
#undef SEMICOLON #if LSQUIC_TEST_QUANTUM_READINESS
#define SEMICOLON "" if (params->tp_set & (1 << TPI_QUANTUM_READINESS))
WRITE_ONE_PARAM(max_ack_delay, "%"PRIu64); {
if (params->tp_flags & TRAPA_RESET_TOKEN) nw = snprintf(buf, end - buf, "%.*s%s",
(buf + sz > end) << 1, "; ", tpi2str[TPI_QUANTUM_READINESS]);
buf += nw;
if (buf >= end)
return;
}
#endif
if (params->tp_set & (1 << TPI_STATELESS_RESET_TOKEN))
{ {
lsquic_hexstr(params->tp_stateless_reset_token, lsquic_hexstr(params->tp_stateless_reset_token,
sizeof(params->tp_stateless_reset_token), tok_str, sizeof(tok_str)); sizeof(params->tp_stateless_reset_token), tok_str, sizeof(tok_str));
@ -552,7 +554,7 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
if (buf >= end) if (buf >= end)
return; return;
} }
if (params->tp_flags & TRAPA_RESET_TOKEN) if (params->tp_set & (1 << TPI_ORIGINAL_CONNECTION_ID))
{ {
char cidbuf_[MAX_CID_LEN * 2 + 1]; char cidbuf_[MAX_CID_LEN * 2 + 1];
nw = snprintf(buf, end - buf, "; original DCID (ODCID): %"CID_FMT, nw = snprintf(buf, end - buf, "; original DCID (ODCID): %"CID_FMT,
@ -561,7 +563,7 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
if (buf >= end) if (buf >= end)
return; return;
} }
if (params->tp_flags & TRAPA_PREFADDR_IPv4) if (lsquic_tp_has_pref_ipv4(params))
{ {
if (inet_ntop(AF_INET, params->tp_preferred_address.ipv4_addr, if (inet_ntop(AF_INET, params->tp_preferred_address.ipv4_addr,
addr_str, sizeof(addr_str))) addr_str, sizeof(addr_str)))
@ -573,7 +575,7 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
return; return;
} }
} }
if (params->tp_flags & TRAPA_PREFADDR_IPv6) if (lsquic_tp_has_pref_ipv6(params))
{ {
if (inet_ntop(AF_INET6, params->tp_preferred_address.ipv6_addr, if (inet_ntop(AF_INET6, params->tp_preferred_address.ipv6_addr,
addr_str, sizeof(addr_str))) addr_str, sizeof(addr_str)))
@ -585,15 +587,4 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
return; return;
} }
} }
if (params->tp_flags & TRAPA_QL_BITS)
{
nw = snprintf(buf, end - buf, "; QL loss bits: %hhu",
params->tp_loss_bits);
buf += nw;
if (buf >= end)
return;
}
#undef SEMICOLON
#undef WRITE_ONE_PARAM
} }

View file

@ -6,98 +6,76 @@
#ifndef LSQUIC_TRANS_PARAMS_H #ifndef LSQUIC_TRANS_PARAMS_H
#define LSQUIC_TRANS_PARAMS_H 1 #define LSQUIC_TRANS_PARAMS_H 1
/* [draft-ietf-quic-transport-17], Section 18 */ /* Transport parameters are grouped by the type of their values: numeric,
* empty, and custom.
*
* The enum values are arbitrary. The literal transport parameter ID
* *values* (e.g. 0x1057 for loss bits) are not exposed by the API.
*/
enum transport_param_id enum transport_param_id
{ {
TPI_ORIGINAL_CONNECTION_ID = 0, /*
TPI_MAX_IDLE_TIMEOUT = 1, * Numeric transport parameters that have default values:
TPI_STATELESS_RESET_TOKEN = 2, */
TPI_MAX_PACKET_SIZE = 3, TPI_MAX_IDLE_TIMEOUT,
TPI_INIT_MAX_DATA = 4, TPI_MAX_PACKET_SIZE,
TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL = 5, TPI_INIT_MAX_DATA,
TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE = 6, TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL,
TPI_INIT_MAX_STREAM_DATA_UNI = 7, TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE,
TPI_INIT_MAX_STREAMS_BIDI = 8, TPI_INIT_MAX_STREAM_DATA_UNI,
TPI_INIT_MAX_STREAMS_UNI = 9, TPI_INIT_MAX_STREAMS_BIDI,
TPI_ACK_DELAY_EXPONENT = 10, TPI_INIT_MAX_STREAMS_UNI,
TPI_MAX_ACK_DELAY = 11, TPI_ACK_DELAY_EXPONENT,
TPI_DISABLE_ACTIVE_MIGRATION = 12, TPI_MAX_ACK_DELAY,
TPI_PREFERRED_ADDRESS = 13, TPI_ACTIVE_CONNECTION_ID_LIMIT, MAX_NUM_WITH_DEF_TPI = TPI_ACTIVE_CONNECTION_ID_LIMIT,
TPI_ACTIVE_CONNECTION_ID_LIMIT = 14,
#define MAX_TPI TPI_ACTIVE_CONNECTION_ID_LIMIT
};
#define NUMERIC_TRANS_PARAMS (\ /*
(1 << TPI_MAX_PACKET_SIZE) \ * Numeric transport parameters without default values:
|(1 << TPI_INIT_MAX_STREAMS_UNI) \ */
|(1 << TPI_INIT_MAX_STREAMS_UNI) \ TPI_LOSS_BITS, MAX_NUMERIC_TPI = TPI_LOSS_BITS,
|(1 << TPI_INIT_MAX_STREAMS_BIDI) \
|(1 << TPI_INIT_MAX_DATA) \
|(1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL) \
|(1 << TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE) \
|(1 << TPI_INIT_MAX_STREAM_DATA_UNI) \
|(1 << TPI_MAX_IDLE_TIMEOUT) \
|(1 << TPI_MAX_ACK_DELAY) \
|(1 << TPI_ACK_DELAY_EXPONENT) \
|(1 << TPI_ACTIVE_CONNECTION_ID_LIMIT) \
)
#define IQUIC_MAX_SUPP_VERS ((2<<7) - 4)/sizeof(uint32_t) /*
* Empty transport parameters:
*/
TPI_DISABLE_ACTIVE_MIGRATION, MAX_EMPTY_TPI = TPI_DISABLE_ACTIVE_MIGRATION,
enum trapa_flags /*
{ * Custom handlers:
TRAPA_RESET_TOKEN = 1 << 0, /* Reset token is set */ */
TRAPA_SERVER = 1 << 1, /* Server transport parameters */ TPI_PREFERRED_ADDRESS,
TRAPA_PREFADDR_IPv4 = 1 << 2, /* Preferred IPv4 address is set */ TPI_ORIGINAL_CONNECTION_ID,
TRAPA_PREFADDR_IPv6 = 1 << 3, /* Preferred IPv6 address is set */
TRAPA_ORIGINAL_CID = 1 << 4, /* Original CID is set */
#if LSQUIC_TEST_QUANTUM_READINESS #if LSQUIC_TEST_QUANTUM_READINESS
#define QUANTUM_READY_SZ 1200
/* https://github.com/quicwg/base-drafts/wiki/Quantum-Readiness-test */ /* https://github.com/quicwg/base-drafts/wiki/Quantum-Readiness-test */
#define TPI_QUANTUM_READINESS 3127 #define QUANTUM_READY_SZ 1200
TRAPA_QUANTUM_READY = 1 << 5, /* Include "Quantum Readiness" TP */ TPI_QUANTUM_READINESS,
#endif #endif
#define TPI_QL_BITS 0x1057 /* 1057 is 133t for "lost" */ TPI_STATELESS_RESET_TOKEN, LAST_TPI = TPI_STATELESS_RESET_TOKEN
TRAPA_QL_BITS = 1 << 6, /* tp_loss_bits contains valid value */
TRAPA_QL_BITS_OLD = 1 << 7, /* Send old-school boolean loss_bits TP.
* Not set on decoded transport parameters.
*/
}; };
struct transport_params struct transport_params
{ {
enum trapa_flags tp_flags; /* Which transport parameters values are set: */
unsigned tp_set;
union { /* Which transport parameters were present (set by the decoder): */
struct { unsigned tp_decoded;
uint64_t init_max_stream_data_bidi_local;
uint64_t init_max_stream_data_bidi_remote; uint64_t tp_numerics[MAX_NUMERIC_TPI + 1];
uint64_t init_max_stream_data_uni;
uint64_t init_max_data; #define tp_init_max_stream_data_bidi_local tp_numerics[TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL]
uint64_t max_idle_timeout; #define tp_init_max_stream_data_bidi_remote tp_numerics[TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE]
uint64_t init_max_streams_bidi; #define tp_init_max_stream_data_uni tp_numerics[TPI_INIT_MAX_STREAM_DATA_UNI]
uint64_t init_max_streams_uni; #define tp_init_max_data tp_numerics[TPI_INIT_MAX_DATA]
uint64_t max_packet_size; #define tp_max_idle_timeout tp_numerics[TPI_MAX_IDLE_TIMEOUT]
uint64_t ack_delay_exponent; #define tp_init_max_streams_bidi tp_numerics[TPI_INIT_MAX_STREAMS_BIDI]
uint64_t max_ack_delay; #define tp_init_max_streams_uni tp_numerics[TPI_INIT_MAX_STREAMS_UNI]
uint64_t active_connection_id_limit; #define tp_max_packet_size tp_numerics[TPI_MAX_PACKET_SIZE]
} s; #define tp_ack_delay_exponent tp_numerics[TPI_ACK_DELAY_EXPONENT]
uint64_t a[11]; #define tp_max_ack_delay tp_numerics[TPI_MAX_ACK_DELAY]
} tp_numerics_u; #define tp_active_connection_id_limit tp_numerics[TPI_ACTIVE_CONNECTION_ID_LIMIT]
#define tp_init_max_stream_data_bidi_local tp_numerics_u.s.init_max_stream_data_bidi_local #define tp_loss_bits tp_numerics[TPI_LOSS_BITS]
#define tp_init_max_stream_data_bidi_remote tp_numerics_u.s.init_max_stream_data_bidi_remote
#define tp_init_max_stream_data_uni tp_numerics_u.s.init_max_stream_data_uni
#define tp_init_max_data tp_numerics_u.s.init_max_data
#define tp_max_idle_timeout tp_numerics_u.s.max_idle_timeout
#define tp_init_max_streams_bidi tp_numerics_u.s.init_max_streams_bidi
#define tp_init_max_streams_uni tp_numerics_u.s.init_max_streams_uni
#define tp_max_packet_size tp_numerics_u.s.max_packet_size
#define tp_ack_delay_exponent tp_numerics_u.s.ack_delay_exponent
#define tp_max_ack_delay tp_numerics_u.s.max_ack_delay
#define tp_active_connection_id_limit tp_numerics_u.s.active_connection_id_limit
unsigned char tp_loss_bits; /* Valid values 0, 1. Set if TRAPA_QL_BITS is set. */
signed char tp_disable_active_migration;
uint8_t tp_stateless_reset_token[IQUIC_SRESET_TOKEN_SZ]; uint8_t tp_stateless_reset_token[IQUIC_SRESET_TOKEN_SZ];
struct { struct {
uint8_t ipv4_addr[4]; uint8_t ipv4_addr[4];
@ -127,6 +105,7 @@ struct transport_params
#define TP_MAX_MAX_ACK_DELAY ((1u << 14) - 1) #define TP_MAX_MAX_ACK_DELAY ((1u << 14) - 1)
#define TP_DEFAULT_VALUES \ #define TP_DEFAULT_VALUES \
.tp_set = ((1 << (MAX_NUM_WITH_DEF_TPI + 1)) - 1), \
.tp_active_connection_id_limit = TP_DEF_ACTIVE_CONNECTION_ID_LIMIT, \ .tp_active_connection_id_limit = TP_DEF_ACTIVE_CONNECTION_ID_LIMIT, \
.tp_max_idle_timeout = TP_DEF_MAX_IDLE_TIMEOUT, \ .tp_max_idle_timeout = TP_DEF_MAX_IDLE_TIMEOUT, \
.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY, \ .tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY, \
@ -135,7 +114,6 @@ struct transport_params
.tp_init_max_streams_bidi = TP_DEF_INIT_MAX_STREAMS_BIDI, \ .tp_init_max_streams_bidi = TP_DEF_INIT_MAX_STREAMS_BIDI, \
.tp_init_max_streams_uni = TP_DEF_INIT_MAX_STREAMS_UNI, \ .tp_init_max_streams_uni = TP_DEF_INIT_MAX_STREAMS_UNI, \
.tp_init_max_data = TP_DEF_INIT_MAX_DATA, \ .tp_init_max_data = TP_DEF_INIT_MAX_DATA, \
.tp_disable_active_migration = TP_DEF_DISABLE_ACTIVE_MIGRATION, \
.tp_init_max_stream_data_bidi_local = TP_DEF_INIT_MAX_STREAM_DATA_BIDI_LOCAL, \ .tp_init_max_stream_data_bidi_local = TP_DEF_INIT_MAX_STREAM_DATA_BIDI_LOCAL, \
.tp_init_max_stream_data_bidi_remote = TP_DEF_INIT_MAX_STREAM_DATA_BIDI_REMOTE, \ .tp_init_max_stream_data_bidi_remote = TP_DEF_INIT_MAX_STREAM_DATA_BIDI_REMOTE, \
.tp_init_max_stream_data_uni = TP_DEF_INIT_MAX_STREAM_DATA_UNI .tp_init_max_stream_data_uni = TP_DEF_INIT_MAX_STREAM_DATA_UNI
@ -143,7 +121,7 @@ struct transport_params
#define TP_INITIALIZER() (struct transport_params) { TP_DEFAULT_VALUES } #define TP_INITIALIZER() (struct transport_params) { TP_DEFAULT_VALUES }
int int
lsquic_tp_encode (const struct transport_params *, lsquic_tp_encode (const struct transport_params *, int is_server,
unsigned char *buf, size_t bufsz); unsigned char *buf, size_t bufsz);
int int
@ -158,4 +136,10 @@ lsquic_tp_decode (const unsigned char *buf, size_t bufsz,
void void
lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz); lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz);
int
lsquic_tp_has_pref_ipv4 (const struct transport_params *);
int
lsquic_tp_has_pref_ipv6 (const struct transport_params *);
#endif #endif

View file

@ -29,6 +29,8 @@ struct trapa_test
} flags; } flags;
struct transport_params params; struct transport_params params;
size_t enc_len, dec_len; size_t enc_len, dec_len;
unsigned addl_set;
int is_server;
int expect_decode_err; int expect_decode_err;
unsigned char encoded[ENC_BUF_SZ]; unsigned char encoded[ENC_BUF_SZ];
}; };
@ -53,13 +55,20 @@ static const struct trapa_test tests[] =
.line = __LINE__, .line = __LINE__,
.flags = TEST_ENCODE | TEST_DECODE, .flags = TEST_ENCODE | TEST_DECODE,
.params = { .params = {
.tp_flags = 0, .tp_set = (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL)
| (1 << TPI_INIT_MAX_DATA)
| (1 << TPI_MAX_IDLE_TIMEOUT)
| (1 << TPI_MAX_ACK_DELAY)
| (1 << TPI_MAX_PACKET_SIZE)
| (1 << TPI_ACK_DELAY_EXPONENT)
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT),
.tp_init_max_stream_data_bidi_local = 0x12348877, .tp_init_max_stream_data_bidi_local = 0x12348877,
.tp_init_max_data = 0xAABB, .tp_init_max_data = 0xAABB,
.tp_max_idle_timeout = 10 * 1000, .tp_max_idle_timeout = 10 * 1000,
.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY, .tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY,
.tp_active_connection_id_limit = 7, .tp_active_connection_id_limit = 7,
}, },
.is_server = 0,
.enc_len = 39, .enc_len = 39,
.encoded = .encoded =
/* Overall length */ "\x00\x25" /* Overall length */ "\x00\x25"
@ -94,12 +103,12 @@ static const struct trapa_test tests[] =
.flags = TEST_ENCODE | TEST_DECODE, .flags = TEST_ENCODE | TEST_DECODE,
.params = { .params = {
TP_DEFAULT_VALUES, TP_DEFAULT_VALUES,
.tp_flags = TRAPA_SERVER,
.tp_init_max_data = 0x123456, .tp_init_max_data = 0x123456,
.tp_init_max_stream_data_bidi_local = 0xABCDEF88, .tp_init_max_stream_data_bidi_local = 0xABCDEF88,
.tp_disable_active_migration = 1,
.tp_max_packet_size = 0x333, .tp_max_packet_size = 0x333,
}, },
.is_server = 1,
.addl_set = 1 << TPI_DISABLE_ACTIVE_MIGRATION,
.enc_len = 32, .enc_len = 32,
.encoded = .encoded =
/* Overall length */ "\x00\x1E" /* Overall length */ "\x00\x1E"
@ -117,7 +126,6 @@ static const struct trapa_test tests[] =
.flags = TEST_DECODE, .flags = TEST_DECODE,
.params = { .params = {
TP_DEFAULT_VALUES, TP_DEFAULT_VALUES,
.tp_flags = TRAPA_SERVER | TRAPA_PREFADDR_IPv4 | TRAPA_PREFADDR_IPv6,
.tp_max_ack_delay = 25, .tp_max_ack_delay = 25,
.tp_max_packet_size = 0x333, .tp_max_packet_size = 0x333,
.tp_preferred_address = { .tp_preferred_address = {
@ -129,6 +137,8 @@ static const struct trapa_test tests[] =
.srst = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F", .srst = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F",
}, },
}, },
.is_server = 1,
.addl_set = 1 << TPI_PREFERRED_ADDRESS,
.enc_len = 0x3E + 2, .enc_len = 0x3E + 2,
.encoded = .encoded =
/* Overall length */ "\x00\x3E" /* Overall length */ "\x00\x3E"
@ -154,9 +164,8 @@ params_are_equal (const struct transport_params *a,
const struct transport_params *b) const struct transport_params *b)
{ {
#define MCMP(f) 0 == memcmp(&a->f, &b->f, sizeof(a->f)) #define MCMP(f) 0 == memcmp(&a->f, &b->f, sizeof(a->f))
return a->tp_flags == b->tp_flags return MCMP(tp_numerics)
&& MCMP(tp_numerics_u) && MCMP(tp_set)
&& a->tp_disable_active_migration == b->tp_disable_active_migration
&& MCMP(tp_stateless_reset_token) && MCMP(tp_stateless_reset_token)
&& MCMP(tp_preferred_address.ipv4_addr) && MCMP(tp_preferred_address.ipv4_addr)
&& MCMP(tp_preferred_address.ipv6_addr) && MCMP(tp_preferred_address.ipv6_addr)
@ -175,14 +184,18 @@ params_are_equal (const struct transport_params *a,
static void static void
run_test (const struct trapa_test *test) run_test (const struct trapa_test *test)
{ {
struct transport_params source_params;
struct transport_params decoded_params; struct transport_params decoded_params;
size_t dec_len; size_t dec_len;
int s; int s;
unsigned char buf[ENC_BUF_SZ]; unsigned char buf[ENC_BUF_SZ];
source_params = test->params;
source_params.tp_set |= test->addl_set;
if (test->flags & TEST_ENCODE) if (test->flags & TEST_ENCODE)
{ {
s = lsquic_tp_encode(&test->params, buf, sizeof(buf)); s = lsquic_tp_encode(&source_params, test->is_server, buf, sizeof(buf));
assert(s > 0); assert(s > 0);
assert((size_t) s == test->enc_len); assert((size_t) s == test->enc_len);
assert(0 == memcmp(test->encoded, buf, s)); assert(0 == memcmp(test->encoded, buf, s));
@ -195,12 +208,16 @@ run_test (const struct trapa_test *test)
else else
dec_len = sizeof(buf); dec_len = sizeof(buf);
s = lsquic_tp_decode(test->encoded, dec_len, s = lsquic_tp_decode(test->encoded, dec_len,
test->params.tp_flags & TRAPA_SERVER, &decoded_params); test->is_server, &decoded_params);
if (!test->expect_decode_err) if (!test->expect_decode_err)
{ {
assert(s > 0); assert(s > 0);
assert((size_t) s == test->enc_len); assert((size_t) s == test->enc_len);
s = params_are_equal(&test->params, &decoded_params); /* The decoder initializes all default values, so set the flag
* accordingly:
*/
source_params.tp_set |= ((1 << (MAX_NUM_WITH_DEF_TPI + 1)) - 1);
s = params_are_equal(&source_params, &decoded_params);
assert(s); assert(s);
} }
else else