mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 4.0.0
This commit is contained in:
parent
b373fe5220
commit
79880b469a
47 changed files with 2459 additions and 606 deletions
|
@ -1,3 +1,11 @@
|
|||
2023-03-14
|
||||
- 4.0.0
|
||||
- Add support for QUICv2 (RFC9369).
|
||||
- Add support for version negotiation (RFC9368).
|
||||
- Retry packet for address validation.
|
||||
- Improve handshake under high packet loss/corruption.
|
||||
- Improve QUIC interop results
|
||||
|
||||
2023-01-26
|
||||
- 3.3.1
|
||||
- Fix blocked header encoding stream due to connection flow control congestion.
|
||||
|
|
26
README.md
26
README.md
|
@ -14,9 +14,31 @@ and HTTP/3 functionality for servers and clients. Most of the code in this
|
|||
distribution is used in our own products: LiteSpeed Web Server, LiteSpeed ADC,
|
||||
and OpenLiteSpeed.
|
||||
|
||||
Currently supported QUIC versions are v1, Internet-Draft versions 29, and 27;
|
||||
Currently supported QUIC versions are v1, v2, Internet-Draft versions 29, and 27;
|
||||
and the older "Google" QUIC versions Q043, Q046, an Q050.
|
||||
|
||||
Standard Compliance
|
||||
-------------------
|
||||
|
||||
LiteSpeed QUIC is mostly compliant to the follow RFCs:
|
||||
|
||||
- [RFC 9000](https://www.rfc-editor.org/rfc/rfc9000)
|
||||
- [RFC 9001](https://www.rfc-editor.org/rfc/rfc9001)
|
||||
- [RFC 9002](https://www.rfc-editor.org/rfc/rfc9002)
|
||||
- [RFC 9114](https://www.rfc-editor.org/rfc/rfc9114)
|
||||
- [RFC 9204](https://www.rfc-editor.org/rfc/rfc9204)
|
||||
|
||||
QUIC protocol extensions
|
||||
------------------------
|
||||
|
||||
The following QUIC protocol extensions are implemented:
|
||||
|
||||
- [QUIC Version 2](https://www.rfc-editor.org/authors/rfc9369.html)
|
||||
- [Compatible Version Negotiation](https://datatracker.ietf.org/doc/draft-ietf-quic-version-negotiation/)
|
||||
- [Datagrams](https://datatracker.ietf.org/doc/html/rfc9221)`
|
||||
- [ACK Frequency](https://datatracker.ietf.org/doc/draft-ietf-quic-ack-frequency/)
|
||||
- [Greasing the QUIC Bit](https://datatracker.ietf.org/doc/html/rfc9287)
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
|
@ -136,7 +158,7 @@ docker build -t lsquic .
|
|||
|
||||
Then you can use the examples from the command line. For example:
|
||||
```
|
||||
sudo docker run -it --rm lsquic http_client -s www.google.com -p / -o version=h3-29
|
||||
sudo docker run -it --rm lsquic http_client -s www.google.com -p / -o version=h3
|
||||
sudo docker run -p 12345:12345/udp -v /path/to/certs:/mnt/certs -it --rm lsquic http_server -c www.example.com,/mnt/certs/chain,/mnt/certs/key
|
||||
```
|
||||
|
||||
|
|
|
@ -804,7 +804,7 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
|
|||
#ifndef WIN32
|
||||
int flags;
|
||||
#endif
|
||||
SOCKOPT_VAL on;
|
||||
SOCKOPT_VAL on = 1;
|
||||
socklen_t socklen;
|
||||
char addr_str[0x20];
|
||||
|
||||
|
@ -828,6 +828,14 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
|
|||
if (-1 == sockfd)
|
||||
return -1;
|
||||
|
||||
if (AF_INET6 == sa_local->sa_family
|
||||
&& setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
CHAR_CAST &on, sizeof(on)) == -1)
|
||||
{
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 != bind(sockfd, sa_local, socklen)) {
|
||||
saved_errno = errno;
|
||||
LSQ_WARN("bind failed: %s", strerror(errno));
|
||||
|
@ -977,9 +985,21 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
|
|||
#if ECN_SUPPORTED
|
||||
on = 1;
|
||||
if (AF_INET == sa_local->sa_family)
|
||||
s = setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS, CHAR_CAST &on, sizeof(on));
|
||||
{
|
||||
s = setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS,
|
||||
CHAR_CAST &on, sizeof(on));
|
||||
if (!s)
|
||||
s = setsockopt(sockfd, IPPROTO_IP, IP_TOS,
|
||||
CHAR_CAST &on, sizeof(on));
|
||||
}
|
||||
else
|
||||
s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVTCLASS, CHAR_CAST &on, sizeof(on));
|
||||
{
|
||||
s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVTCLASS,
|
||||
CHAR_CAST &on, sizeof(on));
|
||||
if (!s)
|
||||
s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_TCLASS,
|
||||
CHAR_CAST &on, sizeof(on));
|
||||
}
|
||||
if (0 != s)
|
||||
{
|
||||
saved_errno = errno;
|
||||
|
@ -987,6 +1007,8 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
|
|||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
LSQ_DEBUG("server ECN support is enabled.");
|
||||
|
||||
#endif
|
||||
|
||||
if (sport->sp_flags & SPORT_SET_SNDBUF)
|
||||
|
@ -1177,11 +1199,21 @@ sport_init_client (struct service_port *sport, struct lsquic_engine *engine,
|
|||
{
|
||||
int on = 1;
|
||||
if (AF_INET == sa_local->sa_family)
|
||||
{
|
||||
s = setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS,
|
||||
CHAR_CAST &on, sizeof(on));
|
||||
CHAR_CAST &on, sizeof(on));
|
||||
if (!s)
|
||||
s = setsockopt(sockfd, IPPROTO_IP, IP_TOS,
|
||||
CHAR_CAST &on, sizeof(on));
|
||||
}
|
||||
else
|
||||
{
|
||||
s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVTCLASS,
|
||||
CHAR_CAST &on, sizeof(on));
|
||||
CHAR_CAST &on, sizeof(on));
|
||||
if (!s)
|
||||
s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_TCLASS,
|
||||
CHAR_CAST &on, sizeof(on));
|
||||
}
|
||||
if (0 != s)
|
||||
{
|
||||
saved_errno = errno;
|
||||
|
@ -1189,6 +1221,7 @@ sport_init_client (struct service_port *sport, struct lsquic_engine *engine,
|
|||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
LSQ_DEBUG("client ECN support is enabled.");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1796,6 +1829,11 @@ set_engine_option (struct lsquic_engine_settings *settings,
|
|||
settings->es_spin = atoi(val);
|
||||
return 0;
|
||||
}
|
||||
if (0 == strncmp(name, "srej", 4))
|
||||
{
|
||||
settings->es_support_srej = atoi(val);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (0 == strncmp(name, "version", 7))
|
||||
|
@ -1933,6 +1971,11 @@ set_engine_option (struct lsquic_engine_settings *settings,
|
|||
settings->es_handshake_to = atoi(val);
|
||||
return 0;
|
||||
}
|
||||
if (0 == strncmp(name, "support_srej", 12))
|
||||
{
|
||||
settings->es_support_srej = atoi(val);
|
||||
return 0;
|
||||
}
|
||||
if (0 == strncmp(name, "delayed_acks", 12))
|
||||
{
|
||||
settings->es_delayed_acks = atoi(val);
|
||||
|
|
|
@ -24,9 +24,9 @@ copyright = u'2023, LiteSpeed Technologies'
|
|||
author = u'LiteSpeed Technologies'
|
||||
|
||||
# The short X.Y version
|
||||
version = u'3.3'
|
||||
version = u'4.0'
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = u'3.3.1'
|
||||
release = u'4.0.0'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
|
|
@ -25,9 +25,9 @@ struct sockaddr;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LSQUIC_MAJOR_VERSION 3
|
||||
#define LSQUIC_MINOR_VERSION 3
|
||||
#define LSQUIC_PATCH_VERSION 1
|
||||
#define LSQUIC_MAJOR_VERSION 4
|
||||
#define LSQUIC_MINOR_VERSION 0
|
||||
#define LSQUIC_PATCH_VERSION 0
|
||||
|
||||
/**
|
||||
* Engine flags:
|
||||
|
@ -82,12 +82,23 @@ enum lsquic_version
|
|||
LSQVER_I001,
|
||||
|
||||
/**
|
||||
* Special version to trigger version negotiation.
|
||||
* [draft-ietf-quic-transport-11], Section 3.
|
||||
* IETF QUIC v2.
|
||||
*/
|
||||
LSQVER_VERNEG,
|
||||
LSQVER_I002,
|
||||
|
||||
N_LSQVER
|
||||
/**
|
||||
* Reserved version to trigger version negotiation.
|
||||
* [rfc9000], Section 15.
|
||||
*/
|
||||
LSQVER_RESVED,
|
||||
|
||||
N_LSQVER,
|
||||
|
||||
/**
|
||||
* The version 0x00000000 is reserved to represent version negotiation.
|
||||
* [rfc9000], Section 15.
|
||||
*/
|
||||
LSQVER_VERNEG
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -103,19 +114,19 @@ enum lsquic_version
|
|||
#define LSQUIC_FORCED_TCID0_VERSIONS ((1 << LSQVER_046)|(1 << LSQVER_050))
|
||||
|
||||
#define LSQUIC_EXPERIMENTAL_VERSIONS ( \
|
||||
(1 << LSQVER_VERNEG))
|
||||
(1 << LSQVER_RESVED))
|
||||
|
||||
#define LSQUIC_DEPRECATED_VERSIONS ((1 << LSQVER_ID27))
|
||||
|
||||
#define LSQUIC_GQUIC_HEADER_VERSIONS (1 << LSQVER_043)
|
||||
|
||||
#define LSQUIC_IETF_VERSIONS ((1 << LSQVER_ID27) \
|
||||
| (1 << LSQVER_ID29) \
|
||||
| (1 << LSQVER_I001) | (1 << LSQVER_VERNEG))
|
||||
| (1 << LSQVER_ID29) | (1 << LSQVER_I001) \
|
||||
| (1 << LSQVER_I002) | (1 << LSQVER_RESVED))
|
||||
|
||||
#define LSQUIC_IETF_DRAFT_VERSIONS ((1 << LSQVER_ID27) \
|
||||
| (1 << LSQVER_ID29) \
|
||||
| (1 << LSQVER_VERNEG))
|
||||
| (1 << LSQVER_RESVED))
|
||||
|
||||
enum lsquic_hsk_status
|
||||
{
|
||||
|
@ -306,6 +317,10 @@ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)(
|
|||
|
||||
#define LSQUIC_DF_STTL 86400
|
||||
#define LSQUIC_DF_MAX_INCHOATE (1 * 1000 * 1000)
|
||||
|
||||
#define LSQUIC_DF_SUPPORT_SREJ_SERVER 0
|
||||
#define LSQUIC_DF_SUPPORT_SREJ_CLIENT 0
|
||||
|
||||
/** Do not use NSTP by default */
|
||||
#define LSQUIC_DF_SUPPORT_NSTP 0
|
||||
/** TODO: IETF QUIC clients do not support push */
|
||||
|
@ -355,6 +370,9 @@ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)(
|
|||
/** Allow migration by default */
|
||||
#define LSQUIC_DF_ALLOW_MIGRATION 1
|
||||
|
||||
/** Default retry token duration. */ /* Do not set this value to zero. */
|
||||
#define LSQUIC_DF_RETRY_TOKEN_DURATION 10
|
||||
|
||||
/** Use QL loss bits by default */
|
||||
#define LSQUIC_DF_QL_BITS 2
|
||||
|
||||
|
@ -544,6 +562,17 @@ struct lsquic_engine_settings {
|
|||
*/
|
||||
unsigned es_max_inchoate;
|
||||
|
||||
/**
|
||||
* Support SREJ: for client side, this means supporting server's SREJ
|
||||
* responses (this does not work yet) and for server side, this means
|
||||
* generating SREJ instead of REJ when appropriate.
|
||||
*
|
||||
* For IETF QUIC, this sending stateless retries when appropriate.
|
||||
* The IETF client always supports stateless retries and knows how to
|
||||
* handle them.
|
||||
*/
|
||||
int es_support_srej;
|
||||
|
||||
/**
|
||||
* Setting this value to 0 means that
|
||||
*
|
||||
|
@ -863,6 +892,13 @@ struct lsquic_engine_settings {
|
|||
*/
|
||||
int es_allow_migration;
|
||||
|
||||
/**
|
||||
* Amount of time, in seconds, after which the server token included in
|
||||
* a stateless retry expires. If set to zero, the default value is
|
||||
* used, which is @ref LSQUIC_DF_RETRY_TOKEN_DURATION
|
||||
*/
|
||||
unsigned es_retry_token_duration;
|
||||
|
||||
/**
|
||||
* Use QL loss bits. Allowed values are:
|
||||
* 0: Do not use loss bits
|
||||
|
|
|
@ -40,7 +40,7 @@ enum lsquic_conn_flags {
|
|||
LSCONN_HASHED = (1 << 2),
|
||||
LSCONN_MINI = (1 << 3), /* This is a mini connection */
|
||||
LSCONN_IMMED_CLOSE = (1 << 4),
|
||||
LSCONN_UNUSED_5 = (1 << 5),
|
||||
LSCONN_PROMOTE_FAIL = (1 << 5),
|
||||
LSCONN_HANDSHAKE_DONE = (1 << 6),
|
||||
LSCONN_CLOSING = (1 << 7),
|
||||
LSCONN_PEER_GOING_AWAY= (1 << 8),
|
||||
|
@ -60,6 +60,8 @@ enum lsquic_conn_flags {
|
|||
LSCONN_SERVER = (1 <<22),
|
||||
LSCONN_IETF = (1 <<23),
|
||||
LSCONN_RETRY_CONN = (1 <<24), /* This is a retry connection */
|
||||
LSCONN_VER_UPDATED = (1 <<25),
|
||||
LSCONN_NO_BL = (1 <<26),
|
||||
};
|
||||
|
||||
/* A connection may have things to send and be closed at the same time.
|
||||
|
@ -68,6 +70,7 @@ enum tick_st {
|
|||
TICK_SEND = (1 << 0),
|
||||
TICK_CLOSE = (1 << 1),
|
||||
TICK_PROMOTE = (1 << 2), /* Promote mini connection to full connection */
|
||||
TICK_RETRY = (1 << 3), /* Send retry packet -- used by mini conns */
|
||||
};
|
||||
|
||||
#define TICK_QUIET 0
|
||||
|
|
|
@ -39,10 +39,10 @@ enum lsquic_version;
|
|||
/* This enum maps to the list above */
|
||||
enum enc_level
|
||||
{
|
||||
ENC_LEV_CLEAR,
|
||||
ENC_LEV_EARLY,
|
||||
ENC_LEV_INIT,
|
||||
ENC_LEV_FORW,
|
||||
ENC_LEV_0RTT,
|
||||
ENC_LEV_HSK,
|
||||
ENC_LEV_APP,
|
||||
N_ENC_LEVS
|
||||
};
|
||||
|
||||
|
@ -300,7 +300,9 @@ struct enc_session_funcs_iquic
|
|||
void *(crypto_streams)[4],
|
||||
const struct crypto_stream_if *,
|
||||
const struct lsquic_cid *odcid,
|
||||
const struct lsquic_cid *iscid);
|
||||
const struct lsquic_cid *iscid,
|
||||
const struct lsquic_cid *rscid
|
||||
);
|
||||
|
||||
void
|
||||
(*esfi_shake_stream)(enc_session_t *, struct lsquic_stream *,
|
||||
|
@ -340,10 +342,7 @@ struct enc_session_funcs_gquic lsquic_enc_session_gquic_gquic_1;
|
|||
LSQUIC_EXTERN const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1;
|
||||
|
||||
#define select_esf_common_by_ver(ver) ( \
|
||||
ver == LSQVER_ID27 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_ID29 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_I001 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_VERNEG ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver > LSQVER_050 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_050 ? &lsquic_enc_session_common_gquic_2 : \
|
||||
&lsquic_enc_session_common_gquic_1 )
|
||||
|
||||
|
@ -376,4 +375,16 @@ lsquic_enc_sess_ietf_gen_quic_ctx (
|
|||
const struct lsquic_engine_settings *settings,
|
||||
enum lsquic_version version, unsigned char *buf, size_t bufsz);
|
||||
|
||||
struct enc_sess_iquic;
|
||||
int
|
||||
iquic_esfi_init_server_tp (struct enc_sess_iquic *const enc_sess);
|
||||
|
||||
int
|
||||
iquic_esfi_switch_version (enc_session_t *enc_session_p, lsquic_cid_t *dcid,
|
||||
int backup_keys);
|
||||
|
||||
int
|
||||
iquic_esf_is_enc_level_ready (enc_session_t *enc_session_p,
|
||||
enum enc_level level);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
|
||||
const char *const lsquic_enclev2str[] =
|
||||
{
|
||||
[ENC_LEV_EARLY] = "early",
|
||||
[ENC_LEV_CLEAR] = "clear",
|
||||
[ENC_LEV_INIT] = "initial",
|
||||
[ENC_LEV_FORW] = "forw-secure",
|
||||
[ENC_LEV_0RTT] = "0RTT",
|
||||
[ENC_LEV_INIT] = "INIT",
|
||||
[ENC_LEV_HSK] = "HSK",
|
||||
[ENC_LEV_APP] = "APP",
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -58,13 +58,6 @@
|
|||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(enc_sess->esi_conn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
#define KEY_LABEL "quic key"
|
||||
#define KEY_LABEL_SZ (sizeof(KEY_LABEL) - 1)
|
||||
#define IV_LABEL "quic iv"
|
||||
#define IV_LABEL_SZ (sizeof(IV_LABEL) - 1)
|
||||
#define PN_LABEL "quic hp"
|
||||
#define PN_LABEL_SZ (sizeof(PN_LABEL) - 1)
|
||||
|
||||
#define N_HSK_PAIRS (N_ENC_LEVS - 1)
|
||||
|
||||
static const struct alpn_map {
|
||||
|
@ -74,7 +67,8 @@ static const struct alpn_map {
|
|||
{ LSQVER_ID27, (unsigned char *) "\x05h3-27", },
|
||||
{ LSQVER_ID29, (unsigned char *) "\x05h3-29", },
|
||||
{ LSQVER_I001, (unsigned char *) "\x02h3", },
|
||||
{ LSQVER_VERNEG, (unsigned char *) "\x02h3", },
|
||||
{ LSQVER_I002, (unsigned char *) "\x02h3", },
|
||||
{ LSQVER_RESVED, (unsigned char *) "\x02h3", },
|
||||
};
|
||||
|
||||
struct enc_sess_iquic;
|
||||
|
@ -159,11 +153,36 @@ struct crypto_ctx_pair
|
|||
};
|
||||
|
||||
|
||||
struct hsk_crypto
|
||||
{
|
||||
struct crypto_ctx_pair pair;
|
||||
struct header_prot hp;
|
||||
};
|
||||
|
||||
|
||||
struct label_set
|
||||
{
|
||||
const char *key;
|
||||
const char *iv;
|
||||
const char *hp;
|
||||
int key_len;
|
||||
int iv_len;
|
||||
int hp_len;
|
||||
};
|
||||
|
||||
static struct label_set hkdf_labels[2] =
|
||||
{
|
||||
{ "quic key", "quic iv", "quic hp", 8, 7, 7 },
|
||||
{ "quicv2 key", "quicv2 iv", "quicv2 hp", 10, 9, 9 }
|
||||
};
|
||||
|
||||
|
||||
/* [draft-ietf-quic-tls-12] Section 5.3.6 */
|
||||
static int
|
||||
init_crypto_ctx (struct crypto_ctx *crypto_ctx, const EVP_MD *md,
|
||||
const EVP_AEAD *aead, const unsigned char *secret,
|
||||
size_t secret_sz, enum evp_aead_direction_t dir)
|
||||
size_t secret_sz, enum evp_aead_direction_t dir,
|
||||
struct label_set *key_iv)
|
||||
{
|
||||
crypto_ctx->yk_key_sz = EVP_AEAD_key_length(aead);
|
||||
crypto_ctx->yk_iv_sz = EVP_AEAD_nonce_length(aead);
|
||||
|
@ -174,9 +193,9 @@ init_crypto_ctx (struct crypto_ctx *crypto_ctx, const EVP_MD *md,
|
|||
return -1;
|
||||
}
|
||||
|
||||
lsquic_qhkdf_expand(md, secret, secret_sz, KEY_LABEL, KEY_LABEL_SZ,
|
||||
lsquic_qhkdf_expand(md, secret, secret_sz, key_iv->key, key_iv->key_len,
|
||||
crypto_ctx->yk_key_buf, crypto_ctx->yk_key_sz);
|
||||
lsquic_qhkdf_expand(md, secret, secret_sz, IV_LABEL, IV_LABEL_SZ,
|
||||
lsquic_qhkdf_expand(md, secret, secret_sz, key_iv->iv, key_iv->iv_len,
|
||||
crypto_ctx->yk_iv_buf, crypto_ctx->yk_iv_sz);
|
||||
if (!EVP_AEAD_CTX_init_with_direction(&crypto_ctx->yk_aead_ctx, aead,
|
||||
crypto_ctx->yk_key_buf, crypto_ctx->yk_key_sz, IQUIC_TAG_LEN, dir))
|
||||
|
@ -216,13 +235,9 @@ struct enc_sess_iquic
|
|||
struct header_prot esi_hp;
|
||||
struct crypto_ctx_pair
|
||||
esi_pairs[2];
|
||||
/* These are used during handshake. There are three of them.
|
||||
* esi_hsk_pairs and esi_hsk_hps are allocated and freed
|
||||
* together.
|
||||
*/
|
||||
struct crypto_ctx_pair *
|
||||
esi_hsk_pairs;
|
||||
struct header_prot *esi_hsk_hps;
|
||||
/* These are used during handshake. There are three of them. */
|
||||
struct hsk_crypto *esi_hsk_crypto;
|
||||
struct hsk_crypto *esi_vn_save;
|
||||
lsquic_packno_t esi_max_packno[N_PNS];
|
||||
lsquic_cid_t esi_odcid;
|
||||
lsquic_cid_t esi_rscid; /* Retry SCID */
|
||||
|
@ -250,6 +265,7 @@ struct enc_sess_iquic
|
|||
ESI_MAX_PACKNO_HSK = ESI_MAX_PACKNO_INIT << PNS_HSK,
|
||||
ESI_MAX_PACKNO_APP = ESI_MAX_PACKNO_INIT << PNS_APP,
|
||||
ESI_HAVE_0RTT_TP = 1 << 20,
|
||||
ESI_SWITCH_VER = 1 << 21,
|
||||
} esi_flags;
|
||||
enum enc_level esi_last_w;
|
||||
unsigned esi_trasec_sz;
|
||||
|
@ -496,6 +512,20 @@ strip_hp (struct enc_sess_iquic *enc_sess,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
set_tp_version_info (struct transport_params *params,
|
||||
unsigned versions, enum lsquic_version ver)
|
||||
{
|
||||
assert(params->tp_version_cnt == 0);
|
||||
params->tp_version_info[params->tp_version_cnt++] = ver;
|
||||
if (versions & (1 << LSQVER_I002))
|
||||
params->tp_version_info[params->tp_version_cnt++] = LSQVER_I002;
|
||||
if (versions & (1 << LSQVER_I001))
|
||||
params->tp_version_info[params->tp_version_cnt++] = LSQVER_I001;
|
||||
params->tp_set |= 1 << TPI_VERSION_INFORMATION;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
|
||||
size_t bufsz)
|
||||
|
@ -525,6 +555,11 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
|
|||
params.tp_original_dest_cid = enc_sess->esi_odcid;
|
||||
params.tp_set |= 1 << TPI_ORIGINAL_DEST_CID;
|
||||
}
|
||||
if (enc_sess->esi_flags & ESI_RSCID)
|
||||
{
|
||||
params.tp_retry_source_cid = enc_sess->esi_rscid;
|
||||
params.tp_set |= 1 << TPI_RETRY_SOURCE_CID;
|
||||
}
|
||||
#if LSQUIC_PREFERRED_ADDR
|
||||
char addr_buf[INET6_ADDRSTRLEN + 6 /* port */ + 1];
|
||||
const char *s, *colon;
|
||||
|
@ -661,6 +696,14 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
|
|||
params.tp_set |= 1 << TPI_MAX_DATAGRAM_FRAME_SIZE;
|
||||
}
|
||||
|
||||
if (enc_sess->esi_ver_neg && enc_sess->esi_ver_neg->vn_supp
|
||||
!= (1u << enc_sess->esi_ver_neg->vn_ver))
|
||||
set_tp_version_info(¶ms, enc_sess->esi_ver_neg->vn_supp,
|
||||
enc_sess->esi_ver_neg->vn_ver);
|
||||
else if (enc_sess->esi_conn->cn_flags & LSCONN_VER_UPDATED)
|
||||
set_tp_version_info(¶ms, settings->es_versions,
|
||||
enc_sess->esi_conn->cn_version);
|
||||
|
||||
len = (version == LSQVER_ID27 ? lsquic_tp_encode_27 : lsquic_tp_encode)(
|
||||
¶ms, enc_sess->esi_flags & ESI_SERVER, buf, bufsz);
|
||||
if (len >= 0)
|
||||
|
@ -1018,7 +1061,8 @@ iquic_esfi_create_server (struct lsquic_engine_public *enpub,
|
|||
void *(crypto_streams)[4],
|
||||
const struct crypto_stream_if *cryst_if,
|
||||
const struct lsquic_cid *odcid,
|
||||
const struct lsquic_cid *iscid)
|
||||
const struct lsquic_cid *iscid,
|
||||
const struct lsquic_cid *rscid)
|
||||
{
|
||||
struct enc_sess_iquic *enc_sess;
|
||||
|
||||
|
@ -1042,6 +1086,11 @@ iquic_esfi_create_server (struct lsquic_engine_public *enpub,
|
|||
enc_sess->esi_odcid = *odcid;
|
||||
enc_sess->esi_flags |= ESI_ODCID;
|
||||
}
|
||||
if (rscid)
|
||||
{
|
||||
enc_sess->esi_rscid = *rscid;
|
||||
enc_sess->esi_flags |= ESI_RSCID;
|
||||
}
|
||||
enc_sess->esi_iscid = *iscid;
|
||||
enc_sess->esi_flags |= ESI_ISCID;
|
||||
|
||||
|
@ -1099,6 +1148,18 @@ log_crypto_pair (const struct enc_sess_iquic *enc_sess,
|
|||
}
|
||||
|
||||
|
||||
static const unsigned char *const lsquic_ver2salt[N_LSQVER] = {
|
||||
[LSQVER_043] = HSK_SALT_PRE29,
|
||||
[LSQVER_046] = HSK_SALT_PRE29,
|
||||
[LSQVER_050] = HSK_SALT_PRE29,
|
||||
[LSQVER_ID27] = HSK_SALT_PRE29,
|
||||
[LSQVER_ID29] = HSK_SALT_PRE33,
|
||||
[LSQVER_I001] = HSK_SALT,
|
||||
[LSQVER_I002] = HSK_SALT_V2,
|
||||
[LSQVER_RESVED] = HSK_SALT,
|
||||
};
|
||||
|
||||
|
||||
/* [draft-ietf-quic-tls-12] Section 5.3.2 */
|
||||
static int
|
||||
setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid)
|
||||
|
@ -1118,30 +1179,20 @@ setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid)
|
|||
unsigned char secret[2][SHA256_DIGEST_LENGTH]; /* client, server */
|
||||
unsigned char key[2][EVP_MAX_KEY_LENGTH];
|
||||
char hexbuf[EVP_MAX_MD_SIZE * 2 + 1];
|
||||
struct label_set *labels;
|
||||
|
||||
if (!enc_sess->esi_hsk_pairs)
|
||||
if (!enc_sess->esi_hsk_crypto)
|
||||
{
|
||||
enc_sess->esi_hsk_pairs = calloc(N_HSK_PAIRS,
|
||||
sizeof(enc_sess->esi_hsk_pairs[0]));
|
||||
enc_sess->esi_hsk_hps = calloc(N_HSK_PAIRS,
|
||||
sizeof(enc_sess->esi_hsk_hps[0]));
|
||||
if (!(enc_sess->esi_hsk_pairs && enc_sess->esi_hsk_hps))
|
||||
{
|
||||
free(enc_sess->esi_hsk_pairs);
|
||||
free(enc_sess->esi_hsk_hps);
|
||||
enc_sess->esi_hsk_crypto = calloc(N_HSK_PAIRS,
|
||||
sizeof(enc_sess->esi_hsk_crypto[0]));
|
||||
if (!enc_sess->esi_hsk_crypto)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
pair = &enc_sess->esi_hsk_pairs[ENC_LEV_CLEAR];
|
||||
pair = &enc_sess->esi_hsk_crypto[ENC_LEV_INIT].pair;
|
||||
pair->ykp_thresh = IQUIC_INVALID_PACKNO;
|
||||
hp = &enc_sess->esi_hsk_hps[ENC_LEV_CLEAR];
|
||||
hp = &enc_sess->esi_hsk_crypto[ENC_LEV_INIT].hp;
|
||||
|
||||
if (enc_sess->esi_conn->cn_version < LSQVER_ID29)
|
||||
salt = HSK_SALT_PRE29;
|
||||
else if (enc_sess->esi_conn->cn_version < LSQVER_I001)
|
||||
salt = HSK_SALT_PRE33;
|
||||
else
|
||||
salt = HSK_SALT;
|
||||
salt = lsquic_ver2salt[enc_sess->esi_conn->cn_version];
|
||||
HKDF_extract(hsk_secret, &hsk_secret_sz, md, cid->idbuf, cid->len,
|
||||
salt, HSK_SALT_SZ);
|
||||
if (enc_sess->esi_flags & ESI_LOG_SECRETS)
|
||||
|
@ -1163,21 +1214,22 @@ setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid)
|
|||
HEXSTR(secret[1], sizeof(secret[1]), hexbuf));
|
||||
}
|
||||
|
||||
labels = &hkdf_labels[enc_sess->esi_conn->cn_version == LSQVER_I002];
|
||||
cliser = !!(enc_sess->esi_flags & ESI_SERVER);
|
||||
if (0 != init_crypto_ctx(&pair->ykp_ctx[!cliser], md, aead, secret[0],
|
||||
sizeof(secret[0]), rw2dir(!cliser)))
|
||||
sizeof(secret[0]), rw2dir(!cliser), labels))
|
||||
goto err;
|
||||
if (0 != init_crypto_ctx(&pair->ykp_ctx[cliser], md, aead, secret[1],
|
||||
sizeof(secret[1]), rw2dir(cliser)))
|
||||
sizeof(secret[1]), rw2dir(cliser), labels))
|
||||
goto err;
|
||||
|
||||
hp->hp_gen_mask = gen_hp_mask_aes;
|
||||
hp->hp_enc_level = ENC_LEV_CLEAR;
|
||||
hp->hp_enc_level = ENC_LEV_INIT;
|
||||
key_len = EVP_AEAD_key_length(aead);
|
||||
lsquic_qhkdf_expand(md, secret[!cliser], sizeof(secret[0]), PN_LABEL,
|
||||
PN_LABEL_SZ, key[0], key_len);
|
||||
lsquic_qhkdf_expand(md, secret[cliser], sizeof(secret[0]), PN_LABEL,
|
||||
PN_LABEL_SZ, key[1], key_len);
|
||||
lsquic_qhkdf_expand(md, secret[!cliser], sizeof(secret[0]), labels->hp,
|
||||
labels->hp_len, key[0], key_len);
|
||||
lsquic_qhkdf_expand(md, secret[cliser], sizeof(secret[0]), labels->hp,
|
||||
labels->hp_len, key[1], key_len);
|
||||
if (enc_sess->esi_flags & ESI_LOG_SECRETS)
|
||||
{
|
||||
log_crypto_pair(enc_sess, pair, "handshake");
|
||||
|
@ -1217,30 +1269,43 @@ cleanup_hp (struct header_prot *hp)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
cleanup_hsk_crypto (struct hsk_crypto *c)
|
||||
{
|
||||
cleanup_crypto_ctx(&c->pair.ykp_ctx[0]);
|
||||
cleanup_crypto_ctx(&c->pair.ykp_ctx[1]);
|
||||
cleanup_hp(&c->hp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_vn_save (struct enc_sess_iquic *enc_sess)
|
||||
{
|
||||
if (enc_sess->esi_vn_save)
|
||||
{
|
||||
cleanup_hsk_crypto(enc_sess->esi_vn_save);
|
||||
free(enc_sess->esi_vn_save);
|
||||
enc_sess->esi_vn_save = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_handshake_keys (struct enc_sess_iquic *enc_sess)
|
||||
{
|
||||
struct crypto_ctx_pair *pair;
|
||||
unsigned i;
|
||||
struct hsk_crypto *c;
|
||||
|
||||
if (enc_sess->esi_hsk_pairs)
|
||||
if (enc_sess->esi_hsk_crypto)
|
||||
{
|
||||
assert(enc_sess->esi_hsk_hps);
|
||||
for (pair = enc_sess->esi_hsk_pairs; pair <
|
||||
enc_sess->esi_hsk_pairs + N_HSK_PAIRS; ++pair)
|
||||
for (c = enc_sess->esi_hsk_crypto; c <
|
||||
enc_sess->esi_hsk_crypto + N_HSK_PAIRS; ++c)
|
||||
{
|
||||
cleanup_crypto_ctx(&pair->ykp_ctx[0]);
|
||||
cleanup_crypto_ctx(&pair->ykp_ctx[1]);
|
||||
cleanup_hsk_crypto(c);
|
||||
}
|
||||
free(enc_sess->esi_hsk_pairs);
|
||||
enc_sess->esi_hsk_pairs = NULL;
|
||||
for (i = 0; i < N_HSK_PAIRS; ++i)
|
||||
cleanup_hp(&enc_sess->esi_hsk_hps[i]);
|
||||
free(enc_sess->esi_hsk_hps);
|
||||
enc_sess->esi_hsk_hps = NULL;
|
||||
free(enc_sess->esi_hsk_crypto);
|
||||
enc_sess->esi_hsk_crypto = NULL;
|
||||
}
|
||||
else
|
||||
assert(!enc_sess->esi_hsk_hps);
|
||||
free_vn_save(enc_sess);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1342,6 +1407,33 @@ iquic_esf_set_conn (enc_session_t *enc_session_p, struct lsquic_conn *lconn)
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
iquic_esfi_init_server_tp (struct enc_sess_iquic *const enc_sess)
|
||||
{
|
||||
unsigned char trans_params[sizeof(struct transport_params)
|
||||
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||
+ 4 + lsquic_tp_get_quantum_sz()
|
||||
#endif
|
||||
];
|
||||
int transpa_len;
|
||||
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
||||
transpa_len = gen_trans_params(enc_sess, trans_params,
|
||||
sizeof(trans_params));
|
||||
if (transpa_len < 0)
|
||||
return -1;
|
||||
|
||||
if (1 != SSL_set_quic_transport_params(enc_sess->esi_ssl, trans_params,
|
||||
transpa_len))
|
||||
{
|
||||
LSQ_ERROR("cannot set QUIC transport params: %s",
|
||||
ERR_error_string(ERR_get_error(), errbuf));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
iquic_esfi_init_server (enc_session_t *enc_session_p)
|
||||
{
|
||||
|
@ -1349,16 +1441,7 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
|
|||
struct network_path *path;
|
||||
const struct alpn_map *am;
|
||||
unsigned quic_ctx_idx;
|
||||
int transpa_len;
|
||||
SSL_CTX *ssl_ctx = NULL;
|
||||
union {
|
||||
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
||||
unsigned char trans_params[sizeof(struct transport_params)
|
||||
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||
+ 4 + lsquic_tp_get_quantum_sz()
|
||||
#endif
|
||||
];
|
||||
} u;
|
||||
|
||||
if (enc_sess->esi_enpub->enp_alpn)
|
||||
enc_sess->esi_alpn = enc_sess->esi_enpub->enp_alpn;
|
||||
|
@ -1388,8 +1471,9 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
|
|||
enc_sess->esi_ssl = SSL_new(ssl_ctx);
|
||||
if (!enc_sess->esi_ssl)
|
||||
{
|
||||
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
||||
LSQ_ERROR("cannot create SSL object: %s",
|
||||
ERR_error_string(ERR_get_error(), u.errbuf));
|
||||
ERR_error_string(ERR_get_error(), errbuf));
|
||||
return -1;
|
||||
}
|
||||
#if BORINGSSL_API_VERSION >= 13
|
||||
|
@ -1410,18 +1494,8 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
|
|||
return -1;
|
||||
}
|
||||
|
||||
transpa_len = gen_trans_params(enc_sess, u.trans_params,
|
||||
sizeof(u.trans_params));
|
||||
if (transpa_len < 0)
|
||||
return -1;
|
||||
|
||||
if (1 != SSL_set_quic_transport_params(enc_sess->esi_ssl, u.trans_params,
|
||||
transpa_len))
|
||||
{
|
||||
LSQ_ERROR("cannot set QUIC transport params: %s",
|
||||
ERR_error_string(ERR_get_error(), u.errbuf));
|
||||
return -1;
|
||||
}
|
||||
// if (iquic_esfi_init_server_tp(enc_sess) == -1)
|
||||
// return -1;
|
||||
|
||||
SSL_clear_options(enc_sess->esi_ssl, SSL_OP_NO_TLSv1_3);
|
||||
if (enc_sess->esi_enpub->enp_lookup_cert)
|
||||
|
@ -1786,6 +1860,7 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
|
|||
cidbuf[0]),
|
||||
CID_BITS_B(cids[TP_CID_IDX(tpi)], cidbuf[1]));
|
||||
}
|
||||
enc_sess->esi_conn->cn_flags |= LSCONN_NO_BL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -2026,30 +2101,46 @@ iquic_esfi_destroy (enc_session_t *enc_session_p)
|
|||
/* See [draft-ietf-quic-tls-14], Section 4 */
|
||||
static const enum enc_level hety2el[] =
|
||||
{
|
||||
[HETY_NOT_SET] = ENC_LEV_FORW,
|
||||
[HETY_SHORT] = ENC_LEV_APP,
|
||||
[HETY_VERNEG] = 0,
|
||||
[HETY_INITIAL] = ENC_LEV_CLEAR,
|
||||
[HETY_INITIAL] = ENC_LEV_INIT,
|
||||
[HETY_RETRY] = 0,
|
||||
[HETY_HANDSHAKE] = ENC_LEV_INIT,
|
||||
[HETY_0RTT] = ENC_LEV_EARLY,
|
||||
[HETY_HANDSHAKE] = ENC_LEV_HSK,
|
||||
[HETY_0RTT] = ENC_LEV_0RTT,
|
||||
};
|
||||
|
||||
|
||||
static const enum enc_level pns2enc_level[2][N_PNS] =
|
||||
{
|
||||
[0] = {
|
||||
[PNS_INIT] = ENC_LEV_CLEAR,
|
||||
[PNS_HSK] = ENC_LEV_INIT,
|
||||
[PNS_APP] = ENC_LEV_EARLY,
|
||||
[PNS_INIT] = ENC_LEV_INIT,
|
||||
[PNS_HSK] = ENC_LEV_HSK,
|
||||
[PNS_APP] = ENC_LEV_0RTT,
|
||||
},
|
||||
[1] = {
|
||||
[PNS_INIT] = ENC_LEV_CLEAR,
|
||||
[PNS_HSK] = ENC_LEV_INIT,
|
||||
[PNS_APP] = ENC_LEV_FORW,
|
||||
[PNS_INIT] = ENC_LEV_INIT,
|
||||
[PNS_HSK] = ENC_LEV_HSK,
|
||||
[PNS_APP] = ENC_LEV_APP,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
iquic_esf_is_enc_level_ready (enc_session_t *enc_session_p,
|
||||
enum enc_level level)
|
||||
{
|
||||
const struct enc_sess_iquic *enc_sess = enc_session_p;
|
||||
const struct header_prot *hp;
|
||||
if (level == ENC_LEV_APP)
|
||||
hp = &enc_sess->esi_hp;
|
||||
else if (enc_sess->esi_hsk_crypto)
|
||||
hp = &enc_sess->esi_hsk_crypto[level].hp;
|
||||
else
|
||||
return 0;
|
||||
return header_prot_inited(hp, 0);
|
||||
}
|
||||
|
||||
|
||||
static enum enc_packout
|
||||
iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
||||
const struct lsquic_engine_public *enpub, struct lsquic_conn *lconn_UNUSED,
|
||||
|
@ -2075,17 +2166,17 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
|||
pns = lsquic_packet_out_pns(packet_out);
|
||||
enc_level = pns2enc_level[ enc_sess->esi_have_forw ][ pns ];
|
||||
|
||||
if (enc_level == ENC_LEV_FORW)
|
||||
if (enc_level == ENC_LEV_APP)
|
||||
{
|
||||
pair = &enc_sess->esi_pairs[ enc_sess->esi_key_phase ];
|
||||
crypto_ctx = &pair->ykp_ctx[ 1 ];
|
||||
hp = &enc_sess->esi_hp;
|
||||
}
|
||||
else if (enc_sess->esi_hsk_pairs)
|
||||
else if (enc_sess->esi_hsk_crypto)
|
||||
{
|
||||
pair = &enc_sess->esi_hsk_pairs[ enc_level ];
|
||||
pair = &enc_sess->esi_hsk_crypto[ enc_level ].pair;
|
||||
crypto_ctx = &pair->ykp_ctx[ 1 ];
|
||||
hp = &enc_sess->esi_hsk_hps[ enc_level ];
|
||||
hp = &enc_sess->esi_hsk_crypto[ enc_level ].hp;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2146,7 +2237,7 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
|||
dst_sz, &packno_off, &packno_len);
|
||||
if (header_sz < 0)
|
||||
goto err;
|
||||
if (enc_level == ENC_LEV_FORW)
|
||||
if (enc_level == ENC_LEV_APP)
|
||||
dst[0] |= enc_sess->esi_key_phase << 2;
|
||||
dst[0] &= enc_sess->esi_grease | packet_out->po_path->np_dcid.idbuf[0];
|
||||
|
||||
|
@ -2183,7 +2274,7 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
|||
lsquic_packet_out_set_enc_level(packet_out, enc_level);
|
||||
lsquic_packet_out_set_kp(packet_out, enc_sess->esi_key_phase);
|
||||
|
||||
if (enc_level == ENC_LEV_FORW && hp->hp_gen_mask != gen_hp_mask_chacha20)
|
||||
if (enc_level == ENC_LEV_APP && hp->hp_gen_mask != gen_hp_mask_chacha20)
|
||||
apply_hp_batch(enc_sess, hp, packet_out, packno_off, packno_len);
|
||||
else
|
||||
apply_hp_immediately(enc_sess, hp, packet_out, packno_off, packno_len);
|
||||
|
@ -2218,9 +2309,14 @@ static struct ku_label
|
|||
}
|
||||
|
||||
|
||||
select_ku_label (const struct enc_sess_iquic *enc_sess)
|
||||
select_ku_label (enum lsquic_version version)
|
||||
{
|
||||
return (struct ku_label) { "quic ku", 7, };
|
||||
static struct ku_label labels[2] =
|
||||
{
|
||||
{ "quic ku", 7, },
|
||||
{ "quicv2 ku", 9, }
|
||||
};
|
||||
return labels[version == LSQVER_I002];
|
||||
}
|
||||
|
||||
|
||||
|
@ -2267,10 +2363,10 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
}
|
||||
|
||||
enc_level = hety2el[packet_in->pi_header_type];
|
||||
if (enc_level == ENC_LEV_FORW)
|
||||
if (enc_level == ENC_LEV_APP)
|
||||
hp = &enc_sess->esi_hp;
|
||||
else if (enc_sess->esi_hsk_pairs)
|
||||
hp = &enc_sess->esi_hsk_hps[ enc_level ];
|
||||
else if (enc_sess->esi_hsk_crypto)
|
||||
hp = &enc_sess->esi_hsk_crypto[ enc_level ].hp;
|
||||
else
|
||||
hp = NULL;
|
||||
|
||||
|
@ -2299,7 +2395,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
packet_in->pi_data + sample_off,
|
||||
dst, packet_in->pi_header_sz, &packno_len);
|
||||
|
||||
if (enc_level == ENC_LEV_FORW)
|
||||
if (enc_level == ENC_LEV_APP)
|
||||
{
|
||||
key_phase = (dst[0] & 0x04) > 0;
|
||||
pair = &enc_sess->esi_pairs[ key_phase ];
|
||||
|
@ -2314,7 +2410,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
|| packet_in->pi_packno
|
||||
> enc_sess->esi_pairs[enc_sess->esi_key_phase].ykp_thresh)
|
||||
{
|
||||
const struct ku_label kl = select_ku_label(enc_sess);
|
||||
const struct ku_label kl = select_ku_label(enc_sess->esi_conn->cn_version);
|
||||
lsquic_qhkdf_expand(enc_sess->esi_md,
|
||||
enc_sess->esi_traffic_secrets[0], enc_sess->esi_trasec_sz,
|
||||
kl.str, kl.len, new_secret, enc_sess->esi_trasec_sz);
|
||||
|
@ -2329,7 +2425,9 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
crypto_ctx->yk_flags = 0;
|
||||
s = init_crypto_ctx(crypto_ctx, enc_sess->esi_md,
|
||||
enc_sess->esi_aead, new_secret, enc_sess->esi_trasec_sz,
|
||||
evp_aead_open);
|
||||
evp_aead_open,
|
||||
&hkdf_labels[enc_sess->esi_conn->cn_version == LSQVER_I002]
|
||||
);
|
||||
if (s != 0)
|
||||
{
|
||||
LSQ_ERROR("could not init open crypto ctx (key phase)");
|
||||
|
@ -2352,8 +2450,8 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
else
|
||||
{
|
||||
key_phase = 0;
|
||||
assert(enc_sess->esi_hsk_pairs);
|
||||
pair = &enc_sess->esi_hsk_pairs[ enc_level ];
|
||||
assert(enc_sess->esi_hsk_crypto);
|
||||
pair = &enc_sess->esi_hsk_crypto[ enc_level ].pair;
|
||||
crypto_ctx = &pair->ykp_ctx[ 0 ];
|
||||
if (UNLIKELY(0 == (crypto_ctx->yk_flags & YK_INITED)))
|
||||
{
|
||||
|
@ -2411,7 +2509,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
if (dst[0] & 0x08)
|
||||
packet_in->pi_flags |= PI_LOSS_BIT;
|
||||
}
|
||||
else if (dst[0] & (0x0C << (packet_in->pi_header_type == HETY_NOT_SET)))
|
||||
else if (dst[0] & (0x0C << (packet_in->pi_header_type == HETY_SHORT)))
|
||||
{
|
||||
LSQ_DEBUG("reserved bits are not set to zero");
|
||||
dec_packin = DECPI_VIOLATION;
|
||||
|
@ -2422,7 +2520,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
{
|
||||
LSQ_DEBUG("decryption in the new key phase %u successful, rotate "
|
||||
"keys", key_phase);
|
||||
const struct ku_label kl = select_ku_label(enc_sess);
|
||||
const struct ku_label kl = select_ku_label(enc_sess->esi_conn->cn_version);
|
||||
pair->ykp_thresh = packet_in->pi_packno;
|
||||
pair->ykp_ctx[ 0 ] = crypto_ctx_buf;
|
||||
memcpy(enc_sess->esi_traffic_secrets[ 0 ], new_secret,
|
||||
|
@ -2434,7 +2532,8 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
enc_sess->esi_trasec_sz);
|
||||
s = init_crypto_ctx(&pair->ykp_ctx[1], enc_sess->esi_md,
|
||||
enc_sess->esi_aead, new_secret, enc_sess->esi_trasec_sz,
|
||||
evp_aead_seal);
|
||||
evp_aead_seal,
|
||||
&hkdf_labels[enc_sess->esi_conn->cn_version == LSQVER_I002]);
|
||||
if (s != 0)
|
||||
{
|
||||
LSQ_ERROR("could not init seal crypto ctx (key phase)");
|
||||
|
@ -2457,8 +2556,6 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
packet_in->pi_data = dst;
|
||||
packet_in->pi_flags |= PI_OWN_DATA | PI_DECRYPTED
|
||||
| (enc_level << PIBIT_ENC_LEV_SHIFT);
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "decrypted packet %"PRIu64,
|
||||
packet_in->pi_packno);
|
||||
pns = lsquic_enclev2pns[enc_level];
|
||||
if (packet_in->pi_packno > enc_sess->esi_max_packno[pns]
|
||||
|| !(enc_sess->esi_flags & (ESI_MAX_PACKNO_INIT << pns)))
|
||||
|
@ -2622,23 +2719,58 @@ iquic_esfi_set_iscid (enc_session_t *enc_session_p,
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
iquic_esfi_switch_version (enc_session_t *enc_session_p, lsquic_cid_t *dcid,
|
||||
int backup_keys)
|
||||
{
|
||||
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
||||
|
||||
enc_sess->esi_flags |= ESI_SWITCH_VER;
|
||||
|
||||
/* Free previous handshake keys */
|
||||
assert(enc_sess->esi_hsk_crypto);
|
||||
if (backup_keys)
|
||||
{
|
||||
if (!enc_sess->esi_vn_save)
|
||||
{
|
||||
enc_sess->esi_vn_save = calloc(1, sizeof(*enc_sess->esi_vn_save));
|
||||
//skip error, non fatal
|
||||
}
|
||||
else
|
||||
cleanup_hsk_crypto(enc_sess->esi_vn_save);
|
||||
if (enc_sess->esi_vn_save)
|
||||
*enc_sess->esi_vn_save = enc_sess->esi_hsk_crypto[ENC_LEV_INIT];
|
||||
}
|
||||
if (!enc_sess->esi_vn_save)
|
||||
cleanup_hsk_crypto(&enc_sess->esi_hsk_crypto[ENC_LEV_INIT]);
|
||||
else
|
||||
memset(&enc_sess->esi_hsk_crypto[ENC_LEV_INIT], 0,
|
||||
sizeof(enc_sess->esi_hsk_crypto[ENC_LEV_INIT]));
|
||||
|
||||
if (0 == setup_handshake_keys(enc_sess, dcid ? dcid : &enc_sess->esi_odcid))
|
||||
{
|
||||
LSQ_INFO("update handshake keys to version %s",
|
||||
lsquic_ver2str[enc_sess->esi_conn->cn_version]);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
iquic_esfi_reset_dcid (enc_session_t *enc_session_p,
|
||||
const lsquic_cid_t *old_dcid, const lsquic_cid_t *new_dcid)
|
||||
{
|
||||
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
||||
struct crypto_ctx_pair *pair;
|
||||
|
||||
enc_sess->esi_odcid = *old_dcid;
|
||||
enc_sess->esi_rscid = *new_dcid;
|
||||
enc_sess->esi_flags |= ESI_ODCID|ESI_RSCID|ESI_RETRY;
|
||||
|
||||
/* Free previous handshake keys */
|
||||
assert(enc_sess->esi_hsk_pairs);
|
||||
pair = &enc_sess->esi_hsk_pairs[ENC_LEV_CLEAR];
|
||||
cleanup_crypto_ctx(&pair->ykp_ctx[0]);
|
||||
cleanup_crypto_ctx(&pair->ykp_ctx[1]);
|
||||
cleanup_hp(&enc_sess->esi_hsk_hps[ENC_LEV_CLEAR]);
|
||||
assert(enc_sess->esi_hsk_crypto);
|
||||
cleanup_hsk_crypto(&enc_sess->esi_hsk_crypto[ENC_LEV_INIT]);
|
||||
|
||||
if (0 == setup_handshake_keys(enc_sess, new_dcid))
|
||||
{
|
||||
|
@ -2812,7 +2944,7 @@ maybe_drop_SSL (struct enc_sess_iquic *enc_sess)
|
|||
if ((enc_sess->esi_flags & (ESI_HSK_CONFIRMED|ESI_HANDSHAKE_OK))
|
||||
== (ESI_HSK_CONFIRMED|ESI_HANDSHAKE_OK)
|
||||
&& enc_sess->esi_ssl
|
||||
&& lsquic_frab_list_empty(&enc_sess->esi_frals[ENC_LEV_FORW]))
|
||||
&& lsquic_frab_list_empty(&enc_sess->esi_frals[ENC_LEV_APP]))
|
||||
{
|
||||
if ((enc_sess->esi_flags & (ESI_SERVER|ESI_WANT_TICKET))
|
||||
!= ESI_WANT_TICKET)
|
||||
|
@ -2841,10 +2973,10 @@ no_sess_ticket (enum alarm_id alarm_id, void *ctx,
|
|||
|
||||
|
||||
typedef char enums_have_the_same_value[
|
||||
(int) ssl_encryption_initial == (int) ENC_LEV_CLEAR &&
|
||||
(int) ssl_encryption_early_data == (int) ENC_LEV_EARLY &&
|
||||
(int) ssl_encryption_handshake == (int) ENC_LEV_INIT &&
|
||||
(int) ssl_encryption_application == (int) ENC_LEV_FORW ? 1 : -1];
|
||||
(int) ssl_encryption_initial == (int) ENC_LEV_INIT &&
|
||||
(int) ssl_encryption_early_data == (int) ENC_LEV_0RTT &&
|
||||
(int) ssl_encryption_handshake == (int) ENC_LEV_HSK &&
|
||||
(int) ssl_encryption_application == (int) ENC_LEV_APP ? 1 : -1];
|
||||
|
||||
static int
|
||||
set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
||||
|
@ -2862,6 +2994,7 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
|||
unsigned char key[EVP_MAX_KEY_LENGTH];
|
||||
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
||||
#define hexbuf errbuf
|
||||
struct label_set *labels;
|
||||
|
||||
enc_sess = SSL_get_ex_data(ssl, s_idx);
|
||||
if (!enc_sess)
|
||||
|
@ -2894,11 +3027,11 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
|||
secrets[0] = write_secret, secrets[1] = read_secret;
|
||||
*/
|
||||
|
||||
if (enc_level < ENC_LEV_FORW)
|
||||
if (enc_level < ENC_LEV_APP)
|
||||
{
|
||||
assert(enc_sess->esi_hsk_pairs);
|
||||
pair = &enc_sess->esi_hsk_pairs[enc_level];
|
||||
hp = &enc_sess->esi_hsk_hps[enc_level];
|
||||
assert(enc_sess->esi_hsk_crypto);
|
||||
pair = &enc_sess->esi_hsk_crypto[enc_level].pair;
|
||||
hp = &enc_sess->esi_hsk_crypto[enc_level].hp;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2924,8 +3057,9 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
|||
else
|
||||
LSQ_DEBUG("set %s for level %u", rw2str[rw], enc_level);
|
||||
|
||||
labels = &hkdf_labels[enc_sess->esi_conn->cn_version == LSQVER_I002];
|
||||
if (0 != init_crypto_ctx(&pair->ykp_ctx[rw], crypa.md,
|
||||
crypa.aead, secret, secret_len, rw2dir(rw)))
|
||||
crypa.aead, secret, secret_len, rw2dir(rw), labels))
|
||||
goto err;
|
||||
|
||||
if (pair->ykp_ctx[!rw].yk_flags & YK_INITED)
|
||||
|
@ -2943,8 +3077,8 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
|||
key_len = EVP_AEAD_key_length(crypa.aead);
|
||||
if (hp->hp_gen_mask == gen_hp_mask_aes)
|
||||
{
|
||||
lsquic_qhkdf_expand(crypa.md, secret, secret_len, PN_LABEL, PN_LABEL_SZ,
|
||||
key, key_len);
|
||||
lsquic_qhkdf_expand(crypa.md, secret, secret_len, labels->hp,
|
||||
labels->hp_len, key, key_len);
|
||||
EVP_CIPHER_CTX_init(&hp->hp_u.cipher_ctx[rw]);
|
||||
if (!EVP_EncryptInit_ex(&hp->hp_u.cipher_ctx[rw], crypa.hp, NULL, key, 0))
|
||||
{
|
||||
|
@ -2953,8 +3087,8 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
|||
}
|
||||
}
|
||||
else
|
||||
lsquic_qhkdf_expand(crypa.md, secret, secret_len, PN_LABEL, PN_LABEL_SZ,
|
||||
hp->hp_u.buf[rw], key_len);
|
||||
lsquic_qhkdf_expand(crypa.md, secret, secret_len, labels->hp,
|
||||
labels->hp_len, hp->hp_u.buf[rw], key_len);
|
||||
hp->hp_flags |= 1 << rw;
|
||||
|
||||
if (enc_sess->esi_flags & ESI_LOG_SECRETS)
|
||||
|
@ -2965,7 +3099,7 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
|||
key_len, hexbuf));
|
||||
}
|
||||
|
||||
if (rw && enc_level == ENC_LEV_FORW)
|
||||
if (rw && enc_level == ENC_LEV_APP)
|
||||
enc_sess->esi_have_forw = 1;
|
||||
|
||||
return 1;
|
||||
|
@ -3106,7 +3240,7 @@ chsk_ietf_on_new_stream (void *stream_if_ctx, struct lsquic_stream *stream)
|
|||
enum enc_level enc_level;
|
||||
|
||||
enc_level = enc_sess->esi_cryst_if->csi_enc_level(stream);
|
||||
if (enc_level == ENC_LEV_CLEAR)
|
||||
if (enc_level == ENC_LEV_INIT)
|
||||
enc_sess->esi_cryst_if->csi_wantwrite(stream, 1);
|
||||
|
||||
LSQ_DEBUG("handshake stream created successfully");
|
||||
|
@ -3344,6 +3478,9 @@ const unsigned char *const lsquic_retry_key_buf[N_IETF_RETRY_VERSIONS] =
|
|||
/* [draft-ietf-quic-tls-33] Section 5.8 */
|
||||
(unsigned char *)
|
||||
"\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e",
|
||||
/* [draft-draft-ietf-quic-v2] Section 3.3.3 */
|
||||
(unsigned char *)
|
||||
"\x8f\xb4\xb0\x1b\x56\xac\x48\xe2\x60\xfb\xcb\xce\xad\x7c\xcc\x92",
|
||||
};
|
||||
|
||||
|
||||
|
@ -3355,6 +3492,8 @@ const unsigned char *const lsquic_retry_nonce_buf[N_IETF_RETRY_VERSIONS] =
|
|||
(unsigned char *) "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c",
|
||||
/* [draft-ietf-quic-tls-33] Section 5.8 */
|
||||
(unsigned char *) "\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb",
|
||||
/* [draft-draft-ietf-quic-v2] Section 3.3.3 */
|
||||
(unsigned char *) "\xd8\x69\x69\xbc\x2d\x7c\x6d\x99\x90\xef\xb0\x4a",
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -226,6 +226,7 @@ struct lsquic_engine
|
|||
*/
|
||||
ENG_CONNS_BY_ADDR
|
||||
= (1 << 9), /* Connections are hashed by address */
|
||||
ENG_FORCE_RETRY = (1 << 10), /* Will force retry packets to be sent */
|
||||
#ifndef NDEBUG
|
||||
ENG_COALESCE = (1 << 24), /* Packet coalescing is enabled */
|
||||
#endif
|
||||
|
@ -307,6 +308,7 @@ lsquic_engine_init_settings (struct lsquic_engine_settings *settings,
|
|||
{
|
||||
settings->es_cfcw = LSQUIC_DF_CFCW_SERVER;
|
||||
settings->es_sfcw = LSQUIC_DF_SFCW_SERVER;
|
||||
settings->es_support_srej= LSQUIC_DF_SUPPORT_SREJ_SERVER;
|
||||
settings->es_init_max_data
|
||||
= LSQUIC_DF_INIT_MAX_DATA_SERVER;
|
||||
settings->es_init_max_stream_data_bidi_remote
|
||||
|
@ -325,6 +327,7 @@ lsquic_engine_init_settings (struct lsquic_engine_settings *settings,
|
|||
{
|
||||
settings->es_cfcw = LSQUIC_DF_CFCW_CLIENT;
|
||||
settings->es_sfcw = LSQUIC_DF_SFCW_CLIENT;
|
||||
settings->es_support_srej= LSQUIC_DF_SUPPORT_SREJ_CLIENT;
|
||||
settings->es_init_max_data
|
||||
= LSQUIC_DF_INIT_MAX_DATA_CLIENT;
|
||||
settings->es_init_max_stream_data_bidi_remote
|
||||
|
@ -373,6 +376,7 @@ lsquic_engine_init_settings (struct lsquic_engine_settings *settings,
|
|||
settings->es_qpack_enc_max_size = LSQUIC_DF_QPACK_ENC_MAX_SIZE;
|
||||
settings->es_qpack_enc_max_blocked = LSQUIC_DF_QPACK_ENC_MAX_BLOCKED;
|
||||
settings->es_allow_migration = LSQUIC_DF_ALLOW_MIGRATION;
|
||||
settings->es_retry_token_duration = LSQUIC_DF_RETRY_TOKEN_DURATION;
|
||||
settings->es_ql_bits = LSQUIC_DF_QL_BITS;
|
||||
settings->es_spin = LSQUIC_DF_SPIN;
|
||||
settings->es_delayed_acks = LSQUIC_DF_DELAYED_ACKS;
|
||||
|
@ -756,7 +760,7 @@ lsquic_engine_new (unsigned flags,
|
|||
if (flags & LSENG_HTTP)
|
||||
engine->pub.enp_flags |= ENPUB_HTTP;
|
||||
|
||||
#ifndef NDEBUG
|
||||
#if !defined(NDEBUG) || LSQUIC_QIR
|
||||
{
|
||||
const char *env;
|
||||
env = getenv("LSQUIC_LOSE_PACKETS_RE");
|
||||
|
@ -775,6 +779,15 @@ lsquic_engine_new (unsigned flags,
|
|||
env);
|
||||
}
|
||||
#endif
|
||||
env = getenv("LSQUIC_FORCE_RETRY");
|
||||
if (env)
|
||||
{
|
||||
if (atoi(env))
|
||||
{
|
||||
engine->flags |= ENG_FORCE_RETRY;
|
||||
LSQ_WARN("will force retry");
|
||||
}
|
||||
}
|
||||
env = getenv("LSQUIC_COALESCE");
|
||||
if (env)
|
||||
{
|
||||
|
@ -908,7 +921,7 @@ destroy_conn (struct lsquic_engine *engine, struct lsquic_conn *conn,
|
|||
struct purga_el *puel;
|
||||
|
||||
engine->mini_conns_count -= !!(conn->cn_flags & LSCONN_MINI);
|
||||
if (engine->purga
|
||||
if (engine->purga && !(conn->cn_flags & LSCONN_NO_BL)
|
||||
/* Blacklist all CIDs except for promoted mini connections */
|
||||
&& (conn->cn_flags & (LSCONN_MINI|LSCONN_PROMOTED))
|
||||
!= (LSCONN_MINI|LSCONN_PROMOTED))
|
||||
|
@ -1145,6 +1158,44 @@ new_full_conn_server (lsquic_engine_t *engine, lsquic_conn_t *mini_conn,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
remove_conn_from_hash (lsquic_engine_t *engine, lsquic_conn_t *conn);
|
||||
|
||||
|
||||
static int
|
||||
promote_mini_conn (lsquic_engine_t *engine, lsquic_conn_t *mini_conn,
|
||||
lsquic_time_t now)
|
||||
{
|
||||
lsquic_conn_t *new_conn;
|
||||
EV_LOG_CONN_EVENT(lsquic_conn_log_cid( mini_conn ),
|
||||
"promote to full conn");
|
||||
assert( mini_conn->cn_flags & LSCONN_MINI);
|
||||
new_conn = new_full_conn_server(engine, mini_conn, now);
|
||||
if (new_conn)
|
||||
{
|
||||
new_conn->cn_last_sent = engine->last_sent;
|
||||
eng_hist_inc(&engine->history, now, sl_new_full_conns);
|
||||
mini_conn->cn_flags |= LSCONN_PROMOTED;
|
||||
assert(engine->curr_conn == mini_conn);
|
||||
engine->curr_conn = new_conn;
|
||||
|
||||
if (mini_conn->cn_flags & LSCONN_ATTQ)
|
||||
{
|
||||
lsquic_attq_remove(engine->attq, mini_conn);
|
||||
(void) engine_decref_conn(engine, mini_conn, LSCONN_ATTQ);
|
||||
}
|
||||
if (mini_conn->cn_flags & LSCONN_HASHED)
|
||||
remove_conn_from_hash(engine, mini_conn);
|
||||
|
||||
lsquic_mh_insert(&engine->conns_tickable, new_conn,
|
||||
new_conn->cn_last_ticked);
|
||||
engine_incref_conn(new_conn, LSCONN_TICKABLE);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static enum
|
||||
{
|
||||
VER_NOT_SPECIFIED,
|
||||
|
@ -1203,6 +1254,38 @@ schedule_req_packet (struct lsquic_engine *engine, enum packet_req_type type,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
schedule_mini_retry (struct lsquic_engine *engine, struct lsquic_conn *conn,
|
||||
lsquic_time_t now)
|
||||
{
|
||||
const struct network_path *path;
|
||||
|
||||
assert(engine->pr_queue);
|
||||
path = conn->cn_if->ci_get_path(conn, NULL);
|
||||
if (!path)
|
||||
{
|
||||
LSQ_WARN("cannot fetch default path");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(conn->cn_flags & LSCONN_IETF);
|
||||
if (0 == lsquic_prq_new_req_ext(engine->pr_queue, PACKET_REQ_RETRY,
|
||||
0 /* Only supporting retry on IETF mini conns for now */,
|
||||
conn->cn_version, path->np_pack_size, &conn->cn_cid,
|
||||
&path->np_dcid, path->np_peer_ctx, NP_LOCAL_SA(path),
|
||||
NP_PEER_SA(path)
|
||||
))
|
||||
LSQ_DEBUGC("scheduled %s packet for mini conn %"CID_FMT,
|
||||
lsquic_preqt2str[PACKET_REQ_RETRY],
|
||||
CID_BITS(lsquic_conn_log_cid(conn)));
|
||||
else
|
||||
LSQ_DEBUGC("could not schedule %s packet for mini conn %"CID_FMT,
|
||||
lsquic_preqt2str[PACKET_REQ_RETRY],
|
||||
CID_BITS(lsquic_conn_log_cid(conn)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
static unsigned short
|
||||
sa2port (const struct sockaddr *sa)
|
||||
{
|
||||
|
@ -1423,8 +1506,60 @@ find_or_create_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
|||
|
||||
if ((1 << version) & LSQUIC_IETF_VERSIONS)
|
||||
{
|
||||
lsquic_cid_t odcid;
|
||||
if (engine->pub.enp_settings.es_support_srej
|
||||
&& HETY_INITIAL == packet_in->pi_header_type)
|
||||
{
|
||||
/* XXX Need to handle condition when packets are reordered? */
|
||||
const int has_token
|
||||
= packet_in->pi_token && packet_in->pi_token_size;
|
||||
const int need_retry =
|
||||
!!(engine->flags & ENG_FORCE_RETRY);
|
||||
switch ((need_retry << 1) | has_token)
|
||||
{
|
||||
case (0 << 1) | 0:
|
||||
odcid.len = 0;
|
||||
goto create_ietf_mini_conn;
|
||||
case (1 << 1) | 1:
|
||||
case (0 << 1) | 1:
|
||||
odcid.len = 0;
|
||||
if (0 == lsquic_tg_validate_token(engine->pub.enp_tokgen,
|
||||
packet_in, sa_peer, &odcid))
|
||||
goto create_ietf_mini_conn;
|
||||
/* From [draft-ietf-quic-transport-30] Section 8.1.2:
|
||||
" In response to processing an Initial containing a token that was
|
||||
" provided in a Retry packet, a server cannot send another Retry
|
||||
" packet; it can only refuse the connection or permit it to proceed.
|
||||
*/
|
||||
if (TOKEN_RETRY == packet_in->pi_data[packet_in->pi_token])
|
||||
{
|
||||
LSQ_DEBUGC("CID %"CID_FMT" has invalid Retry token",
|
||||
CID_BITS(&packet_in->pi_conn_id));
|
||||
return NULL;
|
||||
}
|
||||
/* According to the spec, we SHOULD send CONNECTION_CLOSE
|
||||
* when receiving an invalid Retry token. We don't do it
|
||||
* because it's a lot of code change for an event that is
|
||||
* not likely to happen: a major browser copying the token
|
||||
* incorrectly.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
/* fall-through */
|
||||
case (1 << 1) | 0:
|
||||
break;
|
||||
}
|
||||
schedule_req_packet(engine, PACKET_REQ_RETRY, packet_in, sa_local,
|
||||
sa_peer, peer_ctx);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
odcid.len = 0;
|
||||
create_ietf_mini_conn:
|
||||
conn = lsquic_mini_conn_ietf_new(&engine->pub, packet_in, version,
|
||||
sa_peer->sa_family == AF_INET, NULL, packet_in_size);
|
||||
sa_peer->sa_family == AF_INET, odcid.len ? &odcid : NULL,
|
||||
packet_in_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1621,6 +1756,12 @@ process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
|
|||
#endif
|
||||
QLOG_PACKET_RX(lsquic_conn_log_cid(conn), packet_in, packet_in_data, packet_in_size);
|
||||
lsquic_packet_in_put(&engine->pub.enp_mm, packet_in);
|
||||
if ((conn->cn_flags & (LSCONN_MINI | LSCONN_HANDSHAKE_DONE))
|
||||
== (LSCONN_MINI | LSCONN_HANDSHAKE_DONE))
|
||||
{
|
||||
if (promote_mini_conn(engine, conn, lsquic_time_now()) == -1)
|
||||
conn->cn_flags |= LSCONN_PROMOTE_FAIL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1900,7 +2041,8 @@ engine_incref_conn (lsquic_conn_t *conn, enum lsquic_conn_flags flag)
|
|||
assert(flag & CONN_REF_FLAGS);
|
||||
assert(!(conn->cn_flags & flag));
|
||||
conn->cn_flags |= flag;
|
||||
LSQ_DEBUGC("incref conn %"CID_FMT", '%s' -> '%s'",
|
||||
LSQ_DEBUGC("incref %sconn %"CID_FMT", '%s' -> '%s'",
|
||||
(conn->cn_flags &LSCONN_MINI) ? "mini-" : "",
|
||||
CID_BITS(lsquic_conn_log_cid(conn)),
|
||||
(refflags2str(conn->cn_flags & ~flag, str[0]), str[0]),
|
||||
(refflags2str(conn->cn_flags, str[1]), str[1]));
|
||||
|
@ -1920,7 +2062,8 @@ engine_decref_conn (lsquic_engine_t *engine, lsquic_conn_t *conn,
|
|||
assert(0 == (conn->cn_flags & LSCONN_HASHED));
|
||||
#endif
|
||||
conn->cn_flags &= ~flags;
|
||||
LSQ_DEBUGC("decref conn %"CID_FMT", '%s' -> '%s'",
|
||||
LSQ_DEBUGC("decref %sconn %"CID_FMT", '%s' -> '%s'",
|
||||
(conn->cn_flags &LSCONN_MINI) ? "mini-" : "",
|
||||
CID_BITS(lsquic_conn_log_cid(conn)),
|
||||
(refflags2str(conn->cn_flags | flags, str[0]), str[0]),
|
||||
(refflags2str(conn->cn_flags, str[1]), str[1]));
|
||||
|
@ -2296,7 +2439,7 @@ lose_matching_packets (const lsquic_engine_t *engine, struct out_batch *batch,
|
|||
|
||||
for (i = 0; i < n; ++i)
|
||||
{
|
||||
snprintf(packno_str, sizeof(packno_str), "%"PRIu64,
|
||||
snprintf(packno_str, sizeof(packno_str), "#%"PRIu64,
|
||||
batch->packets[i]->po_packno);
|
||||
if (0 == regexec(&engine->lose_packets_re, packno_str, 0, NULL, 0))
|
||||
{
|
||||
|
@ -2662,7 +2805,7 @@ send_packets_out (struct lsquic_engine *engine,
|
|||
goto end_for;
|
||||
}
|
||||
}
|
||||
LSQ_DEBUGC("batched packet %"PRIu64" for connection %"CID_FMT,
|
||||
LSQ_DEBUGC("batched packet #%"PRIu64" for connection %"CID_FMT,
|
||||
packet_out->po_packno, CID_BITS(lsquic_conn_log_cid(conn)));
|
||||
if (packet_out->po_flags & PO_ENCRYPTED)
|
||||
{
|
||||
|
@ -2928,6 +3071,11 @@ process_connections (lsquic_engine_t *engine, conn_iter_f next_conn,
|
|||
}
|
||||
tick_st |= TICK_CLOSE; /* Destroy mini connection */
|
||||
}
|
||||
if (tick_st & TICK_RETRY)
|
||||
{
|
||||
assert(conn->cn_flags & LSCONN_MINI);
|
||||
schedule_mini_retry(engine, conn, now);
|
||||
}
|
||||
if (tick_st & TICK_SEND)
|
||||
{
|
||||
if (!(conn->cn_flags & LSCONN_HAS_OUTGOING))
|
||||
|
|
|
@ -57,23 +57,23 @@ lsquic_ev_log_packet_in (const lsquic_cid_t *cid,
|
|||
switch (packet_in->pi_flags & (PI_FROM_MINI|PI_GQUIC))
|
||||
{
|
||||
case PI_FROM_MINI|PI_GQUIC:
|
||||
LCID("packet in: %"PRIu64" (from mini)", packet_in->pi_packno);
|
||||
LCID("RX packet #%"PRIu64" (mini)", packet_in->pi_packno);
|
||||
break;
|
||||
case PI_FROM_MINI:
|
||||
LCID("packet in: %"PRIu64" (from mini), type: %s, ecn: %u",
|
||||
LCID("RX packet #%"PRIu64" %s (mini), ecn: %u",
|
||||
packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type],
|
||||
lsquic_packet_in_ecn(packet_in));
|
||||
break;
|
||||
case PI_GQUIC:
|
||||
packet_sz = packet_in->pi_data_sz
|
||||
+ (packet_in->pi_flags & PI_DECRYPTED ? GQUIC_PACKET_HASH_SZ : 0);
|
||||
LCID("packet in: %"PRIu64", size: %u", packet_in->pi_packno, packet_sz);
|
||||
LCID("RX packet #%"PRIu64", size: %u", packet_in->pi_packno, packet_sz);
|
||||
break;
|
||||
default:
|
||||
packet_sz = packet_in->pi_data_sz
|
||||
+ (packet_in->pi_flags & PI_DECRYPTED ? IQUIC_TAG_LEN : 0);
|
||||
if (packet_in->pi_flags & PI_LOG_QL_BITS)
|
||||
LCID("packet in: %"PRIu64", type: %s, size: %u; ecn: %u, spin: %d; "
|
||||
LCID("RX packet #%"PRIu64" %s, size: %u; ecn: %u, spin: %d; "
|
||||
"path: %hhu; Q: %d; L: %d",
|
||||
packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type],
|
||||
packet_sz,
|
||||
|
@ -83,7 +83,7 @@ lsquic_ev_log_packet_in (const lsquic_cid_t *cid,
|
|||
((packet_in->pi_flags & PI_SQUARE_BIT) > 0),
|
||||
((packet_in->pi_flags & PI_LOSS_BIT) > 0));
|
||||
else
|
||||
LCID("packet in: %"PRIu64", type: %s, size: %u; ecn: %u, spin: %d; "
|
||||
LCID("RX packet #%"PRIu64" %s, size: %u; ecn: %u, spin: %d; "
|
||||
"path: %hhu",
|
||||
packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type],
|
||||
packet_sz,
|
||||
|
@ -102,7 +102,7 @@ lsquic_ev_log_ack_frame_in (const lsquic_cid_t *cid,
|
|||
char buf[MAX_ACKI_STR_SZ];
|
||||
|
||||
lsquic_acki2str(acki, buf, sizeof(buf));
|
||||
LCID("ACK frame in: %s", buf);
|
||||
LCID("RX ACK frame: %s", buf);
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,7 +110,7 @@ void
|
|||
lsquic_ev_log_stream_frame_in (const lsquic_cid_t *cid,
|
||||
const struct stream_frame *frame)
|
||||
{
|
||||
LCID("STREAM frame in: stream %"PRIu64"; offset %"PRIu64"; size %"PRIu16
|
||||
LCID("RX STREAM frame: stream %"PRIu64"; offset %"PRIu64"; size %"PRIu16
|
||||
"; fin: %d", frame->stream_id, frame->data_frame.df_offset,
|
||||
frame->data_frame.df_size, (int) frame->data_frame.df_fin);
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ void
|
|||
lsquic_ev_log_crypto_frame_in (const lsquic_cid_t *cid,
|
||||
const struct stream_frame *frame, unsigned enc_level)
|
||||
{
|
||||
LCID("CRYPTO frame in: level %u; offset %"PRIu64"; size %"PRIu16,
|
||||
LCID("RX CRYPTO frame: level %u; offset %"PRIu64"; size %"PRIu16,
|
||||
enc_level, frame->data_frame.df_offset, frame->data_frame.df_size);
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ void
|
|||
lsquic_ev_log_stop_waiting_frame_in (const lsquic_cid_t *cid,
|
||||
lsquic_packno_t least)
|
||||
{
|
||||
LCID("STOP_WAITING frame in: least unacked packno %"PRIu64, least);
|
||||
LCID("RX STOP_WAITING frame: least unacked packno %"PRIu64, least);
|
||||
}
|
||||
|
||||
|
||||
|
@ -137,7 +137,7 @@ void
|
|||
lsquic_ev_log_window_update_frame_in (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id, uint64_t offset)
|
||||
{
|
||||
LCID("WINDOW_UPDATE frame in: stream %"PRIu64"; offset %"PRIu64,
|
||||
LCID("RX WINDOW_UPDATE frame: stream %"PRIu64"; offset %"PRIu64,
|
||||
stream_id, offset);
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ void
|
|||
lsquic_ev_log_blocked_frame_in (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id)
|
||||
{
|
||||
LCID("BLOCKED frame in: stream %"PRIu64, stream_id);
|
||||
LCID("RX BLOCKED frame: stream %"PRIu64, stream_id);
|
||||
}
|
||||
|
||||
|
||||
|
@ -154,7 +154,7 @@ void
|
|||
lsquic_ev_log_connection_close_frame_in (const lsquic_cid_t *cid,
|
||||
uint64_t error_code, int reason_len, const char *reason)
|
||||
{
|
||||
LCID("CONNECTION_CLOSE frame in: error code %"PRIu64", reason: %.*s",
|
||||
LCID("RX CONNECTION_CLOSE frame: error code %"PRIu64", reason: %.*s",
|
||||
error_code, reason_len, reason);
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ void
|
|||
lsquic_ev_log_goaway_frame_in (const lsquic_cid_t *cid, uint32_t error_code,
|
||||
lsquic_stream_id_t stream_id, int reason_len, const char *reason)
|
||||
{
|
||||
LCID("GOAWAY frame in: error code %"PRIu32", stream %"PRIu64
|
||||
LCID("RX GOAWAY frame: error code %"PRIu32", stream %"PRIu64
|
||||
", reason: %.*s", error_code, stream_id, reason_len, reason);
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ void
|
|||
lsquic_ev_log_rst_stream_frame_in (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id, uint64_t offset, uint64_t error_code)
|
||||
{
|
||||
LCID("RST_STREAM frame in: error code %"PRIu64", stream %"PRIu64
|
||||
LCID("RX RST_STREAM frame: error code %"PRIu64", stream %"PRIu64
|
||||
", offset: %"PRIu64, error_code, stream_id, offset);
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ void
|
|||
lsquic_ev_log_stop_sending_frame_in (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id, uint64_t error_code)
|
||||
{
|
||||
LCID("STOP_SENDING frame in: error code %"PRIu64", stream %"PRIu64,
|
||||
LCID("RX STOP_SENDING frame: error code %"PRIu64", stream %"PRIu64,
|
||||
error_code, stream_id);
|
||||
}
|
||||
|
||||
|
@ -189,14 +189,14 @@ lsquic_ev_log_stop_sending_frame_in (const lsquic_cid_t *cid,
|
|||
void
|
||||
lsquic_ev_log_padding_frame_in (const lsquic_cid_t *cid, size_t len)
|
||||
{
|
||||
LCID("PADDING frame in of %zd bytes", len);
|
||||
LCID("RX PADDING frame of %zd bytes", len);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_ping_frame_in (const lsquic_cid_t *cid)
|
||||
{
|
||||
LCID("PING frame in");
|
||||
LCID("RX PING frame");
|
||||
}
|
||||
|
||||
|
||||
|
@ -204,8 +204,9 @@ void
|
|||
lsquic_ev_log_packet_created (const lsquic_cid_t *cid,
|
||||
const struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
LCID("created packet %"PRIu64"; flags: version=%d, nonce=%d, conn_id=%d",
|
||||
LCID("created packet #%"PRIu64" %s; flags: version=%d, nonce=%d, conn_id=%d",
|
||||
packet_out->po_packno,
|
||||
lsquic_hety2str[packet_out->po_header_type],
|
||||
!!(packet_out->po_flags & PO_VERSION),
|
||||
!!(packet_out->po_flags & PO_NONCE),
|
||||
!!(packet_out->po_flags & PO_CONN_ID));
|
||||
|
@ -218,34 +219,34 @@ lsquic_ev_log_packet_sent (const lsquic_cid_t *cid,
|
|||
{
|
||||
char frames[lsquic_frame_types_str_sz];
|
||||
if (lsquic_packet_out_verneg(packet_out))
|
||||
LCID("sent version negotiation packet, size %hu",
|
||||
LCID("TX version negotiation packet, size %hu",
|
||||
packet_out->po_data_sz);
|
||||
else if (lsquic_packet_out_retry(packet_out))
|
||||
LCID("sent stateless retry packet, size %hu", packet_out->po_data_sz);
|
||||
LCID("TX stateless retry packet, size %hu", 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);
|
||||
LCID("TX public reset packet, size %hu", packet_out->po_data_sz);
|
||||
else if (packet_out->po_lflags & POL_GQUIC)
|
||||
LCID("sent packet %"PRIu64", size %hu, frame types: %s",
|
||||
packet_out->po_packno, packet_out->po_enc_data_sz,
|
||||
LCID("TX packet #%"PRIu64" (%s), size %hu",
|
||||
packet_out->po_packno,
|
||||
/* 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));
|
||||
packet_out->po_frame_types),
|
||||
packet_out->po_enc_data_sz);
|
||||
else if (packet_out->po_lflags & POL_LOG_QL_BITS)
|
||||
LCID("sent packet %"PRIu64", type %s, crypto: %s, size %hu, frame "
|
||||
"types: %s, ecn: %u, spin: %d; kp: %u, path: %hhu, flags: %u; "
|
||||
LCID("TX packet #%"PRIu64" %s (%s), size %hu, "
|
||||
"ecn: %u, spin: %d; kp: %u, path: %hhu, flags: %u; "
|
||||
"Q: %u; L: %u",
|
||||
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),
|
||||
packet_out->po_enc_data_sz,
|
||||
lsquic_packet_out_ecn(packet_out),
|
||||
/* spin bit value is only valid for short packet headers */
|
||||
lsquic_packet_out_spin_bit(packet_out),
|
||||
|
@ -255,17 +256,16 @@ lsquic_ev_log_packet_sent (const lsquic_cid_t *cid,
|
|||
lsquic_packet_out_square_bit(packet_out),
|
||||
lsquic_packet_out_loss_bit(packet_out));
|
||||
else
|
||||
LCID("sent packet %"PRIu64", type %s, crypto: %s, size %hu, frame "
|
||||
"types: %s, ecn: %u, spin: %d; kp: %u, path: %hhu, flags: %u",
|
||||
LCID("TX packet #%"PRIu64" %s (%s), size %hu, "
|
||||
"ecn: %u, spin: %d; kp: %u, path: %hhu, flags: %u",
|
||||
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),
|
||||
packet_out->po_enc_data_sz,
|
||||
lsquic_packet_out_ecn(packet_out),
|
||||
/* spin bit value is only valid for short packet headers */
|
||||
lsquic_packet_out_spin_bit(packet_out),
|
||||
|
@ -280,13 +280,14 @@ lsquic_ev_log_packet_not_sent (const lsquic_cid_t *cid,
|
|||
const struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
char frames[lsquic_frame_types_str_sz];
|
||||
LCID("unsent packet %"PRIu64", size %hu, frame types: %s",
|
||||
packet_out->po_packno, packet_out->po_enc_data_sz,
|
||||
LCID("unsent packet #%"PRIu64" %s, size %hu",
|
||||
packet_out->po_packno,
|
||||
/* 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));
|
||||
packet_out->po_frame_types),
|
||||
packet_out->po_enc_data_sz);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1608,7 +1608,7 @@ process_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
|
|||
|
||||
enc_level = lsquic_packet_in_enc_level(packet_in);
|
||||
if (!is_handshake_stream_id(conn, stream_frame->stream_id)
|
||||
&& enc_level == ENC_LEV_CLEAR)
|
||||
&& enc_level == ENC_LEV_INIT)
|
||||
{
|
||||
lsquic_malo_put(stream_frame);
|
||||
ABORT_ERROR("received unencrypted data for stream %"PRIu64,
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
#define MAX_ANY_PACKETS_SINCE_LAST_ACK 20
|
||||
#define ACK_TIMEOUT (TP_DEF_MAX_ACK_DELAY * 1000)
|
||||
#define INITIAL_CHAL_TIMEOUT 250000
|
||||
#define HSK_PING_TIMEOUT 200000
|
||||
|
||||
/* Retire original CID after this much time has elapsed: */
|
||||
#define RET_CID_TIMEOUT 2000000
|
||||
|
@ -191,6 +192,7 @@ enum send
|
|||
SEND_MAX_STREAMS_BIDI = SEND_MAX_STREAMS + SD_BIDI,
|
||||
SEND_MAX_STREAMS_UNI = SEND_MAX_STREAMS + SD_UNI,
|
||||
SEND_STOP_SENDING,
|
||||
SEND_NEW_TOKEN,
|
||||
SEND_HANDSHAKE_DONE,
|
||||
SEND_ACK_FREQUENCY,
|
||||
N_SEND
|
||||
|
@ -220,6 +222,7 @@ enum send_flags
|
|||
SF_SEND_MAX_STREAMS_BIDI = 1 << SEND_MAX_STREAMS_BIDI,
|
||||
SF_SEND_MAX_STREAMS_UNI = 1 << SEND_MAX_STREAMS_UNI,
|
||||
SF_SEND_STOP_SENDING = 1 << SEND_STOP_SENDING,
|
||||
SF_SEND_NEW_TOKEN = 1 << SEND_NEW_TOKEN,
|
||||
SF_SEND_HANDSHAKE_DONE = 1 << SEND_HANDSHAKE_DONE,
|
||||
SF_SEND_ACK_FREQUENCY = 1 << SEND_ACK_FREQUENCY,
|
||||
};
|
||||
|
@ -1356,7 +1359,10 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
|||
|
||||
assert(versions);
|
||||
versions &= LSQUIC_IETF_VERSIONS;
|
||||
ver = highest_bit_set(versions);
|
||||
if (versions & (1 << LSQVER_I001))
|
||||
ver = LSQVER_I001;
|
||||
else
|
||||
ver = highest_bit_set(versions);
|
||||
if (sess_resume)
|
||||
{
|
||||
sess_resume_version = lsquic_sess_resume_version(sess_resume, sess_resume_sz);
|
||||
|
@ -1432,13 +1438,13 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
|||
if (!conn->ifc_conn.cn_enc_session)
|
||||
goto err2;
|
||||
|
||||
conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR] = lsquic_stream_new_crypto(
|
||||
ENC_LEV_CLEAR, &conn->ifc_pub, &lsquic_cry_sm_if,
|
||||
conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT] = lsquic_stream_new_crypto(
|
||||
ENC_LEV_INIT, &conn->ifc_pub, &lsquic_cry_sm_if,
|
||||
conn->ifc_conn.cn_enc_session,
|
||||
SCF_IETF|SCF_DI_AUTOSWITCH|SCF_CALL_ON_NEW|SCF_CRITICAL);
|
||||
if (!conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR])
|
||||
if (!conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT])
|
||||
goto err3;
|
||||
if (!lsquic_stream_get_ctx(conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR]))
|
||||
if (!lsquic_stream_get_ctx(conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT]))
|
||||
goto err4;
|
||||
conn->ifc_pub.packet_out_malo =
|
||||
lsquic_malo_create(sizeof(struct lsquic_packet_out));
|
||||
|
@ -1467,7 +1473,7 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
|
|||
return &conn->ifc_conn;
|
||||
|
||||
err4:
|
||||
lsquic_stream_destroy(conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR]);
|
||||
lsquic_stream_destroy(conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT]);
|
||||
err3:
|
||||
conn->ifc_conn.cn_esf.i->esfi_destroy(conn->ifc_conn.cn_enc_session);
|
||||
err2:
|
||||
|
@ -1544,6 +1550,8 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub,
|
|||
goto err1;
|
||||
if (imc->imc_flags & IMC_IGNORE_INIT)
|
||||
conn->ifc_flags |= IFC_IGNORE_INIT;
|
||||
if (enpub->enp_settings.es_support_srej)
|
||||
conn->ifc_send_flags |= SF_SEND_NEW_TOKEN;
|
||||
|
||||
conn->ifc_paths[0].cop_path = imc->imc_path;
|
||||
conn->ifc_paths[0].cop_flags = COP_VALIDATED|COP_INITIALIZED|COP_ALLOW_MTU_PADDING;
|
||||
|
@ -1603,6 +1611,11 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub,
|
|||
conn->ifc_process_incoming_packet = process_incoming_packet_fast;
|
||||
|
||||
conn->ifc_send_ctl.sc_cur_packno = imc->imc_next_packno - 1;
|
||||
conn->ifc_incoming_ecn = imc->imc_incoming_ecn;
|
||||
conn->ifc_pub.rtt_stats = imc->imc_rtt_stats;
|
||||
|
||||
conn->ifc_last_live_update = now;
|
||||
|
||||
lsquic_send_ctl_begin_optack_detection(&conn->ifc_send_ctl);
|
||||
|
||||
for (pns = 0; pns < IMICO_N_PNS; ++pns)
|
||||
|
@ -1675,15 +1688,6 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub,
|
|||
{
|
||||
conn->ifc_ecn_counts_in[pns][i] = imc->imc_ecn_counts_in[pns][i];
|
||||
}
|
||||
conn->ifc_incoming_ecn = imc->imc_incoming_ecn;
|
||||
conn->ifc_pub.rtt_stats = imc->imc_rtt_stats;
|
||||
|
||||
lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_RET_CIDS,
|
||||
ret_cids_alarm_expired, conn);
|
||||
lsquic_alarmset_set(&conn->ifc_alset, AL_RET_CIDS,
|
||||
now + RET_CID_TIMEOUT);
|
||||
|
||||
conn->ifc_last_live_update = now;
|
||||
|
||||
if (0 != handshake_ok(&conn->ifc_conn))
|
||||
goto err3;
|
||||
|
@ -1693,10 +1697,10 @@ lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *enpub,
|
|||
conn->ifc_enpub->enp_stream_if_ctx, &conn->ifc_conn);
|
||||
conn->ifc_idle_to = conn->ifc_settings->es_idle_timeout * 1000000;
|
||||
|
||||
conn->ifc_created = imc->imc_created;
|
||||
conn->ifc_created = now;
|
||||
if (conn->ifc_idle_to)
|
||||
lsquic_alarmset_set(&conn->ifc_alset, AL_IDLE,
|
||||
imc->imc_created + conn->ifc_idle_to);
|
||||
now + conn->ifc_idle_to);
|
||||
while ((packet_in = TAILQ_FIRST(&imc->imc_app_packets)))
|
||||
{
|
||||
TAILQ_REMOVE(&imc->imc_app_packets, packet_in, pi_next);
|
||||
|
@ -1901,6 +1905,16 @@ generate_ack_frame_for_pns (struct ietf_full_conn *conn,
|
|||
packet_out->po_data + packet_out->po_data_sz, w);
|
||||
lsquic_send_ctl_scheduled_ack(&conn->ifc_send_ctl, pns,
|
||||
packet_out->po_ack2ed);
|
||||
|
||||
// NOTE: Add a PING frame after ACK frame before HANDSHAKE_DONE, in a hacky way
|
||||
if (!(conn->ifc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
&& packet_out->po_data_sz + w < packet_out->po_n_alloc)
|
||||
{
|
||||
LSQ_DEBUG("add a PING frame before HANDSHAKE_DONE");
|
||||
*(packet_out->po_data + packet_out->po_data_sz + w) = '\x01';
|
||||
++w;
|
||||
}
|
||||
|
||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_ACK;
|
||||
if (0 != lsquic_packet_out_add_frame(packet_out, conn->ifc_pub.mm, 0,
|
||||
QUIC_FRAME_ACK, packet_out->po_data_sz, w))
|
||||
|
@ -1914,7 +1928,8 @@ generate_ack_frame_for_pns (struct ietf_full_conn *conn,
|
|||
conn->ifc_flags |= IFC_ACK_HAD_MISS;
|
||||
else
|
||||
conn->ifc_flags &= ~IFC_ACK_HAD_MISS;
|
||||
LSQ_DEBUG("Put %d bytes of ACK frame into packet on outgoing queue", w);
|
||||
LSQ_DEBUG("Put %d bytes of ACK frame into packet %" PRIu64
|
||||
" on outgoing queue", w, packet_out->po_packno);
|
||||
if (conn->ifc_n_cons_unretx >= conn->ifc_ping_unretx_thresh &&
|
||||
!lsquic_send_ctl_have_outgoing_retx_frames(&conn->ifc_send_ctl))
|
||||
{
|
||||
|
@ -2034,6 +2049,58 @@ generate_max_data_frame (struct ietf_full_conn *conn)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
generate_new_token_frame (struct ietf_full_conn *conn, lsquic_time_t now)
|
||||
{
|
||||
struct lsquic_packet_out *packet_out;
|
||||
const struct network_path *path;
|
||||
ssize_t token_sz;
|
||||
size_t need;
|
||||
int w;
|
||||
unsigned char token_buf[MAX_RETRY_TOKEN_LEN];
|
||||
|
||||
path = &conn->ifc_paths[conn->ifc_cur_path_id].cop_path;
|
||||
token_sz = lsquic_tg_token_size(conn->ifc_enpub->enp_tokgen, TOKEN_RESUME,
|
||||
NP_PEER_SA(path));
|
||||
need = conn->ifc_conn.cn_pf->pf_new_token_frame_size(token_sz);
|
||||
packet_out = get_writeable_packet(conn, need);
|
||||
if (!packet_out)
|
||||
return;
|
||||
|
||||
token_sz = lsquic_tg_generate_resume(conn->ifc_enpub->enp_tokgen, token_buf,
|
||||
sizeof(token_buf), NP_PEER_SA(path));
|
||||
if (token_sz < 0)
|
||||
{
|
||||
LSQ_WARN("could not generate resume token");
|
||||
conn->ifc_send_flags &= ~SF_SEND_NEW_TOKEN; /* Let's not try again */
|
||||
return;
|
||||
}
|
||||
|
||||
w = conn->ifc_conn.cn_pf->pf_gen_new_token_frame(
|
||||
packet_out->po_data + packet_out->po_data_sz,
|
||||
lsquic_packet_out_avail(packet_out), token_buf, token_sz);
|
||||
if (w < 0)
|
||||
{
|
||||
ABORT_ERROR("generating NEW_TOKEN frame failed: %d", errno);
|
||||
return;
|
||||
}
|
||||
LSQ_DEBUG("generated %d-byte NEW_TOKEN frame", w);
|
||||
EV_LOG_GENERATED_NEW_TOKEN_FRAME(LSQUIC_LOG_CONN_ID, conn->ifc_conn.cn_pf,
|
||||
packet_out->po_data + packet_out->po_data_sz, w);
|
||||
if (0 != lsquic_packet_out_add_frame(packet_out, conn->ifc_pub.mm, 0,
|
||||
QUIC_FRAME_NEW_TOKEN, packet_out->po_data_sz, w))
|
||||
{
|
||||
ABORT_ERROR("adding frame to packet failed: %d", errno);
|
||||
return;
|
||||
}
|
||||
packet_out->po_frame_types |= QUIC_FTBIT_NEW_TOKEN;
|
||||
lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, w);
|
||||
|
||||
conn->ifc_send_flags &= ~SF_SEND_NEW_TOKEN;
|
||||
(void) token_sz;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
can_issue_cids (const struct ietf_full_conn *conn)
|
||||
{
|
||||
|
@ -3799,6 +3866,29 @@ handshake_ok (struct lsquic_conn *lconn)
|
|||
else
|
||||
dce->de_flags = DE_ASSIGNED;
|
||||
|
||||
if (!(conn->ifc_flags & IFC_SERVER)
|
||||
&& (params->tp_set & (1 << TPI_VERSION_INFORMATION)))
|
||||
{
|
||||
LSQ_DEBUG("server chosen version %s",
|
||||
lsquic_ver2str[params->tp_chosen_version]);
|
||||
if (((1 << params->tp_chosen_version)
|
||||
& conn->ifc_settings->es_versions) == 0)
|
||||
{
|
||||
ABORT_QUIETLY(0, TEC_VERSION_NEGOTIATION_ERROR,
|
||||
"server chosen version %s is not supported",
|
||||
lsquic_ver2str[params->tp_chosen_version]
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
// if (conn->ifc_conn.cn_version != params->tp_chosen_version)
|
||||
// {
|
||||
// LSQ_DEBUG("version negociation: switch version from %s to %s",
|
||||
// lsquic_ver2str[conn->ifc_conn.cn_version],
|
||||
// lsquic_ver2str[params->tp_chosen_version]);
|
||||
// conn->ifc_conn.cn_version = params->tp_chosen_version;
|
||||
// }
|
||||
}
|
||||
|
||||
LSQ_INFO("applied peer transport parameters");
|
||||
|
||||
if ((conn->ifc_flags & (IFC_HTTP|IFC_HTTP_INITED)) == IFC_HTTP)
|
||||
|
@ -4413,7 +4503,8 @@ generate_connection_close_packet (struct ietf_full_conn *conn)
|
|||
lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, sz);
|
||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_CONNECTION_CLOSE;
|
||||
conn->ifc_mflags |= MF_CONN_CLOSE_PACK;
|
||||
LSQ_DEBUG("generated CONNECTION_CLOSE frame in its own packet");
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID,
|
||||
"generated CONNECTION_CLOSE frame in its own packet");
|
||||
conn->ifc_send_flags &= ~SF_SEND_CONN_CLOSE;
|
||||
}
|
||||
|
||||
|
@ -4431,12 +4522,30 @@ log_conn_flow_control (struct ietf_full_conn *conn)
|
|||
|
||||
|
||||
static void
|
||||
generate_ping_frame (struct ietf_full_conn *conn, lsquic_time_t unused)
|
||||
generate_ping_frame (struct ietf_full_conn *conn, lsquic_time_t now)
|
||||
{
|
||||
struct lsquic_packet_out *packet_out;
|
||||
int pns;
|
||||
int sz;
|
||||
|
||||
packet_out = get_writeable_packet(conn, 1);
|
||||
if (conn->ifc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
packet_out = get_writeable_packet(conn, 1);
|
||||
else
|
||||
{
|
||||
conn->ifc_ping_period += HSK_PING_TIMEOUT;
|
||||
lsquic_alarmset_set(&conn->ifc_alset, AL_PING,
|
||||
now + conn->ifc_ping_period);
|
||||
if (iquic_esf_is_enc_level_ready(conn->ifc_conn.cn_enc_session,
|
||||
ENC_LEV_HSK))
|
||||
pns = PNS_HSK;
|
||||
else
|
||||
pns = PNS_INIT;
|
||||
packet_out = lsquic_send_ctl_new_packet_out(&conn->ifc_send_ctl, 0, pns,
|
||||
CUR_NPATH(conn));
|
||||
if (packet_out)
|
||||
lsquic_send_ctl_scheduled_one(&conn->ifc_send_ctl, packet_out);
|
||||
|
||||
}
|
||||
if (!packet_out)
|
||||
{
|
||||
LSQ_DEBUG("cannot get writeable packet for PING frame");
|
||||
|
@ -4839,7 +4948,9 @@ static unsigned
|
|||
process_padding_frame (struct ietf_full_conn *conn,
|
||||
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
||||
{
|
||||
return (unsigned) count_zero_bytes(p, len);
|
||||
unsigned sz = (unsigned) count_zero_bytes(p, len);
|
||||
EV_LOG_PADDING_FRAME_IN(LSQUIC_LOG_CONN_ID, sz);
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
|
@ -5591,7 +5702,7 @@ process_crypto_frame_server (struct ietf_full_conn *conn,
|
|||
parsed_len);
|
||||
return (unsigned) parsed_len;
|
||||
}
|
||||
if (enc_level < ENC_LEV_INIT)
|
||||
if (enc_level < ENC_LEV_HSK)
|
||||
{ /* Must be dup */
|
||||
LSQ_DEBUG("discard %d-byte CRYPTO frame on level %s", parsed_len,
|
||||
lsquic_enclev2str[enc_level]);
|
||||
|
@ -5613,6 +5724,11 @@ process_crypto_frame_server (struct ietf_full_conn *conn,
|
|||
LSQ_DEBUG("handshake confirmed: send HANDSHAKE_DONE");
|
||||
conn->ifc_flags &= ~IFC_PROC_CRYPTO;
|
||||
conn->ifc_send_flags |= SF_SEND_HANDSHAKE_DONE;
|
||||
|
||||
lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_RET_CIDS,
|
||||
ret_cids_alarm_expired, conn);
|
||||
lsquic_alarmset_set(&conn->ifc_alset, AL_RET_CIDS,
|
||||
lsquic_time_now() + RET_CID_TIMEOUT);
|
||||
}
|
||||
|
||||
return (unsigned) parsed_len;
|
||||
|
@ -5653,7 +5769,7 @@ process_crypto_frame_client (struct ietf_full_conn *conn,
|
|||
EV_LOG_CRYPTO_FRAME_IN(LSQUIC_LOG_CONN_ID, stream_frame, enc_level);
|
||||
LSQ_DEBUG("Got CRYPTO frame for enc level #%u", enc_level);
|
||||
if ((conn->ifc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
&& enc_level != ENC_LEV_FORW)
|
||||
&& enc_level != ENC_LEV_APP)
|
||||
{
|
||||
LSQ_DEBUG("handshake complete: ignore CRYPTO frames in "
|
||||
"non-forward-secure packets");
|
||||
|
@ -5743,7 +5859,6 @@ process_stream_frame (struct ietf_full_conn *conn,
|
|||
return 0;
|
||||
}
|
||||
EV_LOG_STREAM_FRAME_IN(LSQUIC_LOG_CONN_ID, stream_frame);
|
||||
LSQ_DEBUG("Got stream frame for stream #%"PRIu64, stream_frame->stream_id);
|
||||
CONN_STATS(in.stream_frames, 1);
|
||||
CONN_STATS(in.stream_data_sz, stream_frame->data_frame.df_size);
|
||||
|
||||
|
@ -5941,7 +6056,6 @@ process_ping_frame (struct ietf_full_conn *conn,
|
|||
* return the length of this frame.
|
||||
*/
|
||||
EV_LOG_PING_FRAME_IN(LSQUIC_LOG_CONN_ID);
|
||||
LSQ_DEBUG("received PING");
|
||||
if (conn->ifc_flags & IFC_SERVER)
|
||||
log_conn_flow_control(conn);
|
||||
|
||||
|
@ -6037,7 +6151,7 @@ process_max_data_frame (struct ietf_full_conn *conn,
|
|||
if (parsed_len < 0)
|
||||
return 0;
|
||||
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "MAX_DATA frame in; offset: %"PRIu64,
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "RX MAX_DATA frame; offset: %"PRIu64,
|
||||
max_data);
|
||||
if (max_data > conn->ifc_pub.conn_cap.cc_max)
|
||||
{
|
||||
|
@ -6067,7 +6181,7 @@ process_max_stream_data_frame (struct ietf_full_conn *conn,
|
|||
if (parsed_len < 0)
|
||||
return 0;
|
||||
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "MAX_STREAM_DATA frame in; "
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "RX MAX_STREAM_DATA frame; "
|
||||
"stream_id: %"PRIu64"; offset: %"PRIu64, stream_id, max_data);
|
||||
if (conn_is_receive_only_stream(conn, stream_id))
|
||||
{
|
||||
|
@ -6480,7 +6594,7 @@ process_stream_blocked_frame (struct ietf_full_conn *conn,
|
|||
if (parsed_len < 0)
|
||||
return 0;
|
||||
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "STREAM_BLOCKED frame in: stream "
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "RX STREAM_BLOCKED frame: stream "
|
||||
"%"PRIu64"; offset %"PRIu64, stream_id, peer_off);
|
||||
LSQ_DEBUG("received STREAM_BLOCKED frame: stream %"PRIu64
|
||||
"; offset %"PRIu64, stream_id, peer_off);
|
||||
|
@ -6546,7 +6660,7 @@ process_blocked_frame (struct ietf_full_conn *conn,
|
|||
if (parsed_len < 0)
|
||||
return 0;
|
||||
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "BLOCKED frame in: offset %"PRIu64,
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "RX BLOCKED frame: offset %"PRIu64,
|
||||
peer_off);
|
||||
LSQ_DEBUG("received BLOCKED frame: offset %"PRIu64, peer_off);
|
||||
|
||||
|
@ -6576,7 +6690,7 @@ process_handshake_done_frame (struct ietf_full_conn *conn,
|
|||
if (parsed_len < 0)
|
||||
return 0;
|
||||
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "HANDSHAKE_DONE frame in");
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "RX HANDSHAKE_DONE frame");
|
||||
LSQ_DEBUG("received HANDSHAKE_DONE frame");
|
||||
|
||||
if (conn->ifc_flags & IFC_SERVER)
|
||||
|
@ -6612,11 +6726,11 @@ process_ack_frequency_frame (struct ietf_full_conn *conn,
|
|||
if (parsed_len < 0)
|
||||
return 0;
|
||||
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "ACK_FREQUENCY(seqno: %"PRIu64"; "
|
||||
"pack_tol: %"PRIu64"; upd: %"PRIu64"; ignore: %d) frame in", seqno,
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "RX ACK_FREQUENCY frame: (seqno: %"PRIu64"; "
|
||||
"pack_tol: %"PRIu64"; upd: %"PRIu64"; ignore: %d)", seqno,
|
||||
pack_tol, upd_mad, ignore);
|
||||
LSQ_DEBUG("ACK_FREQUENCY(seqno: %"PRIu64"; pack_tol: %"PRIu64"; "
|
||||
"upd: %"PRIu64"; ignore: %d) frame in", seqno, pack_tol, upd_mad,
|
||||
LSQ_DEBUG("RX ACK_FREQUENCY frame: (seqno: %"PRIu64"; pack_tol: %"PRIu64"; "
|
||||
"upd: %"PRIu64"; ignore: %d)", seqno, pack_tol, upd_mad,
|
||||
ignore);
|
||||
|
||||
if (pack_tol == 0)
|
||||
|
@ -6764,6 +6878,7 @@ process_packet_frame (struct ietf_full_conn *conn,
|
|||
{
|
||||
LSQ_DEBUG("invalid frame %u (bytes: %s) at encryption level %s",
|
||||
type, HEXSTR(p, MIN(len, 8), str), lsquic_enclev2str[enc_level]);
|
||||
ABORT_QUIETLY(0, TEC_FRAME_ENCODING_ERROR, "invalid frame");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -7246,10 +7361,10 @@ ignore_init (struct ietf_full_conn *conn)
|
|||
lsquic_rechist_cleanup(&conn->ifc_rechist[PNS_INIT]);
|
||||
if (!(conn->ifc_flags & IFC_SERVER))
|
||||
{
|
||||
if (conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR])
|
||||
if (conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT])
|
||||
{
|
||||
lsquic_stream_destroy(conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR]);
|
||||
conn->ifc_u.cli.crypto_streams[ENC_LEV_CLEAR] = NULL;
|
||||
lsquic_stream_destroy(conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT]);
|
||||
conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT] = NULL;
|
||||
}
|
||||
conn->ifc_conn.cn_if = ietf_full_conn_iface_ptr;
|
||||
}
|
||||
|
@ -7265,10 +7380,10 @@ ignore_hsk (struct ietf_full_conn *conn)
|
|||
lsquic_send_ctl_empty_pns(&conn->ifc_send_ctl, PNS_HSK);
|
||||
lsquic_rechist_cleanup(&conn->ifc_rechist[PNS_HSK]);
|
||||
if (!(conn->ifc_flags & IFC_SERVER))
|
||||
if (conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT])
|
||||
if (conn->ifc_u.cli.crypto_streams[ENC_LEV_HSK])
|
||||
{
|
||||
lsquic_stream_destroy(conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT]);
|
||||
conn->ifc_u.cli.crypto_streams[ENC_LEV_INIT] = NULL;
|
||||
lsquic_stream_destroy(conn->ifc_u.cli.crypto_streams[ENC_LEV_HSK]);
|
||||
conn->ifc_u.cli.crypto_streams[ENC_LEV_HSK] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7323,11 +7438,6 @@ process_regular_packet (struct ietf_full_conn *conn,
|
|||
CONN_STATS(in.packets, 1);
|
||||
|
||||
pns = lsquic_hety2pns[ packet_in->pi_header_type ];
|
||||
if (pns == PNS_INIT)
|
||||
conn->ifc_conn.cn_esf.i->esfi_set_iscid(conn->ifc_conn.cn_enc_session,
|
||||
packet_in);
|
||||
else if (pns == PNS_HSK)
|
||||
lsquic_send_ctl_maybe_calc_rough_rtt(&conn->ifc_send_ctl, pns - 1);
|
||||
if ((pns == PNS_INIT && (conn->ifc_flags & IFC_IGNORE_INIT))
|
||||
|| (pns == PNS_HSK && (conn->ifc_flags & IFC_IGNORE_HSK)))
|
||||
{
|
||||
|
@ -7423,6 +7533,12 @@ process_regular_packet (struct ietf_full_conn *conn,
|
|||
}
|
||||
}
|
||||
|
||||
if (pns == PNS_INIT)
|
||||
conn->ifc_conn.cn_esf.i->esfi_set_iscid(conn->ifc_conn.cn_enc_session,
|
||||
packet_in);
|
||||
else if (pns == PNS_HSK)
|
||||
lsquic_send_ctl_maybe_calc_rough_rtt(&conn->ifc_send_ctl, pns - 1);
|
||||
|
||||
EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in);
|
||||
|
||||
is_rechist_empty = lsquic_rechist_is_empty(&conn->ifc_rechist[pns]);
|
||||
|
@ -7534,7 +7650,7 @@ process_regular_packet (struct ietf_full_conn *conn,
|
|||
}
|
||||
conn->ifc_pub.bytes_in += packet_in->pi_data_sz;
|
||||
if ((conn->ifc_mflags & MF_VALIDATE_PATH) &&
|
||||
(packet_in->pi_header_type == HETY_NOT_SET
|
||||
(packet_in->pi_header_type == HETY_SHORT
|
||||
|| packet_in->pi_header_type == HETY_HANDSHAKE))
|
||||
{
|
||||
conn->ifc_mflags &= ~MF_VALIDATE_PATH;
|
||||
|
@ -7562,7 +7678,24 @@ verneg_ok (const struct ietf_full_conn *conn)
|
|||
enum lsquic_version ver;
|
||||
|
||||
ver = highest_bit_set(conn->ifc_u.cli.ifcli_ver_neg.vn_supp);
|
||||
return (1 << ver) & LSQUIC_IETF_DRAFT_VERSIONS;
|
||||
return (1 << ver) & LSQUIC_IETF_VERSIONS;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
enable_ping_alarm_for_handshake (struct ietf_full_conn *conn)
|
||||
{
|
||||
conn->ifc_ping_period = HSK_PING_TIMEOUT;
|
||||
lsquic_alarmset_set(&conn->ifc_alset, AL_PING,
|
||||
lsquic_time_now() + conn->ifc_ping_period);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
switch_version (struct ietf_full_conn *conn, enum lsquic_version version)
|
||||
{
|
||||
conn->ifc_conn.cn_version = version;
|
||||
return iquic_esfi_switch_version(conn->ifc_conn.cn_enc_session, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -7650,19 +7783,39 @@ process_incoming_packet_verneg (struct ietf_full_conn *conn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (packet_in->pi_version != conn->ifc_u.cli.ifcli_ver_neg.vn_ver)
|
||||
{
|
||||
if (!((1 << packet_in->pi_version)
|
||||
& conn->ifc_u.cli.ifcli_ver_neg.vn_supp))
|
||||
{
|
||||
LSQ_DEBUG("server version doesn't match versions "
|
||||
"supported: ignore");
|
||||
return 0;
|
||||
}
|
||||
LSQ_DEBUG("version negociation: server switched version from %s to %s",
|
||||
lsquic_ver2str[conn->ifc_u.cli.ifcli_ver_neg.vn_ver],
|
||||
lsquic_ver2str[packet_in->pi_version]);
|
||||
switch_version(conn, packet_in->pi_version);
|
||||
}
|
||||
else
|
||||
conn->ifc_conn.cn_version = conn->ifc_u.cli.ifcli_ver_neg.vn_ver;
|
||||
assert(conn->ifc_u.cli.ifcli_ver_neg.vn_tag);
|
||||
assert(conn->ifc_u.cli.ifcli_ver_neg.vn_state != VN_END);
|
||||
conn->ifc_u.cli.ifcli_ver_neg.vn_state = VN_END;
|
||||
conn->ifc_u.cli.ifcli_ver_neg.vn_tag = NULL;
|
||||
conn->ifc_conn.cn_version = conn->ifc_u.cli.ifcli_ver_neg.vn_ver;
|
||||
conn->ifc_conn.cn_flags |= LSCONN_VER_SET;
|
||||
LSQ_DEBUG("end of version negotiation: agreed upon %s",
|
||||
lsquic_ver2str[conn->ifc_u.cli.ifcli_ver_neg.vn_ver]);
|
||||
lsquic_ver2str[conn->ifc_conn.cn_version]);
|
||||
EV_LOG_VER_NEG(LSQUIC_LOG_CONN_ID,
|
||||
"agreed", lsquic_ver2str[conn->ifc_u.cli.ifcli_ver_neg.vn_ver]);
|
||||
conn->ifc_process_incoming_packet = process_incoming_packet_fast;
|
||||
"agreed", lsquic_ver2str[conn->ifc_conn.cn_version]);
|
||||
conn->ifc_process_incoming_packet = process_regular_packet;
|
||||
|
||||
return process_regular_packet(conn, packet_in);
|
||||
if (process_regular_packet(conn, packet_in) == 0)
|
||||
{
|
||||
enable_ping_alarm_for_handshake(conn);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -7825,6 +7978,7 @@ static void (*const send_funcs[N_SEND])(
|
|||
[SEND_MAX_STREAMS_UNI] = generate_max_streams_uni_frame,
|
||||
[SEND_MAX_STREAMS_BIDI] = generate_max_streams_bidi_frame,
|
||||
[SEND_STOP_SENDING] = generate_stop_sending_frames,
|
||||
[SEND_NEW_TOKEN] = generate_new_token_frame,
|
||||
[SEND_PATH_CHAL_PATH_0] = generate_path_chal_0,
|
||||
[SEND_PATH_CHAL_PATH_1] = generate_path_chal_1,
|
||||
[SEND_PATH_CHAL_PATH_2] = generate_path_chal_2,
|
||||
|
@ -7849,7 +8003,7 @@ static void (*const send_funcs[N_SEND])(
|
|||
|SF_SEND_PATH_RESP_PATH_2|SF_SEND_PATH_RESP_PATH_3\
|
||||
|SF_SEND_PING|SF_SEND_HANDSHAKE_DONE\
|
||||
|SF_SEND_ACK_FREQUENCY\
|
||||
|SF_SEND_STOP_SENDING)
|
||||
|SF_SEND_STOP_SENDING|SF_SEND_NEW_TOKEN)
|
||||
|
||||
|
||||
/* This should be called before lsquic_alarmset_ring_expired() */
|
||||
|
@ -8442,7 +8596,8 @@ ietf_full_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
|
|||
goto end;
|
||||
}
|
||||
}
|
||||
else if (conn->ifc_ping_period)
|
||||
else if (conn->ifc_ping_period
|
||||
&& (conn->ifc_conn.cn_flags & LSCONN_HANDSHAKE_DONE))
|
||||
{
|
||||
lsquic_alarmset_unset(&conn->ifc_alset, AL_PING);
|
||||
lsquic_send_ctl_sanity_check(&conn->ifc_send_ctl);
|
||||
|
@ -8797,7 +8952,7 @@ ietf_full_conn_ci_count_garbage (struct lsquic_conn *lconn, size_t garbage_sz)
|
|||
{
|
||||
struct ietf_full_conn *conn = (struct ietf_full_conn *) lconn;
|
||||
|
||||
conn->ifc_pub.bytes_in = garbage_sz;
|
||||
conn->ifc_pub.bytes_in += garbage_sz;
|
||||
LSQ_DEBUG("count %zd bytes of garbage, new value: %u bytes", garbage_sz,
|
||||
conn->ifc_pub.bytes_in);
|
||||
}
|
||||
|
@ -9481,6 +9636,7 @@ hcsi_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
|
|||
break;
|
||||
case (0 << 8) | LSQVER_ID29:
|
||||
case (0 << 8) | LSQVER_I001:
|
||||
case (0 << 8) | LSQVER_I002:
|
||||
callbacks = &hcsi_callbacks_client_29;
|
||||
break;
|
||||
default:
|
||||
|
@ -9488,6 +9644,7 @@ hcsi_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
|
|||
/* fallthru */
|
||||
case (1 << 8) | LSQVER_ID29:
|
||||
case (1 << 8) | LSQVER_I001:
|
||||
case (1 << 8) | LSQVER_I002:
|
||||
callbacks = &hcsi_callbacks_server_29;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -767,7 +767,7 @@ gquic2_setup_handshake_keys (struct lsquic_enc_session *enc_session)
|
|||
secret, sizeof(secret)))
|
||||
goto err;
|
||||
if (enc_session->es_flags & ES_LOG_SECRETS)
|
||||
log_crypto_ctx(enc_session, ENC_LEV_CLEAR, i);
|
||||
log_crypto_ctx(enc_session, ENC_LEV_INIT, i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -3069,14 +3069,14 @@ decrypt_packet (struct lsquic_enc_session *enc_session, uint8_t path_id,
|
|||
key = enc_session->dec_ctx_f;
|
||||
memcpy(nonce, enc_session->dec_key_nonce_f, 4);
|
||||
LSQ_DEBUG("decrypt_packet using 'F' key...");
|
||||
enc_level = ENC_LEV_FORW;
|
||||
enc_level = ENC_LEV_APP;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = enc_session->dec_ctx_i;
|
||||
memcpy(nonce, enc_session->dec_key_nonce_i, 4);
|
||||
LSQ_DEBUG("decrypt_packet using 'I' key...");
|
||||
enc_level = ENC_LEV_INIT;
|
||||
enc_level = ENC_LEV_HSK;
|
||||
}
|
||||
memcpy(nonce + 4, &path_id_packet_number,
|
||||
sizeof(path_id_packet_number));
|
||||
|
@ -3150,7 +3150,7 @@ lsquic_enc_session_decrypt (struct lsquic_enc_session *enc_session,
|
|||
header_len, data_len, buf_out, max_out_len, out_len);
|
||||
else if (0 == verify_packet_hash(enc_session, version, buf, header_len,
|
||||
data_len, buf_out, max_out_len, out_len))
|
||||
return ENC_LEV_CLEAR;
|
||||
return ENC_LEV_INIT;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
@ -3247,7 +3247,7 @@ gquic_encrypt_buf (struct lsquic_enc_session *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 ENC_LEV_CLEAR;
|
||||
return ENC_LEV_INIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3262,14 +3262,14 @@ gquic_encrypt_buf (struct lsquic_enc_session *enc_session,
|
|||
{
|
||||
enc_session->server_start_use_final_key = 1;
|
||||
}
|
||||
enc_level = ENC_LEV_INIT;
|
||||
enc_level = ENC_LEV_HSK;
|
||||
}
|
||||
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;
|
||||
enc_level = ENC_LEV_APP;
|
||||
}
|
||||
path_id_packet_number = combine_path_id_pack_num(path_id, pack_num);
|
||||
memcpy(nonce + 4, &path_id_packet_number,
|
||||
|
@ -3964,9 +3964,9 @@ static const char *const gel2str[] =
|
|||
|
||||
static const enum enc_level gel2el[] =
|
||||
{
|
||||
[GEL_CLEAR] = ENC_LEV_CLEAR,
|
||||
[GEL_EARLY] = ENC_LEV_EARLY,
|
||||
[GEL_FORW] = ENC_LEV_FORW,
|
||||
[GEL_CLEAR] = ENC_LEV_INIT,
|
||||
[GEL_EARLY] = ENC_LEV_0RTT,
|
||||
[GEL_FORW] = ENC_LEV_APP,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
#define HSK_SALT ((unsigned char *) \
|
||||
"\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17" \
|
||||
"\x9a\xe6\xa4\xc8\x0c\xad\xcc\xbb\x7f\x0a")
|
||||
/* [draft-ietf-quic-v2] Section 3.3.1 */
|
||||
#define HSK_SALT_V2 ((unsigned char *) \
|
||||
"\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93" \
|
||||
"\x81\xbe\x6e\x26\x9d\xcb\xf9\xbd\x2e\xd9")
|
||||
#define HSK_SALT_SZ (sizeof(HSK_SALT_BUF) - 1)
|
||||
|
||||
#define CLIENT_LABEL "client in"
|
||||
|
|
|
@ -24,6 +24,7 @@ enum trans_error_code
|
|||
TEC_KEY_UPDATE_ERROR = 0xE,
|
||||
TEC_AEAD_LIMIT_REACHED = 0xF,
|
||||
TEC_NO_VIABLE_PATH = 0x10,
|
||||
TEC_VERSION_NEGOTIATION_ERROR = 0x11,
|
||||
};
|
||||
|
||||
/* Must be at least two */
|
||||
|
@ -33,12 +34,12 @@ enum trans_error_code
|
|||
#define IETF_RETRY_KEY_SZ 16
|
||||
#define IETF_RETRY_NONCE_SZ 12
|
||||
|
||||
#define N_IETF_RETRY_VERSIONS 3
|
||||
#define N_IETF_RETRY_VERSIONS 4
|
||||
extern const unsigned char *const lsquic_retry_key_buf[N_IETF_RETRY_VERSIONS];
|
||||
extern const unsigned char *const lsquic_retry_nonce_buf[N_IETF_RETRY_VERSIONS];
|
||||
#define lsquic_version_2_retryver(ver_) ( \
|
||||
(ver_) <= LSQVER_ID27 ? 0 : \
|
||||
(ver_) < LSQVER_I001 ? 1 : \
|
||||
2)
|
||||
(ver_) == LSQVER_I002 ? 3 : 2)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -58,10 +58,10 @@ ietf_mini_conn_ci_abort_error (struct lsquic_conn *lconn, int is_app,
|
|||
|
||||
static const enum header_type el2hety[] =
|
||||
{
|
||||
[ENC_LEV_INIT] = HETY_HANDSHAKE,
|
||||
[ENC_LEV_CLEAR] = HETY_INITIAL,
|
||||
[ENC_LEV_FORW] = HETY_NOT_SET,
|
||||
[ENC_LEV_EARLY] = 0, /* Invalid */
|
||||
[ENC_LEV_HSK] = HETY_HANDSHAKE,
|
||||
[ENC_LEV_INIT] = HETY_INITIAL,
|
||||
[ENC_LEV_APP] = HETY_SHORT,
|
||||
[ENC_LEV_0RTT] = 0, /* Invalid */
|
||||
};
|
||||
|
||||
|
||||
|
@ -87,19 +87,13 @@ lsquic_mini_conn_ietf_ecn_ok (const struct ietf_mini_conn *conn)
|
|||
}
|
||||
|
||||
|
||||
#define imico_ecn_ok lsquic_mini_conn_ietf_ecn_ok
|
||||
|
||||
|
||||
static enum ecn
|
||||
imico_get_ecn (struct ietf_mini_conn *conn)
|
||||
{
|
||||
if (!conn->imc_enpub->enp_settings.es_ecn)
|
||||
return ECN_NOT_ECT;
|
||||
else if (!conn->imc_sent_packnos /* We set ECT0 in first flight */
|
||||
|| imico_ecn_ok(conn))
|
||||
return ECN_ECT0;
|
||||
else
|
||||
return ECN_NOT_ECT;
|
||||
return ECN_ECT0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,8 +169,54 @@ read_from_msg_ctx (void *ctx, void *buf, size_t len, int *fin)
|
|||
static int
|
||||
imico_chlo_has_been_consumed (const struct ietf_mini_conn *conn)
|
||||
{
|
||||
return conn->imc_streams[ENC_LEV_CLEAR].mcs_read_off > 3
|
||||
&& conn->imc_streams[ENC_LEV_CLEAR].mcs_read_off >= conn->imc_ch_len;
|
||||
return conn->imc_streams[ENC_LEV_INIT].mcs_read_off > 3
|
||||
&& conn->imc_streams[ENC_LEV_INIT].mcs_read_off >= conn->imc_ch_len;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
imico_process_version_negociation (struct ietf_mini_conn *conn,
|
||||
const struct transport_params *params)
|
||||
{
|
||||
unsigned common_versions;
|
||||
unsigned ver;
|
||||
int i;
|
||||
if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG))
|
||||
{
|
||||
LSQ_DEBUG("client chosen version %s",
|
||||
lsquic_ver2str[params->tp_chosen_version]);
|
||||
for (i = 1; i < params->tp_version_cnt; ++i)
|
||||
{
|
||||
LSQ_DEBUG("client available version %s",
|
||||
lsquic_ver2str[params->tp_version_info[i]]);
|
||||
//EV_LOG_VER_NEG(LSQUIC_LOG_CONN_ID, "supports",
|
||||
// lsquic_ver2str[params->tp_version_info[i]]);
|
||||
}
|
||||
}
|
||||
if (params->tp_chosen_version != conn->imc_conn.cn_version)
|
||||
{
|
||||
LSQ_DEBUG("client chosen version does not match the version in use %s",
|
||||
lsquic_ver2str[conn->imc_conn.cn_version]);
|
||||
ietf_mini_conn_ci_abort_error(&conn->imc_conn, 0,
|
||||
TEC_VERSION_NEGOTIATION_ERROR,
|
||||
"chosen version mismatch");
|
||||
return -1;
|
||||
}
|
||||
common_versions = conn->imc_enpub->enp_settings.es_versions
|
||||
& params->tp_versions;
|
||||
ver = highest_bit_set(common_versions);
|
||||
if (conn->imc_conn.cn_version != ver)
|
||||
{
|
||||
LSQ_DEBUG("version negociation: switch version from %s to %s",
|
||||
lsquic_ver2str[conn->imc_conn.cn_version],
|
||||
lsquic_ver2str[ver]);
|
||||
conn->imc_conn.cn_version = ver;
|
||||
conn->imc_conn.cn_flags |= LSCONN_VER_UPDATED;
|
||||
iquic_esfi_switch_version(conn->imc_conn.cn_enc_session,
|
||||
&conn->imc_cces[0].cce_cid, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -204,6 +244,15 @@ imico_maybe_process_params (struct ietf_mini_conn *conn)
|
|||
}
|
||||
LSQ_DEBUG("read transport params, packet size is set to %hu bytes",
|
||||
conn->imc_path.np_pack_size);
|
||||
if (params->tp_set & (1 << TPI_VERSION_INFORMATION))
|
||||
{
|
||||
if (imico_process_version_negociation(conn, params) == -1)
|
||||
{
|
||||
conn->imc_flags |= IMC_VER_NEG_FAILED;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
iquic_esfi_init_server_tp(conn->imc_conn.cn_enc_session);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -216,6 +265,10 @@ imico_maybe_process_params (struct ietf_mini_conn *conn)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
imico_generate_ack (struct ietf_mini_conn *conn, enum packnum_space pns,
|
||||
lsquic_time_t now);
|
||||
|
||||
static ssize_t
|
||||
imico_stream_write (void *stream, const void *bufp, size_t bufsz)
|
||||
{
|
||||
|
@ -239,19 +292,32 @@ imico_stream_write (void *stream, const void *bufp, size_t bufsz)
|
|||
return bufsz;
|
||||
}
|
||||
|
||||
if (cryst->mcs_enc_level == ENC_LEV_INIT
|
||||
&& (conn->imc_flags & IMC_QUEUED_ACK_INIT))
|
||||
{
|
||||
imico_generate_ack(conn, PNS_INIT, lsquic_time_now());
|
||||
}
|
||||
|
||||
while (msg_ctx.buf < msg_ctx.end)
|
||||
{
|
||||
header_sz = lconn->cn_pf->pf_calc_crypto_frame_header_sz(
|
||||
cryst->mcs_write_off, msg_ctx.end - msg_ctx.buf);
|
||||
need = header_sz + 1;
|
||||
need = header_sz + 500;
|
||||
packet_out = imico_get_packet_out(conn,
|
||||
el2hety[ cryst->mcs_enc_level ], need);
|
||||
if (!packet_out)
|
||||
return -1;
|
||||
|
||||
// NOTE: reduce the size of first crypto frame to combine packets
|
||||
int avail = lsquic_packet_out_avail(packet_out);
|
||||
if (cryst->mcs_enc_level == ENC_LEV_HSK
|
||||
&& cryst->mcs_write_off == 0
|
||||
&& avail > conn->imc_hello_pkt_remain - conn->imc_long_header_sz)
|
||||
{
|
||||
avail = conn->imc_hello_pkt_remain - conn->imc_long_header_sz;
|
||||
}
|
||||
p = msg_ctx.buf;
|
||||
len = pf->pf_gen_crypto_frame(packet_out->po_data + packet_out->po_data_sz,
|
||||
lsquic_packet_out_avail(packet_out), 0, cryst->mcs_write_off, 0,
|
||||
avail, 0, cryst->mcs_write_off, 0,
|
||||
msg_ctx.end - msg_ctx.buf, read_from_msg_ctx, &msg_ctx);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
@ -261,6 +327,8 @@ imico_stream_write (void *stream, const void *bufp, size_t bufsz)
|
|||
packet_out->po_frame_types |= 1 << QUIC_FRAME_CRYPTO;
|
||||
packet_out->po_flags |= PO_HELLO;
|
||||
cryst->mcs_write_off += msg_ctx.buf - p;
|
||||
if (cryst->mcs_enc_level == ENC_LEV_INIT)
|
||||
conn->imc_hello_pkt_remain = avail - len;
|
||||
}
|
||||
|
||||
assert(msg_ctx.buf == msg_ctx.end);
|
||||
|
@ -299,8 +367,8 @@ imico_read_chlo_size (struct ietf_mini_conn *conn, const unsigned char *buf,
|
|||
{
|
||||
const unsigned char *const end = buf + sz;
|
||||
|
||||
assert(conn->imc_streams[ENC_LEV_CLEAR].mcs_read_off < 4);
|
||||
switch (conn->imc_streams[ENC_LEV_CLEAR].mcs_read_off)
|
||||
assert(conn->imc_streams[ENC_LEV_INIT].mcs_read_off < 4);
|
||||
switch (conn->imc_streams[ENC_LEV_INIT].mcs_read_off)
|
||||
{
|
||||
case 0:
|
||||
if (buf == end)
|
||||
|
@ -356,7 +424,7 @@ imico_stream_readf (void *stream,
|
|||
avail = DF_SIZE(frame) - frame->data_frame.df_read_off;
|
||||
buf = frame->data_frame.df_data + frame->data_frame.df_read_off;
|
||||
nread = readf(ctx, buf, avail, DF_FIN(frame));
|
||||
if (cryst->mcs_enc_level == ENC_LEV_CLEAR && cryst->mcs_read_off < 4)
|
||||
if (cryst->mcs_enc_level == ENC_LEV_INIT && cryst->mcs_read_off < 4)
|
||||
imico_read_chlo_size(conn, buf, nread);
|
||||
total_read += nread;
|
||||
cryst->mcs_read_off += nread;
|
||||
|
@ -468,7 +536,7 @@ imico_peer_addr_validated (struct ietf_mini_conn *conn, const char *how)
|
|||
|
||||
struct lsquic_conn *
|
||||
lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
|
||||
const struct lsquic_packet_in *packet_in,
|
||||
struct lsquic_packet_in *packet_in,
|
||||
enum lsquic_version version, int is_ipv4, const lsquic_cid_t *odcid,
|
||||
size_t udp_payload_size)
|
||||
{
|
||||
|
@ -480,7 +548,7 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
|
|||
|
||||
if (!is_first_packet_ok(packet_in, udp_payload_size))
|
||||
return NULL;
|
||||
|
||||
packet_in->pi_flags |= PI_FIRST_INIT;
|
||||
conn = lsquic_malo_get(enpub->enp_mm.malo.mini_conn_ietf);
|
||||
if (!conn)
|
||||
{
|
||||
|
@ -539,9 +607,16 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
|
|||
}
|
||||
|
||||
esfi = select_esf_iquic_by_ver(version);
|
||||
enc_sess = esfi->esfi_create_server(enpub, &conn->imc_conn,
|
||||
&packet_in->pi_dcid, conn->imc_stream_ps, &crypto_stream_if,
|
||||
&conn->imc_cces[0].cce_cid, &conn->imc_path.np_dcid);
|
||||
if (version > LSQVER_ID27)
|
||||
enc_sess = esfi->esfi_create_server(enpub, &conn->imc_conn,
|
||||
&packet_in->pi_dcid, conn->imc_stream_ps, &crypto_stream_if,
|
||||
odcid ? odcid : &conn->imc_cces[0].cce_cid,
|
||||
&conn->imc_path.np_dcid,
|
||||
odcid ? &conn->imc_cces[0].cce_cid : NULL);
|
||||
else
|
||||
enc_sess = esfi->esfi_create_server(enpub, &conn->imc_conn,
|
||||
&packet_in->pi_dcid, conn->imc_stream_ps, &crypto_stream_if,
|
||||
odcid, &conn->imc_path.np_dcid, NULL);
|
||||
if (!enc_sess)
|
||||
{
|
||||
lsquic_malo_put(conn);
|
||||
|
@ -549,7 +624,8 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
|
|||
}
|
||||
|
||||
conn->imc_enpub = enpub;
|
||||
conn->imc_created = packet_in->pi_received;
|
||||
conn->imc_expire = packet_in->pi_received +
|
||||
enpub->enp_settings.es_handshake_to;
|
||||
if (enpub->enp_settings.es_base_plpmtu)
|
||||
conn->imc_path.np_pack_size = enpub->enp_settings.es_base_plpmtu;
|
||||
else if (is_ipv4)
|
||||
|
@ -576,8 +652,22 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
|
|||
}
|
||||
#endif
|
||||
|
||||
conn->imc_long_header_sz = 1 /* Type */
|
||||
+ 4 /* Version */
|
||||
+ 1 /* DCIL */
|
||||
+ conn->imc_path.np_dcid.len
|
||||
+ 1 /* SCIL */
|
||||
+ CN_SCID(&conn->imc_conn)->len
|
||||
+ 0 /* HSK packet by server has no token */
|
||||
+ 2 /* Always use two bytes to encode payload length */
|
||||
+ 1 /* mini conn packet number < 256 */
|
||||
+ IQUIC_TAG_LEN
|
||||
;
|
||||
conn->imc_hello_pkt_remain = conn->imc_path.np_pack_size
|
||||
- conn->imc_long_header_sz - 1 /* token len */;
|
||||
|
||||
LSQ_DEBUG("created mini connection object %p; max packet size=%hu",
|
||||
conn, conn->imc_path.np_pack_size);
|
||||
conn, conn->imc_path.np_pack_size);
|
||||
return &conn->imc_conn;
|
||||
}
|
||||
|
||||
|
@ -679,7 +769,8 @@ ietf_mini_conn_ci_is_tickable (struct lsquic_conn *lconn)
|
|||
const struct lsquic_packet_out *packet_out;
|
||||
size_t packet_size;
|
||||
|
||||
if (conn->imc_enpub->enp_flags & ENPUB_CAN_SEND)
|
||||
if ((conn->imc_enpub->enp_flags & ENPUB_CAN_SEND)
|
||||
&& !(conn->imc_flags & IMC_AMP_CAPPED))
|
||||
TAILQ_FOREACH(packet_out, &conn->imc_packets_out, po_next)
|
||||
if (!(packet_out->po_flags & PO_SENT))
|
||||
{
|
||||
|
@ -700,18 +791,117 @@ imico_can_send (const struct ietf_mini_conn *conn, size_t size)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
imico_zero_pad (struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
size_t pad_size;
|
||||
// static void
|
||||
// imico_zero_pad (struct lsquic_packet_out *packet_out)
|
||||
// {
|
||||
// size_t pad_size;
|
||||
//
|
||||
// pad_size = lsquic_packet_out_avail(packet_out);
|
||||
// memset(packet_out->po_data + packet_out->po_data_sz, 0, pad_size);
|
||||
// packet_out->po_padding_sz = pad_size;
|
||||
// packet_out->po_data_sz += pad_size;
|
||||
// packet_out->po_frame_types |= QUIC_FTBIT_PADDING;
|
||||
// }
|
||||
|
||||
pad_size = lsquic_packet_out_avail(packet_out);
|
||||
memset(packet_out->po_data + packet_out->po_data_sz, 0, pad_size);
|
||||
packet_out->po_data_sz += pad_size;
|
||||
packet_out->po_frame_types |= QUIC_FTBIT_PADDING;
|
||||
|
||||
static lsquic_time_t
|
||||
imico_rechist_largest_recv (void *rechist_ctx);
|
||||
|
||||
|
||||
static int
|
||||
imico_build_ack_frame (struct ietf_mini_conn *conn, enum packnum_space pns,
|
||||
lsquic_time_t now, unsigned char *outbuf,
|
||||
size_t outbuf_sz, lsquic_packno_t *ack2ed)
|
||||
{
|
||||
struct ietf_mini_rechist rechist;
|
||||
uint64_t ecn_counts_buf[4];
|
||||
const uint64_t *ecn_counts;
|
||||
int not_used_has_missing, len;
|
||||
if (conn->imc_incoming_ecn)
|
||||
{
|
||||
ecn_counts_buf[0] = conn->imc_ecn_counts_in[pns][0];
|
||||
ecn_counts_buf[1] = conn->imc_ecn_counts_in[pns][1];
|
||||
ecn_counts_buf[2] = conn->imc_ecn_counts_in[pns][2];
|
||||
ecn_counts_buf[3] = conn->imc_ecn_counts_in[pns][3];
|
||||
ecn_counts = ecn_counts_buf;
|
||||
}
|
||||
else
|
||||
ecn_counts = NULL;
|
||||
lsquic_imico_rechist_init(&rechist, conn, pns);
|
||||
len = conn->imc_conn.cn_pf->pf_gen_ack_frame(outbuf, outbuf_sz,
|
||||
lsquic_imico_rechist_first,
|
||||
lsquic_imico_rechist_next, imico_rechist_largest_recv, &rechist,
|
||||
now, ¬_used_has_missing, ack2ed, ecn_counts);
|
||||
if (len < 0)
|
||||
{
|
||||
LSQ_WARN("could not generate ACK frame");
|
||||
return -1;
|
||||
}
|
||||
EV_LOG_GENERATED_ACK_FRAME(LSQUIC_LOG_CONN_ID, conn->imc_conn.cn_pf,
|
||||
outbuf, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
remove_ack_frame (struct ietf_mini_conn *conn,
|
||||
struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
if (packet_out->po_regen_sz == 0)
|
||||
return;
|
||||
|
||||
int l = packet_out->po_data_sz - packet_out->po_regen_sz
|
||||
- packet_out->po_padding_sz;
|
||||
memmove(packet_out->po_data ,
|
||||
packet_out->po_data + packet_out->po_regen_sz, l);
|
||||
memset(packet_out->po_data + l, 0, packet_out->po_regen_sz);
|
||||
packet_out->po_padding_sz += packet_out->po_regen_sz;
|
||||
packet_out->po_regen_sz = 0;
|
||||
}
|
||||
|
||||
|
||||
// static void
|
||||
// update_packet_ack (struct ietf_mini_conn *conn, enum packnum_space pns,
|
||||
// struct lsquic_packet_out *packet_out)
|
||||
// {
|
||||
// int len, need;
|
||||
// unsigned char outbuf[1024];
|
||||
// size_t outbuf_sz = sizeof(outbuf);
|
||||
// lsquic_packno_t ack2ed;
|
||||
//
|
||||
// len = imico_build_ack_frame(conn, pns, lsquic_time_now(), outbuf,
|
||||
// outbuf_sz, &ack2ed);
|
||||
// if (len > packet_out->po_regen_sz + packet_out->po_padding_sz)
|
||||
// return;
|
||||
// need = len + !!(packet_out->po_frame_types & (1 << QUIC_FRAME_PING));
|
||||
// LSQ_DEBUG("update leading ACK frame for packet %"PRIu64
|
||||
// ", regen_sz: %hd, padding_sz: %hd, need: %d, len: %d",
|
||||
// packet_out->po_packno, packet_out->po_regen_sz,
|
||||
// packet_out->po_padding_sz, need, len);
|
||||
//
|
||||
// if (need != packet_out->po_regen_sz)
|
||||
// {
|
||||
// int l = packet_out->po_data_sz - packet_out->po_regen_sz
|
||||
// - packet_out->po_padding_sz;
|
||||
// memmove(packet_out->po_data + need,
|
||||
// packet_out->po_data + packet_out->po_regen_sz, l);
|
||||
// if (packet_out->po_padding_sz)
|
||||
// {
|
||||
// if (need < packet_out->po_regen_sz)
|
||||
// memset(packet_out->po_data + need + l, 0,
|
||||
// packet_out->po_regen_sz - need);
|
||||
// packet_out->po_padding_sz += packet_out->po_regen_sz - need;
|
||||
// }
|
||||
// else
|
||||
// packet_out->po_data_sz -= packet_out->po_regen_sz - need;
|
||||
// packet_out->po_regen_sz = need;
|
||||
// }
|
||||
// memmove(packet_out->po_data, outbuf, len);
|
||||
// packet_out->po_frame_types |= 1 << QUIC_FRAME_ACK;
|
||||
// packet_out->po_ack2ed = ack2ed;
|
||||
// }
|
||||
|
||||
|
||||
static struct lsquic_packet_out *
|
||||
ietf_mini_conn_ci_next_packet_to_send (struct lsquic_conn *lconn,
|
||||
const struct to_coal *to_coal)
|
||||
|
@ -729,11 +919,31 @@ ietf_mini_conn_ci_next_packet_to_send (struct lsquic_conn *lconn,
|
|||
" ack-eliciting Initial packets to at least the smallest allowed
|
||||
" maximum datagram size of 1200 bytes.
|
||||
*/
|
||||
if (packet_out->po_header_type == HETY_INITIAL
|
||||
&& !(packet_out->po_frame_types & (1 << QUIC_FRAME_PADDING))
|
||||
&& (packet_out->po_frame_types & IQUIC_FRAME_ACKABLE_MASK)
|
||||
&& lsquic_packet_out_avail(packet_out) > 0)
|
||||
imico_zero_pad(packet_out);
|
||||
if (packet_out->po_header_type == HETY_INITIAL)
|
||||
{
|
||||
if (packet_out->po_frame_types & (1 << QUIC_FRAME_ACK)
|
||||
&& packet_out->po_retx_cnt > 0)
|
||||
{
|
||||
remove_ack_frame(conn, packet_out);
|
||||
}
|
||||
|
||||
if (packet_out->po_retx_cnt > 0
|
||||
&& !imico_can_send(conn, IQUIC_MAX_IPv4_PACKET_SZ))
|
||||
{
|
||||
conn->imc_flags |= IMC_AMP_CAPPED;
|
||||
LSQ_DEBUG("cannot send INIT packet #%"PRIu64" without "
|
||||
"enough quota", packet_out->po_packno);
|
||||
return NULL;
|
||||
}
|
||||
// if (!(packet_out->po_frame_types & (1 << QUIC_FRAME_PADDING))
|
||||
// && (packet_out->po_frame_types & IQUIC_FRAME_ACKABLE_MASK)
|
||||
// && lsquic_packet_out_avail(packet_out) > 0)
|
||||
// {
|
||||
// LSQ_DEBUG("generated PADDING frame: %hd bytes for packet %"PRIu64,
|
||||
// lsquic_packet_out_avail(packet_out), packet_out->po_packno);
|
||||
// imico_zero_pad(packet_out);
|
||||
// }
|
||||
}
|
||||
packet_size = lsquic_packet_out_total_sz(lconn, packet_out);
|
||||
if (!(to_coal
|
||||
&& (packet_size + to_coal->prev_sz_sum
|
||||
|
@ -743,6 +953,7 @@ ietf_mini_conn_ci_next_packet_to_send (struct lsquic_conn *lconn,
|
|||
{
|
||||
if (!imico_can_send(conn, packet_size))
|
||||
{
|
||||
conn->imc_flags |= IMC_AMP_CAPPED;
|
||||
LSQ_DEBUG("cannot send packet %"PRIu64" of size %zu: client "
|
||||
"address has not been validated", packet_out->po_packno,
|
||||
packet_size);
|
||||
|
@ -778,7 +989,7 @@ imico_calc_retx_timeout (const struct ietf_mini_conn *conn)
|
|||
}
|
||||
else
|
||||
to = 300000;
|
||||
return to << conn->imc_hsk_count;
|
||||
return to;
|
||||
}
|
||||
|
||||
|
||||
|
@ -789,23 +1000,20 @@ ietf_mini_conn_ci_next_tick_time (struct lsquic_conn *lconn, unsigned *why)
|
|||
const struct lsquic_packet_out *packet_out;
|
||||
lsquic_time_t exp_time, retx_time;
|
||||
|
||||
exp_time = conn->imc_created +
|
||||
conn->imc_enpub->enp_settings.es_handshake_to;
|
||||
exp_time = conn->imc_expire;
|
||||
|
||||
TAILQ_FOREACH(packet_out, &conn->imc_packets_out, po_next)
|
||||
if (packet_out->po_flags & PO_SENT)
|
||||
{
|
||||
retx_time = packet_out->po_sent + imico_calc_retx_timeout(conn);
|
||||
retx_time = packet_out->po_sent + (imico_calc_retx_timeout(conn)
|
||||
<< (packet_out->po_retx_cnt >> 1));
|
||||
if (retx_time < exp_time)
|
||||
{
|
||||
*why = N_AEWS + AL_RETX_HSK;
|
||||
return retx_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
*why = AEW_MINI_EXPIRE;
|
||||
return exp_time;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*why = AEW_MINI_EXPIRE;
|
||||
|
@ -1092,6 +1300,7 @@ static unsigned
|
|||
imico_process_ping_frame (IMICO_PROC_FRAME_ARGS)
|
||||
{
|
||||
LSQ_DEBUG("got a PING frame, do nothing");
|
||||
EV_LOG_PING_FRAME_IN(LSQUIC_LOG_CONN_ID);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1136,6 +1345,17 @@ imico_process_invalid_frame (IMICO_PROC_FRAME_ARGS)
|
|||
}
|
||||
|
||||
|
||||
static unsigned
|
||||
imico_process_invalid_frame_pv (IMICO_PROC_FRAME_ARGS)
|
||||
{
|
||||
LSQ_DEBUG("invalid frame %u (%s)", p[0],
|
||||
frame_type_2_str[ conn->imc_conn.cn_pf->pf_parse_frame_type(p, len) ]);
|
||||
ietf_mini_conn_ci_abort_error(&conn->imc_conn, 0, TEC_PROTOCOL_VIOLATION,
|
||||
"protocol violation detected while processing frame");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned (*const imico_process_frames[N_QUIC_FRAMES])
|
||||
(IMICO_PROC_FRAME_ARGS) =
|
||||
{
|
||||
|
@ -1154,13 +1374,15 @@ static unsigned (*const imico_process_frames[N_QUIC_FRAMES])
|
|||
[QUIC_FRAME_BLOCKED] = imico_process_invalid_frame,
|
||||
[QUIC_FRAME_STREAM_BLOCKED] = imico_process_invalid_frame,
|
||||
[QUIC_FRAME_STREAMS_BLOCKED] = imico_process_invalid_frame,
|
||||
[QUIC_FRAME_NEW_CONNECTION_ID] = imico_process_invalid_frame,
|
||||
[QUIC_FRAME_NEW_CONNECTION_ID] = imico_process_invalid_frame_pv,
|
||||
[QUIC_FRAME_STOP_SENDING] = imico_process_invalid_frame,
|
||||
[QUIC_FRAME_PATH_CHALLENGE] = imico_process_invalid_frame,
|
||||
[QUIC_FRAME_PATH_RESPONSE] = imico_process_invalid_frame,
|
||||
/* STREAM frame can only come in the App PNS and we delay those packets: */
|
||||
[QUIC_FRAME_STREAM] = imico_process_invalid_frame,
|
||||
[QUIC_FRAME_HANDSHAKE_DONE] = imico_process_invalid_frame,
|
||||
[QUIC_FRAME_RETIRE_CONNECTION_ID] = imico_process_invalid_frame_pv,
|
||||
[QUIC_FRAME_NEW_TOKEN] = imico_process_invalid_frame_pv,
|
||||
[QUIC_FRAME_HANDSHAKE_DONE] = imico_process_invalid_frame_pv,
|
||||
[QUIC_FRAME_ACK_FREQUENCY] = imico_process_invalid_frame,
|
||||
[QUIC_FRAME_TIMESTAMP] = imico_process_invalid_frame,
|
||||
};
|
||||
|
@ -1185,6 +1407,16 @@ imico_process_packet_frame (struct ietf_mini_conn *conn,
|
|||
{
|
||||
LSQ_DEBUG("invalid frame %u at encryption level %s", type,
|
||||
lsquic_enclev2str[enc_level]);
|
||||
if (type == QUIC_FRAME_INVALID)
|
||||
ietf_mini_conn_ci_abort_error(&conn->imc_conn, 0,
|
||||
TEC_FRAME_ENCODING_ERROR,
|
||||
"invalid frame %u at encryption level %s",
|
||||
type, lsquic_enclev2str[enc_level]);
|
||||
else
|
||||
ietf_mini_conn_ci_abort_error(&conn->imc_conn, 0,
|
||||
TEC_PROTOCOL_VIOLATION,
|
||||
"protcol violation for invalid frame %u at encryption level %s",
|
||||
type, lsquic_enclev2str[enc_level]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1258,6 +1490,15 @@ ignore_init (struct ietf_mini_conn *conn)
|
|||
|
||||
LSQ_DEBUG("henceforth, no Initial packets shall be sent or received; "
|
||||
"destroyed %u packet%.*s", count, count != 1, "s");
|
||||
|
||||
int ext_to = conn->imc_enpub->enp_settings.es_idle_timeout * 1000000
|
||||
- conn->imc_enpub->enp_settings.es_handshake_to;
|
||||
if (ext_to > 0)
|
||||
{
|
||||
conn->imc_expire += ext_to;
|
||||
LSQ_DEBUG("extend mini-conn expire time to %d seconds",
|
||||
conn->imc_enpub->enp_settings.es_idle_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1397,6 +1638,10 @@ imico_switch_to_trechist (struct ietf_mini_conn *conn)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
imico_generate_handshake_done (struct ietf_mini_conn *conn);
|
||||
|
||||
|
||||
/* Only a single packet is supported */
|
||||
static void
|
||||
ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn,
|
||||
|
@ -1416,6 +1661,7 @@ ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn,
|
|||
" that contain packets that are all discarded.
|
||||
*/
|
||||
conn->imc_bytes_in += packet_in->pi_data_sz;
|
||||
conn->imc_flags &= ~IMC_AMP_CAPPED;
|
||||
|
||||
if (conn->imc_flags & IMC_ERROR)
|
||||
{
|
||||
|
@ -1446,6 +1692,15 @@ ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn,
|
|||
case DECPI_NOT_YET:
|
||||
imico_maybe_delay_processing(conn, packet_in);
|
||||
return;
|
||||
case DECPI_BADCRYPT:
|
||||
if (packet_in->pi_flags & PI_FIRST_INIT)
|
||||
{
|
||||
LSQ_DEBUG("possible packet corruption, destroy mini-conn.");
|
||||
conn->imc_flags |= IMC_ERROR | IMC_CLOSE_RECVD;
|
||||
/* avoid adding CID to black list */
|
||||
conn->imc_conn.cn_flags |= LSCONN_NO_BL;
|
||||
}
|
||||
//fall through
|
||||
default:
|
||||
LSQ_DEBUG("could not decrypt packet");
|
||||
return;
|
||||
|
@ -1491,19 +1746,28 @@ ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn,
|
|||
conn->imc_largest_recvd[pns] = packet_in->pi_received;
|
||||
imico_record_recvd_packno(conn, pns, packet_in->pi_packno);
|
||||
|
||||
if (!(conn->imc_flags & (IMC_QUEUED_ACK_INIT << pns)))
|
||||
{
|
||||
LSQ_DEBUG("queued ACK in %s", lsquic_pns2str[pns]);
|
||||
conn->imc_flags |= IMC_QUEUED_ACK_INIT << pns;
|
||||
}
|
||||
++conn->imc_ecn_counts_in[pns][ lsquic_packet_in_ecn(packet_in) ];
|
||||
conn->imc_incoming_ecn <<= 1;
|
||||
conn->imc_incoming_ecn |= lsquic_packet_in_ecn(packet_in) != ECN_NOT_ECT;
|
||||
|
||||
if (0 != imico_parse_regular_packet(conn, packet_in))
|
||||
{
|
||||
LSQ_DEBUG("connection is now in error state");
|
||||
conn->imc_flags |= IMC_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(conn->imc_flags & (IMC_QUEUED_ACK_INIT << pns)))
|
||||
LSQ_DEBUG("queued ACK in %s", lsquic_pns2str[pns]);
|
||||
conn->imc_flags |= IMC_QUEUED_ACK_INIT << pns;
|
||||
++conn->imc_ecn_counts_in[pns][ lsquic_packet_in_ecn(packet_in) ];
|
||||
conn->imc_incoming_ecn <<= 1;
|
||||
conn->imc_incoming_ecn |= lsquic_packet_in_ecn(packet_in) != ECN_NOT_ECT;
|
||||
if (conn->imc_flags & IMC_HSK_OK)
|
||||
{
|
||||
if (lconn->cn_esf.i->esfi_in_init(lconn->cn_enc_session))
|
||||
LSQ_DEBUG("still in init, defer HANDSHAKE_DONE");
|
||||
else if (0 != imico_generate_handshake_done(conn))
|
||||
conn->imc_flags |= IMC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1563,12 +1827,11 @@ imico_repackage_packet (struct ietf_mini_conn *conn,
|
|||
if (packno > MAX_PACKETS)
|
||||
return -1;
|
||||
|
||||
LSQ_DEBUG("Packet %"PRIu64" repackaged for resending as packet %"PRIu64,
|
||||
oldno, packno);
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "packet %"PRIu64" repackaged for "
|
||||
"resending as packet %"PRIu64, oldno, packno);
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "schedule resend, repackage packet "
|
||||
"#%"PRIu64" -> #%"PRIu64, oldno, packno);
|
||||
packet_out->po_packno = packno;
|
||||
packet_out->po_flags &= ~PO_SENT;
|
||||
++packet_out->po_retx_cnt;
|
||||
lsquic_packet_out_set_ecn(packet_out, imico_get_ecn(conn));
|
||||
if (packet_out->po_flags & PO_ENCRYPTED)
|
||||
imico_return_enc_data(conn, packet_out);
|
||||
|
@ -1595,14 +1858,26 @@ imico_handle_losses_and_have_unsent (struct ietf_mini_conn *conn,
|
|||
next = TAILQ_NEXT(packet_out, po_next);
|
||||
if (packet_out->po_flags & PO_SENT)
|
||||
{
|
||||
if (0 == retx_to)
|
||||
retx_to = imico_calc_retx_timeout(conn);
|
||||
if (packet_out->po_sent + retx_to < now)
|
||||
if (packet_out->po_frame_types & IQUIC_FRAME_RETX_MASK)
|
||||
{
|
||||
if (0 == retx_to)
|
||||
retx_to = imico_calc_retx_timeout(conn);
|
||||
if (conn->imc_hsk_count == 0)
|
||||
packet_out->po_retx_cnt = 0;
|
||||
if (packet_out->po_sent
|
||||
+ (retx_to << (packet_out->po_retx_cnt >> 1)) < now)
|
||||
{
|
||||
LSQ_DEBUG("packet %"PRIu64" has been lost (rto: %"PRIu64")",
|
||||
packet_out->po_packno,
|
||||
retx_to << (packet_out->po_retx_cnt >> 1));
|
||||
TAILQ_REMOVE(&conn->imc_packets_out, packet_out, po_next);
|
||||
TAILQ_INSERT_TAIL(&lost_packets, packet_out, po_next);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_DEBUG("packet %"PRIu64" has been lost (rto: %"PRIu64")",
|
||||
packet_out->po_packno, retx_to);
|
||||
TAILQ_REMOVE(&conn->imc_packets_out, packet_out, po_next);
|
||||
TAILQ_INSERT_TAIL(&lost_packets, packet_out, po_next);
|
||||
imico_destroy_packet(conn, packet_out);
|
||||
}
|
||||
}
|
||||
else if (packet_size = lsquic_packet_out_total_sz(lconn, packet_out),
|
||||
|
@ -1617,8 +1892,7 @@ imico_handle_losses_and_have_unsent (struct ietf_mini_conn *conn,
|
|||
while ((packet_out = TAILQ_FIRST(&lost_packets)))
|
||||
{
|
||||
TAILQ_REMOVE(&lost_packets, packet_out, po_next);
|
||||
if ((packet_out->po_frame_types & IQUIC_FRAME_RETX_MASK)
|
||||
&& 0 == imico_repackage_packet(conn, packet_out))
|
||||
if (0 == imico_repackage_packet(conn, packet_out))
|
||||
{
|
||||
packet_size = lsquic_packet_out_total_sz(lconn, packet_out);
|
||||
if (imico_can_send(conn, packet_size))
|
||||
|
@ -1738,57 +2012,58 @@ static const enum header_type pns2hety[] =
|
|||
{
|
||||
[PNS_INIT] = HETY_INITIAL,
|
||||
[PNS_HSK] = HETY_HANDSHAKE,
|
||||
[PNS_APP] = HETY_NOT_SET,
|
||||
[PNS_APP] = HETY_SHORT,
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
imico_generate_ping (struct ietf_mini_conn *conn,
|
||||
struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
int len;
|
||||
len = conn->imc_conn.cn_pf->pf_gen_ping_frame(
|
||||
packet_out->po_data + packet_out->po_data_sz,
|
||||
lsquic_packet_out_avail(packet_out));
|
||||
if (len > 0)
|
||||
{
|
||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_PING;
|
||||
packet_out->po_data_sz += len;
|
||||
packet_out->po_regen_sz += len;
|
||||
LSQ_DEBUG("wrote PING frame of size %d to packet %" PRIu64,
|
||||
len, packet_out->po_packno);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
imico_generate_ack (struct ietf_mini_conn *conn, enum packnum_space pns,
|
||||
lsquic_time_t now)
|
||||
{
|
||||
struct lsquic_packet_out *packet_out;
|
||||
enum header_type header_type;
|
||||
struct ietf_mini_rechist rechist;
|
||||
int not_used_has_missing, len;
|
||||
uint64_t ecn_counts_buf[4];
|
||||
const uint64_t *ecn_counts;
|
||||
int len;
|
||||
|
||||
header_type = pns2hety[pns];
|
||||
|
||||
if (conn->imc_incoming_ecn)
|
||||
{
|
||||
ecn_counts_buf[0] = conn->imc_ecn_counts_in[pns][0];
|
||||
ecn_counts_buf[1] = conn->imc_ecn_counts_in[pns][1];
|
||||
ecn_counts_buf[2] = conn->imc_ecn_counts_in[pns][2];
|
||||
ecn_counts_buf[3] = conn->imc_ecn_counts_in[pns][3];
|
||||
ecn_counts = ecn_counts_buf;
|
||||
}
|
||||
else
|
||||
ecn_counts = NULL;
|
||||
|
||||
packet_out = imico_get_packet_out(conn, header_type, 0);
|
||||
if (!packet_out)
|
||||
return -1;
|
||||
|
||||
/* Generate ACK frame */
|
||||
lsquic_imico_rechist_init(&rechist, conn, pns);
|
||||
len = conn->imc_conn.cn_pf->pf_gen_ack_frame(
|
||||
packet_out->po_data + packet_out->po_data_sz,
|
||||
lsquic_packet_out_avail(packet_out), lsquic_imico_rechist_first,
|
||||
lsquic_imico_rechist_next, imico_rechist_largest_recv, &rechist,
|
||||
now, ¬_used_has_missing, &packet_out->po_ack2ed, ecn_counts);
|
||||
len = imico_build_ack_frame(conn, pns, now,
|
||||
packet_out->po_data + packet_out->po_data_sz,
|
||||
lsquic_packet_out_avail(packet_out),
|
||||
&packet_out->po_ack2ed);
|
||||
if (len < 0)
|
||||
{
|
||||
LSQ_WARN("could not generate ACK frame");
|
||||
return -1;
|
||||
}
|
||||
EV_LOG_GENERATED_ACK_FRAME(LSQUIC_LOG_CONN_ID, conn->imc_conn.cn_pf,
|
||||
packet_out->po_data + packet_out->po_data_sz, len);
|
||||
|
||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_ACK;
|
||||
packet_out->po_data_sz += len;
|
||||
packet_out->po_regen_sz += len;
|
||||
conn->imc_flags &= ~(IMC_QUEUED_ACK_INIT << pns);
|
||||
LSQ_DEBUG("wrote ACK frame of size %d in %s", len, lsquic_pns2str[pns]);
|
||||
LSQ_DEBUG("wrote ACK frame of size %d in %s to packet %" PRIu64,
|
||||
len, lsquic_pns2str[pns], packet_out->po_packno);
|
||||
if (pns == PNS_INIT && conn->imc_hsk_count > 0)
|
||||
imico_generate_ping(conn, packet_out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1801,9 +2076,10 @@ imico_generate_acks (struct ietf_mini_conn *conn, lsquic_time_t now)
|
|||
for (pns = PNS_INIT; pns < IMICO_N_PNS; ++pns)
|
||||
if (conn->imc_flags & (IMC_QUEUED_ACK_INIT << pns)
|
||||
&& !(pns == PNS_INIT && (conn->imc_flags & IMC_IGNORE_INIT)))
|
||||
{
|
||||
if (0 != imico_generate_ack(conn, pns, now))
|
||||
return -1;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1848,6 +2124,13 @@ imico_generate_conn_close (struct ietf_mini_conn *conn)
|
|||
reason = "bad transport parameters";
|
||||
rlen = 24;
|
||||
}
|
||||
else if (conn->imc_flags & IMC_VER_NEG_FAILED)
|
||||
{
|
||||
is_app = 0;
|
||||
error_code = TEC_VERSION_NEGOTIATION_ERROR;
|
||||
reason = "version negociation failed";
|
||||
rlen = 26;
|
||||
}
|
||||
else if (conn->imc_flags & IMC_HSK_FAILED)
|
||||
{
|
||||
is_app = 0;
|
||||
|
@ -1953,7 +2236,7 @@ imico_generate_handshake_done (struct ietf_mini_conn *conn)
|
|||
int sz;
|
||||
|
||||
need = conn->imc_conn.cn_pf->pf_handshake_done_frame_size();
|
||||
packet_out = imico_get_packet_out(conn, HETY_NOT_SET, need);
|
||||
packet_out = imico_get_packet_out(conn, HETY_SHORT, need);
|
||||
if (!packet_out)
|
||||
return -1;
|
||||
sz = conn->imc_conn.cn_pf->pf_gen_handshake_done_frame(
|
||||
|
@ -1980,12 +2263,20 @@ ietf_mini_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
|
|||
struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
|
||||
enum tick_st tick;
|
||||
|
||||
if (conn->imc_created + conn->imc_enpub->enp_settings.es_handshake_to < now)
|
||||
if (conn->imc_expire < now)
|
||||
{
|
||||
LSQ_DEBUG("connection expired: closing");
|
||||
return TICK_CLOSE;
|
||||
}
|
||||
|
||||
if (!(conn->imc_flags &
|
||||
(IMC_HAVE_TP|IMC_ADDR_VALIDATED|IMC_BAD_TRANS_PARAMS))
|
||||
&& conn->imc_enpub->enp_settings.es_support_srej)
|
||||
{
|
||||
LSQ_DEBUG("Peer not validated and do not have transport parameters "
|
||||
"on the first tick: retry");
|
||||
return TICK_RETRY|TICK_CLOSE;
|
||||
}
|
||||
|
||||
if (conn->imc_flags & (IMC_QUEUED_ACK_INIT|IMC_QUEUED_ACK_HSK))
|
||||
{
|
||||
|
@ -1997,6 +2288,9 @@ ietf_mini_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
|
|||
}
|
||||
|
||||
|
||||
if (lconn->cn_flags & (LSCONN_PROMOTED|LSCONN_PROMOTE_FAIL))
|
||||
return TICK_CLOSE;
|
||||
|
||||
tick = 0;
|
||||
|
||||
if (conn->imc_flags & IMC_ERROR)
|
||||
|
@ -2131,6 +2425,7 @@ ietf_mini_conn_ci_count_garbage (struct lsquic_conn *lconn, size_t garbage_sz)
|
|||
struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
|
||||
|
||||
conn->imc_bytes_in += garbage_sz;
|
||||
conn->imc_flags &= ~IMC_AMP_CAPPED;
|
||||
LSQ_DEBUG("count %zd bytes of garbage, new value: %u bytes", garbage_sz,
|
||||
conn->imc_bytes_in);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#ifndef LSQUIC_MINI_CONN_IETF_H
|
||||
#define LSQUIC_MINI_CONN_IETF_H 1
|
||||
|
||||
#include "lsquic_ietf.h"
|
||||
|
||||
struct lsquic_conn;
|
||||
struct lsquic_engine_public;
|
||||
struct lsquic_packet_in;
|
||||
|
@ -32,14 +34,13 @@ typedef uint64_t packno_set_t;
|
|||
* connection is promoted. This means we do not have to have data
|
||||
* structures to track the App PNS.
|
||||
*/
|
||||
#define IMICO_N_PNS (N_PNS - 1)
|
||||
|
||||
struct ietf_mini_conn
|
||||
{
|
||||
struct lsquic_conn imc_conn;
|
||||
struct conn_cid_elem imc_cces[3];
|
||||
struct lsquic_engine_public *imc_enpub;
|
||||
lsquic_time_t imc_created;
|
||||
lsquic_time_t imc_expire;
|
||||
enum {
|
||||
IMC_ENC_SESS_INITED = 1 << 0,
|
||||
IMC_QUEUED_ACK_INIT = 1 << 1,
|
||||
|
@ -66,6 +67,8 @@ struct ietf_mini_conn
|
|||
IMC_PATH_CHANGED = 1 << 21,
|
||||
IMC_HSK_DONE_SENT = 1 << 22,
|
||||
IMC_TRECHIST = 1 << 23,
|
||||
IMC_VER_NEG_FAILED = 1 << 24,
|
||||
IMC_AMP_CAPPED = 1 << 25,
|
||||
} imc_flags;
|
||||
struct mini_crypto_stream imc_streams[N_ENC_LEVS];
|
||||
void *imc_stream_ps[N_ENC_LEVS];
|
||||
|
@ -87,7 +90,7 @@ struct ietf_mini_conn
|
|||
packno_set_t imc_acked_packnos[IMICO_N_PNS];
|
||||
lsquic_time_t imc_largest_recvd[IMICO_N_PNS];
|
||||
struct lsquic_rtt_stats imc_rtt_stats;
|
||||
unsigned imc_error_code;
|
||||
enum trans_error_code imc_error_code;
|
||||
unsigned imc_bytes_in;
|
||||
unsigned imc_bytes_out;
|
||||
unsigned short imc_crypto_frames_sz;
|
||||
|
@ -112,6 +115,8 @@ struct ietf_mini_conn
|
|||
unsigned char imc_delayed_packets_count;
|
||||
#define IMICO_MAX_STASHED_FRAMES 10u
|
||||
unsigned char imc_n_crypto_frames;
|
||||
unsigned short imc_hello_pkt_remain;
|
||||
unsigned char imc_long_header_sz;
|
||||
struct network_path imc_path;
|
||||
};
|
||||
|
||||
|
@ -128,7 +133,7 @@ struct ietf_mini_conn
|
|||
|
||||
struct lsquic_conn *
|
||||
lsquic_mini_conn_ietf_new (struct lsquic_engine_public *,
|
||||
const struct lsquic_packet_in *,
|
||||
struct lsquic_packet_in *,
|
||||
enum lsquic_version, int is_ipv4, const struct lsquic_cid *,
|
||||
size_t udp_payload_size);
|
||||
|
||||
|
|
|
@ -49,11 +49,11 @@ lsquic_frame_types_to_str (char *buf, size_t bufsz,
|
|||
|
||||
const char *const lsquic_hety2str[] =
|
||||
{
|
||||
[HETY_NOT_SET] = "Short",
|
||||
[HETY_VERNEG] = "Version Negotiation",
|
||||
[HETY_INITIAL] = "Initial",
|
||||
[HETY_RETRY] = "Retry",
|
||||
[HETY_HANDSHAKE] = "Handshake",
|
||||
[HETY_SHORT] = "SHORT",
|
||||
[HETY_VERNEG] = "VERNEG",
|
||||
[HETY_INITIAL] = "INIT",
|
||||
[HETY_RETRY] = "RETRY",
|
||||
[HETY_HANDSHAKE] = "HSK",
|
||||
[HETY_0RTT] = "0-RTT",
|
||||
};
|
||||
|
||||
|
@ -61,7 +61,7 @@ const char *const lsquic_hety2str[] =
|
|||
/* [draft-ietf-quic-tls-14], Section 4 */
|
||||
const enum packnum_space lsquic_hety2pns[] =
|
||||
{
|
||||
[HETY_NOT_SET] = PNS_APP,
|
||||
[HETY_SHORT] = PNS_APP,
|
||||
[HETY_VERNEG] = 0,
|
||||
[HETY_INITIAL] = PNS_INIT,
|
||||
[HETY_RETRY] = 0,
|
||||
|
@ -73,16 +73,16 @@ const enum packnum_space lsquic_hety2pns[] =
|
|||
/* [draft-ietf-quic-tls-14], Section 4 */
|
||||
const enum packnum_space lsquic_enclev2pns[] =
|
||||
{
|
||||
[ENC_LEV_CLEAR] = PNS_INIT,
|
||||
[ENC_LEV_INIT] = PNS_HSK,
|
||||
[ENC_LEV_EARLY] = PNS_APP,
|
||||
[ENC_LEV_FORW] = PNS_APP,
|
||||
[ENC_LEV_INIT] = PNS_INIT,
|
||||
[ENC_LEV_HSK] = PNS_HSK,
|
||||
[ENC_LEV_0RTT] = PNS_APP,
|
||||
[ENC_LEV_APP] = PNS_APP,
|
||||
};
|
||||
|
||||
|
||||
const char *const lsquic_pns2str[] =
|
||||
{
|
||||
[PNS_INIT] = "Init PNS",
|
||||
[PNS_HSK] = "Handshake PNS",
|
||||
[PNS_APP] = "App PNS",
|
||||
[PNS_INIT] = "INIT pns",
|
||||
[PNS_HSK] = "HSK pns",
|
||||
[PNS_APP] = "APP pns",
|
||||
};
|
||||
|
|
|
@ -176,7 +176,8 @@ enum
|
|||
|
||||
enum header_type
|
||||
{
|
||||
HETY_NOT_SET, /* This value must be zero */
|
||||
HETY_NOT_SET, /* This value must be zero */
|
||||
HETY_SHORT = HETY_NOT_SET, /* This value must be zero */
|
||||
HETY_VERNEG,
|
||||
HETY_INITIAL,
|
||||
HETY_RETRY,
|
||||
|
@ -197,6 +198,7 @@ enum packnum_space
|
|||
PNS_INIT,
|
||||
PNS_HSK,
|
||||
PNS_APP,
|
||||
IMICO_N_PNS = PNS_APP,
|
||||
N_PNS
|
||||
};
|
||||
|
||||
|
@ -240,8 +242,9 @@ extern const char *const lsquic_pns2str[];
|
|||
* regenerating them. This keeps the code simple(r).
|
||||
*/
|
||||
#define IQUIC_FRAME_RETX_MASK ( \
|
||||
ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_PADDING|QUIC_FTBIT_PATH_RESPONSE \
|
||||
|QUIC_FTBIT_PATH_CHALLENGE|QUIC_FTBIT_ACK|QUIC_FTBIT_TIMESTAMP))
|
||||
ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_PADDING | QUIC_FTBIT_PATH_RESPONSE \
|
||||
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_ACK \
|
||||
| QUIC_FTBIT_TIMESTAMP | QUIC_FTBIT_PING))
|
||||
|
||||
extern const enum quic_ft_bit lsquic_legal_frames_by_level[][4];
|
||||
|
||||
|
|
|
@ -88,6 +88,8 @@ typedef struct lsquic_packet_in
|
|||
PI_LOG_QL_BITS = (1 <<14),
|
||||
PI_SQUARE_BIT = (1 <<15),
|
||||
PI_LOSS_BIT = (1 <<16),
|
||||
PI_VER_PARSED = (1 <<17),
|
||||
PI_FIRST_INIT = (1 <<18),
|
||||
} pi_flags;
|
||||
/* pi_token and pi_token_size are set in Initial and Retry packets */
|
||||
unsigned short pi_token_size; /* Size of the token */
|
||||
|
@ -101,6 +103,7 @@ typedef struct lsquic_packet_in
|
|||
unsigned char pi_nonce; /* Offset to nonce */
|
||||
enum header_type pi_header_type:8;
|
||||
unsigned char pi_path_id;
|
||||
unsigned char pi_version; /* parsed enum lsquic_version */
|
||||
/* If PI_OWN_DATA flag is not set, `pi_data' points to user-supplied
|
||||
* packet data, which is NOT TO BE MODIFIED.
|
||||
*/
|
||||
|
|
|
@ -382,7 +382,7 @@ lsquic_packet_out_chop_regen (lsquic_packet_out_t *packet_out)
|
|||
}
|
||||
}
|
||||
|
||||
assert(adj); /* Otherwise why are we called? */
|
||||
//assert(adj); /* Otherwise why are we called? */
|
||||
packet_out->po_regen_sz = 0;
|
||||
packet_out->po_frame_types &= ~BQUIC_FRAME_REGEN_MASK;
|
||||
}
|
||||
|
@ -479,7 +479,7 @@ lsquic_packet_out_turn_on_fin (struct lsquic_packet_out *packet_out,
|
|||
static unsigned
|
||||
offset_to_dcid (const struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
if (packet_out->po_header_type == HETY_NOT_SET)
|
||||
if (packet_out->po_header_type == HETY_SHORT)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
|
|
|
@ -111,6 +111,8 @@ typedef struct lsquic_packet_out
|
|||
PO_SCHED = (1 <<14), /* On scheduled queue */
|
||||
PO_SENT_SZ = (1 <<15),
|
||||
PO_LONGHEAD = (1 <<16),
|
||||
PO_ACKED_LOSS_CHAIN = (1<<17),
|
||||
|
||||
#define POIPv6_SHIFT 20
|
||||
PO_IPv6 = (1 <<20), /* Set if pmi_allocate was passed is_ipv6=1,
|
||||
* otherwise unset.
|
||||
|
@ -185,6 +187,8 @@ typedef struct lsquic_packet_out
|
|||
unsigned char *po_enc_data;
|
||||
|
||||
lsquic_ver_tag_t po_ver_tag; /* Set if PO_VERSION is set */
|
||||
unsigned short po_retx_cnt;
|
||||
unsigned short po_padding_sz;
|
||||
unsigned char *po_nonce; /* Use to generate header if PO_NONCE is set */
|
||||
const struct network_path
|
||||
*po_path;
|
||||
|
|
|
@ -486,7 +486,7 @@ gquic_Q050_packout_size (const struct lsquic_conn *lconn,
|
|||
size_t sz;
|
||||
|
||||
if ((lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
&& packet_out->po_header_type == HETY_NOT_SET)
|
||||
&& packet_out->po_header_type == HETY_SHORT)
|
||||
sz = gquic_Q050_packout_header_size_short(lconn, packet_out->po_flags);
|
||||
else
|
||||
sz = gquic_Q050_packout_header_size_long_by_packet(lconn, packet_out);
|
||||
|
|
|
@ -21,26 +21,27 @@ parse_ietf_v1_or_Q046plus_long_begin (struct lsquic_packet_in *packet_in,
|
|||
size_t length, int is_server, unsigned cid_len,
|
||||
struct packin_parse_state *state)
|
||||
{
|
||||
lsquic_ver_tag_t tag;
|
||||
|
||||
if (length >= 5)
|
||||
{
|
||||
memcpy(&tag, packet_in->pi_data + 1, 4);
|
||||
switch (tag)
|
||||
{
|
||||
case TAG('Q', '0', '4', '6'):
|
||||
return lsquic_Q046_parse_packet_in_long_begin(packet_in, length,
|
||||
is_server, cid_len, state);
|
||||
case TAG('Q', '0', '5', '0'):
|
||||
return lsquic_Q050_parse_packet_in_long_begin(packet_in, length,
|
||||
is_server, cid_len, state);
|
||||
default:
|
||||
return lsquic_ietf_v1_parse_packet_in_long_begin(packet_in, length,
|
||||
is_server, cid_len, state);
|
||||
}
|
||||
}
|
||||
else
|
||||
enum lsquic_version version;
|
||||
if (length < 6)
|
||||
return -1;
|
||||
version = lsquic_tag2ver_fast(packet_in->pi_data + 1);
|
||||
if (version != N_LSQVER)
|
||||
{
|
||||
packet_in->pi_version = version;
|
||||
packet_in->pi_flags |= PI_VER_PARSED;
|
||||
}
|
||||
switch (version)
|
||||
{
|
||||
case LSQVER_046:
|
||||
return lsquic_Q046_parse_packet_in_long_begin(packet_in, length,
|
||||
is_server, cid_len, state);
|
||||
case LSQVER_050:
|
||||
return lsquic_Q050_parse_packet_in_long_begin(packet_in, length,
|
||||
is_server, cid_len, state);
|
||||
default:
|
||||
return lsquic_ietf_v1_parse_packet_in_long_begin(packet_in, length,
|
||||
is_server, cid_len, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -51,10 +52,10 @@ static int (* const parse_begin_funcs[32]) (struct lsquic_packet_in *,
|
|||
/* Xs vary, Gs are iGnored: */
|
||||
#define PBEL(mask) [(mask) >> 3]
|
||||
/* 1X11 XGGG: */
|
||||
PBEL(0x80|0x40|0x20|0x10|0x08) = lsquic_Q046_parse_packet_in_long_begin,
|
||||
PBEL(0x80|0x00|0x20|0x10|0x08) = lsquic_Q046_parse_packet_in_long_begin,
|
||||
PBEL(0x80|0x40|0x20|0x10|0x00) = lsquic_Q046_parse_packet_in_long_begin,
|
||||
PBEL(0x80|0x00|0x20|0x10|0x00) = lsquic_Q046_parse_packet_in_long_begin,
|
||||
PBEL(0x80|0x40|0x20|0x10|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
|
||||
PBEL(0x80|0x00|0x20|0x10|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
|
||||
PBEL(0x80|0x40|0x20|0x10|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
|
||||
PBEL(0x80|0x00|0x20|0x10|0x00) = parse_ietf_v1_or_Q046plus_long_begin,
|
||||
/* 1X00 XGGG: */
|
||||
PBEL(0x80|0x40|0x00|0x00|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
|
||||
PBEL(0x80|0x00|0x00|0x00|0x08) = parse_ietf_v1_or_Q046plus_long_begin,
|
||||
|
@ -336,10 +337,10 @@ lsquic_dcid_from_packet (const unsigned char *buf, size_t bufsz,
|
|||
/* See [draft-ietf-quic-transport-28], Section 12.4 (Table 3) */
|
||||
const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] =
|
||||
{
|
||||
[LSQVER_I001] = {
|
||||
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[LSQVER_I002] = {
|
||||
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_0RTT] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
||||
| QUIC_FTBIT_BLOCKED | QUIC_FTBIT_CONNECTION_CLOSE
|
||||
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
|
||||
|
@ -349,9 +350,39 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] =
|
|||
| QUIC_FTBIT_PATH_CHALLENGE
|
||||
| QUIC_FTBIT_DATAGRAM
|
||||
| QUIC_FTBIT_RETIRE_CONNECTION_ID,
|
||||
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_HSK] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK| QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_FORW] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_APP] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE
|
||||
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
||||
| QUIC_FTBIT_BLOCKED
|
||||
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
|
||||
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
|
||||
| QUIC_FTBIT_STREAMS_BLOCKED
|
||||
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
|
||||
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
|
||||
| QUIC_FTBIT_HANDSHAKE_DONE | QUIC_FTBIT_ACK_FREQUENCY
|
||||
| QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN
|
||||
| QUIC_FTBIT_TIMESTAMP
|
||||
| QUIC_FTBIT_DATAGRAM
|
||||
,
|
||||
},
|
||||
[LSQVER_I001] = {
|
||||
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_0RTT] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
||||
| QUIC_FTBIT_BLOCKED | QUIC_FTBIT_CONNECTION_CLOSE
|
||||
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
|
||||
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
|
||||
| QUIC_FTBIT_STREAMS_BLOCKED
|
||||
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
|
||||
| QUIC_FTBIT_PATH_CHALLENGE
|
||||
| QUIC_FTBIT_DATAGRAM
|
||||
| QUIC_FTBIT_RETIRE_CONNECTION_ID,
|
||||
[ENC_LEV_HSK] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK| QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_APP] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE
|
||||
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
||||
| QUIC_FTBIT_BLOCKED
|
||||
|
@ -367,9 +398,9 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] =
|
|||
,
|
||||
},
|
||||
[LSQVER_ID29] = {
|
||||
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_0RTT] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
||||
| QUIC_FTBIT_BLOCKED | QUIC_FTBIT_CONNECTION_CLOSE
|
||||
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
|
||||
|
@ -379,9 +410,9 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] =
|
|||
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
|
||||
| QUIC_FTBIT_DATAGRAM
|
||||
| QUIC_FTBIT_RETIRE_CONNECTION_ID,
|
||||
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_HSK] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK| QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_FORW] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_APP] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE
|
||||
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
||||
| QUIC_FTBIT_BLOCKED
|
||||
|
@ -397,9 +428,9 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] =
|
|||
,
|
||||
},
|
||||
[LSQVER_ID27] = {
|
||||
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_0RTT] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
||||
| QUIC_FTBIT_BLOCKED
|
||||
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
|
||||
|
@ -410,9 +441,9 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] =
|
|||
| QUIC_FTBIT_RETIRE_CONNECTION_ID
|
||||
| QUIC_FTBIT_DATAGRAM
|
||||
,
|
||||
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_HSK] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK| QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_FORW] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
[ENC_LEV_APP] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE
|
||||
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
||||
| QUIC_FTBIT_BLOCKED
|
||||
|
|
|
@ -68,6 +68,11 @@ int
|
|||
lsquic_ietf_v1_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz,
|
||||
const lsquic_cid_t *scid, const lsquic_cid_t *dcid, unsigned versions,
|
||||
uint8_t);
|
||||
int
|
||||
lsquic_iquic_gen_retry_pkt (unsigned char *buf, size_t bufsz,
|
||||
const struct lsquic_engine_public *, const lsquic_cid_t *scid,
|
||||
const lsquic_cid_t *dcid, enum lsquic_version, const struct sockaddr *,
|
||||
uint8_t random_nybble);
|
||||
|
||||
#define GQUIC_RESET_SZ 33
|
||||
ssize_t
|
||||
|
|
|
@ -142,7 +142,7 @@ ietf_v1_packout_max_header_size (const struct lsquic_conn *lconn,
|
|||
enum packet_out_flags flags, size_t dcid_len, enum header_type header_type)
|
||||
{
|
||||
if ((lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
&& header_type == HETY_NOT_SET)
|
||||
&& header_type == HETY_SHORT)
|
||||
return ietf_v1_packout_header_size_short(flags, dcid_len);
|
||||
else
|
||||
return ietf_v1_packout_header_size_long_by_flags(lconn, header_type,
|
||||
|
@ -159,6 +159,15 @@ static const unsigned char header_type_to_bin[] = {
|
|||
};
|
||||
|
||||
|
||||
/* [draft-ietf-quic-v2] Section-3.2 */
|
||||
static const unsigned char header_type_to_bin_v2[] = {
|
||||
[HETY_INITIAL] = 0x1,
|
||||
[HETY_0RTT] = 0x2,
|
||||
[HETY_HANDSHAKE] = 0x3,
|
||||
[HETY_RETRY] = 0x0,
|
||||
};
|
||||
|
||||
|
||||
static unsigned
|
||||
write_packno (unsigned char *p, lsquic_packno_t packno,
|
||||
enum packno_bits bits)
|
||||
|
@ -205,10 +214,16 @@ gen_long_pkt_header (const struct lsquic_conn *lconn,
|
|||
|
||||
packno_bits = lsquic_packet_out_packno_bits(packet_out);
|
||||
p = buf;
|
||||
*p++ = 0xC0
|
||||
| ( header_type_to_bin[ packet_out->po_header_type ] << 4)
|
||||
| packno_bits
|
||||
;
|
||||
if (lconn->cn_version == LSQVER_I002)
|
||||
*p++ = 0xC0
|
||||
| ( header_type_to_bin_v2[ packet_out->po_header_type ] << 4)
|
||||
| packno_bits
|
||||
;
|
||||
else
|
||||
*p++ = 0xC0
|
||||
| ( header_type_to_bin[ packet_out->po_header_type ] << 4)
|
||||
| packno_bits
|
||||
;
|
||||
ver_tag = lsquic_ver2tag(lconn->cn_version);
|
||||
memcpy(p, &ver_tag, sizeof(ver_tag));
|
||||
p += sizeof(ver_tag);
|
||||
|
@ -285,7 +300,7 @@ ietf_v1_gen_reg_pkt_header (const struct lsquic_conn *lconn,
|
|||
const struct lsquic_packet_out *packet_out, unsigned char *buf,
|
||||
size_t bufsz, unsigned *packno_off, unsigned *packno_len)
|
||||
{
|
||||
if (packet_out->po_header_type == HETY_NOT_SET)
|
||||
if (packet_out->po_header_type == HETY_SHORT)
|
||||
return gen_short_pkt_header(lconn, packet_out, buf, bufsz, packno_off,
|
||||
packno_len);
|
||||
else
|
||||
|
@ -301,7 +316,7 @@ ietf_v1_packout_size (const struct lsquic_conn *lconn,
|
|||
size_t sz;
|
||||
|
||||
if ((lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
&& packet_out->po_header_type == HETY_NOT_SET)
|
||||
&& packet_out->po_header_type == HETY_SHORT)
|
||||
sz = ietf_v1_packout_header_size_short(packet_out->po_flags,
|
||||
packet_out->po_path->np_dcid.len);
|
||||
else
|
||||
|
@ -1700,16 +1715,21 @@ static const enum header_type bits2ht[4] =
|
|||
};
|
||||
|
||||
|
||||
static const enum header_type bits2ht_v2[4] =
|
||||
{
|
||||
[0] = HETY_RETRY,
|
||||
[1] = HETY_INITIAL,
|
||||
[2] = HETY_0RTT,
|
||||
[3] = HETY_HANDSHAKE,
|
||||
};
|
||||
|
||||
#if LSQUIC_QIR
|
||||
/* Return true if the parsing function is to enforce the minimum DCID
|
||||
* length requirement as specified in IETF v1 and the I-Ds.
|
||||
*/
|
||||
static int
|
||||
enforce_initial_dcil (lsquic_ver_tag_t tag)
|
||||
enforce_initial_dcil (enum lsquic_version version)
|
||||
{
|
||||
enum lsquic_version version;
|
||||
|
||||
version = lsquic_tag2ver(tag);
|
||||
return version != (enum lsquic_version) -1
|
||||
&& ((1 << version) & LSQUIC_IETF_VERSIONS);
|
||||
}
|
||||
|
@ -1723,22 +1743,28 @@ lsquic_ietf_v1_parse_packet_in_long_begin (struct lsquic_packet_in *packet_in,
|
|||
{
|
||||
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, r;
|
||||
int r;
|
||||
unsigned char first_byte;
|
||||
uint64_t payload_len, token_len;
|
||||
|
||||
if (length < 6)
|
||||
return -1;
|
||||
first_byte = *p++;
|
||||
|
||||
memcpy(&tag, p, 4);
|
||||
if ((packet_in->pi_flags & PI_VER_PARSED) == 0)
|
||||
{
|
||||
packet_in->pi_version = lsquic_tag2ver_fast(p);
|
||||
packet_in->pi_flags |= PI_VER_PARSED;
|
||||
}
|
||||
p += 4;
|
||||
verneg = 0 == tag;
|
||||
if (!verneg)
|
||||
header_type = bits2ht[ (first_byte >> 4) & 3 ];
|
||||
if (packet_in->pi_version != LSQVER_VERNEG)
|
||||
{
|
||||
if (packet_in->pi_version == LSQVER_I002)
|
||||
header_type = bits2ht_v2[ (first_byte >> 4) & 3 ];
|
||||
else
|
||||
header_type = bits2ht[ (first_byte >> 4) & 3 ];
|
||||
}
|
||||
else
|
||||
header_type = HETY_VERNEG;
|
||||
|
||||
|
@ -1769,7 +1795,7 @@ lsquic_ietf_v1_parse_packet_in_long_begin (struct lsquic_packet_in *packet_in,
|
|||
{
|
||||
case HETY_INITIAL:
|
||||
#if LSQUIC_QIR
|
||||
if (!enforce_initial_dcil(tag))
|
||||
if (!enforce_initial_dcil(packet_in->pi_version))
|
||||
{
|
||||
/* Count even zero-length DCID as having DCID */
|
||||
packet_in->pi_flags |= PI_CONN_ID;
|
||||
|
@ -1893,7 +1919,10 @@ lsquic_is_valid_ietf_v1_or_Q046plus_hs_packet (const unsigned char *buf,
|
|||
return 0;
|
||||
first_byte = *p++;
|
||||
|
||||
header_type = bits2ht[ (first_byte >> 4) & 3 ];
|
||||
if (*p != 0x6B)
|
||||
header_type = bits2ht[ (first_byte >> 4) & 3 ];
|
||||
else
|
||||
header_type = bits2ht_v2[ (first_byte >> 4) & 3 ];
|
||||
if (header_type != HETY_INITIAL)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/aead.h>
|
||||
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_int_types.h"
|
||||
|
@ -181,7 +182,7 @@ lsquic_Q046_parse_packet_in_short_begin (lsquic_packet_in_t *packet_in,
|
|||
packet_in->pi_packno = packno;
|
||||
p += packet_len;
|
||||
|
||||
packet_in->pi_header_type = HETY_NOT_SET;
|
||||
packet_in->pi_header_type = HETY_SHORT;
|
||||
packet_in->pi_quic_ver = 0;
|
||||
packet_in->pi_nonce = 0;
|
||||
packet_in->pi_header_sz = p - packet_in->pi_data;
|
||||
|
@ -320,8 +321,6 @@ popcount (unsigned v)
|
|||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -379,3 +378,76 @@ lsquic_Q046_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz,
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_iquic_gen_retry_pkt (unsigned char *buf, size_t bufsz,
|
||||
const struct lsquic_engine_public *enpub,
|
||||
const lsquic_cid_t *scid, const lsquic_cid_t *dcid,
|
||||
enum lsquic_version version, const struct sockaddr *sockaddr,
|
||||
uint8_t random_nybble)
|
||||
{
|
||||
struct token_generator *const tokgen = enpub->enp_tokgen;
|
||||
const unsigned our_scid_len = enpub->enp_settings.es_scid_len;
|
||||
unsigned char *const end = buf + bufsz;
|
||||
unsigned char *p = buf;
|
||||
lsquic_ver_tag_t ver_tag;
|
||||
size_t ad_len, out_len;
|
||||
unsigned ret_ver;
|
||||
ssize_t sz;
|
||||
const size_t INTEGRITY_TAG_LEN = 16;
|
||||
|
||||
/* [draft-ietf-quic-tls-25] Section 5.8 specifies the layout of the
|
||||
* Retry Pseudo-Packet:
|
||||
*/
|
||||
unsigned char ad_buf[
|
||||
1 + MAX_CID_LEN /* ODCID */
|
||||
+ 1 + 4 /* Type and version */
|
||||
+ 1 + MAX_CID_LEN /* DCID */
|
||||
+ 1 + MAX_CID_LEN /* SCID */
|
||||
+ MAX_RETRY_TOKEN_LEN /* Retry token */
|
||||
];
|
||||
|
||||
unsigned char tag[INTEGRITY_TAG_LEN];
|
||||
|
||||
/* See [draft-ietf-quic-transport-25], Section 17.2.5 */
|
||||
|
||||
if (bufsz < 1 + sizeof(ver_tag) + 1 + our_scid_len + 1 + dcid->len
|
||||
+ MAX_RETRY_TOKEN_LEN + INTEGRITY_TAG_LEN)
|
||||
return -1;
|
||||
|
||||
p = ad_buf;
|
||||
*p++ = dcid->len;
|
||||
memcpy(p, dcid->idbuf, dcid->len);
|
||||
p += dcid->len;
|
||||
*p++ = 0xC0
|
||||
| (3 << 4)
|
||||
| random_nybble
|
||||
;
|
||||
ver_tag = lsquic_ver2tag(version);
|
||||
memcpy(p, &ver_tag, sizeof(ver_tag));
|
||||
p += sizeof(ver_tag);
|
||||
|
||||
*p++ = scid->len;
|
||||
memcpy(p, scid->idbuf, scid->len);
|
||||
p += scid->len;
|
||||
*p++ = our_scid_len;
|
||||
RAND_bytes(p, our_scid_len);
|
||||
p += our_scid_len;
|
||||
sz = lsquic_tg_generate_retry(tokgen, p, end - p,
|
||||
p - our_scid_len, our_scid_len, sockaddr, dcid);
|
||||
if (sz < 0)
|
||||
return -1;
|
||||
p += sz;
|
||||
ad_len = p - ad_buf;
|
||||
|
||||
ret_ver = lsquic_version_2_retryver(version);
|
||||
out_len = sizeof(tag);
|
||||
if (!(1 == EVP_AEAD_CTX_seal(&enpub->enp_retry_aead_ctx[ret_ver], tag,
|
||||
&out_len, out_len, lsquic_retry_nonce_buf[ret_ver],
|
||||
IETF_RETRY_NONCE_SZ,
|
||||
NULL, 0, ad_buf, ad_len) && out_len == sizeof(tag)))
|
||||
return -1;
|
||||
|
||||
memcpy(buf, ad_buf + 1 + dcid->len, ad_len - 1 - dcid->len);
|
||||
memcpy(buf + ad_len - 1 - dcid->len, tag, sizeof(tag));
|
||||
return ad_len - 1 - dcid->len + sizeof(tag);
|
||||
}
|
||||
|
|
|
@ -84,6 +84,13 @@ struct evanescent_conn
|
|||
+ 1 /* DCIL */ + MAX_CID_LEN + 1 /* SCIL */ + MAX_CID_LEN + \
|
||||
4 * N_LSQVER)
|
||||
|
||||
/* [draft-ietf-quic-transport-22], Section 17.2.5 */
|
||||
#define IQUIC_RETRY_SIZE (1 /* Type */ + 4 /* Version */ + \
|
||||
+ 1 /* DCIL */ + MAX_CID_LEN + 1 /* SCIL */ + MAX_CID_LEN + \
|
||||
+ 1 /* ODCIL */ + MAX_CID_LEN + MAX_RETRY_TOKEN_LEN)
|
||||
|
||||
/* GQUIC retry is dynamically size, this is a reasonable high bound */
|
||||
#define GQUIC_RETRY_SIZE 512
|
||||
|
||||
struct pr_queue
|
||||
{
|
||||
|
@ -262,7 +269,7 @@ put_req (struct pr_queue *prq, struct packet_req *req)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
int
|
||||
lsquic_prq_new_req_ext (struct pr_queue *prq, enum packet_req_type type,
|
||||
unsigned flags, enum lsquic_version version, unsigned short data_sz,
|
||||
const lsquic_cid_t *dcid, const lsquic_cid_t *scid, void *peer_ctx,
|
||||
|
@ -370,10 +377,11 @@ lsquic_prq_new_req (struct pr_queue *prq, enum packet_req_type type,
|
|||
static size_t
|
||||
max_bufsz (const struct pr_queue *prq)
|
||||
{
|
||||
return MAX(MAX(MAX(IQUIC_VERNEG_SIZE,
|
||||
IQUIC_MIN_SRST_SIZE),
|
||||
sizeof(prq->prq_verneg_g_buf)),
|
||||
sizeof(prq->prq_pubres_g_buf));
|
||||
return MAX(MAX(MAX(MAX(IQUIC_VERNEG_SIZE,
|
||||
IQUIC_RETRY_SIZE),
|
||||
IQUIC_MAX_SRST_SIZE),
|
||||
sizeof(prq->prq_verneg_g_buf)),
|
||||
sizeof(prq->prq_pubres_g_buf));
|
||||
}
|
||||
|
||||
|
||||
|
@ -484,6 +492,17 @@ lsquic_prq_next_conn (struct pr_queue *prq)
|
|||
else
|
||||
packet_out->po_data_sz = 0;
|
||||
break;
|
||||
case (PACKET_REQ_RETRY << 29) | 0:
|
||||
packet_out->po_flags |= PO_RETRY;
|
||||
len = lsquic_iquic_gen_retry_pkt(packet_out->po_data, max_bufsz(prq),
|
||||
prq->prq_enpub, &req->pr_scid, &req->pr_dcid,
|
||||
req->pr_version, NP_PEER_SA(&req->pr_path),
|
||||
lsquic_crand_get_nybble(prq->prq_enpub->enp_crand));
|
||||
if (len > 0)
|
||||
packet_out->po_data_sz = len;
|
||||
else
|
||||
packet_out->po_data_sz = 0;
|
||||
break;
|
||||
default:
|
||||
packet_out->po_flags &= ~PO_VERNEG;
|
||||
packet_out->po_data_sz = req->pr_rst_sz;
|
||||
|
|
|
@ -51,6 +51,7 @@ struct sockaddr;
|
|||
enum packet_req_type {
|
||||
PACKET_REQ_VERNEG,
|
||||
PACKET_REQ_PUBRES,
|
||||
PACKET_REQ_RETRY,
|
||||
N_PREQ_TYPES,
|
||||
};
|
||||
|
||||
|
@ -75,6 +76,12 @@ lsquic_prq_next_conn (struct pr_queue *);
|
|||
int
|
||||
lsquic_prq_have_pending (const struct pr_queue *);
|
||||
|
||||
int
|
||||
lsquic_prq_new_req_ext (struct pr_queue *prq, enum packet_req_type type,
|
||||
unsigned flags, enum lsquic_version version, unsigned short data_sz,
|
||||
const lsquic_cid_t *dcid, const lsquic_cid_t *scid, void *peer_ctx,
|
||||
const struct sockaddr *local_addr, const struct sockaddr *peer_addr);
|
||||
|
||||
void
|
||||
lsquic_prq_drop (struct lsquic_conn *);
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#define DEFAULT_RETX_DELAY 500000 /* Microseconds */
|
||||
#define MAX_RTO_DELAY 60000000 /* Microseconds */
|
||||
#define MIN_RTO_DELAY 200000 /* Microseconds */
|
||||
#define INITIAL_RTT 333333 /* Microseconds */
|
||||
#define N_NACKS_BEFORE_RETX 3
|
||||
|
||||
#define CGP(ctl) ((struct cong_ctl *) (ctl)->sc_cong_ctl)
|
||||
|
@ -260,6 +261,10 @@ get_retx_delay (const struct lsquic_rtt_stats *rtt_stats)
|
|||
}
|
||||
|
||||
|
||||
static lsquic_time_t
|
||||
calculate_packet_rto (lsquic_send_ctl_t *ctl);
|
||||
|
||||
|
||||
static void
|
||||
retx_alarm_rings (enum alarm_id al_id, void *ctx, lsquic_time_t expiry, lsquic_time_t now)
|
||||
{
|
||||
|
@ -275,7 +280,7 @@ retx_alarm_rings (enum alarm_id al_id, void *ctx, lsquic_time_t expiry, lsquic_t
|
|||
assert(!lsquic_alarmset_is_set(ctl->sc_alset, AL_RETX_INIT + pns));
|
||||
|
||||
rm = get_retx_mode(ctl);
|
||||
LSQ_INFO("retx timeout, mode %s", retx2str[rm]);
|
||||
LSQ_INFO("%s timeout, mode %s", lsquic_alid2str[al_id], retx2str[rm]);
|
||||
|
||||
switch (rm)
|
||||
{
|
||||
|
@ -287,18 +292,23 @@ retx_alarm_rings (enum alarm_id al_id, void *ctx, lsquic_time_t expiry, lsquic_t
|
|||
send_ctl_detect_losses(ctl, pns, now);
|
||||
break;
|
||||
case RETX_MODE_TLP:
|
||||
ctl->sc_last_rto_time = now;
|
||||
++ctl->sc_n_tlp;
|
||||
send_ctl_expire(ctl, pns, EXFI_LAST);
|
||||
break;
|
||||
case RETX_MODE_RTO:
|
||||
ctl->sc_last_rto_time = now;
|
||||
++ctl->sc_n_consec_rtos;
|
||||
ctl->sc_next_limit = 2;
|
||||
LSQ_DEBUG("packet RTO is %"PRIu64" usec", expiry);
|
||||
if ( now - ctl->sc_last_rto_time >= calculate_packet_rto(ctl))
|
||||
{
|
||||
ctl->sc_last_rto_time = now;
|
||||
++ctl->sc_n_consec_rtos;
|
||||
ctl->sc_next_limit = 2;
|
||||
ctl->sc_ci->cci_timeout(CGP(ctl));
|
||||
if (lconn->cn_if->ci_retx_timeout)
|
||||
lconn->cn_if->ci_retx_timeout(lconn);
|
||||
}
|
||||
LSQ_DEBUG("packet RTO is %"PRIu64" (+%"PRIu64") usec, consec RTOs: %d",
|
||||
expiry, now - expiry, ctl->sc_n_consec_rtos);
|
||||
send_ctl_expire(ctl, pns, EXFI_ALL);
|
||||
ctl->sc_ci->cci_timeout(CGP(ctl));
|
||||
if (lconn->cn_if->ci_retx_timeout)
|
||||
lconn->cn_if->ci_retx_timeout(lconn);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -450,18 +460,14 @@ calculate_tlp_delay (lsquic_send_ctl_t *ctl)
|
|||
lsquic_time_t srtt, delay;
|
||||
|
||||
srtt = lsquic_rtt_stats_get_srtt(&ctl->sc_conn_pub->rtt_stats);
|
||||
if (!srtt)
|
||||
srtt = INITIAL_RTT;
|
||||
if (ctl->sc_n_in_flight_all > 1)
|
||||
{
|
||||
delay = 10000; /* 10 ms is the minimum tail loss probe delay */
|
||||
if (delay < 2 * srtt)
|
||||
delay = 2 * srtt;
|
||||
}
|
||||
else
|
||||
{
|
||||
delay = srtt + srtt / 2 + ctl->sc_conn_pub->max_peer_ack_usec;
|
||||
if (delay < 2 * srtt)
|
||||
delay = 2 * srtt;
|
||||
}
|
||||
if (delay < 2 * srtt)
|
||||
delay = 2 * srtt;
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
@ -519,8 +525,9 @@ set_retx_alarm (struct lsquic_send_ctl *ctl, enum packnum_space pns,
|
|||
if (delay > MAX_RTO_DELAY)
|
||||
delay = MAX_RTO_DELAY;
|
||||
|
||||
LSQ_DEBUG("set retx alarm to %"PRIu64", which is %"PRIu64
|
||||
" usec from now, mode %s", now + delay, delay, retx2str[rm]);
|
||||
LSQ_DEBUG("set RETX_%s alarm to %"PRIu64" (%"PRIu64
|
||||
"), mode %s", lsquic_pns2str[pns],
|
||||
now + delay, delay, retx2str[rm]);
|
||||
lsquic_alarmset_set(ctl->sc_alset, AL_RETX_INIT + pns, now + delay);
|
||||
|
||||
if (PNS_APP == pns
|
||||
|
@ -656,7 +663,7 @@ send_ctl_add_poison (struct lsquic_send_ctl *ctl)
|
|||
poison->po_packno = ctl->sc_gap;
|
||||
poison->po_loss_chain = poison; /* Won't be used, but just in case */
|
||||
TAILQ_INSERT_TAIL(&ctl->sc_unacked_packets[PNS_APP], poison, po_next);
|
||||
LSQ_DEBUG("insert poisoned packet %"PRIu64, poison->po_packno);
|
||||
LSQ_DEBUG("insert poisoned packet #%"PRIu64, poison->po_packno);
|
||||
ctl->sc_flags |= SC_POISON;
|
||||
return 0;
|
||||
}
|
||||
|
@ -672,7 +679,7 @@ send_ctl_reschedule_poison (struct lsquic_send_ctl *ctl)
|
|||
TAILQ_FOREACH(poison, &ctl->sc_unacked_packets[PNS_APP], po_next)
|
||||
if (poison->po_flags & PO_POISON)
|
||||
{
|
||||
LSQ_DEBUG("remove poisoned packet %"PRIu64, poison->po_packno);
|
||||
LSQ_DEBUG("remove poisoned packet #%"PRIu64, poison->po_packno);
|
||||
TAILQ_REMOVE(&ctl->sc_unacked_packets[PNS_APP], poison, po_next);
|
||||
lsquic_malo_put(poison);
|
||||
lsquic_send_ctl_begin_optack_detection(ctl);
|
||||
|
@ -690,7 +697,7 @@ send_ctl_reschedule_poison (struct lsquic_send_ctl *ctl)
|
|||
}
|
||||
else
|
||||
log_level = LSQ_LOG_DEBUG;
|
||||
LSQ_LOG(log_level, "odd: poisoned packet %"PRIu64" not found during "
|
||||
LSQ_LOG(log_level, "odd: poisoned packet #%"PRIu64" not found during "
|
||||
"reschedule, flag: %d", ctl->sc_gap, !!(ctl->sc_flags & SC_POISON));
|
||||
}
|
||||
|
||||
|
@ -734,7 +741,7 @@ lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl,
|
|||
pns = lsquic_packet_out_pns(packet_out);
|
||||
if (0 != send_ctl_update_poison_hist(ctl, packet_out->po_packno))
|
||||
return -1;
|
||||
LSQ_DEBUG("packet %"PRIu64" has been sent (frame types: %s)",
|
||||
LSQ_DEBUG("sent packet #%"PRIu64" (%s)",
|
||||
packet_out->po_packno, lsquic_frame_types_to_str(frames,
|
||||
sizeof(frames), packet_out->po_frame_types));
|
||||
lsquic_senhist_add(&ctl->sc_senhist, packet_out->po_packno);
|
||||
|
@ -795,7 +802,7 @@ take_rtt_sample (lsquic_send_ctl_t *ctl,
|
|||
const lsquic_packno_t packno = ctl->sc_largest_acked_packno;
|
||||
const lsquic_time_t sent = ctl->sc_largest_acked_sent_time;
|
||||
const lsquic_time_t measured_rtt = now - sent;
|
||||
if (packno > ctl->sc_max_rtt_packno && lack_delta < measured_rtt)
|
||||
if ((!packno || packno > ctl->sc_max_rtt_packno) && lack_delta < measured_rtt)
|
||||
{
|
||||
if (UNLIKELY(ctl->sc_flags & SC_ROUGH_RTT))
|
||||
{
|
||||
|
@ -860,6 +867,88 @@ send_ctl_maybe_renumber_sched_to_right (struct lsquic_send_ctl *ctl,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
send_ctl_process_loss_chain_pkt (struct lsquic_send_ctl *ctl,
|
||||
struct lsquic_packet_out *const chain_cur,
|
||||
struct lsquic_packet_out **next)
|
||||
{
|
||||
unsigned packet_sz;
|
||||
const char *state;
|
||||
enum packnum_space pns;
|
||||
switch (chain_cur->po_flags & (PO_SCHED|PO_UNACKED|PO_LOST))
|
||||
{
|
||||
case PO_SCHED:
|
||||
send_ctl_maybe_renumber_sched_to_right(ctl, chain_cur);
|
||||
send_ctl_sched_remove(ctl, chain_cur);
|
||||
state = "scheduled";
|
||||
break;
|
||||
case PO_UNACKED:
|
||||
if (chain_cur->po_flags & PO_LOSS_REC)
|
||||
{
|
||||
pns = lsquic_packet_out_pns(chain_cur);
|
||||
TAILQ_REMOVE(&ctl->sc_unacked_packets[pns], chain_cur, po_next);
|
||||
state = "loss record";
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_sz = packet_out_sent_sz(chain_cur);
|
||||
send_ctl_unacked_remove(ctl, chain_cur, packet_sz);
|
||||
state = "unacked";
|
||||
}
|
||||
break;
|
||||
case PO_LOST:
|
||||
TAILQ_REMOVE(&ctl->sc_lost_packets, chain_cur, po_next);
|
||||
state = "lost";
|
||||
break;
|
||||
case 0:
|
||||
/* This is also weird, but let it pass */
|
||||
state = "unknown";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
if (next && *next == chain_cur)
|
||||
*next = TAILQ_NEXT(*next, po_next);
|
||||
if (0 == (chain_cur->po_flags & PO_LOSS_REC))
|
||||
lsquic_packet_out_ack_streams(chain_cur);
|
||||
LSQ_DEBUG("loss chain, destroy %s packet #%"PRIu64, state,
|
||||
chain_cur->po_packno);
|
||||
send_ctl_destroy_packet(ctl, chain_cur);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
send_ctl_acked_loss_chain (struct lsquic_send_ctl *ctl,
|
||||
struct lsquic_packet_out *const packet_out,
|
||||
struct lsquic_packet_out **next,
|
||||
lsquic_packno_t largest_acked)
|
||||
{
|
||||
struct lsquic_packet_out *chain_cur, *chain_next;
|
||||
unsigned count;
|
||||
count = 0;
|
||||
for (chain_cur = packet_out->po_loss_chain; chain_cur != packet_out;
|
||||
chain_cur = chain_next)
|
||||
{
|
||||
chain_next = chain_cur->po_loss_chain;
|
||||
if (chain_cur->po_packno > packet_out->po_packno
|
||||
&& chain_cur->po_packno <= largest_acked
|
||||
&& (chain_cur->po_flags & PO_LOST) == 0)
|
||||
{
|
||||
chain_cur->po_flags |= PO_ACKED_LOSS_CHAIN;
|
||||
continue;
|
||||
}
|
||||
send_ctl_process_loss_chain_pkt(ctl, chain_cur, next);
|
||||
++count;
|
||||
}
|
||||
packet_out->po_loss_chain = packet_out;
|
||||
|
||||
if (count)
|
||||
LSQ_DEBUG("destroyed %u packet%.*s in chain of packet #%"PRIu64,
|
||||
count, count != 1, "s", packet_out->po_packno);
|
||||
}
|
||||
|
||||
|
||||
/* The third argument to advance `next' pointer when modifying the unacked
|
||||
* queue. This is because the unacked queue may contain several elements
|
||||
* of the same chain. This is not true of the lost and scheduled packet
|
||||
|
@ -871,50 +960,19 @@ send_ctl_destroy_chain (struct lsquic_send_ctl *ctl,
|
|||
struct lsquic_packet_out **next)
|
||||
{
|
||||
struct lsquic_packet_out *chain_cur, *chain_next;
|
||||
unsigned packet_sz, count;
|
||||
enum packnum_space pns = lsquic_packet_out_pns(packet_out);
|
||||
|
||||
unsigned count;
|
||||
count = 0;
|
||||
for (chain_cur = packet_out->po_loss_chain; chain_cur != packet_out;
|
||||
chain_cur = chain_next)
|
||||
{
|
||||
chain_next = chain_cur->po_loss_chain;
|
||||
switch (chain_cur->po_flags & (PO_SCHED|PO_UNACKED|PO_LOST))
|
||||
{
|
||||
case PO_SCHED:
|
||||
send_ctl_maybe_renumber_sched_to_right(ctl, chain_cur);
|
||||
send_ctl_sched_remove(ctl, chain_cur);
|
||||
break;
|
||||
case PO_UNACKED:
|
||||
if (chain_cur->po_flags & PO_LOSS_REC)
|
||||
TAILQ_REMOVE(&ctl->sc_unacked_packets[pns], chain_cur, po_next);
|
||||
else
|
||||
{
|
||||
packet_sz = packet_out_sent_sz(chain_cur);
|
||||
send_ctl_unacked_remove(ctl, chain_cur, packet_sz);
|
||||
}
|
||||
break;
|
||||
case PO_LOST:
|
||||
TAILQ_REMOVE(&ctl->sc_lost_packets, chain_cur, po_next);
|
||||
break;
|
||||
case 0:
|
||||
/* This is also weird, but let it pass */
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
if (next && *next == chain_cur)
|
||||
*next = TAILQ_NEXT(*next, po_next);
|
||||
if (0 == (chain_cur->po_flags & PO_LOSS_REC))
|
||||
lsquic_packet_out_ack_streams(chain_cur);
|
||||
send_ctl_destroy_packet(ctl, chain_cur);
|
||||
send_ctl_process_loss_chain_pkt(ctl, chain_cur, next);
|
||||
++count;
|
||||
}
|
||||
packet_out->po_loss_chain = packet_out;
|
||||
|
||||
if (count)
|
||||
LSQ_DEBUG("destroyed %u packet%.*s in chain of packet %"PRIu64,
|
||||
LSQ_DEBUG("destroyed %u packet%.*s in chain of packet #%"PRIu64,
|
||||
count, count != 1, "s", packet_out->po_packno);
|
||||
}
|
||||
|
||||
|
@ -972,7 +1030,7 @@ send_ctl_handle_regular_lost_packet (struct lsquic_send_ctl *ctl,
|
|||
if (packet_out->po_frame_types & (1 << QUIC_FRAME_ACK))
|
||||
{
|
||||
ctl->sc_flags |= SC_LOST_ACK_INIT << lsquic_packet_out_pns(packet_out);
|
||||
LSQ_DEBUG("lost ACK in packet %"PRIu64, packet_out->po_packno);
|
||||
LSQ_DEBUG("lost ACK in packet #%"PRIu64, packet_out->po_packno);
|
||||
}
|
||||
|
||||
if (ctl->sc_ci->cci_lost)
|
||||
|
@ -990,7 +1048,7 @@ send_ctl_handle_regular_lost_packet (struct lsquic_send_ctl *ctl,
|
|||
|
||||
if (packet_out->po_frame_types & ctl->sc_retx_frames)
|
||||
{
|
||||
LSQ_DEBUG("lost retransmittable packet %"PRIu64,
|
||||
LSQ_DEBUG("lost retransmittable packet #%"PRIu64,
|
||||
packet_out->po_packno);
|
||||
loss_record = send_ctl_record_loss(ctl, packet_out);
|
||||
send_ctl_unacked_remove(ctl, packet_out, packet_sz);
|
||||
|
@ -1000,7 +1058,7 @@ send_ctl_handle_regular_lost_packet (struct lsquic_send_ctl *ctl,
|
|||
}
|
||||
else
|
||||
{
|
||||
LSQ_DEBUG("lost unretransmittable packet %"PRIu64,
|
||||
LSQ_DEBUG("lost unretransmittable packet #%"PRIu64,
|
||||
packet_out->po_packno);
|
||||
send_ctl_unacked_remove(ctl, packet_out, packet_sz);
|
||||
send_ctl_destroy_chain(ctl, packet_out, next);
|
||||
|
@ -1016,7 +1074,7 @@ send_ctl_handle_lost_mtu_probe (struct lsquic_send_ctl *ctl,
|
|||
{
|
||||
unsigned packet_sz;
|
||||
|
||||
LSQ_DEBUG("lost MTU probe in packet %"PRIu64, packet_out->po_packno);
|
||||
LSQ_DEBUG("lost MTU probe in packet #%"PRIu64, packet_out->po_packno);
|
||||
packet_sz = packet_out_sent_sz(packet_out);
|
||||
send_ctl_unacked_remove(ctl, packet_out, packet_sz);
|
||||
assert(packet_out->po_loss_chain == packet_out);
|
||||
|
@ -1090,7 +1148,7 @@ send_ctl_detect_losses (struct lsquic_send_ctl *ctl, enum packnum_space pns,
|
|||
if (packet_out->po_packno + ctl->sc_reord_thresh <
|
||||
ctl->sc_largest_acked_packno)
|
||||
{
|
||||
LSQ_DEBUG("loss by FACK detected (dist: %"PRIu64"), packet %"PRIu64,
|
||||
LSQ_DEBUG("loss by FACK detected (dist: %"PRIu64"), packet #%"PRIu64,
|
||||
ctl->sc_largest_acked_packno - packet_out->po_packno,
|
||||
packet_out->po_packno);
|
||||
if (0 == (packet_out->po_flags & PO_MTU_PROBE))
|
||||
|
@ -1111,12 +1169,12 @@ send_ctl_detect_losses (struct lsquic_send_ctl *ctl, enum packnum_space pns,
|
|||
&& 0 == (packet_out->po_flags & PO_MTU_PROBE)
|
||||
&& largest_retx_packno <= ctl->sc_largest_acked_packno)
|
||||
{
|
||||
LSQ_DEBUG("loss by early retransmit detected, packet %"PRIu64,
|
||||
LSQ_DEBUG("loss by early retransmit detected, packet #%"PRIu64,
|
||||
packet_out->po_packno);
|
||||
largest_lost_packno = packet_out->po_packno;
|
||||
ctl->sc_loss_to =
|
||||
lsquic_rtt_stats_get_srtt(&ctl->sc_conn_pub->rtt_stats) / 4;
|
||||
LSQ_DEBUG("set sc_loss_to to %"PRIu64", packet %"PRIu64,
|
||||
LSQ_DEBUG("set sc_loss_to to %"PRIu64", packet #%"PRIu64,
|
||||
ctl->sc_loss_to, packet_out->po_packno);
|
||||
(void) send_ctl_handle_lost_packet(ctl, packet_out, &next);
|
||||
continue;
|
||||
|
@ -1125,7 +1183,7 @@ send_ctl_detect_losses (struct lsquic_send_ctl *ctl, enum packnum_space pns,
|
|||
if (ctl->sc_largest_acked_sent_time > packet_out->po_sent +
|
||||
lsquic_rtt_stats_get_srtt(&ctl->sc_conn_pub->rtt_stats))
|
||||
{
|
||||
LSQ_DEBUG("loss by sent time detected: packet %"PRIu64,
|
||||
LSQ_DEBUG("loss by sent time detected: packet #%"PRIu64,
|
||||
packet_out->po_packno);
|
||||
if ((packet_out->po_frame_types & ctl->sc_retx_frames)
|
||||
&& 0 == (packet_out->po_flags & PO_MTU_PROBE))
|
||||
|
@ -1138,7 +1196,7 @@ send_ctl_detect_losses (struct lsquic_send_ctl *ctl, enum packnum_space pns,
|
|||
|
||||
if (largest_lost_packno > ctl->sc_largest_sent_at_cutback)
|
||||
{
|
||||
LSQ_DEBUG("detected new loss: packet %"PRIu64"; new lsac: "
|
||||
LSQ_DEBUG("detected new loss: packet #%"PRIu64"; new lsac: "
|
||||
"%"PRIu64, largest_lost_packno, ctl->sc_largest_sent_at_cutback);
|
||||
send_ctl_loss_event(ctl);
|
||||
}
|
||||
|
@ -1147,7 +1205,7 @@ send_ctl_detect_losses (struct lsquic_send_ctl *ctl, enum packnum_space pns,
|
|||
* number sent at the time of the last loss event indicate the same
|
||||
* loss event. This follows NewReno logic, see RFC 6582.
|
||||
*/
|
||||
LSQ_DEBUG("ignore loss of packet %"PRIu64" smaller than lsac "
|
||||
LSQ_DEBUG("ignore loss of packet #%"PRIu64" smaller than lsac "
|
||||
"%"PRIu64, largest_lost_packno, ctl->sc_largest_sent_at_cutback);
|
||||
|
||||
return largest_lost_packno > ctl->sc_largest_sent_at_cutback;
|
||||
|
@ -1160,7 +1218,7 @@ send_ctl_mtu_probe_acked (struct lsquic_send_ctl *ctl,
|
|||
{
|
||||
struct lsquic_conn *const lconn = ctl->sc_conn_pub->lconn;
|
||||
|
||||
LSQ_DEBUG("MTU probe in packet %"PRIu64" has been ACKed",
|
||||
LSQ_DEBUG("MTU probe in packet #%"PRIu64" has been ACKed",
|
||||
packet_out->po_packno);
|
||||
assert(lconn->cn_if->ci_mtu_probe_acked);
|
||||
if (lconn->cn_if->ci_mtu_probe_acked)
|
||||
|
@ -1181,7 +1239,7 @@ send_ctl_maybe_increase_reord_thresh (struct lsquic_send_ctl *ctl,
|
|||
< prev_largest_acked)
|
||||
{
|
||||
ctl->sc_reord_thresh = prev_largest_acked - loss_record->po_packno;
|
||||
LSQ_DEBUG("packet %"PRIu64" was a spurious loss by FACK, increase "
|
||||
LSQ_DEBUG("packet #%"PRIu64" was a spurious loss by FACK, increase "
|
||||
"reordering threshold to %u", loss_record->po_packno,
|
||||
ctl->sc_reord_thresh);
|
||||
}
|
||||
|
@ -1294,14 +1352,14 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
|||
ctl->sc_largest_acked_sent_time = packet_out->po_sent;
|
||||
ecn_total_acked += lsquic_packet_out_ecn(packet_out) != ECN_NOT_ECT;
|
||||
ecn_ce_cnt += lsquic_packet_out_ecn(packet_out) == ECN_CE;
|
||||
one_rtt_cnt += lsquic_packet_out_enc_level(packet_out) == ENC_LEV_FORW;
|
||||
one_rtt_cnt += lsquic_packet_out_enc_level(packet_out) == ENC_LEV_APP;
|
||||
if (0 == (packet_out->po_flags
|
||||
& (PO_LOSS_REC|PO_POISON|PO_MTU_PROBE)))
|
||||
{
|
||||
packet_sz = packet_out_sent_sz(packet_out);
|
||||
send_ctl_unacked_remove(ctl, packet_out, packet_sz);
|
||||
lsquic_packet_out_ack_streams(packet_out);
|
||||
LSQ_DEBUG("acking via regular record %"PRIu64,
|
||||
LSQ_DEBUG("acking via regular record #%"PRIu64,
|
||||
packet_out->po_packno);
|
||||
}
|
||||
else if (packet_out->po_flags & PO_LOSS_REC)
|
||||
|
@ -1309,7 +1367,7 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
|||
packet_sz = packet_out->po_sent_sz;
|
||||
TAILQ_REMOVE(&ctl->sc_unacked_packets[pns], packet_out,
|
||||
po_next);
|
||||
LSQ_DEBUG("acking via loss record %"PRIu64,
|
||||
LSQ_DEBUG("acking via loss record #%"PRIu64,
|
||||
packet_out->po_packno);
|
||||
send_ctl_maybe_increase_reord_thresh(ctl, packet_out,
|
||||
prev_largest_acked);
|
||||
|
@ -1325,7 +1383,7 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
|||
}
|
||||
else
|
||||
{
|
||||
LSQ_WARN("poisoned packet %"PRIu64" acked",
|
||||
LSQ_WARN("poisoned packet #%"PRIu64" acked",
|
||||
packet_out->po_packno);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1334,9 +1392,15 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
|||
do_rtt |= packet_out->po_packno == largest_acked(acki);
|
||||
ctl->sc_ci->cci_ack(CGP(ctl), packet_out, packet_sz, now,
|
||||
app_limited);
|
||||
send_ctl_destroy_chain(ctl, packet_out, &next);
|
||||
if (!(packet_out->po_flags & PO_ACKED_LOSS_CHAIN))
|
||||
send_ctl_acked_loss_chain(ctl, packet_out, &next,
|
||||
largest_acked(acki));
|
||||
send_ctl_destroy_packet(ctl, packet_out);
|
||||
}
|
||||
else if (packet_out->po_flags & PO_ACKED_LOSS_CHAIN)
|
||||
{
|
||||
send_ctl_process_loss_chain_pkt(ctl, packet_out, &next);
|
||||
}
|
||||
packet_out = next;
|
||||
}
|
||||
while (packet_out && packet_out->po_packno <= largest_acked(acki));
|
||||
|
@ -1344,6 +1408,7 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
|||
if (do_rtt)
|
||||
{
|
||||
take_rtt_sample(ctl, ack_recv_time, acki->lack_delta);
|
||||
LSQ_DEBUG("clear sc_n_consec_rtos, sc_n_hsk, sc_ntlp");
|
||||
ctl->sc_n_consec_rtos = 0;
|
||||
ctl->sc_n_hsk = 0;
|
||||
ctl->sc_n_tlp = 0;
|
||||
|
@ -1352,7 +1417,10 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
|||
detect_losses:
|
||||
losses_detected = send_ctl_detect_losses(ctl, pns, ack_recv_time);
|
||||
if (send_ctl_first_unacked_retx_packet(ctl, pns))
|
||||
set_retx_alarm(ctl, pns, now);
|
||||
{
|
||||
if (!lsquic_alarmset_is_set(ctl->sc_alset, pns) && losses_detected)
|
||||
set_retx_alarm(ctl, pns, now);
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_DEBUG("No retransmittable packets: clear alarm");
|
||||
|
@ -1469,7 +1537,7 @@ send_ctl_next_lost (lsquic_send_ctl_t *ctl)
|
|||
UINT64_MAX);
|
||||
if (lost_packet->po_regen_sz >= lost_packet->po_data_sz)
|
||||
{
|
||||
LSQ_DEBUG("Dropping packet %"PRIu64" from lost queue",
|
||||
LSQ_DEBUG("Dropping packet #%"PRIu64" from lost queue",
|
||||
lost_packet->po_packno);
|
||||
TAILQ_REMOVE(&ctl->sc_lost_packets, lost_packet, po_next);
|
||||
lost_packet->po_flags &= ~PO_LOST;
|
||||
|
@ -1927,7 +1995,7 @@ send_ctl_maybe_zero_pad (struct lsquic_send_ctl *ctl,
|
|||
if (cum_size + size > limit)
|
||||
break;
|
||||
cum_size += size;
|
||||
if (HETY_NOT_SET == packet_out->po_header_type)
|
||||
if (HETY_SHORT == packet_out->po_header_type)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1942,7 +2010,7 @@ send_ctl_maybe_zero_pad (struct lsquic_send_ctl *ctl,
|
|||
initial_packet->po_data_sz += size;
|
||||
initial_packet->po_frame_types |= QUIC_FTBIT_PADDING;
|
||||
}
|
||||
LSQ_DEBUG("Added %zu bytes of PADDING to packet %"PRIu64, size,
|
||||
LSQ_DEBUG("Added %zu bytes of PADDING to packet #%"PRIu64, size,
|
||||
initial_packet->po_packno);
|
||||
}
|
||||
|
||||
|
@ -1960,7 +2028,8 @@ lsquic_send_ctl_next_packet_to_send_predict (struct lsquic_send_ctl *ctl)
|
|||
n_rtos = ~0u;
|
||||
TAILQ_FOREACH(packet_out, &ctl->sc_scheduled_packets, po_next)
|
||||
{
|
||||
if (!(packet_out->po_frame_types & (1 << QUIC_FRAME_ACK))
|
||||
if (!(packet_out->po_frame_types
|
||||
& ((1 << QUIC_FRAME_ACK) | (1 << QUIC_FRAME_CRYPTO)))
|
||||
&& 0 == ctl->sc_next_limit
|
||||
&& 0 != (n_rtos == ~0u ? /* Initialize once */
|
||||
(n_rtos = send_ctl_get_n_consec_rtos(ctl)) : n_rtos))
|
||||
|
@ -1972,11 +2041,11 @@ lsquic_send_ctl_next_packet_to_send_predict (struct lsquic_send_ctl *ctl)
|
|||
&& packet_out->po_regen_sz == packet_out->po_data_sz
|
||||
&& packet_out->po_frame_types != QUIC_FTBIT_PATH_CHALLENGE)
|
||||
{
|
||||
LSQ_DEBUG("send prediction: packet %"PRIu64" would be dropped, "
|
||||
LSQ_DEBUG("send prediction: packet #%"PRIu64" would be dropped, "
|
||||
"continue", packet_out->po_packno);
|
||||
continue;
|
||||
}
|
||||
LSQ_DEBUG("send prediction: yes, packet %"PRIu64", flags %u, frames 0x%X",
|
||||
LSQ_DEBUG("send prediction: yes, packet #%"PRIu64", flags %u, frames 0x%X",
|
||||
packet_out->po_packno, (unsigned) packet_out->po_flags,
|
||||
(unsigned) packet_out->po_frame_types);
|
||||
return 1;
|
||||
|
@ -1998,18 +2067,26 @@ lsquic_send_ctl_next_packet_to_send (struct lsquic_send_ctl *ctl,
|
|||
get_packet:
|
||||
packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets);
|
||||
if (!packet_out)
|
||||
{
|
||||
LSQ_DEBUG("no more scheduled packets");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Note: keep logic in this function and in
|
||||
* lsquic_send_ctl_next_packet_to_send_predict() in synch.
|
||||
*/
|
||||
if (!(packet_out->po_frame_types & (1 << QUIC_FRAME_ACK))
|
||||
&& send_ctl_get_n_consec_rtos(ctl))
|
||||
if (!(packet_out->po_frame_types
|
||||
& ((1 << QUIC_FRAME_ACK) | (1 << QUIC_FRAME_CRYPTO)))
|
||||
&& send_ctl_get_n_consec_rtos(ctl))
|
||||
{
|
||||
if (ctl->sc_next_limit)
|
||||
dec_limit = 1;
|
||||
else
|
||||
{
|
||||
LSQ_DEBUG("sc_n_consec_rtos: %d, sc_next_limit is 0",
|
||||
ctl->sc_n_consec_rtos);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
dec_limit = 0;
|
||||
|
@ -2024,7 +2101,7 @@ lsquic_send_ctl_next_packet_to_send (struct lsquic_send_ctl *ctl,
|
|||
}
|
||||
else
|
||||
{
|
||||
LSQ_DEBUG("Dropping packet %"PRIu64" from scheduled queue",
|
||||
LSQ_DEBUG("Dropping packet #%"PRIu64" from scheduled queue",
|
||||
packet_out->po_packno);
|
||||
send_ctl_sched_remove(ctl, packet_out);
|
||||
send_ctl_destroy_chain(ctl, packet_out, NULL);
|
||||
|
@ -2043,7 +2120,7 @@ lsquic_send_ctl_next_packet_to_send (struct lsquic_send_ctl *ctl,
|
|||
> SC_PACK_SIZE(ctl)
|
||||
|| !lsquic_packet_out_equal_dcids(to_coal->prev_packet, packet_out))
|
||||
return NULL;
|
||||
LSQ_DEBUG("packet %"PRIu64" (%zu bytes) will be tacked on to "
|
||||
LSQ_DEBUG("packet #%"PRIu64" (%zu bytes) will be tacked on to "
|
||||
"previous packet(s) (%zu bytes) (coalescing)",
|
||||
packet_out->po_packno, packet_out_total_sz(packet_out),
|
||||
to_coal->prev_sz_sum);
|
||||
|
@ -2061,7 +2138,7 @@ lsquic_send_ctl_next_packet_to_send (struct lsquic_send_ctl *ctl,
|
|||
else
|
||||
packet_out->po_lflags &= ~POL_LIMITED;
|
||||
|
||||
if (UNLIKELY(packet_out->po_header_type == HETY_INITIAL)
|
||||
if (UNLIKELY(!(ctl->sc_conn_pub->lconn->cn_flags & LSCONN_HANDSHAKE_DONE))
|
||||
&& (!(ctl->sc_conn_pub->lconn->cn_flags & LSCONN_SERVER)
|
||||
|| (packet_out->po_frame_types
|
||||
& IQUIC_FRAME_ACKABLE_MASK))
|
||||
|
@ -2080,7 +2157,7 @@ lsquic_send_ctl_next_packet_to_send (struct lsquic_send_ctl *ctl,
|
|||
}
|
||||
else
|
||||
packet_out->po_lflags &= ~POL_LOSS_BIT;
|
||||
if (packet_out->po_header_type == HETY_NOT_SET)
|
||||
if (packet_out->po_header_type == HETY_SHORT)
|
||||
{
|
||||
if (ctl->sc_gap + 1 == packet_out->po_packno)
|
||||
++ctl->sc_square_count;
|
||||
|
@ -2102,14 +2179,14 @@ lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *ctl,
|
|||
send_ctl_sched_prepend(ctl, packet_out);
|
||||
if (packet_out->po_lflags & POL_LIMITED)
|
||||
++ctl->sc_next_limit;
|
||||
LSQ_DEBUG("packet %"PRIu64" has been delayed", packet_out->po_packno);
|
||||
LSQ_DEBUG("packet #%"PRIu64" has been delayed", packet_out->po_packno);
|
||||
#if LSQUIC_SEND_STATS
|
||||
++ctl->sc_stats.n_delayed;
|
||||
#endif
|
||||
if (packet_out->po_lflags & POL_LOSS_BIT)
|
||||
++ctl->sc_loss_count;
|
||||
if ((ctl->sc_flags & SC_QL_BITS)
|
||||
&& packet_out->po_header_type == HETY_NOT_SET)
|
||||
&& packet_out->po_header_type == HETY_SHORT)
|
||||
ctl->sc_square_count -= 1 + (ctl->sc_gap + 1 == packet_out->po_packno);
|
||||
}
|
||||
|
||||
|
@ -2168,7 +2245,7 @@ send_ctl_allocate_packet (struct lsquic_send_ctl *ctl, enum packno_bits bits,
|
|||
{
|
||||
[PNS_INIT] = HETY_INITIAL,
|
||||
[PNS_HSK] = HETY_HANDSHAKE,
|
||||
[PNS_APP] = HETY_NOT_SET,
|
||||
[PNS_APP] = HETY_SHORT,
|
||||
};
|
||||
lsquic_packet_out_t *packet_out;
|
||||
|
||||
|
@ -2232,7 +2309,7 @@ lsquic_send_ctl_new_packet_out (lsquic_send_ctl_t *ctl, unsigned need_at_least,
|
|||
return NULL;
|
||||
|
||||
packet_out->po_packno = send_ctl_next_packno(ctl);
|
||||
LSQ_DEBUG("created packet %"PRIu64, packet_out->po_packno);
|
||||
LSQ_DEBUG("created packet #%"PRIu64, packet_out->po_packno);
|
||||
EV_LOG_PACKET_CREATED(LSQUIC_LOG_CONN_ID, packet_out);
|
||||
return packet_out;
|
||||
}
|
||||
|
@ -2367,10 +2444,8 @@ update_for_resending (lsquic_send_ctl_t *ctl, lsquic_packet_out_t *packet_out)
|
|||
ctl->sc_bytes_scheduled -= packet_out->po_regen_sz;
|
||||
lsquic_packet_out_chop_regen(packet_out);
|
||||
}
|
||||
LSQ_DEBUG("Packet %"PRIu64" repackaged for resending as packet %"PRIu64,
|
||||
oldno, packno);
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "packet %"PRIu64" repackaged for "
|
||||
"resending as packet %"PRIu64, oldno, packno);
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "schedule resend, repackage packet "
|
||||
"#%"PRIu64" -> #%"PRIu64, oldno, packno);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2447,7 +2522,7 @@ lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *ctl,
|
|||
ctl->sc_bytes_scheduled -= adj;
|
||||
if (0 == packet_out->po_frame_types)
|
||||
{
|
||||
LSQ_DEBUG("cancel packet %"PRIu64" after eliding frames for "
|
||||
LSQ_DEBUG("cancel packet #%"PRIu64" after eliding frames for "
|
||||
"stream %"PRIu64, packet_out->po_packno, stream_id);
|
||||
send_ctl_sched_remove(ctl, packet_out);
|
||||
send_ctl_destroy_chain(ctl, packet_out, NULL);
|
||||
|
@ -2587,7 +2662,7 @@ lsquic_send_ctl_squeeze_sched (lsquic_send_ctl_t *ctl)
|
|||
"scheduled packets before squeezing");
|
||||
#endif
|
||||
send_ctl_sched_remove(ctl, packet_out);
|
||||
LSQ_DEBUG("Dropping packet %"PRIu64" from scheduled queue",
|
||||
LSQ_DEBUG("Dropping packet #%"PRIu64" from scheduled queue",
|
||||
packet_out->po_packno);
|
||||
send_ctl_destroy_chain(ctl, packet_out, NULL);
|
||||
send_ctl_destroy_packet(ctl, packet_out);
|
||||
|
@ -3107,7 +3182,7 @@ lsquic_send_ctl_schedule_buffered (lsquic_send_ctl_t *ctl,
|
|||
--packet_q->bpq_count;
|
||||
packet_out->po_packno = send_ctl_next_packno(ctl);
|
||||
LSQ_DEBUG("Remove packet from buffered queue #%u; count: %u. "
|
||||
"It becomes packet %"PRIu64, packet_type, packet_q->bpq_count,
|
||||
"It becomes packet #%"PRIu64, packet_type, packet_q->bpq_count,
|
||||
packet_out->po_packno);
|
||||
lsquic_send_ctl_scheduled_one(ctl, packet_out);
|
||||
}
|
||||
|
@ -3360,6 +3435,8 @@ lsquic_send_ctl_maybe_calc_rough_rtt (struct lsquic_send_ctl *ctl,
|
|||
if (min_sent < UINT64_MAX)
|
||||
{
|
||||
rtt = lsquic_time_now() - min_sent;
|
||||
if (rtt > 500000)
|
||||
rtt = 500000;
|
||||
lsquic_rtt_stats_update(&ctl->sc_conn_pub->rtt_stats, rtt, 0);
|
||||
ctl->sc_flags |= SC_ROUGH_RTT;
|
||||
LSQ_DEBUG("set rough RTT to %"PRIu64" usec", rtt);
|
||||
|
@ -3557,7 +3634,7 @@ send_ctl_resize_q (struct lsquic_send_ctl *ctl, struct lsquic_packets_tailq *q,
|
|||
++count_dst;
|
||||
packet_out->po_packno = send_ctl_next_packno(ctl);
|
||||
send_ctl_sched_append(ctl, packet_out);
|
||||
LSQ_DEBUG("created packet %"PRIu64, packet_out->po_packno);
|
||||
LSQ_DEBUG("created packet #%"PRIu64, packet_out->po_packno);
|
||||
EV_LOG_PACKET_CREATED(LSQUIC_LOG_CONN_ID, packet_out);
|
||||
}
|
||||
else
|
||||
|
@ -4040,13 +4117,14 @@ lsquic_send_ctl_0rtt_to_1rtt (struct lsquic_send_ctl *ctl)
|
|||
if (packet_out->po_header_type == HETY_0RTT)
|
||||
{
|
||||
++count;
|
||||
packet_out->po_header_type = HETY_NOT_SET;
|
||||
packet_out->po_header_type = HETY_SHORT;
|
||||
if (packet_out->po_flags & PO_ENCRYPTED)
|
||||
send_ctl_return_enc_data(ctl, packet_out);
|
||||
}
|
||||
|
||||
LSQ_DEBUG("handshake ok: changed %u packet%.*s from 0-RTT to 1-RTT",
|
||||
count, count != 1, "s");
|
||||
ctl->sc_n_consec_rtos >>= 1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2561,7 +2561,7 @@ lsquic_stream_flush_threshold (const struct lsquic_stream *stream,
|
|||
flags |= PO_LONGHEAD;
|
||||
|
||||
packet_header_sz = lsquic_po_header_length(stream->conn_pub->lconn, flags,
|
||||
stream->conn_pub->path->np_dcid.len, HETY_NOT_SET);
|
||||
stream->conn_pub->path->np_dcid.len, HETY_SHORT);
|
||||
stream_header_sz = stream->sm_frame_header_sz(stream, data_sz);
|
||||
tag_len = stream->conn_pub->lconn->cn_esf_c->esf_tag_len;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -49,13 +50,22 @@ struct tokgen_shm_state
|
|||
{
|
||||
uint8_t tgss_version;
|
||||
uint8_t tgss_magic_top[sizeof(TOKGEN_SHM_MAGIC_TOP) - 1];
|
||||
uint8_t tgss_padding[2 * CRYPTER_KEY_SIZE];
|
||||
uint8_t tgss_crypter_key[N_TOKEN_TYPES][CRYPTER_KEY_SIZE];
|
||||
uint8_t tgss_srst_prk_size;
|
||||
uint8_t tgss_srst_prk[SRST_MAX_PRK_SIZE];
|
||||
uint8_t tgss_magic_bottom[sizeof(TOKGEN_SHM_MAGIC_BOTTOM) - 1];
|
||||
};
|
||||
|
||||
|
||||
/* The various salt values below were obtained by reading from /dev/random
|
||||
* when the code was first written.
|
||||
*/
|
||||
|
||||
static const uint64_t salts[N_TOKEN_TYPES] =
|
||||
{
|
||||
[TOKEN_RETRY] = 0xa49c3ef763a6243f,
|
||||
[TOKEN_RESUME] = 0x0b3664549086b8ca,
|
||||
};
|
||||
|
||||
static const uint8_t srst_salt[8] = "\x28\x6e\x81\x02\x40\x5b\x2c\x2b";
|
||||
|
||||
|
@ -68,19 +78,56 @@ struct crypter
|
|||
};
|
||||
|
||||
|
||||
/* Bloom filter of Resume tokens. See below. */
|
||||
struct resumed_token_page
|
||||
{
|
||||
TAILQ_ENTRY(resumed_token_page) next;
|
||||
time_t begin, /* Oldest entry */
|
||||
end; /* Newest entry */
|
||||
unsigned count; /* Number of entries */
|
||||
uintptr_t masks[];
|
||||
};
|
||||
|
||||
|
||||
struct token_generator
|
||||
{
|
||||
/* We encrypt different token types using different keys. */
|
||||
struct crypter tg_crypters[N_TOKEN_TYPES];
|
||||
|
||||
/* Stateless reset token is generated using HKDF with CID as the
|
||||
* `info' parameter to HKDF-Expand.
|
||||
*/
|
||||
size_t tg_srst_prk_sz;
|
||||
uint8_t tg_srst_prk_buf[SRST_MAX_PRK_SIZE];
|
||||
unsigned tg_retry_token_duration;
|
||||
TAILQ_HEAD(resumed_token_pages_head, resumed_token_page)
|
||||
tg_resume_token_pages;
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
setup_nonce_prk (unsigned char *nonce_prk_buf, size_t *nonce_prk_sz,
|
||||
unsigned i, time_t now)
|
||||
{
|
||||
struct {
|
||||
time_t now;
|
||||
enum token_type tt;
|
||||
uint8_t buf[16];
|
||||
} ikm;
|
||||
|
||||
ikm.now = now;
|
||||
ikm.tt = i;
|
||||
RAND_bytes(ikm.buf, sizeof(ikm.buf));
|
||||
if (HKDF_extract(nonce_prk_buf, nonce_prk_sz,
|
||||
EVP_sha256(), (uint8_t *) &ikm, sizeof(ikm),
|
||||
(void *) &salts[i], sizeof(salts[i])))
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
LSQ_ERROR("HKDF_extract failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
|
@ -149,10 +196,14 @@ get_or_generate_state (struct lsquic_engine_public *enpub, time_t now,
|
|||
if (getenv("LSQUIC_NULL_TOKGEN"))
|
||||
{
|
||||
LSQ_NOTICE("using NULL tokgen");
|
||||
memset(shm_state->tgss_crypter_key, 0,
|
||||
sizeof(shm_state->tgss_crypter_key));
|
||||
memset(&srst_ikm, 0, sizeof(srst_ikm));
|
||||
}
|
||||
else
|
||||
{
|
||||
RAND_bytes((void *) shm_state->tgss_crypter_key,
|
||||
sizeof(shm_state->tgss_crypter_key));
|
||||
srst_ikm.now = now;
|
||||
RAND_bytes(srst_ikm.buf, sizeof(srst_ikm.buf));
|
||||
}
|
||||
|
@ -205,6 +256,26 @@ lsquic_tg_new (struct lsquic_engine_public *enpub)
|
|||
if (0 != get_or_generate_state(enpub, now, &shm_state))
|
||||
goto err;
|
||||
|
||||
TAILQ_INIT(&tokgen->tg_resume_token_pages);
|
||||
unsigned i;
|
||||
for (i = 0; i < sizeof(tokgen->tg_crypters)
|
||||
/ sizeof(tokgen->tg_crypters[0]); ++i)
|
||||
{
|
||||
struct crypter *crypter;
|
||||
crypter = tokgen->tg_crypters + i;
|
||||
if (0 != setup_nonce_prk(crypter->nonce_prk_buf,
|
||||
&crypter->nonce_prk_sz, i, now))
|
||||
goto err;
|
||||
if (1 != EVP_AEAD_CTX_init(&crypter->ctx, EVP_aead_aes_128_gcm(),
|
||||
shm_state.tgss_crypter_key[i],
|
||||
sizeof(shm_state.tgss_crypter_key[i]), RETRY_TAG_LEN, 0))
|
||||
goto err;
|
||||
}
|
||||
|
||||
tokgen->tg_retry_token_duration
|
||||
= enpub->enp_settings.es_retry_token_duration;
|
||||
if (tokgen->tg_retry_token_duration == 0)
|
||||
tokgen->tg_retry_token_duration = LSQUIC_DF_RETRY_TOKEN_DURATION;
|
||||
|
||||
tokgen->tg_srst_prk_sz = shm_state.tgss_srst_prk_size;
|
||||
if (tokgen->tg_srst_prk_sz > sizeof(tokgen->tg_srst_prk_buf))
|
||||
|
@ -228,11 +299,513 @@ lsquic_tg_new (struct lsquic_engine_public *enpub)
|
|||
void
|
||||
lsquic_tg_destroy (struct token_generator *tokgen)
|
||||
{
|
||||
struct resumed_token_page *page;
|
||||
struct crypter *crypter;
|
||||
unsigned i;
|
||||
|
||||
while ((page = TAILQ_FIRST(&tokgen->tg_resume_token_pages)))
|
||||
{
|
||||
TAILQ_REMOVE(&tokgen->tg_resume_token_pages, page, next);
|
||||
free(page);
|
||||
}
|
||||
for (i = 0; i < sizeof(tokgen->tg_crypters)
|
||||
/ sizeof(tokgen->tg_crypters[0]); ++i)
|
||||
{
|
||||
crypter = tokgen->tg_crypters + i;
|
||||
EVP_AEAD_CTX_cleanup(&crypter->ctx);
|
||||
}
|
||||
free(tokgen);
|
||||
LSQ_DEBUG("destroyed");
|
||||
}
|
||||
|
||||
|
||||
/* To limit reuse of Resume tokens, used Resume tokens are inserted into a
|
||||
* list of Bloom filters with very low false positive rate. Before a Resume
|
||||
* token is used, we check in the Bloom filter. If this token has already
|
||||
* been used, it fails validation.
|
||||
*
|
||||
* There are three ways when this check will fail:
|
||||
* 1. Bloom filter false positive. In this case, Resume token fails
|
||||
* validation, which may cause the server may issue a Retry. This
|
||||
* should happen very infrequently (see below).
|
||||
* 2. Server restart. Because the Bloom filter is stored in process
|
||||
* memory, this will result in false negative and a Resume token can be
|
||||
* reused.
|
||||
* 3. Different working process. Similar to (2).
|
||||
*
|
||||
* Bloom filters are on a linked list. Each filter is used up to MAX_PER_PAGE
|
||||
* values or RESUME_MAX_SECS seconds, after which a new Bloom filter is inserted.
|
||||
* Bloom filters are removed once the most recent element is older than
|
||||
* RESUME_MAX_HOURS hours.
|
||||
*/
|
||||
|
||||
#define RESUME_MAX_SECS (24 * 3600)
|
||||
|
||||
#define N_BLOOM_FUNCS 10
|
||||
|
||||
/* We need 30 bytes to generate 10 24-bit Bloom filter values */
|
||||
typedef char enough_blooms[MIN_RESUME_TOKEN_LEN >= 3 * N_BLOOM_FUNCS ? 1 : -1];
|
||||
|
||||
typedef uint32_t bloom_vals_t[N_BLOOM_FUNCS];
|
||||
|
||||
#define RESUME_TOKEN_PAGE_SIZE (1u << 21)
|
||||
|
||||
/* For memory efficiency, we allocate 2MB chunks of memory,
|
||||
* not 2MB + 28 bytes. Thus, we can't use the whole 24-bit range.
|
||||
*/
|
||||
#define MAX_BLOOM_VALUE ((RESUME_TOKEN_PAGE_SIZE - \
|
||||
sizeof(struct resumed_token_page)) * 8 - 1)
|
||||
|
||||
#define MAX_PER_PAGE 500000
|
||||
/* This works out to 0.00012924% false positive rate:
|
||||
* perl -E '$k=10;$m=1<<24;$n=500000;printf("%.10lf",(1-exp(1)**-($k*$n/$m))**$k)'
|
||||
*/
|
||||
|
||||
static int
|
||||
tokgen_seen_resumed_token (struct token_generator *tokgen,
|
||||
const unsigned char *token, size_t token_sz, bloom_vals_t bloom_vals)
|
||||
{
|
||||
const struct resumed_token_page *page;
|
||||
unsigned n, idx;
|
||||
uintptr_t slot;
|
||||
|
||||
if (1 + N_BLOOM_FUNCS * 3 > token_sz)
|
||||
return 0;
|
||||
|
||||
++token;
|
||||
for (n = 0; n < N_BLOOM_FUNCS; ++n)
|
||||
{
|
||||
bloom_vals[n] = *token++;
|
||||
bloom_vals[n] |= *token++ << 8;
|
||||
bloom_vals[n] |= *token++ << 16;
|
||||
if (bloom_vals[n] > MAX_BLOOM_VALUE)
|
||||
bloom_vals[n] = MAX_BLOOM_VALUE;
|
||||
}
|
||||
|
||||
page = TAILQ_FIRST(&tokgen->tg_resume_token_pages);
|
||||
while (page)
|
||||
{
|
||||
for (n = 0; n < N_BLOOM_FUNCS; ++n)
|
||||
{
|
||||
idx = bloom_vals[n] / (sizeof(page->masks[0]) * 8);
|
||||
slot = 1;
|
||||
slot <<= bloom_vals[n] % (sizeof(page->masks[0]) * 8);
|
||||
if (!(page->masks[idx] & slot))
|
||||
goto next_page;
|
||||
}
|
||||
return 1;
|
||||
next_page:
|
||||
page = TAILQ_NEXT(page, next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void /* void: if it fails, there is nothing to do */
|
||||
tokgen_record_resumed_token (struct token_generator *tokgen, time_t now,
|
||||
bloom_vals_t bloom_vals)
|
||||
{
|
||||
struct resumed_token_page *page;
|
||||
unsigned n, idx;
|
||||
uintptr_t slot;
|
||||
|
||||
/* Expunge old pages at insertion time only to save on time() syscall */
|
||||
while ((page = TAILQ_FIRST(&tokgen->tg_resume_token_pages)))
|
||||
if (page->end + RESUME_MAX_SECS < now)
|
||||
{
|
||||
LSQ_DEBUG("drop resumed cache page");
|
||||
TAILQ_REMOVE(&tokgen->tg_resume_token_pages, page, next);
|
||||
free(page);
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
page = TAILQ_LAST(&tokgen->tg_resume_token_pages, resumed_token_pages_head);
|
||||
if (!(page && page->count < MAX_PER_PAGE && now
|
||||
< page->begin + RESUME_MAX_SECS))
|
||||
{
|
||||
page = calloc(1, RESUME_TOKEN_PAGE_SIZE);
|
||||
if (!page)
|
||||
{
|
||||
LSQ_WARN("cannot allocate resumed cache page");
|
||||
return;
|
||||
}
|
||||
LSQ_DEBUG("allocate resumed cache page");
|
||||
TAILQ_INSERT_TAIL(&tokgen->tg_resume_token_pages, page, next);
|
||||
page->begin = now;
|
||||
page->end = now;
|
||||
page->count = 0;
|
||||
}
|
||||
|
||||
page->end = now;
|
||||
++page->count;
|
||||
|
||||
for (n = 0; n < N_BLOOM_FUNCS; ++n)
|
||||
{
|
||||
idx = bloom_vals[n] / (sizeof(page->masks[0]) * 8);
|
||||
slot = 1;
|
||||
slot <<= bloom_vals[n] % (sizeof(page->masks[0]) * 8);
|
||||
page->masks[idx] |= slot;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char *const tt2str[N_TOKEN_TYPES] = {
|
||||
[TOKEN_RESUME] = "resume",
|
||||
[TOKEN_RETRY] = "retry",
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
lsquic_tg_validate_token (struct token_generator *tokgen,
|
||||
const struct lsquic_packet_in *packet_in, const struct sockaddr *sa_peer,
|
||||
lsquic_cid_t *odcid)
|
||||
{
|
||||
size_t decr_token_len, encr_token_len, ad_len;
|
||||
const unsigned char *nonce, *encr_token, *p, *end, *ad;
|
||||
struct crypter *crypter;
|
||||
enum token_type token_type;
|
||||
time_t issued_at, ttl, now;
|
||||
int is_ipv6;
|
||||
unsigned version;
|
||||
bloom_vals_t bloom_vals;
|
||||
unsigned char decr_token[MAX_RETRY_TOKEN_LEN - RETRY_TAG_LEN
|
||||
- RETRY_NONCE_LEN];
|
||||
char token_str[MAX_RETRY_TOKEN_LEN * 2 + 1];
|
||||
char addr_str[2][INET6_ADDRSTRLEN];
|
||||
|
||||
if (!(packet_in->pi_token && packet_in->pi_token_size))
|
||||
{
|
||||
LSQ_DEBUGC("packet for connection %"CID_FMT" has no token: "
|
||||
"validation failed", CID_BITS(&packet_in->pi_dcid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (packet_in->pi_token_size < RETRY_TAG_LEN + RETRY_NONCE_LEN)
|
||||
{
|
||||
LSQ_DEBUGC("packet for connection %"CID_FMT" has too-short token "
|
||||
"(%hu bytes): validation failed", CID_BITS(&packet_in->pi_dcid),
|
||||
packet_in->pi_token_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
token_type = packet_in->pi_data[packet_in->pi_token];
|
||||
switch (token_type)
|
||||
{
|
||||
case TOKEN_RETRY:
|
||||
ttl = tokgen->tg_retry_token_duration;
|
||||
ad = packet_in->pi_dcid.idbuf;
|
||||
ad_len = packet_in->pi_dcid.len;
|
||||
break;
|
||||
case TOKEN_RESUME:
|
||||
if (tokgen_seen_resumed_token(tokgen, packet_in->pi_data
|
||||
+ packet_in->pi_token, packet_in->pi_token_size, bloom_vals))
|
||||
{
|
||||
LSQ_DEBUGC("%s token for connection %"CID_FMT" has already "
|
||||
"been used: validation failed", tt2str[token_type],
|
||||
CID_BITS(&packet_in->pi_dcid));
|
||||
return -1;
|
||||
}
|
||||
ttl = RESUME_MAX_SECS;
|
||||
ad = NULL;
|
||||
ad_len = 0;
|
||||
break;
|
||||
default:
|
||||
LSQ_DEBUGC("packet for connection %"CID_FMT" has unknown token "
|
||||
"type (%u): validation failed", CID_BITS(&packet_in->pi_dcid),
|
||||
token_type);
|
||||
return -1;
|
||||
}
|
||||
crypter = &tokgen->tg_crypters[ token_type ];
|
||||
|
||||
nonce = packet_in->pi_data + packet_in->pi_token;
|
||||
encr_token = nonce + RETRY_NONCE_LEN;
|
||||
encr_token_len = packet_in->pi_token_size - RETRY_NONCE_LEN;
|
||||
decr_token_len = sizeof(decr_token);
|
||||
if (!EVP_AEAD_CTX_open(&crypter->ctx, decr_token, &decr_token_len,
|
||||
decr_token_len, nonce, RETRY_NONCE_LEN,
|
||||
encr_token, encr_token_len, ad, ad_len))
|
||||
{
|
||||
LSQ_DEBUGC("packet for connection %"CID_FMT" has undecryptable %s "
|
||||
"token %s: validation failed", CID_BITS(&packet_in->pi_dcid),
|
||||
tt2str[token_type],
|
||||
HEXSTR(packet_in->pi_data + packet_in->pi_token,
|
||||
packet_in->pi_token_size, token_str));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* From here on, we begin to warn: this is because we were able to
|
||||
* decrypt it, so this is our token. We should be able to parse it.
|
||||
*/
|
||||
|
||||
p = decr_token;
|
||||
end = p + decr_token_len;
|
||||
|
||||
if (p + 1 > end)
|
||||
goto too_short;
|
||||
version = *p++;
|
||||
if (version != TOKGEN_VERSION)
|
||||
{
|
||||
LSQ_DEBUGC("packet for connection %"CID_FMT" has %s token with "
|
||||
"wrong version %u (expected %u): validation failed",
|
||||
CID_BITS(&packet_in->pi_dcid), tt2str[token_type],
|
||||
version, TOKGEN_VERSION);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p + sizeof(issued_at) > end)
|
||||
goto too_short;
|
||||
memcpy(&issued_at, p, sizeof(issued_at));
|
||||
now = time(NULL);
|
||||
if (issued_at + ttl < now)
|
||||
{
|
||||
LSQ_DEBUGC("%s token for connection %"CID_FMT" expired %lu "
|
||||
"seconds ago", tt2str[token_type], CID_BITS(&packet_in->pi_dcid),
|
||||
(unsigned long) (now - issued_at - ttl));
|
||||
return -1;
|
||||
}
|
||||
p += sizeof(issued_at);
|
||||
|
||||
if (p + 1 > end)
|
||||
goto too_short;
|
||||
is_ipv6 = *p++;
|
||||
if (is_ipv6)
|
||||
{
|
||||
if (p + 16 > end)
|
||||
goto too_short;
|
||||
if (!(AF_INET6 == sa_peer->sa_family &&
|
||||
0 == memcmp(p, &((struct sockaddr_in6 *) sa_peer)->sin6_addr, 16)))
|
||||
goto ip_mismatch;
|
||||
p += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p + 4 > end)
|
||||
goto too_short;
|
||||
if (!(AF_INET == sa_peer->sa_family &&
|
||||
0 == memcmp(p, &((struct sockaddr_in *)
|
||||
sa_peer)->sin_addr.s_addr, 4)))
|
||||
goto ip_mismatch;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
if (TOKEN_RETRY == token_type)
|
||||
{
|
||||
if (p + 2 >= end)
|
||||
goto too_short;
|
||||
if (AF_INET == sa_peer->sa_family)
|
||||
{
|
||||
if (memcmp(p, &((struct sockaddr_in *) sa_peer)->sin_port, 2))
|
||||
goto port_mismatch;
|
||||
}
|
||||
else if (memcmp(p, &((struct sockaddr_in6 *) sa_peer)->sin6_port, 2))
|
||||
goto port_mismatch;
|
||||
if (0 && LSQ_LOG_ENABLED(LSQ_LOG_DEBUG))
|
||||
{
|
||||
uint16_t port;
|
||||
memcpy(&port, p, sizeof(port));
|
||||
port = ntohs(port);
|
||||
LSQ_DEBUG("port %hu in Retry token matches", port);
|
||||
}
|
||||
p += 2;
|
||||
if (end - p > MAX_CID_LEN)
|
||||
goto too_long;
|
||||
if (odcid)
|
||||
{
|
||||
memcpy(odcid->idbuf, p, end - p);
|
||||
odcid->len = end - p;
|
||||
LSQ_DEBUGC("ODCID: %"CID_FMT, CID_BITS(odcid));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p != end)
|
||||
{
|
||||
assert(p < end);
|
||||
goto too_long;
|
||||
}
|
||||
tokgen_record_resumed_token(tokgen, now, bloom_vals);
|
||||
}
|
||||
|
||||
LSQ_DEBUGC("validated %lu-second-old %s token %s for connection "
|
||||
"%"CID_FMT, (unsigned long) (now - issued_at), tt2str[token_type],
|
||||
HEXSTR(packet_in->pi_data + packet_in->pi_token,
|
||||
packet_in->pi_token_size, token_str),
|
||||
CID_BITS(&packet_in->pi_dcid));
|
||||
return 0;
|
||||
|
||||
too_short:
|
||||
LSQ_INFOC("decrypted %s token for connection %"CID_FMT" is too short "
|
||||
"(%zu bytes): validation failed", tt2str[token_type],
|
||||
CID_BITS(&packet_in->pi_dcid), decr_token_len);
|
||||
return -1;
|
||||
|
||||
ip_mismatch:
|
||||
addr_str[0][0] = '\0';
|
||||
addr_str[1][0] = '\0';
|
||||
(void) inet_ntop(is_ipv6 ? AF_INET6 : AF_INET, p, addr_str[0],
|
||||
sizeof(addr_str[0]));
|
||||
if (AF_INET6 == sa_peer->sa_family)
|
||||
(void) inet_ntop(AF_INET6, &((struct sockaddr_in6 *) sa_peer
|
||||
)->sin6_addr, addr_str[1], sizeof(addr_str[1]));
|
||||
else
|
||||
(void) inet_ntop(AF_INET, &((struct sockaddr_in *) sa_peer
|
||||
)->sin_addr.s_addr, addr_str[1], sizeof(addr_str[1]));
|
||||
LSQ_INFOC("IP address %s in %s token for connection %"CID_FMT" does not "
|
||||
"match peer IP address %s: validation failed", addr_str[0],
|
||||
tt2str[token_type], CID_BITS(&packet_in->pi_dcid), addr_str[1]);
|
||||
return -1;
|
||||
|
||||
too_long:
|
||||
LSQ_INFOC("decrypted %s token for connection %"CID_FMT" is too long "
|
||||
"(%zu bytes): validation failed", tt2str[token_type],
|
||||
CID_BITS(&packet_in->pi_dcid), decr_token_len);
|
||||
return -1;
|
||||
|
||||
port_mismatch:
|
||||
{
|
||||
uint16_t ports[2];
|
||||
ports[0] = AF_INET6 == sa_peer->sa_family
|
||||
? ((struct sockaddr_in6 *) sa_peer)->sin6_port
|
||||
: ((struct sockaddr_in *) sa_peer)->sin_port;
|
||||
ports[0] = ntohs(ports[0]);
|
||||
memcpy(&ports[1], p, sizeof(ports[1]));
|
||||
ports[1] = ntohs(ports[1]);
|
||||
LSQ_INFOC("port %hu in %s token for connection %"CID_FMT" does not "
|
||||
"match peer port %hu: validation failed", ports[1], tt2str[token_type],
|
||||
CID_BITS(&packet_in->pi_dcid), ports[0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define LABEL_PREFIX_SZ 8
|
||||
|
||||
static const uint8_t *labels[N_TOKEN_TYPES] =
|
||||
{
|
||||
[TOKEN_RETRY] = (uint8_t *) "retry me",
|
||||
[TOKEN_RESUME] = (uint8_t *) "resume m",
|
||||
};
|
||||
|
||||
|
||||
static ssize_t
|
||||
tokgen_generate_token (struct token_generator *tokgen,
|
||||
enum token_type token_type, unsigned char *buf, size_t bufsz,
|
||||
const unsigned char *ad_buf, size_t ad_len,
|
||||
const struct sockaddr *sa_peer, const lsquic_cid_t *odcid)
|
||||
{
|
||||
struct crypter *crypter;
|
||||
unsigned char *p, *in;
|
||||
time_t now;
|
||||
size_t len, in_len;
|
||||
unsigned char label[ LABEL_PREFIX_SZ + sizeof(crypter->nonce_counter) ];
|
||||
char in_str[(MAX_RETRY_TOKEN_LEN - RETRY_NONCE_LEN
|
||||
- RETRY_TAG_LEN) * 2 + 1],
|
||||
ad_str[ad_len * 2 + 1],
|
||||
token_str[MAX_RETRY_TOKEN_LEN * 2 + 1];
|
||||
|
||||
if (bufsz < MAX_RETRY_TOKEN_LEN)
|
||||
return -1;
|
||||
|
||||
crypter = &tokgen->tg_crypters[ token_type ];
|
||||
p = buf;
|
||||
|
||||
*p = token_type;
|
||||
memcpy(label, labels[token_type], LABEL_PREFIX_SZ);
|
||||
memcpy(label + LABEL_PREFIX_SZ, &crypter->nonce_counter,
|
||||
sizeof(crypter->nonce_counter));
|
||||
(void) HKDF_expand(p + 1, RETRY_NONCE_LEN - 1, EVP_sha256(),
|
||||
crypter->nonce_prk_buf, crypter->nonce_prk_sz, label, sizeof(label));
|
||||
p += RETRY_NONCE_LEN;
|
||||
*p++ = TOKGEN_VERSION;
|
||||
now = time(NULL);
|
||||
memcpy(p, &now, sizeof(now));
|
||||
p += sizeof(now);
|
||||
|
||||
if (AF_INET == sa_peer->sa_family)
|
||||
{
|
||||
*p++ = 0;
|
||||
memcpy(p, &((struct sockaddr_in *) sa_peer)->sin_addr.s_addr, 4);
|
||||
p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = 1;
|
||||
memcpy(p, &((struct sockaddr_in6 *) sa_peer)->sin6_addr, 16);
|
||||
p += 16;
|
||||
}
|
||||
|
||||
if (token_type == TOKEN_RETRY)
|
||||
{
|
||||
if (AF_INET == sa_peer->sa_family)
|
||||
memcpy(p, &((struct sockaddr_in *) sa_peer)->sin_port, 2);
|
||||
else
|
||||
memcpy(p, &((struct sockaddr_in6 *) sa_peer)->sin6_port, 2);
|
||||
p += 2;
|
||||
}
|
||||
|
||||
if (odcid)
|
||||
{
|
||||
assert(odcid->len <= MAX_CID_LEN);
|
||||
memcpy(p, odcid->idbuf, odcid->len);
|
||||
p += odcid->len;
|
||||
}
|
||||
|
||||
len = bufsz - RETRY_NONCE_LEN;
|
||||
in = buf + RETRY_NONCE_LEN;
|
||||
in_len = p - buf - RETRY_NONCE_LEN;
|
||||
if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG))
|
||||
lsquic_hexstr(in, in_len, in_str, sizeof(in_str));
|
||||
if (EVP_AEAD_CTX_seal(&crypter->ctx, in, &len, len,
|
||||
buf, RETRY_NONCE_LEN, in, in_len, ad_buf, ad_len))
|
||||
{
|
||||
++crypter->nonce_counter;
|
||||
LSQ_DEBUG("in: %s, ad: %s -> %s token: %s (%zu bytes)",
|
||||
in_str,
|
||||
HEXSTR(ad_buf, ad_len, ad_str),
|
||||
tt2str[token_type],
|
||||
HEXSTR(buf, RETRY_NONCE_LEN + len, token_str),
|
||||
RETRY_NONCE_LEN + len);
|
||||
return RETRY_NONCE_LEN + len;
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_WARN("could not seal retry token");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
lsquic_tg_generate_retry (struct token_generator *tokgen,
|
||||
unsigned char *buf, size_t bufsz, const unsigned char *scid_buf,
|
||||
size_t scid_len, const struct sockaddr *sa_peer,
|
||||
const lsquic_cid_t *odcid)
|
||||
{
|
||||
return tokgen_generate_token(tokgen, TOKEN_RETRY, buf, bufsz, scid_buf,
|
||||
scid_len, sa_peer, odcid);
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
lsquic_tg_generate_resume (struct token_generator *tokgen,
|
||||
unsigned char *buf, size_t bufsz, const struct sockaddr *sa_peer)
|
||||
{
|
||||
return tokgen_generate_token(tokgen, TOKEN_RESUME, buf, bufsz, NULL,
|
||||
0, sa_peer, NULL);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_tg_token_size (const struct token_generator *tokgen,
|
||||
enum token_type token_type, const struct sockaddr *sa_peer)
|
||||
{
|
||||
return MAX_RETRY_TOKEN_LEN - 16
|
||||
+ (AF_INET == sa_peer->sa_family ? 4 : 16);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_tg_generate_sreset (struct token_generator *tokgen,
|
||||
const struct lsquic_cid *cid, unsigned char *reset_token)
|
||||
|
|
|
@ -7,6 +7,8 @@ struct sockaddr;
|
|||
struct lsquic_packet_in;
|
||||
struct lsquic_cid;
|
||||
|
||||
enum token_type { TOKEN_RETRY, TOKEN_RESUME, N_TOKEN_TYPES, };
|
||||
|
||||
struct token_generator;
|
||||
|
||||
struct token_generator *
|
||||
|
@ -20,4 +22,44 @@ void
|
|||
lsquic_tg_generate_sreset (struct token_generator *,
|
||||
const struct lsquic_cid *cid, unsigned char *reset_token);
|
||||
|
||||
|
||||
/* Retry and Resume tokens have identical sizes. Use *RETRY* macros
|
||||
* for both.
|
||||
*/
|
||||
#define RETRY_TAG_LEN 16
|
||||
|
||||
/* Type is encoded in the nonce */
|
||||
#define RETRY_NONCE_LEN 12
|
||||
|
||||
#define MAX_RETRY_TOKEN_LEN (RETRY_NONCE_LEN + 1 /* version */ + \
|
||||
sizeof(time_t) /* time */ + 1 /* IPv4 or IPv6 */ + \
|
||||
16 /* IPv6 or IPv4 address */ + 2 /* Port number */ + MAX_CID_LEN + \
|
||||
RETRY_TAG_LEN)
|
||||
|
||||
/* Need this to make sure we have enough bytes for Bloom filter functions */
|
||||
#define MIN_RESUME_TOKEN_LEN (RETRY_NONCE_LEN + 1 /* version */ + \
|
||||
sizeof(time_t) /* time */ + 1 /* IPv4 or IPv6 */ + \
|
||||
4 /* IPv4 address */ + 0 /* No port number */ + 0 /* No CID */ + \
|
||||
RETRY_TAG_LEN)
|
||||
|
||||
ssize_t
|
||||
lsquic_tg_generate_retry (struct token_generator *,
|
||||
unsigned char *buf, size_t bufsz,
|
||||
const unsigned char *scid_buf, size_t scid_len,
|
||||
const struct sockaddr *sa_peer, const struct lsquic_cid *odcid);
|
||||
|
||||
ssize_t
|
||||
lsquic_tg_generate_resume (struct token_generator *,
|
||||
unsigned char *buf, size_t bufsz,
|
||||
const struct sockaddr *sa_peer);
|
||||
|
||||
int
|
||||
lsquic_tg_validate_token (struct token_generator *,
|
||||
const struct lsquic_packet_in *, const struct sockaddr *,
|
||||
struct lsquic_cid *);
|
||||
|
||||
size_t
|
||||
lsquic_tg_token_size (const struct token_generator *tokgen,
|
||||
enum token_type token_type, const struct sockaddr *sa_peer);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "Ws2tcpip.h"
|
||||
#endif
|
||||
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_byteswap.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_types.h"
|
||||
|
@ -54,6 +55,7 @@ tpi_val_2_enum (uint64_t tpi_val)
|
|||
case 14: return TPI_ACTIVE_CONNECTION_ID_LIMIT;
|
||||
case 15: return TPI_INITIAL_SOURCE_CID;
|
||||
case 16: return TPI_RETRY_SOURCE_CID;
|
||||
case 17: return TPI_VERSION_INFORMATION;
|
||||
case 0x20: return TPI_MAX_DATAGRAM_FRAME_SIZE;
|
||||
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||
case 0xC37: return TPI_QUANTUM_READINESS;
|
||||
|
@ -87,6 +89,7 @@ static const unsigned enum_2_tpi_val[LAST_TPI + 1] =
|
|||
[TPI_ACTIVE_CONNECTION_ID_LIMIT] = 0xE,
|
||||
[TPI_INITIAL_SOURCE_CID] = 0xF,
|
||||
[TPI_RETRY_SOURCE_CID] = 0x10,
|
||||
[TPI_VERSION_INFORMATION] = 0x11,
|
||||
[TPI_MAX_DATAGRAM_FRAME_SIZE] = 0x20,
|
||||
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||
[TPI_QUANTUM_READINESS] = 0xC37,
|
||||
|
@ -267,6 +270,8 @@ lsquic_tp_encode (const struct transport_params *params, int is_server,
|
|||
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||
const size_t quantum_sz = lsquic_tp_get_quantum_sz();
|
||||
#endif
|
||||
lsquic_ver_tag_t tag;
|
||||
int i;
|
||||
|
||||
need = 0;
|
||||
set = params->tp_set; /* Will turn bits off for default values */
|
||||
|
@ -357,6 +362,16 @@ lsquic_tp_encode (const struct transport_params *params, int is_server,
|
|||
need += (1 << bits[tpi][0]) + 1 /* Zero length byte */;
|
||||
}
|
||||
|
||||
if (set & (1 << TPI_VERSION_INFORMATION))
|
||||
{
|
||||
tpi = TPI_VERSION_INFORMATION;
|
||||
bits[tpi][0] = vint_val2bits(enum_2_tpi_val[tpi]);
|
||||
bits[tpi][1] = vint_val2bits(params->tp_version_cnt << 2);
|
||||
need += (1 << bits[tpi][0])
|
||||
+ (1 << bits[tpi][1])
|
||||
+ (params->tp_version_cnt << 2);
|
||||
}
|
||||
|
||||
if (need > bufsz || need > UINT16_MAX)
|
||||
{
|
||||
errno = ENOBUFS;
|
||||
|
@ -458,6 +473,17 @@ lsquic_tp_encode (const struct transport_params *params, int is_server,
|
|||
p += quantum_sz;
|
||||
break;
|
||||
#endif
|
||||
case TPI_VERSION_INFORMATION:
|
||||
//FIXME: generate supported version info.
|
||||
vint_write(p, params->tp_version_cnt << 2,
|
||||
bits[tpi][1], 1 << bits[tpi][1]);
|
||||
p += 1 << bits[tpi][1];
|
||||
for(i = 0; i < params->tp_version_cnt; ++i)
|
||||
{
|
||||
tag = lsquic_ver2tag(params->tp_version_info[i]);
|
||||
WRITE_TO_P(&tag, 4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,6 +506,7 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
|
|||
enum transport_param_id tpi;
|
||||
unsigned set_of_ids;
|
||||
int s;
|
||||
lsquic_ver_tag_t tag;
|
||||
|
||||
p = buf;
|
||||
end = buf + bufsz;
|
||||
|
@ -643,6 +670,31 @@ lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
|
|||
if (q != p + len)
|
||||
return -1;
|
||||
break;
|
||||
case TPI_VERSION_INFORMATION:
|
||||
if (len & 0x3)
|
||||
return -1;
|
||||
q = p;
|
||||
while(q < p + len)
|
||||
{
|
||||
memmove(&tag, q, 4);
|
||||
if (tag == 0)
|
||||
return -1;
|
||||
int ver = lsquic_tag2ver(tag);
|
||||
if (ver != -1)
|
||||
{
|
||||
if (params->tp_version_cnt > 0)
|
||||
params->tp_versions |= 1 << ver;
|
||||
if (params->tp_version_cnt < sizeof(params->tp_version_info))
|
||||
params->tp_version_info[params->tp_version_cnt++] = ver;
|
||||
}
|
||||
else if (params->tp_version_cnt == 0)
|
||||
return -1;
|
||||
q += 4;
|
||||
}
|
||||
if (!is_server && (params->tp_versions
|
||||
& (1 << params->tp_chosen_version)) == 0)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
/* Do nothing: skip this transport parameter */
|
||||
break;
|
||||
|
@ -693,6 +745,7 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
|
|||
enum transport_param_id tpi;
|
||||
char tok_str[sizeof(params->tp_stateless_reset_token) * 2 + 1];
|
||||
char addr_str[INET6_ADDRSTRLEN];
|
||||
int i;
|
||||
|
||||
for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
|
||||
if (params->tp_set & (1 << tpi))
|
||||
|
@ -766,6 +819,23 @@ lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (params->tp_set & (1 << TPI_VERSION_INFORMATION))
|
||||
{
|
||||
nw = snprintf(buf, end - buf, "; version information: chosen: %s, available:",
|
||||
lsquic_ver2str[params->tp_chosen_version]);
|
||||
buf += nw;
|
||||
if (buf >= end)
|
||||
return;
|
||||
for(i = 1; i < params->tp_version_cnt; ++i)
|
||||
{
|
||||
nw = snprintf(buf, end - buf, " %s",
|
||||
lsquic_ver2str[params->tp_version_info[i]]);
|
||||
buf += nw;
|
||||
if (buf >= end)
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -988,6 +1058,8 @@ lsquic_tp_encode_27 (const struct transport_params *params, int is_server,
|
|||
p += quantum_sz;
|
||||
break;
|
||||
#endif
|
||||
case TPI_VERSION_INFORMATION:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ enum transport_param_id
|
|||
#if LSQUIC_TEST_QUANTUM_READINESS
|
||||
TPI_QUANTUM_READINESS,
|
||||
#endif
|
||||
TPI_VERSION_INFORMATION,
|
||||
TPI_STATELESS_RESET_TOKEN, LAST_TPI = TPI_STATELESS_RESET_TOKEN
|
||||
};
|
||||
|
||||
|
@ -106,6 +107,10 @@ struct transport_params
|
|||
#define tp_original_dest_cid tp_cids[TP_CID_IDX(TPI_ORIGINAL_DEST_CID)]
|
||||
#define tp_initial_source_cid tp_cids[TP_CID_IDX(TPI_INITIAL_SOURCE_CID)]
|
||||
#define tp_retry_source_cid tp_cids[TP_CID_IDX(TPI_RETRY_SOURCE_CID)]
|
||||
unsigned tp_versions;
|
||||
uint8_t tp_version_cnt;
|
||||
uint8_t tp_version_info[7];
|
||||
#define tp_chosen_version tp_version_info[0]
|
||||
};
|
||||
|
||||
#define MAX_TP_STR_SZ ((LAST_TPI + 1) * \
|
||||
|
|
|
@ -18,7 +18,8 @@ static const unsigned char version_tags[N_LSQVER][4] =
|
|||
[LSQVER_ID27] = { 0xFF, 0, 0, 27, },
|
||||
[LSQVER_ID29] = { 0xFF, 0, 0, 29, },
|
||||
[LSQVER_I001] = { 0, 0, 0, 1, },
|
||||
[LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, },
|
||||
[LSQVER_I002] = { 0x6B, 0x33, 0x43, 0xCF },
|
||||
[LSQVER_RESVED] = { 0xFA, 0xFA, 0xFA, 0xFA, },
|
||||
};
|
||||
|
||||
|
||||
|
@ -47,6 +48,37 @@ lsquic_tag2ver (uint32_t ver_tag)
|
|||
}
|
||||
|
||||
|
||||
enum lsquic_version
|
||||
lsquic_tag2ver_fast (const unsigned char *tag)
|
||||
{
|
||||
unsigned char ch;
|
||||
ch = *tag;
|
||||
if (ch == 'Q' && *(tag + 1) == '0')
|
||||
{
|
||||
if (*(tag + 2) == '5' && *(tag + 3) == '0')
|
||||
return LSQVER_050;
|
||||
else if (*(tag + 2) == '4' && *(tag + 3) == '6')
|
||||
return LSQVER_046;
|
||||
}
|
||||
else if (ch == 0x6b && *(tag + 1) == 0x33
|
||||
&& *(tag + 2) == 0x43 && *(tag + 3) == 0xcf)
|
||||
{
|
||||
return LSQVER_I002;
|
||||
}
|
||||
else if (ch == '\0' && *(tag + 1) == 0 && *(tag + 2) == 0)
|
||||
{
|
||||
if (*(tag + 3) == 0x01)
|
||||
return LSQVER_I001;
|
||||
else if (*(tag + 3) == 0x00)
|
||||
return LSQVER_VERNEG;
|
||||
}
|
||||
else if ((ch & 0xf) == 0xa && (*(tag + 1) & 0xf) == 0xa
|
||||
&& (*(tag + 2) & 0xf) == 0xa && (*(tag + 3) & 0xf) == 0xa)
|
||||
return LSQVER_RESVED;
|
||||
return N_LSQVER;
|
||||
}
|
||||
|
||||
|
||||
const char *const lsquic_ver2str[N_LSQVER] = {
|
||||
[LSQVER_043] = "Q043",
|
||||
[LSQVER_046] = "Q046",
|
||||
|
@ -54,7 +86,8 @@ const char *const lsquic_ver2str[N_LSQVER] = {
|
|||
[LSQVER_ID27] = "FF00001B",
|
||||
[LSQVER_ID29] = "FF00001D",
|
||||
[LSQVER_I001] = "00000001",
|
||||
[LSQVER_VERNEG] = "FAFAFAFA",
|
||||
[LSQVER_I002] = "6B3343CF",
|
||||
[LSQVER_RESVED] = "FAFAFAFA",
|
||||
};
|
||||
|
||||
|
||||
|
@ -65,7 +98,8 @@ const char *const lsquic_ver2altstr[N_LSQVER] = {
|
|||
[LSQVER_ID27] = "h3-27",
|
||||
[LSQVER_ID29] = "h3-29",
|
||||
[LSQVER_I001] = "h3",
|
||||
[LSQVER_VERNEG] = "VERNEG",
|
||||
[LSQVER_I002] = "h3-v2",
|
||||
[LSQVER_RESVED] = "RESERVED",
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ lsquic_ver2tag (unsigned version);
|
|||
enum lsquic_version
|
||||
lsquic_tag2ver (uint32_t ver_tag);
|
||||
|
||||
enum lsquic_version
|
||||
lsquic_tag2ver_fast (const unsigned char * tag);
|
||||
|
||||
extern const char *const lsquic_ver2str[];
|
||||
|
||||
int
|
||||
|
|
|
@ -179,7 +179,7 @@ run_test (const struct test *test)
|
|||
size_t sz;
|
||||
unsigned char buf[0x1000];
|
||||
|
||||
pf = select_pf_by_ver(LSQVER_ID27);
|
||||
pf = select_pf_by_ver(LSQVER_I001);
|
||||
if (!test->skip_gen)
|
||||
{
|
||||
rechist.acki = &test->acki;
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
|
||||
static struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 0);
|
||||
|
||||
//static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_ID27); // will not work on MSVC
|
||||
#define pf ((const struct parse_funcs *const)select_pf_by_ver(LSQVER_ID27))
|
||||
//static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_I001); // will not work on MSVC
|
||||
#define pf ((const struct parse_funcs *const)select_pf_by_ver(LSQVER_I001))
|
||||
|
||||
|
||||
static void
|
||||
|
|
|
@ -103,7 +103,7 @@ main (void)
|
|||
const struct test tests[] = {
|
||||
|
||||
{ .lineno = __LINE__,
|
||||
.pf = select_pf_by_ver(LSQVER_ID27),
|
||||
.pf = select_pf_by_ver(LSQVER_I001),
|
||||
.offset = 0,
|
||||
.data_sz = 10,
|
||||
.data = "0123456789",
|
||||
|
@ -119,7 +119,7 @@ main (void)
|
|||
},
|
||||
|
||||
{ .lineno = __LINE__,
|
||||
.pf = select_pf_by_ver(LSQVER_ID27),
|
||||
.pf = select_pf_by_ver(LSQVER_I001),
|
||||
.offset = 500,
|
||||
.data_sz = 10,
|
||||
.data = "0123456789",
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
static const struct parse_funcs *g_pf = select_pf_by_ver(LSQVER_ID27);
|
||||
static const struct parse_funcs *g_pf = select_pf_by_ver(LSQVER_I001);
|
||||
|
||||
struct test_ctl_settings
|
||||
{
|
||||
|
@ -343,7 +343,7 @@ init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window,
|
|||
memset(tobjs, 0, sizeof(*tobjs));
|
||||
LSCONN_INITIALIZE(&tobjs->lconn);
|
||||
tobjs->lconn.cn_pf = g_pf;
|
||||
tobjs->lconn.cn_version = LSQVER_ID27;
|
||||
tobjs->lconn.cn_version = LSQVER_I001;
|
||||
tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_ietf_v1;
|
||||
network_path.np_pack_size = packet_sz;
|
||||
tobjs->lconn.cn_if = &our_conn_if;
|
||||
|
|
|
@ -214,7 +214,7 @@ new_packet (struct test_ctx *ctx)
|
|||
*/
|
||||
|
||||
packet_out = lsquic_packet_out_new(&ctx->enpub.enp_mm, ctx->enpub.enp_mm.malo.packet_out, 1,
|
||||
&ctx->lconn, PACKNO_BITS_0, 0, NULL, &ctx->path, HETY_NOT_SET);
|
||||
&ctx->lconn, PACKNO_BITS_0, 0, NULL, &ctx->path, HETY_SHORT);
|
||||
if (packet_out)
|
||||
packet_out->po_packno = packno++;
|
||||
|
||||
|
|
|
@ -185,8 +185,8 @@ init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window,
|
|||
int s;
|
||||
memset(tobjs, 0, sizeof(*tobjs));
|
||||
LSCONN_INITIALIZE(&tobjs->lconn);
|
||||
tobjs->lconn.cn_pf = select_pf_by_ver(LSQVER_ID27);
|
||||
tobjs->lconn.cn_version = LSQVER_ID27;
|
||||
tobjs->lconn.cn_pf = select_pf_by_ver(LSQVER_I001);
|
||||
tobjs->lconn.cn_version = LSQVER_I001;
|
||||
tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_ietf_v1;
|
||||
network_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ;
|
||||
tobjs->lconn.cn_if = &our_conn_if;
|
||||
|
|
|
@ -363,7 +363,7 @@ init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window,
|
|||
LSCONN_INITIALIZE(&tobjs->lconn);
|
||||
tobjs->lconn.cn_pf = pf ? pf : g_pf;
|
||||
tobjs->lconn.cn_version = tobjs->lconn.cn_pf == &lsquic_parse_funcs_ietf_v1 ?
|
||||
LSQVER_ID27 : LSQVER_043;
|
||||
LSQVER_I001 : LSQVER_043;
|
||||
tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_gquic_1;
|
||||
network_path.np_pack_size = 1370;
|
||||
tobjs->lconn.cn_if = &our_conn_if;
|
||||
|
@ -1620,7 +1620,7 @@ test_termination (void)
|
|||
{
|
||||
init_test_ctl_settings(&g_ctl_settings);
|
||||
g_ctl_settings.tcs_schedule_stream_packets_immediately = 1;
|
||||
init_test_objs(&tobjs, 0x4000, 0x4000, select_pf_by_ver(LSQVER_ID27));
|
||||
init_test_objs(&tobjs, 0x4000, 0x4000, select_pf_by_ver(LSQVER_I001));
|
||||
tf->func(&tobjs);
|
||||
deinit_test_objs(&tobjs);
|
||||
}
|
||||
|
@ -2619,7 +2619,7 @@ test_changing_pack_size (void)
|
|||
enum lsquic_version versions_to_test[3] =
|
||||
{
|
||||
LSQVER_046,
|
||||
LSQVER_ID27,
|
||||
LSQVER_I001,
|
||||
};
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
|
@ -3005,7 +3005,7 @@ test_resize_buffered (void)
|
|||
ssize_t nw;
|
||||
struct test_objs tobjs;
|
||||
struct lsquic_stream *streams[1];
|
||||
const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_ID27);
|
||||
const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_I001);
|
||||
char buf[0x10000];
|
||||
unsigned char buf_out[0x10000];
|
||||
int s, fin;
|
||||
|
@ -3068,7 +3068,7 @@ test_resize_scheduled (void)
|
|||
ssize_t nw;
|
||||
struct test_objs tobjs;
|
||||
struct lsquic_stream *streams[1];
|
||||
const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_ID27);
|
||||
const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_I001);
|
||||
char buf[0x10000];
|
||||
unsigned char buf_out[0x10000];
|
||||
int s, fin;
|
||||
|
@ -3260,8 +3260,8 @@ test_packetization (int schedule_stream_packets_immediately, int dispatch_once,
|
|||
|
||||
if (g_use_crypto_ctor)
|
||||
{
|
||||
stream_ids[0] = ENC_LEV_CLEAR;
|
||||
stream_ids[1] = ENC_LEV_INIT;
|
||||
stream_ids[0] = ENC_LEV_INIT;
|
||||
stream_ids[1] = ENC_LEV_HSK;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3754,7 +3754,7 @@ main (int argc, char **argv)
|
|||
|
||||
/* Redo some tests using crypto streams and frames */
|
||||
g_use_crypto_ctor = 1;
|
||||
g_pf = select_pf_by_ver(LSQVER_ID27);
|
||||
g_pf = select_pf_by_ver(LSQVER_I001);
|
||||
main_test_packetization();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -371,7 +371,7 @@ main (void)
|
|||
*/
|
||||
|
||||
{ .lineno = __LINE__,
|
||||
.pf = select_pf_by_ver(LSQVER_ID27),
|
||||
.pf = select_pf_by_ver(LSQVER_I001),
|
||||
.fin = { 0, 1, },
|
||||
.offset = 0x0807060504030201UL,
|
||||
.stream_id = 0x210,
|
||||
|
@ -391,7 +391,7 @@ main (void)
|
|||
},
|
||||
|
||||
{ .lineno = __LINE__,
|
||||
.pf = select_pf_by_ver(LSQVER_ID27),
|
||||
.pf = select_pf_by_ver(LSQVER_I001),
|
||||
.fin = { 0, 0, },
|
||||
.offset = 0,
|
||||
.stream_id = 0x210,
|
||||
|
@ -410,7 +410,7 @@ main (void)
|
|||
},
|
||||
|
||||
{ .lineno = __LINE__,
|
||||
.pf = select_pf_by_ver(LSQVER_ID27),
|
||||
.pf = select_pf_by_ver(LSQVER_I001),
|
||||
.fin = { 0, 0, },
|
||||
.offset = 0,
|
||||
.stream_id = 0x21,
|
||||
|
@ -428,7 +428,7 @@ main (void)
|
|||
},
|
||||
|
||||
{ .lineno = __LINE__,
|
||||
.pf = select_pf_by_ver(LSQVER_ID27),
|
||||
.pf = select_pf_by_ver(LSQVER_I001),
|
||||
.fin = { 0, 0, },
|
||||
.offset = 0x0807060504030201UL,
|
||||
.stream_id = 0x210,
|
||||
|
@ -448,7 +448,7 @@ main (void)
|
|||
},
|
||||
|
||||
{ .lineno = __LINE__,
|
||||
.pf = select_pf_by_ver(LSQVER_ID27),
|
||||
.pf = select_pf_by_ver(LSQVER_I001),
|
||||
.fin = { 1, 0, },
|
||||
.offset = 0x0807060504030201UL,
|
||||
.stream_id = 0x210,
|
||||
|
@ -466,7 +466,7 @@ main (void)
|
|||
},
|
||||
|
||||
{ .lineno = __LINE__,
|
||||
.pf = select_pf_by_ver(LSQVER_ID27),
|
||||
.pf = select_pf_by_ver(LSQVER_I001),
|
||||
.fin = { 1, 0, },
|
||||
.offset = 0x0807060504030201UL,
|
||||
.stream_id = 0x210,
|
||||
|
|
|
@ -274,7 +274,7 @@ main (void)
|
|||
|
||||
{ "Balls to the wall: every possible bit is set",
|
||||
__LINE__,
|
||||
select_pf_by_ver(LSQVER_ID27),
|
||||
select_pf_by_ver(LSQVER_I001),
|
||||
/* TYPE OFF DLEN FIN */
|
||||
{ 0x10 | 1<<2 | 1<<1 | 1<<0,
|
||||
0x41, 0x23, /* Stream ID */
|
||||
|
@ -293,7 +293,7 @@ main (void)
|
|||
|
||||
{ "Balls to the wall #2: every possible bit is set except FIN",
|
||||
__LINE__,
|
||||
select_pf_by_ver(LSQVER_ID27),
|
||||
select_pf_by_ver(LSQVER_I001),
|
||||
/* TYPE OFF DLEN FIN */
|
||||
{ 0x10 | 1<<2 | 1<<1 | 0<<0,
|
||||
0x81, 0x23, 0x00, 0xE4, /* Stream ID */
|
||||
|
@ -312,7 +312,7 @@ main (void)
|
|||
|
||||
{ "Data length is zero",
|
||||
__LINE__,
|
||||
select_pf_by_ver(LSQVER_ID27),
|
||||
select_pf_by_ver(LSQVER_I001),
|
||||
/* TYPE OFF DLEN FIN */
|
||||
{ 0x10 | 1<<2 | 0<<1 | 0<<0,
|
||||
0x81, 0x23, 0x00, 0xE4, /* Stream ID */
|
||||
|
@ -330,7 +330,7 @@ main (void)
|
|||
|
||||
{ "Sanity check: what happens when data length is zero #1",
|
||||
__LINE__,
|
||||
select_pf_by_ver(LSQVER_ID27),
|
||||
select_pf_by_ver(LSQVER_I001),
|
||||
/* TYPE OFF DLEN FIN */
|
||||
{ 0x10 | 1<<2 | 1<<1 | 0<<0,
|
||||
0x81, 0x23, 0x00, 0xE4, /* Stream ID */
|
||||
|
@ -349,7 +349,7 @@ main (void)
|
|||
|
||||
{ "Sanity check: what happens when data length is zero #2",
|
||||
__LINE__,
|
||||
select_pf_by_ver(LSQVER_ID27),
|
||||
select_pf_by_ver(LSQVER_I001),
|
||||
/* TYPE OFF DLEN FIN */
|
||||
{ 0x10 | 1<<2 | 1<<1 | 0<<0,
|
||||
0x81, 0x23, 0x00, 0xE4, /* Stream ID */
|
||||
|
@ -368,7 +368,7 @@ main (void)
|
|||
|
||||
{ "Sanity check: what happens when data length is zero #3",
|
||||
__LINE__,
|
||||
select_pf_by_ver(LSQVER_ID27),
|
||||
select_pf_by_ver(LSQVER_I001),
|
||||
/* TYPE OFF DLEN FIN */
|
||||
{ 0x10 | 0<<2 | 1<<1 | 0<<0,
|
||||
0x81, 0x23, 0x00, 0xE4, /* Stream ID */
|
||||
|
@ -386,7 +386,7 @@ main (void)
|
|||
|
||||
{ "Sanity check: what happens when data length is zero #3",
|
||||
__LINE__,
|
||||
select_pf_by_ver(LSQVER_ID27),
|
||||
select_pf_by_ver(LSQVER_I001),
|
||||
/* TYPE OFF DLEN FIN */
|
||||
{ 0x10 | 1<<2 | 1<<1 | 1<<0,
|
||||
0x81, 0x23, 0x00, 0xE4, /* Stream ID */
|
||||
|
@ -405,7 +405,7 @@ main (void)
|
|||
|
||||
{ "Check data bounds #1",
|
||||
__LINE__,
|
||||
select_pf_by_ver(LSQVER_ID27),
|
||||
select_pf_by_ver(LSQVER_I001),
|
||||
/* TYPE OFF DLEN FIN */
|
||||
{ 0x10 | 1<<2 | 1<<1 | 1<<0,
|
||||
0x81, 0x23, 0x00, 0xE4, /* Stream ID */
|
||||
|
@ -424,7 +424,7 @@ main (void)
|
|||
|
||||
{ "Check data bounds #2",
|
||||
__LINE__,
|
||||
select_pf_by_ver(LSQVER_ID27),
|
||||
select_pf_by_ver(LSQVER_I001),
|
||||
/* TYPE OFF DLEN FIN */
|
||||
{ 0x10 | 1<<2 | 1<<1 | 1<<0,
|
||||
0x81, 0x23, 0x00, 0xE4, /* Stream ID */
|
||||
|
|
Loading…
Reference in a new issue