From a909f3c64ddd8a6b88ba207f54f798ee77888b93 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Dosko=C4=8Dil?= <jan.doskocil@nic.cz>
Date: Wed, 20 Nov 2024 16:54:59 +0100
Subject: [PATCH] libngtcp2: update to 1.9.0

---
 src/contrib/libngtcp2/ngtcp2/crypto/shared.c  | 200 ++++++++++++++++++
 .../libngtcp2/ngtcp2/lib/ngtcp2_acktr.c       |   9 +-
 .../libngtcp2/ngtcp2/lib/ngtcp2_acktr.h       |   4 +-
 .../libngtcp2/ngtcp2/lib/ngtcp2_balloc.h      |   2 +-
 src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c |   2 +-
 .../libngtcp2/ngtcp2/lib/ngtcp2_conn.c        |  51 +++--
 .../libngtcp2/ngtcp2/lib/ngtcp2_conn.h        |  10 +-
 .../libngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c |   2 +-
 .../libngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h |   2 +-
 .../libngtcp2/ngtcp2/lib/ngtcp2_gaptr.c       |  16 +-
 src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.c |  73 +++++--
 src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h | 104 +++++++--
 .../libngtcp2/ngtcp2/lib/ngtcp2_macro.h       |  36 ++--
 src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pv.h  |   2 +-
 .../libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c     |  16 +-
 src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rob.c |  16 +-
 src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c |  12 +-
 src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h |   2 +-
 .../libngtcp2/ngtcp2/lib/ngtcp2_strm.c        |   7 +-
 src/contrib/libngtcp2/ngtcp2/ngtcp2.h         |   7 +
 src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h  | 118 +++++++++++
 src/contrib/libngtcp2/ngtcp2/version.h        |   4 +-
 22 files changed, 573 insertions(+), 122 deletions(-)

diff --git a/src/contrib/libngtcp2/ngtcp2/crypto/shared.c b/src/contrib/libngtcp2/ngtcp2/crypto/shared.c
index 6088b80c37..98cd4de7e8 100644
--- a/src/contrib/libngtcp2/ngtcp2/crypto/shared.c
+++ b/src/contrib/libngtcp2/ngtcp2/crypto/shared.c
@@ -1080,6 +1080,206 @@ int ngtcp2_crypto_verify_retry_token(
   return 0;
 }
 
