From: Frédéric Lécaille Date: Mon, 27 Nov 2023 10:34:03 +0000 (+0100) Subject: REORG: quic: Move several inlined functions from quic_conn.h X-Git-Tag: v2.9-dev12~65 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=09ab48472ccb8fcb3e26a276627387455cdbd4e5;p=thirdparty%2Fhaproxy.git REORG: quic: Move several inlined functions from quic_conn.h Move quic_pkt_type(), quic_saddr_cpy(), quic_write_uint32(), max_available_room(), max_stream_data_size(), quic_packet_number_length(), quic_packet_number_encode() and quic_compute_ack_delay_us() to quic_tx.c because only used in this file. Also move quic_ack_delay_ms() and quic_read_uint32() to quic_tx.c because they are used only in this file. Move quic_rx_packet_refinc() and quic_rx_packet_refdec() to quic_rx.h header. Move qc_el_rx_pkts(), qc_el_rx_pkts_del() and qc_list_qel_rx_pkts() to quic_tls.h header. --- diff --git a/include/haproxy/quic_conn.h b/include/haproxy/quic_conn.h index ec8d4b24ea..9ff559646c 100644 --- a/include/haproxy/quic_conn.h +++ b/include/haproxy/quic_conn.h @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include @@ -85,64 +85,11 @@ void qc_check_close_on_released_mux(struct quic_conn *qc); int quic_stateless_reset_token_cpy(unsigned char *pos, size_t len, const unsigned char *salt, size_t saltlen); -/* Return the long packet type matching with version and */ -static inline int quic_pkt_type(int type, uint32_t version) -{ - if (version != QUIC_PROTOCOL_VERSION_2) - return type; - - switch (type) { - case QUIC_PACKET_TYPE_INITIAL: - return 1; - case QUIC_PACKET_TYPE_0RTT: - return 2; - case QUIC_PACKET_TYPE_HANDSHAKE: - return 3; - case QUIC_PACKET_TYPE_RETRY: - return 0; - } - - return -1; -} - static inline int qc_is_listener(struct quic_conn *qc) { return qc->flags & QUIC_FL_CONN_LISTENER; } -/* Copy socket address data into buffer. - * This is the responsibility of the caller to check the output buffer is big - * enough to contain these socket address data. - * Return the number of bytes copied. - */ -static inline size_t quic_saddr_cpy(unsigned char *buf, - const struct sockaddr_storage *saddr) -{ - void *port, *addr; - unsigned char *p; - size_t port_len, addr_len; - - p = buf; - if (saddr->ss_family == AF_INET6) { - port = &((struct sockaddr_in6 *)saddr)->sin6_port; - addr = &((struct sockaddr_in6 *)saddr)->sin6_addr; - port_len = sizeof ((struct sockaddr_in6 *)saddr)->sin6_port; - addr_len = sizeof ((struct sockaddr_in6 *)saddr)->sin6_addr; - } - else { - port = &((struct sockaddr_in *)saddr)->sin_port; - addr = &((struct sockaddr_in *)saddr)->sin_addr; - port_len = sizeof ((struct sockaddr_in *)saddr)->sin_port; - addr_len = sizeof ((struct sockaddr_in *)saddr)->sin_addr; - } - memcpy(p, port, port_len); - p += port_len; - memcpy(p, addr, addr_len); - p += addr_len; - - return p - buf; -} - /* Free the CIDs attached to QUIC connection. */ static inline void free_quic_conn_cids(struct quic_conn *conn) { @@ -199,201 +146,6 @@ static inline void quic_connection_id_to_frm_cpy(struct quic_frame *dst, ncid_frm->stateless_reset_token = src->stateless_reset_token; } -/* Return a 32-bits integer in from QUIC packet with as address. - * Makes point to the data after this 32-bits value if succeeded. - * Note that these 32-bits integers are network bytes ordered. - * Returns 0 if failed (not enough data in the buffer), 1 if succeeded. - */ -static inline int quic_read_uint32(uint32_t *val, - const unsigned char **buf, - const unsigned char *end) -{ - if (end - *buf < sizeof *val) - return 0; - - *val = ntohl(*(uint32_t *)*buf); - *buf += sizeof *val; - - return 1; -} - -/* Write a 32-bits integer to a buffer with as address. - * Make point to the data after this 32-buts value if succeeded. - * Note that these 32-bits integers are networkg bytes ordered. - * Returns 0 if failed (not enough room in the buffer), 1 if succeeded. - */ -static inline int quic_write_uint32(unsigned char **buf, - const unsigned char *end, uint32_t val) -{ - if (end - *buf < sizeof val) - return 0; - - *(uint32_t *)*buf = htonl(val); - *buf += sizeof val; - - return 1; -} - - -/* Return the maximum number of bytes we must use to completely fill a - * buffer with as size for a data field of bytes prefixed by its QUIC - * variable-length (may be 0). - * Also put in <*len_sz> the size of this QUIC variable-length. - * So after returning from this function we have : <*len_sz> + <= - * (<*len_sz> = { max(i), i + ret <= }) . - */ -static inline size_t max_available_room(size_t sz, size_t *len_sz) -{ - size_t sz_sz, ret; - size_t diff; - - sz_sz = quic_int_getsize(sz); - if (sz <= sz_sz) - return 0; - - ret = sz - sz_sz; - *len_sz = quic_int_getsize(ret); - /* Difference between the two sizes. Note that >= <*len_sz>. */ - diff = sz_sz - *len_sz; - if (unlikely(diff > 0)) { - /* Let's try to take into an account remaining bytes. - * - * <----------------> - * <--------------><--------> +----> - * | - * +---------------------------+-----------.... - * <--------------------------------> - */ - size_t max_int = quic_max_int(*len_sz); - - if (max_int + *len_sz <= sz) - ret = max_int; - else - ret = sz - diff; - } - - return ret; -} - -/* This function computes the maximum data we can put into a buffer with as - * size prefixed with a variable-length field "Length" whose value is the - * remaining data length, already filled of bytes which must be taken - * into an account by "Length" field, and finally followed by the data we want - * to put in this buffer prefixed again by a variable-length field. - * is the size of the buffer to fill. - * the number of bytes already put after the "Length" field. - * the number of bytes we want to at most put in the buffer. - * Also set <*dlen_sz> to the size of the data variable-length we want to put in - * the buffer. This is typically this function which must be used to fill as - * much as possible a QUIC packet made of only one CRYPTO or STREAM frames. - * Returns this computed size if there is enough room in the buffer, 0 if not. - */ -static inline size_t max_stream_data_size(size_t sz, size_t ilen, size_t dlen) -{ - size_t ret, len_sz, dlen_sz; - - /* - * The length of variable-length QUIC integers are powers of two. - * Look for the first 3length" field value which match our need. - * As we must put bytes in our buffer, the minimum value for - * is the number of bytes required to encode . - */ - for (len_sz = quic_int_getsize(ilen); - len_sz <= QUIC_VARINT_MAX_SIZE; - len_sz <<= 1) { - if (sz < len_sz + ilen) - return 0; - - ret = max_available_room(sz - len_sz - ilen, &dlen_sz); - if (!ret) - return 0; - - /* Check that <*len_sz> matches value */ - if (len_sz + ilen + dlen_sz + ret <= quic_max_int(len_sz)) - return ret < dlen ? ret : dlen; - } - - return 0; -} - -/* Return the length in bytes of packet number depending on - * the largest ackownledged packet number. - */ -static inline size_t quic_packet_number_length(int64_t pn, - int64_t largest_acked_pn) -{ - int64_t max_nack_pkts; - - /* About packet number encoding, the RFC says: - * The sender MUST use a packet number size able to represent more than - * twice as large a range than the difference between the largest - * acknowledged packet and packet number being sent. - */ - max_nack_pkts = 2 * (pn - largest_acked_pn) + 1; - if (max_nack_pkts > 0xffffff) - return 4; - if (max_nack_pkts > 0xffff) - return 3; - if (max_nack_pkts > 0xff) - return 2; - - return 1; -} - -/* Encode packet number with as length in byte into a buffer with - * as current copy address and as pointer to one past the end of - * this buffer. This is the responsibility of the caller to check there is - * enough room in the buffer to copy bytes. - * Never fails. - */ -static inline int quic_packet_number_encode(unsigned char **buf, - const unsigned char *end, - uint64_t pn, size_t pn_len) -{ - if (end - *buf < pn_len) - return 0; - - /* Encode the packet number. */ - switch (pn_len) { - case 1: - **buf = pn; - break; - case 2: - write_n16(*buf, pn); - break; - case 3: - (*buf)[0] = pn >> 16; - (*buf)[1] = pn >> 8; - (*buf)[2] = pn; - break; - case 4: - write_n32(*buf, pn); - break; - } - *buf += pn_len; - - return 1; -} - -/* Returns the field value in milliseconds from ACK frame for - * QUIC connection. Note that the value of coming from - * ACK frame is in microseconds. - */ -static inline unsigned int quic_ack_delay_ms(struct qf_ack *ack_frm, - struct quic_conn *conn) -{ - return (ack_frm->ack_delay << conn->tx.params.ack_delay_exponent) / 1000; -} - -/* Returns the field value in microsecond to be set in an ACK frame - * depending on the time the packet with a new largest packet number was received. - */ -static inline uint64_t quic_compute_ack_delay_us(unsigned int time_received, - struct quic_conn *conn) -{ - return ((now_ms - time_received) * 1000) >> conn->tx.params.ack_delay_exponent; -} - /* Initialize

QUIC network path depending on boolean * which is true for an IPv4 path, if not false for an IPv6 path. */ @@ -427,76 +179,12 @@ static inline size_t quic_path_prep_data(struct quic_path *path) return path->cwnd - path->prep_in_flight; } -/* Return the number of bytes which may be sent from connection when - * it has not already been validated. Note that this is the responsibility - * of the caller to check that the case with quic_peer_validated_addr(). - * This latter BUG_ON() if 3 * qc->rx.bytes < qc->tx.prep_bytes. - */ -static inline size_t quic_may_send_bytes(struct quic_conn *qc) -{ - return 3 * qc->bytes.rx - qc->bytes.prep; -} - /* Return 1 if header form is long, 0 if not. */ static inline int qc_pkt_long(const struct quic_rx_packet *pkt) { return pkt->type != QUIC_PACKET_TYPE_SHORT; } -/* Return 1 if there is RX packets for QUIC encryption level, 0 if not */ -static inline int qc_el_rx_pkts(struct quic_enc_level *qel) -{ - int ret; - - ret = !eb_is_empty(&qel->rx.pkts); - - return ret; -} - -/* Increment the reference counter of */ -static inline void quic_rx_packet_refinc(struct quic_rx_packet *pkt) -{ - pkt->refcnt++; -} - -/* Decrement the reference counter of while remaining positive */ -static inline void quic_rx_packet_refdec(struct quic_rx_packet *pkt) -{ - if (pkt->refcnt) - pkt->refcnt--; -} - -/* Delete all RX packets for QUIC encryption level */ -static inline void qc_el_rx_pkts_del(struct quic_enc_level *qel) -{ - struct eb64_node *node; - - node = eb64_first(&qel->rx.pkts); - while (node) { - struct quic_rx_packet *pkt = - eb64_entry(node, struct quic_rx_packet, pn_node); - - node = eb64_next(node); - eb64_delete(&pkt->pn_node); - quic_rx_packet_refdec(pkt); - } -} - -static inline void qc_list_qel_rx_pkts(struct quic_enc_level *qel) -{ - struct eb64_node *node; - - node = eb64_first(&qel->rx.pkts); - while (node) { - struct quic_rx_packet *pkt; - - pkt = eb64_entry(node, struct quic_rx_packet, pn_node); - fprintf(stderr, "pkt@%p type=%d pn=%llu\n", - pkt, pkt->type, (ull)pkt->pn_node.key); - node = eb64_next(node); - } -} - void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm); void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err); diff --git a/include/haproxy/quic_rx.h b/include/haproxy/quic_rx.h index aea208c6cd..8c017724e3 100644 --- a/include/haproxy/quic_rx.h +++ b/include/haproxy/quic_rx.h @@ -36,4 +36,17 @@ int qc_release_lost_pkts(struct quic_conn *qc, struct quic_pktns *pktns, int qc_treat_rx_crypto_frms(struct quic_conn *qc, struct quic_enc_level *el, struct ssl_sock_ctx *ctx); +/* Increment the reference counter of */ +static inline void quic_rx_packet_refinc(struct quic_rx_packet *pkt) +{ + pkt->refcnt++; +} + +/* Decrement the reference counter of while remaining positive */ +static inline void quic_rx_packet_refdec(struct quic_rx_packet *pkt) +{ + if (pkt->refcnt) + pkt->refcnt--; +} + #endif /* _HAPROXY_QUIC_RX_H */ diff --git a/include/haproxy/quic_tls.h b/include/haproxy/quic_tls.h index e747f778f2..473545fefe 100644 --- a/include/haproxy/quic_tls.h +++ b/include/haproxy/quic_tls.h @@ -1049,6 +1049,57 @@ static inline int quic_tls_has_tx_sec(const struct quic_enc_level *qel) return qel && !!qel->tls_ctx.tx.key; } +/* Return 1 if there is RX packets for QUIC encryption level, 0 if not */ +static inline int qc_el_rx_pkts(struct quic_enc_level *qel) +{ + int ret; + + ret = !eb_is_empty(&qel->rx.pkts); + + return ret; +} + +/* Delete all RX packets for QUIC encryption level */ +static inline void qc_el_rx_pkts_del(struct quic_enc_level *qel) +{ + struct eb64_node *node; + + node = eb64_first(&qel->rx.pkts); + while (node) { + struct quic_rx_packet *pkt = + eb64_entry(node, struct quic_rx_packet, pn_node); + + node = eb64_next(node); + eb64_delete(&pkt->pn_node); + quic_rx_packet_refdec(pkt); + } +} + +static inline void qc_list_qel_rx_pkts(struct quic_enc_level *qel) +{ + struct eb64_node *node; + + node = eb64_first(&qel->rx.pkts); + while (node) { + struct quic_rx_packet *pkt; + + pkt = eb64_entry(node, struct quic_rx_packet, pn_node); + fprintf(stderr, "pkt@%p type=%d pn=%llu\n", + pkt, pkt->type, (ull)pkt->pn_node.key); + node = eb64_next(node); + } +} + +/* Returns a boolean if needs to emit frames for encryption level. */ +static inline int qc_need_sending(struct quic_conn *qc, struct quic_enc_level *qel) +{ + return (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE) || + (qel->pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED) || + qel->pktns->tx.pto_probe || + !LIST_ISEMPTY(&qel->pktns->tx.frms); +} + + #endif /* USE_QUIC */ #endif /* _PROTO_QUIC_TLS_H */ diff --git a/include/haproxy/quic_tx.h b/include/haproxy/quic_tx.h index 66541b208a..dfe44a39a1 100644 --- a/include/haproxy/quic_tx.h +++ b/include/haproxy/quic_tx.h @@ -33,7 +33,6 @@ void qc_txb_release(struct quic_conn *qc); int qc_purge_txbuf(struct quic_conn *qc, struct buffer *buf); struct buffer *qc_get_txb(struct quic_conn *qc); -int qc_need_sending(struct quic_conn *qc, struct quic_enc_level *qel); int qc_prep_hpkts(struct quic_conn *qc, struct buffer *buf, struct list *qels); int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx); int qc_may_probe_ipktns(struct quic_conn *qc); @@ -86,4 +85,15 @@ static inline void quic_tx_packet_refdec(struct quic_tx_packet *pkt) } } +/* Return the number of bytes which may be sent from connection when + * it has not already been validated. Note that this is the responsability + * of the caller to check that the case with quic_peer_validated_addr(). + * This latter BUG_ON() if 3 * qc->rx.bytes < qc->tx.prep_bytes. + */ +static inline size_t quic_may_send_bytes(struct quic_conn *qc) +{ + return 3 * qc->bytes.rx - qc->bytes.prep; +} + + #endif /* _HAPROXY_QUIC_TX_H */ diff --git a/src/quic_rx.c b/src/quic_rx.c index c717b73e1a..5bb130160f 100644 --- a/src/quic_rx.c +++ b/src/quic_rx.c @@ -940,6 +940,16 @@ static int qc_handle_retire_connection_id_frm(struct quic_conn *qc, goto leave; } +/* Returns the field value in milliseconds from ACK frame for + * QUIC connection. Note that the value of coming from + * ACK frame is in microseconds. + */ +static inline unsigned int quic_ack_delay_ms(struct qf_ack *ack_frm, + struct quic_conn *conn) +{ + return (ack_frm->ack_delay << conn->tx.params.ack_delay_exponent) / 1000; +} + /* Parse all the frames of QUIC packet for QUIC connection and * as encryption level. * Returns 1 if succeeded, 0 if failed. @@ -1670,6 +1680,24 @@ static int qc_try_rm_hp(struct quic_conn *qc, struct quic_rx_packet *pkt, return ret; } +/* Return a 32-bits integer in from QUIC packet with as address. + * Makes point to the data after this 32-bits value if succeeded. + * Note that these 32-bits integers are network bytes ordered. + * Returns 0 if failed (not enough data in the buffer), 1 if succeeded. + */ +static inline int quic_read_uint32(uint32_t *val, + const unsigned char **buf, + const unsigned char *end) +{ + if (end - *buf < sizeof *val) + return 0; + + *val = ntohl(*(uint32_t *)*buf); + *buf += sizeof *val; + + return 1; +} + /* Parse a QUIC packet header starting at position without exceeding . * Version and type are stored in packet instance. Type is set to unknown * on two occasions : for unsupported version, in this case version field is diff --git a/src/quic_tx.c b/src/quic_tx.c index 7953c04817..49dfd6914c 100644 --- a/src/quic_tx.c +++ b/src/quic_tx.c @@ -1429,15 +1429,6 @@ int qc_dgrams_retransmit(struct quic_conn *qc) return ret; } -/* Returns a boolean if needs to emit frames for encryption level. */ -int qc_need_sending(struct quic_conn *qc, struct quic_enc_level *qel) -{ - return (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE) || - (qel->pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED) || - qel->pktns->tx.pto_probe || - !LIST_ISEMPTY(&qel->pktns->tx.frms); -} - /* Return 1 if connection may probe the Initial packet number space, 0 if not. * This is not the case if the remote peer address is not validated and if * it cannot send at least QUIC_INITIAL_PACKET_MINLEN bytes. @@ -1568,6 +1559,40 @@ int send_stateless_reset(struct listener *l, struct sockaddr_storage *dstaddr, return ret; } +/* Copy socket address data into buffer. + * This is the responsibility of the caller to check the output buffer is big + * enough to contain these socket address data. + * Return the number of bytes copied. + */ +static inline size_t quic_saddr_cpy(unsigned char *buf, + const struct sockaddr_storage *saddr) +{ + void *port, *addr; + unsigned char *p; + size_t port_len, addr_len; + + p = buf; + if (saddr->ss_family == AF_INET6) { + port = &((struct sockaddr_in6 *)saddr)->sin6_port; + addr = &((struct sockaddr_in6 *)saddr)->sin6_addr; + port_len = sizeof ((struct sockaddr_in6 *)saddr)->sin6_port; + addr_len = sizeof ((struct sockaddr_in6 *)saddr)->sin6_addr; + } + else { + port = &((struct sockaddr_in *)saddr)->sin_port; + addr = &((struct sockaddr_in *)saddr)->sin_addr; + port_len = sizeof ((struct sockaddr_in *)saddr)->sin_port; + addr_len = sizeof ((struct sockaddr_in *)saddr)->sin_addr; + } + memcpy(p, port, port_len); + p += port_len; + memcpy(p, addr, addr_len); + p += addr_len; + + return p - buf; +} + + /* QUIC server only function. * Add AAD to buffer from connection ID and socket address. * This is the responsibility of the caller to check size is big enough @@ -1676,6 +1701,27 @@ static int quic_generate_retry_token(unsigned char *token, size_t len, goto leave; } +/* Return the long packet type matching with version and */ +static inline int quic_pkt_type(int type, uint32_t version) +{ + if (version != QUIC_PROTOCOL_VERSION_2) + return type; + + switch (type) { + case QUIC_PACKET_TYPE_INITIAL: + return 1; + case QUIC_PACKET_TYPE_0RTT: + return 2; + case QUIC_PACKET_TYPE_HANDSHAKE: + return 3; + case QUIC_PACKET_TYPE_RETRY: + return 0; + } + + return -1; +} + + /* Generate a Retry packet and send it on socket to in response to * the Initial packet. * @@ -1747,6 +1793,163 @@ int send_retry(int fd, struct sockaddr_storage *addr, return !ret; } +/* Write a 32-bits integer to a buffer with as address. + * Make point to the data after this 32-buts value if succeeded. + * Note that these 32-bits integers are networkg bytes ordered. + * Returns 0 if failed (not enough room in the buffer), 1 if succeeded. + */ +static inline int quic_write_uint32(unsigned char **buf, + const unsigned char *end, uint32_t val) +{ + if (end - *buf < sizeof val) + return 0; + + *(uint32_t *)*buf = htonl(val); + *buf += sizeof val; + + return 1; +} + +/* Return the maximum number of bytes we must use to completely fill a + * buffer with as size for a data field of bytes prefixed by its QUIC + * variable-length (may be 0). + * Also put in <*len_sz> the size of this QUIC variable-length. + * So after returning from this function we have : <*len_sz> + <= + * (<*len_sz> = { max(i), i + ret <= }) . + */ +static inline size_t max_available_room(size_t sz, size_t *len_sz) +{ + size_t sz_sz, ret; + size_t diff; + + sz_sz = quic_int_getsize(sz); + if (sz <= sz_sz) + return 0; + + ret = sz - sz_sz; + *len_sz = quic_int_getsize(ret); + /* Difference between the two sizes. Note that >= <*len_sz>. */ + diff = sz_sz - *len_sz; + if (unlikely(diff > 0)) { + /* Let's try to take into an account remaining bytes. + * + * <----------------> + * <--------------><--------> +----> + * | + * +---------------------------+-----------.... + * <--------------------------------> + */ + size_t max_int = quic_max_int(*len_sz); + + if (max_int + *len_sz <= sz) + ret = max_int; + else + ret = sz - diff; + } + + return ret; +} + +/* This function computes the maximum data we can put into a buffer with as + * size prefixed with a variable-length field "Length" whose value is the + * remaining data length, already filled of bytes which must be taken + * into an account by "Length" field, and finally followed by the data we want + * to put in this buffer prefixed again by a variable-length field. + * is the size of the buffer to fill. + * the number of bytes already put after the "Length" field. + * the number of bytes we want to at most put in the buffer. + * Also set <*dlen_sz> to the size of the data variable-length we want to put in + * the buffer. This is typically this function which must be used to fill as + * much as possible a QUIC packet made of only one CRYPTO or STREAM frames. + * Returns this computed size if there is enough room in the buffer, 0 if not. + */ +static inline size_t max_stream_data_size(size_t sz, size_t ilen, size_t dlen) +{ + size_t ret, len_sz, dlen_sz; + + /* + * The length of variable-length QUIC integers are powers of two. + * Look for the first 3length" field value which match our need. + * As we must put bytes in our buffer, the minimum value for + * is the number of bytes required to encode . + */ + for (len_sz = quic_int_getsize(ilen); + len_sz <= QUIC_VARINT_MAX_SIZE; + len_sz <<= 1) { + if (sz < len_sz + ilen) + return 0; + + ret = max_available_room(sz - len_sz - ilen, &dlen_sz); + if (!ret) + return 0; + + /* Check that <*len_sz> matches value */ + if (len_sz + ilen + dlen_sz + ret <= quic_max_int(len_sz)) + return ret < dlen ? ret : dlen; + } + + return 0; +} + +/* Return the length in bytes of packet number depending on + * the largest ackownledged packet number. + */ +static inline size_t quic_packet_number_length(int64_t pn, + int64_t largest_acked_pn) +{ + int64_t max_nack_pkts; + + /* About packet number encoding, the RFC says: + * The sender MUST use a packet number size able to represent more than + * twice as large a range than the difference between the largest + * acknowledged packet and packet number being sent. + */ + max_nack_pkts = 2 * (pn - largest_acked_pn) + 1; + if (max_nack_pkts > 0xffffff) + return 4; + if (max_nack_pkts > 0xffff) + return 3; + if (max_nack_pkts > 0xff) + return 2; + + return 1; +} + +/* Encode packet number with as length in byte into a buffer with + * as current copy address and as pointer to one past the end of + * this buffer. This is the responsibility of the caller to check there is + * enough room in the buffer to copy bytes. + * Never fails. + */ +static inline int quic_packet_number_encode(unsigned char **buf, + const unsigned char *end, + uint64_t pn, size_t pn_len) +{ + if (end - *buf < pn_len) + return 0; + + /* Encode the packet number. */ + switch (pn_len) { + case 1: + **buf = pn; + break; + case 2: + write_n16(*buf, pn); + break; + case 3: + (*buf)[0] = pn >> 16; + (*buf)[1] = pn >> 8; + (*buf)[2] = pn; + break; + case 4: + write_n32(*buf, pn); + break; + } + *buf += pn_len; + + return 1; +} + /* This function builds into a buffer at position a QUIC long packet header, * being one byte past the end of this buffer. * Return 1 if enough room to build this header, 0 if not. @@ -2186,6 +2389,15 @@ static void qc_build_cc_frm(struct quic_conn *qc, struct quic_enc_level *qel, } +/* Returns the field value in microsecond to be set in an ACK frame + * depending on the time the packet with a new largest packet number was received. + */ +static inline uint64_t quic_compute_ack_delay_us(unsigned int time_received, + struct quic_conn *conn) +{ + return ((now_ms - time_received) * 1000) >> conn->tx.params.ack_delay_exponent; +} + /* This function builds a clear packet from information (its type) * into a buffer with as position pointer and as QUIC TLS encryption * level for QUIC connection and as QUIC TLS encryption level,