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));
 | 
			
		||||
            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));
 | 
			
		||||
            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,
 | 
			
		||||
                /* 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));
 | 
			
		||||
    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; "
 | 
			
		||||
            "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,
 | 
			
		||||
        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_enc_data_sz);
 | 
			
		||||
    else if (packet_out->po_lflags & POL_LOG_QL_BITS)
 | 
			
		||||
        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],
 | 
			
		||||
                /* 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,6 +1359,9 @@ lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *enpub,
 | 
			
		|||
 | 
			
		||||
    assert(versions);
 | 
			
		||||
    versions &= LSQUIC_IETF_VERSIONS;
 | 
			
		||||
    if (versions & (1 << LSQVER_I001))
 | 
			
		||||
        ver = LSQVER_I001;
 | 
			
		||||
    else
 | 
			
		||||
        ver = highest_bit_set(versions);
 | 
			
		||||
    if (sess_resume)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    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,
 | 
			
		||||
                &conn->imc_cces[0].cce_cid, &conn->imc_path.np_dcid);
 | 
			
		||||
                    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,6 +652,20 @@ 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);
 | 
			
		||||
    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,16 +791,115 @@ 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 *
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			@ -1594,17 +1857,29 @@ 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 (packet_out->po_frame_types & IQUIC_FRAME_RETX_MASK)
 | 
			
		||||
            {
 | 
			
		||||
                if (0 == retx_to)
 | 
			
		||||
                    retx_to = imico_calc_retx_timeout(conn);
 | 
			
		||||
            if (packet_out->po_sent + retx_to < now)
 | 
			
		||||
                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_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
 | 
			
		||||
            {
 | 
			
		||||
                TAILQ_REMOVE(&conn->imc_packets_out, packet_out, po_next);
 | 
			
		||||
                imico_destroy_packet(conn, packet_out);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (packet_size = lsquic_packet_out_total_sz(lconn, packet_out),
 | 
			
		||||
                                                imico_can_send(conn, packet_size))
 | 
			
		||||
            ++n_to_send;
 | 
			
		||||
| 
						 | 
				
			
			@ -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(
 | 
			
		||||
    len = imico_build_ack_frame(conn, pns, now,
 | 
			
		||||
            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);
 | 
			
		||||
            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",
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -177,6 +177,7 @@ enum
 | 
			
		|||
enum header_type
 | 
			
		||||
{
 | 
			
		||||
    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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -241,7 +243,8 @@ extern const char *const lsquic_pns2str[];
 | 
			
		|||
 */
 | 
			
		||||
#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))
 | 
			
		||||
            | 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,17 +21,21 @@ 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)
 | 
			
		||||
    enum lsquic_version version;
 | 
			
		||||
    if (length < 6)
 | 
			
		||||
        return -1;
 | 
			
		||||
    version = lsquic_tag2ver_fast(packet_in->pi_data + 1);
 | 
			
		||||
    if (version != N_LSQVER)
 | 
			
		||||
    {
 | 
			
		||||
        memcpy(&tag, packet_in->pi_data + 1, 4);
 | 
			
		||||
        switch (tag)
 | 
			
		||||
        packet_in->pi_version = version;
 | 
			
		||||
        packet_in->pi_flags |= PI_VER_PARSED;
 | 
			
		||||
    }
 | 
			
		||||
    switch (version)
 | 
			
		||||
    {
 | 
			
		||||
        case TAG('Q', '0', '4', '6'):
 | 
			
		||||
    case LSQVER_046:
 | 
			
		||||
        return lsquic_Q046_parse_packet_in_long_begin(packet_in, length,
 | 
			
		||||
                                                is_server, cid_len, state);
 | 
			
		||||
        case TAG('Q', '0', '5', '0'):
 | 
			
		||||
    case LSQVER_050:
 | 
			
		||||
        return lsquic_Q050_parse_packet_in_long_begin(packet_in, length,
 | 
			
		||||
                                                is_server, cid_len, state);
 | 
			
		||||
    default:
 | 
			
		||||
| 
						 | 
				
			
			@ -39,9 +43,6 @@ parse_ietf_v1_or_Q046plus_long_begin (struct lsquic_packet_in *packet_in,
 | 
			
		|||
                                                is_server, cid_len, state);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    else
 | 
			
		||||
        return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int (* const parse_begin_funcs[32]) (struct lsquic_packet_in *,
 | 
			
		||||
| 
						 | 
				
			
			@ -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_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
 | 
			
		||||
                    | 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_FORW]  = QUIC_FTBIT_CRYPTO | 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
 | 
			
		||||
                    | 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,6 +214,12 @@ gen_long_pkt_header (const struct lsquic_conn *lconn,
 | 
			
		|||
 | 
			
		||||
    packno_bits = lsquic_packet_out_packno_bits(packet_out);
 | 
			
		||||
    p = buf;
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    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++;
 | 
			
		||||
 | 
			
		||||
    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,8 +377,9 @@ 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),
 | 
			
		||||
    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:
 | 
			
		||||
        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;
 | 
			
		||||
        LSQ_DEBUG("packet RTO is %"PRIu64" usec", expiry);
 | 
			
		||||
        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);
 | 
			
		||||
        }
 | 
			
		||||
        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);
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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))
 | 
			
		||||
    {
 | 
			
		||||
        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,19 +2067,27 @@ 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))
 | 
			
		||||
    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…
	
	Add table
		Add a link
		
	
		Reference in a new issue