+static size_t crypto_generate_retry_token_aad2(uint8_t *dest, uint32_t version,
+                                               const ngtcp2_cid *retry_scid) {
+  uint8_t *p = dest;
+
+  version = ngtcp2_htonl(version);
+  memcpy(p, &version, sizeof(version));
+  p += sizeof(version);
+  memcpy(p, retry_scid->data, retry_scid->datalen);
+  p += retry_scid->datalen;
+
+  return (size_t)(p - dest);
+}
+
+static const uint8_t retry_token_info_prefix2[] = "retry_token2";
+
+ngtcp2_ssize ngtcp2_crypto_generate_retry_token2(
+  uint8_t *token, const uint8_t *secret, size_t secretlen, uint32_t version,
+  const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
+  const ngtcp2_cid *retry_scid, const ngtcp2_cid *odcid, ngtcp2_tstamp ts) {
+  uint8_t plaintext[sizeof(ngtcp2_sockaddr_union) + /* cid len = */ 1 +
+                    NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp)];
+  uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN];
+  uint8_t key[16];
+  uint8_t iv[12];
+  size_t keylen;
+  size_t ivlen;
+  ngtcp2_crypto_aead aead;
+  ngtcp2_crypto_md md;
+  ngtcp2_crypto_aead_ctx aead_ctx;
+  uint8_t aad[sizeof(version) + NGTCP2_MAX_CIDLEN];
+  size_t aadlen;
+  uint8_t *p = plaintext;
+  ngtcp2_tstamp ts_be = ngtcp2_htonl64(ts);
+  int rv;
+
+  assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union));
+
+  memset(plaintext, 0, sizeof(plaintext));
+
+  memcpy(p, remote_addr, (size_t)remote_addrlen);
+  p += sizeof(ngtcp2_sockaddr_union);
+  *p++ = (uint8_t)odcid->datalen;
+  memcpy(p, odcid->data, odcid->datalen);
+  p += NGTCP2_MAX_CIDLEN;
+  memcpy(p, &ts_be, sizeof(ts_be));
+
+  assert((size_t)(p + sizeof(ts_be) - plaintext) == sizeof(plaintext));
+
+  if (ngtcp2_crypto_random(rand_data, sizeof(rand_data)) != 0) {
+    return -1;
+  }
+
+  ngtcp2_crypto_aead_aes_128_gcm(&aead);
+  ngtcp2_crypto_md_sha256(&md);
+
+  keylen = ngtcp2_crypto_aead_keylen(&aead);
+  ivlen = ngtcp2_crypto_aead_noncelen(&aead);
+
+  assert(sizeof(key) == keylen);
+  assert(sizeof(iv) == ivlen);
+
+  if (crypto_derive_token_key(key, keylen, iv, ivlen, &md, secret, secretlen,
+                              rand_data, sizeof(rand_data),
+                              retry_token_info_prefix2,
+                              sizeof(retry_token_info_prefix2) - 1) != 0) {
+    return -1;
+  }
+
+  aadlen = crypto_generate_retry_token_aad2(aad, version, retry_scid);
+
+  p = token;
+  *p++ = NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2;
+
+  if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &aead, key, ivlen) != 0) {
+    return -1;
+  }
+
+  rv = ngtcp2_crypto_encrypt(p, &aead, &aead_ctx, plaintext, sizeof(plaintext),
+                             iv, ivlen, aad, aadlen);
+
+  ngtcp2_crypto_aead_ctx_free(&aead_ctx);
+
+  if (rv != 0) {
+    return -1;
+  }
+
+  p += sizeof(plaintext) + aead.max_overhead;
+  memcpy(p, rand_data, sizeof(rand_data));
+  p += sizeof(rand_data);
+
+  return p - token;
+}
+
+int ngtcp2_crypto_verify_retry_token2(
+  ngtcp2_cid *odcid, const uint8_t *token, size_t tokenlen,
+  const uint8_t *secret, size_t secretlen, uint32_t version,
+  const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
+  const ngtcp2_cid *dcid, ngtcp2_duration timeout, ngtcp2_tstamp ts) {
+  uint8_t plaintext[sizeof(ngtcp2_sockaddr_union) + /* cid len = */ 1 +
+                    NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp)];
+  uint8_t key[16];
+  uint8_t iv[12];
+  size_t keylen;
+  size_t ivlen;
+  ngtcp2_crypto_aead_ctx aead_ctx;
+  ngtcp2_crypto_aead aead;
+  ngtcp2_crypto_md md;
+  uint8_t aad[sizeof(version) + NGTCP2_MAX_CIDLEN];
+  size_t aadlen;
+  const uint8_t *rand_data;
+  const uint8_t *ciphertext;
+  size_t ciphertextlen;
+  size_t cil;
+  int rv;
+  ngtcp2_tstamp gen_ts;
+  ngtcp2_sockaddr_union addr;
+  size_t addrlen;
+  uint8_t *p;
+
+  assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union));
+
+  if (tokenlen != NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN2 ||
+      token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2) {
+    return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
+  }
+
+  rand_data = token + tokenlen - NGTCP2_CRYPTO_TOKEN_RAND_DATALEN;
+  ciphertext = token + 1;
+  ciphertextlen = (size_t)(rand_data - ciphertext);
+
+  ngtcp2_crypto_aead_aes_128_gcm(&aead);
+  ngtcp2_crypto_md_sha256(&md);
+
+  keylen = ngtcp2_crypto_aead_keylen(&aead);
+  ivlen = ngtcp2_crypto_aead_noncelen(&aead);
+
+  assert(sizeof(key) == keylen);
+  assert(sizeof(iv) == ivlen);
+
+  if (crypto_derive_token_key(key, keylen, iv, ivlen, &md, secret, secretlen,
+                              rand_data, NGTCP2_CRYPTO_TOKEN_RAND_DATALEN,
+                              retry_token_info_prefix2,
+                              sizeof(retry_token_info_prefix2) - 1) != 0) {
+    return NGTCP2_CRYPTO_ERR_INTERNAL;
+  }
+
+  aadlen = crypto_generate_retry_token_aad2(aad, version, dcid);
+
+  if (ngtcp2_crypto_aead_ctx_decrypt_init(&aead_ctx, &aead, key, ivlen) != 0) {
+    return NGTCP2_CRYPTO_ERR_INTERNAL;
+  }
+
+  rv = ngtcp2_crypto_decrypt(plaintext, &aead, &aead_ctx, ciphertext,
+                             ciphertextlen, iv, ivlen, aad, aadlen);
+
+  ngtcp2_crypto_aead_ctx_free(&aead_ctx);
+
+  if (rv != 0) {
+    return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
+  }
+
+  p = plaintext;
+
+  memcpy(&addr, p, sizeof(addr));
+
+  switch (addr.sa.sa_family) {
+  case NGTCP2_AF_INET:
+    addrlen = sizeof(ngtcp2_sockaddr_in);
+    break;
+  case NGTCP2_AF_INET6:
+    addrlen = sizeof(ngtcp2_sockaddr_in6);
+    break;
+  default:
+    return NGTCP2_CRYPTO_ERR_VERIFY_TOKEN;
+  }
+
+  if (addrlen != (size_t)remote_addrlen ||
+      memcmp(&addr, remote_addr, addrlen) != 0) {
+    return NGTCP2_CRYPTO_ERR_VERIFY_TOKEN;
+  }
+
+  p += sizeof(addr);
+  cil = *p++;
+
+  if (cil != 0 && (cil < NGTCP2_MIN_CIDLEN || cil > NGTCP2_MAX_CIDLEN)) {
+    return NGTCP2_CRYPTO_ERR_VERIFY_TOKEN;
+  }
+
+  memcpy(&gen_ts, p + NGTCP2_MAX_CIDLEN, sizeof(gen_ts));
+
+  gen_ts = ngtcp2_ntohl64(gen_ts);
+  if (gen_ts + timeout <= ts) {
+    return NGTCP2_CRYPTO_ERR_VERIFY_TOKEN;
+  }
+
+  ngtcp2_cid_init(odcid, p, cil);
+
+  return 0;
+}
+
 static size_t crypto_generate_regular_token_aad(uint8_t *dest,
                                                 const ngtcp2_sockaddr *sa) {
   const uint8_t *addr;
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_acktr.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_acktr.c
index d5508ba890..0e5bfe069e 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_acktr.c
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_acktr.c
@@ -29,7 +29,7 @@
 #include "ngtcp2_macro.h"
 #include "ngtcp2_tstamp.h"
 
-ngtcp2_objalloc_def(acktr_entry, ngtcp2_acktr_entry, oplent);
+ngtcp2_objalloc_def(acktr_entry, ngtcp2_acktr_entry, oplent)
 
 static void acktr_entry_init(ngtcp2_acktr_entry *ent, int64_t pkt_num,
                              ngtcp2_tstamp tstamp) {
@@ -56,10 +56,6 @@ void ngtcp2_acktr_entry_objalloc_del(ngtcp2_acktr_entry *ent,
   ngtcp2_objalloc_acktr_entry_release(objalloc, ent);
 }
 
-static int greater(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
-  return *(int64_t *)lhs > *(int64_t *)rhs;
-}
-
 void ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log,
                        const ngtcp2_mem *mem) {
   ngtcp2_objalloc_acktr_entry_init(&acktr->objalloc, NGTCP2_ACKTR_MAX_ENT + 1,
@@ -67,7 +63,8 @@ void ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log,
 
   ngtcp2_static_ringbuf_acks_init(&acktr->acks);
 
-  ngtcp2_ksl_init(&acktr->ents, greater, sizeof(int64_t), mem);
+  ngtcp2_ksl_init(&acktr->ents, ngtcp2_ksl_int64_greater,
+                  ngtcp2_ksl_int64_greater_search, sizeof(int64_t), mem);
 
   acktr->log = log;
   acktr->flags = NGTCP2_ACKTR_FLAG_NONE;
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_acktr.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_acktr.h
index 4ef420723d..16aee42f27 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_acktr.h
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_acktr.h
@@ -65,7 +65,7 @@ typedef struct ngtcp2_acktr_entry {
   };
 } ngtcp2_acktr_entry;
 
-ngtcp2_objalloc_decl(acktr_entry, ngtcp2_acktr_entry, oplent);
+ngtcp2_objalloc_decl(acktr_entry, ngtcp2_acktr_entry, oplent)
 
 /*
  * ngtcp2_acktr_entry_objalloc_new allocates memory for ent, and
@@ -108,7 +108,7 @@ typedef struct ngtcp2_acktr_ack_entry {
    expired and canceled. */
 #define NGTCP2_ACKTR_FLAG_CANCEL_TIMER 0x0100u
 
-ngtcp2_static_ringbuf_def(acks, 32, sizeof(ngtcp2_acktr_ack_entry));
+ngtcp2_static_ringbuf_def(acks, 32, sizeof(ngtcp2_acktr_ack_entry))
 
 /*
  * ngtcp2_acktr tracks received packets which we have to send ack.
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_balloc.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_balloc.h
index e69e7efc6f..c0e2a3f756 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_balloc.h
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_balloc.h
@@ -63,7 +63,7 @@ typedef struct ngtcp2_balloc {
 
 /*
  * ngtcp2_balloc_init initializes |balloc| with |blklen| which is the
- * size of memory block.
+ * size of memory block.  |blklen| must be divisible by 16.
  */
 void ngtcp2_balloc_init(ngtcp2_balloc *balloc, size_t blklen,
                         const ngtcp2_mem *mem);
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c
index 5a66c1870b..8777ca4c8a 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c
@@ -1149,7 +1149,7 @@ static uint64_t bbr_bdp_multiple(ngtcp2_cc_bbr *bbr, uint64_t gain_h) {
     return bbr->initial_cwnd;
   }
 
-  bdp = bbr->bw * bbr->min_rtt / NGTCP2_SECONDS;
+  bdp = ngtcp2_max_uint64(bbr->bw * bbr->min_rtt / NGTCP2_SECONDS, 1);
 
   return (uint64_t)(bdp * gain_h / 100);
 }
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c
index dff8d59459..0f67ac09bf 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c
@@ -51,8 +51,12 @@
 /* NGTCP2_MIN_COALESCED_PAYLOADLEN is the minimum length of QUIC
    packet payload that should be coalesced to a long packet. */
 #define NGTCP2_MIN_COALESCED_PAYLOADLEN 128
+/* NGTCP2_MAX_ACK_PER_PKT is the maximum number of ACK frame per an
+   incoming QUIC packet to process.  ACK frames that exceed this limit
+   are not processed. */
+#define NGTCP2_MAX_ACK_PER_PKT 1
 
-ngtcp2_objalloc_def(strm, ngtcp2_strm, oplent);
+ngtcp2_objalloc_def(strm, ngtcp2_strm, oplent)
 
 /*
  * conn_local_stream returns nonzero if |stream_id| indicates that it
@@ -767,6 +771,8 @@ static int cid_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
   return ngtcp2_cid_less(lhs, rhs);
 }
 
+ngtcp2_ksl_search_def(cid_less, cid_less)
+
 static int retired_ts_less(const ngtcp2_pq_entry *lhs,
                            const ngtcp2_pq_entry *rhs) {
   const ngtcp2_scid *a = ngtcp2_struct_of(lhs, ngtcp2_scid, pe);
@@ -1159,7 +1165,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
 
   ngtcp2_gaptr_init(&(*pconn)->dcid.seqgap, mem);
 
-  ngtcp2_ksl_init(&(*pconn)->scid.set, cid_less, sizeof(ngtcp2_cid), mem);
+  ngtcp2_ksl_init(&(*pconn)->scid.set, cid_less, ksl_cid_less_search,
+                  sizeof(ngtcp2_cid), mem);
 
   ngtcp2_pq_init(&(*pconn)->scid.used, retired_ts_less, mem);
 
@@ -1657,8 +1664,9 @@ static int conn_ensure_ack_ranges(ngtcp2_conn *conn, size_t n) {
  * ACK.
  */
 static ngtcp2_duration conn_compute_ack_delay(ngtcp2_conn *conn) {
-  return ngtcp2_min_uint64(conn->local.transport_params.max_ack_delay,
-                           conn->cstat.smoothed_rtt / 8);
+  return ngtcp2_min_uint64(
+    conn->local.transport_params.max_ack_delay,
+    ngtcp2_max_uint64(conn->cstat.smoothed_rtt / 8, NGTCP2_NANOSECONDS));
 }
 
 int ngtcp2_conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr,
@@ -2901,7 +2909,7 @@ static int conn_should_send_max_stream_data(ngtcp2_conn *conn,
   uint64_t inc = strm->rx.unsent_max_offset - strm->rx.max_offset;
   (void)conn;
 
-  return strm->rx.window < 2 * inc;
+  return strm->rx.window < 4 * inc;
 }
 
 /*
@@ -2911,7 +2919,7 @@ static int conn_should_send_max_stream_data(ngtcp2_conn *conn,
 static int conn_should_send_max_data(ngtcp2_conn *conn) {
   uint64_t inc = conn->rx.unsent_max_offset - conn->rx.max_offset;
 
-  return conn->rx.window < 2 * inc;
+  return conn->rx.window < 4 * inc;
 }
 
 /*
@@ -3423,10 +3431,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
         ngtcp2_acktr_commit_ack(&pktns->acktr);
         ngtcp2_acktr_add_ack(&pktns->acktr, hd->pkt_num,
                              ackfr->ack.largest_ack);
-        if (type == NGTCP2_PKT_1RTT) {
-          conn_handle_unconfirmed_key_update_from_remote(
-            conn, ackfr->ack.largest_ack, ts);
-        }
+        assert(NGTCP2_PKT_1RTT == type);
+        conn_handle_unconfirmed_key_update_from_remote(
+          conn, ackfr->ack.largest_ack, ts);
         pkt_empty = 0;
       }
     }
@@ -4209,7 +4216,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
       ngtcp2_rtb_entry_objalloc_new(&ent, hd, NULL, ts, (size_t)nwrite,
                                     rtb_entry_flags, &conn->rtb_entry_objalloc);
     if (rv != 0) {
-      assert(ngtcp2_err_is_fatal((int)nwrite));
+      assert(ngtcp2_err_is_fatal(rv));
       return rv;
     }
 
@@ -6109,6 +6116,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
   ngtcp2_strm *crypto;
   ngtcp2_encryption_level encryption_level;
   int invalid_reserved_bits = 0;
+  size_t num_ack_processed = 0;
 
   if (pktlen == 0) {
     return 0;
@@ -6561,6 +6569,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
     switch (fr->type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
+      if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
+        break;
+      }
       if (!conn->server && hd.type == NGTCP2_PKT_HANDSHAKE) {
         conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
       }
@@ -6568,6 +6579,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
       if (rv != 0) {
         return rv;
       }
+      ++num_ack_processed;
       break;
     case NGTCP2_FRAME_PADDING:
       break;
@@ -8676,6 +8688,7 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
   int rv;
   int require_ack = 0;
   ngtcp2_pktns *pktns;
+  size_t num_ack_processed = 0;
 
   assert(hd->type == NGTCP2_PKT_HANDSHAKE);
 
@@ -8710,6 +8723,9 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
     switch (fr->type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
+      if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
+        break;
+      }
       if (!conn->server) {
         conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
       }
@@ -8717,6 +8733,7 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi,
       if (rv != 0) {
         return rv;
       }
+      ++num_ack_processed;
       break;
     case NGTCP2_FRAME_PADDING:
       break;
@@ -8878,6 +8895,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
   int recv_ncid = 0;
   int new_cid_used = 0;
   int path_challenge_recved = 0;
+  size_t num_ack_processed = 0;
 
   if (conn->server && conn->local.transport_params.disable_active_migration &&
       !ngtcp2_path_eq(&conn->dcid.current.ps.path, path) &&
@@ -9228,6 +9246,9 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
     switch (fr->type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
+      if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
+        break;
+      }
       if (!conn->server) {
         conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
       }
@@ -9236,6 +9257,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
         return rv;
       }
       non_probing_pkt = 1;
+      ++num_ack_processed;
       break;
     case NGTCP2_FRAME_STREAM:
       rv = conn_recv_stream(conn, &fr->stream);
@@ -11703,7 +11725,10 @@ static ngtcp2_ssize conn_write_vmsg_wrapper(ngtcp2_conn *conn,
 
   if (cstat->bytes_in_flight >= cstat->cwnd) {
     conn->rst.is_cwnd_limited = 1;
-  } else if (nwrite == 0 && conn_pacing_pkt_tx_allowed(conn, ts)) {
+  } else if ((cstat->cwnd >= cstat->ssthresh ||
+              cstat->bytes_in_flight * 2 < cstat->cwnd) &&
+             nwrite == 0 && conn_pacing_pkt_tx_allowed(conn, ts) &&
+             (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) {
     conn->rst.app_limited = conn->rst.delivered + cstat->bytes_in_flight;
 
     if (conn->rst.app_limited == 0) {
@@ -12793,6 +12818,8 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
                            ngtcp2_duration ack_delay, ngtcp2_tstamp ts) {
   ngtcp2_conn_stat *cstat = &conn->cstat;
 
+  assert(rtt > 0);
+
   if (cstat->min_rtt == UINT64_MAX) {
     cstat->latest_rtt = rtt;
     cstat->min_rtt = rtt;
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h
index 562628d089..55073fcc82 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h
@@ -337,15 +337,15 @@ typedef struct ngtcp2_early_transport_params {
 } ngtcp2_early_transport_params;
 
 ngtcp2_static_ringbuf_def(dcid_bound, NGTCP2_MAX_BOUND_DCID_POOL_SIZE,
-                          sizeof(ngtcp2_dcid));
+                          sizeof(ngtcp2_dcid))
 ngtcp2_static_ringbuf_def(dcid_unused, NGTCP2_MAX_DCID_POOL_SIZE,
-                          sizeof(ngtcp2_dcid));
+                          sizeof(ngtcp2_dcid))
 ngtcp2_static_ringbuf_def(dcid_retired, NGTCP2_MAX_DCID_RETIRED_SIZE,
-                          sizeof(ngtcp2_dcid));
+                          sizeof(ngtcp2_dcid))
 ngtcp2_static_ringbuf_def(path_challenge, 4,
-                          sizeof(ngtcp2_path_challenge_entry));
+                          sizeof(ngtcp2_path_challenge_entry))
 
-ngtcp2_objalloc_decl(strm, ngtcp2_strm, oplent);
+ngtcp2_objalloc_decl(strm, ngtcp2_strm, oplent)
 
 struct ngtcp2_conn {
   ngtcp2_objalloc frc_objalloc;
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c
index cf0f117179..6a8a22c3f0 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c
@@ -27,7 +27,7 @@
 #include <string.h>
 #include <assert.h>
 
-ngtcp2_objalloc_def(frame_chain, ngtcp2_frame_chain, oplent);
+ngtcp2_objalloc_def(frame_chain, ngtcp2_frame_chain, oplent)
 
 int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem) {
   *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain));
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h
index c38f1aeac9..e5b6779c0f 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h
@@ -74,7 +74,7 @@ struct ngtcp2_frame_chain {
   };
 };
 
-ngtcp2_objalloc_decl(frame_chain, ngtcp2_frame_chain, oplent);
+ngtcp2_objalloc_decl(frame_chain, ngtcp2_frame_chain, oplent)
 
 /*
  * ngtcp2_bind_frame_chains binds two frame chains |a| and |b| using
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_gaptr.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_gaptr.c
index 1475c22865..3bfa398480 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_gaptr.c
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_gaptr.c
@@ -28,8 +28,8 @@
 #include <assert.h>
 
 void ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem) {
-  ngtcp2_ksl_init(&gaptr->gap, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range),
-                  mem);
+  ngtcp2_ksl_init(&gaptr->gap, ngtcp2_ksl_range_compar, ngtcp2_ksl_range_search,
+                  sizeof(ngtcp2_range), mem);
 
   gaptr->mem = mem;
 }
@@ -60,8 +60,8 @@ int ngtcp2_gaptr_push(ngtcp2_gaptr *gaptr, uint64_t offset, uint64_t datalen) {
     }
   }
 
-  it = ngtcp2_ksl_lower_bound_compar(&gaptr->gap, &q,
-                                     ngtcp2_ksl_range_exclusive_compar);
+  it = ngtcp2_ksl_lower_bound_search(&gaptr->gap, &q,
+                                     ngtcp2_ksl_range_exclusive_search);
 
   for (; !ngtcp2_ksl_it_end(&it);) {
     k = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
@@ -118,8 +118,8 @@ ngtcp2_range ngtcp2_gaptr_get_first_gap_after(const ngtcp2_gaptr *gaptr,
     return r;
   }
 
-  it = ngtcp2_ksl_lower_bound_compar(&gaptr->gap, &q,
-                                     ngtcp2_ksl_range_exclusive_compar);
+  it = ngtcp2_ksl_lower_bound_search(&gaptr->gap, &q,
+                                     ngtcp2_ksl_range_exclusive_search);
 
   assert(!ngtcp2_ksl_it_end(&it));
 
@@ -136,8 +136,8 @@ int ngtcp2_gaptr_is_pushed(const ngtcp2_gaptr *gaptr, uint64_t offset,
     return 0;
   }
 
-  it = ngtcp2_ksl_lower_bound_compar(&gaptr->gap, &q,
-                                     ngtcp2_ksl_range_exclusive_compar);
+  it = ngtcp2_ksl_lower_bound_search(&gaptr->gap, &q,
+                                     ngtcp2_ksl_range_exclusive_search);
   m = ngtcp2_range_intersect(&q, (ngtcp2_range *)ngtcp2_ksl_it_key(&it));
 
   return ngtcp2_range_len(&m) == 0;
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.c
index 2280b462cb..5e74f64724 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.c
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.c
@@ -35,7 +35,7 @@
 
 static ngtcp2_ksl_blk null_blk = {{{NULL, NULL, 0, 0, {0}}}};
 
-ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent);
+ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent)
 
 static size_t ksl_nodelen(size_t keylen) {
   assert(keylen >= sizeof(uint64_t));
@@ -57,7 +57,8 @@ static void ksl_node_set_key(ngtcp2_ksl *ksl, ngtcp2_ksl_node *node,
   memcpy(node->key, key, ksl->keylen);
 }
 
-void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar, size_t keylen,
+void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar,
+                     ngtcp2_ksl_search search, size_t keylen,
                      const ngtcp2_mem *mem) {
   size_t nodelen = ksl_nodelen(keylen);
 
@@ -67,6 +68,7 @@ void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar, size_t keylen,
   ksl->head = NULL;
   ksl->front = ksl->back = NULL;
   ksl->compar = compar;
+  ksl->search = search;
   ksl->n = 0;
   ksl->keylen = keylen;
   ksl->nodelen = nodelen;
@@ -269,19 +271,6 @@ static void ksl_insert_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i,
   ++blk->n;
 }
 
-static size_t ksl_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
-                         const ngtcp2_ksl_key *key, ngtcp2_ksl_compar compar) {
-  size_t i;
-  ngtcp2_ksl_node *node;
-
-  for (i = 0, node = (ngtcp2_ksl_node *)(void *)blk->nodes;
-       i < blk->n && compar((ngtcp2_ksl_key *)node->key, key);
-       ++i, node = (ngtcp2_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen))
-    ;
-
-  return i;
-}
-
 int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
                       const ngtcp2_ksl_key *key, void *data) {
   ngtcp2_ksl_blk *blk;
@@ -306,7 +295,7 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
   blk = ksl->head;
 
   for (;;) {
-    i = ksl_search(ksl, blk, key, ksl->compar);
+    i = ksl->search(ksl, blk, key);
 
     if (blk->leaf) {
       if (i < blk->n &&
@@ -565,7 +554,7 @@ int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
   }
 
   for (;;) {
-    i = ksl_search(ksl, blk, key, ksl->compar);
+    i = ksl->search(ksl, blk, key);
 
     if (i == blk->n) {
       if (it) {
@@ -636,12 +625,12 @@ int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
 
 ngtcp2_ksl_it ngtcp2_ksl_lower_bound(const ngtcp2_ksl *ksl,
                                      const ngtcp2_ksl_key *key) {
-  return ngtcp2_ksl_lower_bound_compar(ksl, key, ksl->compar);
+  return ngtcp2_ksl_lower_bound_search(ksl, key, ksl->search);
 }
 
-ngtcp2_ksl_it ngtcp2_ksl_lower_bound_compar(const ngtcp2_ksl *ksl,
+ngtcp2_ksl_it ngtcp2_ksl_lower_bound_search(const ngtcp2_ksl *ksl,
                                             const ngtcp2_ksl_key *key,
-                                            ngtcp2_ksl_compar compar) {
+                                            ngtcp2_ksl_search search) {
   ngtcp2_ksl_blk *blk = ksl->head;
   ngtcp2_ksl_it it;
   size_t i;
@@ -652,7 +641,7 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound_compar(const ngtcp2_ksl *ksl,
   }
 
   for (;;) {
-    i = ksl_search(ksl, blk, key, compar);
+    i = search(ksl, blk, key);
 
     if (blk->leaf) {
       if (i == blk->n && blk->next) {
@@ -696,7 +685,7 @@ void ngtcp2_ksl_update_key(ngtcp2_ksl *ksl, const ngtcp2_ksl_key *old_key,
   assert(ksl->head);
 
   for (;;) {
-    i = ksl_search(ksl, blk, old_key, ksl->compar);
+    i = ksl->search(ksl, blk, old_key);
 
     assert(i < blk->n);
     node = ngtcp2_ksl_nth_node(ksl, blk, i);
@@ -819,9 +808,49 @@ int ngtcp2_ksl_range_compar(const ngtcp2_ksl_key *lhs,
   return a->begin < b->begin;
 }
 
+ngtcp2_ksl_search_def(range, ngtcp2_ksl_range_compar)
+
+size_t ngtcp2_ksl_range_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
+                               const ngtcp2_ksl_key *key) {
+  return ksl_range_search(ksl, blk, key);
+}
+
 int ngtcp2_ksl_range_exclusive_compar(const ngtcp2_ksl_key *lhs,
                                       const ngtcp2_ksl_key *rhs) {
   const ngtcp2_range *a = lhs, *b = rhs;
   return a->begin < b->begin && !(ngtcp2_max_uint64(a->begin, b->begin) <
                                   ngtcp2_min_uint64(a->end, b->end));
 }
+
+ngtcp2_ksl_search_def(range_exclusive, ngtcp2_ksl_range_exclusive_compar)
+
+size_t ngtcp2_ksl_range_exclusive_search(const ngtcp2_ksl *ksl,
+                                         ngtcp2_ksl_blk *blk,
+                                         const ngtcp2_ksl_key *key) {
+  return ksl_range_exclusive_search(ksl, blk, key);
+}
+
+int ngtcp2_ksl_uint64_less(const ngtcp2_ksl_key *lhs,
+                           const ngtcp2_ksl_key *rhs) {
+  return *(uint64_t *)lhs < *(uint64_t *)rhs;
+}
+
+ngtcp2_ksl_search_def(uint64_less, ngtcp2_ksl_uint64_less)
+
+size_t ngtcp2_ksl_uint64_less_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
+                                     const ngtcp2_ksl_key *key) {
+  return ksl_uint64_less_search(ksl, blk, key);
+}
+
+int ngtcp2_ksl_int64_greater(const ngtcp2_ksl_key *lhs,
+                             const ngtcp2_ksl_key *rhs) {
+  return *(int64_t *)lhs > *(int64_t *)rhs;
+}
+
+ngtcp2_ksl_search_def(int64_greater, ngtcp2_ksl_int64_greater)
+
+size_t ngtcp2_ksl_int64_greater_search(const ngtcp2_ksl *ksl,
+                                       ngtcp2_ksl_blk *blk,
+                                       const ngtcp2_ksl_key *key) {
+  return ksl_int64_greater_search(ksl, blk, key);
+}
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h
index d8374b9b5b..de78bcb807 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h
@@ -103,7 +103,7 @@ struct ngtcp2_ksl_blk {
   };
 };
 
-ngtcp2_objalloc_decl(ksl_blk, ngtcp2_ksl_blk, oplent);
+ngtcp2_objalloc_decl(ksl_blk, ngtcp2_ksl_blk, oplent)
 
 /*
  * ngtcp2_ksl_compar is a function type which returns nonzero if key
@@ -114,6 +114,33 @@ typedef int (*ngtcp2_ksl_compar)(const ngtcp2_ksl_key *lhs,
 
 typedef struct ngtcp2_ksl ngtcp2_ksl;
 
+/*
+ * ngtcp2_ksl_search is a function to search for the first element in
+ * |blk|->nodes which is not ordered before |key|.  It returns the
+ * index of such element.  It returns |blk|->n if there is no such
+ * element.
+ */
+typedef size_t (*ngtcp2_ksl_search)(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
+                                    const ngtcp2_ksl_key *key);
+
+/*
+ * ngtcp2_ksl_search_def is a macro to implement ngtcp2_ksl_search
+ * with COMPAR which is supposed to be ngtcp2_ksl_compar.
+ */
+#define ngtcp2_ksl_search_def(NAME, COMPAR)                                    \
+  static size_t ksl_##NAME##_search(                                           \
+    const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, const ngtcp2_ksl_key *key) {   \
+    size_t i;                                                                  \
+    ngtcp2_ksl_node *node;                                                     \
+                                                                               \
+    for (i = 0, node = (ngtcp2_ksl_node *)(void *)blk->nodes;                  \
+         i < blk->n && COMPAR((ngtcp2_ksl_key *)node->key, key); ++i,          \
+        node = (ngtcp2_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen))    \
+      ;                                                                        \
+                                                                               \
+    return i;                                                                  \
+  }
+
 typedef struct ngtcp2_ksl_it ngtcp2_ksl_it;
 
 /*
@@ -137,6 +164,7 @@ struct ngtcp2_ksl {
   /* back points to the last leaf block. */
   ngtcp2_ksl_blk *back;
   ngtcp2_ksl_compar compar;
+  ngtcp2_ksl_search search;
   /* n is the number of elements stored. */
   size_t n;
   /* keylen is the size of key */
@@ -148,10 +176,12 @@ struct ngtcp2_ksl {
 
 /*
  * ngtcp2_ksl_init initializes |ksl|.  |compar| specifies compare
- * function.  |keylen| is the length of key and must be at least
+ * function.  |search| is a search function which must use |compar|.
+ * |keylen| is the length of key and must be at least
  * sizeof(uint64_t).
  */
-void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar, size_t keylen,
+void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar,
+                     ngtcp2_ksl_search search, size_t keylen,
                      const ngtcp2_mem *mem);
 
 /*
@@ -217,12 +247,12 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound(const ngtcp2_ksl *ksl,
                                      const ngtcp2_ksl_key *key);
 
 /*
- * ngtcp2_ksl_lower_bound_compar works like ngtcp2_ksl_lower_bound,
- * but it takes custom function |compar| to do lower bound search.
+ * ngtcp2_ksl_lower_bound_search works like ngtcp2_ksl_lower_bound,
+ * but it takes custom function |search| to do lower bound search.
  */
-ngtcp2_ksl_it ngtcp2_ksl_lower_bound_compar(const ngtcp2_ksl *ksl,
+ngtcp2_ksl_it ngtcp2_ksl_lower_bound_search(const ngtcp2_ksl *ksl,
                                             const ngtcp2_ksl_key *key,
-                                            ngtcp2_ksl_compar compar);
+                                            ngtcp2_ksl_search search);
 
 /*
  * ngtcp2_ksl_update_key replaces the key of nodes which has |old_key|
@@ -329,21 +359,67 @@ int ngtcp2_ksl_it_begin(const ngtcp2_ksl_it *it);
 
 /*
  * ngtcp2_ksl_range_compar is an implementation of ngtcp2_ksl_compar.
- * lhs->ptr and rhs->ptr must point to ngtcp2_range object and the
- * function returns nonzero if (const ngtcp2_range *)(lhs->ptr)->begin
- * < (const ngtcp2_range *)(rhs->ptr)->begin.
+ * |lhs| and |rhs| must point to ngtcp2_range object, and the function
+ * returns nonzero if ((const ngtcp2_range *)lhs)->begin < ((const
+ * ngtcp2_range *)rhs)->begin.
  */
 int ngtcp2_ksl_range_compar(const ngtcp2_ksl_key *lhs,
                             const ngtcp2_ksl_key *rhs);
 
+/*
+ * ngtcp2_ksl_range_search is an implementation of ngtcp2_ksl_search
+ * that uses ngtcp2_ksl_range_compar.
+ */
+size_t ngtcp2_ksl_range_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
+                               const ngtcp2_ksl_key *key);
+
 /*
  * ngtcp2_ksl_range_exclusive_compar is an implementation of
- * ngtcp2_ksl_compar.  lhs->ptr and rhs->ptr must point to
- * ngtcp2_range object and the function returns nonzero if (const
- * ngtcp2_range *)(lhs->ptr)->begin < (const ngtcp2_range
- * *)(rhs->ptr)->begin and the 2 ranges do not intersect.
+ * ngtcp2_ksl_compar.  |lhs| and |rhs| must point to ngtcp2_range
+ * object, and the function returns nonzero if ((const ngtcp2_range
+ * *)lhs)->begin < ((const ngtcp2_range *)rhs)->begin, and the 2
+ * ranges do not intersect.
  */
 int ngtcp2_ksl_range_exclusive_compar(const ngtcp2_ksl_key *lhs,
                                       const ngtcp2_ksl_key *rhs);
 
+/*
+ * ngtcp2_ksl_range_exclusive_search is an implementation of
+ * ngtcp2_ksl_search that uses ngtcp2_ksl_range_exclusive_compar.
+ */
+size_t ngtcp2_ksl_range_exclusive_search(const ngtcp2_ksl *ksl,
+                                         ngtcp2_ksl_blk *blk,
+                                         const ngtcp2_ksl_key *key);
+
+/*
+ * ngtcp2_ksl_uint64_less is an implementation of ngtcp2_ksl_compar.
+ * |lhs| and |rhs| must point to uint64_t objects, and the function
+ * returns nonzero if *(uint64_t *)|lhs| < *(uint64_t *)|rhs|.
+ */
+int ngtcp2_ksl_uint64_less(const ngtcp2_ksl_key *lhs,
+                           const ngtcp2_ksl_key *rhs);
+
+/*
+ * ngtcp2_ksl_uint64_less_search is an implementation of
+ * ngtcp2_ksl_search that uses ngtcp2_ksl_uint64_less.
+ */
+size_t ngtcp2_ksl_uint64_less_search(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
+                                     const ngtcp2_ksl_key *key);
+
+/*
+ * ngtcp2_ksl_int64_greater is an implementation of ngtcp2_ksl_compar.
+ * |lhs| and |rhs| must point to int64_t objects, and the function
+ * returns nonzero if *(int64_t *)|lhs| > *(int64_t *)|rhs|.
+ */
+int ngtcp2_ksl_int64_greater(const ngtcp2_ksl_key *lhs,
+                             const ngtcp2_ksl_key *rhs);
+
+/*
+ * ngtcp2_ksl_int64_greater_search is an implementation of
+ * ngtcp2_ksl_search that uses ngtcp2_ksl_int64_greater.
+ */
+size_t ngtcp2_ksl_int64_greater_search(const ngtcp2_ksl *ksl,
+                                       ngtcp2_ksl_blk *blk,
+                                       const ngtcp2_ksl_key *key);
+
 #endif /* !defined(NGTCP2_KSL_H) */
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_macro.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_macro.h
index 649ed8434a..dfe5e0aed2 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_macro.h
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_macro.h
@@ -55,27 +55,27 @@
 #define ngtcp2_max_def(SUFFIX, T)                                              \
   static inline T ngtcp2_max_##SUFFIX(T a, T b) { return a < b ? b : a; }
 
-ngtcp2_max_def(int8, int8_t);
-ngtcp2_max_def(int16, int16_t);
-ngtcp2_max_def(int32, int32_t);
-ngtcp2_max_def(int64, int64_t);
-ngtcp2_max_def(uint8, uint8_t);
-ngtcp2_max_def(uint16, uint16_t);
-ngtcp2_max_def(uint32, uint32_t);
-ngtcp2_max_def(uint64, uint64_t);
-ngtcp2_max_def(size, size_t);
+ngtcp2_max_def(int8, int8_t)
+ngtcp2_max_def(int16, int16_t)
+ngtcp2_max_def(int32, int32_t)
+ngtcp2_max_def(int64, int64_t)
+ngtcp2_max_def(uint8, uint8_t)
+ngtcp2_max_def(uint16, uint16_t)
+ngtcp2_max_def(uint32, uint32_t)
+ngtcp2_max_def(uint64, uint64_t)
+ngtcp2_max_def(size, size_t)
 
 #define ngtcp2_min_def(SUFFIX, T)                                              \
   static inline T ngtcp2_min_##SUFFIX(T a, T b) { return a < b ? a : b; }
 
-ngtcp2_min_def(int8, int8_t);
-ngtcp2_min_def(int16, int16_t);
-ngtcp2_min_def(int32, int32_t);
-ngtcp2_min_def(int64, int64_t);
-ngtcp2_min_def(uint8, uint8_t);
-ngtcp2_min_def(uint16, uint16_t);
-ngtcp2_min_def(uint32, uint32_t);
-ngtcp2_min_def(uint64, uint64_t);
-ngtcp2_min_def(size, size_t);
+ngtcp2_min_def(int8, int8_t)
+ngtcp2_min_def(int16, int16_t)
+ngtcp2_min_def(int32, int32_t)
+ngtcp2_min_def(int64, int64_t)
+ngtcp2_min_def(uint8, uint8_t)
+ngtcp2_min_def(uint16, uint16_t)
+ngtcp2_min_def(uint32, uint32_t)
+ngtcp2_min_def(uint64, uint64_t)
+ngtcp2_min_def(size, size_t)
 
 #endif /* !defined(NGTCP2_MACRO_H) */
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pv.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pv.h
index 7ffa623d17..e9573da497 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pv.h
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pv.h
@@ -83,7 +83,7 @@ void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data,
 typedef struct ngtcp2_pv ngtcp2_pv;
 
 ngtcp2_static_ringbuf_def(pv_ents, NGTCP2_PV_MAX_ENTRIES,
-                          sizeof(ngtcp2_pv_entry));
+                          sizeof(ngtcp2_pv_entry))
 /*
  * ngtcp2_pv is the context of a single path validation.
  */
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c
index 1dab296a80..41446739bf 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c
@@ -31,18 +31,20 @@
 
 #include "ngtcp2_macro.h"
 
+#ifndef NDEBUG
 static int ispow2(size_t n) {
-#if defined(_MSC_VER) && !defined(__clang__) &&                                \
-  (defined(_M_ARM) || (defined(_M_ARM64) && _MSC_VER < 1941))
+#  if defined(_MSC_VER) && !defined(__clang__) &&                              \
+    (defined(_M_ARM) || (defined(_M_ARM64) && _MSC_VER < 1941))
   return n && !(n & (n - 1));
-#elif defined(WIN32)
+#  elif defined(WIN32)
   return 1 == __popcnt((unsigned int)n);
-#else  /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) ||   \
-          (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
+#  else  /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \
+            (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
   return 1 == __builtin_popcount((unsigned int)n);
-#endif /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) ||   \
-          (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
+#  endif /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \
+            (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
 }
+#endif /* !defined(NDEBUG) */
 
 int ngtcp2_ringbuf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size,
                         const ngtcp2_mem *mem) {
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rob.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rob.c
index 12c7d40976..ce6c2113dd 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rob.c
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rob.c
@@ -68,8 +68,8 @@ int ngtcp2_rob_init(ngtcp2_rob *rob, size_t chunk, const ngtcp2_mem *mem) {
   int rv;
   ngtcp2_rob_gap *g;
 
-  ngtcp2_ksl_init(&rob->gapksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range),
-                  mem);
+  ngtcp2_ksl_init(&rob->gapksl, ngtcp2_ksl_range_compar,
+                  ngtcp2_ksl_range_search, sizeof(ngtcp2_range), mem);
 
   rv = ngtcp2_rob_gap_new(&g, 0, UINT64_MAX, mem);
   if (rv != 0) {
@@ -81,8 +81,8 @@ int ngtcp2_rob_init(ngtcp2_rob *rob, size_t chunk, const ngtcp2_mem *mem) {
     goto fail_gapksl_ksl_insert;
   }
 
-  ngtcp2_ksl_init(&rob->dataksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range),
-                  mem);
+  ngtcp2_ksl_init(&rob->dataksl, ngtcp2_ksl_range_compar,
+                  ngtcp2_ksl_range_search, sizeof(ngtcp2_range), mem);
 
   rob->chunk = chunk;
   rob->mem = mem;
@@ -125,8 +125,8 @@ static int rob_write_data(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
   ngtcp2_range range = {offset, offset + len};
   ngtcp2_ksl_it it;
 
-  for (it = ngtcp2_ksl_lower_bound_compar(&rob->dataksl, &range,
-                                          ngtcp2_ksl_range_exclusive_compar);
+  for (it = ngtcp2_ksl_lower_bound_search(&rob->dataksl, &range,
+                                          ngtcp2_ksl_range_exclusive_search);
        len; ngtcp2_ksl_it_next(&it)) {
     if (ngtcp2_ksl_it_end(&it)) {
       d = NULL;
@@ -166,8 +166,8 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
   ngtcp2_range m, l, r, q = {offset, offset + datalen};
   ngtcp2_ksl_it it;
 
-  it = ngtcp2_ksl_lower_bound_compar(&rob->gapksl, &q,
-                                     ngtcp2_ksl_range_exclusive_compar);
+  it = ngtcp2_ksl_lower_bound_search(&rob->gapksl, &q,
+                                     ngtcp2_ksl_range_exclusive_search);
 
   for (; !ngtcp2_ksl_it_end(&it);) {
     g = ngtcp2_ksl_it_get(&it);
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c
index 008ba470c2..4d417186e1 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c
@@ -38,7 +38,7 @@
 #include "ngtcp2_tstamp.h"
 #include "ngtcp2_frame_chain.h"
 
-ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent);
+ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent)
 
 static void rtb_entry_init(ngtcp2_rtb_entry *ent, const ngtcp2_pkt_hd *hd,
                            ngtcp2_frame_chain *frc, ngtcp2_tstamp ts,
@@ -81,17 +81,14 @@ void ngtcp2_rtb_entry_objalloc_del(ngtcp2_rtb_entry *ent,
   ngtcp2_objalloc_rtb_entry_release(objalloc, ent);
 }
 
-static int greater(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
-  return *(int64_t *)lhs > *(int64_t *)rhs;
-}
-
 void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_rst *rst, ngtcp2_cc *cc,
                      int64_t cc_pkt_num, ngtcp2_log *log, ngtcp2_qlog *qlog,
                      ngtcp2_objalloc *rtb_entry_objalloc,
                      ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) {
   rtb->rtb_entry_objalloc = rtb_entry_objalloc;
   rtb->frc_objalloc = frc_objalloc;
-  ngtcp2_ksl_init(&rtb->ents, greater, sizeof(int64_t), mem);
+  ngtcp2_ksl_init(&rtb->ents, ngtcp2_ksl_int64_greater,
+                  ngtcp2_ksl_int64_greater_search, sizeof(int64_t), mem);
   rtb->rst = rst;
   rtb->cc = cc;
   rtb->log = log;
@@ -870,7 +867,8 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
   }
 
   if (largest_pkt_sent_ts != UINT64_MAX && ack_eliciting_pkt_acked) {
-    cc_ack.rtt = pkt_ts - largest_pkt_sent_ts;
+    cc_ack.rtt =
+      ngtcp2_max_uint64(pkt_ts - largest_pkt_sent_ts, NGTCP2_NANOSECONDS);
 
     rv = ngtcp2_conn_update_rtt(conn, cc_ack.rtt, fr->ack_delay_unscaled, ts);
     if (rv == 0 && cc->new_rtt_sample) {
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h
index 768f4abc42..2ef772b2e1 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h
@@ -124,7 +124,7 @@ struct ngtcp2_rtb_entry {
   };
 };
 
-ngtcp2_objalloc_decl(rtb_entry, ngtcp2_rtb_entry, oplent);
+ngtcp2_objalloc_decl(rtb_entry, ngtcp2_rtb_entry, oplent)
 
 /*
  * ngtcp2_rtb_entry_objalloc_new allocates ngtcp2_rtb_entry object via
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c
index a30b052483..8ea969c4ad 100644
--- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c
+++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c
@@ -32,10 +32,6 @@
 #include "ngtcp2_vec.h"
 #include "ngtcp2_frame_chain.h"
 
-static int offset_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
-  return *(int64_t *)lhs < *(int64_t *)rhs;
-}
-
 void ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags,
                       uint64_t max_rx_offset, uint64_t max_tx_offset,
                       void *stream_user_data, ngtcp2_objalloc *frc_objalloc,
@@ -180,7 +176,8 @@ static int strm_streamfrq_init(ngtcp2_strm *strm) {
     return NGTCP2_ERR_NOMEM;
   }
 
-  ngtcp2_ksl_init(streamfrq, offset_less, sizeof(uint64_t), strm->mem);
+  ngtcp2_ksl_init(streamfrq, ngtcp2_ksl_uint64_less,
+                  ngtcp2_ksl_uint64_less_search, sizeof(uint64_t), strm->mem);
 
   strm->tx.streamfrq = streamfrq;
 
diff --git a/src/contrib/libngtcp2/ngtcp2/ngtcp2.h b/src/contrib/libngtcp2/ngtcp2/ngtcp2.h
index d9957752eb..acc79be6e0 100644
--- a/src/contrib/libngtcp2/ngtcp2/ngtcp2.h
+++ b/src/contrib/libngtcp2/ngtcp2/ngtcp2.h
@@ -1777,6 +1777,13 @@ typedef struct ngtcp2_settings {
    * or :member:`ngtcp2_transport_params.initial_max_stream_data_uni`,
    * depending on the type of stream.  The window size is scaled up to
    * the value specified in this field.
+   *
+   * Please note that the auto-tuning is done per stream.  Even if the
+   * previous stream gets larger window as a result of auto-tuning,
+   * the new stream still starts with the initial value set in
+   * transport parameters.  This might become a bottleneck if
+   * congestion window of a remote server is wide open.  If this
+   * causes an issue, do not enable auto-tuning.
    */
   uint64_t max_stream_window;
   /**
diff --git a/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h b/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h
index 5b8626191d..68093d18b7 100644
--- a/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h
+++ b/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h
@@ -38,6 +38,37 @@ extern "C" {
 #  include <ws2tcpip.h>
 #endif /* defined(WIN32) */
 
+/**
+ * @macrosection
+ *
+ * ngtcp2 crypto library error codes
+ */
+
+/**
+ * @macro
+ *
+ * :macro:`NGTCP2_CRYPTO_ERR_INTERNAL` indicates an internal error.
+ */
+#define NGTCP2_CRYPTO_ERR_INTERNAL -201
+
+/**
+ * @macro
+ *
+ * :macro:`NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN` indicates that a token
+ * is unreadable because it is not correctly formatted; or verifying
+ * the integrity protection failed.
+ */
+#define NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN -202
+
+/**
+ * @macro
+ *
+ * :macro:`NGTCP2_CRYPTO_ERR_VERIFY_TOKEN` indicates that a token does
+ * not probe the client address; or the token validity has expired; or
+ * it contains invalid Connection ID.
+ */
+#define NGTCP2_CRYPTO_ERR_VERIFY_TOKEN -203
+
 /**
  * @function
  *
@@ -547,6 +578,14 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token(
  */
 #define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY 0xb6
 
+/**
+ * @macro
+ *
+ * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2` is the magic byte for
+ * Retry token generated by `ngtcp2_crypto_generate_retry_token2`.
+ */
+#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2 0xb7
+
 /**
  * @macro
  *
@@ -566,6 +605,17 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token(
    sizeof(ngtcp2_tstamp) + /* aead tag = */ 16 +                               \
    NGTCP2_CRYPTO_TOKEN_RAND_DATALEN)
 
+/**
+ * @macro
+ *
+ * :macro:`NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN2` is the maximum length of
+ * a token generated by `ngtcp2_crypto_generate_retry_token2`.
+ */
+#define NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN2                                      \
+  (/* magic = */ 1 + sizeof(ngtcp2_sockaddr_union) + /* cid len = */ 1 +       \
+   NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp) + /* aead tag = */ 16 +           \
+   NGTCP2_CRYPTO_TOKEN_RAND_DATALEN)
+
 /**
  * @macro
  *
@@ -592,6 +642,8 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token(
  * is a Destination Connection ID in Initial packet sent by client.
  * |ts| is the timestamp when the token is generated.
  *
+ * See also `ngtcp2_crypto_generate_retry_token2`.
+ *
  * This function returns the length of generated token if it succeeds,
  * or -1.
  */
@@ -624,6 +676,72 @@ NGTCP2_EXTERN int ngtcp2_crypto_verify_retry_token(
   const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
   const ngtcp2_cid *dcid, ngtcp2_duration timeout, ngtcp2_tstamp ts);
 
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_generate_retry_token2` generates a token in the
+ * buffer pointed by |token| that is sent with Retry packet.  The
+ * buffer pointed by |token| must have at least
+ * :macro:`NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN2` bytes long.  The
+ * successfully generated token starts with
+ * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2`.  |secret| of length
+ * |secretlen| is a keying material to generate keys to encrypt the
+ * token.  |version| is QUIC version.  |remote_addr| of length
+ * |remote_addrlen| is an address of client.  |retry_scid| is a Source
+ * Connection ID chosen by server, and set in Retry packet.  |odcid|
+ * is a Destination Connection ID in Initial packet sent by client.
+ * |ts| is the timestamp when the token is generated.
+ *
+ * Use this function instead of `ngtcp2_crypto_generate_retry_token`
+ * if more detailed error handling is required when verifying the
+ * token.  `ngtcp2_crypto_verify_retry_token2` must be used to verify
+ * the token.
+ *
+ * This function returns the length of generated token if it succeeds,
+ * or -1.
+ */
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_generate_retry_token2(
+  uint8_t *token, const uint8_t *secret, size_t secretlen, uint32_t version,
+  const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
+  const ngtcp2_cid *retry_scid, const ngtcp2_cid *odcid, ngtcp2_tstamp ts);
+
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_verify_retry_token2` verifies Retry token stored in
+ * the buffer pointed by |token| of length |tokenlen|.  |secret| of
+ * length |secretlen| is a keying material to generate keys to decrypt
+ * the token.  |version| is QUIC version of the Initial packet that
+ * contains this token.  |remote_addr| of length |remote_addrlen| is
+ * an address of client.  |dcid| is a Destination Connection ID in
+ * Initial packet sent by client.  |timeout| is the period during
+ * which the token is valid.  |ts| is the current timestamp.  When
+ * validation succeeds, the extracted Destination Connection ID (which
+ * is the Destination Connection ID in Initial packet sent by client
+ * that triggered Retry packet) is stored in the buffer pointed by
+ * |odcid|.
+ *
+ * The token must be generated by
+ * `ngtcp2_crypto_generate_retry_token2`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :macro:`NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN`
+ *     A token is badly formatted; or verifying the integrity
+ *     protection failed.
+ * :macro:`NGTCP2_CRYPTO_ERR_VERIFY_TOKEN`
+ *     A token does not probe the client address; or the token
+ *     validity has expired; or it contains invalid Connection ID.
+ * :macro:`NGTCP2_CRYPTO_ERR_INTERNAL`
+ *     Internal error occurred.
+ */
+NGTCP2_EXTERN int ngtcp2_crypto_verify_retry_token2(
+  ngtcp2_cid *odcid, const uint8_t *token, size_t tokenlen,
+  const uint8_t *secret, size_t secretlen, uint32_t version,
+  const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
+  const ngtcp2_cid *dcid, ngtcp2_duration timeout, ngtcp2_tstamp ts);
+
 /**
  * @function
  *
diff --git a/src/contrib/libngtcp2/ngtcp2/version.h b/src/contrib/libngtcp2/ngtcp2/version.h
index 881ecb114d..15bf36ded2 100644
--- a/src/contrib/libngtcp2/ngtcp2/version.h
+++ b/src/contrib/libngtcp2/ngtcp2/version.h
@@ -36,7 +36,7 @@
  *
  * Version number of the ngtcp2 library release.
  */
-#define NGTCP2_VERSION "1.8.1"
+#define NGTCP2_VERSION "1.9.0"
 
 /**
  * @macro
@@ -46,6 +46,6 @@
  * number, 8 bits for minor and 8 bits for patch. Version 1.2.3
  * becomes 0x010203.
  */
-#define NGTCP2_VERSION_NUM 0x010801
+#define NGTCP2_VERSION_NUM 0x010900
 
 #endif /* !defined(NGTCP2_VERSION_H) */
-- 
GitLab