diff -Npur samba-4.23.7/VERSION samba-4.23.8/VERSION
--- samba-4.23.7/VERSION	2026-04-21 13:40:11.572528100 +0200
+++ samba-4.23.8/VERSION	2026-05-15 15:49:15.061977000 +0200
@@ -27,7 +27,7 @@ SAMBA_COPYRIGHT_STRING="Copyright Andrew
 ########################################################
 SAMBA_VERSION_MAJOR=4
 SAMBA_VERSION_MINOR=23
-SAMBA_VERSION_RELEASE=7
+SAMBA_VERSION_RELEASE=8
 
 ########################################################
 # If a official release has a serious bug              #
diff -Npur samba-4.23.7/WHATSNEW.txt samba-4.23.8/WHATSNEW.txt
--- samba-4.23.7/WHATSNEW.txt	2026-04-21 13:40:11.572528100 +0200
+++ samba-4.23.8/WHATSNEW.txt	2026-05-15 15:49:15.061977000 +0200
@@ -1,4 +1,126 @@
                    ==============================
+                   Release Notes for Samba 4.23.8
+                            May 26, 2026
+                   ==============================
+
+
+This is a security release in order to address the following defects:
+
+o CVE-2026-1933:   Missing access checks on reparse point operations
+
+                   On a share marked "read only = yes" and
+                   on file handles opened R/O users can set
+                   or delete the reparse point xattrs on files
+                   that the user has write-access in the file
+                   system for.
+
+                   https://www.samba.org/samba/security/CVE-2026-1933.html
+
+
+o CVE-2026-2340:   WORM vfs module does not block overwrites
+
+                   The WORM (Write-Once, Read Many) vfs module
+                   is supposed to lock write access to shared
+                   files, so they cannot be altered after initial
+                   writes. It was allowing files to be overwritten
+                   by renaming a newly created file over a protected
+                   file.
+
+                   https://www.samba.org/samba/security/CVE-2026-2340.html
+
+
+o CVE-2026-3012:   auto-enrolment GPO installing CA certificate over http
+                   without verification
+
+                   To bootstrap a certificate chain a domain member must
+                   fetch a certificate without TLS. It was trusting HTTP
+                   for this when a more secure encrypted LDAP channel
+                   was also available.
+
+                   https://www.samba.org/samba/security/CVE-2026-3012.html
+
+
+o CVE-2026-3238:   Denial of service against AD DC WINS server
+
+                   The WINS server component of the Active
+                   Directory Domain controller code in Samba
+                   is vulnerable to a NULL pointer dereference
+                   and crash caused by a unauthenticated UDP
+                   packet.
+
+                   https://www.samba.org/samba/security/CVE-2026-3238.html
+
+
+o CVE-2026-4408:   Unauthenticated Remote Code Execution in Samba DCE/RPC SAMR
+                   server
+
+                   Samba file servers and classic (non-AD) domain controllers
+                   with samba-dcerpcd started as a system service and with a
+                   "check password script" that has the %u substitution
+                   character are vulnerable to a remote code execution.
+
+                   https://www.samba.org/samba/security/CVE-2026-4408.html
+
+
+o CVE-2026-4480:   Unauthenticated Remote Code Execution in Samba printing
+                   subsystem
+
+                   Samba print servers with a "print command"
+                   that has the %J substitution character
+                   are vulnerable to a Remote Code Execution.
+
+                   https://www.samba.org/samba/security/CVE-2026-4480.html
+
+
+Changes since 4.23.7
+--------------------
+
+o  Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
+   * BUG 15997: CVE-2026-2340
+   * BUG 16003: CVE-2026-3012
+   * BUG 16033: CVE-2026-4480
+   * BUG 16034: CVE-2026-4408
+
+o  Pavel Kohout <pavel@aisle.com>
+   * BUG 15997: CVE-2026-2340
+
+o  Volker Lendecke <vl@samba.org>
+   * BUG 15992: CVE-2026-1933
+   * BUG 16012: CVE-2026-3238
+
+o  Stefan Metzmacher <metze@samba.org>
+   * BUG 15992: CVE-2026-1933
+   * BUG 16033: CVE-2026-4480
+   * BUG 16034: CVE-2026-4408
+   * BUG 16059: CVE-2026-40170: thirdparty ngtcp2 needs to be updated
+   * BUG 16073: Winbind can change Ownership Of / To A User Who has Homedir / In
+     passwd
+
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical:matrix.org matrix room, or
+#samba-technical IRC channel on irc.libera.chat.
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored.  All bug reports should
+be filed under the Samba 4.1 and newer product in the project's Bugzilla
+database (https://bugzilla.samba.org/).
+
+
+======================================================================
+== Our Code, Our Bugs, Our Responsibility.
+== The Samba Team
+======================================================================
+
+
+Release notes for older releases follow:
+----------------------------------------
+                   ==============================
                    Release Notes for Samba 4.23.7
                            April 21, 2026
                    ==============================
@@ -51,8 +173,7 @@ database (https://bugzilla.samba.org/).
 ======================================================================
 
 
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
                    ==============================
                    Release Notes for Samba 4.23.6
                          February 27, 2026
diff -Npur samba-4.23.7/ctdb/doc/ctdb-etcd.7 samba-4.23.8/ctdb/doc/ctdb-etcd.7
--- samba-4.23.7/ctdb/doc/ctdb-etcd.7	2026-04-21 13:41:23.681366000 +0200
+++ samba-4.23.8/ctdb/doc/ctdb-etcd.7	2026-05-15 15:49:34.162084600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ctdb-etcd
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB\-ETCD" "7" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\-ETCD" "7" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdb-etcd.7.html samba-4.23.8/ctdb/doc/ctdb-etcd.7.html
--- samba-4.23.7/ctdb/doc/ctdb-etcd.7.html	2026-04-21 13:41:23.809367400 +0200
+++ samba-4.23.8/ctdb/doc/ctdb-etcd.7.html	2026-05-15 15:49:34.242498200 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-etcd</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-etcd.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-etcd &#8212; CTDB etcd integration</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdb_etcd_lock</code> </p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-etcd</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-etcd.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-etcd &#8212; CTDB etcd integration</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdb_etcd_lock</code> </p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       ctdb_etcd_lock is intended to be run as a mutex helper for CTDB. It
       will try to connect to an existing etcd cluster and grab a lock in that
       cluster to function as CTDB's cluster lock. Please see
diff -Npur samba-4.23.7/ctdb/doc/ctdb-script.options.5 samba-4.23.8/ctdb/doc/ctdb-script.options.5
--- samba-4.23.7/ctdb/doc/ctdb-script.options.5	2026-04-21 13:41:22.033347100 +0200
+++ samba-4.23.8/ctdb/doc/ctdb-script.options.5	2026-05-15 15:49:33.184678800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ctdb-script.options
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB\-SCRIPT\&.OPTIO" "5" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\-SCRIPT\&.OPTIO" "5" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdb-script.options.5.html samba-4.23.8/ctdb/doc/ctdb-script.options.5.html
--- samba-4.23.7/ctdb/doc/ctdb-script.options.5.html	2026-04-21 13:41:22.189349000 +0200
+++ samba-4.23.8/ctdb/doc/ctdb-script.options.5.html	2026-05-15 15:49:33.274643200 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-script.options</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-script.options.5"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-script.options &#8212; CTDB scripts configuration files</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><div class="refsect2"><a name="id1338"></a><h3>Location</h3><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-script.options</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-script.options.5"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-script.options &#8212; CTDB scripts configuration files</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><div class="refsect2"><a name="id1338"></a><h3>Location</h3><p>
 	Each CTDB script has 2 possible locations for its configuration options:
       </p><div class="variablelist"><dl class="variablelist"><dt><span class="term">
 	    <code class="filename">/usr/local/etc/ctdb/script.options</code>
diff -Npur samba-4.23.7/ctdb/doc/ctdb-statistics.7 samba-4.23.8/ctdb/doc/ctdb-statistics.7
--- samba-4.23.7/ctdb/doc/ctdb-statistics.7	2026-04-21 13:41:23.033358600 +0200
+++ samba-4.23.8/ctdb/doc/ctdb-statistics.7	2026-05-15 15:49:33.782311400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ctdb-statistics
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB\-STATISTICS" "7" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\-STATISTICS" "7" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdb-statistics.7.html samba-4.23.8/ctdb/doc/ctdb-statistics.7.html
--- samba-4.23.7/ctdb/doc/ctdb-statistics.7.html	2026-04-21 13:41:23.165360000 +0200
+++ samba-4.23.8/ctdb/doc/ctdb-statistics.7.html	2026-05-15 15:49:33.868804700 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-statistics</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-statistics.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-statistics &#8212; CTDB statistics output</p></div><div class="refsect1"><a name="id1337"></a><h2>OVERALL STATISTICS</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-statistics</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-statistics.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-statistics &#8212; CTDB statistics output</p></div><div class="refsect1"><a name="id1337"></a><h2>OVERALL STATISTICS</h2><p>
       CTDB maintains information about various messages communicated
       and some of the important operations per node.  See the
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span> commands
diff -Npur samba-4.23.7/ctdb/doc/ctdb-tunables.7 samba-4.23.8/ctdb/doc/ctdb-tunables.7
--- samba-4.23.7/ctdb/doc/ctdb-tunables.7	2026-04-21 13:41:23.369362400 +0200
+++ samba-4.23.8/ctdb/doc/ctdb-tunables.7	2026-05-15 15:49:33.980749800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ctdb-tunables
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB\-TUNABLES" "7" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\-TUNABLES" "7" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdb-tunables.7.html samba-4.23.8/ctdb/doc/ctdb-tunables.7.html
--- samba-4.23.7/ctdb/doc/ctdb-tunables.7.html	2026-04-21 13:41:23.501364000 +0200
+++ samba-4.23.8/ctdb/doc/ctdb-tunables.7.html	2026-05-15 15:49:34.064217300 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-tunables</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-tunables.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-tunables &#8212; CTDB tunable configuration variables</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb-tunables</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb-tunables.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb-tunables &#8212; CTDB tunable configuration variables</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       CTDB's behaviour can be configured by setting run-time tunable
       variables.  This lists and describes all tunables.  See the
       <span class="citerefentry"><span class="refentrytitle">ctdb</span>(1)</span>
diff -Npur samba-4.23.7/ctdb/doc/ctdb.1 samba-4.23.8/ctdb/doc/ctdb.1
--- samba-4.23.7/ctdb/doc/ctdb.1	2026-04-21 13:41:19.729320500 +0200
+++ samba-4.23.8/ctdb/doc/ctdb.1	2026-05-15 15:49:31.863327500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ctdb
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB" "1" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB" "1" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdb.1.html samba-4.23.8/ctdb/doc/ctdb.1.html
--- samba-4.23.7/ctdb/doc/ctdb.1.html	2026-04-21 13:41:19.889322500 +0200
+++ samba-4.23.8/ctdb/doc/ctdb.1.html	2026-05-15 15:49:31.958517300 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb &#8212; CTDB management utility</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdb</code>  [<em class="replaceable"><code>OPTION</code></em>...] {<em class="replaceable"><code>COMMAND</code></em>} [<em class="replaceable"><code>COMMAND-ARGS</code></em>]</p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb &#8212; CTDB management utility</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdb</code>  [<em class="replaceable"><code>OPTION</code></em>...] {<em class="replaceable"><code>COMMAND</code></em>} [<em class="replaceable"><code>COMMAND-ARGS</code></em>]</p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       ctdb is a utility to view and manage a CTDB cluster.
     </p><p>
       The following terms are used when referring to nodes in a
diff -Npur samba-4.23.7/ctdb/doc/ctdb.7 samba-4.23.8/ctdb/doc/ctdb.7
--- samba-4.23.7/ctdb/doc/ctdb.7	2026-04-21 13:41:22.705354700 +0200
+++ samba-4.23.8/ctdb/doc/ctdb.7	2026-05-15 15:49:33.590409300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ctdb
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB" "7" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB" "7" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdb.7.html samba-4.23.8/ctdb/doc/ctdb.7.html
--- samba-4.23.7/ctdb/doc/ctdb.7.html	2026-04-21 13:41:22.845356500 +0200
+++ samba-4.23.8/ctdb/doc/ctdb.7.html	2026-05-15 15:49:33.677691200 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb &#8212; Clustered TDB</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb &#8212; Clustered TDB</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
     CTDB is a clustered database component in clustered Samba that
     provides a high-availability load-sharing CIFS server cluster.
   </p><p>
diff -Npur samba-4.23.7/ctdb/doc/ctdb.conf.5 samba-4.23.8/ctdb/doc/ctdb.conf.5
--- samba-4.23.7/ctdb/doc/ctdb.conf.5	2026-04-21 13:41:21.657342700 +0200
+++ samba-4.23.8/ctdb/doc/ctdb.conf.5	2026-05-15 15:49:32.981877800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ctdb.conf
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB\&.CONF" "5" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\&.CONF" "5" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdb.conf.5.html samba-4.23.8/ctdb/doc/ctdb.conf.5.html
--- samba-4.23.7/ctdb/doc/ctdb.conf.5.html	2026-04-21 13:41:21.813344500 +0200
+++ samba-4.23.8/ctdb/doc/ctdb.conf.5.html	2026-05-15 15:49:33.070333200 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb.conf</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.conf.5"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb.conf &#8212; CTDB configuration file</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb.conf</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.conf.5"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb.conf &#8212; CTDB configuration file</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       This file contains CTDB configuration options that affect the
       operation of CTDB daemons and command-line tools.  The default
       location of this file is
diff -Npur samba-4.23.7/ctdb/doc/ctdb.sysconfig.5 samba-4.23.8/ctdb/doc/ctdb.sysconfig.5
--- samba-4.23.7/ctdb/doc/ctdb.sysconfig.5	2026-04-21 13:41:22.357350800 +0200
+++ samba-4.23.8/ctdb/doc/ctdb.sysconfig.5	2026-05-15 15:49:33.389469400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ctdb.sysconfig
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB\&.SYSCONFIG" "5" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\&.SYSCONFIG" "5" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdb.sysconfig.5.html samba-4.23.8/ctdb/doc/ctdb.sysconfig.5.html
--- samba-4.23.7/ctdb/doc/ctdb.sysconfig.5.html	2026-04-21 13:41:22.493352400 +0200
+++ samba-4.23.8/ctdb/doc/ctdb.sysconfig.5.html	2026-05-15 15:49:33.472217800 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb.sysconfig</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.sysconfig.5"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb.sysconfig &#8212; CTDB daemon configuration file</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb.sysconfig</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb.sysconfig.5"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb.sysconfig &#8212; CTDB daemon configuration file</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       This file contains configuration that affects the operation of
       CTDB.  This is a distribution-specific service configuration
       file such as <code class="filename">/etc/sysconfig/ctdb</code> (Red Hat)
diff -Npur samba-4.23.7/ctdb/doc/ctdb_diagnostics.1 samba-4.23.8/ctdb/doc/ctdb_diagnostics.1
--- samba-4.23.7/ctdb/doc/ctdb_diagnostics.1	2026-04-21 13:41:21.001335100 +0200
+++ samba-4.23.8/ctdb/doc/ctdb_diagnostics.1	2026-05-15 15:49:32.609043400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ctdb_diagnostics
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDB_DIAGNOSTICS" "1" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB_DIAGNOSTICS" "1" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdb_diagnostics.1.html samba-4.23.8/ctdb/doc/ctdb_diagnostics.1.html
--- samba-4.23.7/ctdb/doc/ctdb_diagnostics.1.html	2026-04-21 13:41:21.125336600 +0200
+++ samba-4.23.8/ctdb/doc/ctdb_diagnostics.1.html	2026-05-15 15:49:32.687226000 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb_diagnostics</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb_diagnostics.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb_diagnostics &#8212; dump diagnostic information about CTDB/Samba installation</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdb_diagnostics</code>  [OPTIONS]  ... </p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdb_diagnostics</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb_diagnostics.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb_diagnostics &#8212; dump diagnostic information about CTDB/Samba installation</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdb_diagnostics</code>  [OPTIONS]  ... </p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       ctdb_diagnostics is used to dump diagnostic information about a
       clustered Samba installation.  This includes configuration
       files, output of relevant commands and logs.  This information
diff -Npur samba-4.23.7/ctdb/doc/ctdb_mutex_ceph_rados_helper.7 samba-4.23.8/ctdb/doc/ctdb_mutex_ceph_rados_helper.7
--- samba-4.23.7/ctdb/doc/ctdb_mutex_ceph_rados_helper.7	2026-04-21 13:41:23.993369600 +0200
+++ samba-4.23.8/ctdb/doc/ctdb_mutex_ceph_rados_helper.7	2026-05-15 15:49:34.351509600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: Ceph RADOS Mutex
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CEPH RADOS MUTEX" "7" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CEPH RADOS MUTEX" "7" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdb_mutex_ceph_rados_helper.7.html samba-4.23.8/ctdb/doc/ctdb_mutex_ceph_rados_helper.7.html
--- samba-4.23.7/ctdb/doc/ctdb_mutex_ceph_rados_helper.7.html	2026-04-21 13:41:24.129371200 +0200
+++ samba-4.23.8/ctdb/doc/ctdb_mutex_ceph_rados_helper.7.html	2026-05-15 15:49:34.432503500 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Ceph RADOS Mutex</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb_mutex_ceph_rados_helper.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb_mutex_ceph_rados_helper &#8212; Ceph RADOS cluster mutex helper</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Ceph RADOS Mutex</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdb_mutex_ceph_rados_helper.7"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdb_mutex_ceph_rados_helper &#8212; Ceph RADOS cluster mutex helper</p></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       ctdb_mutex_ceph_rados_helper can be used as a cluster lock provider
       for CTDB.  When configured, split brain avoidance during CTDB recovery
       will be handled using locks against an object located in a Ceph RADOS
diff -Npur samba-4.23.7/ctdb/doc/ctdbd.1 samba-4.23.8/ctdb/doc/ctdbd.1
--- samba-4.23.7/ctdb/doc/ctdbd.1	2026-04-21 13:41:20.065324500 +0200
+++ samba-4.23.8/ctdb/doc/ctdbd.1	2026-05-15 15:49:32.057958400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ctdbd
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "CTDBD" "1" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDBD" "1" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ctdbd.1.html samba-4.23.8/ctdb/doc/ctdbd.1.html
--- samba-4.23.7/ctdb/doc/ctdbd.1.html	2026-04-21 13:41:20.193326000 +0200
+++ samba-4.23.8/ctdb/doc/ctdbd.1.html	2026-05-15 15:49:32.137218200 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdbd.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd &#8212; The CTDB cluster daemon</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdbd</code>  [<em class="replaceable"><code>OPTION</code></em>...]</p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ctdbd</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ctdbd.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ctdbd &#8212; The CTDB cluster daemon</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ctdbd</code>  [<em class="replaceable"><code>OPTION</code></em>...]</p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       ctdbd is the main CTDB daemon.
     </p><p>
       See <span class="citerefentry"><span class="refentrytitle">ctdb</span>(7)</span> for an overview of CTDB.
diff -Npur samba-4.23.7/ctdb/doc/ltdbtool.1 samba-4.23.8/ctdb/doc/ltdbtool.1
--- samba-4.23.7/ctdb/doc/ltdbtool.1	2026-04-21 13:41:20.385328000 +0200
+++ samba-4.23.8/ctdb/doc/ltdbtool.1	2026-05-15 15:49:32.237539800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ltdbtool
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "LTDBTOOL" "1" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "LTDBTOOL" "1" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ltdbtool.1.html samba-4.23.8/ctdb/doc/ltdbtool.1.html
--- samba-4.23.7/ctdb/doc/ltdbtool.1.html	2026-04-21 13:41:20.521329600 +0200
+++ samba-4.23.8/ctdb/doc/ltdbtool.1.html	2026-05-15 15:49:32.330318500 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ltdbtool</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ltdbtool.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ltdbtool &#8212; manipulate CTDB's local TDB files</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ltdbtool</code>  [<em class="replaceable"><code>OPTION</code></em>...] {<em class="replaceable"><code>COMMAND</code></em>} [<em class="replaceable"><code>COMMAND-ARGS</code></em>]</p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ltdbtool</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ltdbtool.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ltdbtool &#8212; manipulate CTDB's local TDB files</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ltdbtool</code>  [<em class="replaceable"><code>OPTION</code></em>...] {<em class="replaceable"><code>COMMAND</code></em>} [<em class="replaceable"><code>COMMAND-ARGS</code></em>]</p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       ltdbtool is a utility to manipulate CTDB's local TDB databases
       (LTDBs) without connecting to a CTDB daemon.
     </p><p>
diff -Npur samba-4.23.7/ctdb/doc/onnode.1 samba-4.23.8/ctdb/doc/onnode.1
--- samba-4.23.7/ctdb/doc/onnode.1	2026-04-21 13:41:21.321339000 +0200
+++ samba-4.23.8/ctdb/doc/onnode.1	2026-05-15 15:49:32.786227500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: onnode
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "ONNODE" "1" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "ONNODE" "1" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/onnode.1.html samba-4.23.8/ctdb/doc/onnode.1.html
--- samba-4.23.7/ctdb/doc/onnode.1.html	2026-04-21 13:41:21.461340400 +0200
+++ samba-4.23.8/ctdb/doc/onnode.1.html	2026-05-15 15:49:32.870558000 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>onnode</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="onnode.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>onnode &#8212; run commands on CTDB cluster nodes</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">onnode</code>  [<em class="replaceable"><code>OPTION</code></em>...] {<em class="replaceable"><code>NODES</code></em>} {<em class="replaceable"><code>COMMAND</code></em>}</p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>onnode</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="onnode.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>onnode &#8212; run commands on CTDB cluster nodes</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">onnode</code>  [<em class="replaceable"><code>OPTION</code></em>...] {<em class="replaceable"><code>NODES</code></em>} {<em class="replaceable"><code>COMMAND</code></em>}</p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       onnode is a utility to run commands on a specific node of a CTDB
       cluster, or on all nodes.
     </p><p>
diff -Npur samba-4.23.7/ctdb/doc/ping_pong.1 samba-4.23.8/ctdb/doc/ping_pong.1
--- samba-4.23.7/ctdb/doc/ping_pong.1	2026-04-21 13:41:20.705331800 +0200
+++ samba-4.23.8/ctdb/doc/ping_pong.1	2026-05-15 15:49:32.432145400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ping_pong
 .\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: CTDB - clustered TDB database
 .\"    Source: ctdb
 .\"  Language: English
 .\"
-.TH "PING_PONG" "1" "04/21/2026" "ctdb" "CTDB \- clustered TDB database"
+.TH "PING_PONG" "1" "05/15/2026" "ctdb" "CTDB \- clustered TDB database"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/ctdb/doc/ping_pong.1.html samba-4.23.8/ctdb/doc/ping_pong.1.html
--- samba-4.23.7/ctdb/doc/ping_pong.1.html	2026-04-21 13:41:20.837333400 +0200
+++ samba-4.23.8/ctdb/doc/ping_pong.1.html	2026-05-15 15:49:32.511983600 +0200
@@ -1,4 +1,4 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ping_pong</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ping_pong.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ping_pong &#8212; measures the ping-pong byte range lock latency</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ping_pong</code>  { -r  |   -w  |   -rw } [-m] [-c] {<em class="replaceable"><code>FILENAME</code></em>} {<em class="replaceable"><code>NUM-LOCKS</code></em>}</p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>ping_pong</title><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"><a name="ping_pong.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>ping_pong &#8212; measures the ping-pong byte range lock latency</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">ping_pong</code>  { -r  |   -w  |   -rw } [-m] [-c] {<em class="replaceable"><code>FILENAME</code></em>} {<em class="replaceable"><code>NUM-LOCKS</code></em>}</p></div></div><div class="refsect1"><a name="id1337"></a><h2>DESCRIPTION</h2><p>
       ping_pong measures the byte range lock latency. It is especially
       useful on a cluster of nodes sharing a common lock manager as it
       will give some indication of the lock manager's performance
diff -Npur samba-4.23.7/docs/manpages/cifsdd.8 samba-4.23.8/docs/manpages/cifsdd.8
--- samba-4.23.7/docs/manpages/cifsdd.8	2026-04-21 13:41:25.069382000 +0200
+++ samba-4.23.8/docs/manpages/cifsdd.8	2026-05-15 15:49:35.543266300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: cifsdd
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "CIFSDD" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "CIFSDD" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/dbwrap_tool.1 samba-4.23.8/docs/manpages/dbwrap_tool.1
--- samba-4.23.7/docs/manpages/dbwrap_tool.1	2026-04-21 13:41:25.273384000 +0200
+++ samba-4.23.8/docs/manpages/dbwrap_tool.1	2026-05-15 15:49:35.762609500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: dbwrap_tool
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "DBWRAP_TOOL" "1" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "DBWRAP_TOOL" "1" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -317,7 +317,7 @@ dbwrap_tool
 Use with caution!
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsmbd\fR(8),
diff -Npur samba-4.23.7/docs/manpages/eventlogadm.8 samba-4.23.8/docs/manpages/eventlogadm.8
--- samba-4.23.7/docs/manpages/eventlogadm.8	2026-04-21 13:41:25.509387000 +0200
+++ samba-4.23.8/docs/manpages/eventlogadm.8	2026-05-15 15:49:35.950272000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: eventlogadm
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "EVENTLOGADM" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "EVENTLOGADM" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -336,7 +336,7 @@ Filter messages from the system log into
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/idmap_ad.8 samba-4.23.8/docs/manpages/idmap_ad.8
--- samba-4.23.7/docs/manpages/idmap_ad.8	2026-04-21 13:41:25.729389400 +0200
+++ samba-4.23.8/docs/manpages/idmap_ad.8	2026-05-15 15:49:36.114789000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: idmap_ad
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "IDMAP_AD" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "IDMAP_AD" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/idmap_autorid.8 samba-4.23.8/docs/manpages/idmap_autorid.8
--- samba-4.23.7/docs/manpages/idmap_autorid.8	2026-04-21 13:41:25.933391800 +0200
+++ samba-4.23.8/docs/manpages/idmap_autorid.8	2026-05-15 15:49:36.267120800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: idmap_autorid
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "IDMAP_AUTORID" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "IDMAP_AUTORID" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/idmap_hash.8 samba-4.23.8/docs/manpages/idmap_hash.8
--- samba-4.23.7/docs/manpages/idmap_hash.8	2026-04-21 13:41:26.133394000 +0200
+++ samba-4.23.8/docs/manpages/idmap_hash.8	2026-05-15 15:49:36.407960000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: idmap_hash
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "IDMAP_HASH" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "IDMAP_HASH" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/idmap_ldap.8 samba-4.23.8/docs/manpages/idmap_ldap.8
--- samba-4.23.7/docs/manpages/idmap_ldap.8	2026-04-21 13:41:26.373396900 +0200
+++ samba-4.23.8/docs/manpages/idmap_ldap.8	2026-05-15 15:49:36.539070400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: idmap_ldap
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "IDMAP_LDAP" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "IDMAP_LDAP" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/idmap_nss.8 samba-4.23.8/docs/manpages/idmap_nss.8
--- samba-4.23.7/docs/manpages/idmap_nss.8	2026-04-21 13:41:26.565399000 +0200
+++ samba-4.23.8/docs/manpages/idmap_nss.8	2026-05-15 15:49:36.660841500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: idmap_nss
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "IDMAP_NSS" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "IDMAP_NSS" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/idmap_rfc2307.8 samba-4.23.8/docs/manpages/idmap_rfc2307.8
--- samba-4.23.7/docs/manpages/idmap_rfc2307.8	2026-04-21 13:41:26.761401200 +0200
+++ samba-4.23.8/docs/manpages/idmap_rfc2307.8	2026-05-15 15:49:36.784428100 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: idmap_rfc2307
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "IDMAP_RFC2307" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "IDMAP_RFC2307" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/idmap_rid.8 samba-4.23.8/docs/manpages/idmap_rid.8
--- samba-4.23.7/docs/manpages/idmap_rid.8	2026-04-21 13:41:26.957403400 +0200
+++ samba-4.23.8/docs/manpages/idmap_rid.8	2026-05-15 15:49:36.906217300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: idmap_rid
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "IDMAP_RID" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "IDMAP_RID" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/idmap_script.8 samba-4.23.8/docs/manpages/idmap_script.8
--- samba-4.23.7/docs/manpages/idmap_script.8	2026-04-21 13:41:27.165406000 +0200
+++ samba-4.23.8/docs/manpages/idmap_script.8	2026-05-15 15:49:37.028187000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: idmap_script
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "IDMAP_SCRIPT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "IDMAP_SCRIPT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/idmap_tdb.8 samba-4.23.8/docs/manpages/idmap_tdb.8
--- samba-4.23.7/docs/manpages/idmap_tdb.8	2026-04-21 13:41:27.369408100 +0200
+++ samba-4.23.8/docs/manpages/idmap_tdb.8	2026-05-15 15:49:37.146401400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: idmap_tdb
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "IDMAP_TDB" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "IDMAP_TDB" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/idmap_tdb2.8 samba-4.23.8/docs/manpages/idmap_tdb2.8
--- samba-4.23.7/docs/manpages/idmap_tdb2.8	2026-04-21 13:41:27.565410400 +0200
+++ samba-4.23.8/docs/manpages/idmap_tdb2.8	2026-05-15 15:49:37.273985000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: idmap_tdb2
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "IDMAP_TDB2" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "IDMAP_TDB2" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/libsmbclient.7 samba-4.23.8/docs/manpages/libsmbclient.7
--- samba-4.23.7/docs/manpages/libsmbclient.7	2026-04-21 13:41:27.773413000 +0200
+++ samba-4.23.8/docs/manpages/libsmbclient.7	2026-05-15 15:49:37.408447700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: libsmbclient
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: 7
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "LIBSMBCLIENT" "7" "04/21/2026" "Samba 4\&.23\&.7" "7"
+.TH "LIBSMBCLIENT" "7" "05/15/2026" "Samba 4\&.23\&.8" "7"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -86,7 +86,7 @@ parameter was not included in the URL\&.
 Watch this space for future updates\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/lmhosts.5 samba-4.23.8/docs/manpages/lmhosts.5
--- samba-4.23.7/docs/manpages/lmhosts.5	2026-04-21 13:41:27.973415100 +0200
+++ samba-4.23.8/docs/manpages/lmhosts.5	2026-05-15 15:49:37.526500700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: lmhosts
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: File Formats and Conventions
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "LMHOSTS" "5" "04/21/2026" "Samba 4\&.23\&.7" "File Formats and Conventions"
+.TH "LMHOSTS" "5" "05/15/2026" "Samba 4\&.23\&.8" "File Formats and Conventions"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -112,7 +112,7 @@ or
 /usr/local/samba/lib\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsmbclient\fR(1),
diff -Npur samba-4.23.7/docs/manpages/log2pcap.1 samba-4.23.8/docs/manpages/log2pcap.1
--- samba-4.23.7/docs/manpages/log2pcap.1	2026-04-21 13:41:28.169417400 +0200
+++ samba-4.23.8/docs/manpages/log2pcap.1	2026-05-15 15:49:37.643227300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: log2pcap
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "LOG2PCAP" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "LOG2PCAP" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -105,7 +105,7 @@ Convert to pcap using text2pcap:
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "BUGS"
 .PP
 Only SMB data is extracted from the samba logs, no LDAP, NetBIOS lookup or other data\&.
diff -Npur samba-4.23.7/docs/manpages/mdsearch.1 samba-4.23.8/docs/manpages/mdsearch.1
--- samba-4.23.7/docs/manpages/mdsearch.1	2026-04-21 13:41:28.393420000 +0200
+++ samba-4.23.8/docs/manpages/mdsearch.1	2026-05-15 15:49:37.769896700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: mdsearch
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "MDSEARCH" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "MDSEARCH" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -343,7 +343,7 @@ File Metadata Search Programming Guide
 https://developer\&.apple\&.com/library/archive/documentation/Carbon/Conceptual/SpotlightQuery/Concepts/Introduction\&.html
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/mvxattr.1 samba-4.23.8/docs/manpages/mvxattr.1
--- samba-4.23.7/docs/manpages/mvxattr.1	2026-04-21 13:41:28.621422500 +0200
+++ samba-4.23.8/docs/manpages/mvxattr.1	2026-05-15 15:49:37.890380400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: mvxattr
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "MVXATTR" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "MVXATTR" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -76,7 +76,7 @@ Force overwriting of destination xattr\&
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/net.8 samba-4.23.8/docs/manpages/net.8
--- samba-4.23.7/docs/manpages/net.8	2026-04-21 13:41:28.977426500 +0200
+++ samba-4.23.8/docs/manpages/net.8	2026-05-15 15:49:38.071389400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: net
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "NET" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "NET" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -3033,7 +3033,7 @@ Produce verbose logging
 Gives usage information for the specified command\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/nmbd.8 samba-4.23.8/docs/manpages/nmbd.8
--- samba-4.23.7/docs/manpages/nmbd.8	2026-04-21 13:41:29.205429300 +0200
+++ samba-4.23.8/docs/manpages/nmbd.8	2026-05-15 15:49:38.198741200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: nmbd
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "NMBD" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "NMBD" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -292,7 +292,7 @@ The debug log level of nmbd may be raise
 (SIGUSR[1|2] signals are no longer used since Samba 2\&.2)\&. This is to allow transient problems to be diagnosed, whilst still running at a normally low log level\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBinetd\fR(8),
diff -Npur samba-4.23.7/docs/manpages/nmblookup.1 samba-4.23.8/docs/manpages/nmblookup.1
--- samba-4.23.7/docs/manpages/nmblookup.1	2026-04-21 13:41:29.425431700 +0200
+++ samba-4.23.8/docs/manpages/nmblookup.1	2026-05-15 15:49:38.335769200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: nmblookup
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "NMBLOOKUP" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "NMBLOOKUP" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -330,7 +330,7 @@ nmblookup \-U samba\&.org \-R \*(AqIRIX#
 would query the WINS server samba\&.org for the domain master browser (1B name type) for the IRIX workgroup\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBnmbd\fR(8),
diff -Npur samba-4.23.7/docs/manpages/ntlm_auth.1 samba-4.23.8/docs/manpages/ntlm_auth.1
--- samba-4.23.7/docs/manpages/ntlm_auth.1	2026-04-21 13:41:29.645434400 +0200
+++ samba-4.23.8/docs/manpages/ntlm_auth.1	2026-05-15 15:49:38.468679000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: ntlm_auth
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "NTLM_AUTH" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "NTLM_AUTH" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -450,7 +450,7 @@ If you\*(Aqre experiencing problems with
 the Microsoft Knowledge Base article #239869 and follow instructions described there\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/pam_winbind.8 samba-4.23.8/docs/manpages/pam_winbind.8
--- samba-4.23.7/docs/manpages/pam_winbind.8	2026-04-21 13:41:29.873437000 +0200
+++ samba-4.23.8/docs/manpages/pam_winbind.8	2026-05-15 15:49:38.588591800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: pam_winbind
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: 8
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "PAM_WINBIND" "8" "04/21/2026" "Samba 4\&.23\&.7" "8"
+.TH "PAM_WINBIND" "8" "05/15/2026" "Samba 4\&.23\&.8" "8"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -209,7 +209,7 @@ This is the profile path set in the prof
 \fBsmb.conf\fR(5)
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of Samba\&.
+This man page is part of version 4\&.23\&.8 of Samba\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/pam_winbind.conf.5 samba-4.23.8/docs/manpages/pam_winbind.conf.5
--- samba-4.23.7/docs/manpages/pam_winbind.conf.5	2026-04-21 13:41:30.081439300 +0200
+++ samba-4.23.8/docs/manpages/pam_winbind.conf.5	2026-05-15 15:49:38.707845700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: pam_winbind.conf
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: 5
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "PAM_WINBIND\&.CONF" "5" "04/21/2026" "Samba 4\&.23\&.7" "5"
+.TH "PAM_WINBIND\&.CONF" "5" "05/15/2026" "Samba 4\&.23\&.8" "5"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -153,7 +153,7 @@ Generate prompt for changing an expired
 \fBsmb.conf\fR(5)
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of Samba\&.
+This man page is part of version 4\&.23\&.8 of Samba\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/pdbedit.8 samba-4.23.8/docs/manpages/pdbedit.8
--- samba-4.23.7/docs/manpages/pdbedit.8	2026-04-21 13:41:30.301441700 +0200
+++ samba-4.23.8/docs/manpages/pdbedit.8	2026-05-15 15:49:38.839001400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: pdbedit
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "PDBEDIT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "PDBEDIT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -635,7 +635,7 @@ Prints the program version number\&.
 This command may be used only by root\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsmbpasswd\fR(5),
diff -Npur samba-4.23.7/docs/manpages/profiles.1 samba-4.23.8/docs/manpages/profiles.1
--- samba-4.23.7/docs/manpages/profiles.1	2026-04-21 13:41:30.509444200 +0200
+++ samba-4.23.8/docs/manpages/profiles.1	2026-05-15 15:49:38.959614500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: profiles
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "PROFILES" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "PROFILES" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -128,7 +128,7 @@ Display brief usage message\&.
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/rpcclient.1 samba-4.23.8/docs/manpages/rpcclient.1
--- samba-4.23.7/docs/manpages/rpcclient.1	2026-04-21 13:41:30.801447400 +0200
+++ samba-4.23.8/docs/manpages/rpcclient.1	2026-05-15 15:49:39.105625400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: rpcclient
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "RPCCLIENT" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "RPCCLIENT" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -1958,7 +1958,7 @@ and
 that are incompatible for some commands or services\&. Additionally, the developers are sending reports to Microsoft, and problems found or reported to Microsoft are fixed in Service Packs, which may result in incompatibilities\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/samba-bgqd.8 samba-4.23.8/docs/manpages/samba-bgqd.8
--- samba-4.23.7/docs/manpages/samba-bgqd.8	2026-04-21 13:41:30.997449600 +0200
+++ samba-4.23.8/docs/manpages/samba-bgqd.8	2026-05-15 15:49:39.221593000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: samba-bgqd
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SAMBA\-BGQD" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "SAMBA\-BGQD" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/samba-dcerpcd.8 samba-4.23.8/docs/manpages/samba-dcerpcd.8
--- samba-4.23.7/docs/manpages/samba-dcerpcd.8	2026-04-21 13:41:31.205452200 +0200
+++ samba-4.23.8/docs/manpages/samba-dcerpcd.8	2026-05-15 15:49:39.354462100 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: samba-dcerpcd
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SAMBA\-DCERPCD" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "SAMBA\-DCERPCD" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/samba-log-parser.1 samba-4.23.8/docs/manpages/samba-log-parser.1
--- samba-4.23.7/docs/manpages/samba-log-parser.1	2026-04-21 13:41:31.409454300 +0200
+++ samba-4.23.8/docs/manpages/samba-log-parser.1	2026-05-15 15:49:39.471872300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: samba-log-parser
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SAMBA\-LOG\-PARSER" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SAMBA\-LOG\-PARSER" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -140,7 +140,7 @@ Sort traces using the timestamp for log
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/samba-regedit.8 samba-4.23.8/docs/manpages/samba-regedit.8
--- samba-4.23.7/docs/manpages/samba-regedit.8	2026-04-21 13:41:31.625456800 +0200
+++ samba-4.23.8/docs/manpages/samba-regedit.8	2026-05-15 15:49:39.596447500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: samba-regedit
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SAMBA\-REGEDIT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "SAMBA\-REGEDIT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -365,7 +365,7 @@ In case you need more fine grained contr
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsmbd\fR(8),
diff -Npur samba-4.23.7/docs/manpages/samba-tool.8 samba-4.23.8/docs/manpages/samba-tool.8
--- samba-4.23.7/docs/manpages/samba-tool.8	2026-04-21 13:41:31.973461000 +0200
+++ samba-4.23.8/docs/manpages/samba-tool.8	2026-05-15 15:49:39.771206600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: samba-tool
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SAMBA\-TOOL" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "SAMBA\-TOOL" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -3174,7 +3174,7 @@ because the repsFrom/To objects are not
 Gives usage information\&.
 .SH "VERSION"
 .PP
-This man page is complete for version 4\&.23\&.7 of the Samba suite\&.
+This man page is complete for version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/samba.7 samba-4.23.8/docs/manpages/samba.7
--- samba-4.23.7/docs/manpages/samba.7	2026-04-21 13:41:32.181463200 +0200
+++ samba-4.23.8/docs/manpages/samba.7	2026-05-15 15:49:39.897388200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: samba
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: Miscellanea
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SAMBA" "7" "04/21/2026" "Samba 4\&.23\&.7" "Miscellanea"
+.TH "SAMBA" "7" "05/15/2026" "Samba 4\&.23\&.8" "Miscellanea"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -231,7 +231,7 @@ https://lists\&.samba\&.org
 you can find a lot of information in the archives and you can subscribe to the samba list and ask for help or discuss things\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "CONTRIBUTIONS"
 .PP
 If you wish to contribute to the Samba project, then I suggest you join the Samba mailing list at
diff -Npur samba-4.23.7/docs/manpages/samba.8 samba-4.23.8/docs/manpages/samba.8
--- samba-4.23.7/docs/manpages/samba.8	2026-04-21 13:41:32.409465800 +0200
+++ samba-4.23.8/docs/manpages/samba.8	2026-05-15 15:49:40.022486700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: samba
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SAMBA" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "SAMBA" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -243,7 +243,7 @@ The number and nature of diagnostics ava
 Most messages are reasonably self\-explanatory\&. Unfortunately, at the time this man page was created, there are too many diagnostics available in the source code to warrant describing each and every diagnostic\&. At this stage your best bet is still to grep the source code and inspect the conditions that gave rise to the diagnostics you are seeing\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBhosts_access\fR(5)
diff -Npur samba-4.23.7/docs/manpages/samba_downgrade_db.8 samba-4.23.8/docs/manpages/samba_downgrade_db.8
--- samba-4.23.7/docs/manpages/samba_downgrade_db.8	2026-04-21 13:41:32.637468600 +0200
+++ samba-4.23.8/docs/manpages/samba_downgrade_db.8	2026-05-15 15:49:40.137722500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: samba_downgrade_db
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SAMBA_DOWNGRADE_DB" "8" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SAMBA_DOWNGRADE_DB" "8" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -42,7 +42,7 @@ The format of the Samba Active Directory
 \fIbefore\fR
 the Samba packages can be safely downgraded\&.
 .PP
-This tool downgrades a Samba sam\&.ldb database from the format used in version 4\&.23\&.7 to that of version 4\&.7\&. The v4\&.7 database format can safely be read by any version of Samba\&. If necessary, later versions of Samba will repack and reconfigure a v4\&.7\-format database when the samba executable is first started\&.
+This tool downgrades a Samba sam\&.ldb database from the format used in version 4\&.23\&.8 to that of version 4\&.7\&. The v4\&.7 database format can safely be read by any version of Samba\&. If necessary, later versions of Samba will repack and reconfigure a v4\&.7\-format database when the samba executable is first started\&.
 .PP
 Note that all Samba services must be stopped on the DC before running this tool\&. Once the tool has run, do not restart samba or modify the database before the Samba software package has been downgraded\&.
 .SH "OPTIONS"
@@ -58,7 +58,7 @@ Link directly to smb\&.conf file instead
 .RE
 .SH "VERSION"
 .PP
-This man page is complete for version 4\&.23\&.7 of the Samba suite\&.
+This man page is complete for version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/sharesec.1 samba-4.23.8/docs/manpages/sharesec.1
--- samba-4.23.7/docs/manpages/sharesec.1	2026-04-21 13:41:32.845471000 +0200
+++ samba-4.23.8/docs/manpages/sharesec.1	2026-05-15 15:49:40.262085000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: sharesec
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SHARESEC" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SHARESEC" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -355,7 +355,7 @@ List all ACEs for
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/smb.conf.5 samba-4.23.8/docs/manpages/smb.conf.5
--- samba-4.23.7/docs/manpages/smb.conf.5	2026-04-21 13:41:34.869494000 +0200
+++ samba-4.23.8/docs/manpages/smb.conf.5	2026-05-15 15:49:41.928356400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smb.conf
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: File Formats and Conventions
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMB\&.CONF" "5" "04/21/2026" "Samba 4\&.23\&.7" "File Formats and Conventions"
+.TH "SMB\&.CONF" "5" "05/15/2026" "Samba 4\&.23\&.8" "File Formats and Conventions"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -2109,7 +2109,7 @@ Note that starting with Samba 4\&.11 the
 .sp -1
 .IP \(bu 2.3
 .\}
-SAMBA_CPS_ACCOUNT_NAME is always present and contains the sAMAccountName of user, the is the same as the %u substitutions in the none AD DC case\&.
+SAMBA_CPS_ACCOUNT_NAME is always present and contains the sAMAccountName of user\&. It is the same as the \*(Aq%u\*(Aq substitutions in the non AD DC case\&.
 .RE
 .sp
 .RS 4
@@ -2135,6 +2135,8 @@ SAMBA_CPS_FULL_NAME is optional if the d
 .RE
 .sp
 .RE
+Even on a non AD DC SAMBA_CPS_ACCOUNT_NAME is the preferred way to access the account name, as it contains the raw value provided by the client\&. If that\*(Aqs not possible you should use single quotes (directly) around %u, e\&.g\&. /path/to/somescript \*(Aq%u\*(Aq, see CVE\-2026\-4408 for more details\&.
+.sp
 Note: In the example directory is a sample program called
 crackcheck
 that uses cracklib to check the password quality\&.
@@ -10590,7 +10592,7 @@ The print command is simply a text strin
 .sp
 %p \- the appropriate printer name
 .sp
-%J \- the job name as transmitted by the client\&.
+%J \- the job name as transmitted by the client, but with dangerous characters being replaced by _\&. You should use single quotes (directly) around %J, e\&.g\&. \*(Aq%J\*(Aq, see CVE\-2026\-4480 for more details\&.
 .sp
 %c \- The number of printed pages of the spooled job (if known)\&.
 .sp
@@ -15793,7 +15795,7 @@ and
 special sections make life for an administrator easy, but the various combinations of default attributes can be tricky\&. Take extreme care when designing these sections\&. In particular, ensure that the permissions on spool directories are correct\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsamba\fR(7),
diff -Npur samba-4.23.7/docs/manpages/smb_prometheus_endpoint.8 samba-4.23.8/docs/manpages/smb_prometheus_endpoint.8
--- samba-4.23.7/docs/manpages/smb_prometheus_endpoint.8	2026-04-21 13:41:35.109496800 +0200
+++ samba-4.23.8/docs/manpages/smb_prometheus_endpoint.8	2026-05-15 15:49:42.063477300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smb_prometheus_endpoint
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMB_PROMETHEUS_ENDPO" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "SMB_PROMETHEUS_ENDPO" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/smbcacls.1 samba-4.23.8/docs/manpages/smbcacls.1
--- samba-4.23.7/docs/manpages/smbcacls.1	2026-04-21 13:41:35.349499500 +0200
+++ samba-4.23.8/docs/manpages/smbcacls.1	2026-05-15 15:49:42.198521400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbcacls
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBCACLS" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SMBCACLS" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -1048,7 +1048,7 @@ smbcacls
 couldn\*(Aqt connect to the specified server, or there was an error getting or setting the ACLs, an exit status of 1 is returned\&. If there was an error parsing any command line arguments, an exit status of 2 is returned\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/smbclient.1 samba-4.23.8/docs/manpages/smbclient.1
--- samba-4.23.7/docs/manpages/smbclient.1	2026-04-21 13:41:35.637502700 +0200
+++ samba-4.23.8/docs/manpages/smbclient.1	2026-05-15 15:49:42.360246200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbclient
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBCLIENT" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SMBCLIENT" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -1247,7 +1247,7 @@ Most diagnostics issued by the client ar
 The number and nature of diagnostics available depends on the debug level used by the client\&. If you have problems, set the debug level to 3 and peruse the log files\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/smbcontrol.1 samba-4.23.8/docs/manpages/smbcontrol.1
--- samba-4.23.7/docs/manpages/smbcontrol.1	2026-04-21 13:41:35.865505500 +0200
+++ samba-4.23.8/docs/manpages/smbcontrol.1	2026-05-15 15:49:42.484631500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbcontrol
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBCONTROL" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SMBCONTROL" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -338,7 +338,7 @@ Instruct the LDAP server of a Samba AD D
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBnmbd\fR(8)
diff -Npur samba-4.23.7/docs/manpages/smbcquotas.1 samba-4.23.8/docs/manpages/smbcquotas.1
--- samba-4.23.7/docs/manpages/smbcquotas.1	2026-04-21 13:41:36.085507900 +0200
+++ samba-4.23.8/docs/manpages/smbcquotas.1	2026-05-15 15:49:42.609932700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbcquotas
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBCQUOTAS" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SMBCQUOTAS" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -431,7 +431,7 @@ smbcquotas
 couldn\*(Aqt connect to the specified server, or when there was an error getting or setting the quota(s), an exit status of 1 is returned\&. If there was an error parsing any command line arguments, an exit status of 2 is returned\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/smbd.8 samba-4.23.8/docs/manpages/smbd.8
--- samba-4.23.7/docs/manpages/smbd.8	2026-04-21 13:41:36.325510500 +0200
+++ samba-4.23.8/docs/manpages/smbd.8	2026-05-15 15:49:42.736621400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbd
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBD" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "SMBD" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -264,7 +264,7 @@ parameter\&. When this is set, the follo
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "DIAGNOSTICS"
 .PP
 Most diagnostics issued by the server are logged in a specified log file\&. The log file name is specified at compile time, but may be overridden on the command line\&.
diff -Npur samba-4.23.7/docs/manpages/smbget.1 samba-4.23.8/docs/manpages/smbget.1
--- samba-4.23.7/docs/manpages/smbget.1	2026-04-21 13:41:36.557513200 +0200
+++ samba-4.23.8/docs/manpages/smbget.1	2026-05-15 15:49:42.867338700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbget
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBGET" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SMBGET" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -481,7 +481,7 @@ smbget \-\-recursive \-resume smb://rhon
 Permission denied is returned in some cases where the cause of the error is unknown (such as an illegally formatted smb:// url or trying to get a directory without \-\-resursive turned on)\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/smbpasswd.5 samba-4.23.8/docs/manpages/smbpasswd.5
--- samba-4.23.7/docs/manpages/smbpasswd.5	2026-04-21 13:41:36.753515500 +0200
+++ samba-4.23.8/docs/manpages/smbpasswd.5	2026-05-15 15:49:42.989852700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbpasswd
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: File Formats and Conventions
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBPASSWD" "5" "04/21/2026" "Samba 4\&.23\&.7" "File Formats and Conventions"
+.TH "SMBPASSWD" "5" "05/15/2026" "Samba 4\&.23\&.8" "File Formats and Conventions"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -165,7 +165,7 @@ This field consists of the time the acco
 All other colon separated fields are ignored at this time\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsmbpasswd\fR(8),
diff -Npur samba-4.23.7/docs/manpages/smbpasswd.8 samba-4.23.8/docs/manpages/smbpasswd.8
--- samba-4.23.7/docs/manpages/smbpasswd.8	2026-04-21 13:41:36.973518000 +0200
+++ samba-4.23.8/docs/manpages/smbpasswd.8	2026-05-15 15:49:43.112565000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbpasswd
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBPASSWD" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "SMBPASSWD" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -314,7 +314,7 @@ file and neglecting to allow "localhost"
 In addition, the smbpasswd command is only useful if Samba has been set up to use encrypted passwords\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsmbpasswd\fR(5),
diff -Npur samba-4.23.7/docs/manpages/smbspool.8 samba-4.23.8/docs/manpages/smbspool.8
--- samba-4.23.7/docs/manpages/smbspool.8	2026-04-21 13:41:37.173520300 +0200
+++ samba-4.23.8/docs/manpages/smbspool.8	2026-05-15 15:49:43.230939600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbspool
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBSPOOL" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "SMBSPOOL" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -173,7 +173,7 @@ The filename argument (argv[6]) contains
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsmbd\fR(8)
diff -Npur samba-4.23.7/docs/manpages/smbspool_krb5_wrapper.8 samba-4.23.8/docs/manpages/smbspool_krb5_wrapper.8
--- samba-4.23.7/docs/manpages/smbspool_krb5_wrapper.8	2026-04-21 13:41:37.393522700 +0200
+++ samba-4.23.8/docs/manpages/smbspool_krb5_wrapper.8	2026-05-15 15:49:43.361329300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbspool_krb5_wrapper
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBSPOOL_KRB5_WRAPPE" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "SMBSPOOL_KRB5_WRAPPE" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/smbstatus.1 samba-4.23.8/docs/manpages/smbstatus.1
--- samba-4.23.7/docs/manpages/smbstatus.1	2026-04-21 13:41:37.629525400 +0200
+++ samba-4.23.8/docs/manpages/smbstatus.1	2026-05-15 15:49:43.486642100 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbstatus
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBSTATUS" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SMBSTATUS" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -477,7 +477,7 @@ Prints the program version number\&.
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsmbd\fR(8)
diff -Npur samba-4.23.7/docs/manpages/smbtar.1 samba-4.23.8/docs/manpages/smbtar.1
--- samba-4.23.7/docs/manpages/smbtar.1	2026-04-21 13:41:37.837528000 +0200
+++ samba-4.23.8/docs/manpages/smbtar.1	2026-05-15 15:49:43.609205200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbtar
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBTAR" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SMBTAR" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -145,7 +145,7 @@ section for the
 command\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsmbd\fR(8),
diff -Npur samba-4.23.7/docs/manpages/smbtree.1 samba-4.23.8/docs/manpages/smbtree.1
--- samba-4.23.7/docs/manpages/smbtree.1	2026-04-21 13:41:38.053530500 +0200
+++ samba-4.23.8/docs/manpages/smbtree.1	2026-05-15 15:49:43.732335600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: smbtree
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "SMBTREE" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "SMBTREE" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -244,7 +244,7 @@ In case you need more fine grained contr
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/testparm.1 samba-4.23.8/docs/manpages/testparm.1
--- samba-4.23.7/docs/manpages/testparm.1	2026-04-21 13:41:38.261532800 +0200
+++ samba-4.23.8/docs/manpages/testparm.1	2026-05-15 15:49:43.858874000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: testparm
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "TESTPARM" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "TESTPARM" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -184,7 +184,7 @@ The program will issue a message saying
 For certain use cases, SMB protocol requires use of cryptographic algorithms which are known to be weak and already broken\&. DES and ARCFOUR (RC4) ciphers and the SHA1 and MD5 hash algorithms are considered weak but they are required for backward compatibility\&. The testparm utility shows whether the Samba tools will fall back to these weak crypto algorithms if it is not possible to use strong cryptography by default\&. In FIPS mode weak crypto cannot be enabled\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBsmb.conf\fR(5),
diff -Npur samba-4.23.7/docs/manpages/traffic_learner.7 samba-4.23.8/docs/manpages/traffic_learner.7
--- samba-4.23.7/docs/manpages/traffic_learner.7	2026-04-21 13:41:38.457535000 +0200
+++ samba-4.23.8/docs/manpages/traffic_learner.7	2026-05-15 15:49:43.983054600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: traffic_learner
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "TRAFFIC_LEARNER" "7" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "TRAFFIC_LEARNER" "7" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -114,7 +114,7 @@ There are two special packet types here\
 The other special packet is "\-", which represents the limit of the conversation\&. In the example, this indicates that one observed conversation ended after this particular ngram\&. This special opcode is also used at the beginning of conversations, which are indicated by the ngram "\-\et\-"\&.
 .SH "VERSION"
 .PP
-This man page is complete for version 4\&.23\&.7 of the Samba suite\&.
+This man page is complete for version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBtraffic_replay\fR(7)\&.
diff -Npur samba-4.23.7/docs/manpages/traffic_replay.7 samba-4.23.8/docs/manpages/traffic_replay.7
--- samba-4.23.7/docs/manpages/traffic_replay.7	2026-04-21 13:41:38.673537500 +0200
+++ samba-4.23.8/docs/manpages/traffic_replay.7	2026-05-15 15:49:44.111794200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: traffic_replay
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "TRAFFIC_REPLAY" "7" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "TRAFFIC_REPLAY" "7" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -367,7 +367,7 @@ traffic_replay traffic\-model\&.txt my\-
 The users created by the test will have names like STGU\-0\-xyz\&. The groups generated have names like STGG\-0\-xyz\&.
 .SH "VERSION"
 .PP
-This man page is complete for version 4\&.23\&.7 of the Samba suite\&.
+This man page is complete for version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBtraffic_learner\fR(7)\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_acl_tdb.8 samba-4.23.8/docs/manpages/vfs_acl_tdb.8
--- samba-4.23.7/docs/manpages/vfs_acl_tdb.8	2026-04-21 13:41:38.897539900 +0200
+++ samba-4.23.8/docs/manpages/vfs_acl_tdb.8	2026-05-15 15:49:44.232423500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_acl_tdb
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_ACL_TDB" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_ACL_TDB" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/vfs_acl_xattr.8 samba-4.23.8/docs/manpages/vfs_acl_xattr.8
--- samba-4.23.7/docs/manpages/vfs_acl_xattr.8	2026-04-21 13:41:39.133542800 +0200
+++ samba-4.23.8/docs/manpages/vfs_acl_xattr.8	2026-05-15 15:49:44.368745000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_acl_xattr
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_ACL_XATTR" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_ACL_XATTR" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/vfs_aio_fork.8 samba-4.23.8/docs/manpages/vfs_aio_fork.8
--- samba-4.23.7/docs/manpages/vfs_aio_fork.8	2026-04-21 13:41:39.329544800 +0200
+++ samba-4.23.8/docs/manpages/vfs_aio_fork.8	2026-05-15 15:49:44.488278600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_aio_fork
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_AIO_FORK" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_AIO_FORK" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -62,7 +62,7 @@ Straight forward use:
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_aio_pthread.8 samba-4.23.8/docs/manpages/vfs_aio_pthread.8
--- samba-4.23.7/docs/manpages/vfs_aio_pthread.8	2026-04-21 13:41:39.553547400 +0200
+++ samba-4.23.8/docs/manpages/vfs_aio_pthread.8	2026-05-15 15:49:44.610008500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_aio_pthread
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_AIO_PTHREAD" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_AIO_PTHREAD" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -75,7 +75,7 @@ The default is \*(Aqno\*(Aq\&.
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_audit.8 samba-4.23.8/docs/manpages/vfs_audit.8
--- samba-4.23.7/docs/manpages/vfs_audit.8	2026-04-21 13:41:39.749549600 +0200
+++ samba-4.23.8/docs/manpages/vfs_audit.8	2026-05-15 15:49:44.728873500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_audit
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_AUDIT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_AUDIT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -112,7 +112,7 @@ Log operations on all shares using the L
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_btrfs.8 samba-4.23.8/docs/manpages/vfs_btrfs.8
--- samba-4.23.7/docs/manpages/vfs_btrfs.8	2026-04-21 13:41:39.945551900 +0200
+++ samba-4.23.8/docs/manpages/vfs_btrfs.8	2026-05-15 15:49:44.849185700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_btrfs
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_BTRFS" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_BTRFS" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -101,7 +101,7 @@ to Windows Explorer as file / directory
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_cacheprime.8 samba-4.23.8/docs/manpages/vfs_cacheprime.8
--- samba-4.23.7/docs/manpages/vfs_cacheprime.8	2026-04-21 13:41:40.141554000 +0200
+++ samba-4.23.8/docs/manpages/vfs_cacheprime.8	2026-05-15 15:49:44.968399300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_cacheprime
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_CACHEPRIME" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_CACHEPRIME" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -115,7 +115,7 @@ cacheprime
 is not a substitute for a general\-purpose readahead mechanism\&. It is intended for use only in very specific environments where disk operations must be aligned and sized to known values (as much as that is possible)\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_cap.8 samba-4.23.8/docs/manpages/vfs_cap.8
--- samba-4.23.7/docs/manpages/vfs_cap.8	2026-04-21 13:41:40.337556400 +0200
+++ samba-4.23.8/docs/manpages/vfs_cap.8	2026-05-15 15:49:45.085305500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_cap
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_CAP" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_CAP" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -63,7 +63,7 @@ On a system using GNU libiconv, use CAP
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_catia.8 samba-4.23.8/docs/manpages/vfs_catia.8
--- samba-4.23.7/docs/manpages/vfs_catia.8	2026-04-21 13:41:40.549558900 +0200
+++ samba-4.23.8/docs/manpages/vfs_catia.8	2026-05-15 15:49:45.204081800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_catia
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_CATIA" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_CATIA" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/vfs_ceph.8 samba-4.23.8/docs/manpages/vfs_ceph.8
--- samba-4.23.7/docs/manpages/vfs_ceph.8	2026-04-21 13:41:40.753561000 +0200
+++ samba-4.23.8/docs/manpages/vfs_ceph.8	2026-05-15 15:49:45.335275000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_ceph
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_CEPH" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_CEPH" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -114,7 +114,7 @@ Example: ceph:filesystem = myfs2
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_ceph_new.8 samba-4.23.8/docs/manpages/vfs_ceph_new.8
--- samba-4.23.7/docs/manpages/vfs_ceph_new.8	2026-04-21 13:41:40.953563500 +0200
+++ samba-4.23.8/docs/manpages/vfs_ceph_new.8	2026-05-15 15:49:45.460757500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_ceph_new
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_CEPH_NEW" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_CEPH_NEW" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -167,7 +167,7 @@ daemon\&.
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_ceph_snapshots.8 samba-4.23.8/docs/manpages/vfs_ceph_snapshots.8
--- samba-4.23.7/docs/manpages/vfs_ceph_snapshots.8	2026-04-21 13:41:41.157565800 +0200
+++ samba-4.23.8/docs/manpages/vfs_ceph_snapshots.8	2026-05-15 15:49:45.581288600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_ceph_snapshots
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_CEPH_SNAPSHOTS" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_CEPH_SNAPSHOTS" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -105,7 +105,7 @@ Example:
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_commit.8 samba-4.23.8/docs/manpages/vfs_commit.8
--- samba-4.23.7/docs/manpages/vfs_commit.8	2026-04-21 13:41:41.353568000 +0200
+++ samba-4.23.8/docs/manpages/vfs_commit.8	2026-05-15 15:49:45.697936800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_commit
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_COMMIT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_COMMIT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -116,7 +116,7 @@ commit
 may reduce performance\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_crossrename.8 samba-4.23.8/docs/manpages/vfs_crossrename.8
--- samba-4.23.7/docs/manpages/vfs_crossrename.8	2026-04-21 13:41:41.581570600 +0200
+++ samba-4.23.8/docs/manpages/vfs_crossrename.8	2026-05-15 15:49:45.812714000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_crossrename
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_CROSSRENAME" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_CROSSRENAME" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -91,7 +91,7 @@ To add server\-side cross\-device rename
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_default_quota.8 samba-4.23.8/docs/manpages/vfs_default_quota.8
--- samba-4.23.7/docs/manpages/vfs_default_quota.8	2026-04-21 13:41:41.781572800 +0200
+++ samba-4.23.8/docs/manpages/vfs_default_quota.8	2026-05-15 15:49:45.937823300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_default_quota
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_DEFAULT_QUOTA" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_DEFAULT_QUOTA" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -86,7 +86,7 @@ Store the default quota record in the qu
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_dirsort.8 samba-4.23.8/docs/manpages/vfs_dirsort.8
--- samba-4.23.7/docs/manpages/vfs_dirsort.8	2026-04-21 13:41:41.977575000 +0200
+++ samba-4.23.8/docs/manpages/vfs_dirsort.8	2026-05-15 15:49:46.056457300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_dirsort
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_DIRSORT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_DIRSORT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -59,7 +59,7 @@ Sort directories for all shares:
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_expand_msdfs.8 samba-4.23.8/docs/manpages/vfs_expand_msdfs.8
--- samba-4.23.7/docs/manpages/vfs_expand_msdfs.8	2026-04-21 13:41:42.209577800 +0200
+++ samba-4.23.8/docs/manpages/vfs_expand_msdfs.8	2026-05-15 15:49:46.172416200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_expand_msdfs
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_EXPAND_MSDFS" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_EXPAND_MSDFS" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -55,7 +55,7 @@ With this module, the link target is not
 With this, clients from network 192\&.168\&.234/24 are redirected to host local\&.samba\&.org, clients from 192\&.168/16 are redirected to remote\&.samba\&.org and all other clients go to default\&.samba\&.org\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_extd_audit.8 samba-4.23.8/docs/manpages/vfs_extd_audit.8
--- samba-4.23.7/docs/manpages/vfs_extd_audit.8	2026-04-21 13:41:42.413580200 +0200
+++ samba-4.23.8/docs/manpages/vfs_extd_audit.8	2026-05-15 15:49:46.290426000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_extd_audit
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_EXTD_AUDIT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_EXTD_AUDIT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -55,7 +55,7 @@ is identical to
 This module is stackable\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_fake_perms.8 samba-4.23.8/docs/manpages/vfs_fake_perms.8
--- samba-4.23.7/docs/manpages/vfs_fake_perms.8	2026-04-21 13:41:42.613582400 +0200
+++ samba-4.23.8/docs/manpages/vfs_fake_perms.8	2026-05-15 15:49:46.421083200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_fake_perms
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_FAKE_PERMS" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_FAKE_PERMS" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -58,7 +58,7 @@ This module is stackable\&.
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_fileid.8 samba-4.23.8/docs/manpages/vfs_fileid.8
--- samba-4.23.7/docs/manpages/vfs_fileid.8	2026-04-21 13:41:42.821584700 +0200
+++ samba-4.23.8/docs/manpages/vfs_fileid.8	2026-05-15 15:49:46.543977500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_fileid
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_FILEID" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_FILEID" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -212,7 +212,7 @@ module in order avoid load on heavily co
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_fruit.8 samba-4.23.8/docs/manpages/vfs_fruit.8
--- samba-4.23.7/docs/manpages/vfs_fruit.8	2026-04-21 13:41:43.057587400 +0200
+++ samba-4.23.8/docs/manpages/vfs_fruit.8	2026-05-15 15:49:46.666627400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_fruit
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_FRUIT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_FRUIT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/vfs_full_audit.8 samba-4.23.8/docs/manpages/vfs_full_audit.8
--- samba-4.23.7/docs/manpages/vfs_full_audit.8	2026-04-21 13:41:43.261589800 +0200
+++ samba-4.23.8/docs/manpages/vfs_full_audit.8	2026-05-15 15:49:46.788097400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_full_audit
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_FULL_AUDIT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_FULL_AUDIT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -500,7 +500,7 @@ Log file and directory open operations o
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_glusterfs.8 samba-4.23.8/docs/manpages/vfs_glusterfs.8
--- samba-4.23.7/docs/manpages/vfs_glusterfs.8	2026-04-21 13:41:43.489592300 +0200
+++ samba-4.23.8/docs/manpages/vfs_glusterfs.8	2026-05-15 15:49:46.908798200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_glusterfs
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_GLUSTERFS" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_GLUSTERFS" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -127,7 +127,7 @@ on the commandline\&.
 With GlusterFS versions >= 9, we silently bypass write\-behind translator during initial connect and failure is avoided\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_glusterfs_fuse.8 samba-4.23.8/docs/manpages/vfs_glusterfs_fuse.8
--- samba-4.23.7/docs/manpages/vfs_glusterfs_fuse.8	2026-04-21 13:41:43.697594600 +0200
+++ samba-4.23.8/docs/manpages/vfs_glusterfs_fuse.8	2026-05-15 15:49:47.027351600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_glusterfs_fuse
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_GLUSTERFS_FUSE" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_GLUSTERFS_FUSE" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -77,7 +77,7 @@ module\&.
 This module does currently have no further options\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_gpfs.8 samba-4.23.8/docs/manpages/vfs_gpfs.8
--- samba-4.23.7/docs/manpages/vfs_gpfs.8	2026-04-21 13:41:43.905597000 +0200
+++ samba-4.23.8/docs/manpages/vfs_gpfs.8	2026-05-15 15:49:47.151188100 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_gpfs
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_GPFS" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_GPFS" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -656,7 +656,7 @@ gpfs\&.h
 in gpfs versions newer than 3\&.2\&.1 PTF8\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_io_uring.8 samba-4.23.8/docs/manpages/vfs_io_uring.8
--- samba-4.23.7/docs/manpages/vfs_io_uring.8	2026-04-21 13:41:44.097599300 +0200
+++ samba-4.23.8/docs/manpages/vfs_io_uring.8	2026-05-15 15:49:47.271067100 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_io_uring
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_IO_URING" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_IO_URING" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -78,7 +78,7 @@ The default is \*(Aqno\*(Aq\&.
 \fBio_uring_setup\fR(2)\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_linux_xfs_sgid.8 samba-4.23.8/docs/manpages/vfs_linux_xfs_sgid.8
--- samba-4.23.7/docs/manpages/vfs_linux_xfs_sgid.8	2026-04-21 13:41:44.297601500 +0200
+++ samba-4.23.8/docs/manpages/vfs_linux_xfs_sgid.8	2026-05-15 15:49:47.402300600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_linux_xfs_sgid
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_LINUX_XFS_SGID" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_LINUX_XFS_SGID" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -64,7 +64,7 @@ Add linux_xfs_sgid functionality for [sh
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_media_harmony.8 samba-4.23.8/docs/manpages/vfs_media_harmony.8
--- samba-4.23.7/docs/manpages/vfs_media_harmony.8	2026-04-21 13:41:44.497604000 +0200
+++ samba-4.23.8/docs/manpages/vfs_media_harmony.8	2026-05-15 15:49:47.521163500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_media_harmony
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_MEDIA_HARMONY" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_MEDIA_HARMONY" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -138,7 +138,7 @@ vfs_media_harmony
 is designed to work with Avid editing applications that look in the Avid MediaFiles or OMFI MediaFiles directories for media\&. It is not designed to work as expected in all circumstances for general use\&. For example: It is possible to open a client\-specific file such as msmMMOB\&.mdb_192\&.168\&.1\&.10_userx even though it doesn\*(Aqt show up in a directory listing\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_nfs4acl_xattr.8 samba-4.23.8/docs/manpages/vfs_nfs4acl_xattr.8
--- samba-4.23.7/docs/manpages/vfs_nfs4acl_xattr.8	2026-04-21 13:41:44.701606000 +0200
+++ samba-4.23.8/docs/manpages/vfs_nfs4acl_xattr.8	2026-05-15 15:49:47.642784400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_nfs4acl_xattr
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_NFS4ACL_XATTR" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_NFS4ACL_XATTR" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/vfs_offline.8 samba-4.23.8/docs/manpages/vfs_offline.8
--- samba-4.23.7/docs/manpages/vfs_offline.8	2026-04-21 13:41:44.897608300 +0200
+++ samba-4.23.8/docs/manpages/vfs_offline.8	2026-05-15 15:49:47.758940200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_offline
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_OFFLINE" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_OFFLINE" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -59,7 +59,7 @@ Mark all files in a share as offline:
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_prealloc.8 samba-4.23.8/docs/manpages/vfs_prealloc.8
--- samba-4.23.7/docs/manpages/vfs_prealloc.8	2026-04-21 13:41:45.097610700 +0200
+++ samba-4.23.8/docs/manpages/vfs_prealloc.8	2026-05-15 15:49:47.880632900 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_prealloc
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_PREALLOC" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_PREALLOC" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -112,7 +112,7 @@ vfs_prealloc
 is not supported on all platforms and filesystems\&. Currently only XFS filesystems on Linux and IRIX are supported\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_preopen.8 samba-4.23.8/docs/manpages/vfs_preopen.8
--- samba-4.23.7/docs/manpages/vfs_preopen.8	2026-04-21 13:41:45.309613000 +0200
+++ samba-4.23.8/docs/manpages/vfs_preopen.8	2026-05-15 15:49:48.005808800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_preopen
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_PREOPEN" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_PREOPEN" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -147,7 +147,7 @@ in the \*(Aq\m[blue]\fBlog level\fR\m[]\
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_readahead.8 samba-4.23.8/docs/manpages/vfs_readahead.8
--- samba-4.23.7/docs/manpages/vfs_readahead.8	2026-04-21 13:41:45.509615400 +0200
+++ samba-4.23.8/docs/manpages/vfs_readahead.8	2026-05-15 15:49:48.129541200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_readahead
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_READAHEAD" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_READAHEAD" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -115,7 +115,7 @@ G
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_readonly.8 samba-4.23.8/docs/manpages/vfs_readonly.8
--- samba-4.23.7/docs/manpages/vfs_readonly.8	2026-04-21 13:41:45.705617700 +0200
+++ samba-4.23.8/docs/manpages/vfs_readonly.8	2026-05-15 15:49:48.245736800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_readonly
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_READONLY" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_READONLY" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -81,7 +81,7 @@ Mark the [backup] share as read only dur
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_recycle.8 samba-4.23.8/docs/manpages/vfs_recycle.8
--- samba-4.23.7/docs/manpages/vfs_recycle.8	2026-04-21 13:41:45.917620000 +0200
+++ samba-4.23.8/docs/manpages/vfs_recycle.8	2026-05-15 15:49:48.379446700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_recycle
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_RECYCLE" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_RECYCLE" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -136,7 +136,7 @@ instead of deleting them:
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_shadow_copy.8 samba-4.23.8/docs/manpages/vfs_shadow_copy.8
--- samba-4.23.7/docs/manpages/vfs_shadow_copy.8	2026-04-21 13:41:46.109622200 +0200
+++ samba-4.23.8/docs/manpages/vfs_shadow_copy.8	2026-05-15 15:49:48.502872000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_shadow_copy
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_SHADOW_COPY" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_SHADOW_COPY" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -166,7 +166,7 @@ vfs_shadow_copy
 is designed to be an end\-user tool only\&. It does not replace or enhance your backup and archival solutions and should in no way be considered as such\&. Additionally, if you need version control, implement a version control system\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_shadow_copy2.8 samba-4.23.8/docs/manpages/vfs_shadow_copy2.8
--- samba-4.23.7/docs/manpages/vfs_shadow_copy2.8	2026-04-21 13:41:46.325624700 +0200
+++ samba-4.23.8/docs/manpages/vfs_shadow_copy2.8	2026-05-15 15:49:48.630761400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_shadow_copy2
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_SHADOW_COPY2" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_SHADOW_COPY2" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -518,7 +518,7 @@ vfs_shadow_copy2
 is designed to be an end\-user tool only\&. It does not replace or enhance your backup and archival solutions and should in no way be considered as such\&. Additionally, if you need version control, implement a version control system\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_shell_snap.8 samba-4.23.8/docs/manpages/vfs_shell_snap.8
--- samba-4.23.7/docs/manpages/vfs_shell_snap.8	2026-04-21 13:41:46.533627000 +0200
+++ samba-4.23.8/docs/manpages/vfs_shell_snap.8	2026-05-15 15:49:48.750780800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_shell_snap
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_SHELL_SNAP" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_SHELL_SNAP" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -212,7 +212,7 @@ Samba\*(Aqs FSRVP server must be configu
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_snapper.8 samba-4.23.8/docs/manpages/vfs_snapper.8
--- samba-4.23.7/docs/manpages/vfs_snapper.8	2026-04-21 13:41:46.733629200 +0200
+++ samba-4.23.8/docs/manpages/vfs_snapper.8	2026-05-15 15:49:48.873095000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_snapper
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_SNAPPER" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_SNAPPER" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -82,7 +82,7 @@ Remote snapshot creation and deletion is
 The DiskShadow\&.exe FSRVP client initially authenticates as the Active Directory computer account\&. This account must therefore be granted the same permissions as the user account issuing the snapshot creation and deletion requests\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_streams_depot.8 samba-4.23.8/docs/manpages/vfs_streams_depot.8
--- samba-4.23.7/docs/manpages/vfs_streams_depot.8	2026-04-21 13:41:46.949631700 +0200
+++ samba-4.23.8/docs/manpages/vfs_streams_depot.8	2026-05-15 15:49:48.996709800 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_streams_depot
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_STREAMS_DEPOT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_STREAMS_DEPOT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/vfs_streams_xattr.8 samba-4.23.8/docs/manpages/vfs_streams_xattr.8
--- samba-4.23.7/docs/manpages/vfs_streams_xattr.8	2026-04-21 13:41:47.141634000 +0200
+++ samba-4.23.8/docs/manpages/vfs_streams_xattr.8	2026-05-15 15:49:49.116508500 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_streams_xattr
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_STREAMS_XATTR" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_STREAMS_XATTR" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/vfs_syncops.8 samba-4.23.8/docs/manpages/vfs_syncops.8
--- samba-4.23.7/docs/manpages/vfs_syncops.8	2026-04-21 13:41:47.337636200 +0200
+++ samba-4.23.8/docs/manpages/vfs_syncops.8	2026-05-15 15:49:49.237703600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_syncops
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_SYNCOPS" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_SYNCOPS" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -76,7 +76,7 @@ Add syncops functionality for [share]:
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_time_audit.8 samba-4.23.8/docs/manpages/vfs_time_audit.8
--- samba-4.23.7/docs/manpages/vfs_time_audit.8	2026-04-21 13:41:47.541638400 +0200
+++ samba-4.23.8/docs/manpages/vfs_time_audit.8	2026-05-15 15:49:49.368860200 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_time_audit
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_TIME_AUDIT" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_TIME_AUDIT" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -72,7 +72,7 @@ This would log VFS calls that take longe
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_tsmsm.8 samba-4.23.8/docs/manpages/vfs_tsmsm.8
--- samba-4.23.7/docs/manpages/vfs_tsmsm.8	2026-04-21 13:41:47.741640800 +0200
+++ samba-4.23.8/docs/manpages/vfs_tsmsm.8	2026-05-15 15:49:49.487648700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_tsmsm
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_TSMSM" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_TSMSM" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -83,7 +83,7 @@ A GPFS mount with TSM support can be exp
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_unityed_media.8 samba-4.23.8/docs/manpages/vfs_unityed_media.8
--- samba-4.23.7/docs/manpages/vfs_unityed_media.8	2026-04-21 13:41:47.937643000 +0200
+++ samba-4.23.8/docs/manpages/vfs_unityed_media.8	2026-05-15 15:49:49.606819600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_unityed_media
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_UNITYED_MEDIA" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_UNITYED_MEDIA" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -111,7 +111,7 @@ Enable unityed_media for Mac and Windows
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_virusfilter.8 samba-4.23.8/docs/manpages/vfs_virusfilter.8
--- samba-4.23.7/docs/manpages/vfs_virusfilter.8	2026-04-21 13:41:48.145645400 +0200
+++ samba-4.23.8/docs/manpages/vfs_virusfilter.8	2026-05-15 15:49:49.731342600 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_virusfilter
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
 .\"    Source: Samba 4.8
 .\"  Language: English
 .\"
-.TH "VFS_VIRUSFILTER" "8" "04/21/2026" "Samba 4\&.8" "System Administration tools"
+.TH "VFS_VIRUSFILTER" "8" "05/15/2026" "Samba 4\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/vfs_widelinks.8 samba-4.23.8/docs/manpages/vfs_widelinks.8
--- samba-4.23.7/docs/manpages/vfs_widelinks.8	2026-04-21 13:41:48.341647600 +0200
+++ samba-4.23.8/docs/manpages/vfs_widelinks.8	2026-05-15 15:49:49.852545700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_widelinks
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_WIDELINKS" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_WIDELINKS" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -53,7 +53,7 @@ This module is stackable\&.
 No examples listed\&. This module is implicitly loaded by smbd as needed\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_worm.8 samba-4.23.8/docs/manpages/vfs_worm.8
--- samba-4.23.7/docs/manpages/vfs_worm.8	2026-04-21 13:41:48.537649900 +0200
+++ samba-4.23.8/docs/manpages/vfs_worm.8	2026-05-15 15:49:49.977016400 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_worm
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_WORM" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_WORM" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -68,7 +68,7 @@ Deny the write access to files and folde
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfs_xattr_tdb.8 samba-4.23.8/docs/manpages/vfs_xattr_tdb.8
--- samba-4.23.7/docs/manpages/vfs_xattr_tdb.8	2026-04-21 13:41:48.733652000 +0200
+++ samba-4.23.8/docs/manpages/vfs_xattr_tdb.8	2026-05-15 15:49:50.094183700 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_xattr_tdb
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_XATTR_TDB" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_XATTR_TDB" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff -Npur samba-4.23.7/docs/manpages/vfs_zfsacl.8 samba-4.23.8/docs/manpages/vfs_zfsacl.8
--- samba-4.23.7/docs/manpages/vfs_zfsacl.8	2026-04-21 13:41:48.953654500 +0200
+++ samba-4.23.8/docs/manpages/vfs_zfsacl.8	2026-05-15 15:49:50.218836000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfs_zfsacl
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFS_ZFSACL" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "VFS_ZFSACL" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -310,7 +310,7 @@ A ZFS mount can be exported via Samba as
 .\}
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/vfstest.1 samba-4.23.8/docs/manpages/vfstest.1
--- samba-4.23.7/docs/manpages/vfstest.1	2026-04-21 13:41:49.169657000 +0200
+++ samba-4.23.8/docs/manpages/vfstest.1	2026-05-15 15:49:50.360857000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: vfstest
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "VFSTEST" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "VFSTEST" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -797,7 +797,7 @@ exit
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/wbinfo.1 samba-4.23.8/docs/manpages/wbinfo.1
--- samba-4.23.7/docs/manpages/wbinfo.1	2026-04-21 13:41:49.393659600 +0200
+++ samba-4.23.8/docs/manpages/wbinfo.1	2026-05-15 15:49:50.490900300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: wbinfo
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "WBINFO" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "WBINFO" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -472,7 +472,7 @@ wbinfo
 will always return failure\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 \fBwinbindd\fR(8)
diff -Npur samba-4.23.7/docs/manpages/winbind_krb5_localauth.8 samba-4.23.8/docs/manpages/winbind_krb5_localauth.8
--- samba-4.23.7/docs/manpages/winbind_krb5_localauth.8	2026-04-21 13:41:49.589661800 +0200
+++ samba-4.23.8/docs/manpages/winbind_krb5_localauth.8	2026-05-15 15:49:50.612445000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: winbind_krb5_localauth
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: 8
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "WINBIND_KRB5_LOCALAU" "8" "04/21/2026" "Samba 4\&.23\&.7" "8"
+.TH "WINBIND_KRB5_LOCALAU" "8" "05/15/2026" "Samba 4\&.23\&.8" "8"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -65,7 +65,7 @@ file\&.
 .sp
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/winbind_krb5_locator.8 samba-4.23.8/docs/manpages/winbind_krb5_locator.8
--- samba-4.23.7/docs/manpages/winbind_krb5_locator.8	2026-04-21 13:41:49.785664000 +0200
+++ samba-4.23.8/docs/manpages/winbind_krb5_locator.8	2026-05-15 15:49:50.730356000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: winbind_krb5_locator
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: 8
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "WINBIND_KRB5_LOCATOR" "8" "04/21/2026" "Samba 4\&.23\&.7" "8"
+.TH "WINBIND_KRB5_LOCATOR" "8" "05/15/2026" "Samba 4\&.23\&.8" "8"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -57,7 +57,7 @@ After copying the locator plugin to the
 /etc/krb5\&.conf\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/winbindd.8 samba-4.23.8/docs/manpages/winbindd.8
--- samba-4.23.7/docs/manpages/winbindd.8	2026-04-21 13:41:50.021666800 +0200
+++ samba-4.23.8/docs/manpages/winbindd.8	2026-05-15 15:49:50.866327300 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: winbindd
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: System Administration tools
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "WINBINDD" "8" "04/21/2026" "Samba 4\&.23\&.7" "System Administration tools"
+.TH "WINBINDD" "8" "05/15/2026" "Samba 4\&.23\&.8" "System Administration tools"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -591,7 +591,7 @@ Storage for cached user and group inform
 .RE
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "SEE ALSO"
 .PP
 nsswitch\&.conf(5),
diff -Npur samba-4.23.7/docs/manpages/winexe.1 samba-4.23.8/docs/manpages/winexe.1
--- samba-4.23.7/docs/manpages/winexe.1	2026-04-21 13:41:50.245669400 +0200
+++ samba-4.23.8/docs/manpages/winexe.1	2026-05-15 15:49:51.000316100 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: winexe
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "WINEXE" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "WINEXE" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -464,7 +464,7 @@ Display brief usage message\&.
 The winexe program returns 0 if the operation succeeded, or 1 if the operation failed\&.
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs/manpages/wspsearch.1 samba-4.23.8/docs/manpages/wspsearch.1
--- samba-4.23.7/docs/manpages/wspsearch.1	2026-04-21 13:41:50.457671600 +0200
+++ samba-4.23.8/docs/manpages/wspsearch.1	2026-05-15 15:49:51.125295000 +0200
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: wspsearch
 .\"    Author: [see the "AUTHOR" section]
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 04/21/2026
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 05/15/2026
 .\"    Manual: User Commands
-.\"    Source: Samba 4.23.7
+.\"    Source: Samba 4.23.8
 .\"  Language: English
 .\"
-.TH "WSPSEARCH" "1" "04/21/2026" "Samba 4\&.23\&.7" "User Commands"
+.TH "WSPSEARCH" "1" "05/15/2026" "Samba 4\&.23\&.8" "User Commands"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -530,7 +530,7 @@ Adanced Query Syntax
 https://learn\&.microsoft\&.com/en\-gb/windows/win32/search/\-search\-3x\-advancedquerysyntax
 .SH "VERSION"
 .PP
-This man page is part of version 4\&.23\&.7 of the Samba suite\&.
+This man page is part of version 4\&.23\&.8 of the Samba suite\&.
 .SH "AUTHOR"
 .PP
 The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Npur samba-4.23.7/docs-xml/smbdotconf/printing/printcommand.xml samba-4.23.8/docs-xml/smbdotconf/printing/printcommand.xml
--- samba-4.23.7/docs-xml/smbdotconf/printing/printcommand.xml	2026-01-23 11:53:40.669125000 +0100
+++ samba-4.23.8/docs-xml/smbdotconf/printing/printcommand.xml	2026-05-15 15:49:15.086977500 +0200
@@ -21,8 +21,11 @@
     <para>%p - the appropriate printer 
     name</para>
 
-    <para>%J - the job 
-    name as transmitted by the client.</para>
+    <para>%J - the job name as transmitted by the client,
+    but with dangerous characters being replaced by _.
+    You should use single quotes (directly) around %J, e.g. '%J',
+    see CVE-2026-4480 for more details.
+    </para>
 
     <para>%c - The number of printed pages
     of the spooled job (if known).</para>
diff -Npur samba-4.23.7/docs-xml/smbdotconf/security/checkpasswordscript.xml samba-4.23.8/docs-xml/smbdotconf/security/checkpasswordscript.xml
--- samba-4.23.7/docs-xml/smbdotconf/security/checkpasswordscript.xml	2026-01-23 11:53:40.673126000 +0100
+++ samba-4.23.8/docs-xml/smbdotconf/security/checkpasswordscript.xml	2026-05-15 15:49:15.086977500 +0200
@@ -20,8 +20,8 @@
 
     <itemizedlist>
 	<listitem><para>
-	SAMBA_CPS_ACCOUNT_NAME is always present and contains the sAMAccountName of user,
-	the is the same as the %u substitutions in the none AD DC case.
+	SAMBA_CPS_ACCOUNT_NAME is always present and contains the sAMAccountName of user.
+	It is the same as the '%u' substitutions in the non AD DC case.
 	</para></listitem>
 
 	<listitem><para>
@@ -33,6 +33,12 @@
 	</para></listitem>
     </itemizedlist>
 
+    <para>Even on a non AD DC SAMBA_CPS_ACCOUNT_NAME is the preferred way to access the
+    account name, as it contains the raw value provided by the client. If that's not
+    possible you should use single quotes (directly) around %u, e.g. /path/to/somescript '%u',
+    see CVE-2026-4408 for more details.
+    </para>
+
     <para>Note: In the example directory is a sample program called <command moreinfo="none">crackcheck</command>
     that uses cracklib to check the password quality.</para>
 
diff -Npur samba-4.23.7/lib/util/samba_util.h samba-4.23.8/lib/util/samba_util.h
--- samba-4.23.7/lib/util/samba_util.h	2026-01-23 11:53:40.777151000 +0100
+++ samba-4.23.8/lib/util/samba_util.h	2026-05-15 15:49:15.090977400 +0200
@@ -304,6 +304,15 @@ _PUBLIC_ bool set_boolean(const char *bo
 _PUBLIC_ bool conv_str_bool(const char * str, bool * val);
 
 /**
+ * Returns a pointer to the first invalid character in name.
+ *
+ * Passing a NULL pointer as name is not allowed!
+ *
+ * This returns NULL for a valid account name.
+ **/
+_PUBLIC_ const char *strstr_for_invalid_account_characters(const char *name);
+
+/**
  * Convert a size specification like 16K into an integral number of bytes.
  **/
 _PUBLIC_ bool conv_str_size_error(const char * str, uint64_t * val);
diff -Npur samba-4.23.7/lib/util/substitute.c samba-4.23.8/lib/util/substitute.c
--- samba-4.23.7/lib/util/substitute.c	2026-01-23 11:53:40.777151000 +0100
+++ samba-4.23.8/lib/util/substitute.c	2026-05-15 15:49:15.090977400 +0200
@@ -22,8 +22,11 @@
 */
 
 #include "replace.h"
+#include "system/locale.h"
 #include "debug.h"
 #ifndef SAMBA_UTIL_CORE_ONLY
+#include "lib/util/fault.h"
+#include "lib/util/talloc_stack.h"
 #include "charset/charset.h"
 #else
 #include "charset_compat.h"
@@ -35,6 +38,37 @@
  * @brief Substitute utilities.
  **/
 
+static inline
+char mask_unsafe_character(char in,
+			   bool is_last,
+			   bool allow_trailing_dollar,
+			   const char *unsafe_characters,
+			   char safe_out)
+{
+	const char *unsafe = NULL;
+
+	if (unsafe_characters == NULL) {
+		return in;
+	}
+
+	/* allow a trailing $ (as in machine accounts) */
+	if (allow_trailing_dollar && is_last && in == '$') {
+		return in;
+	}
+
+	if (iscntrl(in)) {
+		return safe_out;
+	}
+
+	unsafe = strchr(unsafe_characters, in);
+	if (unsafe != NULL) {
+		return safe_out;
+	}
+
+	/* ok */
+	return in;
+}
+
 /**
  Substitute a string for a pattern in another string. Make sure there is
  enough room!
@@ -42,15 +76,17 @@
  This routine looks for pattern in s and replaces it with
  insert. It may do multiple replacements or just one.
 
- Any of " ; ' $ or ` in the insert string are replaced with _
+ Any of STRING_SUB_UNSAFE_CHARACTERS and any character
+ caught by calling iscntrl() in the insert string are replaced with _
+
  if len==0 then the string cannot be extended. This is different from the old
  use of len==0 which was for no length checks to be done.
 **/
 
-static void string_sub2(char *s,const char *pattern, const char *insert, size_t len,
-			bool remove_unsafe_characters, bool replace_once,
-			bool allow_trailing_dollar)
+void string_sub(char *s, const char *pattern, const char *insert, size_t len)
 {
+	const char *unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
+	char safe_character = '_';
 	char *p;
 	size_t ls, lp, li, i;
 
@@ -77,47 +113,24 @@ static void string_sub2(char *s,const ch
 			memmove(p+li,p+lp,strlen(p+lp)+1);
 		}
 		for (i=0;i<li;i++) {
-			switch (insert[i]) {
-			case '$':
-				/* allow a trailing $
-				 * (as in machine accounts) */
-				if (allow_trailing_dollar && (i == li - 1 )) {
-					p[i] = insert[i];
-					break;
-				}
-				FALL_THROUGH;
-			case '`':
-			case '"':
-			case '\'':
-			case ';':
-			case '%':
-			case '\r':
-			case '\n':
-				if ( remove_unsafe_characters ) {
-					p[i] = '_';
-					/* yes this break should be here
-					 * since we want to fall throw if
-					 * not replacing unsafe chars */
-					break;
-				}
-				FALL_THROUGH;
-			default:
-				p[i] = insert[i];
-			}
+			/*
+			 * Without allow_trailing_dollar we don't
+			 * need to calculate is_last...
+			 */
+			const bool is_last = false;
+			const bool allow_trailing_dollar = false;
+
+			p[i] = mask_unsafe_character(insert[i],
+						     is_last,
+						     allow_trailing_dollar,
+						     unsafe_characters,
+						     safe_character);
 		}
 		s = p + li;
 		ls = ls + li - lp;
-
-		if (replace_once)
-			break;
 	}
 }
 
-void string_sub(char *s,const char *pattern, const char *insert, size_t len)
-{
-	string_sub2( s, pattern, insert, len, true, false, false );
-}
-
 /**
  Similar to string_sub() but allows for any character to be substituted. 
  Use with caution!
@@ -166,88 +179,53 @@ _PUBLIC_ void all_string_sub(char *s,con
  * talloc version of string_sub2.
  */
 
-char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
-			const char *pattern,
-			const char *insert,
-			bool remove_unsafe_characters,
-			bool replace_once,
-			bool allow_trailing_dollar)
+bool realloc_string_sub_raw(char **_string,
+			    const char *pattern,
+			    const char *insert,
+			    bool replace_once,
+			    bool allow_trailing_dollar,
+			    const char *unsafe_characters,
+			    char safe_character)
 {
-	char *p, *in;
-	char *s;
-	char *string;
+	char *p = NULL;
+	char *s = NULL;
+	char *string = NULL;
 	ssize_t ls,lp,li,ld, i;
 
-	if (!insert || !pattern || !*pattern || !src) {
-		return NULL;
+	if (!insert || !pattern || !*pattern || !_string|| !*_string) {
+		return false;
 	}
 
-	string = talloc_strdup(mem_ctx, src);
-	if (string == NULL) {
-		DEBUG(0, ("talloc_string_sub2: "
-			"talloc_strdup failed\n"));
-		return NULL;
-	}
+	s = string = *_string;
 
-	s = string;
-
-	in = talloc_strdup(mem_ctx, insert);
-	if (!in) {
-		DEBUG(0, ("talloc_string_sub2: ENOMEM\n"));
-		talloc_free(string);
-		return NULL;
-	}
 	ls = (ssize_t)strlen(s);
 	lp = (ssize_t)strlen(pattern);
 	li = (ssize_t)strlen(insert);
 	ld = li - lp;
 
-	for (i=0;i<li;i++) {
-		switch (in[i]) {
-			case '$':
-				/* allow a trailing $
-				 * (as in machine accounts) */
-				if (allow_trailing_dollar && (i == li - 1 )) {
-					break;
-				}
-
-				FALL_THROUGH;
-			case '`':
-			case '"':
-			case '\'':
-			case ';':
-			case '%':
-			case '\r':
-			case '\n':
-				if (remove_unsafe_characters) {
-					in[i] = '_';
-					break;
-				}
-
-				FALL_THROUGH;
-			default:
-				/* ok */
-				break;
-		}
-	}
-
 	while ((p = strstr_m(s,pattern))) {
 		if (ld > 0) {
-			int offset = PTR_DIFF(s,string);
-			string = (char *)talloc_realloc_size(mem_ctx, string,
-							ls + ld + 1);
+			ptrdiff_t offset = PTR_DIFF(s,string);
+			string = talloc_realloc(NULL, string, char, ls + ld + 1);
 			if (!string) {
-				DEBUG(0, ("talloc_string_sub: out of "
-					  "memory!\n"));
-				TALLOC_FREE(in);
-				return NULL;
+				DBG_ERR("out of memory(realloc)!\n");
+				return false;
 			}
+			*_string = string;
 			p = string + offset + (p - s);
 		}
 		if (li != lp) {
 			memmove(p+li,p+lp,strlen(p+lp)+1);
 		}
-		memcpy(p, in, li);
+		for (i=0; i < li; i++) {
+			bool is_last = (i == li - 1);
+
+			p[i] = mask_unsafe_character(insert[i],
+						     is_last,
+						     allow_trailing_dollar,
+						     unsafe_characters,
+						     safe_character);
+		}
 		s = p + li;
 		ls += ld;
 
@@ -255,7 +233,50 @@ char *talloc_string_sub2(TALLOC_CTX *mem
 			break;
 		}
 	}
-	TALLOC_FREE(in);
+	return true;
+}
+
+char *talloc_string_sub2(TALLOC_CTX *mem_ctx,
+			 const char *src,
+			 const char *pattern,
+			 const char *insert,
+			 bool remove_unsafe_characters,
+			 bool replace_once,
+			 bool allow_trailing_dollar)
+{
+	const char *unsafe_characters = NULL;
+	char safe_character = '\0';
+	char *string = NULL;
+	bool ok;
+
+	if (!insert || !pattern || !*pattern || !src) {
+		return NULL;
+	}
+
+	if (remove_unsafe_characters) {
+		unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
+		safe_character = '_';
+	}
+
+	string = talloc_strdup(mem_ctx, src);
+	if (string == NULL) {
+		DBG_ERR("out of memory, talloc_strdup(src)!\n");
+		return NULL;
+	}
+
+	ok = realloc_string_sub_raw(&string,
+				    pattern,
+				    insert,
+				    replace_once,
+				    allow_trailing_dollar,
+				    unsafe_characters,
+				    safe_character);
+	if (!ok) {
+		TALLOC_FREE(string);
+		DBG_ERR("out of memory, realloc_string_sub_raw()!\n");
+		return NULL;
+	}
+
 	return string;
 }
 
@@ -278,3 +299,261 @@ char *talloc_all_string_sub(TALLOC_CTX *
 	return talloc_string_sub2(ctx, src, pattern, insert,
 			false, false, false);
 }
+
+#ifndef SAMBA_UTIL_CORE_ONLY
+
+bool talloc_string_sub_mixed_quoting(const char *full_cmd, char variable_char)
+{
+	/*
+	 * Try to make sure talloc_string_sub_unsafe()
+	 * won't return NULL, instead talloc_stackframe_pool()
+	 * would panic
+	 */
+	size_t cmd_len = full_cmd != NULL ? strlen(full_cmd) : 0;
+	size_t pool_size = 512 + cmd_len;
+	TALLOC_CTX *frame = talloc_stackframe_pool(pool_size);
+	char *cmd = NULL;
+	bool modified = false;
+	bool masked = false;
+	bool mixed_fallback = false;
+
+	cmd = talloc_string_sub_unsafe(frame,
+				       full_cmd,
+				       variable_char,
+				       "U",  /* unsafe_value */
+				       "'\"%", /* unsafe_characters */
+				       '_',    /* safe_character */
+				       "F",  /* fallback_value */
+				       &modified,
+				       &masked,
+				       &mixed_fallback);
+	if (cmd == NULL) {
+		mixed_fallback = false;
+	}
+	TALLOC_FREE(frame);
+	return mixed_fallback;
+}
+
+char *talloc_string_sub_unsafe(TALLOC_CTX *mem_ctx,
+			       const char *orig_cmd,
+			       char variable_char,
+			       const char *unsafe_value,
+			       const char *unsafe_characters,
+			       char safe_character,
+			       const char *fallback_value,
+			       bool *_modified,
+			       bool *_masked,
+			       bool *_mixed_fallback)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	const char variable[3] =
+		{ '%', variable_char, '\0' };
+	const char variable_s_quoted[5] =
+		{ '\'', '%', variable_char, '\'', '\0' };
+	const char variable_d_quoted[5] =
+		{ '"', '%', variable_char, '"', '\0' };
+	char *cmd = NULL;
+	char *masked_value = NULL;
+	char *quoted_value = NULL;
+	bool has_s_quotes;
+	bool has_d_quotes;
+	bool has_variable;
+	bool has_variable_s_quoted;
+	bool has_variable_d_quoted;
+	bool modified = false;
+	bool masked = false;
+	bool mixed_fallback = false;
+	bool ok;
+
+	/*
+	 * The unsafe_characters argument should contain
+	 * single and double quotes.
+	 * Otherwise We can't safely handle this.
+	 */
+	SMB_ASSERT(unsafe_characters != NULL);
+	SMB_ASSERT(strchr(unsafe_characters, '\'') != NULL);
+	SMB_ASSERT(strchr(unsafe_characters, '"') != NULL);
+	SMB_ASSERT(strchr(unsafe_characters, '%') != NULL);
+
+	cmd = talloc_strdup(mem_ctx, orig_cmd);
+	if (cmd == NULL) {
+		TALLOC_FREE(frame);
+		return NULL;
+	}
+	cmd = talloc_steal(frame, cmd);
+
+	has_variable = strstr(orig_cmd, variable) != NULL;
+	if (!has_variable) {
+		/*
+		 * Nothing to do...
+		 */
+		goto done;
+	}
+	modified = true;
+
+	/*
+	 * Replace all unsafe characters as well as control
+	 * characters.
+	 *
+	 * Note that we start with masked_value = "%u"
+	 * and then replace "%u" with unsafe_value,
+	 * as a result we have a masked version of
+	 * unsafe_value.
+	 *
+	 * And don't allow option injected like
+	 *
+	 * '-h value'
+	 * '--help value'
+	 *
+	 */
+	masked_value = talloc_strdup(frame, variable);
+	if (masked_value == NULL) {
+		goto nomem;
+	}
+	ok = realloc_string_sub_raw(&masked_value,
+				    variable,
+				    unsafe_value,
+				    false, /* replace_once */
+				    false, /* allow_trailing_dollar */
+				    unsafe_characters,
+				    safe_character);
+	if (!ok) {
+		goto nomem;
+	}
+	if (masked_value[0] == '-') {
+		masked_value[0] = safe_character;
+	}
+	masked = strcmp(masked_value, unsafe_value) != 0;
+
+retry:
+
+	has_s_quotes = strchr(cmd, '\'') != NULL;
+	has_d_quotes = strchr(cmd, '"') != NULL;
+	has_variable = strstr(cmd, variable) != NULL;
+	has_variable_s_quoted = strstr(cmd, variable_s_quoted) != NULL;
+	has_variable_d_quoted = strstr(cmd, variable_d_quoted) != NULL;
+
+	if (has_variable_s_quoted) {
+		/*
+		 * In smb.conf we have something like
+		 *
+		 * some script = /usr/bin/script '%u'
+		 *
+		 * It is safe to replace '%u' (or '%J' etc, depending
+		 * on variable_char) with '<masked_value>' if
+		 * masked_value does not contain single quotes. We
+		 * have checked that.
+		 */
+
+		if (quoted_value == NULL) {
+			quoted_value = talloc_asprintf(frame, "'%s'",
+						       masked_value);
+			if (quoted_value == NULL) {
+				goto nomem;
+			}
+		}
+
+		ok = realloc_string_sub_raw(&cmd,
+					    variable_s_quoted,
+					    quoted_value,
+					    false, /* replace_once */
+					    false, /* allow_trailing_dollar */
+					    NULL,  /* unsafe_characters */
+					    '\0'); /* safe_character */
+		if (!ok) {
+			goto nomem;
+		}
+
+		goto retry;
+	}
+
+	if (has_variable_d_quoted && !has_s_quotes) {
+		/*
+		 * replace the "%u"
+		 *
+		 * some script = /usr/bin/script "%u"
+		 *
+		 * with '%u' and try the '%u' -> 'variable' substitution
+		 * again.
+		 */
+
+		ok = realloc_string_sub_raw(&cmd,
+					    variable_d_quoted,
+					    variable_s_quoted,
+					    false, /* replace_once */
+					    false, /* allow_trailing_dollar */
+					    NULL,  /* unsafe_characters */
+					    '\0'); /* safe_character */
+		if (!ok) {
+			goto nomem;
+		}
+
+		goto retry;
+	}
+
+	if (has_variable && !has_s_quotes && !has_d_quotes) {
+		/*
+		 * In this case:
+		 *
+		 * some script = /usr/bin/script %u
+		 *
+		 * we can safely substitute %u -> '%u' and try the
+		 * single quote test again.
+		 */
+
+		ok = realloc_string_sub_raw(&cmd,
+					    variable,
+					    variable_s_quoted,
+					    false, /* replace_once */
+					    false, /* allow_trailing_dollar */
+					    NULL,  /* unsafe_characters */
+					    '\0'); /* safe_character */
+		if (!ok) {
+			goto nomem;
+		}
+
+		goto retry;
+	}
+
+	if (has_variable) {
+		/*
+		 * There are single or double quotes, but not tightly
+		 * bound around a %u.
+		 *
+		 * Or there's a mix of single and double quotes.
+		 *
+		 * We just use a generic fallback value.
+		 * and let the caller warn about this
+		 * and give the admin a hind to fix the smb.conf
+		 * option.
+		 */
+		mixed_fallback = true;
+
+		ok = realloc_string_sub_raw(&cmd,
+					    variable,
+					    fallback_value,
+					    false, /* replace_once */
+					    false, /* allow_trailing_dollar */
+					    NULL,  /* unsafe_characters */
+					    '\0'); /* safe_character */
+		if (!ok) {
+			goto nomem;
+		}
+	}
+
+done:
+	*_modified = modified;
+	*_masked = masked;
+	*_mixed_fallback = mixed_fallback;
+	cmd = talloc_steal(mem_ctx, cmd);
+	TALLOC_FREE(frame);
+	return cmd;
+
+nomem:
+	*_modified = false;
+	*_masked = false;
+	*_mixed_fallback = false;
+	TALLOC_FREE(frame);
+	return NULL;
+}
+#endif /* ! SAMBA_UTIL_CORE_ONLY */
diff -Npur samba-4.23.7/lib/util/substitute.h samba-4.23.8/lib/util/substitute.h
--- samba-4.23.7/lib/util/substitute.h	2026-01-23 11:53:40.777151000 +0100
+++ samba-4.23.8/lib/util/substitute.h	2026-05-15 15:49:15.091977400 +0200
@@ -26,6 +26,8 @@
 
 #include <talloc.h>
 
+#define STRING_SUB_UNSAFE_CHARACTERS "$`\"';%|&<>"
+
 /**
  Substitute a string for a pattern in another string. Make sure there is
  enough room!
@@ -33,7 +35,9 @@
  This routine looks for pattern in s and replaces it with
  insert. It may do multiple replacements.
 
- Any of " ; ' $ or ` in the insert string are replaced with _
+ Any of STRING_SUB_UNSAFE_CHARACTERS (see above) and any character
+ caught by calling iscntrl() in the insert string are replaced with _
+
  if len==0 then the string cannot be extended. This is different from the old
  use of len==0 which was for no length checks to be done.
 **/
@@ -47,6 +51,24 @@ void string_sub(char *s,const char *patt
 **/
 void all_string_sub(char *s,const char *pattern,const char *insert, size_t len);
 
+/*
+ * If unsafe_characters is NULL all characters are allowed,
+ * if unsafe_characters is not NULL all characters caught
+ * by iscntrl() are also replaced by safe_character.
+ *
+ * *_string might be reallocated!
+ *
+ * On error *_string may still be reallocated and
+ * may contain partial replacements.
+ */
+bool realloc_string_sub_raw(char **_string,
+			    const char *pattern,
+			    const char *insert,
+			    bool replace_once,
+			    bool allow_trailing_dollar,
+			    const char *unsafe_characters,
+			    char safe_character);
+
 char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
 			const char *pattern,
 			const char *insert,
@@ -61,4 +83,21 @@ char *talloc_all_string_sub(TALLOC_CTX *
 				const char *src,
 				const char *pattern,
 				const char *insert);
+
+#ifndef SAMBA_UTIL_CORE_ONLY
+bool talloc_string_sub_mixed_quoting(const char *full_cmd, char variable_char);
+
+char *talloc_string_sub_unsafe(TALLOC_CTX *mem_ctx,
+			       const char *orig_cmd,
+			       char variable_char,
+			       const char *unsafe_value,
+			       const char *unsafe_characters,
+			       char safe_character,
+			       const char *fallback_value,
+			       bool *_modified,
+			       bool *_masked,
+			       bool *_mixed_fallback);
+
+#endif /* ! SAMBA_UTIL_CORE_ONLY */
+
 #endif /* _SAMBA_SUBSTITUTE_H_ */
diff -Npur samba-4.23.7/lib/util/tests/test_string_sub.c samba-4.23.8/lib/util/tests/test_string_sub.c
--- samba-4.23.7/lib/util/tests/test_string_sub.c	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/lib/util/tests/test_string_sub.c	2026-05-15 15:49:15.091977400 +0200
@@ -0,0 +1,1044 @@
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <sys/stat.h>
+#include "replace.h"
+#include <cmocka.h>
+#include "talloc.h"
+
+#include "../substitute.h"
+
+/* set _DEBUG_VERBOSE to print more. */
+#define _DEBUG_VERBOSE
+
+#ifdef _DEBUG_VERBOSE
+#define debug_message(...) print_message(__VA_ARGS__)
+#else
+#define debug_message(...) /* debug_message */
+#endif
+
+
+static int setup_talloc_context(void **state)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	*state = mem_ctx;
+	return 0;
+}
+
+static int teardown_talloc_context(void **state)
+{
+	TALLOC_CTX *mem_ctx = *state;
+	TALLOC_FREE(mem_ctx);
+	return 0;
+}
+
+struct cmd_expansion {
+	const char *lp_cmd;
+	const char *username;
+	const char *result_cmd;
+	bool modified;
+	bool masked;
+	bool mixed_fallback;
+};
+
+static void _test_talloc_string_sub_unsafe(void **state,
+					   struct cmd_expansion expansions[],
+					   size_t n_expansions,
+					   const char *unsafe_characters)
+{
+	TALLOC_CTX *mem_ctx = *state;
+	size_t i;
+
+	for (i = 0; i < n_expansions; i++) {
+		struct cmd_expansion t = expansions[i];
+		char *result_cmd = NULL;
+		bool masked;
+		bool mixed_fallback;
+		bool modified;
+		bool flags_correct;
+		bool mixed;
+		int cmp;
+
+		mixed = talloc_string_sub_mixed_quoting(t.lp_cmd, 'u');
+
+		result_cmd = talloc_string_sub_unsafe(mem_ctx,
+						      t.lp_cmd,
+						      'u',
+						      t.username,
+						      unsafe_characters,
+						      '_',
+						      "FallbackUsername",
+						      &modified,
+						      &masked,
+						      &mixed_fallback);
+		assert_ptr_not_equal(result_cmd, NULL);
+		assert_ptr_not_equal(t.result_cmd, NULL);
+
+		cmp = strcmp(t.result_cmd, result_cmd);
+		flags_correct = (modified == t.modified &&
+				 masked == t.masked &&
+				 mixed_fallback == t.mixed_fallback);
+
+		if (cmp == 0) {
+			debug_message("[%zu] «%s» «%s»   ->   «%s»; AS EXPECTED\n",
+				      i, t.lp_cmd,
+				      t.username,
+				      result_cmd);
+		} else {
+			debug_message("[%zu] «%s» «%s»; "
+				      "expected   [%zu] «%s»   got  [%zu] «%s»\033[1;31m BAD! \033[0m\n",
+				      i, t.lp_cmd,
+				      t.username,
+				      strlen(t.result_cmd), t.result_cmd,
+				      strlen(result_cmd), result_cmd);
+		}
+		assert_int_equal(cmp, 0);
+		if (!flags_correct) {
+			debug_message("[%zu] ", i);
+#define _FLAG(x) debug_message((t. x  == x) ? "%s: %s √; ":		\
+			       "%s \033[1;31m expected %s \033[0m; ",	\
+			       #x, t.x ? "true": "false");
+			_FLAG(modified);
+			_FLAG(masked);
+			_FLAG(mixed_fallback);
+			debug_message("\n");
+		}
+		assert_int_equal(flags_correct, true);
+		if (mixed_fallback != mixed) {
+			debug_message("[%zu] %s mixed \033[1;31m expected %s \033[0m; ",
+				      i, t.lp_cmd,
+				      mixed_fallback ? "true": "false");
+		}
+		assert_int_equal(mixed_fallback, mixed);
+#undef _FLAG
+	}
+	debug_message("ALL correct\n");
+}
+
+static void test_talloc_string_sub_unsafe(void **state)
+{
+	const char *unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
+
+	static struct cmd_expansion expansions[] = {
+		{
+			"/bin/echo \"bob'",
+			"bob",
+			"/bin/echo \"bob'",
+			false,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"bob",
+			"/bin/echo 'bob'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"bob",
+			"/bin/echo 'bob'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"bob'",
+			"/bin/echo 'bob_'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"bob'''",
+			"/bin/echo 'bob___'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"bob\'",
+			"/bin/echo 'bob_'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo '%u",
+			"bob bob bob",
+			"/bin/echo 'FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo \"%u\"",
+			" ",
+			"/bin/echo ' '",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo \"--uu=%u\"",
+			"bob",
+			"/bin/echo \"--uu=FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo \"--uu=%u\"",
+			"bob !0",
+			"/bin/echo \"--uu=FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo %u",
+			"!0",
+			"/bin/echo '!0'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo \"--uu=%u\"",
+			"bob \\",
+			"/bin/echo \"--uu=FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo --uu='%u'",
+			"bob >> x",
+			"/bin/echo --uu='bob __ x'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo '--uu=%u\"",
+			"bob",
+			"/bin/echo '--uu=FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo --uu='%u'",
+			"bob",
+			"/bin/echo --uu='bob'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo --uu'=%u'",
+			"bob",
+			"/bin/echo --uu'=FallbackUsername'",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo --uu'=%u'",
+			"`ls`",
+			"/bin/echo --uu'=FallbackUsername'",
+			true,
+			true,
+			true,
+		},
+		{
+			"/bin/echo --uu='%u'",
+			"u%u%u%u%u",
+			"/bin/echo --uu='u_u_u_u_u'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo --uu='%u'",
+			"$(ls)",
+			"/bin/echo --uu='_(ls)'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo --uu='%u'",
+			"`ls`",
+			"/bin/echo --uu='_ls_'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo --uu='1' %u",
+			"`ls`",
+			"/bin/echo --uu='1' FallbackUsername",
+			true,
+			true,
+			true,
+		},
+		{
+			"/bin/echo --uu=\"'%u'\"",
+			"bob",
+			"/bin/echo --uu=\"'bob'\"",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo --uu='%u' --yy='%u' '%u' %u",
+			"bob",
+			"/bin/echo --uu='bob' --yy='bob' 'bob' FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo --uu=%u%u%u'' %user 50%u",
+			"bob",
+			"/bin/echo --uu=FallbackUsernameFallbackUsernameFallbackUsername'' FallbackUsernameser 50FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo %u",
+			"!!",
+			"/bin/echo '!!'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			">xxx",
+			"/bin/echo '_xxx'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"3",
+			"/bin/echo '3'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"3$",
+			"/bin/echo '3_'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"comp$",
+			"/bin/echo 'comp_'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"3$3",
+			"/bin/echo '3_3'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"q $3",
+			"/bin/echo 'q _3'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo '%u",
+			"q $3",
+			"/bin/echo 'FallbackUsername",
+			true,
+			true,
+			true,
+		},
+		{
+			"/bin/echo -s '%u' %u",
+			"āāā",
+			"/bin/echo -s 'āāā' FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo -s '%u' %u",
+			"-āāā",
+			"/bin/echo -s '_āāā' FallbackUsername",
+			true,
+			true,
+			true,
+		},
+		{
+			"/bin/echo -s %u",
+			"āāā",
+			"/bin/echo -s 'āāā'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo -s %u",
+			"a -a",
+			"/bin/echo -s 'a -a'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo -s=%u %u",
+			"ā -a",
+			"/bin/echo -s='ā -a' 'ā -a'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo -s=\"%u %u\"",
+			"ā -a",
+			"/bin/echo -s=\"FallbackUsername FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo -m='fridge' %u",
+			"ā  -ß",
+			"/bin/echo -m='fridge' FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo -m='fridge' %u",
+			"-ā -a",
+			"/bin/echo -m='fridge' FallbackUsername",
+			true,
+			true,
+			true,
+		},
+		{
+			"/bin/echo %u",
+			"-n",
+			"/bin/echo '_n'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"o'clock",
+			"/bin/echo 'o_clock'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo \"bob'",
+			"bob",
+			"/bin/echo \"bob'",
+			false,
+			false,
+			false,
+		},
+		{
+			"/bin/echo \"%u\"",
+			"%u",
+			"/bin/echo '_u'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo \"$(ls)\"",
+			"%u",
+			"/bin/echo \"$(ls)\"",
+			false,
+			false,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"\\",
+			"/bin/echo '\\'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"\\",
+			"/bin/echo '\\'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo \"%u\"",
+			"\\",
+			"/bin/echo '\\'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo \"%u\" %u",
+			"\\",
+			"/bin/echo '\\' FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo '%u' \"%u\" %u",
+			"\\",
+			"/bin/echo '\\' \"FallbackUsername\" FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo '%u' \"%u\"",
+			"bob",
+			"/bin/echo 'bob' \"FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+	};
+
+	_test_talloc_string_sub_unsafe(state,
+				       expansions,
+				       ARRAY_SIZE(expansions),
+				       unsafe_characters);
+}
+
+static void test_talloc_string_sub_unsafe_minimal_unsafe_chars(void **state)
+{
+	const char *unsafe_characters = "\"'%";
+
+	static struct cmd_expansion expansions[] = {
+		{
+			"/bin/echo \"bob'",
+			"bob",
+			"/bin/echo \"bob'",
+			false,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"bob",
+			"/bin/echo 'bob'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"bob",
+			"/bin/echo 'bob'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"bob'",
+			"/bin/echo 'bob_'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"bob'''",
+			"/bin/echo 'bob___'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"bob\'",
+			"/bin/echo 'bob_'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo '%u",
+			"bob bob bob",
+			"/bin/echo 'FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo \"%u\"",
+			" ",
+			"/bin/echo ' '",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo \"--uu=%u\"",
+			"bob",
+			"/bin/echo \"--uu=FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo \"--uu=%u\"",
+			"bob !0",
+			"/bin/echo \"--uu=FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo %u",
+			"!0",
+			"/bin/echo '!0'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo \"--uu=%u\"",
+			"bob \\",
+			"/bin/echo \"--uu=FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo --uu='%u'",
+			"bob >> x",
+			"/bin/echo --uu='bob >> x'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '--uu=%u\"",
+			"bob",
+			"/bin/echo '--uu=FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo --uu='%u'",
+			"bob",
+			"/bin/echo --uu='bob'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo --uu'=%u'",
+			"bob",
+			"/bin/echo --uu'=FallbackUsername'",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo --uu'=%u'",
+			"`ls`",
+			"/bin/echo --uu'=FallbackUsername'",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo --uu='%u'",
+			"u%u%u%u%u",
+			"/bin/echo --uu='u_u_u_u_u'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo --uu='%u'",
+			"$(ls)",
+			"/bin/echo --uu='$(ls)'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo --uu='%u'",
+			"`ls`",
+			"/bin/echo --uu='`ls`'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo --uu='1' %u",
+			"`ls`",
+			"/bin/echo --uu='1' FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo --uu=\"'%u'\"",
+			"bob",
+			"/bin/echo --uu=\"'bob'\"",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo --uu='%u' --yy='%u' '%u' %u",
+			"bob",
+			"/bin/echo --uu='bob' --yy='bob' 'bob' FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo --uu=%u%u%u'' %user 50%u",
+			"bob",
+			"/bin/echo --uu=FallbackUsernameFallbackUsernameFallbackUsername'' FallbackUsernameser 50FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo %u",
+			"!!",
+			"/bin/echo '!!'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			">xxx",
+			"/bin/echo '>xxx'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"3",
+			"/bin/echo '3'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"3$",
+			"/bin/echo '3$'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"comp$",
+			"/bin/echo 'comp$'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"3$3",
+			"/bin/echo '3$3'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"q $3",
+			"/bin/echo 'q $3'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '%u",
+			"q $3",
+			"/bin/echo 'FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo -s '%u' %u",
+			"āāā",
+			"/bin/echo -s 'āāā' FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo -s '%u' %u",
+			"-āāā",
+			"/bin/echo -s '_āāā' FallbackUsername",
+			true,
+			true,
+			true,
+		},
+		{
+			"/bin/echo -s %u",
+			"āāā",
+			"/bin/echo -s 'āāā'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo -s %u",
+			"a -a",
+			"/bin/echo -s 'a -a'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo -s=%u %u",
+			"ā -a",
+			"/bin/echo -s='ā -a' 'ā -a'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo -s=\"%u %u\"",
+			"ā -a",
+			"/bin/echo -s=\"FallbackUsername FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo -m='fridge' %u",
+			"ā  -ß",
+			"/bin/echo -m='fridge' FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo -m='fridge' %u",
+			"-ā -a",
+			"/bin/echo -m='fridge' FallbackUsername",
+			true,
+			true,
+			true,
+		},
+		{
+			"/bin/echo %u",
+			"-n",
+			"/bin/echo '_n'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"o'clock",
+			"/bin/echo 'o_clock'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo \"bob'",
+			"bob",
+			"/bin/echo \"bob'",
+			false,
+			false,
+			false,
+		},
+		{
+			"/bin/echo \"%u\"",
+			"%u",
+			"/bin/echo '_u'",
+			true,
+			true,
+			false,
+		},
+		{
+			"/bin/echo \"$(ls)\"",
+			"%u",
+			"/bin/echo \"$(ls)\"",
+			false,
+			false,
+			false,
+		},
+		{
+			"/bin/echo %u",
+			"\\",
+			"/bin/echo '\\'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo '%u'",
+			"\\",
+			"/bin/echo '\\'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo \"%u\"",
+			"\\",
+			"/bin/echo '\\'",
+			true,
+			false,
+			false,
+		},
+		{
+			"/bin/echo \"%u\" %u",
+			"\\",
+			"/bin/echo '\\' FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo '%u' \"%u\" %u",
+			"\\",
+			"/bin/echo '\\' \"FallbackUsername\" FallbackUsername",
+			true,
+			false,
+			true,
+		},
+		{
+			"/bin/echo '%u' \"%u\"",
+			"bob",
+			"/bin/echo 'bob' \"FallbackUsername\"",
+			true,
+			false,
+			true,
+		},
+	};
+
+	_test_talloc_string_sub_unsafe(state,
+				       expansions,
+				       ARRAY_SIZE(expansions),
+				       unsafe_characters);
+}
+
+static void test_talloc_string_sub_unsafe_all_mixes(void **state)
+{
+	const char *unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
+	size_t i;
+
+	for (i = 0; i < 32; i++) {
+		char in[100] = { 0, };
+		char out[100] = { 0, };
+		struct cmd_expansion expansions[] = {
+			{
+				in,
+				"bob",
+				out,
+				true,
+				false,
+				false,
+			},
+		};
+		bool vsq = i & 1;
+		bool vdq = i & 2;
+		bool v = i & 4;
+		bool sq = i & 8;
+		bool dq = i & 16;
+		char *inp = in;
+		char *outp = out;
+		if (vsq) {
+			inp = stpcpy(inp, "'%u' ");
+			outp = stpcpy(outp, "'bob' ");
+			debug_message("vsq ");
+		}
+		if (vdq) {
+			inp = stpcpy(inp, "\"%u\" ");
+			outp = stpcpy(outp, (vsq || sq) ? "\"FallbackUsername\" " : "'bob' ");
+			debug_message("vdq ");
+			if (vsq || sq) {
+				expansions[0].mixed_fallback = true;
+			}
+		}
+		if (v) {
+			inp = stpcpy(inp, "%u ");
+			outp = stpcpy(outp, (vsq || vdq || sq || dq) ? "FallbackUsername " : "'bob' ");
+			debug_message("v ");
+			if (vsq || vdq || sq || dq) {
+				expansions[0].mixed_fallback = true;
+			}
+		}
+		if (sq) {
+			inp = stpcpy(inp, "' ");
+			outp = stpcpy(outp, "' ");
+			debug_message("sq ");
+		}
+		if (dq) {
+			inp = stpcpy(inp, "\" ");
+			outp = stpcpy(outp, "\" ");
+			debug_message("dq ");
+		}
+		debug_message("(i: %zu)\n", i);
+		*inp = '\0';
+		*outp = '\0';
+		expansions[0].modified = strcmp(in, out) != 0;
+
+		_test_talloc_string_sub_unsafe(state,
+					       expansions,
+					       ARRAY_SIZE(expansions),
+					       unsafe_characters);
+	}
+}
+
+
+int main(void)
+{
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test(test_talloc_string_sub_unsafe),
+		cmocka_unit_test(test_talloc_string_sub_unsafe_minimal_unsafe_chars),
+		cmocka_unit_test(test_talloc_string_sub_unsafe_all_mixes),
+	};
+	if (!isatty(1)) {
+		cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+	}
+	return cmocka_run_group_tests(tests,
+				      setup_talloc_context,
+				      teardown_talloc_context);
+}
diff -Npur samba-4.23.7/lib/util/util_str.c samba-4.23.8/lib/util/util_str.c
--- samba-4.23.7/lib/util/util_str.c	2026-01-23 11:53:40.785153200 +0100
+++ samba-4.23.8/lib/util/util_str.c	2026-05-15 15:49:15.091977400 +0200
@@ -267,3 +267,41 @@ _PUBLIC_ bool set_boolean(const char *bo
 	}
 	return false;
 }
+
+_PUBLIC_ const char *strstr_for_invalid_account_characters(const char *name)
+{
+	/*
+	 * Return a pointer to the first invalid character in the
+	 * sAMAccountName, or NULL if the whole name is valid.
+	 *
+	 * The rules here are based on
+	 *
+	 * https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx
+	 */
+	size_t i;
+
+	for (i = 0; name[i] != '\0'; i++) {
+		uint8_t c = name[i];
+		const char *p = NULL;
+
+		if (iscntrl(c)) {
+			return &name[i];
+		}
+
+		p = strchr("\"[]:;|=+*?<>/\\,", c);
+		if (p != NULL) {
+			return &name[i];
+		}
+	}
+
+	if (i == 0) {
+		return &name[i];
+	}
+
+	if (name[i - 1] == '.') {
+		i -= 1;
+		return &name[i];
+	}
+
+	return NULL;
+}
diff -Npur samba-4.23.7/lib/util/util_str_escape.c samba-4.23.8/lib/util/util_str_escape.c
--- samba-4.23.7/lib/util/util_str_escape.c	2026-01-23 11:53:40.785153200 +0100
+++ samba-4.23.8/lib/util/util_str_escape.c	2026-05-15 15:49:15.091977400 +0200
@@ -18,6 +18,7 @@
 */
 
 #include "replace.h"
+#include "system/locale.h"
 #include "lib/util/debug.h"
 #include "lib/util/util_str_escape.h"
 
@@ -28,7 +29,7 @@
  */
 static size_t encoded_length(unsigned char c)
 {
-	if (c != '\\' &&  c > 0x1F) {
+	if (c != '\\' && !iscntrl(c)) {
 		return 1;
 	} else {
 		switch (c) {
@@ -79,7 +80,7 @@ char *log_escape(TALLOC_CTX *frame, cons
 	c = in;
 	e = encoded;
 	while (*c) {
-		if (*c != '\\' && (unsigned char)(*c) > 0x1F) {
+		if (*c != '\\' && !iscntrl((unsigned char)(*c))) {
 			*e++ = *c++;
 		} else {
 			switch (*c) {
diff -Npur samba-4.23.7/lib/util/wscript_build samba-4.23.8/lib/util/wscript_build
--- samba-4.23.7/lib/util/wscript_build	2026-01-23 11:53:40.785153200 +0100
+++ samba-4.23.8/lib/util/wscript_build	2026-05-15 15:49:15.092977500 +0200
@@ -420,3 +420,9 @@ else:
                      deps='cmocka replace talloc stable_sort',
                      local_include=False,
                      for_selftest=True)
+
+    bld.SAMBA3_BINARY('test_string_sub',
+                      source='tests/test_string_sub.c',
+                      deps='''cmocka replace talloc samba-util
+                      ''',
+                      for_selftest=True)
diff -Npur samba-4.23.7/nsswitch/pam_winbind.c samba-4.23.8/nsswitch/pam_winbind.c
--- samba-4.23.7/nsswitch/pam_winbind.c	2026-01-23 11:53:40.849168500 +0100
+++ samba-4.23.8/nsswitch/pam_winbind.c	2026-05-15 15:49:15.093977500 +0200
@@ -1589,12 +1589,32 @@ static char *_pam_compose_pwd_restrictio
 
 static int _pam_create_homedir(struct pwb_context *ctx,
 			       const char *dirname,
-			       mode_t mode)
+			       mode_t mode,
+			       uid_t uid,
+			       gid_t gid)
 {
 	int ret;
 
 	ret = mkdir(dirname, mode);
-	if (ret != 0 && errno == EEXIST) {
+	if (ret == 0) {
+		if (uid == 0 && gid == 0) {
+			return PAM_SUCCESS;
+		}
+
+		ret = chown(dirname, uid, gid);
+		if (ret == 0) {
+			return PAM_SUCCESS;
+		}
+
+		_make_remark_format(ctx, PAM_TEXT_INFO,
+				    _("Change owner of user homedir: %s failed: %s"),
+				    dirname, strerror(errno));
+		_pam_log(ctx, LOG_ERR, "failed to chown user homedir: %s (%s)",
+			 dirname, strerror(errno));
+		return PAM_PERM_DENIED;
+	}
+
+	if (errno == EEXIST) {
 		struct stat sbuf;
 
 		ret = stat(dirname, &sbuf);
@@ -1605,32 +1625,16 @@ static int _pam_create_homedir(struct pw
 		if (!S_ISDIR(sbuf.st_mode)) {
 			return PAM_PERM_DENIED;
 		}
-	}
-
-	if (ret != 0) {
-		_make_remark_format(ctx, PAM_TEXT_INFO,
-				    _("Creating directory: %s failed: %s"),
-				    dirname, strerror(errno));
-		_pam_log(ctx, LOG_ERR, "could not create dir: %s (%s)",
-		 dirname, strerror(errno));
-		 return PAM_PERM_DENIED;
-	}
 
-	return PAM_SUCCESS;
-}
-
-static int _pam_chown_homedir(struct pwb_context *ctx,
-			      const char *dirname,
-			      uid_t uid,
-			      gid_t gid)
-{
-	if (chown(dirname, uid, gid) != 0) {
-		_pam_log(ctx, LOG_ERR, "failed to chown user homedir: %s (%s)",
-			 dirname, strerror(errno));
-		return PAM_PERM_DENIED;
+		return PAM_SUCCESS;
 	}
 
-	return PAM_SUCCESS;
+	_make_remark_format(ctx, PAM_TEXT_INFO,
+			    _("Creating directory: %s failed: %s"),
+			    dirname, strerror(errno));
+	_pam_log(ctx, LOG_ERR, "could not create dir: %s (%s)",
+		 dirname, strerror(errno));
+	return PAM_PERM_DENIED;
 }
 
 static int _pam_mkhomedir(struct pwb_context *ctx)
@@ -1641,7 +1645,6 @@ static int _pam_mkhomedir(struct pwb_con
 	char *user_dir = NULL;
 	int ret;
 	const char *username;
-	mode_t mode = 0700;
 	char *safe_ptr = NULL;
 	char *p = NULL;
 
@@ -1658,14 +1661,18 @@ static int _pam_mkhomedir(struct pwb_con
 		return PAM_USER_UNKNOWN;
 	}
 	_pam_log_debug(ctx, LOG_DEBUG, "homedir is: %s", pwd->pw_dir);
-
-	ret = _pam_create_homedir(ctx, pwd->pw_dir, 0700);
-	if (ret == PAM_SUCCESS) {
-		ret = _pam_chown_homedir(ctx, pwd->pw_dir,
-					 pwd->pw_uid,
-					 pwd->pw_gid);
+	if (pwd->pw_uid == 0 && pwd->pw_gid == 0) {
+		/*
+		 * Just skip this for root.
+		 */
+		return PAM_SUCCESS;
 	}
 
+	ret = _pam_create_homedir(ctx,
+				  pwd->pw_dir,
+				  0700,
+				  pwd->pw_uid,
+				  pwd->pw_gid);
 	if (ret == PAM_SUCCESS) {
 		return ret;
 	}
@@ -1688,8 +1695,9 @@ static int _pam_mkhomedir(struct pwb_con
 	p = pwd->pw_dir;
 
 	while ((token = strtok_r(p, "/", &safe_ptr)) != NULL) {
-
-		mode = 0755;
+		mode_t mode = 0755;
+		uid_t uid = 0;
+		gid_t gid = 0;
 
 		p = NULL;
 
@@ -1704,17 +1712,17 @@ static int _pam_mkhomedir(struct pwb_con
 		if (strcmp(token, user_dir) == 0) {
 			_pam_log_debug(ctx, LOG_DEBUG, "assuming last directory: %s", token);
 			mode = 0700;
+			uid = pwd->pw_uid;
+			gid = pwd->pw_gid;
 		}
 
-		ret = _pam_create_homedir(ctx, create_dir, mode);
+		ret = _pam_create_homedir(ctx, create_dir, mode, uid, gid);
 		if (ret != PAM_SUCCESS) {
 			return ret;
 		}
 	}
 
-	return _pam_chown_homedir(ctx, create_dir,
-				  pwd->pw_uid,
-				  pwd->pw_gid);
+	return PAM_SUCCESS;
 }
 
 /* talk to winbindd */
diff -Npur samba-4.23.7/python/samba/gp/gp_cert_auto_enroll_ext.py samba-4.23.8/python/samba/gp/gp_cert_auto_enroll_ext.py
--- samba-4.23.7/python/samba/gp/gp_cert_auto_enroll_ext.py	2026-01-23 11:53:40.865172400 +0100
+++ samba-4.23.8/python/samba/gp/gp_cert_auto_enroll_ext.py	2026-05-15 15:49:15.094977400 +0200
@@ -16,7 +16,6 @@
 
 import os
 import operator
-import requests
 from samba.gp.gpclass import gp_pol_ext, gp_applier, GPOSTATE
 from samba import Ldb
 from samba.dcerpc import misc
@@ -195,58 +194,24 @@ def get_supported_templates(server):
     return out.strip().split()
 
 
-def getca(ca, url, trust_dir):
-    """Fetch Certificate Chain from the CA."""
+def getca(ca, trust_dir):
+    """Fetch a certificate from LDAP."""
     root_cert = os.path.join(trust_dir, '%s.crt' % ca['name'])
     root_certs = []
-
-    try:
-        r = requests.get(url=url, params={'operation': 'GetCACert',
-                                          'message': 'CAIdentifier'})
-    except requests.exceptions.ConnectionError:
-        log.warn('Could not connect to Network Device Enrollment Service.')
-        r = None
-    if r is None or r.content == b'' or r.headers['Content-Type'] == 'text/html':
-        log.warn('Unable to fetch root certificates (requires NDES).')
-        if 'cACertificate' in ca:
-            log.warn('Installing the server certificate only.')
-            der_certificate = base64.b64decode(ca['cACertificate'])
-            try:
-                cert = load_der_x509_certificate(der_certificate)
-            except TypeError:
-                cert = load_der_x509_certificate(der_certificate,
-                                                 default_backend())
-            cert_data = cert.public_bytes(Encoding.PEM)
-            with open(root_cert, 'wb') as w:
-                w.write(cert_data)
-            root_certs.append(root_cert)
-        return root_certs
-
-    if r.headers['Content-Type'] == 'application/x-x509-ca-cert':
-        # Older versions of load_der_x509_certificate require a backend param
+    if 'cACertificate' in ca:
+        log.warn('Installing the server certificate only.')
+        der_certificate = base64.b64decode(ca['cACertificate'])
         try:
-            cert = load_der_x509_certificate(r.content)
+            cert = load_der_x509_certificate(der_certificate)
         except TypeError:
-            cert = load_der_x509_certificate(r.content, default_backend())
+            cert = load_der_x509_certificate(der_certificate,
+                                             default_backend())
         cert_data = cert.public_bytes(Encoding.PEM)
         with open(root_cert, 'wb') as w:
             w.write(cert_data)
         root_certs.append(root_cert)
-    elif r.headers['Content-Type'] == 'application/x-x509-ca-ra-cert':
-        certs = load_der_pkcs7_certificates(r.content)
-        for i in range(0, len(certs)):
-            cert = certs[i].public_bytes(Encoding.PEM)
-            filename, extension = root_cert.rsplit('.', 1)
-            dest = '%s.%d.%s' % (filename, i, extension)
-            with open(dest, 'wb') as w:
-                w.write(cert)
-            root_certs.append(dest)
-    else:
-        log.warn('getca: Wrong (or missing) MIME content type')
-
     return root_certs
 
-
 def find_global_trust_dir():
     """Return the global trust dir using known paths from various Linux distros."""
     for trust_dir in global_trust_dirs:
@@ -266,11 +231,10 @@ def changed(new_data, old_data):
 def cert_enroll(ca, ldb, trust_dir, private_dir, auth='Kerberos'):
     """Install the root certificate chain."""
     data = dict({'files': [], 'templates': []}, **ca)
-    url = 'http://%s/CertSrv/mscep/mscep.dll/pkiclient.exe?' % ca['hostname']
 
     log.info("Try to get root or server certificates")
 
-    root_certs = getca(ca, url, trust_dir)
+    root_certs = getca(ca, trust_dir)
     data['files'].extend(root_certs)
     global_trust_dir = find_global_trust_dir()
     for src in root_certs:
@@ -488,11 +452,21 @@ class gp_cert_auto_enroll_ext(gp_pol_ext
                     # This is a basic configuration.
                     cas = fetch_certification_authorities(ldb)
                     for _ca in cas:
+                        if 'cACertificate' not in _ca:
+                            log.warning(f"ignoring CA '{_ca['name']}' with no "
+                                        "cACertificate in LDAP.")
+                            continue
+
                         self.apply(guid, _ca, cert_enroll, _ca, ldb, trust_dir,
                                    private_dir)
                         ca_names.append(_ca['name'])
                 # If EndPoint.URI starts with "HTTPS//":
                 elif ca['URL'].lower().startswith('https://'):
+                    if 'cACertificate' not in ca:
+                        log.warning(f"ignoring CA '{ca['name']}' "
+                                    f"({ca['URL']}) with no "
+                                    "cACertificate in LDAP.")
+                        continue
                     self.apply(guid, ca, cert_enroll, ca, ldb, trust_dir,
                                private_dir, auth=ca['auth'])
                     ca_names.append(ca['name'])
diff -Npur samba-4.23.7/python/samba/tests/gpo.py samba-4.23.8/python/samba/tests/gpo.py
--- samba-4.23.7/python/samba/tests/gpo.py	2026-01-23 11:53:40.897180300 +0100
+++ samba-4.23.8/python/samba/tests/gpo.py	2026-05-15 15:49:15.100977700 +0200
@@ -6951,6 +6951,7 @@ class GPOTests(tests.TestCase):
         confdn = 'CN=Public Key Services,CN=Services,CN=Configuration,%s' % base_dn
         ca_cn = '%s-CA' % hostname.replace('.', '-')
         certa_dn = 'CN=%s,CN=Certification Authorities,%s' % (ca_cn, confdn)
+        self.addCleanup(ldb.delete, certa_dn)
         ldb.add({'dn': certa_dn,
                  'objectClass': 'certificationAuthority',
                  'authorityRevocationList': ['XXX'],
@@ -6959,6 +6960,7 @@ class GPOTests(tests.TestCase):
                 })
         # Write the dummy pKIEnrollmentService
         enroll_dn = 'CN=%s,CN=Enrollment Services,%s' % (ca_cn, confdn)
+        self.addCleanup(ldb.delete, enroll_dn)
         ldb.add({'dn': enroll_dn,
                  'objectClass': 'pKIEnrollmentService',
                  'cACertificate': dummy_certificate(),
@@ -6967,6 +6969,7 @@ class GPOTests(tests.TestCase):
                 })
         # Write the dummy pKICertificateTemplate
         template_dn = 'CN=Machine,CN=Certificate Templates,%s' % confdn
+        self.addCleanup(ldb.delete, template_dn)
         ldb.add({'dn': template_dn,
                  'objectClass': 'pKICertificateTemplate',
                 })
@@ -7012,11 +7015,6 @@ class GPOTests(tests.TestCase):
             self.assertNotIn(b'Workstation', out,
                              'Workstation certificate not removed')
 
-        # Remove the dummy CA, pKIEnrollmentService, and pKICertificateTemplate
-        ldb.delete(certa_dn)
-        ldb.delete(enroll_dn)
-        ldb.delete(template_dn)
-
         # Unstage the Registry.pol file
         unstage_file(reg_pol)
 
@@ -7027,6 +7025,7 @@ class GPOTests(tests.TestCase):
                                'MACHINE/REGISTRY.POL')
         cache_dir = self.lp.get('cache directory')
         store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb'))
+        self.addCleanup(store.log.close)
 
         machine_creds = Credentials()
         machine_creds.guess(self.lp)
@@ -7059,28 +7058,34 @@ class GPOTests(tests.TestCase):
         confdn = 'CN=Public Key Services,CN=Services,CN=Configuration,%s' % base_dn
         ca_cn = '%s-CA' % hostname.replace('.', '-')
         certa_dn = 'CN=%s,CN=Certification Authorities,%s' % (ca_cn, confdn)
+        self.addCleanup(ldb.delete, certa_dn)
         ldb.add({'dn': certa_dn,
                  'objectClass': 'certificationAuthority',
                  'authorityRevocationList': ['XXX'],
-                 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I',
+                 'cACertificate': dummy_certificate(),
                  'certificateRevocationList': ['XXX'],
                 })
         # Write the dummy pKIEnrollmentService
         enroll_dn = 'CN=%s,CN=Enrollment Services,%s' % (ca_cn, confdn)
+        self.addCleanup(ldb.delete, enroll_dn)
         ldb.add({'dn': enroll_dn,
                  'objectClass': 'pKIEnrollmentService',
-                 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I',
+                 'cACertificate': dummy_certificate(),
                  'certificateTemplates': ['Machine'],
                  'dNSHostName': hostname,
                 })
         # Write the dummy pKICertificateTemplate
         template_dn = 'CN=Machine,CN=Certificate Templates,%s' % confdn
+        self.addCleanup(ldb.delete, template_dn)
         ldb.add({'dn': template_dn,
                  'objectClass': 'pKICertificateTemplate',
                 })
 
         with TemporaryDirectory() as dname:
-            ext.process_group_policy([], gpos, dname, dname)
+            try:
+                ext.process_group_policy([], gpos, dname, dname)
+            except Exception as e:
+                self.fail(f"process_group_policy() raised {e}")
             ca_crt = os.path.join(dname, '%s.crt' % ca_cn)
             self.assertTrue(os.path.exists(ca_crt),
                             'Root CA certificate was not requested')
@@ -7169,11 +7174,6 @@ class GPOTests(tests.TestCase):
             self.assertNotIn(b'Workstation', out,
                              'Workstation certificate not removed')
 
-        # Remove the dummy CA, pKIEnrollmentService, and pKICertificateTemplate
-        ldb.delete(certa_dn)
-        ldb.delete(enroll_dn)
-        ldb.delete(template_dn)
-
         # Unstage the Registry.pol file
         unstage_file(reg_pol)
 
@@ -7626,6 +7626,7 @@ class GPOTests(tests.TestCase):
                                'MACHINE/REGISTRY.POL')
         cache_dir = self.lp.get('cache directory')
         store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb'))
+        self.addCleanup(store.log.close)
 
         machine_creds = Credentials()
         machine_creds.guess(self.lp)
@@ -7667,28 +7668,40 @@ class GPOTests(tests.TestCase):
         confdn = 'CN=Public Key Services,CN=Services,CN=Configuration,%s' % base_dn
         ca_cn = '%s-CA' % hostname.replace('.', '-')
         certa_dn = 'CN=%s,CN=Certification Authorities,%s' % (ca_cn, confdn)
+        self.addCleanup(ldb.delete, certa_dn)
+
         ldb.add({'dn': certa_dn,
                  'objectClass': 'certificationAuthority',
                  'authorityRevocationList': ['XXX'],
-                 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I',
+                 'cACertificate': dummy_certificate(),
                  'certificateRevocationList': ['XXX'],
                 })
         # Write the dummy pKIEnrollmentService
         enroll_dn = 'CN=%s,CN=Enrollment Services,%s' % (ca_cn, confdn)
+        self.addCleanup(ldb.delete, enroll_dn)
         ldb.add({'dn': enroll_dn,
                  'objectClass': 'pKIEnrollmentService',
-                 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I',
+                 'cACertificate': dummy_certificate(),
                  'certificateTemplates': ['Machine'],
                  'dNSHostName': hostname,
                 })
         # Write the dummy pKICertificateTemplate
         template_dn = 'CN=Machine,CN=Certificate Templates,%s' % confdn
+        try:
+            ldb.delete(template_dn)
+        except _ldb.LdbError:
+            pass
+
+        self.addCleanup(ldb.delete, template_dn)
         ldb.add({'dn': template_dn,
                  'objectClass': 'pKICertificateTemplate',
                 })
 
         with TemporaryDirectory() as dname:
-            ext.process_group_policy([], gpos, dname, dname)
+            try:
+                ext.process_group_policy([], gpos, dname, dname)
+            except Exception as e:
+                self.fail(f"process_group_policy() raised {e}")
             ca_list = [ca_cn, 'example0-com-CA', 'example1-com-CA',
                        'example2-com-CA']
             for ca in ca_list:
@@ -7751,11 +7764,6 @@ class GPOTests(tests.TestCase):
             self.assertNotIn(b'Workstation', out,
                              'Workstation certificate not removed')
 
-        # Remove the dummy CA, pKIEnrollmentService, and pKICertificateTemplate
-        ldb.delete(certa_dn)
-        ldb.delete(enroll_dn)
-        ldb.delete(template_dn)
-
         # Unstage the Registry.pol file
         unstage_file(reg_pol)
 
diff -Npur samba-4.23.7/python/samba/tests/smb3unix.py samba-4.23.8/python/samba/tests/smb3unix.py
--- samba-4.23.7/python/samba/tests/smb3unix.py	2026-01-23 11:53:40.925187000 +0100
+++ samba-4.23.8/python/samba/tests/smb3unix.py	2026-05-15 15:49:15.101977600 +0200
@@ -446,7 +446,7 @@ class Smb3UnixTests(samba.tests.libsmb.L
 
             wire_mode = libsmb.unix_mode_to_wire(0o600)
             f,_,cc_out = c.create_ex('\\reparse',
-                                     DesiredAccess=security.SEC_STD_ALL,
+                                     DesiredAccess=security.SEC_FILE_WRITE_ATTRIBUTE,
                                      CreateDisposition=libsmb.FILE_CREATE,
                                      CreateContexts=[posix_context(wire_mode)])
 
@@ -460,7 +460,7 @@ class Smb3UnixTests(samba.tests.libsmb.L
 
             wire_mode = libsmb.unix_mode_to_wire(0o600)
             f,_,cc_out = c.create_ex('\\reparse',
-                                     DesiredAccess=security.SEC_STD_ALL,
+                                     DesiredAccess=security.SEC_FILE_WRITE_ATTRIBUTE,
                                      CreateDisposition=libsmb.FILE_OPEN,
                                      CreateContexts=[posix_context(wire_mode)])
             c.close(f)
diff -Npur samba-4.23.7/selftest/knownfail.d/gpo-auto-enrol samba-4.23.8/selftest/knownfail.d/gpo-auto-enrol
--- samba-4.23.7/selftest/knownfail.d/gpo-auto-enrol	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/selftest/knownfail.d/gpo-auto-enrol	2026-05-15 15:49:15.103977700 +0200
@@ -0,0 +1 @@
+^samba\.tests\.gpo\.samba\.tests\.gpo\.GPOTests\.test_advanced_gp_cert_auto_enroll_ext\(ad_dc:local\)
diff -Npur samba-4.23.7/selftest/tests.py samba-4.23.8/selftest/tests.py
--- samba-4.23.7/selftest/tests.py	2026-01-23 11:53:40.949192800 +0100
+++ samba-4.23.8/selftest/tests.py	2026-05-15 15:49:15.106977700 +0200
@@ -569,6 +569,8 @@ plantestsuite("samba.unittests.sys_rw",
               [os.path.join(bindir(), "default/lib/util/test_sys_rw")])
 plantestsuite("samba.unittests.stable_sort", "none",
               [os.path.join(bindir(), "default/lib/util/test_stable_sort")])
+plantestsuite("samba.unittests.test_string_sub", "none",
+              [os.path.join(bindir(), "test_string_sub")])
 plantestsuite("samba.unittests.ntlm_check", "none",
               [os.path.join(bindir(), "default/libcli/auth/test_ntlm_check")])
 plantestsuite("samba.unittests.gnutls", "none",
@@ -583,6 +585,8 @@ plantestsuite("samba.unittests.test_oLsc
               [os.path.join(bindir(), "default/source4/utils/oLschema2ldif/test_oLschema2ldif")])
 plantestsuite("samba.unittests.auth.sam", "none",
               [os.path.join(bindir(), "test_auth_sam")])
+plantestsuite("samba.unittests.test_rpc_samr", "none",
+              [os.path.join(bindir(), "test_rpc_samr")])
 if have_heimdal_support and not using_system_gssapi:
     plantestsuite("samba.unittests.auth.heimdal_gensec_unwrap_des", "none",
                   [valgrindify(os.path.join(bindir(), "test_heimdal_gensec_unwrap_des"))])
diff -Npur samba-4.23.7/source3/lib/substitute.c samba-4.23.8/source3/lib/substitute.c
--- samba-4.23.7/source3/lib/substitute.c	2026-01-23 11:53:40.977199600 +0100
+++ samba-4.23.8/source3/lib/substitute.c	2026-05-15 15:49:15.108977800 +0200
@@ -317,6 +317,7 @@ char *talloc_sub_basic(TALLOC_CTX *mem_c
 	}
 
 	tmp_ctx = talloc_stackframe();
+	a_string = talloc_steal(tmp_ctx, a_string);
 
 	for (s = a_string; (p = strchr_m(s, '%')); s = a_string + (p - b)) {
 
@@ -478,6 +479,7 @@ error:
 	TALLOC_FREE(a_string);
 
 done:
+	a_string = talloc_steal(mem_ctx, a_string);
 	TALLOC_FREE(tmp_ctx);
 	return a_string;
 }
diff -Npur samba-4.23.7/source3/lib/substitute_generic.c samba-4.23.8/source3/lib/substitute_generic.c
--- samba-4.23.7/source3/lib/substitute_generic.c	2026-01-23 11:53:40.977199600 +0100
+++ samba-4.23.8/source3/lib/substitute_generic.c	2026-05-15 15:49:15.108977800 +0200
@@ -37,71 +37,38 @@ char *realloc_string_sub2(char *string,
 			bool remove_unsafe_characters,
 			bool allow_trailing_dollar)
 {
-	char *p, *in;
-	char *s;
-	ssize_t ls,lp,li,ld, i;
+	const char *unsafe_characters = NULL;
+	char safe_character = '\0';
+	bool ok;
 
 	if (!insert || !pattern || !*pattern || !string || !*string)
 		return NULL;
 
-	s = string;
+	if (remove_unsafe_characters) {
+		unsafe_characters = STRING_SUB_UNSAFE_CHARACTERS;
+		safe_character = '_';
+	}
 
-	in = talloc_strdup(talloc_tos(), insert);
-	if (!in) {
-		DEBUG(0, ("realloc_string_sub: out of memory!\n"));
+	ok = realloc_string_sub_raw(&string,
+				    pattern,
+				    insert,
+				    false,  /* replace_once */
+				    allow_trailing_dollar,
+				    unsafe_characters,
+				    safe_character);
+	if (!ok) {
+		DBG_ERR("out of memory, realloc_string_sub_raw()!\n");
+		/*
+		 * The calling convention of realloc_string_sub2()
+		 * is very strange regarding stale string pointers.
+		 *
+		 * It is assumed the given string was allocated
+		 * on talloc_tos(), so we just don't touch
+		 * it at all here...
+		 */
 		return NULL;
 	}
-	ls = (ssize_t)strlen(s);
-	lp = (ssize_t)strlen(pattern);
-	li = (ssize_t)strlen(insert);
-	ld = li - lp;
-	for (i=0;i<li;i++) {
-		switch (in[i]) {
-			case '$':
-				/* allow a trailing $
-				 * (as in machine accounts) */
-				if (allow_trailing_dollar && (i == li - 1 )) {
-					break;
-				}
-				FALL_THROUGH;
-			case '`':
-			case '"':
-			case '\'':
-			case ';':
-			case '%':
-			case '\r':
-			case '\n':
-				if ( remove_unsafe_characters ) {
-					in[i] = '_';
-					break;
-				}
-				FALL_THROUGH;
-			default:
-				/* ok */
-				break;
-		}
-	}
 
-	while ((p = strstr_m(s,pattern))) {
-		if (ld > 0) {
-			int offset = PTR_DIFF(s,string);
-			string = talloc_realloc(NULL, string, char, ls + ld + 1);
-			if (!string) {
-				DEBUG(0, ("realloc_string_sub: "
-					"out of memory!\n"));
-				talloc_free(in);
-				return NULL;
-			}
-			p = string + offset + (p - s);
-		}
-		if (li != lp) {
-			memmove(p+li,p+lp,strlen(p+lp)+1);
-		}
-		memcpy(p, in, li);
-		s = p + li;
-		ls += ld;
-	}
-	talloc_free(in);
 	return string;
 }
 
diff -Npur samba-4.23.7/source3/modules/util_reparse.c samba-4.23.8/source3/modules/util_reparse.c
--- samba-4.23.7/source3/modules/util_reparse.c	2026-01-23 11:53:41.017209300 +0100
+++ samba-4.23.8/source3/modules/util_reparse.c	2026-05-15 15:49:15.115977800 +0200
@@ -320,6 +320,14 @@ NTSTATUS fsctl_set_reparse_point(struct
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
+	if ((fsp->fsp_name->twrp != 0) ||
+	    ((fsp->access_mask &
+	      (SEC_FILE_WRITE_DATA | SEC_FILE_WRITE_ATTRIBUTE)) == 0))
+	{
+		DBG_DEBUG("Access denied on a readonly handle\n");
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
 	status = reparse_buffer_check(in_data,
 				      in_len,
 				      &reparse_tag,
@@ -390,6 +398,14 @@ NTSTATUS fsctl_del_reparse_point(struct
 	uint32_t dos_mode;
 	int ret;
 
+	if ((fsp->fsp_name->twrp != 0) ||
+	    ((fsp->access_mask &
+	      (SEC_FILE_WRITE_DATA | SEC_FILE_WRITE_ATTRIBUTE)) == 0))
+	{
+		DBG_DEBUG("Access denied on a readonly handle\n");
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
 	status = fsctl_get_reparse_tag(fsp, &existing_tag);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
diff -Npur samba-4.23.7/source3/modules/vfs_worm.c samba-4.23.8/source3/modules/vfs_worm.c
--- samba-4.23.7/source3/modules/vfs_worm.c	2026-01-23 11:53:41.029212200 +0100
+++ samba-4.23.8/source3/modules/vfs_worm.c	2026-05-15 15:49:15.119978000 +0200
@@ -218,13 +218,35 @@ static int vfs_worm_renameat(vfs_handle_
 			     const struct smb_filename *smb_fname_dst,
 			     const struct vfs_rename_how *how)
 {
+	struct stat_ex dst_st;
+	int ret;
+
 	if (is_readonly(handle, smb_fname_src)) {
 		errno = EACCES;
 		return -1;
 	}
 
-	return SMB_VFS_NEXT_RENAMEAT(
-		handle, srcfsp, smb_fname_src, dstfsp, smb_fname_dst, how);
+	/* Check if destination is WORM-protected (fixes CVE-2026-2340) */
+	ret = SMB_VFS_FSTATAT(handle->conn,
+			      dstfsp,
+			      smb_fname_dst,
+			      &dst_st,
+			      AT_SYMLINK_NOFOLLOW);
+	if (ret == 0) {
+		struct smb_filename dst_with_stat = *smb_fname_dst;
+		dst_with_stat.st = dst_st;
+		if (is_readonly(handle, &dst_with_stat)) {
+			errno = EACCES;
+			return -1;
+		}
+	}
+
+	return SMB_VFS_NEXT_RENAMEAT(handle,
+				     srcfsp,
+				     smb_fname_src,
+				     dstfsp,
+				     smb_fname_dst,
+				     how);
 }
 
 static int vfs_worm_fsetxattr(struct vfs_handle_struct *handle,
diff -Npur samba-4.23.7/source3/printing/print_generic.c samba-4.23.8/source3/printing/print_generic.c
--- samba-4.23.7/source3/printing/print_generic.c	2026-01-23 11:53:41.045216000 +0100
+++ samba-4.23.8/source3/printing/print_generic.c	2026-05-15 15:49:15.120977900 +0200
@@ -19,6 +19,7 @@
 
 #include "includes.h"
 #include "lib/util/util_file.h"
+#include "lib/util/util_str_escape.h"
 #include "printing.h"
 #include "smbd/proto.h"
 #include "source3/lib/substitute.h"
@@ -207,6 +208,52 @@ static int generic_queue_get(const char
 	return qcount;
 }
 
+static const char *replace_print_cmd_J(TALLOC_CTX *mem_ctx,
+				       const char *orig_cmd,
+				       const char *unsafe_jobname,
+				       const char *fallback_jobname)
+{
+	char *cmd = NULL;
+	bool modified = false;
+	bool masked = false;
+	bool mixed_fallback = false;
+
+	/*
+	 * This replaces unsafe characters with '_'.
+	 * We also mask forward and backslash here.
+	 *
+	 * Then it replaces %J with an single quoted
+	 * version of the masked jobname or it falls
+	 * back to fallback_jobname is the print command
+	 * uses strange mixed quoting.
+	 */
+
+#define JOBNAME_UNSAFE_CHARACTERS \
+	STRING_SUB_UNSAFE_CHARACTERS "/\\"
+
+	cmd = talloc_string_sub_unsafe(mem_ctx,
+				       orig_cmd,
+				       'J',
+				       unsafe_jobname,
+				       JOBNAME_UNSAFE_CHARACTERS,
+				       '_',
+				       fallback_jobname,
+				       &modified,
+				       &masked,
+				       &mixed_fallback);
+	if (cmd == NULL) {
+		return NULL;
+	}
+
+	/*
+	 * The caller already checked talloc_string_sub_mixed_quoting()
+	 * and warned the admin, so we don't check mixed_fallback
+	 * here
+	 */
+
+	return cmd;
+}
+
 /****************************************************************************
  Submit a file for printing - called from print_job_end()
 ****************************************************************************/
@@ -222,11 +269,12 @@ static int generic_job_submit(int snum,
 	char *print_directory = NULL;
 	char *wd = NULL;
 	char *p = NULL;
-	char *jobname = NULL;
+	const char *print_cmd = NULL;
 	TALLOC_CTX *ctx = talloc_tos();
 	fstring job_page_count, job_size;
 	print_queue_struct *q = NULL;
 	print_status_struct status;
+	const char *jobname = "No Document Name";
 
 	/* we print from the directory path to give the best chance of
            parsing the lpq output */
@@ -255,24 +303,48 @@ static int generic_job_submit(int snum,
 		return -1;
 	}
 
-	jobname = talloc_strdup(ctx, pjob->jobname);
-	if (!jobname) {
-		ret = -1;
-		goto out;
+	if (pjob->jobname[0] != '\0') {
+		jobname = pjob->jobname;
 	}
-	jobname = talloc_string_sub(ctx, jobname, "'", "_");
-	if (!jobname) {
-		ret = -1;
-		goto out;
+
+	print_cmd = lp_print_command(snum);
+	if (print_cmd != NULL) {
+		const char *invalid_jobname = "__CVE-2026-4480_FallbackJobname__";
+
+		if (talloc_string_sub_mixed_quoting(print_cmd, 'J')) {
+			/*
+			 * The admin used a strange mixture of
+			 * single and double quotes, fallback
+			 * to InvalidDocumentName and warn about
+			 * it, so that the admin can adjust to
+			 * the use single quotes directly around %J,
+			 * e.g. '%J'.
+			 */
+			jobname = invalid_jobname;
+			D_WARNING("CVE-2026-4480: printer %s "
+				  "strange quoting in 'print command', "
+				  "falling back to jobname=%s, "
+				  "use testparm to fix the configuration\n",
+				  lp_printername(talloc_tos(), lp_sub, snum),
+				  invalid_jobname);
+		}
+
+		print_cmd = replace_print_cmd_J(ctx,
+						print_cmd,
+						jobname,
+						invalid_jobname);
+		if (!print_cmd) {
+			ret = -1;
+			goto out;
+		}
 	}
 	fstr_sprintf(job_page_count, "%d", pjob->page_count);
 	fstr_sprintf(job_size, "%zu", pjob->size);
 
 	/* send it to the system spooler */
 	ret = print_run_command(snum, lp_printername(talloc_tos(), lp_sub, snum), True,
-			lp_print_command(snum), NULL,
+			print_cmd, NULL,
 			"%s", p,
-			"%J", jobname,
 			"%f", p,
 			"%z", job_size,
 			"%c", job_page_count,
@@ -293,17 +365,26 @@ static int generic_job_submit(int snum,
 		int i;
 		for (i = 0; i < ret; i++) {
 			if (strcmp(q[i].fs_file, p) == 0) {
+				char *le_jobname =
+					log_escape(talloc_tos(), jobname);
+
 				pjob->sysjob = q[i].sysjob;
 				DEBUG(5, ("new job %u (%s) matches sysjob %d\n",
-					  pjob->jobid, jobname, pjob->sysjob));
+					  pjob->jobid, le_jobname, pjob->sysjob));
+
+				TALLOC_FREE(le_jobname);
 				break;
 			}
 		}
 		ret = 0;
 	}
 	if (pjob->sysjob == -1) {
+		char *le_jobname = log_escape(talloc_tos(), jobname);
+
 		DEBUG(2, ("failed to get sysjob for job %u (%s), tracking as "
-			  "Unix job\n", pjob->jobid, jobname));
+			  "Unix job\n", pjob->jobid, le_jobname));
+
+		TALLOC_FREE(le_jobname);
 	}
 
 
diff -Npur samba-4.23.7/source3/rpc_server/samr/srv_samr_chgpasswd.c samba-4.23.8/source3/rpc_server/samr/srv_samr_chgpasswd.c
--- samba-4.23.7/source3/rpc_server/samr/srv_samr_chgpasswd.c	2026-01-23 11:53:41.065220800 +0100
+++ samba-4.23.8/source3/rpc_server/samr/srv_samr_chgpasswd.c	2026-05-15 15:49:15.124977800 +0200
@@ -54,6 +54,7 @@
 #include "passdb.h"
 #include "auth.h"
 #include "lib/util/sys_rw.h"
+#include "lib/util/util_str_escape.h"
 #include "librpc/rpc/dcerpc_samr.h"
 
 #include "lib/crypto/gnutls_helpers.h"
@@ -1008,27 +1009,118 @@ static bool check_passwd_history(struct
 /***********************************************************
 ************************************************************/
 
+NTSTATUS check_password_complexity_internal(TALLOC_CTX *tosctx,
+					    const char *orig_cmd,
+					    const char *username,
+					    char **cmd_out)
+{
+	const char *fallback_username = "__CVE-2026-4408_FallbackUsername__";
+	const char *inv = NULL;
+	char *cmd = NULL;
+	bool modified = false;
+	bool masked = false;
+	bool mixed_fallback = false;
+
+	*cmd_out = NULL;
+
+	if (username == NULL) {
+		return NT_STATUS_INVALID_USER_PRINCIPAL_NAME;
+	}
+
+	/*
+	 * This catches invalid characters in account names
+	 * which might be problematic passing to a shell script.
+	 */
+	inv = strstr_for_invalid_account_characters(username);
+	if (inv != NULL) {
+		char *le_username = log_escape(tosctx, username);
+
+		DBG_WARNING("username '%s' has invalid or dangerous characters\n",
+			    le_username);
+
+		TALLOC_FREE(le_username);
+
+		return NT_STATUS_INVALID_USER_PRINCIPAL_NAME;
+	}
+
+	/*
+	 * This masks the remaining unsafe characters which
+	 * are not already caught by strstr_for_invalid_account_characters()
+	 * with '_'.
+	 *
+	 * Then it replaces %u with an single quoted
+	 * and/or shell escaped version of the masked username.
+	 */
+	cmd = talloc_string_sub_unsafe(tosctx,
+				       orig_cmd,
+				       'u',
+				       username,
+				       STRING_SUB_UNSAFE_CHARACTERS,
+				       '_',
+				       fallback_username,
+				       &modified,
+				       &masked,
+				       &mixed_fallback);
+	if (cmd == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	/*
+	 * Now warn about unexpected values
+	 */
+
+	if (mixed_fallback) {
+		D_WARNING("CVE-2026-4408: "
+			  "strange quoting in 'check password script', "
+			  "falling back to replace %%u with %s, "
+			  "use testparm to fix the configuration\n",
+			  fallback_username);
+		D_WARNING("CVE-2026-4408: "
+			  "You should use '%%u', or SAMBA_CPS_ACCOUNT_NAME "
+			  "inside of 'check password script'.\n");
+	} else if (masked) {
+		char *le_username = log_escape(tosctx, username);
+
+		D_WARNING("CVE-2026-4408: "
+			  "replaced %%u with masked value instead of: %s\n",
+			  le_username);
+		D_WARNING("CVE-2026-4408: "
+			  "You should use SAMBA_CPS_ACCOUNT_NAME inside "
+			  "'check password script' instead of %%u.\n");
+
+		TALLOC_FREE(le_username);
+	}
+
+	*cmd_out = cmd;
+	return NT_STATUS_OK;
+}
+
+
 NTSTATUS check_password_complexity(const char *username,
 				   const char *fullname,
 				   const char *password,
 				   enum samPwdChangeReason *samr_reject_reason)
 {
+	int check_ret;
+	NTSTATUS status;
 	TALLOC_CTX *tosctx = talloc_tos();
 	const struct loadparm_substitution *lp_sub =
 		loadparm_s3_global_substitution();
-	int check_ret;
-	char *cmd;
+	const char *orig_cmd = NULL;
+	char *cmd = NULL;
 
-	/* Use external script to check password complexity */
-	if ((lp_check_password_script(tosctx, lp_sub) == NULL)
-	    || (*(lp_check_password_script(tosctx, lp_sub)) == '\0')){
+	orig_cmd = lp_check_password_script(tosctx, lp_sub);
+	if (orig_cmd == NULL || orig_cmd[0] == '\0') {
 		return NT_STATUS_OK;
 	}
 
-	cmd = talloc_string_sub(tosctx, lp_check_password_script(tosctx, lp_sub), "%u",
-				username);
-	if (!cmd) {
-		return NT_STATUS_PASSWORD_RESTRICTION;
+	/* note we don't use 'fullname' or 'password' here */
+	status = check_password_complexity_internal(tosctx,
+						    orig_cmd,
+						    username,
+						    &cmd);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
 	}
 
 	check_ret = setenv("SAMBA_CPS_ACCOUNT_NAME", username, 1);
diff -Npur samba-4.23.7/source3/rpc_server/samr/srv_samr_nt.c samba-4.23.8/source3/rpc_server/samr/srv_samr_nt.c
--- samba-4.23.7/source3/rpc_server/samr/srv_samr_nt.c	2026-01-23 11:53:41.065220800 +0100
+++ samba-4.23.8/source3/rpc_server/samr/srv_samr_nt.c	2026-05-15 15:49:15.125978000 +0200
@@ -7500,6 +7500,14 @@ NTSTATUS _samr_ValidatePassword(struct p
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
+	if (lp_server_role() <= ROLE_DOMAIN_MEMBER) {
+		/*
+		 * We only want this on DCs
+		 */
+		p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
 	if (r->in.level < 1 || r->in.level > 3) {
 		return NT_STATUS_INVALID_INFO_CLASS;
 	}
diff -Npur samba-4.23.7/source3/rpc_server/samr/srv_samr_util.h samba-4.23.8/source3/rpc_server/samr/srv_samr_util.h
--- samba-4.23.7/source3/rpc_server/samr/srv_samr_util.h	2026-01-23 11:53:41.065220800 +0100
+++ samba-4.23.8/source3/rpc_server/samr/srv_samr_util.h	2026-05-15 15:49:15.125978000 +0200
@@ -79,6 +79,11 @@ NTSTATUS pass_oem_change(char *user, con
 			 uchar password_encrypted_with_nt_hash[516],
 			 const uchar old_nt_hash_encrypted[16],
 			 enum samPwdChangeReason *reject_reason);
+
+NTSTATUS check_password_complexity_internal(TALLOC_CTX *mem_ctx,
+					    const char *_orig_cmd,
+					    const char *username,
+					    char **cmd_out);
 NTSTATUS check_password_complexity(const char *username,
 				   const char *fullname,
 				   const char *password,
diff -Npur samba-4.23.7/source3/script/tests/test_worm.sh samba-4.23.8/source3/script/tests/test_worm.sh
--- samba-4.23.7/source3/script/tests/test_worm.sh	2026-01-23 11:53:41.081224700 +0100
+++ samba-4.23.8/source3/script/tests/test_worm.sh	2026-05-15 15:49:15.126978000 +0200
@@ -40,6 +40,7 @@ do_cleanup()
 		#subshell.
 		cd "$share_test_dir" || return
 		rm -f must-be-deleted must-not-be-deleted must-be-deleted-after-ctime-refresh
+		rm -f must-not-be-overwritten sentinel-value
 	)
 	rm -f $tmpfile
 }
@@ -51,6 +52,10 @@ do_cleanup
 
 tmpfile=$PREFIX/smbclient_interactive_prompt_commands
 
+tmp_sentinel=$PREFIX/sentinel_value
+SENTINEL_VALUE='1'
+echo $SENTINEL_VALUE > $tmp_sentinel
+
 test_worm()
 {
 	# use echo because helo scripts don't support variables
@@ -58,6 +63,7 @@ test_worm()
 put $tmpfile must-be-deleted
 put $tmpfile must-be-deleted-after-ctime-refresh
 put $tmpfile must-not-be-deleted
+put $tmpfile must-not-be-overwritten
 del must-be-deleted
 quit" > $tmpfile
 	# make sure the directory is not too old for worm:
@@ -97,6 +103,30 @@ quit" > $tmpfile
 		printf "$0: ERROR: must-not-be-deleted WAS deleted\n"
 		return 1
 	}
+
+	# Check we can't change a protected file by renaming over it.
+	# The source file needs to recently created or access will be
+	# denied before RENAME_AT is reached, which is the thing we
+	# want to test.
+	original_contents=`cat $share_test_dir/must-not-be-overwritten`
+	echo "
+put $tmp_sentinel sentinel-value
+rename sentinel-value must-not-be-overwritten  -f
+quit" > $tmpfile
+	cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/worm -I$SERVER_IP $ADDARGS < $tmpfile 2>&1'
+	eval echo "$cmd"
+	out=$(eval "$cmd")
+	new_contents=`cat $share_test_dir/must-not-be-overwritten`
+
+	if [ "$new_contents" = "$SENTINEL_VALUE" ]; then
+	    echo "must-not-be-overwritten was overwritten"
+	    return 1
+	fi
+	if [ "$new_contents" != "$original_contents" ]; then
+	    echo "must-not-be-overwritten was changed (but not precisely overwritten)"
+	    return 1
+	fi
+
 	# if we're not root, return here:
 	test "$UID" = "0" ||  {
 		return 0
diff -Npur samba-4.23.7/source3/torture/test_rpc_samr.c samba-4.23.8/source3/torture/test_rpc_samr.c
--- samba-4.23.7/source3/torture/test_rpc_samr.c	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/source3/torture/test_rpc_samr.c	2026-05-15 15:49:15.132978000 +0200
@@ -0,0 +1,358 @@
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <sys/stat.h>
+#include <cmocka.h>
+#include "includes.h"
+#include "talloc.h"
+#include "libcli/util/ntstatus.h"
+#include "../librpc/gen_ndr/samr.h"
+#include "rpc_server/samr/srv_samr_util.h"
+
+/* set SAMR_DEBUG_VERBOSE to true to print more. */
+#define SAMR_DEBUG_VERBOSE true
+
+#if SAMR_DEBUG_VERBOSE
+#define debug_message(...) print_message(__VA_ARGS__)
+#else
+#define debug_message(...) /* debug_message */
+#endif
+
+static int setup_talloc_context(void **state)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(NULL);
+	*state = mem_ctx;
+	return 0;
+}
+
+static int teardown_talloc_context(void **state)
+{
+	TALLOC_CTX *mem_ctx = *state;
+	TALLOC_FREE(mem_ctx);
+	return 0;
+}
+
+struct cmd_expansion {
+	const char *lp_cmd;
+	const char *username;
+	const char *result_cmd;
+	NTSTATUS result_code;
+};
+
+static struct cmd_expansion expansions[] = {
+	{
+		"/bin/echo '%u'",
+		"bob",
+		"/bin/echo 'bob'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo %u",
+		"bob",
+		"/bin/echo 'bob'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo %u",
+		"bob'",
+		"/bin/echo 'bob_'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo %u",
+		"bob\'",
+		"/bin/echo 'bob_'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo %u",
+		"bob'''",
+		"/bin/echo 'bob___'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo %u",
+		"bob*",
+		NULL,
+		NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+	},
+	{
+		"/bin/echo %u",
+		"bob\"",
+		NULL,
+		NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+	},
+	{
+		"/bin/echo '%u",
+		"bob bob bob",
+		"/bin/echo '__CVE-2026-4408_FallbackUsername__",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo \"%u\"",
+		" ",
+		"/bin/echo ' '",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo \"--uu=%u\"",
+		"bob",
+		"/bin/echo \"--uu=__CVE-2026-4408_FallbackUsername__\"",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo \"--uu=%u\"",
+		"bob !0",
+		"/bin/echo \"--uu=__CVE-2026-4408_FallbackUsername__\"",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo %u",
+		"!0",
+		"/bin/echo '!0'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo \"--uu=%u\"",
+		"bob \\",
+		NULL,
+		NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+	},
+	{
+		"/bin/echo --uu='%u'",
+		"bob >> x",
+		NULL,
+		NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+	},
+	{
+		"/bin/echo '--uu=%u\"",
+		"bob",
+		"/bin/echo '--uu=__CVE-2026-4408_FallbackUsername__\"",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo --uu='%u'",
+		"bob",
+		"/bin/echo --uu='bob'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo --uu'=%u'",
+		"bob",
+		"/bin/echo --uu'=__CVE-2026-4408_FallbackUsername__'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo --uu'=%u'",
+		"`ls`",
+		"/bin/echo --uu'=__CVE-2026-4408_FallbackUsername__'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo --uu'=%u'",
+		"$(ls)",
+		"/bin/echo --uu'=__CVE-2026-4408_FallbackUsername__'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo --uu='%u'",
+		"$(ls)",
+		"/bin/echo --uu='_(ls)'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo --uu=\"'%u'\"",
+		"bob",
+		"/bin/echo --uu=\"'bob'\"",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo --uu='%u' --yy='%u' '%u' %u",
+		"bob",
+		"/bin/echo --uu='bob' --yy='bob' 'bob' __CVE-2026-4408_FallbackUsername__",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo --uu=%u%u'' %user 50%u",
+		"bob",
+		"/bin/echo --uu=__CVE-2026-4408_FallbackUsername____CVE-2026-4408_FallbackUsername__'' __CVE-2026-4408_FallbackUsername__ser 50__CVE-2026-4408_FallbackUsername__",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo %u",
+		"!!",
+		"/bin/echo '!!'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo %u",
+		">xxx",
+		NULL,
+		NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+	},
+	{
+		"/bin/echo %u",
+		"\\",
+		NULL,
+		NT_STATUS_INVALID_USER_PRINCIPAL_NAME
+	},
+	{
+		"/bin/echo %u",
+		"3",
+		"/bin/echo '3'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo '%u'",
+		"3$",
+		"/bin/echo '3_'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo '%u'",
+		"comp$",
+		"/bin/echo 'comp_'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo '%u'",
+		"3$3",
+		"/bin/echo '3_3'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo '%u'",
+		"q $3",
+		"/bin/echo 'q _3'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo -s '%u' %u",
+		"āāā",
+		"/bin/echo -s 'āāā' __CVE-2026-4408_FallbackUsername__",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo -s '%u' %u",
+		"-āāā",
+		"/bin/echo -s '_āāā' __CVE-2026-4408_FallbackUsername__",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo -s %u",
+		"āāā",
+		"/bin/echo -s 'āāā'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo -s %u",
+		"a -a",
+		"/bin/echo -s 'a -a'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo -s=%u %u",
+		"ā -a",
+		"/bin/echo -s='ā -a' 'ā -a'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo -s=\"%u %u\"",
+		"ā -a",
+		"/bin/echo -s=\"__CVE-2026-4408_FallbackUsername__ __CVE-2026-4408_FallbackUsername__\"",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo -m='fridge' %u",
+		"ā -x -ß",
+		"/bin/echo -m='fridge' __CVE-2026-4408_FallbackUsername__",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo -m='fridge' %u",
+		"-ā -a",
+		"/bin/echo -m='fridge' __CVE-2026-4408_FallbackUsername__",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo %u",
+		"-n",
+		"/bin/echo '_n'",
+		NT_STATUS_OK
+	},
+	{
+		"/bin/echo %u",
+		"o'clock",
+		"/bin/echo 'o_clock'",
+		NT_STATUS_OK
+	},
+};
+
+static void test_expansions(void **state)
+{
+	TALLOC_CTX *mem_ctx = *state;
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(expansions); i++) {
+		struct cmd_expansion t = expansions[i];
+		char *result_cmd = NULL;
+		NTSTATUS status;
+
+		status = check_password_complexity_internal(mem_ctx,
+							    t.lp_cmd,
+							    t.username,
+							    &result_cmd);
+		if (NT_STATUS_IS_OK(t.result_code) && NT_STATUS_IS_OK(status)) {
+			int cmp;
+
+			cmp = strcmp(t.result_cmd, result_cmd);
+			if (cmp == 0) {
+				debug_message("[%zu] «%s» «%s»   ->   «%s», nstatus %s; AS EXPECTED\n",
+					      i, t.lp_cmd,
+					      t.username,
+					      result_cmd,
+					      nt_errstr(status));
+			} else {
+				debug_message("[%zu] «%s» «%s», nstatus %s; "
+					      "expected   «%s»   got  «%s»\033[1;31m BAD! \033[0m\n",
+					      i, t.lp_cmd,
+					      t.username,
+					      nt_errstr(status),
+					      t.result_cmd,
+					      result_cmd);
+			}
+			assert_int_equal(cmp, 0);
+		} else if (NT_STATUS_EQUAL(status, t.result_code)) {
+			debug_message("[%zu] «%s» «%s», nstatus %s FAILED AS EXPECTED\n",
+				      i, t.lp_cmd,
+				      t.username,
+				      nt_errstr(status));
+		} else {
+			debug_message("[%zu] «%s» «%s» -> «%s», nstatus %s; "
+				      "EXPECTED result «%s»   ntstatus %s; \033[1;31m BAD! \033[0m\n",
+				      i, t.lp_cmd,
+				      t.username,
+				      result_cmd,
+				      nt_errstr(status),
+				      t.result_cmd,
+				      nt_errstr(t.result_code));
+			assert_int_equal(true, false);
+		}
+	}
+	debug_message("ALL correct\n");
+}
+
+int main(void)
+{
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test(test_expansions),
+	};
+	if (!isatty(1)) {
+		cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+	}
+	return cmocka_run_group_tests(tests,
+				      setup_talloc_context,
+				      teardown_talloc_context);
+}
diff -Npur samba-4.23.7/source3/torture/wscript_build samba-4.23.8/source3/torture/wscript_build
--- samba-4.23.7/source3/torture/wscript_build	2026-01-23 11:53:41.117233500 +0100
+++ samba-4.23.8/source3/torture/wscript_build	2026-05-15 15:49:15.133978100 +0200
@@ -133,3 +133,9 @@ bld.SAMBA3_BINARY('vfstest',
                       SMBREADLINE
                       ''',
                  for_selftest=True)
+
+bld.SAMBA3_BINARY('test_rpc_samr',
+                 source='test_rpc_samr.c',
+                 deps='''RPC_SERVICE cmocka
+                 ''',
+                 for_selftest=True)
diff -Npur samba-4.23.7/source3/utils/testparm.c samba-4.23.8/source3/utils/testparm.c
--- samba-4.23.7/source3/utils/testparm.c	2026-01-23 11:53:41.133237400 +0100
+++ samba-4.23.8/source3/utils/testparm.c	2026-05-15 15:49:15.135978000 +0200
@@ -359,6 +359,7 @@ static int do_global_checks(void)
 	const char **lp_ptr = NULL;
 	const struct loadparm_substitution *lp_sub =
 		loadparm_s3_global_substitution();
+	const char *check_pw_script = NULL;
 	int ival;
 
 	fprintf(stderr, "\n");
@@ -831,6 +832,17 @@ static int do_global_checks(void)
 #endif
 	}
 
+	check_pw_script = lp_check_password_script(talloc_tos(), lp_sub);
+	if (talloc_string_sub_mixed_quoting(check_pw_script, 'u')) {
+		fprintf(stderr,
+			"WARNING: You are using 'check password script' "
+			"with mixed quoting and %%u.\n"
+			"CVE-2026-4408 changed the way %%u substitution works. \n"
+			"You should use the SAMBA_CPS_ACCOUNT_NAME "
+			"environment variable exported to the script, or\n"
+			"at least use single quotes (directly) around '%%u'.\n\n");
+	}
+
 	return ret;
 }
 
@@ -928,6 +940,14 @@ static void do_per_share_checks(int s)
 			"parameter is ignored when using CUPS libraries.\n\n",
 			lp_servicename(talloc_tos(), lp_sub, s));
 	}
+	if (talloc_string_sub_mixed_quoting(lp_print_command(s), 'J')) {
+		fprintf(stderr,
+			"WARNING: Service %s defines a 'print command' "
+			"with mixed quoting and %%J.\n"
+			"CVE-2026-4480 changed the way %%J substitution works.\n"
+			"You should use single quotes (directly) around '%%J'.\n\n",
+			lp_servicename(talloc_tos(), lp_sub, s));
+	}
 
 	vfs_objects = lp_vfs_objects(s);
 	if (vfs_objects && str_list_check(vfs_objects, "fruit")) {
diff -Npur samba-4.23.7/source4/nbt_server/wins/winsserver.c samba-4.23.8/source4/nbt_server/wins/winsserver.c
--- samba-4.23.7/source4/nbt_server/wins/winsserver.c	2026-01-23 11:53:41.221258400 +0100
+++ samba-4.23.8/source4/nbt_server/wins/winsserver.c	2026-05-15 15:49:15.142978200 +0200
@@ -460,16 +460,34 @@ static void nbtd_winsserver_register(str
 	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 						       struct nbtd_interface);
 	struct wins_server *winssrv = iface->nbtsrv->winssrv;
-	struct nbt_name *name = &packet->questions[0].name;
+	struct nbt_name *name = NULL;
 	struct winsdb_record *rec;
 	uint8_t rcode = NBT_RCODE_OK;
-	uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
-	const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
+	struct nbt_res_rec *additional = NULL;
+	uint16_t nb_flags;
+	const char *address = NULL;
+	struct nbt_rdata_address *addresses = NULL;
 	bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
-	enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
+	enum wrepl_name_type new_type;
 	struct winsdb_addr *winsdb_addr = NULL;
 	bool duplicate_packet;
 
+	NBTD_ASSERT_PACKET(packet, src, packet->qdcount > 0);
+	NBTD_ASSERT_PACKET(packet, src, packet->arcount > 0);
+
+	name = &packet->questions[0].name;
+	additional = packet->additional;
+
+	NBTD_ASSERT_PACKET(packet,
+			   src,
+			   additional[0].rdata.netbios.length > 0);
+
+	addresses = additional[0].rdata.netbios.addresses;
+
+	nb_flags = addresses[0].nb_flags;
+	address = addresses[0].ipaddr;
+	new_type = wrepl_type(nb_flags, name, mhomed);
+
 	/*
 	 * as a special case, the local master browser name is always accepted
 	 * for registration, but never stored, but w2k3 stores it if it's registered
@@ -729,13 +747,17 @@ static void nbtd_winsserver_query(struct
 	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 						       struct nbtd_interface);
 	struct wins_server *winssrv = iface->nbtsrv->winssrv;
-	struct nbt_name *name = &packet->questions[0].name;
+	struct nbt_name *name = NULL;
 	struct winsdb_record *rec;
 	struct winsdb_record *rec_1b = NULL;
 	const char **addresses;
 	const char **addresses_1b = NULL;
 	uint16_t nb_flags = 0;
 
+	NBTD_ASSERT_PACKET(packet, src, packet->qdcount > 0);
+
+	name = &packet->questions[0].name;
+
 	if (name->type == NBT_NAME_MASTER) {
 		goto notfound;
 	}
@@ -871,11 +893,15 @@ static void nbtd_winsserver_release(stru
 	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 						       struct nbtd_interface);
 	struct wins_server *winssrv = iface->nbtsrv->winssrv;
-	struct nbt_name *name = &packet->questions[0].name;
+	struct nbt_name *name = NULL;
 	struct winsdb_record *rec;
 	uint32_t modify_flags = 0;
 	uint8_t ret;
 
+	NBTD_ASSERT_PACKET(packet, src, packet->qdcount > 0);
+
+	name = &packet->questions[0].name;
+
 	if (name->type == NBT_NAME_MASTER) {
 		goto done;
 	}
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/CMakeLists.txt samba-4.23.8/third_party/ngtcp2/crypto/CMakeLists.txt
--- samba-4.23.7/third_party/ngtcp2/crypto/CMakeLists.txt	2026-01-23 11:53:43.273753000 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/CMakeLists.txt	2026-05-15 15:49:15.149978200 +0200
@@ -31,6 +31,12 @@ elseif(ENABLE_OPENSSL)
   message(WARNING "libngtcp2_crypto_quictls library is disabled due to lack of good quictls")
 endif()
 
+if(HAVE_LIBRESSL)
+  add_subdirectory(quictls)
+elseif(ENABLE_OPENSSL)
+  message(WARNING "libngtcp2_crypto_libressl library is disabled due to lack of good LibreSSL")
+endif()
+
 if(HAVE_GNUTLS)
   add_subdirectory(gnutls)
 elseif(ENABLE_GNUTLS)
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/Makefile.am samba-4.23.8/third_party/ngtcp2/crypto/Makefile.am
--- samba-4.23.7/third_party/ngtcp2/crypto/Makefile.am	2026-01-23 11:53:43.273753000 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/Makefile.am	2026-05-15 15:49:15.149978200 +0200
@@ -30,6 +30,10 @@ if HAVE_QUICTLS
 SUBDIRS += quictls
 endif
 
+if HAVE_LIBRESSL
+SUBDIRS += quictls
+endif
+
 if HAVE_GNUTLS
 SUBDIRS += gnutls
 endif
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/boringssl/boringssl.c samba-4.23.8/third_party/ngtcp2/crypto/boringssl/boringssl.c
--- samba-4.23.7/third_party/ngtcp2/crypto/boringssl/boringssl.c	2026-01-23 11:53:43.273753000 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/boringssl/boringssl.c	2026-05-15 15:49:15.149978200 +0200
@@ -39,6 +39,7 @@
 #include <openssl/chacha.h>
 #include <openssl/rand.h>
 
+#include "ngtcp2_macro.h"
 #include "shared.h"
 
 typedef enum ngtcp2_crypto_boringssl_cipher_type {
@@ -401,7 +402,7 @@ int ngtcp2_crypto_decrypt(uint8_t *dest,
 int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
                           const ngtcp2_crypto_cipher_ctx *hp_ctx,
                           const uint8_t *sample) {
-  static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
+  static const uint8_t PLAINTEXT[16] = {0};
   ngtcp2_crypto_boringssl_cipher_ctx *ctx = hp_ctx->native_handle;
   uint32_t counter;
 
@@ -419,7 +420,7 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest,
 #else  /* !defined(WORDS_BIGENDIAN) */
     memcpy(&counter, sample, sizeof(counter));
 #endif /* !defined(WORDS_BIGENDIAN) */
-    CRYPTO_chacha_20(dest, PLAINTEXT, sizeof(PLAINTEXT) - 1, ctx->key,
+    CRYPTO_chacha_20(dest, PLAINTEXT, sizeof(PLAINTEXT), ctx->key,
                      sample + sizeof(counter), counter);
     return 0;
   default:
@@ -435,7 +436,8 @@ int ngtcp2_crypto_read_write_crypto_data
   int rv;
   int err;
 
-  if (SSL_provide_quic_data(
+  if (datalen &&
+      SSL_provide_quic_data(
         ssl,
         ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level(encryption_level),
         data, datalen) != 1) {
@@ -464,6 +466,16 @@ int ngtcp2_crypto_read_write_crypto_data
         }
 
         goto retry;
+      case SSL_ERROR_WANT_X509_LOOKUP:
+      case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION:
+      case SSL_ERROR_WANT_CERTIFICATE_VERIFY:
+        /* It might be better to return this error, but ngtcp2 does
+           not need to know whether handshake has been interrupted or
+           not.  We expect that necessary plumbing should be done by
+           application when handshake is interrupted (e.g., via
+           SSL_PRIVATE_KEY_METHOD).  If it does not work, we will
+           reconsider this. */
+        return 0;
       default:
         return -1;
       }
@@ -564,6 +576,19 @@ int ngtcp2_crypto_get_path_challenge_dat
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
+  return 0;
+}
+
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
+                                              ngtcp2_path_challenge_data *data,
+                                              void *user_data) {
+  (void)conn;
+  (void)user_data;
+
+  if (RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
   return 0;
 }
 
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/boringssl/libngtcp2_crypto_boringssl.pc.in samba-4.23.8/third_party/ngtcp2/crypto/boringssl/libngtcp2_crypto_boringssl.pc.in
--- samba-4.23.7/third_party/ngtcp2/crypto/boringssl/libngtcp2_crypto_boringssl.pc.in	2026-01-23 11:53:43.273753000 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/boringssl/libngtcp2_crypto_boringssl.pc.in	2026-05-15 15:49:15.149978200 +0200
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
 Version: @VERSION@
 Libs: -L${libdir} -lngtcp2_crypto_boringssl
 Cflags: -I${includedir}
+Requires.private: libngtcp2
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/gnutls/gnutls.c samba-4.23.8/third_party/ngtcp2/crypto/gnutls/gnutls.c
--- samba-4.23.7/third_party/ngtcp2/crypto/gnutls/gnutls.c	2026-01-23 11:53:43.273753000 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/gnutls/gnutls.c	2026-05-15 15:49:15.150978300 +0200
@@ -35,6 +35,7 @@
 #include <gnutls/crypto.h>
 #include <string.h>
 
+#include "ngtcp2_macro.h"
 #include "shared.h"
 
 ngtcp2_crypto_aead *ngtcp2_crypto_aead_aes_128_gcm(ngtcp2_crypto_aead *aead) {
@@ -219,14 +220,15 @@ int ngtcp2_crypto_aead_ctx_encrypt_init(
   gnutls_cipher_algorithm_t cipher =
     (gnutls_cipher_algorithm_t)(intptr_t)aead->native_handle;
   gnutls_aead_cipher_hd_t hd;
-  gnutls_datum_t _key;
 
   (void)noncelen;
 
-  _key.data = (void *)key;
-  _key.size = (unsigned int)ngtcp2_crypto_aead_keylen(aead);
-
-  if (gnutls_aead_cipher_init(&hd, cipher, &_key) != 0) {
+  if (gnutls_aead_cipher_init(
+        &hd, cipher,
+        &(gnutls_datum_t){
+          .data = (uint8_t *)key,
+          .size = (unsigned int)ngtcp2_crypto_aead_keylen(aead),
+        }) != 0) {
     return -1;
   }
 
@@ -241,14 +243,15 @@ int ngtcp2_crypto_aead_ctx_decrypt_init(
   gnutls_cipher_algorithm_t cipher =
     (gnutls_cipher_algorithm_t)(intptr_t)aead->native_handle;
   gnutls_aead_cipher_hd_t hd;
-  gnutls_datum_t _key;
 
   (void)noncelen;
 
-  _key.data = (void *)key;
-  _key.size = (unsigned int)ngtcp2_crypto_aead_keylen(aead);
-
-  if (gnutls_aead_cipher_init(&hd, cipher, &_key) != 0) {
+  if (gnutls_aead_cipher_init(
+        &hd, cipher,
+        &(gnutls_datum_t){
+          .data = (uint8_t *)key,
+          .size = (unsigned int)ngtcp2_crypto_aead_keylen(aead),
+        }) != 0) {
     return -1;
   }
 
@@ -266,15 +269,17 @@ void ngtcp2_crypto_aead_ctx_free(ngtcp2_
 int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx,
                                           const ngtcp2_crypto_cipher *cipher,
                                           const uint8_t *key) {
-  gnutls_cipher_algorithm_t _cipher =
+  gnutls_cipher_algorithm_t cph =
     (gnutls_cipher_algorithm_t)(intptr_t)cipher->native_handle;
   gnutls_cipher_hd_t hd;
-  gnutls_datum_t _key;
 
-  _key.data = (void *)key;
-  _key.size = (unsigned int)gnutls_cipher_get_key_size(_cipher);
-
-  if (gnutls_cipher_init(&hd, _cipher, &_key, NULL) != 0) {
+  if (gnutls_cipher_init(
+        &hd, cph,
+        &(gnutls_datum_t){
+          .data = (uint8_t *)key,
+          .size = (unsigned int)gnutls_cipher_get_key_size(cph),
+        },
+        NULL) != 0) {
     return -1;
   }
 
@@ -294,10 +299,17 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *
                                const uint8_t *salt, size_t saltlen) {
   gnutls_mac_algorithm_t prf =
     (gnutls_mac_algorithm_t)(intptr_t)md->native_handle;
-  gnutls_datum_t _secret = {(void *)secret, (unsigned int)secretlen};
-  gnutls_datum_t _salt = {(void *)salt, (unsigned int)saltlen};
 
-  if (gnutls_hkdf_extract(prf, &_secret, &_salt, dest) != 0) {
+  if (gnutls_hkdf_extract(prf,
+                          &(gnutls_datum_t){
+                            .data = (uint8_t *)secret,
+                            .size = (unsigned int)secretlen,
+                          },
+                          &(gnutls_datum_t){
+                            .data = (uint8_t *)salt,
+                            .size = (unsigned int)saltlen,
+                          },
+                          dest) != 0) {
     return -1;
   }
 
@@ -310,10 +322,17 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *d
                               size_t infolen) {
   gnutls_mac_algorithm_t prf =
     (gnutls_mac_algorithm_t)(intptr_t)md->native_handle;
-  gnutls_datum_t _secret = {(void *)secret, (unsigned int)secretlen};
-  gnutls_datum_t _info = {(void *)info, (unsigned int)infolen};
 
-  if (gnutls_hkdf_expand(prf, &_secret, &_info, dest, destlen) != 0) {
+  if (gnutls_hkdf_expand(prf,
+                         &(gnutls_datum_t){
+                           .data = (uint8_t *)secret,
+                           .size = (unsigned int)secretlen,
+                         },
+                         &(gnutls_datum_t){
+                           .data = (uint8_t *)info,
+                           .size = (unsigned int)infolen,
+                         },
+                         dest, destlen) != 0) {
     return -1;
   }
 
@@ -328,18 +347,32 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, si
     (gnutls_mac_algorithm_t)(intptr_t)md->native_handle;
   size_t keylen = ngtcp2_crypto_md_hashlen(md);
   uint8_t key[64];
-  gnutls_datum_t _secret = {(void *)secret, (unsigned int)secretlen};
-  gnutls_datum_t _key = {(void *)key, (unsigned int)keylen};
-  gnutls_datum_t _salt = {(void *)salt, (unsigned int)saltlen};
-  gnutls_datum_t _info = {(void *)info, (unsigned int)infolen};
 
   assert(keylen <= sizeof(key));
 
-  if (gnutls_hkdf_extract(prf, &_secret, &_salt, key) != 0) {
+  if (gnutls_hkdf_extract(prf,
+                          &(gnutls_datum_t){
+                            .data = (uint8_t *)secret,
+                            .size = (unsigned int)secretlen,
+                          },
+                          &(gnutls_datum_t){
+                            .data = (uint8_t *)salt,
+                            .size = (unsigned int)saltlen,
+                          },
+                          key) != 0) {
     return -1;
   }
 
-  if (gnutls_hkdf_expand(prf, &_key, &_info, dest, destlen) != 0) {
+  if (gnutls_hkdf_expand(prf,
+                         &(gnutls_datum_t){
+                           .data = (uint8_t *)key,
+                           .size = (unsigned int)keylen,
+                         },
+                         &(gnutls_datum_t){
+                           .data = (uint8_t *)info,
+                           .size = (unsigned int)infolen,
+                         },
+                         dest, destlen) != 0) {
     return -1;
   }
 
@@ -402,13 +435,11 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest,
   switch (cipher) {
   case GNUTLS_CIPHER_AES_128_CBC:
   case GNUTLS_CIPHER_AES_256_CBC: {
-    uint8_t iv[16];
-    uint8_t buf[16];
-
     /* Emulate one block AES-ECB by invalidating the effect of IV */
-    memset(iv, 0, sizeof(iv));
+    static const uint8_t iv[16] = {0};
+    uint8_t buf[16];
 
-    gnutls_cipher_set_iv(hd, iv, sizeof(iv));
+    gnutls_cipher_set_iv(hd, (uint8_t *)iv, sizeof(iv));
 
     if (gnutls_cipher_encrypt2(hd, sample, 16, buf, sizeof(buf)) != 0) {
       return -1;
@@ -418,14 +449,14 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest,
   } break;
 
   case GNUTLS_CIPHER_CHACHA20_32: {
-    static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
+    static const uint8_t PLAINTEXT[16] = {0};
     uint8_t buf[5 + 16];
     size_t buflen = sizeof(buf);
 
     gnutls_cipher_set_iv(hd, (void *)sample, 16);
 
-    if (gnutls_cipher_encrypt2(hd, PLAINTEXT, sizeof(PLAINTEXT) - 1, buf,
-                               buflen) != 0) {
+    if (gnutls_cipher_encrypt2(hd, PLAINTEXT, sizeof(PLAINTEXT), buf, buflen) !=
+        0) {
       return -1;
     }
 
@@ -539,6 +570,20 @@ int ngtcp2_crypto_get_path_challenge_dat
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
+  return 0;
+}
+
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
+                                              ngtcp2_path_challenge_data *data,
+                                              void *user_data) {
+  (void)conn;
+  (void)user_data;
+
+  if (gnutls_rnd(GNUTLS_RND_RANDOM, data->data,
+                 NGTCP2_PATH_CHALLENGE_DATALEN) != 0) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
   return 0;
 }
 
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/gnutls/libngtcp2_crypto_gnutls.pc.in samba-4.23.8/third_party/ngtcp2/crypto/gnutls/libngtcp2_crypto_gnutls.pc.in
--- samba-4.23.7/third_party/ngtcp2/crypto/gnutls/libngtcp2_crypto_gnutls.pc.in	2026-01-23 11:53:43.273753000 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/gnutls/libngtcp2_crypto_gnutls.pc.in	2026-05-15 15:49:15.150978300 +0200
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
 Version: @VERSION@
 Libs: -L${libdir} -lngtcp2_crypto_gnutls
 Cflags: -I${includedir}
+Requires.private: libngtcp2, gnutls
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/includes/CMakeLists.txt samba-4.23.8/third_party/ngtcp2/crypto/includes/CMakeLists.txt
--- samba-4.23.7/third_party/ngtcp2/crypto/includes/CMakeLists.txt	2026-01-23 11:53:43.273753000 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/includes/CMakeLists.txt	2026-05-15 15:49:15.150978300 +0200
@@ -25,7 +25,7 @@ install(FILES
     ngtcp2/ngtcp2_crypto.h
   DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ngtcp2")
 
-if(HAVE_QUICTLS)
+if(HAVE_QUICTLS OR HAVE_LIBRESSL)
   install(FILES
       ngtcp2/ngtcp2_crypto_quictls.h
       DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ngtcp2")
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/includes/Makefile.am samba-4.23.8/third_party/ngtcp2/crypto/includes/Makefile.am
--- samba-4.23.7/third_party/ngtcp2/crypto/includes/Makefile.am	2026-01-23 11:53:43.273753000 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/includes/Makefile.am	2026-05-15 15:49:15.150978300 +0200
@@ -28,6 +28,10 @@ if HAVE_QUICTLS
 nobase_include_HEADERS += ngtcp2/ngtcp2_crypto_quictls.h
 endif
 
+if HAVE_LIBRESSL
+nobase_include_HEADERS += ngtcp2/ngtcp2_crypto_quictls.h
+endif
+
 if HAVE_GNUTLS
 nobase_include_HEADERS += ngtcp2/ngtcp2_crypto_gnutls.h
 endif
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h samba-4.23.8/third_party/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h
--- samba-4.23.7/third_party/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h	2026-05-15 15:49:15.150978300 +0200
@@ -524,11 +524,14 @@ NGTCP2_EXTERN int ngtcp2_crypto_recv_cli
  * completes.  It is allowed to call this function with |datalen| ==
  * 0.  In this case, no additional read operation is done.
  *
+ * This function is implemented per TLS backend.  See
+ * :ref:`tls-integration` for more details.
+ *
  * This function returns 0 if it succeeds, or a negative error code.
  * The generic error code is -1 if a specific error code is not
  * suitable.  The error codes less than -10000 are specific to
- * underlying TLS implementation.  For quictls, the error codes are
- * defined in *ngtcp2_crypto_quictls.h*.
+ * underlying TLS implementation.  Refer to the implementation
+ * specific header files for error codes.
  */
 NGTCP2_EXTERN int
 ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn,
@@ -542,11 +545,22 @@ ngtcp2_crypto_read_write_crypto_data(ngt
  * `ngtcp2_crypto_read_write_crypto_data`.  It can be directly passed
  * to :member:`ngtcp2_callbacks.recv_crypto_data` field.
  *
+ * For quictls and OpenSSL, the following error codes are treated as
+ * success:
+ *
+ * - -10001 (e.g., :macro:`NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP`)
+ * - -10002 (e.g., :macro:`NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB`)
+ *
+ * To continue the interrupted handshake, call
+ * `ngtcp2_conn_continue_handshake`.
+ *
+ * See :ref:`tls-integration` for more details.
+ *
  * If this function is used, the TLS implementation specific error
  * codes described in `ngtcp2_crypto_read_write_crypto_data` are
- * treated as if it returns -1.  Do not use this function if an
- * application wishes to use the TLS implementation specific error
- * codes.
+ * treated as if it returns -1 except for those that are listed above.
+ * Do not use this function if an application wishes to use the TLS
+ * implementation specific error codes.
  */
 NGTCP2_EXTERN int ngtcp2_crypto_recv_crypto_data_cb(
   ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, uint64_t offset,
@@ -583,7 +597,7 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate
  * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY` is the magic byte for
  * Retry token generated by `ngtcp2_crypto_generate_retry_token`.
  */
-#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY 0xb6
+#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY 0xB6
 
 /**
  * @macro
@@ -591,7 +605,7 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate
  * :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
+#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2 0xB7
 
 /**
  * @macro
@@ -627,7 +641,10 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate
  * @macro
  *
  * :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` is the maximum length
- *  of a token generated by `ngtcp2_crypto_generate_regular_token`.
+ * of a token generated by `ngtcp2_crypto_generate_regular_token`.
+ * `ngtcp2_crypto_generate_regular_token2` generates a token of length
+ * at most :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` bytes + the
+ * length of the provided opaque data.
  */
 #define NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN                                     \
   (/* magic = */ 1 + sizeof(ngtcp2_tstamp) + /* aead tag = */ 16 +             \
@@ -790,6 +807,77 @@ NGTCP2_EXTERN int ngtcp2_crypto_verify_r
 /**
  * @function
  *
+ * `ngtcp2_crypto_generate_regular_token2` generates a token in the
+ * buffer pointed by |token| that is sent with NEW_TOKEN frame.  The
+ * buffer pointed by |token| must have at least
+ * :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` + |datalen| bytes long.
+ * The successfully generated token starts with
+ * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR`.  |secret| of length
+ * |secretlen| is a keying material to generate keys to encrypt the
+ * token.  |remote_addr| of length |remote_addrlen| is an address of
+ * client.  |ts| is the timestamp when the token is generated.  |data|
+ * of length |datalen| is an opaque data embedded in the token.
+ * |datalen| must be less than or equal to 256.
+ *
+ * Calling this function with |datalen| = 0 is equivalent to calling
+ * `ngtcp2_crypto_generate_regular_token`.
+ *
+ * To get the opaque data after successful verification, use
+ * `ngtcp2_crypto_verify_regular_token2`.
+ * `ngtcp2_crypto_verify_regular_token` can verify the token with
+ * |datalen| > 0, but it discards the opaque data.
+ *
+ * This function returns the length of generated token if it succeeds,
+ * or -1.
+ */
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_generate_regular_token2(
+  uint8_t *token, const uint8_t *secret, size_t secretlen,
+  const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
+  const void *data, size_t datalen, ngtcp2_tstamp ts);
+
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_verify_regular_token2` verifies a regular 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.  |remote_addr| of length
+ * |remote_addrlen| is an address of client.  |timeout| is the period
+ * during which the token is valid.  |ts| is the current timestamp.
+ * |data| is the pointer to the buffer of length at least
+ * |max_datalen| bytes.  If the token is verified successfully, the
+ * opaque data embedded in the token is copied to the buffer pointed
+ * by |data|.
+ *
+ * If |tokenlen| is less than
+ * :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN`, this function returns
+ * :macro:`NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN`.
+ *
+ * If the length of opaque data is larger than |max_datalen|, the
+ * verification still succeeds, but nothing is written to the buffer
+ * pointed by |data|, and this function returns 0.  In other words,
+ * the opaque data is discarded.
+ *
+ * This function returns the number of the opaque data written to the
+ * buffer pointed by |data| 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 validity has expired.
+ * :macro:`NGTCP2_CRYPTO_ERR_INTERNAL`
+ *     Internal error occurred.
+ */
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_verify_regular_token2(
+  void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
+  const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
+  ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts);
+
+/**
+ * @function
+ *
  * `ngtcp2_crypto_write_connection_close` writes Initial packet
  * containing CONNECTION_CLOSE with the given |error_code| and the
  * optional |reason| of length |reasonlen| to the buffer pointed by
@@ -904,6 +992,9 @@ NGTCP2_EXTERN void ngtcp2_crypto_delete_
  *
  * This function can be directly passed to
  * :member:`ngtcp2_callbacks.get_path_challenge_data` field.
+ *
+ * Deprecated since v1.22.0.  Use
+ * `ngtcp2_crypto_get_path_challenge_data2_cb` instead.
  */
 NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn,
                                                            uint8_t *data,
@@ -911,6 +1002,21 @@ NGTCP2_EXTERN int ngtcp2_crypto_get_path
 
 /**
  * @function
+ *
+ * `ngtcp2_crypto_get_path_challenge_data2_cb` writes unpredictable
+ * sequence of :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes to |data|
+ * which is sent with PATH_CHALLENGE frame.
+ *
+ * This function can be directly passed to
+ * :member:`ngtcp2_callbacks.get_path_challenge_data2` field.
+ *
+ * This function has been available since v1.22.0.
+ */
+NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data2_cb(
+  ngtcp2_conn *conn, ngtcp2_path_challenge_data *data, void *user_data);
+
+/**
+ * @function
  *
  * `ngtcp2_crypto_version_negotiation_cb` installs Initial keys for
  * |version| which is negotiated or being negotiated.  |client_dcid|
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/ossl/CMakeLists.txt samba-4.23.8/third_party/ngtcp2/crypto/ossl/CMakeLists.txt
--- samba-4.23.7/third_party/ngtcp2/crypto/ossl/CMakeLists.txt	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/ossl/CMakeLists.txt	2026-05-15 15:49:15.150978300 +0200
@@ -29,14 +29,11 @@ set(ngtcp2_crypto_ossl_SOURCES
 )
 
 set(ngtcp2_crypto_ossl_INCLUDE_DIRS
-  "${CMAKE_CURRENT_SOURCE_DIR}/../../lib/includes"
-  "${CMAKE_CURRENT_BINARY_DIR}/../../lib/includes"
-  "${CMAKE_CURRENT_SOURCE_DIR}/../../lib"
-  "${CMAKE_CURRENT_SOURCE_DIR}/../../crypto/includes"
-  "${CMAKE_CURRENT_BINARY_DIR}/../../crypto/includes"
-  "${CMAKE_CURRENT_SOURCE_DIR}/../../crypto"
-  "${CMAKE_CURRENT_BINARY_DIR}/../../crypto"
-  "${OPENSSL_INCLUDE_DIRS}"
+  "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib>"
+  "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/crypto/includes>"
+  "$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/crypto/includes>"
+  "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/crypto>"
+  "$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/crypto>"
 )
 
 foreach(name libngtcp2_crypto_ossl.pc)
@@ -55,9 +52,10 @@ if(ENABLE_SHARED_LIB)
   )
   target_include_directories(ngtcp2_crypto_ossl PUBLIC
     ${ngtcp2_crypto_ossl_INCLUDE_DIRS})
-  target_link_libraries(ngtcp2_crypto_ossl ngtcp2 ${OPENSSL_LIBRARIES})
+  target_link_libraries(ngtcp2_crypto_ossl PUBLIC ngtcp2 OpenSSL::SSL)
 
   install(TARGETS ngtcp2_crypto_ossl
+    EXPORT "${PROJECT_NAME}Targets"
     ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
     LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
@@ -77,8 +75,10 @@ if(ENABLE_STATIC_LIB)
     "-DNGTCP2_STATICLIB")
   target_include_directories(ngtcp2_crypto_ossl_static PUBLIC
     ${ngtcp2_crypto_ossl_INCLUDE_DIRS})
+  target_link_libraries(ngtcp2_crypto_ossl_static PUBLIC ngtcp2_static OpenSSL::SSL)
 
   install(TARGETS ngtcp2_crypto_ossl_static
+    EXPORT "${PROJECT_NAME}Targets"
     DESTINATION "${CMAKE_INSTALL_LIBDIR}")
 endif()
 
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/ossl/libngtcp2_crypto_ossl.pc.in samba-4.23.8/third_party/ngtcp2/crypto/ossl/libngtcp2_crypto_ossl.pc.in
--- samba-4.23.7/third_party/ngtcp2/crypto/ossl/libngtcp2_crypto_ossl.pc.in	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/ossl/libngtcp2_crypto_ossl.pc.in	2026-05-15 15:49:15.150978300 +0200
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
 Version: @VERSION@
 Libs: -L${libdir} -lngtcp2_crypto_ossl
 Cflags: -I${includedir}
+Requires.private: libngtcp2, openssl
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/ossl/ossl.c samba-4.23.8/third_party/ngtcp2/crypto/ossl/ossl.c
--- samba-4.23.7/third_party/ngtcp2/crypto/ossl/ossl.c	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/ossl/ossl.c	2026-05-15 15:49:15.151978300 +0200
@@ -41,70 +41,40 @@
 #include "ngtcp2_macro.h"
 #include "shared.h"
 
-static int crypto_initialized;
+#if defined(OPENSSL_NO_CHACHA) || defined(OPENSSL_NO_POLY1305)
+#  define NGTCP2_NO_CHACHA_POLY1305
+#endif /* defined(OPENSSL_NO_CHACHA) ||                                        \
+          defined(OPENSSL_NO_POLY1305) */
+
 static EVP_CIPHER *crypto_aes_128_gcm;
 static EVP_CIPHER *crypto_aes_256_gcm;
-static EVP_CIPHER *crypto_chacha20_poly1305;
 static EVP_CIPHER *crypto_aes_128_ccm;
-static EVP_CIPHER *crypto_aes_128_ctr;
-static EVP_CIPHER *crypto_aes_256_ctr;
+static EVP_CIPHER *crypto_aes_128_ecb;
+static EVP_CIPHER *crypto_aes_256_ecb;
+#ifndef NGTCP2_NO_CHACHA_POLY1305
+static EVP_CIPHER *crypto_chacha20_poly1305;
 static EVP_CIPHER *crypto_chacha20;
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
 static EVP_MD *crypto_sha256;
 static EVP_MD *crypto_sha384;
 static EVP_KDF *crypto_hkdf;
 
 int ngtcp2_crypto_ossl_init(void) {
+  /* We do not care whether the pre-fetch succeeds or not.  If it
+     fails, it returns NULL, which is still the default value, and our
+     code should still work with it. */
   crypto_aes_128_gcm = EVP_CIPHER_fetch(NULL, "AES-128-GCM", NULL);
-  if (crypto_aes_128_gcm == NULL) {
-    return -1;
-  }
-
   crypto_aes_256_gcm = EVP_CIPHER_fetch(NULL, "AES-256-GCM", NULL);
-  if (crypto_aes_256_gcm == NULL) {
-    return -1;
-  }
-
-  crypto_chacha20_poly1305 = EVP_CIPHER_fetch(NULL, "ChaCha20-Poly1305", NULL);
-  if (crypto_chacha20_poly1305 == NULL) {
-    return -1;
-  }
-
   crypto_aes_128_ccm = EVP_CIPHER_fetch(NULL, "AES-128-CCM", NULL);
-  if (crypto_aes_128_ccm == NULL) {
-    return -1;
-  }
-
-  crypto_aes_128_ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", NULL);
-  if (crypto_aes_128_ctr == NULL) {
-    return -1;
-  }
-
-  crypto_aes_256_ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", NULL);
-  if (crypto_aes_256_ctr == NULL) {
-    return -1;
-  }
-
+  crypto_aes_128_ecb = EVP_CIPHER_fetch(NULL, "AES-128-ECB", NULL);
+  crypto_aes_256_ecb = EVP_CIPHER_fetch(NULL, "AES-256-ECB", NULL);
+#ifndef NGTCP2_NO_CHACHA_POLY1305
+  crypto_chacha20_poly1305 = EVP_CIPHER_fetch(NULL, "ChaCha20-Poly1305", NULL);
   crypto_chacha20 = EVP_CIPHER_fetch(NULL, "ChaCha20", NULL);
-  if (crypto_chacha20 == NULL) {
-    return -1;
-  }
-
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
   crypto_sha256 = EVP_MD_fetch(NULL, "sha256", NULL);
-  if (crypto_sha256 == NULL) {
-    return -1;
-  }
-
   crypto_sha384 = EVP_MD_fetch(NULL, "sha384", NULL);
-  if (crypto_sha384 == NULL) {
-    return -1;
-  }
-
   crypto_hkdf = EVP_KDF_fetch(NULL, "hkdf", NULL);
-  if (crypto_hkdf == NULL) {
-    return -1;
-  }
-
-  crypto_initialized = 1;
 
   return 0;
 }
@@ -125,6 +95,7 @@ static const EVP_CIPHER *crypto_aead_aes
   return EVP_aes_256_gcm();
 }
 
+#ifndef NGTCP2_NO_CHACHA_POLY1305
 static const EVP_CIPHER *crypto_aead_chacha20_poly1305(void) {
   if (crypto_chacha20_poly1305) {
     return crypto_chacha20_poly1305;
@@ -132,6 +103,7 @@ static const EVP_CIPHER *crypto_aead_cha
 
   return EVP_chacha20_poly1305();
 }
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
 
 static const EVP_CIPHER *crypto_aead_aes_128_ccm(void) {
   if (crypto_aes_128_ccm) {
@@ -141,22 +113,23 @@ static const EVP_CIPHER *crypto_aead_aes
   return EVP_aes_128_ccm();
 }
 
-static const EVP_CIPHER *crypto_cipher_aes_128_ctr(void) {
-  if (crypto_aes_128_ctr) {
-    return crypto_aes_128_ctr;
+static const EVP_CIPHER *crypto_cipher_aes_128_ecb(void) {
+  if (crypto_aes_128_ecb) {
+    return crypto_aes_128_ecb;
   }
 
-  return EVP_aes_128_ctr();
+  return EVP_aes_128_ecb();
 }
 
-static const EVP_CIPHER *crypto_cipher_aes_256_ctr(void) {
-  if (crypto_aes_256_ctr) {
-    return crypto_aes_256_ctr;
+static const EVP_CIPHER *crypto_cipher_aes_256_ecb(void) {
+  if (crypto_aes_256_ecb) {
+    return crypto_aes_256_ecb;
   }
 
-  return EVP_aes_256_ctr();
+  return EVP_aes_256_ecb();
 }
 
+#ifndef NGTCP2_NO_CHACHA_POLY1305
 static const EVP_CIPHER *crypto_cipher_chacha20(void) {
   if (crypto_chacha20) {
     return crypto_chacha20;
@@ -164,6 +137,7 @@ static const EVP_CIPHER *crypto_cipher_c
 
   return EVP_chacha20();
 }
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
 
 static const EVP_MD *crypto_md_sha256(void) {
   if (crypto_sha256) {
@@ -189,13 +163,21 @@ static EVP_KDF *crypto_kdf_hkdf(void) {
   return EVP_KDF_fetch(NULL, "hkdf", NULL);
 }
 
+static void crypto_kdf_hkdf_free(EVP_KDF *kdf) {
+  if (kdf && crypto_hkdf != kdf) {
+    EVP_KDF_free(kdf);
+  }
+}
+
 static size_t crypto_aead_max_overhead(const EVP_CIPHER *aead) {
   switch (EVP_CIPHER_nid(aead)) {
   case NID_aes_128_gcm:
   case NID_aes_256_gcm:
     return EVP_GCM_TLS_TAG_LEN;
+#ifndef NGTCP2_NO_CHACHA_POLY1305
   case NID_chacha20_poly1305:
     return EVP_CHACHAPOLY_TLS_TAG_LEN;
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
   case NID_aes_128_ccm:
     return EVP_CCM_TLS_TAG_LEN;
   default:
@@ -216,7 +198,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha25
 ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) {
   ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_aead_aes_128_gcm());
   ctx->md.native_handle = (void *)crypto_md_sha256();
-  ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ctr();
+  ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ecb();
   ctx->max_encryption = 0;
   ctx->max_decryption_failure = 0;
   return ctx;
@@ -239,8 +221,10 @@ static const EVP_CIPHER *crypto_cipher_i
     return crypto_aead_aes_128_gcm();
   case TLS1_3_CK_AES_256_GCM_SHA384:
     return crypto_aead_aes_256_gcm();
+#ifndef NGTCP2_NO_CHACHA_POLY1305
   case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
     return crypto_aead_chacha20_poly1305();
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
   case TLS1_3_CK_AES_128_CCM_SHA256:
     return crypto_aead_aes_128_ccm();
   default:
@@ -253,8 +237,10 @@ static uint64_t crypto_cipher_id_get_aea
   case TLS1_3_CK_AES_128_GCM_SHA256:
   case TLS1_3_CK_AES_256_GCM_SHA384:
     return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM;
+#ifndef NGTCP2_NO_CHACHA_POLY1305
   case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
     return NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305;
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
   case TLS1_3_CK_AES_128_CCM_SHA256:
     return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_CCM;
   default:
@@ -268,8 +254,10 @@ crypto_cipher_id_get_aead_max_decryption
   case TLS1_3_CK_AES_128_GCM_SHA256:
   case TLS1_3_CK_AES_256_GCM_SHA384:
     return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM;
+#ifndef NGTCP2_NO_CHACHA_POLY1305
   case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
     return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305;
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
   case TLS1_3_CK_AES_128_CCM_SHA256:
     return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_CCM;
   default:
@@ -281,11 +269,13 @@ static const EVP_CIPHER *crypto_cipher_i
   switch (cipher_id) {
   case TLS1_3_CK_AES_128_GCM_SHA256:
   case TLS1_3_CK_AES_128_CCM_SHA256:
-    return crypto_cipher_aes_128_ctr();
+    return crypto_cipher_aes_128_ecb();
   case TLS1_3_CK_AES_256_GCM_SHA384:
-    return crypto_cipher_aes_256_ctr();
+    return crypto_cipher_aes_256_ecb();
+#ifndef NGTCP2_NO_CHACHA_POLY1305
   case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
     return crypto_cipher_chacha20();
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
   default:
     return NULL;
   }
@@ -294,7 +284,9 @@ static const EVP_CIPHER *crypto_cipher_i
 static const EVP_MD *crypto_cipher_id_get_md(uint32_t cipher_id) {
   switch (cipher_id) {
   case TLS1_3_CK_AES_128_GCM_SHA256:
+#ifndef NGTCP2_NO_CHACHA_POLY1305
   case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
   case TLS1_3_CK_AES_128_CCM_SHA256:
     return crypto_md_sha256();
   case TLS1_3_CK_AES_256_GCM_SHA384:
@@ -308,7 +300,9 @@ static int supported_cipher_id(uint32_t
   switch (cipher_id) {
   case TLS1_3_CK_AES_128_GCM_SHA256:
   case TLS1_3_CK_AES_256_GCM_SHA384:
+#ifndef NGTCP2_NO_CHACHA_POLY1305
   case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
   case TLS1_3_CK_AES_128_CCM_SHA256:
     return 1;
   default:
@@ -697,9 +691,7 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *
   };
   int rv = 0;
 
-  if (!crypto_initialized) {
-    EVP_KDF_free(kdf);
-  }
+  crypto_kdf_hkdf_free(kdf);
 
   if (EVP_KDF_derive(kctx, dest, (size_t)EVP_MD_size(prf), params) <= 0) {
     rv = -1;
@@ -730,9 +722,7 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *d
   };
   int rv = 0;
 
-  if (!crypto_initialized) {
-    EVP_KDF_free(kdf);
-  }
+  crypto_kdf_hkdf_free(kdf);
 
   if (EVP_KDF_derive(kctx, dest, destlen, params) <= 0) {
     rv = -1;
@@ -763,9 +753,7 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, si
   };
   int rv = 0;
 
-  if (!crypto_initialized) {
-    EVP_KDF_free(kdf);
-  }
+  crypto_kdf_hkdf_free(kdf);
 
   if (EVP_KDF_derive(kctx, dest, destlen, params) <= 0) {
     rv = -1;
@@ -850,16 +838,31 @@ int ngtcp2_crypto_decrypt(uint8_t *dest,
 int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
                           const ngtcp2_crypto_cipher_ctx *hp_ctx,
                           const uint8_t *sample) {
-  static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
+  static const uint8_t PLAINTEXT[16] = {0};
   EVP_CIPHER_CTX *actx = hp_ctx->native_handle;
   int len;
 
   (void)hp;
 
-  if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
-      !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT) - 1) ||
-      !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len)) {
-    return -1;
+  switch (EVP_CIPHER_CTX_nid(actx)) {
+  case NID_aes_128_ecb:
+  case NID_aes_256_ecb:
+    if (!EVP_EncryptUpdate(actx, dest, &len, sample, NGTCP2_HP_SAMPLELEN)) {
+      return -1;
+    }
+
+    break;
+  case NID_chacha20:
+    if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
+        !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT)) ||
+        !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT), &len)) {
+      return -1;
+    }
+
+    break;
+  default:
+    assert(0);
+    abort();
   }
 
   return 0;
@@ -991,6 +994,19 @@ int ngtcp2_crypto_get_path_challenge_dat
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
+  return 0;
+}
+
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
+                                              ngtcp2_path_challenge_data *data,
+                                              void *user_data) {
+  (void)conn;
+  (void)user_data;
+
+  if (RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
   return 0;
 }
 
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/picotls/libngtcp2_crypto_picotls.pc.in samba-4.23.8/third_party/ngtcp2/crypto/picotls/libngtcp2_crypto_picotls.pc.in
--- samba-4.23.7/third_party/ngtcp2/crypto/picotls/libngtcp2_crypto_picotls.pc.in	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/picotls/libngtcp2_crypto_picotls.pc.in	2026-05-15 15:49:15.151978300 +0200
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
 Version: @VERSION@
 Libs: -L${libdir} -lngtcp2_crypto_picotls
 Cflags: -I${includedir}
+Requires.private: libngtcp2, openssl
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/picotls/picotls.c samba-4.23.8/third_party/ngtcp2/crypto/picotls/picotls.c
--- samba-4.23.7/third_party/ngtcp2/crypto/picotls/picotls.c	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/picotls/picotls.c	2026-05-15 15:49:15.151978300 +0200
@@ -35,6 +35,7 @@
 #include <picotls.h>
 #include <picotls/openssl.h>
 
+#include "ngtcp2_macro.h"
 #include "shared.h"
 
 ngtcp2_crypto_aead *ngtcp2_crypto_aead_aes_128_gcm(ngtcp2_crypto_aead *aead) {
@@ -49,7 +50,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha25
 ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) {
   ngtcp2_crypto_aead_init(&ctx->aead, (void *)&ptls_openssl_aes128gcm);
   ctx->md.native_handle = (void *)&ptls_openssl_sha256;
-  ctx->hp.native_handle = (void *)&ptls_openssl_aes128ctr;
+  ctx->hp.native_handle = (void *)&ptls_openssl_aes128ecb;
   ctx->max_encryption = 0;
   ctx->max_decryption_failure = 0;
   return ctx;
@@ -103,11 +104,11 @@ crypto_cipher_suite_get_aead_max_decrypt
 static const ptls_cipher_algorithm_t *
 crypto_cipher_suite_get_hp(ptls_cipher_suite_t *cs) {
   if (cs->aead == &ptls_openssl_aes128gcm) {
-    return &ptls_openssl_aes128ctr;
+    return &ptls_openssl_aes128ecb;
   }
 
   if (cs->aead == &ptls_openssl_aes256gcm) {
-    return &ptls_openssl_aes256ctr;
+    return &ptls_openssl_aes256ecb;
   }
 
 #ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
@@ -237,6 +238,11 @@ int ngtcp2_crypto_cipher_ctx_encrypt_ini
     return -1;
   }
 
+  if (cipher->native_handle == &ptls_openssl_aes128ecb ||
+      cipher->native_handle == &ptls_openssl_aes256ecb) {
+    ptls_cipher_init(actx, NULL);
+  }
+
   cipher_ctx->native_handle = actx;
 
   return 0;
@@ -351,13 +357,20 @@ int ngtcp2_crypto_decrypt(uint8_t *dest,
 int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
                           const ngtcp2_crypto_cipher_ctx *hp_ctx,
                           const uint8_t *sample) {
+  static const uint8_t PLAINTEXT[16] = {0};
   ptls_cipher_context_t *actx = hp_ctx->native_handle;
-  static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
 
   (void)hp;
 
+  if (hp->native_handle == &ptls_openssl_aes128ecb ||
+      hp->native_handle == &ptls_openssl_aes256ecb) {
+    ptls_cipher_encrypt(actx, dest, sample, NGTCP2_HP_SAMPLELEN);
+
+    return 0;
+  }
+
   ptls_cipher_init(actx, sample);
-  ptls_cipher_encrypt(actx, dest, PLAINTEXT, sizeof(PLAINTEXT) - 1);
+  ptls_cipher_encrypt(actx, dest, PLAINTEXT, sizeof(PLAINTEXT));
 
   return 0;
 }
@@ -376,7 +389,7 @@ int ngtcp2_crypto_read_write_crypto_data
 
   ptls_buffer_init(&sendbuf, (void *)"", 0);
 
-  assert(epoch == ptls_get_read_epoch(cptls->ptls));
+  assert(datalen == 0 || epoch == ptls_get_read_epoch(cptls->ptls));
 
   rv = ptls_handle_message(cptls->ptls, &sendbuf, epoch_offsets, epoch, data,
                            datalen, &cptls->handshake_properties);
@@ -492,6 +505,17 @@ int ngtcp2_crypto_get_path_challenge_dat
   return 0;
 }
 
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
+                                              ngtcp2_path_challenge_data *data,
+                                              void *user_data) {
+  (void)conn;
+  (void)user_data;
+
+  ptls_openssl_random_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN);
+
+  return 0;
+}
+
 int ngtcp2_crypto_random(uint8_t *data, size_t datalen) {
   ptls_openssl_random_bytes(data, datalen);
 
@@ -499,8 +523,7 @@ int ngtcp2_crypto_random(uint8_t *data,
 }
 
 void ngtcp2_crypto_picotls_ctx_init(ngtcp2_crypto_picotls_ctx *cptls) {
-  cptls->ptls = NULL;
-  memset(&cptls->handshake_properties, 0, sizeof(cptls->handshake_properties));
+  *cptls = (ngtcp2_crypto_picotls_ctx){0};
 }
 
 static int set_additional_extensions(ptls_handshake_properties_t *hsprops,
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/quictls/.gitignore samba-4.23.8/third_party/ngtcp2/crypto/quictls/.gitignore
--- samba-4.23.7/third_party/ngtcp2/crypto/quictls/.gitignore	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/quictls/.gitignore	2026-05-15 15:49:15.151978300 +0200
@@ -1 +1,2 @@
+/libngtcp2_crypto_libressl.pc
 /libngtcp2_crypto_quictls.pc
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/quictls/CMakeLists.txt samba-4.23.8/third_party/ngtcp2/crypto/quictls/CMakeLists.txt
--- samba-4.23.7/third_party/ngtcp2/crypto/quictls/CMakeLists.txt	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/quictls/CMakeLists.txt	2026-05-15 15:49:15.151978300 +0200
@@ -39,25 +39,31 @@ set(ngtcp2_crypto_quictls_INCLUDE_DIRS
   "${OPENSSL_INCLUDE_DIRS}"
 )
 
-foreach(name libngtcp2_crypto_quictls.pc)
+if(HAVE_LIBRESSL)
+  set(ngtcp2_crypto_lib "ngtcp2_crypto_libressl")
+else()
+  set(ngtcp2_crypto_lib "ngtcp2_crypto_quictls")
+endif()
+
+foreach(name lib${ngtcp2_crypto_lib}.pc)
   configure_file("${name}.in" "${name}" @ONLY)
 endforeach()
 
 # Public shared library
 if(ENABLE_SHARED_LIB)
-  add_library(ngtcp2_crypto_quictls SHARED ${ngtcp2_crypto_quictls_SOURCES})
-  set_target_properties(ngtcp2_crypto_quictls PROPERTIES
+  add_library(${ngtcp2_crypto_lib} SHARED ${ngtcp2_crypto_quictls_SOURCES})
+  set_target_properties(${ngtcp2_crypto_lib} PROPERTIES
     COMPILE_FLAGS "${WARNCFLAGS}"
     VERSION ${CRYPTO_QUICTLS_LT_VERSION}
     SOVERSION ${CRYPTO_QUICTLS_LT_SOVERSION}
     C_VISIBILITY_PRESET hidden
     POSITION_INDEPENDENT_CODE ON
   )
-  target_include_directories(ngtcp2_crypto_quictls PUBLIC
+  target_include_directories(${ngtcp2_crypto_lib} PUBLIC
     ${ngtcp2_crypto_quictls_INCLUDE_DIRS})
-  target_link_libraries(ngtcp2_crypto_quictls ngtcp2 ${OPENSSL_LIBRARIES})
+  target_link_libraries(${ngtcp2_crypto_lib} ngtcp2 ${OPENSSL_LIBRARIES})
 
-  install(TARGETS ngtcp2_crypto_quictls
+  install(TARGETS ${ngtcp2_crypto_lib}
     ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
     LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
@@ -65,22 +71,22 @@ endif()
 
 if(ENABLE_STATIC_LIB)
   # Public static library
-  add_library(ngtcp2_crypto_quictls_static STATIC ${ngtcp2_crypto_quictls_SOURCES})
-  set_target_properties(ngtcp2_crypto_quictls_static PROPERTIES
+  add_library(${ngtcp2_crypto_lib}_static STATIC ${ngtcp2_crypto_quictls_SOURCES})
+  set_target_properties(${ngtcp2_crypto_lib}_static PROPERTIES
     COMPILE_FLAGS "${WARNCFLAGS}"
     VERSION ${CRYPTO_QUICTLS_LT_VERSION}
     SOVERSION ${CRYPTO_QUICTLS_LT_SOVERSION}
-    ARCHIVE_OUTPUT_NAME ngtcp2_crypto_quictls${STATIC_LIB_SUFFIX}
+    ARCHIVE_OUTPUT_NAME ${ngtcp2_crypto_lib}${STATIC_LIB_SUFFIX}
     C_VISIBILITY_PRESET hidden
   )
-  target_compile_definitions(ngtcp2_crypto_quictls_static PUBLIC
+  target_compile_definitions(${ngtcp2_crypto_lib}_static PUBLIC
     "-DNGTCP2_STATICLIB")
-  target_include_directories(ngtcp2_crypto_quictls_static PUBLIC
+  target_include_directories(${ngtcp2_crypto_lib}_static PUBLIC
     ${ngtcp2_crypto_quictls_INCLUDE_DIRS})
 
-  install(TARGETS ngtcp2_crypto_quictls_static
+  install(TARGETS ${ngtcp2_crypto_lib}_static
     DESTINATION "${CMAKE_INSTALL_LIBDIR}")
 endif()
 
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libngtcp2_crypto_quictls.pc"
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/lib${ngtcp2_crypto_lib}.pc"
   DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/quictls/Makefile.am samba-4.23.8/third_party/ngtcp2/crypto/quictls/Makefile.am
--- samba-4.23.7/third_party/ngtcp2/crypto/quictls/Makefile.am	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/quictls/Makefile.am	2026-05-15 15:49:15.151978300 +0200
@@ -31,9 +31,18 @@ AM_CPPFLAGS = -I$(top_srcdir)/lib/includ
 AM_LDFLAGS = ${LIBTOOL_LDFLAGS}
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libngtcp2_crypto_quictls.pc
-DISTCLEANFILES = $(pkgconfig_DATA)
 
+if HAVE_LIBRESSL
+pkgconfig_DATA = libngtcp2_crypto_libressl.pc
+lib_LTLIBRARIES = libngtcp2_crypto_libressl.la
+
+libngtcp2_crypto_libressl_la_SOURCES = quictls.c ../shared.c ../shared.h
+libngtcp2_crypto_libressl_la_LDFLAGS = -no-undefined \
+	-version-info $(CRYPTO_LIBRESSL_LT_CURRENT):$(CRYPTO_LIBRESSL_LT_REVISION):$(CRYPTO_LIBRESSL_LT_AGE)
+libngtcp2_crypto_libressl_la_LIBADD = $(top_builddir)/lib/libngtcp2.la \
+	@OPENSSL_LIBS@
+else
+pkgconfig_DATA = libngtcp2_crypto_quictls.pc
 lib_LTLIBRARIES = libngtcp2_crypto_quictls.la
 
 libngtcp2_crypto_quictls_la_SOURCES = quictls.c ../shared.c ../shared.h
@@ -41,3 +50,6 @@ libngtcp2_crypto_quictls_la_LDFLAGS = -n
 	-version-info $(CRYPTO_QUICTLS_LT_CURRENT):$(CRYPTO_QUICTLS_LT_REVISION):$(CRYPTO_QUICTLS_LT_AGE)
 libngtcp2_crypto_quictls_la_LIBADD = $(top_builddir)/lib/libngtcp2.la \
 	@OPENSSL_LIBS@
+endif
+
+DISTCLEANFILES = $(pkgconfig_DATA)
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_libressl.pc.in samba-4.23.8/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_libressl.pc.in
--- samba-4.23.7/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_libressl.pc.in	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_libressl.pc.in	2026-05-15 15:49:15.151978300 +0200
@@ -0,0 +1,34 @@
+# ngtcp2
+
+# Copyright (c) 2019 ngtcp2 contributors
+
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libngtcp2_crypto_libressl
+Description: ngtcp2 LibreSSL crypto library
+URL: https://github.com/ngtcp2/ngtcp2
+Version: @VERSION@
+Libs: -L${libdir} -lngtcp2_crypto_libressl
+Cflags: -I${includedir}
+Requires.private: libngtcp2, openssl
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_quictls.pc.in samba-4.23.8/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_quictls.pc.in
--- samba-4.23.7/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_quictls.pc.in	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/quictls/libngtcp2_crypto_quictls.pc.in	2026-05-15 15:49:15.151978300 +0200
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
 Version: @VERSION@
 Libs: -L${libdir} -lngtcp2_crypto_quictls
 Cflags: -I${includedir}
+Requires.private: libngtcp2, openssl
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/quictls/quictls.c samba-4.23.8/third_party/ngtcp2/crypto/quictls/quictls.c
--- samba-4.23.7/third_party/ngtcp2/crypto/quictls/quictls.c	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/quictls/quictls.c	2026-05-15 15:49:15.151978300 +0200
@@ -40,6 +40,7 @@
 #  include <openssl/core_names.h>
 #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
 
+#include "ngtcp2_macro.h"
 #include "shared.h"
 
 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
@@ -48,8 +49,8 @@ static EVP_CIPHER *crypto_aes_128_gcm;
 static EVP_CIPHER *crypto_aes_256_gcm;
 static EVP_CIPHER *crypto_chacha20_poly1305;
 static EVP_CIPHER *crypto_aes_128_ccm;
-static EVP_CIPHER *crypto_aes_128_ctr;
-static EVP_CIPHER *crypto_aes_256_ctr;
+static EVP_CIPHER *crypto_aes_128_ecb;
+static EVP_CIPHER *crypto_aes_256_ecb;
 static EVP_CIPHER *crypto_chacha20;
 static EVP_MD *crypto_sha256;
 static EVP_MD *crypto_sha384;
@@ -76,13 +77,13 @@ int ngtcp2_crypto_quictls_init(void) {
     return -1;
   }
 
-  crypto_aes_128_ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", NULL);
-  if (crypto_aes_128_ctr == NULL) {
+  crypto_aes_128_ecb = EVP_CIPHER_fetch(NULL, "AES-128-ECB", NULL);
+  if (crypto_aes_128_ecb == NULL) {
     return -1;
   }
 
-  crypto_aes_256_ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", NULL);
-  if (crypto_aes_256_ctr == NULL) {
+  crypto_aes_256_ecb = EVP_CIPHER_fetch(NULL, "AES-256-ECB", NULL);
+  if (crypto_aes_256_ecb == NULL) {
     return -1;
   }
 
@@ -143,20 +144,20 @@ static const EVP_CIPHER *crypto_aead_aes
   return EVP_aes_128_ccm();
 }
 
-static const EVP_CIPHER *crypto_cipher_aes_128_ctr(void) {
-  if (crypto_aes_128_ctr) {
-    return crypto_aes_128_ctr;
+static const EVP_CIPHER *crypto_cipher_aes_128_ecb(void) {
+  if (crypto_aes_128_ecb) {
+    return crypto_aes_128_ecb;
   }
 
-  return EVP_aes_128_ctr();
+  return EVP_aes_128_ecb();
 }
 
-static const EVP_CIPHER *crypto_cipher_aes_256_ctr(void) {
-  if (crypto_aes_256_ctr) {
-    return crypto_aes_256_ctr;
+static const EVP_CIPHER *crypto_cipher_aes_256_ecb(void) {
+  if (crypto_aes_256_ecb) {
+    return crypto_aes_256_ecb;
   }
 
-  return EVP_aes_256_ctr();
+  return EVP_aes_256_ecb();
 }
 
 static const EVP_CIPHER *crypto_cipher_chacha20(void) {
@@ -195,8 +196,8 @@ static EVP_KDF *crypto_kdf_hkdf(void) {
 #  define crypto_aead_aes_256_gcm EVP_aes_256_gcm
 #  define crypto_aead_chacha20_poly1305 EVP_chacha20_poly1305
 #  define crypto_aead_aes_128_ccm EVP_aes_128_ccm
-#  define crypto_cipher_aes_128_ctr EVP_aes_128_ctr
-#  define crypto_cipher_aes_256_ctr EVP_aes_256_ctr
+#  define crypto_cipher_aes_128_ecb EVP_aes_128_ecb
+#  define crypto_cipher_aes_256_ecb EVP_aes_256_ecb
 #  define crypto_cipher_chacha20 EVP_chacha20
 #  define crypto_md_sha256 EVP_sha256
 #  define crypto_md_sha384 EVP_sha384
@@ -231,7 +232,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha25
 ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) {
   ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_aead_aes_128_gcm());
   ctx->md.native_handle = (void *)crypto_md_sha256();
-  ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ctr();
+  ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ecb();
   ctx->max_encryption = 0;
   ctx->max_decryption_failure = 0;
   return ctx;
@@ -296,9 +297,9 @@ static const EVP_CIPHER *crypto_cipher_i
   switch (cipher_id) {
   case TLS1_3_CK_AES_128_GCM_SHA256:
   case TLS1_3_CK_AES_128_CCM_SHA256:
-    return crypto_cipher_aes_128_ctr();
+    return crypto_cipher_aes_128_ecb();
   case TLS1_3_CK_AES_256_GCM_SHA384:
-    return crypto_cipher_aes_256_ctr();
+    return crypto_cipher_aes_256_ecb();
   case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
     return crypto_cipher_chacha20();
   default:
@@ -778,16 +779,31 @@ int ngtcp2_crypto_decrypt(uint8_t *dest,
 int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
                           const ngtcp2_crypto_cipher_ctx *hp_ctx,
                           const uint8_t *sample) {
-  static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
+  static const uint8_t PLAINTEXT[16] = {0};
   EVP_CIPHER_CTX *actx = hp_ctx->native_handle;
   int len;
 
   (void)hp;
 
-  if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
-      !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT) - 1) ||
-      !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len)) {
-    return -1;
+  switch (EVP_CIPHER_CTX_nid(actx)) {
+  case NID_aes_128_ecb:
+  case NID_aes_256_ecb:
+    if (!EVP_EncryptUpdate(actx, dest, &len, sample, NGTCP2_HP_SAMPLELEN)) {
+      return -1;
+    }
+
+    break;
+  case NID_chacha20:
+    if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
+        !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT)) ||
+        !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT), &len)) {
+      return -1;
+    }
+
+    break;
+  default:
+    assert(0);
+    abort();
   }
 
   return 0;
@@ -800,7 +816,8 @@ int ngtcp2_crypto_read_write_crypto_data
   int rv;
   int err;
 
-  if (SSL_provide_quic_data(
+  if (datalen &&
+      SSL_provide_quic_data(
         ssl,
         ngtcp2_crypto_quictls_from_ngtcp2_encryption_level(encryption_level),
         data, datalen) != 1) {
@@ -917,6 +934,19 @@ int ngtcp2_crypto_get_path_challenge_dat
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
+  return 0;
+}
+
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
+                                              ngtcp2_path_challenge_data *data,
+                                              void *user_data) {
+  (void)conn;
+  (void)user_data;
+
+  if (RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
   return 0;
 }
 
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/shared.c samba-4.23.8/third_party/ngtcp2/crypto/shared.c
--- samba-4.23.7/third_party/ngtcp2/crypto/shared.c	2026-01-23 11:53:43.277753800 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/shared.c	2026-05-15 15:49:15.152978400 +0200
@@ -37,6 +37,22 @@
 #include "ngtcp2_macro.h"
 #include "ngtcp2_net.h"
 
+/*
+ * NGTCP2_INITIAL_SALT_V1 is a salt value which is used to derive
+ * initial secret.  It is used for QUIC v1.
+ */
+static const uint8_t NGTCP2_INITIAL_SALT_V1[] = {
+  0x38, 0x76, 0x2C, 0xF7, 0xF5, 0x59, 0x34, 0xB3, 0x4D, 0x17,
+  0x9A, 0xE6, 0xA4, 0xC8, 0x0C, 0xAD, 0xCC, 0xBB, 0x7F, 0x0A};
+
+/*
+ * NGTCP2_INITIAL_SALT_V2 is a salt value which is used to derive
+ * initial secret.  It is used for QUIC v2.
+ */
+static const uint8_t NGTCP2_INITIAL_SALT_V2[] = {
+  0x0D, 0xED, 0xE3, 0xDE, 0xF7, 0x00, 0xA6, 0xDB, 0x81, 0x93,
+  0x81, 0xBE, 0x6E, 0x26, 0x9D, 0xCB, 0xF9, 0xBD, 0x2E, 0xD9};
+
 ngtcp2_crypto_md *ngtcp2_crypto_md_init(ngtcp2_crypto_md *md,
                                         void *md_native_handle) {
   md->native_handle = md_native_handle;
@@ -53,9 +69,9 @@ int ngtcp2_crypto_hkdf_expand_label(uint
 
   *p++ = (uint8_t)(destlen / 256);
   *p++ = (uint8_t)(destlen % 256);
-  *p++ = (uint8_t)(sizeof(LABEL) - 1 + labellen);
-  memcpy(p, LABEL, sizeof(LABEL) - 1);
-  p += sizeof(LABEL) - 1;
+  *p++ = (uint8_t)(ngtcp2_strlen_lit(LABEL) + labellen);
+  memcpy(p, LABEL, ngtcp2_strlen_lit(LABEL));
+  p += ngtcp2_strlen_lit(LABEL);
   memcpy(p, label, labellen);
   p += labellen;
   *p++ = 0;
@@ -87,12 +103,12 @@ int ngtcp2_crypto_derive_initial_secrets
   switch (version) {
   case NGTCP2_PROTO_VER_V1:
   default:
-    salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V1;
-    saltlen = sizeof(NGTCP2_INITIAL_SALT_V1) - 1;
+    salt = NGTCP2_INITIAL_SALT_V1;
+    saltlen = sizeof(NGTCP2_INITIAL_SALT_V1);
     break;
   case NGTCP2_PROTO_VER_V2:
-    salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V2;
-    saltlen = sizeof(NGTCP2_INITIAL_SALT_V2) - 1;
+    salt = NGTCP2_INITIAL_SALT_V2;
+    saltlen = sizeof(NGTCP2_INITIAL_SALT_V2);
     break;
   }
 
@@ -111,10 +127,12 @@ int ngtcp2_crypto_derive_initial_secrets
 
   if (ngtcp2_crypto_hkdf_expand_label(
         client_secret, NGTCP2_CRYPTO_INITIAL_SECRETLEN, &ctx.md, initial_secret,
-        NGTCP2_CRYPTO_INITIAL_SECRETLEN, CLABEL, sizeof(CLABEL) - 1) != 0 ||
+        NGTCP2_CRYPTO_INITIAL_SECRETLEN, CLABEL,
+        ngtcp2_strlen_lit(CLABEL)) != 0 ||
       ngtcp2_crypto_hkdf_expand_label(
         server_secret, NGTCP2_CRYPTO_INITIAL_SECRETLEN, &ctx.md, initial_secret,
-        NGTCP2_CRYPTO_INITIAL_SECRETLEN, SLABEL, sizeof(SLABEL) - 1) != 0) {
+        NGTCP2_CRYPTO_INITIAL_SECRETLEN, SLABEL,
+        ngtcp2_strlen_lit(SLABEL)) != 0) {
     return -1;
   }
 
@@ -148,19 +166,19 @@ int ngtcp2_crypto_derive_packet_protecti
   switch (version) {
   case NGTCP2_PROTO_VER_V2:
     key_label = KEY_LABEL_V2;
-    key_labellen = sizeof(KEY_LABEL_V2) - 1;
+    key_labellen = ngtcp2_strlen_lit(KEY_LABEL_V2);
     iv_label = IV_LABEL_V2;
-    iv_labellen = sizeof(IV_LABEL_V2) - 1;
+    iv_labellen = ngtcp2_strlen_lit(IV_LABEL_V2);
     hp_key_label = HP_KEY_LABEL_V2;
-    hp_key_labellen = sizeof(HP_KEY_LABEL_V2) - 1;
+    hp_key_labellen = ngtcp2_strlen_lit(HP_KEY_LABEL_V2);
     break;
   default:
     key_label = KEY_LABEL_V1;
-    key_labellen = sizeof(KEY_LABEL_V1) - 1;
+    key_labellen = ngtcp2_strlen_lit(KEY_LABEL_V1);
     iv_label = IV_LABEL_V1;
-    iv_labellen = sizeof(IV_LABEL_V1) - 1;
+    iv_labellen = ngtcp2_strlen_lit(IV_LABEL_V1);
     hp_key_label = HP_KEY_LABEL_V1;
-    hp_key_labellen = sizeof(HP_KEY_LABEL_V1) - 1;
+    hp_key_labellen = ngtcp2_strlen_lit(HP_KEY_LABEL_V1);
   }
 
   if (ngtcp2_crypto_hkdf_expand_label(key, keylen, md, secret, secretlen,
@@ -194,11 +212,11 @@ int ngtcp2_crypto_update_traffic_secret(
   switch (version) {
   case NGTCP2_PROTO_VER_V2:
     label = LABEL_V2;
-    labellen = sizeof(LABEL_V2) - 1;
+    labellen = ngtcp2_strlen_lit(LABEL_V2);
     break;
   default:
     label = LABEL;
-    labellen = sizeof(LABEL) - 1;
+    labellen = ngtcp2_strlen_lit(LABEL);
   }
 
   if (ngtcp2_crypto_hkdf_expand_label(dest, secretlen, md, secret, secretlen,
@@ -461,7 +479,9 @@ int ngtcp2_crypto_derive_and_install_tx_
 
     if (ngtcp2_conn_is_server(conn) &&
         crypto_set_local_transport_params(conn, tls) != 0) {
-      goto fail;
+      /* Just return -1 because aead_ctx and hp_ctx are now owned by
+         conn. */
+      return -1;
     }
 
     break;
@@ -590,11 +610,11 @@ int ngtcp2_crypto_derive_and_install_ini
     case NGTCP2_PROTO_VER_V1:
     default:
       retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V1;
-      retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1;
+      retry_noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V1);
       break;
     case NGTCP2_PROTO_VER_V2:
       retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V2;
-      retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1;
+      retry_noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V2);
       break;
     }
 
@@ -843,7 +863,7 @@ int ngtcp2_crypto_generate_stateless_res
   if (ngtcp2_crypto_hkdf(token, NGTCP2_STATELESS_RESET_TOKENLEN,
                          ngtcp2_crypto_md_sha256(&md), secret, secretlen,
                          cid->data, cid->datalen, info,
-                         sizeof(info) - 1) != 0) {
+                         ngtcp2_strlen_lit(info)) != 0) {
     return -1;
   }
 
@@ -863,8 +883,8 @@ static int crypto_derive_token_key(uint8
   uint8_t *p;
 
   assert(ngtcp2_crypto_md_hashlen(md) == sizeof(intsecret));
-  assert(info_prefixlen + sizeof(key_info_suffix) - 1 <= sizeof(info));
-  assert(info_prefixlen + sizeof(iv_info_suffix) - 1 <= sizeof(info));
+  assert(info_prefixlen + ngtcp2_strlen_lit(key_info_suffix) <= sizeof(info));
+  assert(info_prefixlen + ngtcp2_strlen_lit(iv_info_suffix) <= sizeof(info));
 
   if (ngtcp2_crypto_hkdf_extract(intsecret, md, secret, secretlen, salt,
                                  saltlen) != 0) {
@@ -874,8 +894,8 @@ static int crypto_derive_token_key(uint8
   memcpy(info, info_prefix, info_prefixlen);
   p = info + info_prefixlen;
 
-  memcpy(p, key_info_suffix, sizeof(key_info_suffix) - 1);
-  p += sizeof(key_info_suffix) - 1;
+  memcpy(p, key_info_suffix, ngtcp2_strlen_lit(key_info_suffix));
+  p += ngtcp2_strlen_lit(key_info_suffix);
 
   if (ngtcp2_crypto_hkdf_expand(key, keylen, md, intsecret, sizeof(intsecret),
                                 info, (size_t)(p - info)) != 0) {
@@ -884,8 +904,8 @@ static int crypto_derive_token_key(uint8
 
   p = info + info_prefixlen;
 
-  memcpy(p, iv_info_suffix, sizeof(iv_info_suffix) - 1);
-  p += sizeof(iv_info_suffix) - 1;
+  memcpy(p, iv_info_suffix, ngtcp2_strlen_lit(iv_info_suffix));
+  p += ngtcp2_strlen_lit(iv_info_suffix);
 
   if (ngtcp2_crypto_hkdf_expand(iv, ivlen, md, intsecret, sizeof(intsecret),
                                 info, (size_t)(p - info)) != 0) {
@@ -918,8 +938,8 @@ ngtcp2_ssize ngtcp2_crypto_generate_retr
   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[/* cid len = */ 1 + NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp)];
+  uint8_t plaintext[/* cid len = */ 1 + NGTCP2_MAX_CIDLEN +
+                    sizeof(ngtcp2_tstamp)] = {0};
   uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN];
   uint8_t key[16];
   uint8_t iv[12];
@@ -938,8 +958,6 @@ ngtcp2_ssize ngtcp2_crypto_generate_retr
 
   assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union));
 
-  memset(plaintext, 0, sizeof(plaintext));
-
   *p++ = (uint8_t)odcid->datalen;
   memcpy(p, odcid->data, odcid->datalen);
   p += NGTCP2_MAX_CIDLEN;
@@ -961,10 +979,10 @@ ngtcp2_ssize ngtcp2_crypto_generate_retr
   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_prefix,
-                              sizeof(retry_token_info_prefix) - 1) != 0) {
+  if (crypto_derive_token_key(
+        key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
+        sizeof(rand_data), retry_token_info_prefix,
+        ngtcp2_strlen_lit(retry_token_info_prefix)) != 0) {
     return -1;
   }
 
@@ -1038,10 +1056,10 @@ int ngtcp2_crypto_verify_retry_token(
   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_prefix,
-                              sizeof(retry_token_info_prefix) - 1) != 0) {
+  if (crypto_derive_token_key(
+        key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
+        NGTCP2_CRYPTO_TOKEN_RAND_DATALEN, retry_token_info_prefix,
+        ngtcp2_strlen_lit(retry_token_info_prefix)) != 0) {
     return -1;
   }
 
@@ -1100,7 +1118,7 @@ ngtcp2_ssize ngtcp2_crypto_generate_retr
   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)];
+                    NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp)] = {0};
   uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN];
   uint8_t key[16];
   uint8_t iv[12];
@@ -1117,8 +1135,6 @@ ngtcp2_ssize ngtcp2_crypto_generate_retr
 
   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;
@@ -1141,10 +1157,10 @@ ngtcp2_ssize ngtcp2_crypto_generate_retr
   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) {
+  if (crypto_derive_token_key(
+        key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
+        sizeof(rand_data), retry_token_info_prefix2,
+        ngtcp2_strlen_lit(retry_token_info_prefix2)) != 0) {
     return -1;
   }
 
@@ -1219,10 +1235,10 @@ int ngtcp2_crypto_verify_retry_token2(
   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) {
+  if (crypto_derive_token_key(
+        key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
+        NGTCP2_CRYPTO_TOKEN_RAND_DATALEN, retry_token_info_prefix2,
+        ngtcp2_strlen_lit(retry_token_info_prefix2)) != 0) {
     return NGTCP2_CRYPTO_ERR_INTERNAL;
   }
 
@@ -1305,13 +1321,22 @@ static size_t crypto_generate_regular_to
   return addrlen;
 }
 
+/* NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN is the maximum length of
+   opaque data embedded in a regular token. */
+#define NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN 256
+
+/* NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN is the maximum length
+   of plaintext included in a regular token. */
+#define NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN                           \
+  (sizeof(ngtcp2_tstamp) + NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN)
+
 static const uint8_t regular_token_info_prefix[] = "regular_token";
 
-ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
+static ngtcp2_ssize crypto_generate_regular_token(
   uint8_t *token, const uint8_t *secret, size_t secretlen,
   const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
-  ngtcp2_tstamp ts) {
-  uint8_t plaintext[sizeof(ngtcp2_tstamp)];
+  const void *data, size_t datalen, ngtcp2_tstamp ts) {
+  uint8_t plaintext[NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN];
   uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN];
   uint8_t key[16];
   uint8_t iv[12];
@@ -1328,9 +1353,18 @@ ngtcp2_ssize ngtcp2_crypto_generate_regu
   int rv;
   (void)remote_addrlen;
 
+  if (datalen > NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN) {
+    return -1;
+  }
+
   memcpy(p, &ts_be, sizeof(ts_be));
   p += sizeof(ts_be);
 
+  if (datalen) {
+    memcpy(p, data, datalen);
+    p += datalen;
+  }
+
   plaintextlen = (size_t)(p - plaintext);
 
   if (ngtcp2_crypto_random(rand_data, sizeof(rand_data)) != 0) {
@@ -1346,10 +1380,10 @@ ngtcp2_ssize ngtcp2_crypto_generate_regu
   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),
-                              regular_token_info_prefix,
-                              sizeof(regular_token_info_prefix) - 1) != 0) {
+  if (crypto_derive_token_key(
+        key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
+        sizeof(rand_data), regular_token_info_prefix,
+        ngtcp2_strlen_lit(regular_token_info_prefix)) != 0) {
     return -1;
   }
 
@@ -1378,13 +1412,11 @@ ngtcp2_ssize ngtcp2_crypto_generate_regu
   return p - token;
 }
 
-int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
-                                       const uint8_t *secret, size_t secretlen,
-                                       const ngtcp2_sockaddr *remote_addr,
-                                       ngtcp2_socklen remote_addrlen,
-                                       ngtcp2_duration timeout,
-                                       ngtcp2_tstamp ts) {
-  uint8_t plaintext[sizeof(ngtcp2_tstamp)];
+static ngtcp2_ssize crypto_verify_regular_token(
+  void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
+  const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
+  ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts) {
+  uint8_t plaintext[NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN];
   uint8_t key[16];
   uint8_t iv[12];
   size_t keylen;
@@ -1397,13 +1429,14 @@ int ngtcp2_crypto_verify_regular_token(c
   const uint8_t *rand_data;
   const uint8_t *ciphertext;
   size_t ciphertextlen;
+  size_t datalen;
   int rv;
   ngtcp2_tstamp gen_ts;
   (void)remote_addrlen;
 
-  if (tokenlen != NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN ||
+  if (tokenlen < NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN ||
       token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR) {
-    return -1;
+    return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
   }
 
   rand_data = token + tokenlen - NGTCP2_CRYPTO_TOKEN_RAND_DATALEN;
@@ -1413,23 +1446,27 @@ int ngtcp2_crypto_verify_regular_token(c
   ngtcp2_crypto_aead_aes_128_gcm(&aead);
   ngtcp2_crypto_md_sha256(&md);
 
+  if (ciphertextlen > sizeof(plaintext) + aead.max_overhead) {
+    return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
+  }
+
   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,
-                              regular_token_info_prefix,
-                              sizeof(regular_token_info_prefix) - 1) != 0) {
-    return -1;
+  if (crypto_derive_token_key(
+        key, keylen, iv, ivlen, &md, secret, secretlen, rand_data,
+        NGTCP2_CRYPTO_TOKEN_RAND_DATALEN, regular_token_info_prefix,
+        ngtcp2_strlen_lit(regular_token_info_prefix)) != 0) {
+    return NGTCP2_CRYPTO_ERR_INTERNAL;
   }
 
   aadlen = crypto_generate_regular_token_aad(aad, remote_addr);
 
   if (ngtcp2_crypto_aead_ctx_decrypt_init(&aead_ctx, &aead, key, ivlen) != 0) {
-    return -1;
+    return NGTCP2_CRYPTO_ERR_INTERNAL;
   }
 
   rv = ngtcp2_crypto_decrypt(plaintext, &aead, &aead_ctx, ciphertext,
@@ -1438,19 +1475,74 @@ int ngtcp2_crypto_verify_regular_token(c
   ngtcp2_crypto_aead_ctx_free(&aead_ctx);
 
   if (rv != 0) {
-    return -1;
+    return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
   }
 
   memcpy(&gen_ts, plaintext, sizeof(gen_ts));
 
   gen_ts = ngtcp2_ntohl64(gen_ts);
   if (gen_ts + timeout <= ts) {
+    return NGTCP2_CRYPTO_ERR_VERIFY_TOKEN;
+  }
+
+  if (max_datalen == 0) {
+    return 0;
+  }
+
+  datalen = ciphertextlen - aead.max_overhead - sizeof(gen_ts);
+  if (datalen > max_datalen) {
+    return 0;
+  }
+
+  memcpy(data, plaintext + sizeof(gen_ts), datalen);
+
+  return (ngtcp2_ssize)datalen;
+}
+
+ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
+  uint8_t *token, const uint8_t *secret, size_t secretlen,
+  const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
+  ngtcp2_tstamp ts) {
+  return crypto_generate_regular_token(token, secret, secretlen, remote_addr,
+                                       remote_addrlen, NULL, 0, ts);
+}
+
+int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
+                                       const uint8_t *secret, size_t secretlen,
+                                       const ngtcp2_sockaddr *remote_addr,
+                                       ngtcp2_socklen remote_addrlen,
+                                       ngtcp2_duration timeout,
+                                       ngtcp2_tstamp ts) {
+  ngtcp2_ssize datalen =
+    crypto_verify_regular_token(NULL, 0, token, tokenlen, secret, secretlen,
+                                remote_addr, remote_addrlen, timeout, ts);
+
+  if (datalen < 0) {
     return -1;
   }
 
+  assert(0 == datalen);
+
   return 0;
 }
 
+ngtcp2_ssize ngtcp2_crypto_generate_regular_token2(
+  uint8_t *token, const uint8_t *secret, size_t secretlen,
+  const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
+  const void *data, size_t datalen, ngtcp2_tstamp ts) {
+  return crypto_generate_regular_token(token, secret, secretlen, remote_addr,
+                                       remote_addrlen, data, datalen, ts);
+}
+
+ngtcp2_ssize ngtcp2_crypto_verify_regular_token2(
+  void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
+  const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
+  ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts) {
+  return crypto_verify_regular_token(data, max_datalen, token, tokenlen, secret,
+                                     secretlen, remote_addr, remote_addrlen,
+                                     timeout, ts);
+}
+
 ngtcp2_ssize ngtcp2_crypto_write_connection_close(
   uint8_t *dest, size_t destlen, uint32_t version, const ngtcp2_cid *dcid,
   const ngtcp2_cid *scid, uint64_t error_code, const uint8_t *reason,
@@ -1523,11 +1615,11 @@ ngtcp2_ssize ngtcp2_crypto_write_retry(u
   case NGTCP2_PROTO_VER_V1:
   default:
     key = (const uint8_t *)NGTCP2_RETRY_KEY_V1;
-    noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1;
+    noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V1);
     break;
   case NGTCP2_PROTO_VER_V2:
     key = (const uint8_t *)NGTCP2_RETRY_KEY_V2;
-    noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1;
+    noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V2);
     break;
   }
 
@@ -1637,8 +1729,21 @@ int ngtcp2_crypto_recv_crypto_data_cb(ng
   (void)offset;
   (void)user_data;
 
-  if (ngtcp2_crypto_read_write_crypto_data(conn, encryption_level, data,
-                                           datalen) != 0) {
+  rv =
+    ngtcp2_crypto_read_write_crypto_data(conn, encryption_level, data, datalen);
+  if (rv != 0) {
+    switch (rv) {
+    case /* NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB */ -10001:
+    case /* NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP */ -10002:
+      /* These errors are not unrecoverable error, and they just
+         indicate that handshake has been interrupted.  ngtcp2 does
+         not mind whether handshake is interrupted or not.  Just
+         return 0 in this case.  There are OSSL version and they have
+         the same enum value, therefore we cannot enumerate them
+         here. */
+      return 0;
+    }
+
     rv = ngtcp2_conn_get_tls_error(conn);
     if (rv) {
       return rv;
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/shared.h samba-4.23.8/third_party/ngtcp2/crypto/shared.h
--- samba-4.23.7/third_party/ngtcp2/crypto/shared.h	2026-01-23 11:53:43.281754700 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/shared.h	2026-05-15 15:49:15.152978400 +0200
@@ -31,26 +31,6 @@
 
 #include <ngtcp2/ngtcp2_crypto.h>
 
-/**
- * @macro
- *
- * :macro:`NGTCP2_INITIAL_SALT_V1` is a salt value which is used to
- * derive initial secret.  It is used for QUIC v1.
- */
-#define NGTCP2_INITIAL_SALT_V1                                                 \
-  "\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17\x9a\xe6\xa4\xc8\x0c\xad\xcc\xbb"   \
-  "\x7f\x0a"
-
-/**
- * @macro
- *
- * :macro:`NGTCP2_INITIAL_SALT_V2` is a salt value which is used to
- * derive initial secret.  It is used for QUIC v2.
- */
-#define NGTCP2_INITIAL_SALT_V2                                                 \
-  "\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93\x81\xbe\x6e\x26\x9d\xcb\xf9\xbd"   \
-  "\x2e\xd9"
-
 /* Maximum key usage (encryption) limits */
 #define NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM (1ULL << 23)
 #define NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305 (1ULL << 62)
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/wolfssl/libngtcp2_crypto_wolfssl.pc.in samba-4.23.8/third_party/ngtcp2/crypto/wolfssl/libngtcp2_crypto_wolfssl.pc.in
--- samba-4.23.7/third_party/ngtcp2/crypto/wolfssl/libngtcp2_crypto_wolfssl.pc.in	2026-01-23 11:53:43.281754700 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/wolfssl/libngtcp2_crypto_wolfssl.pc.in	2026-05-15 15:49:15.152978400 +0200
@@ -31,3 +31,4 @@ URL: https://github.com/ngtcp2/ngtcp2
 Version: @VERSION@
 Libs: -L${libdir} -lngtcp2_crypto_wolfssl
 Cflags: -I${includedir}
+Requires.private: libngtcp2, wolfssl
diff -Npur samba-4.23.7/third_party/ngtcp2/crypto/wolfssl/wolfssl.c samba-4.23.8/third_party/ngtcp2/crypto/wolfssl/wolfssl.c
--- samba-4.23.7/third_party/ngtcp2/crypto/wolfssl/wolfssl.c	2026-01-23 11:53:43.281754700 +0100
+++ samba-4.23.8/third_party/ngtcp2/crypto/wolfssl/wolfssl.c	2026-05-15 15:49:15.152978400 +0200
@@ -34,6 +34,7 @@
 #include <wolfssl/ssl.h>
 #include <wolfssl/quic.h>
 
+#include "ngtcp2_macro.h"
 #include "shared.h"
 
 #define PRINTF_DEBUG 0
@@ -55,7 +56,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha25
 ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) {
   ngtcp2_crypto_aead_init(&ctx->aead, (void *)wolfSSL_EVP_aes_128_gcm());
   ctx->md.native_handle = (void *)wolfSSL_EVP_sha256();
-  ctx->hp.native_handle = (void *)wolfSSL_EVP_aes_128_ctr();
+  ctx->hp.native_handle = (void *)wolfSSL_EVP_aes_128_ecb();
   ctx->max_encryption = 0;
   ctx->max_decryption_failure = 0;
   return ctx;
@@ -106,6 +107,21 @@ static int supported_aead(const WOLFSSL_
          wolfSSL_quic_aead_is_chacha20(aead) || wolfSSL_quic_aead_is_ccm(aead);
 }
 
+static const WOLFSSL_EVP_CIPHER *
+crypto_aead_get_hp(const WOLFSSL_EVP_CIPHER *aead) {
+  switch (wolfSSL_EVP_CIPHER_nid(aead)) {
+  case NID_aes_128_gcm:
+  case NID_aes_128_ccm:
+    return wolfSSL_EVP_aes_128_ecb();
+  case NID_aes_256_gcm:
+    return wolfSSL_EVP_aes_256_ecb();
+  case NID_chacha20_poly1305:
+    return wolfSSL_EVP_chacha20();
+  default:
+    return NULL;
+  }
+}
+
 ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx,
                                          void *tls_native_handle) {
   WOLFSSL *ssl = tls_native_handle;
@@ -121,7 +137,7 @@ ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls
 
   ngtcp2_crypto_aead_init(&ctx->aead, (void *)aead);
   ctx->md.native_handle = (void *)wolfSSL_quic_get_md(ssl);
-  ctx->hp.native_handle = (void *)wolfSSL_quic_get_hp(ssl);
+  ctx->hp.native_handle = (void *)crypto_aead_get_hp(aead);
   ctx->max_encryption = crypto_aead_get_aead_max_encryption(aead);
   ctx->max_decryption_failure =
     crypto_aead_get_aead_max_decryption_failure(aead);
@@ -288,20 +304,33 @@ int ngtcp2_crypto_decrypt(uint8_t *dest,
 int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
                           const ngtcp2_crypto_cipher_ctx *hp_ctx,
                           const uint8_t *sample) {
-  static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
+  static const uint8_t PLAINTEXT[16] = {0};
   WOLFSSL_EVP_CIPHER_CTX *actx = hp_ctx->native_handle;
   int len;
 
   (void)hp;
 
-  if (wolfSSL_EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) !=
-        WOLFSSL_SUCCESS ||
-      wolfSSL_EVP_CipherUpdate(actx, dest, &len, PLAINTEXT,
-                               sizeof(PLAINTEXT) - 1) != WOLFSSL_SUCCESS ||
-      wolfSSL_EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len) !=
-        WOLFSSL_SUCCESS) {
-    DEBUG_MSG("WOLFSSL: hp_mask FAILED\n");
-    return -1;
+  switch (wolfSSL_EVP_CIPHER_CTX_nid(actx)) {
+  case NID_aes_128_ecb:
+  case NID_aes_256_ecb:
+    if (!wolfSSL_EVP_CipherUpdate(actx, dest, &len, sample,
+                                  NGTCP2_HP_SAMPLELEN)) {
+      return -1;
+    }
+
+    break;
+  case NID_chacha20:
+    if (wolfSSL_EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) !=
+          WOLFSSL_SUCCESS ||
+        wolfSSL_EVP_CipherUpdate(actx, dest, &len, PLAINTEXT,
+                                 sizeof(PLAINTEXT)) != WOLFSSL_SUCCESS ||
+        wolfSSL_EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT), &len) !=
+          WOLFSSL_SUCCESS) {
+      DEBUG_MSG("WOLFSSL: hp_mask FAILED\n");
+      return -1;
+    }
+
+    break;
   }
 
   return 0;
@@ -440,6 +469,19 @@ int ngtcp2_crypto_get_path_challenge_dat
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
   return 0;
+}
+
+int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn,
+                                              ngtcp2_path_challenge_data *data,
+                                              void *user_data) {
+  (void)conn;
+  (void)user_data;
+
+  DEBUG_MSG("WOLFSSL: get path challenge data\n");
+  if (wolfSSL_RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+  return 0;
 }
 
 int ngtcp2_crypto_random(uint8_t *data, size_t datalen) {
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/CMakeLists.txt samba-4.23.8/third_party/ngtcp2/lib/CMakeLists.txt
--- samba-4.23.7/third_party/ngtcp2/lib/CMakeLists.txt	2026-01-23 11:53:43.285755600 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/CMakeLists.txt	2026-05-15 15:49:15.152978400 +0200
@@ -67,12 +67,17 @@ set(ngtcp2_SOURCES
   ngtcp2_unreachable.c
   ngtcp2_transport_params.c
   ngtcp2_settings.c
+  ngtcp2_callbacks.c
   ngtcp2_dcidtr.c
+  ngtcp2_pcg.c
+  ngtcp2_ratelim.c
+  ngtcp2_conn_info.c
 )
 
 set(ngtcp2_INCLUDE_DIRS
-  "${CMAKE_CURRENT_SOURCE_DIR}/includes"
-  "${CMAKE_CURRENT_BINARY_DIR}/includes"
+  "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/includes>"
+  "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/includes>"
+  "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
 )
 
 set(NGTCP2_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
@@ -103,11 +108,7 @@ if(ENABLE_SHARED_LIB)
     C_VISIBILITY_PRESET hidden
     POSITION_INDEPENDENT_CODE ON
   )
-  foreach(include_DIR IN LISTS ngtcp2_INCLUDE_DIRS)
-    target_include_directories(ngtcp2 PUBLIC $<BUILD_INTERFACE:${include_DIR}>)
-  endforeach()
-
-  target_include_directories(ngtcp2 PUBLIC $<INSTALL_INTERFACE:./include>)
+  target_include_directories(ngtcp2 PUBLIC ${ngtcp2_INCLUDE_DIRS})
 
   install(TARGETS ngtcp2
     EXPORT ${NGTCP2_TARGETS_EXPORT_NAME}
@@ -126,11 +127,7 @@ if(ENABLE_STATIC_LIB)
     C_VISIBILITY_PRESET hidden
   )
   target_compile_definitions(ngtcp2_static PUBLIC "-DNGTCP2_STATICLIB")
-  foreach(include_DIR IN LISTS ngtcp2_INCLUDE_DIRS)
-    target_include_directories(ngtcp2_static PUBLIC $<BUILD_INTERFACE:${include_DIR}>)
-  endforeach()
-
-  target_include_directories(ngtcp2_static PUBLIC $<INSTALL_INTERFACE:./include>)
+  target_include_directories(ngtcp2_static PUBLIC ${ngtcp2_INCLUDE_DIRS})
 
   install(TARGETS ngtcp2_static
     EXPORT ${NGTCP2_TARGETS_EXPORT_NAME}
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/Makefile.am samba-4.23.8/third_party/ngtcp2/lib/Makefile.am
--- samba-4.23.7/third_party/ngtcp2/lib/Makefile.am	2026-01-23 11:53:43.285755600 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/Makefile.am	2026-05-15 15:49:15.152978400 +0200
@@ -75,7 +75,11 @@ OBJECTS = \
 	ngtcp2_unreachable.c \
 	ngtcp2_transport_params.c \
 	ngtcp2_settings.c \
-	ngtcp2_dcidtr.c
+	ngtcp2_callbacks.c \
+	ngtcp2_dcidtr.c \
+	ngtcp2_pcg.c \
+	ngtcp2_ratelim.c \
+	ngtcp2_conn_info.c
 
 HFILES = \
 	ngtcp2_pkt.h \
@@ -120,7 +124,11 @@ HFILES = \
 	ngtcp2_unreachable.h \
 	ngtcp2_transport_params.h \
 	ngtcp2_settings.h \
+	ngtcp2_callbacks.h \
 	ngtcp2_dcidtr.h \
+	ngtcp2_pcg.h \
+	ngtcp2_ratelim.h \
+	ngtcp2_conn_info.h \
 	ngtcp2_conn_stat.h \
 	ngtcp2_pktns_id.h \
 	ngtcp2_tstamp.h
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/config.cmake.in samba-4.23.8/third_party/ngtcp2/lib/config.cmake.in
--- samba-4.23.7/third_party/ngtcp2/lib/config.cmake.in	2026-01-23 11:53:43.285755600 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/config.cmake.in	2026-05-15 15:49:15.153978300 +0200
@@ -1,3 +1,6 @@
 include(CMakeFindDependencyMacro)
+if("@HAVE_OSSL@")
+    find_dependency(OpenSSL)
+endif()
 
 include("${CMAKE_CURRENT_LIST_DIR}/@NGTCP2_TARGETS_EXPORT_NAME@.cmake")
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/includes/ngtcp2/ngtcp2.h samba-4.23.8/third_party/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
--- samba-4.23.7/third_party/ngtcp2/lib/includes/ngtcp2/ngtcp2.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/includes/ngtcp2/ngtcp2.h	2026-05-15 15:49:15.154978300 +0200
@@ -262,7 +262,7 @@ typedef struct ngtcp2_mem {
  *
  * :macro:`NGTCP2_PROTO_VER_V1` is the QUIC version 1.
  */
-#define NGTCP2_PROTO_VER_V1 ((uint32_t)0x00000001u)
+#define NGTCP2_PROTO_VER_V1 ((uint32_t)0x00000001U)
 
 /**
  * @macro
@@ -270,7 +270,7 @@ typedef struct ngtcp2_mem {
  * :macro:`NGTCP2_PROTO_VER_V2` is the QUIC version 2.  See
  * :rfc:`9369`.
  */
-#define NGTCP2_PROTO_VER_V2 ((uint32_t)0x6b3343cfu)
+#define NGTCP2_PROTO_VER_V2 ((uint32_t)0x6B3343CFU)
 
 /**
  * @macro
@@ -294,7 +294,7 @@ typedef struct ngtcp2_mem {
  * :macro:`NGTCP2_RESERVED_VERSION_MASK` is the bit mask of reserved
  * version.
  */
-#define NGTCP2_RESERVED_VERSION_MASK 0x0a0a0a0au
+#define NGTCP2_RESERVED_VERSION_MASK 0x0A0A0A0AU
 
 /**
  * @macrosection
@@ -306,15 +306,29 @@ typedef struct ngtcp2_mem {
  * @macro
  *
  * :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE` is the default maximum UDP
- * datagram payload size that the local endpoint transmits.
+ * datagram payload size that the local endpoint transmits without
+ * Path MTU Discovery (PMTUD) or the custom settings (see
+ * :member:`ngtcp2_settings.max_tx_udp_payload_size` and
+ * :member:`ngtcp2_settings.no_tx_udp_payload_size_shaping`).
  */
 #define NGTCP2_MAX_UDP_PAYLOAD_SIZE 1200
 
 /**
  * @macro
  *
- * :macro:`NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE` is the maximum UDP
+ * :macro:`NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE` is the maximum UDP datagram
+ * payload size that this library can output.
+ */
+#define NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE 65527
+
+/**
+ * @macro
+ *
+ * :macro:`NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE` was the maximum UDP
  * datagram payload size that Path MTU Discovery can discover.
+ *
+ * Deprecated since v1.17.0.  Path MTU Discovery is not capped to this
+ * value anymore.
  */
 #define NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE 1452
 
@@ -363,7 +377,7 @@ typedef struct ngtcp2_mem {
  * integrity tag of Retry packet.  It is used for QUIC v1.
  */
 #define NGTCP2_RETRY_KEY_V1                                                    \
-  "\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e"
+  "\xBE\x0C\x69\x0B\x9F\x66\x57\x5A\x1D\x76\x6B\x54\xE3\x68\xC8\x4E"
 
 /**
  * @macro
@@ -371,7 +385,7 @@ typedef struct ngtcp2_mem {
  * :macro:`NGTCP2_RETRY_NONCE_V1` is nonce used when generating
  * integrity tag of Retry packet.  It is used for QUIC v1.
  */
-#define NGTCP2_RETRY_NONCE_V1 "\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb"
+#define NGTCP2_RETRY_NONCE_V1 "\x46\x15\x99\xD3\x5D\x63\x2B\xF2\x23\x98\x25\xBB"
 
 /**
  * @macro
@@ -381,7 +395,7 @@ typedef struct ngtcp2_mem {
  * :rfc:`9369`.
  */
 #define NGTCP2_RETRY_KEY_V2                                                    \
-  "\x8f\xb4\xb0\x1b\x56\xac\x48\xe2\x60\xfb\xcb\xce\xad\x7c\xcc\x92"
+  "\x8F\xB4\xB0\x1B\x56\xAC\x48\xE2\x60\xFB\xCB\xCE\xAD\x7C\xCC\x92"
 
 /**
  * @macro
@@ -390,7 +404,7 @@ typedef struct ngtcp2_mem {
  * integrity tag of Retry packet.  It is used for QUIC v2.  See
  * :rfc:`9369`.
  */
-#define NGTCP2_RETRY_NONCE_V2 "\xd8\x69\x69\xbc\x2d\x7c\x6d\x99\x90\xef\xb0\x4a"
+#define NGTCP2_RETRY_NONCE_V2 "\xD8\x69\x69\xBC\x2D\x7C\x6D\x99\x90\xEF\xB0\x4A"
 
 /**
  * @macro
@@ -798,7 +812,7 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pk
  *
  * :macro:`NGTCP2_PKT_FLAG_NONE` indicates no flag set.
  */
-#define NGTCP2_PKT_FLAG_NONE 0x00u
+#define NGTCP2_PKT_FLAG_NONE 0x00U
 
 /**
  * @macro
@@ -806,7 +820,7 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pk
  * :macro:`NGTCP2_PKT_FLAG_LONG_FORM` indicates the Long header packet
  * header.
  */
-#define NGTCP2_PKT_FLAG_LONG_FORM 0x01u
+#define NGTCP2_PKT_FLAG_LONG_FORM 0x01U
 
 /**
  * @macro
@@ -814,14 +828,14 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pk
  * :macro:`NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR` indicates that Fixed Bit
  * (aka QUIC bit) is not set.
  */
-#define NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR 0x02u
+#define NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR 0x02U
 
 /**
  * @macro
  *
  * :macro:`NGTCP2_PKT_FLAG_KEY_PHASE` indicates Key Phase bit set.
  */
-#define NGTCP2_PKT_FLAG_KEY_PHASE 0x04u
+#define NGTCP2_PKT_FLAG_KEY_PHASE 0x04U
 
 /**
  * @enum
@@ -873,7 +887,7 @@ typedef enum ngtcp2_pkt_type {
  *
  * :macro:`NGTCP2_NO_ERROR` is QUIC transport error code ``NO_ERROR``.
  */
-#define NGTCP2_NO_ERROR 0x0u
+#define NGTCP2_NO_ERROR 0x0U
 
 /**
  * @macro
@@ -881,7 +895,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_INTERNAL_ERROR` is QUIC transport error code
  * ``INTERNAL_ERROR``.
  */
-#define NGTCP2_INTERNAL_ERROR 0x1u
+#define NGTCP2_INTERNAL_ERROR 0x1U
 
 /**
  * @macro
@@ -889,7 +903,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_CONNECTION_REFUSED` is QUIC transport error code
  * ``CONNECTION_REFUSED``.
  */
-#define NGTCP2_CONNECTION_REFUSED 0x2u
+#define NGTCP2_CONNECTION_REFUSED 0x2U
 
 /**
  * @macro
@@ -897,7 +911,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_FLOW_CONTROL_ERROR` is QUIC transport error code
  * ``FLOW_CONTROL_ERROR``.
  */
-#define NGTCP2_FLOW_CONTROL_ERROR 0x3u
+#define NGTCP2_FLOW_CONTROL_ERROR 0x3U
 
 /**
  * @macro
@@ -905,7 +919,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_STREAM_LIMIT_ERROR` is QUIC transport error code
  * ``STREAM_LIMIT_ERROR``.
  */
-#define NGTCP2_STREAM_LIMIT_ERROR 0x4u
+#define NGTCP2_STREAM_LIMIT_ERROR 0x4U
 
 /**
  * @macro
@@ -913,7 +927,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_STREAM_STATE_ERROR` is QUIC transport error code
  * ``STREAM_STATE_ERROR``.
  */
-#define NGTCP2_STREAM_STATE_ERROR 0x5u
+#define NGTCP2_STREAM_STATE_ERROR 0x5U
 
 /**
  * @macro
@@ -921,7 +935,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_FINAL_SIZE_ERROR` is QUIC transport error code
  * ``FINAL_SIZE_ERROR``.
  */
-#define NGTCP2_FINAL_SIZE_ERROR 0x6u
+#define NGTCP2_FINAL_SIZE_ERROR 0x6U
 
 /**
  * @macro
@@ -929,7 +943,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_FRAME_ENCODING_ERROR` is QUIC transport error code
  * ``FRAME_ENCODING_ERROR``.
  */
-#define NGTCP2_FRAME_ENCODING_ERROR 0x7u
+#define NGTCP2_FRAME_ENCODING_ERROR 0x7U
 
 /**
  * @macro
@@ -937,7 +951,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_TRANSPORT_PARAMETER_ERROR` is QUIC transport error
  * code ``TRANSPORT_PARAMETER_ERROR``.
  */
-#define NGTCP2_TRANSPORT_PARAMETER_ERROR 0x8u
+#define NGTCP2_TRANSPORT_PARAMETER_ERROR 0x8U
 
 /**
  * @macro
@@ -945,7 +959,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_CONNECTION_ID_LIMIT_ERROR` is QUIC transport error
  * code ``CONNECTION_ID_LIMIT_ERROR``.
  */
-#define NGTCP2_CONNECTION_ID_LIMIT_ERROR 0x9u
+#define NGTCP2_CONNECTION_ID_LIMIT_ERROR 0x9U
 
 /**
  * @macro
@@ -953,7 +967,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_PROTOCOL_VIOLATION` is QUIC transport error code
  * ``PROTOCOL_VIOLATION``.
  */
-#define NGTCP2_PROTOCOL_VIOLATION 0xau
+#define NGTCP2_PROTOCOL_VIOLATION 0xAU
 
 /**
  * @macro
@@ -961,7 +975,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_INVALID_TOKEN` is QUIC transport error code
  * ``INVALID_TOKEN``.
  */
-#define NGTCP2_INVALID_TOKEN 0xbu
+#define NGTCP2_INVALID_TOKEN 0xBU
 
 /**
  * @macro
@@ -969,7 +983,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_APPLICATION_ERROR` is QUIC transport error code
  * ``APPLICATION_ERROR``.
  */
-#define NGTCP2_APPLICATION_ERROR 0xcu
+#define NGTCP2_APPLICATION_ERROR 0xCU
 
 /**
  * @macro
@@ -977,7 +991,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_CRYPTO_BUFFER_EXCEEDED` is QUIC transport error code
  * ``CRYPTO_BUFFER_EXCEEDED``.
  */
-#define NGTCP2_CRYPTO_BUFFER_EXCEEDED 0xdu
+#define NGTCP2_CRYPTO_BUFFER_EXCEEDED 0xDU
 
 /**
  * @macro
@@ -985,7 +999,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_KEY_UPDATE_ERROR` is QUIC transport error code
  * ``KEY_UPDATE_ERROR``.
  */
-#define NGTCP2_KEY_UPDATE_ERROR 0xeu
+#define NGTCP2_KEY_UPDATE_ERROR 0xEU
 
 /**
  * @macro
@@ -993,7 +1007,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_AEAD_LIMIT_REACHED` is QUIC transport error code
  * ``AEAD_LIMIT_REACHED``.
  */
-#define NGTCP2_AEAD_LIMIT_REACHED 0xfu
+#define NGTCP2_AEAD_LIMIT_REACHED 0xFU
 
 /**
  * @macro
@@ -1001,7 +1015,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_NO_VIABLE_PATH` is QUIC transport error code
  * ``NO_VIABLE_PATH``.
  */
-#define NGTCP2_NO_VIABLE_PATH 0x10u
+#define NGTCP2_NO_VIABLE_PATH 0x10U
 
 /**
  * @macro
@@ -1009,7 +1023,7 @@ typedef enum ngtcp2_pkt_type {
  * :macro:`NGTCP2_CRYPTO_ERROR` is QUIC transport error code
  * ``CRYPTO_ERROR``.
  */
-#define NGTCP2_CRYPTO_ERROR 0x100u
+#define NGTCP2_CRYPTO_ERROR 0x100U
 
 /**
  * @macro
@@ -1173,6 +1187,9 @@ typedef struct ngtcp2_pkt_hd {
  * @struct
  *
  * :type:`ngtcp2_pkt_stateless_reset` represents Stateless Reset.
+ *
+ * Deprecated since v1.22.0.  Use :type:`ngtcp2_pkt_stateless_reset2`
+ * instead.
  */
 typedef struct ngtcp2_pkt_stateless_reset {
   /**
@@ -1191,6 +1208,40 @@ typedef struct ngtcp2_pkt_stateless_rese
 } ngtcp2_pkt_stateless_reset;
 
 /**
+ * @struct
+ *
+ * :type:`ngtcp2_stateless_reset_token` stores stateless reset token.
+ *
+ * This struct has been available since v1.22.0.
+ */
+typedef struct ngtcp2_stateless_reset_token {
+  uint8_t data[NGTCP2_STATELESS_RESET_TOKENLEN];
+} ngtcp2_stateless_reset_token;
+
+/**
+ * @struct
+ *
+ * :type:`ngtcp2_pkt_stateless_reset2` represents Stateless Reset.
+ *
+ * This struct has been available since v1.22.0.
+ */
+typedef struct ngtcp2_pkt_stateless_reset2 {
+  /**
+   * :member:`token` contains stateless reset token.
+   */
+  ngtcp2_stateless_reset_token token;
+  /**
+   * :member:`rand` points a buffer which contains random bytes
+   * section.
+   */
+  const uint8_t *rand;
+  /**
+   * :member:`randlen` is the number of random bytes.
+   */
+  size_t randlen;
+} ngtcp2_pkt_stateless_reset2;
+
+/**
  * @macrosection
  *
  * QUIC transport parameters related macros
@@ -1236,7 +1287,7 @@ typedef struct ngtcp2_pkt_stateless_rese
  * :macro:`NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1` is TLS
  * extension type of quic_transport_parameters.
  */
-#define NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1 0x39u
+#define NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1 0x39U
 
 #ifdef NGTCP2_USE_GENERIC_SOCKADDR
 #  ifndef NGTCP2_AF_INET
@@ -1267,7 +1318,7 @@ typedef struct ngtcp2_sockaddr_in {
 } ngtcp2_sockaddr_in;
 
 typedef struct ngtcp2_in6_addr {
-  uint8_t in6_addr[16];
+  uint8_t s6_addr[16];
 } ngtcp2_in6_addr;
 
 typedef struct ngtcp2_sockaddr_in6 {
@@ -1561,7 +1612,8 @@ typedef struct ngtcp2_transport_params {
 } ngtcp2_transport_params;
 
 #define NGTCP2_CONN_INFO_V1 1
-#define NGTCP2_CONN_INFO_VERSION NGTCP2_CONN_INFO_V1
+#define NGTCP2_CONN_INFO_V2 2
+#define NGTCP2_CONN_INFO_VERSION NGTCP2_CONN_INFO_V2
 
 /**
  * @struct
@@ -1600,6 +1652,52 @@ typedef struct ngtcp2_conn_info {
    * packets which have not been acknowledged.
    */
   uint64_t bytes_in_flight;
+  /* The following fields have been added since NGTCP2_CONN_INFO_V2. */
+  /**
+   * :member:`pkt_sent` is the number of QUIC packets sent.  This
+   * field has been available since v1.16.0.
+   */
+  uint64_t pkt_sent;
+  /**
+   * :member:`bytes_sent` is the number of bytes (the sum of QUIC
+   * packet length) sent.  This field has been available since
+   * v1.16.0.
+   */
+  uint64_t bytes_sent;
+  /**
+   * :member:`pkt_recv` is the number of QUIC packets received,
+   * excluding discarded ones.  This field has been available since
+   * v1.16.0.
+   */
+  uint64_t pkt_recv;
+  /**
+   * :member:`bytes_recv` is the number of bytes (the sum of QUIC
+   * packet length) received, excluding discarded ones.  This field
+   * has been available since v1.16.0.
+   */
+  uint64_t bytes_recv;
+  /**
+   * :member:`pkt_lost` is the number of QUIC packets that are
+   * considered lost, excluding PMTUD packets.  This field has been
+   * available since v1.16.0.
+   */
+  uint64_t pkt_lost;
+  /**
+   * :member:`bytes_lost` is the number of bytes (the sum of QUIC
+   * packet length) lost, excluding PMTUD packets.  This field has
+   * been available since v1.16.0.
+   */
+  uint64_t bytes_lost;
+  /**
+   * :member:`ping_recv` is the number of PING frames received.  This
+   * field has been available since v1.16.0.
+   */
+  uint64_t ping_recv;
+  /**
+   * :member:`pkt_discarded` is the number of QUIC packets discarded.
+   * This field has been available since v1.16.0.
+   */
+  uint64_t pkt_discarded;
 } ngtcp2_conn_info;
 
 /**
@@ -1642,14 +1740,14 @@ typedef void (*ngtcp2_printf)(void *user
  *
  * :macro:`NGTCP2_QLOG_WRITE_FLAG_NONE` indicates no flag set.
  */
-#define NGTCP2_QLOG_WRITE_FLAG_NONE 0x00u
+#define NGTCP2_QLOG_WRITE_FLAG_NONE 0x00U
 /**
  * @macro
  *
  * :macro:`NGTCP2_QLOG_WRITE_FLAG_FIN` indicates that this is the
  * final call to :type:`ngtcp2_qlog_write` in the current connection.
  */
-#define NGTCP2_QLOG_WRITE_FLAG_FIN 0x01u
+#define NGTCP2_QLOG_WRITE_FLAG_FIN 0x01U
 
 /**
  * @struct
@@ -1704,7 +1802,8 @@ typedef enum ngtcp2_token_type {
 
 #define NGTCP2_SETTINGS_V1 1
 #define NGTCP2_SETTINGS_V2 2
-#define NGTCP2_SETTINGS_VERSION NGTCP2_SETTINGS_V2
+#define NGTCP2_SETTINGS_V3 3
+#define NGTCP2_SETTINGS_VERSION NGTCP2_SETTINGS_V3
 
 /**
  * @struct
@@ -1738,7 +1837,9 @@ typedef struct ngtcp2_settings {
   ngtcp2_printf log_printf;
   /**
    * :member:`max_tx_udp_payload_size` is the maximum size of UDP
-   * datagram payload that the local endpoint transmits.
+   * datagram payload that the local endpoint transmits.  This must be
+   * larger than or equal to :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE`, and
+   * less then or equal to :macro:`NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE`.
    */
   size_t max_tx_udp_payload_size;
   /**
@@ -1802,8 +1903,8 @@ typedef struct ngtcp2_settings {
   uint64_t max_stream_window;
   /**
    * :member:`ack_thresh` is the minimum number of the received ACK
-   * eliciting packets that trigger the immediate acknowledgement from
-   * the local endpoint.
+   * eliciting packets that triggers the immediate acknowledgement
+   * from the local endpoint.
    */
   size_t ack_thresh;
   /**
@@ -1903,12 +2004,13 @@ typedef struct ngtcp2_settings {
   /**
    * :member:`pmtud_probes` is the array of UDP datagram payload size
    * to probe during Path MTU Discovery.  The discovery is done in the
-   * order appeared in this array.  The size must be strictly larger
-   * than 1200, otherwise the behavior is undefined.  The maximum
-   * value in this array should be set to
-   * :member:`max_tx_udp_payload_size`.  If this field is not set, the
-   * predefined PMTUD probes are made.  This field has been available
-   * since v1.4.0.
+   * order appeared in this array.  The payload size must be strictly
+   * larger than :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE`, and less than
+   * or equal to :macro:`NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE`.  Otherwise
+   * the behavior is undefined.  The maximum value in this array
+   * should be set to :member:`max_tx_udp_payload_size`.  If this
+   * field is not set, the predefined PMTUD probes are made.  This
+   * field has been available since v1.4.0.
    */
   const uint16_t *pmtud_probes;
   /**
@@ -1917,6 +2019,23 @@ typedef struct ngtcp2_settings {
    * field has been available since v1.4.0.
    */
   size_t pmtud_probeslen;
+  /* The following fields have been added since NGTCP2_SETTINGS_V3. */
+  /**
+   * :member:`glitch_ratelim_burst` is the maximum number of tokens
+   * available to "glitch" rate limiter.  "glitch" is a suspicious
+   * activity from a remote endpoint.  If detected, certain amount of
+   * tokens are consumed.  If no tokens are available to consume, the
+   * connection is closed.  The rate of token generation is specified
+   * by :member:`glitch_ratelim_rate`.  This field has been available
+   * since v1.15.0.
+   */
+  uint64_t glitch_ratelim_burst;
+  /**
+   * :member:`glitch_ratelim_rate` is the number of tokens generated
+   * per second.  See :member:`glitch_ratelim_burst` for "glitch" rate
+   * limiter.  This field has been available since v1.15.0.
+   */
+  uint64_t glitch_ratelim_rate;
 } ngtcp2_settings;
 
 /**
@@ -2362,6 +2481,9 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_de
  * :macro:`NGTCP2_ERR_INVALID_ARGUMENT`
  *     |randlen| is strictly less than
  *     :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN`.
+ *
+ * Deprecated since v1.22.0.  Use `ngtcp2_pkt_write_stateless_reset2`
+ * instead.
  */
 NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset(
   uint8_t *dest, size_t destlen, const uint8_t *stateless_reset_token,
@@ -2370,6 +2492,34 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_wr
 /**
  * @function
  *
+ * `ngtcp2_pkt_write_stateless_reset2` writes Stateless Reset packet
+ * in the buffer pointed by |dest| whose length is |destlen|.  |token|
+ * must store the Stateless Reset Token.  |rand| specifies the random
+ * octets preceding Stateless Reset Token.  The length of |rand| is
+ * specified by |randlen| which must be at least
+ * :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN` bytes long.
+ *
+ * If |randlen| is too long to write them all in the buffer, |rand| is
+ * written to the buffer as much as possible, and is truncated.
+ *
+ * This function returns the number of bytes written to the buffer, or
+ * one of the following negative error codes:
+ *
+ * :macro:`NGTCP2_ERR_NOBUF`
+ *     Buffer is too small.
+ * :macro:`NGTCP2_ERR_INVALID_ARGUMENT`
+ *     |randlen| is strictly less than
+ *     :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN`.
+ *
+ * This function has been available since v1.22.0.
+ */
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset2(
+  uint8_t *dest, size_t destlen, const ngtcp2_stateless_reset_token *token,
+  const uint8_t *rand, size_t randlen);
+
+/**
+ * @function
+ *
  * `ngtcp2_pkt_write_version_negotiation` writes Version Negotiation
  * packet in the buffer pointed by |dest| whose length is |destlen|.
  * |unused_random| should be generated randomly.  |dcid| is a
@@ -2662,7 +2812,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *d
  *
  * :macro:`NGTCP2_STREAM_DATA_FLAG_NONE` indicates no flag set.
  */
-#define NGTCP2_STREAM_DATA_FLAG_NONE 0x00u
+#define NGTCP2_STREAM_DATA_FLAG_NONE 0x00U
 
 /**
  * @macro
@@ -2670,7 +2820,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *d
  * :macro:`NGTCP2_STREAM_DATA_FLAG_FIN` indicates that this chunk of
  * data is final piece of an incoming stream.
  */
-#define NGTCP2_STREAM_DATA_FLAG_FIN 0x01u
+#define NGTCP2_STREAM_DATA_FLAG_FIN 0x01U
 
 /**
  * @macro
@@ -2679,7 +2829,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *d
  * data contains data received in 0-RTT packet, and the handshake has
  * not completed yet, which means that the data might be replayed.
  */
-#define NGTCP2_STREAM_DATA_FLAG_0RTT 0x02u
+#define NGTCP2_STREAM_DATA_FLAG_0RTT 0x02U
 
 /**
  * @functypedef
@@ -2734,7 +2884,7 @@ typedef int (*ngtcp2_stream_open)(ngtcp2
  *
  * :macro:`NGTCP2_STREAM_CLOSE_FLAG_NONE` indicates no flag set.
  */
-#define NGTCP2_STREAM_CLOSE_FLAG_NONE 0x00u
+#define NGTCP2_STREAM_CLOSE_FLAG_NONE 0x00U
 
 /**
  * @macro
@@ -2742,7 +2892,7 @@ typedef int (*ngtcp2_stream_open)(ngtcp2
  * :macro:`NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET` indicates that
  * app_error_code parameter is set.
  */
-#define NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET 0x01u
+#define NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET 0x01U
 
 /**
  * @functypedef
@@ -2823,6 +2973,9 @@ typedef int (*ngtcp2_acked_stream_data_o
  * The implementation of this callback should return 0 if it succeeds.
  * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library
  * call return immediately.
+ *
+ * Deprecated since v1.22.0.  Use :type:`ngtcp2_recv_stateless_reset2`
+ * instead.
  */
 typedef int (*ngtcp2_recv_stateless_reset)(ngtcp2_conn *conn,
                                            const ngtcp2_pkt_stateless_reset *sr,
@@ -2887,6 +3040,9 @@ typedef void (*ngtcp2_rand)(uint8_t *des
  * The callback function must return 0 if it succeeds.  Returning
  * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
  * immediately.
+ *
+ * Deprecated since v1.22.0.  Use
+ * :type:`ngtcp2_get_new_connection_id2` instead.
  */
 typedef int (*ngtcp2_get_new_connection_id)(ngtcp2_conn *conn, ngtcp2_cid *cid,
                                             uint8_t *token, size_t cidlen,
@@ -2951,7 +3107,7 @@ typedef int (*ngtcp2_update_key)(
  *
  * :macro:`NGTCP2_PATH_VALIDATION_FLAG_NONE` indicates no flag set.
  */
-#define NGTCP2_PATH_VALIDATION_FLAG_NONE 0x00u
+#define NGTCP2_PATH_VALIDATION_FLAG_NONE 0x00U
 
 /**
  * @macro
@@ -2960,7 +3116,7 @@ typedef int (*ngtcp2_update_key)(
  * validation involving server preferred address.  This flag is only
  * set for client.
  */
-#define NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR 0x01u
+#define NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR 0x01U
 
 /**
  * @macro
@@ -2969,7 +3125,29 @@ typedef int (*ngtcp2_update_key)(
  * server should send NEW_TOKEN frame for the new remote address.
  * This flag is only set for server.
  */
-#define NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN 0x02u
+#define NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN 0x02U
+
+/**
+ * @functypedef
+ *
+ * :type:`ngtcp2_begin_path_validation` is a callback function which
+ * is called when the path validation has started.  |flags| is zero or
+ * more of :macro:`NGTCP2_PATH_VALIDATION_FLAG_*
+ * <NGTCP2_PATH_VALIDATION_FLAG_NONE>`.  |path| is the path that is
+ * being validated.  |fallback_path|, if not NULL, is the path that is
+ * used when this validation fails.
+ *
+ * Currently, the flags may only contain
+ * :macro:`NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR`.
+ *
+ * The callback function must return 0 if it succeeds.  Returning
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
+ * immediately.
+ */
+typedef int (*ngtcp2_begin_path_validation)(ngtcp2_conn *conn, uint32_t flags,
+                                            const ngtcp2_path *path,
+                                            const ngtcp2_path *fallback_path,
+                                            void *user_data);
 
 /**
  * @functypedef
@@ -2978,9 +3156,8 @@ typedef int (*ngtcp2_update_key)(
  * an application the outcome of path validation.  |flags| is zero or
  * more of :macro:`NGTCP2_PATH_VALIDATION_FLAG_*
  * <NGTCP2_PATH_VALIDATION_FLAG_NONE>`.  |path| is the path that was
- * validated.  |old_path| is the path that is previously used before a
- * local endpoint has migrated to |path| if |old_path| is not NULL.
- * If |res| is
+ * validated.  |fallback_path|, if not NULL, is the path that is used
+ * if the path validation failed.  If |res| is
  * :enum:`ngtcp2_path_validation_result.NGTCP2_PATH_VALIDATION_RESULT_SUCCESS`,
  * the path validation succeeded.  If |res| is
  * :enum:`ngtcp2_path_validation_result.NGTCP2_PATH_VALIDATION_RESULT_FAILURE`,
@@ -2992,7 +3169,7 @@ typedef int (*ngtcp2_update_key)(
  */
 typedef int (*ngtcp2_path_validation)(ngtcp2_conn *conn, uint32_t flags,
                                       const ngtcp2_path *path,
-                                      const ngtcp2_path *old_path,
+                                      const ngtcp2_path *fallback_path,
                                       ngtcp2_path_validation_result res,
                                       void *user_data);
 
@@ -3063,6 +3240,9 @@ typedef enum ngtcp2_connection_id_status
  * The callback function must return 0 if it succeeds.  Returning
  * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
  * immediately.
+ *
+ * Deprecated since v1.22.0.  Use :type:`ngtcp2_connection_id_status2`
+ * instead.
  */
 typedef int (*ngtcp2_connection_id_status)(
   ngtcp2_conn *conn, ngtcp2_connection_id_status_type type, uint64_t seq,
@@ -3118,7 +3298,7 @@ typedef void (*ngtcp2_delete_crypto_ciph
  *
  * :macro:`NGTCP2_DATAGRAM_FLAG_NONE` indicates no flag set.
  */
-#define NGTCP2_DATAGRAM_FLAG_NONE 0x00u
+#define NGTCP2_DATAGRAM_FLAG_NONE 0x00U
 
 /**
  * @macro
@@ -3127,7 +3307,7 @@ typedef void (*ngtcp2_delete_crypto_ciph
  * received in 0-RTT packet, and the handshake has not completed yet,
  * which means that the data might be replayed.
  */
-#define NGTCP2_DATAGRAM_FLAG_0RTT 0x01u
+#define NGTCP2_DATAGRAM_FLAG_0RTT 0x01U
 
 /**
  * @functypedef
@@ -3190,6 +3370,9 @@ typedef int (*ngtcp2_lost_datagram)(ngtc
  * The callback function must return 0 if it succeeds.  Returning
  * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
  * immediately.
+ *
+ * Deprecated since v1.22.0.  Use
+ * :type:`ngtcp2_get_path_challenge_data2` instead.
  */
 typedef int (*ngtcp2_get_path_challenge_data)(ngtcp2_conn *conn, uint8_t *data,
                                               void *user_data);
@@ -3261,8 +3444,99 @@ typedef int (*ngtcp2_recv_key)(ngtcp2_co
 typedef int (*ngtcp2_tls_early_data_rejected)(ngtcp2_conn *conn,
                                               void *user_data);
 
+/**
+ * @functypedef
+ *
+ * :type:`ngtcp2_recv_stateless_reset2` is a callback function which
+ * is called when Stateless Reset packet is received.  The stateless
+ * reset details are given in |sr|.
+ *
+ * The implementation of this callback should return 0 if it succeeds.
+ * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library
+ * call return immediately.
+ *
+ * This type has been available since v1.22.0
+ */
+typedef int (*ngtcp2_recv_stateless_reset2)(
+  ngtcp2_conn *conn, const ngtcp2_pkt_stateless_reset2 *sr, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * :type:`ngtcp2_get_new_connection_id2` is a callback function to ask
+ * an application for new connection ID.  Application must generate
+ * new unused connection ID with the exact |cidlen| bytes, and store
+ * it in |cid|.  It also has to generate a stateless reset token, and
+ * store it in |token|.
+ *
+ * The callback function must return 0 if it succeeds.  Returning
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
+ * immediately.
+ *
+ * This type has been available since v1.22.0
+ */
+typedef int (*ngtcp2_get_new_connection_id2)(
+  ngtcp2_conn *conn, ngtcp2_cid *cid, ngtcp2_stateless_reset_token *token,
+  size_t cidlen, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * :type:`ngtcp2_connection_id_status2` is a callback function which
+ * is called when the status of Destination Connection ID changes.
+ *
+ * |token| is the associated stateless reset token, and it is ``NULL``
+ * if no token is present.
+ *
+ * |type| is the one of the value defined in
+ * :type:`ngtcp2_connection_id_status_type`.  The new value might be
+ * added in the future release.
+ *
+ * The callback function must return 0 if it succeeds.  Returning
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
+ * immediately.
+ *
+ * This type has been available since v1.22.0
+ */
+typedef int (*ngtcp2_connection_id_status2)(
+  ngtcp2_conn *conn, ngtcp2_connection_id_status_type type, uint64_t seq,
+  const ngtcp2_cid *cid, const ngtcp2_stateless_reset_token *token,
+  void *user_data);
+
+/**
+ * @struct
+ *
+ * :type:`ngtcp2_path_challenge_data` stores path challenge data.
+ *
+ * This type has been available since v1.22.0.
+ */
+typedef struct ngtcp2_path_challenge_data {
+  uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN];
+} ngtcp2_path_challenge_data;
+
+/**
+ * @functypedef
+ *
+ * :type:`ngtcp2_get_path_challenge_data2` is a callback function to
+ * ask an application for new data that is sent in PATH_CHALLENGE
+ * frame.  Application must generate new unpredictable, exactly
+ * :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes of random data, and
+ * store them into |data|.
+ *
+ * The callback function must return 0 if it succeeds.  Returning
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
+ * immediately.
+ *
+ * This type has been available since v1.22.0.
+ */
+typedef int (*ngtcp2_get_path_challenge_data2)(ngtcp2_conn *conn,
+                                               ngtcp2_path_challenge_data *data,
+                                               void *user_data);
+
 #define NGTCP2_CALLBACKS_V1 1
-#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V1
+#define NGTCP2_CALLBACKS_V2 2
+#define NGTCP2_CALLBACKS_V3 3
+#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V3
 
 /**
  * @struct
@@ -3349,6 +3623,11 @@ typedef struct ngtcp2_callbacks {
    * :member:`recv_stateless_reset` is a callback function which is
    * invoked when Stateless Reset packet is received.  This callback
    * function is optional.
+   *
+   * Deprecated since v1.22.0.  Use :member:`recv_stateless_reset2`
+   * instead.  If both :member:`recv_stateless_reset` and
+   * :member:`recv_stateless_reset2` are set, the latter has the
+   * precedence.
    */
   ngtcp2_recv_stateless_reset recv_stateless_reset;
   /**
@@ -3379,8 +3658,14 @@ typedef struct ngtcp2_callbacks {
   ngtcp2_rand rand;
   /**
    * :member:`get_new_connection_id` is a callback function which is
-   * invoked when the library needs new connection ID.  This callback
-   * function must be specified.
+   * invoked when the library needs new connection ID.  Either this
+   * callback function or :member:`get_new_connection_id2` must be
+   * specified.
+   *
+   * Deprecated since v1.22.0.  Use :member:`get_new_connection_id2`
+   * instead.  If both :member:`get_new_connection_id` and
+   * :member:`get_new_connection_id2` are set, the latter has the
+   * precedence.
    */
   ngtcp2_get_new_connection_id get_new_connection_id;
   /**
@@ -3441,6 +3726,10 @@ typedef struct ngtcp2_callbacks {
    * when the new Destination Connection ID is activated, or the
    * activated Destination Connection ID is now deactivated.  This
    * callback function is optional.
+   *
+   * Deprecated since v1.22.0.  Use :member:`dcid_status2` instead.
+   * If both :member:`dcid_status` and :member:`dcid_status2` are set,
+   * the latter has the precedence.
    */
   ngtcp2_connection_id_status dcid_status;
   /**
@@ -3491,6 +3780,9 @@ typedef struct ngtcp2_callbacks {
    * :member:`get_path_challenge_data` is a callback function which is
    * invoked when the library needs new data sent along with
    * PATH_CHALLENGE frame.  This callback must be specified.
+   *
+   * Deprecated since v1.22.0.  Use :member:`get_path_challenge_data2`
+   * instead.
    */
   ngtcp2_get_path_challenge_data get_path_challenge_data;
   /**
@@ -3527,6 +3819,42 @@ typedef struct ngtcp2_callbacks {
    * is only used by client.
    */
   ngtcp2_tls_early_data_rejected tls_early_data_rejected;
+  /* The following fields have been added since NGTCP2_CALLBACKS_V2. */
+  /**
+   * :member:`begin_path_validation` is a callback function which is
+   * invoked when a path validation has started.  This field is
+   * available since v1.14.0.
+   */
+  ngtcp2_begin_path_validation begin_path_validation;
+  /* The following fields have been added since NGTCP2_CALLBACKS_V3. */
+  /**
+   * :member:`recv_stateless_reset2` is a callback function which is
+   * invoked when Stateless Reset packet is received.  This callback
+   * function is optional.  This field is available since v1.22.0.
+   */
+  ngtcp2_recv_stateless_reset2 recv_stateless_reset2;
+  /**
+   * :member:`get_new_connection_id2` is a callback function which is
+   * invoked when the library needs new connection ID.  This callback
+   * function must be specified.  This field is available since
+   * v1.22.0.
+   */
+  ngtcp2_get_new_connection_id2 get_new_connection_id2;
+  /**
+   * :member:`dcid_status2` is a callback function which is invoked
+   * when the new Destination Connection ID is activated, or the
+   * activated Destination Connection ID is now deactivated.  This
+   * callback function is optional.  This field is available since
+   * v1.22.0.
+   */
+  ngtcp2_connection_id_status2 dcid_status2;
+  /**
+   * :member:`get_path_challenge_data2` is a callback function which
+   * is invoked when the library needs new data sent along with
+   * PATH_CHALLENGE frame.  This callback must be specified.  This
+   * field is available since v1.22.0.
+   */
+  ngtcp2_get_path_challenge_data2 get_path_challenge_data2;
 } ngtcp2_callbacks;
 
 /**
@@ -3745,6 +4073,21 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_w
 /**
  * @function
  *
+ * `ngtcp2_conn_continue_handshake` resumes handshake interrupted by
+ * TLS stack routine (e.g., private key operation offloading,
+ * certificate lookup, etc).
+ *
+ * This function returns 0 if it succeeds.  In general, this function
+ * returns the same set of error codes from `ngtcp2_conn_read_pkt`.
+ *
+ * This function has been available since v1.22.0.
+ */
+NGTCP2_EXTERN int ngtcp2_conn_continue_handshake(ngtcp2_conn *conn,
+                                                 ngtcp2_tstamp ts);
+
+/**
+ * @function
+ *
  * `ngtcp2_conn_tls_handshake_completed` tells |conn| that the TLS
  * stack declares TLS handshake completion.  This does not mean QUIC
  * handshake has completed.  The library needs extra conditions to be
@@ -4061,9 +4404,7 @@ NGTCP2_EXTERN void ngtcp2_conn_set_keep_
  * `ngtcp2_conn_get_expiry` returns the next expiry time.  It returns
  * ``UINT64_MAX`` if there is no next expiry.
  *
- * Call `ngtcp2_conn_handle_expiry` and then
- * `ngtcp2_conn_writev_stream` (or `ngtcp2_conn_writev_datagram`) when
- * the expiry time has passed.
+ * Call `ngtcp2_conn_handle_expiry` when the expiry time has passed.
  */
 NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn);
 
@@ -4071,6 +4412,20 @@ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_
  * @function
  *
  * `ngtcp2_conn_handle_expiry` handles expired timer.
+ *
+ * If it returns :macro:`NGTCP2_ERR_IDLE_CLOSE`, it means that an idle
+ * timer has fired for this particular connection.  In this case, drop
+ * the connection without calling
+ * `ngtcp2_conn_write_connection_close`.  If it returns any of the
+ * other negative error codes, close the connection by sending the
+ * terminal packet produced by `ngtcp2_conn_write_connection_close`.
+ * Otherwise, schedule `ngtcp2_conn_writev_stream` call.  An
+ * application may call any number of additional
+ * `ngtcp2_conn_read_pkt` and `ngtcp2_conn_handle_expiry` before
+ * calling `ngtcp2_conn_writev_stream`.  After calling
+ * `ngtcp2_conn_writev_stream`, new expiry is set.  The application
+ * should call `ngtcp2_conn_get_expiry` to get a new deadline and set
+ * the timer.
  */
 NGTCP2_EXTERN int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn,
                                             ngtcp2_tstamp ts);
@@ -4389,7 +4744,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_s
  *
  * :macro:`NGTCP2_WRITE_STREAM_FLAG_NONE` indicates no flag set.
  */
-#define NGTCP2_WRITE_STREAM_FLAG_NONE 0x00u
+#define NGTCP2_WRITE_STREAM_FLAG_NONE 0x00U
 
 /**
  * @macro
@@ -4397,7 +4752,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_s
  * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` indicates that more data may
  * come, and should be coalesced into the same packet if possible.
  */
-#define NGTCP2_WRITE_STREAM_FLAG_MORE 0x01u
+#define NGTCP2_WRITE_STREAM_FLAG_MORE 0x01U
 
 /**
  * @macro
@@ -4405,7 +4760,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_s
  * :macro:`NGTCP2_WRITE_STREAM_FLAG_FIN` indicates that a passed data
  * is the final part of a stream.
  */
-#define NGTCP2_WRITE_STREAM_FLAG_FIN 0x02u
+#define NGTCP2_WRITE_STREAM_FLAG_FIN 0x02U
 
 /**
  * @macro
@@ -4416,7 +4771,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_s
  * finalizing it.  PATH_CHALLENGE, PATH_RESPONSE, CONNECTION_CLOSE
  * only packets and PMTUD packets are excluded.
  */
-#define NGTCP2_WRITE_STREAM_FLAG_PADDING 0x04u
+#define NGTCP2_WRITE_STREAM_FLAG_PADDING 0x04U
 
 /**
  * @function
@@ -4601,7 +4956,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_w
  *
  * :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_NONE` indicates no flag set.
  */
-#define NGTCP2_WRITE_DATAGRAM_FLAG_NONE 0x00u
+#define NGTCP2_WRITE_DATAGRAM_FLAG_NONE 0x00U
 
 /**
  * @macro
@@ -4609,7 +4964,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_w
  * :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_MORE` indicates that more data
  * may come, and should be coalesced into the same packet if possible.
  */
-#define NGTCP2_WRITE_DATAGRAM_FLAG_MORE 0x01u
+#define NGTCP2_WRITE_DATAGRAM_FLAG_MORE 0x01U
 
 /**
  * @macro
@@ -4620,7 +4975,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_w
  * finalizing it.  PATH_CHALLENGE, PATH_RESPONSE, CONNECTION_CLOSE
  * only packets and PMTUD packets are excluded.
  */
-#define NGTCP2_WRITE_DATAGRAM_FLAG_PADDING 0x02u
+#define NGTCP2_WRITE_DATAGRAM_FLAG_PADDING 0x02U
 
 /**
  * @function
@@ -4857,6 +5212,8 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_sci
  *
  * :type:`ngtcp2_cid_token` is the convenient struct to store
  * Connection ID, its associated path, and stateless reset token.
+ *
+ * Deprecated since v1.22.0.  Use :type:`ngtcp2_cid_token2` instead.
  */
 typedef struct ngtcp2_cid_token {
   /**
@@ -4896,11 +5253,66 @@ typedef struct ngtcp2_cid_token {
  * sizeof(:type:`ngtcp2_cid_token`) * n bytes available, where n is
  * the return value of `ngtcp2_conn_get_active_dcid` with |dest| ==
  * NULL.
+ *
+ * Deprecated since v1.22.0.  Use `ngtcp2_conn_get_active_dcid2`
+ * instead.
  */
 NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn,
                                                  ngtcp2_cid_token *dest);
 
 /**
+ * @struct
+ *
+ * :type:`ngtcp2_cid_token2` is the convenient struct to store
+ * Connection ID, its associated path, and stateless reset token.
+ *
+ * This type has been available since v1.22.0.
+ */
+typedef struct ngtcp2_cid_token2 {
+  /**
+   * :member:`seq` is the sequence number of this Connection ID.
+   */
+  uint64_t seq;
+  /**
+   * :member:`cid` is Connection ID.
+   */
+  ngtcp2_cid cid;
+  /**
+   * :member:`ps` is the path which this Connection ID is associated
+   * with.
+   */
+  ngtcp2_path_storage ps;
+  /**
+   * :member:`token` is the stateless reset token for this Connection
+   * ID.
+   */
+  ngtcp2_stateless_reset_token token;
+  /**
+   * :member:`token_present` is nonzero if token contains stateless
+   * reset token.
+   */
+  uint8_t token_present;
+} ngtcp2_cid_token2;
+
+/**
+ * @function
+ *
+ * `ngtcp2_conn_get_active_dcid2` writes the all active Destination
+ * Connection IDs and their tokens to |dest|.  Before handshake
+ * completes, this function returns 0.  If |dest| is NULL, this
+ * function does not write anything, and returns the number of
+ * Destination Connection IDs that would otherwise be written to the
+ * provided buffer.  The buffer pointed by |dest| must have
+ * sizeof(:type:`ngtcp2_cid_token2`) * n bytes available, where n is
+ * the return value of `ngtcp2_conn_get_active_dcid2` with |dest| ==
+ * NULL.
+ *
+ * This function has been available since v1.22.0.
+ */
+NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid2(ngtcp2_conn *conn,
+                                                  ngtcp2_cid_token2 *dest);
+
+/**
  * @function
  *
  * `ngtcp2_conn_get_client_chosen_version` returns the client chosen
@@ -5430,7 +5842,7 @@ NGTCP2_EXTERN void ngtcp2_ccerr_set_appl
  * @function
  *
  * `ngtcp2_conn_write_connection_close` writes a packet which contains
- * CONNECTION_CLOSE frame(s) (type 0x1c or 0x1d) in the buffer pointed
+ * CONNECTION_CLOSE frame(s) (type 0x1C or 0x1D) in the buffer pointed
  * by |dest| whose capacity is |destlen|.
  *
  * For client, |destlen| should be at least
@@ -5447,16 +5859,18 @@ NGTCP2_EXTERN void ngtcp2_ccerr_set_appl
  *
  * If :member:`ccerr->type <ngtcp2_ccerr.type>` ==
  * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, this
- * function sends CONNECTION_CLOSE (type 0x1c) frame.  If
+ * function sends CONNECTION_CLOSE (type 0x1C) frame.  If
  * :member:`ccerr->type <ngtcp2_ccerr.type>` ==
  * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_APPLICATION`, it sends
- * CONNECTION_CLOSE (type 0x1d) frame.  Otherwise, it does not produce
+ * CONNECTION_CLOSE (type 0x1D) frame.  Otherwise, it does not produce
  * any data, and returns 0.
  *
  * |destlen| could be shorten by some factors (e.g., server side
  * amplification limit).  This function returns
  * :macro:`NGTCP2_ERR_NOBUF` if the resulting buffer is too small even
- * if the given buffer has enough space.
+ * if the given buffer has enough space.  This can happen if sending a
+ * packet would exceed a transmission limit (e.g., for amplification
+ * attack protection).
  *
  * This function must not be called from inside the callback
  * functions.
@@ -5471,7 +5885,8 @@ NGTCP2_EXTERN void ngtcp2_ccerr_set_appl
  * :macro:`NGTCP2_ERR_NOMEM`
  *     Out of memory
  * :macro:`NGTCP2_ERR_NOBUF`
- *     Buffer is too small
+ *     Buffer is too small or packet would exceed the transmission
+ *     limit (e.g., for amplification attack protection).
  * :macro:`NGTCP2_ERR_INVALID_STATE`
  *     The current state does not allow sending CONNECTION_CLOSE
  *     frame.
@@ -5538,6 +5953,26 @@ NGTCP2_EXTERN int ngtcp2_conn_set_stream
 /**
  * @function
  *
+ * `ngtcp2_conn_get_stream_user_data` returns stream_user_data
+ * associated to the stream identified by |stream_id|.  If the stream
+ * is not found, or no stream data is associated to the stream, this
+ * function returns NULL.
+ *
+ * The stream_user_data can be associated to the stream by one of the
+ * following functions:
+ *
+ * - `ngtcp2_conn_open_bidi_stream`
+ * - `ngtcp2_conn_open_uni_stream`
+ * - `ngtcp2_conn_set_stream_user_data`
+ *
+ * This function has been available since v1.17.0.
+ */
+NGTCP2_EXTERN void *ngtcp2_conn_get_stream_user_data(ngtcp2_conn *conn,
+                                                     int64_t stream_id);
+
+/**
+ * @function
+ *
  * `ngtcp2_conn_update_pkt_tx_time` sets the time instant of the next
  * packet transmission to pace packets.  This function must be called
  * after (multiple invocation of) `ngtcp2_conn_writev_stream`.  If
@@ -5569,6 +6004,119 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_str
                                                        int64_t stream_id);
 
 /**
+ * @functypedef
+ *
+ * :type:`ngtcp2_write_pkt` is a callback function to write a single
+ * packet in the buffer pointed by |dest| of length |destlen|.  The
+ * implementation should use `ngtcp2_conn_write_pkt`,
+ * `ngtcp2_conn_writev_stream`, `ngtcp2_conn_writev_datagram`, or
+ * their variants to write the packet.  |path|, |pi|, |dest|,
+ * |destlen|, and |ts| should be directly passed to those functions.
+ * If the callback succeeds, it should return the number of bytes
+ * written to the buffer.  In general, this callback function should
+ * return the value that the above mentioned functions returned except
+ * for the following error codes:
+ *
+ * - :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED`
+ * - :macro:`NGTCP2_ERR_STREAM_SHUT_WR`
+ * - :macro:`NGTCP2_ERR_STREAM_NOT_FOUND`
+ *
+ * Those error codes should be handled by an application.  If any
+ * error occurred outside those functions, return
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE`.  If no packet is produced,
+ * return 0.
+ *
+ * Because GSO requires that the aggregated packets have the same
+ * length, :macro:`NGTCP2_WRITE_STREAM_FLAG_PADDING` (or
+ * :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_PADDING` if
+ * `ngtcp2_conn_writev_datagram` is used) is recommended.
+ *
+ * This callback function has been available since v1.15.0.
+ */
+typedef ngtcp2_ssize (*ngtcp2_write_pkt)(ngtcp2_conn *conn, ngtcp2_path *path,
+                                         ngtcp2_pkt_info *pi, uint8_t *dest,
+                                         size_t destlen, ngtcp2_tstamp ts,
+                                         void *user_data);
+
+/**
+ * @function
+ *
+ * `ngtcp2_conn_write_aggregate_pkt` is a helper function to write
+ * multiple packets in the provided buffer, which is suitable to be
+ * sent at once in GSO.  This function returns the number of bytes
+ * written to the buffer pointed by |buf| of length |buflen|.
+ * |buflen| must be at least
+ * `ngtcp2_conn_get_path_max_tx_udp_payload_size(conn)
+ * <ngtcp2_conn_get_path_max_tx_udp_payload_size>` bytes long.  It is
+ * recommended to pass the buffer at least
+ * `ngtcp2_conn_get_max_tx_udp_payload_size(conn)
+ * <ngtcp2_conn_get_max_tx_udp_payload_size>` bytes in order to send a
+ * PMTUD packet.  This function only writes multiple packets if the
+ * first packet is `ngtcp2_conn_get_path_max_tx_udp_payload_size(conn)
+ * <ngtcp2_conn_get_path_max_tx_udp_payload_size>` bytes long.  The
+ * application can adjust the length of the buffer to limit the number
+ * of packets to aggregate (or use `ngtcp2_conn_write_aggregate_pkt2`
+ * to control the number of packets to write directly).  If this
+ * function returns positive integer, all packets share the same
+ * :type:`ngtcp2_path` and :type:`ngtcp2_pkt_info` values, and they
+ * are assigned to the objects pointed by |path| and |pi|
+ * respectively.  The length of all packets other than the last packet
+ * is assigned to |*pgsolen|.  The length of last packet is equal to
+ * or less than |*pgsolen|.  |write_pkt| must write a single packet.
+ * After all packets are written, this function calls
+ * `ngtcp2_conn_update_pkt_tx_time`.
+ *
+ * This function is equivalent to call
+ * `ngtcp2_conn_write_aggregate_pkt2` with |buflen| = min(|buflen|,
+ * `ngtcp2_conn_get_send_quantum(conn)
+ * <ngtcp2_conn_get_send_quantum>`) and |num_pkts| = 0 followed by
+ * `ngtcp2_conn_update_pkt_tx_time(conn)
+ * <ngtcp2_conn_update_pkt_tx_time>`.
+ *
+ * This function returns the number of bytes written to the buffer, or
+ * a negative error code returned by |write_pkt|.
+ *
+ * This function has been available since v1.15.0.
+ */
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt_versioned(
+  ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
+  ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen,
+  ngtcp2_write_pkt write_pkt, ngtcp2_tstamp ts);
+
+/**
+ * @function
+ *
+ * `ngtcp2_conn_write_aggregate_pkt2` behaves like
+ * `ngtcp2_conn_write_aggregate_pkt`, but it accepts |num_pkts| to
+ * specify the maximum number of packets to write.  If |num_pkts| is
+ * 0, this function writes packets as much as possible.  The actual
+ * number of packets to write is determined by the connection state
+ * (e.g., the congestion controller, data available to send) and the
+ * length of packet produced.  It also does not clamp |buflen|, and
+ * does not call `ngtcp2_conn_update_pkt_tx_time`.
+ *
+ * This function offers more flexibility and optimization chances to
+ * an application.  It can experiment different GSO buffer size
+ * strategy and number of GSO writes per event loop.
+ *
+ * This function has been available since v1.17.0.
+ */
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt2_versioned(
+  ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
+  ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen,
+  ngtcp2_write_pkt write_pkt, size_t num_pkts, ngtcp2_tstamp ts);
+
+/**
+ * @function
+ *
+ * `ngtcp2_conn_get_timestamp` returns the latest timestamp that is
+ * known to |conn|.
+ *
+ * This function has been available since v1.16.0.
+ */
+NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_timestamp(const ngtcp2_conn *conn);
+
+/**
  * @function
  *
  * `ngtcp2_strerror` returns the text representation of |liberr|.
@@ -5650,15 +6198,19 @@ NGTCP2_EXTERN void ngtcp2_path_storage_z
  * values.  First this function fills |settings| with 0, and set the
  * default value to the following fields:
  *
- * * :type:`cc_algo <ngtcp2_settings.cc_algo>` =
+ * * :member:`cc_algo <ngtcp2_settings.cc_algo>` =
  *   :enum:`ngtcp2_cc_algo.NGTCP2_CC_ALGO_CUBIC`
- * * :type:`initial_rtt <ngtcp2_settings.initial_rtt>` =
+ * * :member:`initial_rtt <ngtcp2_settings.initial_rtt>` =
  *   :macro:`NGTCP2_DEFAULT_INITIAL_RTT`
- * * :type:`ack_thresh <ngtcp2_settings.ack_thresh>` = 2
- * * :type:`max_tx_udp_payload_size
+ * * :member:`ack_thresh <ngtcp2_settings.ack_thresh>` = 2
+ * * :member:`max_tx_udp_payload_size
  *   <ngtcp2_settings.max_tx_udp_payload_size>` = 1452
- * * :type:`handshake_timeout <ngtcp2_settings.handshake_timeout>` =
+ * * :member:`handshake_timeout <ngtcp2_settings.handshake_timeout>` =
  *   ``UINT64_MAX``
+ * * :member:`glitch_ratelim_burst
+ *   <ngtcp2_settings.glitch_ratelim_burst>` = 10000
+ * * :member:`glitch_ratelim_rate
+ *   <ngtcp2_settings.glitch_ratelim_rate>` = 330
  */
 NGTCP2_EXTERN void ngtcp2_settings_default_versioned(int settings_version,
                                                      ngtcp2_settings *settings);
@@ -5670,15 +6222,15 @@ NGTCP2_EXTERN void ngtcp2_settings_defau
  * default values.  First this function fills |params| with 0, and set
  * the default value to the following fields:
  *
- * * :type:`max_udp_payload_size
+ * * :member:`max_udp_payload_size
  *   <ngtcp2_transport_params.max_udp_payload_size>` =
  *   :macro:`NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE`
- * * :type:`ack_delay_exponent
+ * * :member:`ack_delay_exponent
  *   <ngtcp2_transport_params.ack_delay_exponent>` =
  *   :macro:`NGTCP2_DEFAULT_ACK_DELAY_EXPONENT`
- * * :type:`max_ack_delay <ngtcp2_transport_params.max_ack_delay>` =
+ * * :member:`max_ack_delay <ngtcp2_transport_params.max_ack_delay>` =
  *   :macro:`NGTCP2_DEFAULT_MAX_ACK_DELAY`
- * * :type:`active_connection_id_limit
+ * * :member:`active_connection_id_limit
  *   <ngtcp2_transport_params.active_connection_id_limit>` =
  *   :macro:`NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT`
  */
@@ -5951,6 +6503,28 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_ver
   ngtcp2_conn_get_conn_info_versioned((CONN), NGTCP2_CONN_INFO_VERSION, (CINFO))
 
 /*
+ * `ngtcp2_conn_write_aggregate_pkt` is a wrapper around
+ * `ngtcp2_conn_write_aggregate_pkt_versioned` to set the correct
+ * struct version.
+ */
+#define ngtcp2_conn_write_aggregate_pkt(CONN, PATH, PI, BUF, BUFLEN, PGSOLEN,  \
+                                        WRITE_PKT, TS)                         \
+  ngtcp2_conn_write_aggregate_pkt_versioned(                                   \
+    (CONN), (PATH), NGTCP2_PKT_INFO_VERSION, (PI), (BUF), (BUFLEN), (PGSOLEN), \
+    (WRITE_PKT), (TS))
+
+/*
+ * `ngtcp2_conn_write_aggregate_pkt2` is a wrapper around
+ * `ngtcp2_conn_write_aggregate_pkt2_versioned` to set the correct
+ * struct version.
+ */
+#define ngtcp2_conn_write_aggregate_pkt2(CONN, PATH, PI, BUF, BUFLEN, PGSOLEN, \
+                                         WRITE_PKT, NUM_PKTS, TS)              \
+  ngtcp2_conn_write_aggregate_pkt2_versioned(                                  \
+    (CONN), (PATH), NGTCP2_PKT_INFO_VERSION, (PI), (BUF), (BUFLEN), (PGSOLEN), \
+    (WRITE_PKT), (NUM_PKTS), (TS))
+
+/*
  * `ngtcp2_settings_default` is a wrapper around
  * `ngtcp2_settings_default_versioned` to set the correct struct
  * version.
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_acktr.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_acktr.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_acktr.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_acktr.c	2026-05-15 15:49:15.154978300 +0200
@@ -34,9 +34,11 @@ ngtcp2_objalloc_def(acktr_entry, ngtcp2_
 
 static void acktr_entry_init(ngtcp2_acktr_entry *ent, int64_t pkt_num,
                              ngtcp2_tstamp tstamp) {
-  ent->pkt_num = pkt_num;
-  ent->len = 1;
-  ent->tstamp = tstamp;
+  *ent = (ngtcp2_acktr_entry){
+    .pkt_num = pkt_num,
+    .len = 1,
+    .tstamp = tstamp,
+  };
 }
 
 int ngtcp2_acktr_entry_objalloc_new(ngtcp2_acktr_entry **ent, int64_t pkt_num,
@@ -219,8 +221,10 @@ ngtcp2_acktr_ack_entry *ngtcp2_acktr_add
                                              int64_t largest_ack) {
   ngtcp2_acktr_ack_entry *ent = ngtcp2_ringbuf_push_front(&acktr->acks.rb);
 
-  ent->largest_ack = largest_ack;
-  ent->pkt_num = pkt_num;
+  *ent = (ngtcp2_acktr_ack_entry){
+    .largest_ack = largest_ack,
+    .pkt_num = pkt_num,
+  };
 
   return ent;
 }
@@ -316,9 +320,9 @@ void ngtcp2_acktr_recv_ack(ngtcp2_acktr
 }
 
 void ngtcp2_acktr_commit_ack(ngtcp2_acktr *acktr) {
-  acktr->flags &= (uint16_t) ~(NGTCP2_ACKTR_FLAG_ACTIVE_ACK |
-                               NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK |
-                               NGTCP2_ACKTR_FLAG_CANCEL_TIMER);
+  acktr->flags &=
+    (uint16_t)~(NGTCP2_ACKTR_FLAG_ACTIVE_ACK | NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK |
+                NGTCP2_ACKTR_FLAG_CANCEL_TIMER);
   acktr->first_unacked_ts = UINT64_MAX;
   acktr->rx_npkt = 0;
 }
@@ -333,16 +337,14 @@ void ngtcp2_acktr_immediate_ack(ngtcp2_a
   acktr->flags |= NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK;
 }
 
-ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
-                                            ngtcp2_frame *fr, uint8_t type,
-                                            ngtcp2_tstamp ts,
-                                            ngtcp2_duration ack_delay,
-                                            uint64_t ack_delay_exponent) {
+int ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr, ngtcp2_ack *ack,
+                                  uint8_t type, ngtcp2_tstamp ts,
+                                  ngtcp2_duration ack_delay,
+                                  uint64_t ack_delay_exponent) {
   int64_t last_pkt_num;
   ngtcp2_ack_range *range;
   ngtcp2_ksl_it it;
   ngtcp2_acktr_entry *rpkt;
-  ngtcp2_ack *ack = &fr->ack;
   ngtcp2_tstamp largest_ack_ts;
   size_t num_acks;
 
@@ -351,13 +353,13 @@ ngtcp2_frame *ngtcp2_acktr_create_ack_fr
   }
 
   if (!ngtcp2_acktr_require_active_ack(acktr, ack_delay, ts)) {
-    return NULL;
+    return -1;
   }
 
   it = ngtcp2_acktr_get(acktr);
   if (ngtcp2_ksl_it_end(&it)) {
     ngtcp2_acktr_commit_ack(acktr);
-    return NULL;
+    return -1;
   }
 
   num_acks = ngtcp2_ksl_len(&acktr->ents);
@@ -420,7 +422,7 @@ ngtcp2_frame *ngtcp2_acktr_create_ack_fr
     last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
   }
 
-  return fr;
+  return 0;
 }
 
 void ngtcp2_acktr_increase_ecn_counts(ngtcp2_acktr *acktr,
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_acktr.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_acktr.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_acktr.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_acktr.h	2026-05-15 15:49:15.155978400 +0200
@@ -97,16 +97,16 @@ typedef struct ngtcp2_acktr_ack_entry {
 } ngtcp2_acktr_ack_entry;
 
 /* NGTCP2_ACKTR_FLAG_NONE indicates that no flag set. */
-#define NGTCP2_ACKTR_FLAG_NONE 0x00u
+#define NGTCP2_ACKTR_FLAG_NONE 0x00U
 /* NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK indicates that immediate
    acknowledgement is required. */
-#define NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK 0x01u
+#define NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK 0x01U
 /* NGTCP2_ACKTR_FLAG_ACTIVE_ACK indicates that there are pending
    protected packet to be acknowledged. */
-#define NGTCP2_ACKTR_FLAG_ACTIVE_ACK 0x02u
+#define NGTCP2_ACKTR_FLAG_ACTIVE_ACK 0x02U
 /* NGTCP2_ACKTR_FLAG_CANCEL_TIMER is set when ACK delay timer is
    expired and canceled. */
-#define NGTCP2_ACKTR_FLAG_CANCEL_TIMER 0x0100u
+#define NGTCP2_ACKTR_FLAG_CANCEL_TIMER 0x0100U
 
 ngtcp2_static_ringbuf_def(acks, 32, sizeof(ngtcp2_acktr_ack_entry))
 
@@ -120,8 +120,6 @@ typedef struct ngtcp2_acktr {
      packet number. */
   ngtcp2_ksl ents;
   ngtcp2_log *log;
-  /* flags is bitwise OR of zero, or more of NGTCP2_ACKTR_FLAG_*. */
-  uint16_t flags;
   /* first_unacked_ts is timestamp when ngtcp2_acktr_entry is added
      first time after the last outgoing ACK frame. */
   ngtcp2_tstamp first_unacked_ts;
@@ -148,6 +146,9 @@ typedef struct ngtcp2_acktr {
       uint64_t ce;
     } ack;
   } ecn;
+
+  /* flags is bitwise OR of zero, or more of NGTCP2_ACKTR_FLAG_*. */
+  uint16_t flags;
 } ngtcp2_acktr;
 
 /*
@@ -235,19 +236,18 @@ void ngtcp2_acktr_immediate_ack(ngtcp2_a
 
 /*
  * ngtcp2_acktr_create_ack_frame creates ACK frame in the object
- * pointed by |fr|, and returns |fr| if there are any received packets
- * to acknowledge.  If there are no packets to acknowledge, this
- * function returns NULL.  fr->ack.ranges must be able to contain at
+ * pointed by |ack|, and returns 0 if it successfully creates ACK
+ * frame in |ack|.  If there are no packets to acknowledge, this
+ * function returns -1.  |ack|->ranges must be able to contain at
  * least NGTCP2_MAX_ACK_RANGES elements.
  *
  * Call ngtcp2_acktr_commit_ack after a created ACK frame is
  * successfully serialized into a packet.
  */
-ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
-                                            ngtcp2_frame *fr, uint8_t type,
-                                            ngtcp2_tstamp ts,
-                                            ngtcp2_duration ack_delay,
-                                            uint64_t ack_delay_exponent);
+int ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr, ngtcp2_ack *ack,
+                                  uint8_t type, ngtcp2_tstamp ts,
+                                  ngtcp2_duration ack_delay,
+                                  uint64_t ack_delay_exponent);
 
 /*
  * ngtcp2_acktr_increase_ecn_counts increases ECN counts from |pi|.
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_addr.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_addr.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_addr.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_addr.c	2026-05-15 15:49:15.155978400 +0200
@@ -31,8 +31,11 @@
 
 ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const ngtcp2_sockaddr *addr,
                               ngtcp2_socklen addrlen) {
-  dest->addrlen = addrlen;
-  dest->addr = (ngtcp2_sockaddr *)addr;
+  *dest = (ngtcp2_addr){
+    .addr = (ngtcp2_sockaddr *)addr,
+    .addrlen = addrlen,
+  };
+
   return dest;
 }
 
@@ -58,14 +61,12 @@ int ngtcp2_sockaddr_eq(const ngtcp2_sock
 
   switch (a->sa_family) {
   case NGTCP2_AF_INET: {
-    const ngtcp2_sockaddr_in *ai = (const ngtcp2_sockaddr_in *)(void *)a,
-                             *bi = (const ngtcp2_sockaddr_in *)(void *)b;
+    const ngtcp2_sockaddr_in *ai = (void *)a, *bi = (void *)b;
     return ai->sin_port == bi->sin_port &&
            memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr)) == 0;
   }
   case NGTCP2_AF_INET6: {
-    const ngtcp2_sockaddr_in6 *ai = (const ngtcp2_sockaddr_in6 *)(void *)a,
-                              *bi = (const ngtcp2_sockaddr_in6 *)(void *)b;
+    const ngtcp2_sockaddr_in6 *ai = (void *)a, *bi = (void *)b;
     return ai->sin6_port == bi->sin6_port &&
            memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr)) == 0;
   }
@@ -89,8 +90,7 @@ uint32_t ngtcp2_addr_cmp(const ngtcp2_ad
 
   switch (a->sa_family) {
   case NGTCP2_AF_INET: {
-    const ngtcp2_sockaddr_in *ai = (const ngtcp2_sockaddr_in *)(void *)a,
-                             *bi = (const ngtcp2_sockaddr_in *)(void *)b;
+    const ngtcp2_sockaddr_in *ai = (void *)a, *bi = (void *)b;
     if (memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr))) {
       flags |= NGTCP2_ADDR_CMP_FLAG_ADDR;
     }
@@ -100,8 +100,7 @@ uint32_t ngtcp2_addr_cmp(const ngtcp2_ad
     return flags;
   }
   case NGTCP2_AF_INET6: {
-    const ngtcp2_sockaddr_in6 *ai = (const ngtcp2_sockaddr_in6 *)(void *)a,
-                              *bi = (const ngtcp2_sockaddr_in6 *)(void *)b;
+    const ngtcp2_sockaddr_in6 *ai = (void *)a, *bi = (void *)b;
     if (memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr))) {
       flags |= NGTCP2_ADDR_CMP_FLAG_ADDR;
     }
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_addr.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_addr.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_addr.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_addr.h	2026-05-15 15:49:15.155978400 +0200
@@ -46,14 +46,14 @@ void ngtcp2_addr_copy(ngtcp2_addr *dest,
 int ngtcp2_addr_eq(const ngtcp2_addr *a, const ngtcp2_addr *b);
 
 /* NGTCP2_ADDR_CMP_FLAG_NONE indicates that no flag set. */
-#define NGTCP2_ADDR_CMP_FLAG_NONE 0x0u
+#define NGTCP2_ADDR_CMP_FLAG_NONE 0x0U
 /* NGTCP2_ADDR_CMP_FLAG_ADDR indicates IP addresses do not match. */
-#define NGTCP2_ADDR_CMP_FLAG_ADDR 0x1u
+#define NGTCP2_ADDR_CMP_FLAG_ADDR 0x1U
 /* NGTCP2_ADDR_CMP_FLAG_PORT indicates ports do not match. */
-#define NGTCP2_ADDR_CMP_FLAG_PORT 0x2u
+#define NGTCP2_ADDR_CMP_FLAG_PORT 0x2U
 /* NGTCP2_ADDR_CMP_FLAG_FAMILY indicates address families do not
    match. */
-#define NGTCP2_ADDR_CMP_FLAG_FAMILY 0x4u
+#define NGTCP2_ADDR_CMP_FLAG_FAMILY 0x4U
 
 /*
  * ngtcp2_addr_cmp compares address and port between |a| and |b|, and
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_balloc.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_balloc.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_balloc.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_balloc.c	2026-05-15 15:49:15.155978400 +0200
@@ -30,7 +30,7 @@
 
 void ngtcp2_balloc_init(ngtcp2_balloc *balloc, size_t blklen,
                         const ngtcp2_mem *mem) {
-  assert((blklen & 0xfu) == 0);
+  assert((blklen & 0xFU) == 0);
 
   balloc->mem = mem;
   balloc->blklen = blklen;
@@ -66,25 +66,25 @@ int ngtcp2_balloc_get(ngtcp2_balloc *bal
 
   if (ngtcp2_buf_left(&balloc->buf) < n) {
     p = ngtcp2_mem_malloc(balloc->mem,
-                          sizeof(ngtcp2_memblock_hd) + 0x8u + balloc->blklen);
+                          sizeof(ngtcp2_memblock_hd) + 0x8U + balloc->blklen);
     if (p == NULL) {
       return NGTCP2_ERR_NOMEM;
     }
 
-    hd = (ngtcp2_memblock_hd *)(void *)p;
+    hd = (void *)p;
     hd->next = balloc->head;
     balloc->head = hd;
     ngtcp2_buf_init(
       &balloc->buf,
-      (uint8_t *)(((uintptr_t)p + sizeof(ngtcp2_memblock_hd) + 0xfu) &
-                  ~(uintptr_t)0xfu),
+      (uint8_t *)(((uintptr_t)p + sizeof(ngtcp2_memblock_hd) + 0xFU) &
+                  ~(uintptr_t)0xFU),
       balloc->blklen);
   }
 
-  assert(((uintptr_t)balloc->buf.last & 0xfu) == 0);
+  assert(((uintptr_t)balloc->buf.last & 0xFU) == 0);
 
   *pbuf = balloc->buf.last;
-  balloc->buf.last += (n + 0xfu) & ~(uintptr_t)0xfu;
+  balloc->buf.last += (n + 0xFU) & ~(uintptr_t)0xFU;
 
   return 0;
 }
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_bbr.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_bbr.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_bbr.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_bbr.c	2026-05-15 15:49:15.155978400 +0200
@@ -33,6 +33,7 @@
 #include "ngtcp2_rcvry.h"
 #include "ngtcp2_rst.h"
 #include "ngtcp2_conn_stat.h"
+#include "ngtcp2_pcg.h"
 
 #define NGTCP2_BBR_MAX_BW_FILTERLEN 2
 
@@ -69,19 +70,21 @@ static void bbr_on_transmit(ngtcp2_cc_bb
 
 static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr);
 
-static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr);
+static void bbr_reset_shortterm_model(ngtcp2_cc_bbr *bbr);
 
 static void bbr_init_round_counting(ngtcp2_cc_bbr *bbr);
 
 static void bbr_reset_full_bw(ngtcp2_cc_bbr *bbr);
 
-static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
+static void bbr_init_pacing_rate(const ngtcp2_cc_bbr *bbr,
+                                 ngtcp2_conn_stat *cstat);
 
-static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr,
+static void bbr_set_pacing_rate_with_gain(const ngtcp2_cc_bbr *bbr,
                                           ngtcp2_conn_stat *cstat,
                                           uint64_t pacing_gain_h);
 
-static void bbr_set_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
+static void bbr_set_pacing_rate(const ngtcp2_cc_bbr *bbr,
+                                ngtcp2_conn_stat *cstat);
 
 static void bbr_enter_startup(ngtcp2_cc_bbr *bbr);
 
@@ -99,47 +102,47 @@ static void bbr_update_control_parameter
                                           ngtcp2_conn_stat *cstat,
                                           const ngtcp2_cc_ack *ack);
 
-static void bbr_update_on_loss(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat,
-                               const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
-
 static void bbr_update_latest_delivery_signals(ngtcp2_cc_bbr *bbr,
-                                               ngtcp2_conn_stat *cstat);
+                                               const ngtcp2_conn_stat *cstat);
 
 static void bbr_advance_latest_delivery_signals(ngtcp2_cc_bbr *bbr,
-                                                ngtcp2_conn_stat *cstat);
+                                                const ngtcp2_conn_stat *cstat);
 
 static void bbr_update_congestion_signals(ngtcp2_cc_bbr *bbr,
-                                          ngtcp2_conn_stat *cstat,
+                                          const ngtcp2_conn_stat *cstat,
                                           const ngtcp2_cc_ack *ack);
 
-static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
-                                                   ngtcp2_conn_stat *cstat);
+static void
+bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
+                                       const ngtcp2_conn_stat *cstat);
 
-static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
+static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr,
+                                  const ngtcp2_conn_stat *cstat);
 
 static void bbr_loss_lower_bounds(ngtcp2_cc_bbr *bbr);
 
 static void bbr_bound_bw_for_model(ngtcp2_cc_bbr *bbr);
 
-static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
+static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat,
                               const ngtcp2_cc_ack *ack);
 
 static void bbr_update_round(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack);
 
 static void bbr_start_round(ngtcp2_cc_bbr *bbr);
 
-static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr);
+static int bbr_is_in_probe_bw_state(const ngtcp2_cc_bbr *bbr);
 
-static int bbr_is_probing_bw(ngtcp2_cc_bbr *bbr);
+static int bbr_is_probing_bw(const ngtcp2_cc_bbr *bbr);
 
 static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr,
-                                       ngtcp2_conn_stat *cstat,
+                                       const ngtcp2_conn_stat *cstat,
                                        const ngtcp2_cc_ack *ack,
                                        ngtcp2_tstamp ts);
 
 static void bbr_enter_drain(ngtcp2_cc_bbr *bbr);
 
-static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
+static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr,
+                                 const ngtcp2_conn_stat *cstat,
                                  ngtcp2_tstamp ts);
 
 static void bbr_enter_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts);
@@ -150,59 +153,70 @@ static void bbr_start_probe_bw_cruise(ng
 
 static void bbr_start_probe_bw_refill(ngtcp2_cc_bbr *bbr);
 
-static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
+static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr,
+                                  const ngtcp2_conn_stat *cstat);
 
 static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
-                                            ngtcp2_conn_stat *cstat,
+                                            const ngtcp2_conn_stat *cstat,
                                             const ngtcp2_cc_ack *ack,
                                             ngtcp2_tstamp ts);
 
-static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
-                                 ngtcp2_tstamp ts);
+static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr,
+                                 const ngtcp2_conn_stat *cstat);
 
-static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
+static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr,
+                                  const ngtcp2_conn_stat *cstat);
 
-static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr,
+static int bbr_has_elapsed_in_phase(const ngtcp2_cc_bbr *bbr,
                                     ngtcp2_duration interval, ngtcp2_tstamp ts);
 
-static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr,
-                                           ngtcp2_conn_stat *cstat);
+static uint64_t bbr_inflight_with_headroom(const ngtcp2_cc_bbr *bbr,
+                                           const ngtcp2_conn_stat *cstat);
 
 static void bbr_raise_inflight_longterm_slope(ngtcp2_cc_bbr *bbr,
-                                              ngtcp2_conn_stat *cstat);
+                                              const ngtcp2_conn_stat *cstat);
 
 static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr,
-                                               ngtcp2_conn_stat *cstat,
+                                               const ngtcp2_conn_stat *cstat,
                                                const ngtcp2_cc_ack *ack);
 
-static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
-                                   const ngtcp2_cc_ack *ack);
+static void bbr_adapt_longterm_model(ngtcp2_cc_bbr *bbr,
+                                     const ngtcp2_conn_stat *cstat,
+                                     const ngtcp2_cc_ack *ack);
 
-static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
+static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr,
+                                   const ngtcp2_conn_stat *cstat,
                                    ngtcp2_tstamp ts);
 
 static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr);
 
-static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr,
-                                              ngtcp2_conn_stat *cstat);
+static int bbr_is_reno_coexistence_probe_time(const ngtcp2_cc_bbr *bbr,
+                                              const ngtcp2_conn_stat *cstat);
 
-static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr,
-                                    ngtcp2_conn_stat *cstat);
+static uint64_t bbr_target_inflight(const ngtcp2_cc_bbr *bbr,
+                                    const ngtcp2_conn_stat *cstat);
 
-static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr);
+static int bbr_is_inflight_too_high(const ngtcp2_cc_bbr *bbr,
+                                    const ngtcp2_rs *rs);
 
 static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr,
-                                         ngtcp2_conn_stat *cstat,
-                                         ngtcp2_tstamp ts);
+                                         const ngtcp2_conn_stat *cstat,
+                                         const ngtcp2_rs *rs, ngtcp2_tstamp ts);
 
 static void bbr_note_loss(ngtcp2_cc_bbr *bbr);
 
-static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
+static void bbr_save_state_upon_loss(ngtcp2_cc_bbr *bbr);
+
+static void bbr_handle_spurious_loss_detection(ngtcp2_cc_bbr *bbr,
+                                               const ngtcp2_conn_stat *cstat);
+
+static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr,
+                                   const ngtcp2_conn_stat *cstat,
                                    const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
 
-static uint64_t
-bbr_inflight_longterm_from_lost_packet(ngtcp2_cc_bbr *bbr,
-                                       const ngtcp2_cc_pkt *pkt);
+static uint64_t bbr_inflight_at_loss(const ngtcp2_cc_bbr *bbr,
+                                     const ngtcp2_cc_pkt *pkt,
+                                     const ngtcp2_rs *rs);
 
 static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack,
                                ngtcp2_tstamp ts);
@@ -219,7 +233,7 @@ static void bbr_check_probe_rtt_done(ngt
                                      ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts);
 
 static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr,
-                                            ngtcp2_conn_stat *cstat);
+                                            const ngtcp2_conn_stat *cstat);
 
 static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts);
 
@@ -230,27 +244,28 @@ static void bbr_handle_restart_from_idle
 static uint64_t bbr_bdp_multiple(ngtcp2_cc_bbr *bbr, uint64_t gain_h);
 
 static uint64_t bbr_quantization_budget(ngtcp2_cc_bbr *bbr,
-                                        ngtcp2_conn_stat *cstat,
+                                        const ngtcp2_conn_stat *cstat,
                                         uint64_t inflight);
 
-static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
+static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat,
                              uint64_t gain_h);
 
 static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr,
-                                    ngtcp2_conn_stat *cstat);
+                                    const ngtcp2_conn_stat *cstat);
 
 static void bbr_update_offload_budget(ngtcp2_cc_bbr *bbr,
-                                      ngtcp2_conn_stat *cstat);
+                                      const ngtcp2_conn_stat *cstat);
 
 static uint64_t min_pipe_cwnd(size_t max_udp_payload_size);
 
 static void bbr_advance_max_bw_filter(ngtcp2_cc_bbr *bbr);
 
-static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
+static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat);
 
-static void bbr_restore_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
+static void bbr_restore_cwnd(const ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
 
-static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
+static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr,
+                                   const ngtcp2_conn_stat *cstat);
 
 static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr,
                                          ngtcp2_conn_stat *cstat);
@@ -258,10 +273,11 @@ static void bbr_bound_cwnd_for_probe_rtt
 static void bbr_set_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
                          const ngtcp2_cc_ack *ack);
 
-static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr,
+static void bbr_bound_cwnd_for_model(const ngtcp2_cc_bbr *bbr,
                                      ngtcp2_conn_stat *cstat);
 
-static void bbr_set_send_quantum(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
+static void bbr_set_send_quantum(const ngtcp2_cc_bbr *bbr,
+                                 ngtcp2_conn_stat *cstat);
 
 static int in_congestion_recovery(const ngtcp2_conn_stat *cstat,
                                   ngtcp2_tstamp sent_time);
@@ -288,7 +304,7 @@ static void bbr_on_init(ngtcp2_cc_bbr *b
   bbr->full_bw_reached = 0;
 
   bbr_reset_congestion_signals(bbr);
-  bbr_reset_lower_bounds(bbr);
+  bbr_reset_shortterm_model(bbr);
   bbr_init_round_counting(bbr);
   bbr_reset_full_bw(bbr);
   bbr_init_pacing_rate(bbr, cstat);
@@ -333,9 +349,12 @@ static void bbr_on_init(ngtcp2_cc_bbr *b
 
   bbr->max_inflight = 0;
 
-  bbr->congestion_recovery_start_ts = UINT64_MAX;
-
   bbr->bdp = 0;
+
+  bbr->undo_state = 0;
+  bbr->undo_bw_shortterm = 0;
+  bbr->undo_inflight_shortterm = 0;
+  bbr->undo_inflight_longterm = 0;
 }
 
 static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) {
@@ -344,7 +363,7 @@ static void bbr_reset_congestion_signals
   bbr->inflight_latest = 0;
 }
 
-static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr) {
+static void bbr_reset_shortterm_model(ngtcp2_cc_bbr *bbr) {
   bbr->bw_shortterm = UINT64_MAX;
   bbr->inflight_shortterm = UINT64_MAX;
 }
@@ -362,7 +381,7 @@ static void bbr_reset_full_bw(ngtcp2_cc_
 }
 
 static void bbr_check_full_bw_reached(ngtcp2_cc_bbr *bbr,
-                                      ngtcp2_conn_stat *cstat) {
+                                      const ngtcp2_conn_stat *cstat) {
   if (bbr->full_bw_now || !bbr->round_start || bbr->rst->rs.is_app_limited) {
     return;
   }
@@ -383,15 +402,16 @@ static void bbr_check_full_bw_reached(ng
 
   bbr->full_bw_reached = 1;
 
-  ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
-                  "bbr reached full bandwidth, full_bw=%" PRIu64, bbr->full_bw);
+  ngtcp2_log_infof(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
+                   "bbr reached full bandwidth, full_bw=%" PRIu64,
+                   bbr->full_bw);
 }
 
 static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr) {
   if (bbr->full_bw_reached || bbr->loss_events_in_round <= 6 ||
       (bbr->in_loss_recovery &&
        bbr->round_count <= bbr->round_count_at_recovery) ||
-      !bbr_is_inflight_too_high(bbr)) {
+      !bbr_is_inflight_too_high(bbr, &bbr->rst->rs)) {
     return;
   }
 
@@ -400,15 +420,17 @@ static void bbr_check_startup_high_loss(
     bbr_bdp_multiple(bbr, bbr->cwnd_gain_h), bbr->inflight_latest);
 }
 
-static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
-  cstat->pacing_interval_m =
+static void bbr_init_pacing_rate(const ngtcp2_cc_bbr *bbr,
+                                 ngtcp2_conn_stat *cstat) {
+  cstat->pacing_interval_m = ngtcp2_max_uint64(
     ((cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS
                                                : cstat->smoothed_rtt)
      << 10) *
-    100 / NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd;
+      100 / NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd,
+    1);
 }
 
-static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr,
+static void bbr_set_pacing_rate_with_gain(const ngtcp2_cc_bbr *bbr,
                                           ngtcp2_conn_stat *cstat,
                                           uint64_t pacing_gain_h) {
   uint64_t interval_m;
@@ -426,7 +448,8 @@ static void bbr_set_pacing_rate_with_gai
   }
 }
 
-static void bbr_set_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
+static void bbr_set_pacing_rate(const ngtcp2_cc_bbr *bbr,
+                                ngtcp2_conn_stat *cstat) {
   bbr_set_pacing_rate_with_gain(bbr, cstat, bbr->pacing_gain_h);
 }
 
@@ -482,13 +505,8 @@ static void bbr_update_control_parameter
   bbr_set_cwnd(bbr, cstat, ack);
 }
 
-static void bbr_update_on_loss(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat,
-                               const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
-  bbr_handle_lost_packet(cc, cstat, pkt, ts);
-}
-
 static void bbr_update_latest_delivery_signals(ngtcp2_cc_bbr *bbr,
-                                               ngtcp2_conn_stat *cstat) {
+                                               const ngtcp2_conn_stat *cstat) {
   bbr->loss_round_start = 0;
   bbr->bw_latest = ngtcp2_max_uint64(bbr->bw_latest, cstat->delivery_rate_sec);
   bbr->inflight_latest =
@@ -501,7 +519,7 @@ static void bbr_update_latest_delivery_s
 }
 
 static void bbr_advance_latest_delivery_signals(ngtcp2_cc_bbr *bbr,
-                                                ngtcp2_conn_stat *cstat) {
+                                                const ngtcp2_conn_stat *cstat) {
   if (bbr->loss_round_start) {
     bbr->bw_latest = cstat->delivery_rate_sec;
     bbr->inflight_latest = bbr->rst->rs.delivered;
@@ -509,7 +527,7 @@ static void bbr_advance_latest_delivery_
 }
 
 static void bbr_update_congestion_signals(ngtcp2_cc_bbr *bbr,
-                                          ngtcp2_conn_stat *cstat,
+                                          const ngtcp2_conn_stat *cstat,
                                           const ngtcp2_cc_ack *ack) {
   bbr_update_max_bw(bbr, cstat, ack);
 
@@ -527,8 +545,9 @@ static void bbr_update_congestion_signal
   bbr->loss_in_round = 0;
 }
 
-static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
-                                                   ngtcp2_conn_stat *cstat) {
+static void
+bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
+                                       const ngtcp2_conn_stat *cstat) {
   if (bbr_is_probing_bw(bbr)) {
     return;
   }
@@ -539,7 +558,8 @@ static void bbr_adapt_lower_bounds_from_
   }
 }
 
-static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
+static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr,
+                                  const ngtcp2_conn_stat *cstat) {
   if (bbr->bw_shortterm == UINT64_MAX) {
     bbr->bw_shortterm = bbr->max_bw;
   }
@@ -562,11 +582,12 @@ static void bbr_bound_bw_for_model(ngtcp
   bbr->bw = ngtcp2_min_uint64(bbr->max_bw, bbr->bw_shortterm);
 }
 
-static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
+static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat,
                               const ngtcp2_cc_ack *ack) {
   bbr_update_round(bbr, ack);
 
-  if (cstat->delivery_rate_sec >= bbr->max_bw || !bbr->rst->rs.is_app_limited) {
+  if (cstat->delivery_rate_sec && (cstat->delivery_rate_sec >= bbr->max_bw ||
+                                   !bbr->rst->rs.is_app_limited)) {
     ngtcp2_window_filter_update(&bbr->max_bw_filter, cstat->delivery_rate_sec,
                                 bbr->cycle_count);
 
@@ -597,7 +618,7 @@ static void bbr_start_round(ngtcp2_cc_bb
   bbr->next_round_delivered = bbr->rst->delivered;
 }
 
-static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr) {
+static int bbr_is_in_probe_bw_state(const ngtcp2_cc_bbr *bbr) {
   switch (bbr->state) {
   case NGTCP2_BBR_STATE_PROBE_BW_DOWN:
   case NGTCP2_BBR_STATE_PROBE_BW_CRUISE:
@@ -609,7 +630,7 @@ static int bbr_is_in_probe_bw_state(ngtc
   }
 }
 
-static int bbr_is_probing_bw(ngtcp2_cc_bbr *bbr) {
+static int bbr_is_probing_bw(const ngtcp2_cc_bbr *bbr) {
   switch (bbr->state) {
   case NGTCP2_BBR_STATE_STARTUP:
   case NGTCP2_BBR_STATE_PROBE_BW_REFILL:
@@ -621,7 +642,7 @@ static int bbr_is_probing_bw(ngtcp2_cc_b
 }
 
 static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr,
-                                       ngtcp2_conn_stat *cstat,
+                                       const ngtcp2_conn_stat *cstat,
                                        const ngtcp2_cc_ack *ack,
                                        ngtcp2_tstamp ts) {
   ngtcp2_duration interval = ts - bbr->extra_acked_interval_start;
@@ -663,7 +684,8 @@ static void bbr_enter_drain(ngtcp2_cc_bb
   bbr->cwnd_gain_h = NGTCP2_BBR_DEFAULT_CWND_GAIN_H;
 }
 
-static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
+static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr,
+                                 const ngtcp2_conn_stat *cstat,
                                  ngtcp2_tstamp ts) {
   if (bbr->state == NGTCP2_BBR_STATE_DRAIN &&
       cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, 100)) {
@@ -707,7 +729,7 @@ static void bbr_start_probe_bw_refill(ng
   ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
                   "bbr start ProbeBW_REFILL");
 
-  bbr_reset_lower_bounds(bbr);
+  bbr_reset_shortterm_model(bbr);
 
   bbr->bw_probe_up_rounds = 0;
   bbr->bw_probe_up_acks = 0;
@@ -720,7 +742,8 @@ static void bbr_start_probe_bw_refill(ng
   bbr->cwnd_gain_h = NGTCP2_BBR_DEFAULT_CWND_GAIN_H;
 }
 
-static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
+static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr,
+                                  const ngtcp2_conn_stat *cstat) {
   ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr start ProbeBW_UP");
 
   bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING;
@@ -737,14 +760,14 @@ static void bbr_start_probe_bw_up(ngtcp2
 }
 
 static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
-                                            ngtcp2_conn_stat *cstat,
+                                            const ngtcp2_conn_stat *cstat,
                                             const ngtcp2_cc_ack *ack,
                                             ngtcp2_tstamp ts) {
   if (!bbr->full_bw_reached) {
     return;
   }
 
-  bbr_adapt_upper_bounds(bbr, cstat, ack);
+  bbr_adapt_longterm_model(bbr, cstat, ack);
 
   if (!bbr_is_in_probe_bw_state(bbr)) {
     return;
@@ -756,7 +779,7 @@ static void bbr_update_probe_bw_cycle_ph
       return;
     }
 
-    if (bbr_is_time_to_cruise(bbr, cstat, ts)) {
+    if (bbr_is_time_to_cruise(bbr, cstat)) {
       bbr_start_probe_bw_cruise(bbr);
     }
 
@@ -785,40 +808,34 @@ static void bbr_update_probe_bw_cycle_ph
   }
 }
 
-static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
-                                 ngtcp2_tstamp ts) {
-  (void)ts;
-
-  if (cstat->bytes_in_flight > bbr_inflight_with_headroom(bbr, cstat)) {
-    return 0;
-  }
-
-  if (cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, 100)) {
-    return 1;
-  }
+static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr,
+                                 const ngtcp2_conn_stat *cstat) {
+  uint64_t inflight = ngtcp2_min_uint64(bbr_inflight_with_headroom(bbr, cstat),
+                                        bbr_inflight(bbr, cstat, 100));
 
-  return 0;
+  return cstat->bytes_in_flight <= inflight;
 }
 
-static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
+static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr,
+                                  const ngtcp2_conn_stat *cstat) {
   if (bbr->rst->is_cwnd_limited && cstat->cwnd >= bbr->inflight_longterm) {
     bbr_reset_full_bw(bbr);
     bbr->full_bw = cstat->delivery_rate_sec;
-  } else if (bbr->full_bw_now) {
-    return 1;
+
+    return 0;
   }
 
-  return 0;
+  return bbr->full_bw_now;
 }
 
-static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr,
+static int bbr_has_elapsed_in_phase(const ngtcp2_cc_bbr *bbr,
                                     ngtcp2_duration interval,
                                     ngtcp2_tstamp ts) {
   return ts > bbr->cycle_stamp + interval;
 }
 
-static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr,
-                                           ngtcp2_conn_stat *cstat) {
+static uint64_t bbr_inflight_with_headroom(const ngtcp2_cc_bbr *bbr,
+                                           const ngtcp2_conn_stat *cstat) {
   uint64_t headroom;
   uint64_t mpcwnd;
   if (bbr->inflight_longterm == UINT64_MAX) {
@@ -839,7 +856,7 @@ static uint64_t bbr_inflight_with_headro
 }
 
 static void bbr_raise_inflight_longterm_slope(ngtcp2_cc_bbr *bbr,
-                                              ngtcp2_conn_stat *cstat) {
+                                              const ngtcp2_conn_stat *cstat) {
   uint64_t growth_this_round = cstat->max_tx_udp_payload_size
                                << bbr->bw_probe_up_rounds;
 
@@ -848,7 +865,7 @@ static void bbr_raise_inflight_longterm_
 }
 
 static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr,
-                                               ngtcp2_conn_stat *cstat,
+                                               const ngtcp2_conn_stat *cstat,
                                                const ngtcp2_cc_ack *ack) {
   uint64_t delta;
 
@@ -871,8 +888,9 @@ static void bbr_probe_inflight_longterm_
   }
 }
 
-static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
-                                   const ngtcp2_cc_ack *ack) {
+static void bbr_adapt_longterm_model(ngtcp2_cc_bbr *bbr,
+                                     const ngtcp2_conn_stat *cstat,
+                                     const ngtcp2_cc_ack *ack) {
   if (bbr->ack_phase == NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING &&
       bbr->round_start) {
     bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_FEEDBACK;
@@ -885,7 +903,7 @@ static void bbr_adapt_upper_bounds(ngtcp
     }
   }
 
-  if (!bbr_is_inflight_too_high(bbr)) {
+  if (!bbr_is_inflight_too_high(bbr, &bbr->rst->rs)) {
     if (bbr->inflight_longterm == UINT64_MAX) {
       return;
     }
@@ -900,7 +918,8 @@ static void bbr_adapt_upper_bounds(ngtcp
   }
 }
 
-static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
+static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr,
+                                   const ngtcp2_conn_stat *cstat,
                                    ngtcp2_tstamp ts) {
   if (bbr_has_elapsed_in_phase(bbr, bbr->bw_probe_wait, ts) ||
       bbr_is_reno_coexistence_probe_time(bbr, cstat)) {
@@ -913,41 +932,35 @@ static int bbr_is_time_to_probe_bw(ngtcp
 }
 
 static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr) {
-  uint8_t rand;
-
-  bbr->rand(&rand, 1, &bbr->rand_ctx);
-
-  bbr->rounds_since_bw_probe = (uint64_t)(rand * 2 / 256);
-
-  bbr->rand(&rand, 1, &bbr->rand_ctx);
-
-  bbr->bw_probe_wait = 2 * NGTCP2_SECONDS + NGTCP2_SECONDS * rand / 255;
+  bbr->rounds_since_bw_probe = ngtcp2_pcg32_rand_n(bbr->pcg, 2);
+  bbr->bw_probe_wait =
+    2 * NGTCP2_SECONDS + ngtcp2_pcg32_rand_n(bbr->pcg, NGTCP2_SECONDS + 1);
 }
 
-static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr,
-                                              ngtcp2_conn_stat *cstat) {
+static int bbr_is_reno_coexistence_probe_time(const ngtcp2_cc_bbr *bbr,
+                                              const ngtcp2_conn_stat *cstat) {
   uint64_t reno_rounds =
     bbr_target_inflight(bbr, cstat) / cstat->max_tx_udp_payload_size;
 
   return bbr->rounds_since_bw_probe >= ngtcp2_min_uint64(reno_rounds, 63);
 }
 
-static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr,
-                                    ngtcp2_conn_stat *cstat) {
+static uint64_t bbr_target_inflight(const ngtcp2_cc_bbr *bbr,
+                                    const ngtcp2_conn_stat *cstat) {
   return ngtcp2_min_uint64(bbr->bdp, cstat->cwnd);
 }
 
-static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr) {
-  const ngtcp2_rs *rs = &bbr->rst->rs;
+static int bbr_is_inflight_too_high(const ngtcp2_cc_bbr *bbr,
+                                    const ngtcp2_rs *rs) {
+  (void)bbr;
   return rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM >
          rs->tx_in_flight * NGTCP2_BBR_LOSS_THRESH_NUMER;
 }
 
 static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr,
-                                         ngtcp2_conn_stat *cstat,
+                                         const ngtcp2_conn_stat *cstat,
+                                         const ngtcp2_rs *rs,
                                          ngtcp2_tstamp ts) {
-  const ngtcp2_rs *rs = &bbr->rst->rs;
-
   bbr->bw_probe_samples = 0;
 
   if (!rs->is_app_limited) {
@@ -964,14 +977,51 @@ static void bbr_handle_inflight_too_high
 static void bbr_note_loss(ngtcp2_cc_bbr *bbr) {
   if (!bbr->loss_in_round) {
     bbr->loss_round_delivered = bbr->rst->delivered;
+    bbr_save_state_upon_loss(bbr);
   }
 
   bbr->loss_in_round = 1;
 }
 
-static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
+static void bbr_save_state_upon_loss(ngtcp2_cc_bbr *bbr) {
+  bbr->undo_state = bbr->state;
+  bbr->undo_bw_shortterm = bbr->bw_shortterm;
+  bbr->undo_inflight_shortterm = bbr->inflight_shortterm;
+  bbr->undo_inflight_longterm = bbr->inflight_longterm;
+}
+
+static void bbr_handle_spurious_loss_detection(ngtcp2_cc_bbr *bbr,
+                                               const ngtcp2_conn_stat *cstat) {
+  bbr->loss_in_round = 0;
+
+  bbr_reset_full_bw(bbr);
+
+  bbr->bw_shortterm =
+    ngtcp2_max_uint64(bbr->bw_shortterm, bbr->undo_bw_shortterm);
+  bbr->inflight_shortterm =
+    ngtcp2_max_uint64(bbr->inflight_shortterm, bbr->undo_inflight_shortterm);
+  bbr->inflight_longterm =
+    ngtcp2_max_uint64(bbr->inflight_longterm, bbr->undo_inflight_longterm);
+
+  if (bbr->state != NGTCP2_BBR_STATE_PROBE_RTT &&
+      bbr->state != bbr->undo_state) {
+    switch (bbr->undo_state) {
+    case NGTCP2_BBR_STATE_STARTUP:
+      bbr_enter_startup(bbr);
+      break;
+    case NGTCP2_BBR_STATE_PROBE_BW_UP:
+      bbr_start_probe_bw_up(bbr, cstat);
+      break;
+    default:
+      break;
+    }
+  }
+}
+
+static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr,
+                                   const ngtcp2_conn_stat *cstat,
                                    const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
-  ngtcp2_rs *rs = &bbr->rst->rs;
+  ngtcp2_rs rs = {0};
 
   bbr_note_loss(bbr);
 
@@ -979,23 +1029,21 @@ static void bbr_handle_lost_packet(ngtcp
     return;
   }
 
-  rs->tx_in_flight = pkt->tx_in_flight;
-  /* bbr->rst->lost is not incremented for pkt yet */
-  assert(bbr->rst->lost + pkt->pktlen >= pkt->lost);
-  rs->lost = bbr->rst->lost + pkt->pktlen - pkt->lost;
-  rs->is_app_limited = pkt->is_app_limited;
+  rs.tx_in_flight = pkt->tx_in_flight;
+  assert(bbr->rst->lost >= pkt->lost);
+  rs.lost = bbr->rst->lost - pkt->lost;
+  rs.is_app_limited = pkt->is_app_limited;
 
-  if (bbr_is_inflight_too_high(bbr)) {
-    rs->tx_in_flight = bbr_inflight_longterm_from_lost_packet(bbr, pkt);
+  if (bbr_is_inflight_too_high(bbr, &rs)) {
+    rs.tx_in_flight = bbr_inflight_at_loss(bbr, pkt, &rs);
 
-    bbr_handle_inflight_too_high(bbr, cstat, ts);
+    bbr_handle_inflight_too_high(bbr, cstat, &rs, ts);
   }
 }
 
-static uint64_t
-bbr_inflight_longterm_from_lost_packet(ngtcp2_cc_bbr *bbr,
-                                       const ngtcp2_cc_pkt *pkt) {
-  ngtcp2_rs *rs = &bbr->rst->rs;
+static uint64_t bbr_inflight_at_loss(const ngtcp2_cc_bbr *bbr,
+                                     const ngtcp2_cc_pkt *pkt,
+                                     const ngtcp2_rs *rs) {
   uint64_t inflight_prev, lost_prev, lost_prefix;
   (void)bbr;
 
@@ -1038,8 +1086,8 @@ static void bbr_update_min_rtt(ngtcp2_cc
     bbr->min_rtt = bbr->probe_rtt_min_delay;
     bbr->min_rtt_stamp = bbr->probe_rtt_min_stamp;
 
-    ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
-                    "bbr update min_rtt=%" PRIu64, bbr->min_rtt);
+    ngtcp2_log_infof(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
+                     "bbr update min_rtt=%" PRIu64, bbr->min_rtt);
   }
 }
 
@@ -1110,18 +1158,13 @@ static void bbr_check_probe_rtt_done(ngt
 }
 
 static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr,
-                                            ngtcp2_conn_stat *cstat) {
-  uint64_t app_limited = bbr->rst->delivered + cstat->bytes_in_flight;
-
-  if (app_limited) {
-    bbr->rst->app_limited = app_limited;
-  } else {
-    bbr->rst->app_limited = cstat->max_tx_udp_payload_size;
-  }
+                                            const ngtcp2_conn_stat *cstat) {
+  bbr->rst->app_limited =
+    ngtcp2_max_uint64(bbr->rst->delivered + cstat->bytes_in_flight, 1);
 }
 
 static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) {
-  bbr_reset_lower_bounds(bbr);
+  bbr_reset_shortterm_model(bbr);
 
   if (bbr->full_bw_reached) {
     bbr_start_probe_bw_down(bbr, ts);
@@ -1163,7 +1206,7 @@ static uint64_t min_pipe_cwnd(size_t max
 }
 
 static uint64_t bbr_quantization_budget(ngtcp2_cc_bbr *bbr,
-                                        ngtcp2_conn_stat *cstat,
+                                        const ngtcp2_conn_stat *cstat,
                                         uint64_t inflight) {
   bbr_update_offload_budget(bbr, cstat);
 
@@ -1178,7 +1221,7 @@ static uint64_t bbr_quantization_budget(
   return inflight;
 }
 
-static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
+static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat,
                              uint64_t gain_h) {
   uint64_t inflight = bbr_bdp_multiple(bbr, gain_h);
 
@@ -1186,7 +1229,7 @@ static uint64_t bbr_inflight(ngtcp2_cc_b
 }
 
 static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr,
-                                    ngtcp2_conn_stat *cstat) {
+                                    const ngtcp2_conn_stat *cstat) {
   uint64_t inflight;
 
   inflight = bbr_bdp_multiple(bbr, bbr->cwnd_gain_h) + bbr->extra_acked;
@@ -1194,7 +1237,7 @@ static void bbr_update_max_inflight(ngtc
 }
 
 static void bbr_update_offload_budget(ngtcp2_cc_bbr *bbr,
-                                      ngtcp2_conn_stat *cstat) {
+                                      const ngtcp2_conn_stat *cstat) {
   bbr->offload_budget = 3 * cstat->send_quantum;
 }
 
@@ -1202,7 +1245,7 @@ static void bbr_advance_max_bw_filter(ng
   ++bbr->cycle_count;
 }
 
-static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
+static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat) {
   if (!bbr->in_loss_recovery && bbr->state != NGTCP2_BBR_STATE_PROBE_RTT) {
     bbr->prior_cwnd = cstat->cwnd;
     return;
@@ -1211,12 +1254,13 @@ static void bbr_save_cwnd(ngtcp2_cc_bbr
   bbr->prior_cwnd = ngtcp2_max_uint64(bbr->prior_cwnd, cstat->cwnd);
 }
 
-static void bbr_restore_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
+static void bbr_restore_cwnd(const ngtcp2_cc_bbr *bbr,
+                             ngtcp2_conn_stat *cstat) {
   cstat->cwnd = ngtcp2_max_uint64(cstat->cwnd, bbr->prior_cwnd);
 }
 
 static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr,
-                                   ngtcp2_conn_stat *cstat) {
+                                   const ngtcp2_conn_stat *cstat) {
   uint64_t probe_rtt_cwnd =
     bbr_bdp_multiple(bbr, NGTCP2_BBR_PROBE_RTT_CWND_GAIN_H);
   uint64_t mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size);
@@ -1226,12 +1270,9 @@ static uint64_t bbr_probe_rtt_cwnd(ngtcp
 
 static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr,
                                          ngtcp2_conn_stat *cstat) {
-  uint64_t probe_rtt_cwnd;
-
   if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) {
-    probe_rtt_cwnd = bbr_probe_rtt_cwnd(bbr, cstat);
-
-    cstat->cwnd = ngtcp2_min_uint64(cstat->cwnd, probe_rtt_cwnd);
+    cstat->cwnd =
+      ngtcp2_min_uint64(cstat->cwnd, bbr_probe_rtt_cwnd(bbr, cstat));
   }
 }
 
@@ -1256,7 +1297,7 @@ static void bbr_set_cwnd(ngtcp2_cc_bbr *
   bbr_bound_cwnd_for_model(bbr, cstat);
 }
 
-static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr,
+static void bbr_bound_cwnd_for_model(const ngtcp2_cc_bbr *bbr,
                                      ngtcp2_conn_stat *cstat) {
   uint64_t cap = UINT64_MAX;
   uint64_t mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size);
@@ -1275,7 +1316,8 @@ static void bbr_bound_cwnd_for_model(ngt
   cstat->cwnd = ngtcp2_min_uint64(cstat->cwnd, cap);
 }
 
-static void bbr_set_send_quantum(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
+static void bbr_set_send_quantum(const ngtcp2_cc_bbr *bbr,
+                                 ngtcp2_conn_stat *cstat) {
   size_t send_quantum = 64 * 1024;
   (void)bbr;
 
@@ -1295,28 +1337,15 @@ static int in_congestion_recovery(const
 
 static void bbr_handle_recovery(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
                                 const ngtcp2_cc_ack *ack) {
-  if (bbr->in_loss_recovery) {
-    if (ack->largest_pkt_sent_ts != UINT64_MAX &&
-        !in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
-      bbr->in_loss_recovery = 0;
-      bbr->round_count_at_recovery = UINT64_MAX;
-      bbr_restore_cwnd(bbr, cstat);
-    }
-
+  if (!bbr->in_loss_recovery) {
     return;
   }
 
-  if (bbr->congestion_recovery_start_ts != UINT64_MAX) {
-    bbr->in_loss_recovery = 1;
-    bbr->round_count_at_recovery =
-      bbr->round_start ? bbr->round_count : bbr->round_count + 1;
-    bbr_save_cwnd(bbr, cstat);
-    cstat->cwnd =
-      cstat->bytes_in_flight +
-      ngtcp2_max_uint64(ack->bytes_delivered, cstat->max_tx_udp_payload_size);
-
-    cstat->congestion_recovery_start_ts = bbr->congestion_recovery_start_ts;
-    bbr->congestion_recovery_start_ts = UINT64_MAX;
+  if (ack->largest_pkt_sent_ts != UINT64_MAX &&
+      !in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
+    bbr->in_loss_recovery = 0;
+    bbr->round_count_at_recovery = UINT64_MAX;
+    bbr_restore_cwnd(bbr, cstat);
   }
 }
 
@@ -1324,22 +1353,26 @@ static void bbr_cc_on_pkt_lost(ngtcp2_cc
                                const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
   ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
 
-  bbr_update_on_loss(bbr, cstat, pkt, ts);
+  bbr_handle_lost_packet(bbr, cstat, pkt, ts);
 }
 
 static void bbr_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
-                                    ngtcp2_tstamp sent_ts, uint64_t bytes_lost,
+                                    ngtcp2_tstamp sent_ts,
+                                    const ngtcp2_cc_ack *ack,
                                     ngtcp2_tstamp ts) {
   ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
-  (void)bytes_lost;
+  (void)ack;
 
-  if (bbr->in_loss_recovery ||
-      bbr->congestion_recovery_start_ts != UINT64_MAX ||
-      in_congestion_recovery(cstat, sent_ts)) {
+  if (bbr->in_loss_recovery || in_congestion_recovery(cstat, sent_ts)) {
     return;
   }
 
-  bbr->congestion_recovery_start_ts = ts;
+  bbr->in_loss_recovery = 1;
+  bbr->round_count_at_recovery =
+    bbr->round_start ? bbr->round_count : bbr->round_count + 1;
+  bbr_save_cwnd(bbr, cstat);
+
+  cstat->congestion_recovery_start_ts = ts;
 }
 
 static void bbr_cc_on_spurious_congestion(ngtcp2_cc *cc,
@@ -1348,14 +1381,13 @@ static void bbr_cc_on_spurious_congestio
   ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
   (void)ts;
 
-  bbr->congestion_recovery_start_ts = UINT64_MAX;
   cstat->congestion_recovery_start_ts = UINT64_MAX;
 
-  if (bbr->in_loss_recovery) {
-    bbr->in_loss_recovery = 0;
-    bbr->round_count_at_recovery = UINT64_MAX;
-    bbr_restore_cwnd(bbr, cstat);
-  }
+  bbr->in_loss_recovery = 0;
+  bbr->round_count_at_recovery = UINT64_MAX;
+
+  bbr_restore_cwnd(bbr, cstat);
+  bbr_handle_spurious_loss_detection(bbr, cstat);
 }
 
 static void bbr_cc_on_persistent_congestion(ngtcp2_cc *cc,
@@ -1365,7 +1397,6 @@ static void bbr_cc_on_persistent_congest
   (void)ts;
 
   cstat->congestion_recovery_start_ts = UINT64_MAX;
-  bbr->congestion_recovery_start_ts = UINT64_MAX;
   bbr->in_loss_recovery = 0;
   bbr->round_count_at_recovery = UINT64_MAX;
 
@@ -1380,6 +1411,11 @@ static void bbr_cc_on_ack_recv(ngtcp2_cc
   ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
 
   bbr_handle_recovery(bbr, cstat, ack);
+
+  if (ack->bytes_delivered == 0) {
+    return;
+  }
+
   bbr_update_on_ack(bbr, cstat, ack, ts);
 }
 
@@ -1399,23 +1435,23 @@ static void bbr_cc_reset(ngtcp2_cc *cc,
 
 void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log,
                         ngtcp2_conn_stat *cstat, ngtcp2_rst *rst,
-                        ngtcp2_tstamp initial_ts, ngtcp2_rand rand,
-                        const ngtcp2_rand_ctx *rand_ctx) {
-  memset(bbr, 0, sizeof(*bbr));
-
-  bbr->cc.log = log;
-  bbr->cc.on_pkt_lost = bbr_cc_on_pkt_lost;
-  bbr->cc.congestion_event = bbr_cc_congestion_event;
-  bbr->cc.on_spurious_congestion = bbr_cc_on_spurious_congestion;
-  bbr->cc.on_persistent_congestion = bbr_cc_on_persistent_congestion;
-  bbr->cc.on_ack_recv = bbr_cc_on_ack_recv;
-  bbr->cc.on_pkt_sent = bbr_cc_on_pkt_sent;
-  bbr->cc.reset = bbr_cc_reset;
-
-  bbr->rst = rst;
-  bbr->rand = rand;
-  bbr->rand_ctx = *rand_ctx;
-  bbr->initial_cwnd = cstat->cwnd;
+                        ngtcp2_tstamp initial_ts, ngtcp2_pcg32 *pcg) {
+  *bbr = (ngtcp2_cc_bbr){
+    .cc =
+      {
+        .log = log,
+        .on_pkt_lost = bbr_cc_on_pkt_lost,
+        .congestion_event = bbr_cc_congestion_event,
+        .on_spurious_congestion = bbr_cc_on_spurious_congestion,
+        .on_persistent_congestion = bbr_cc_on_persistent_congestion,
+        .on_ack_recv = bbr_cc_on_ack_recv,
+        .on_pkt_sent = bbr_cc_on_pkt_sent,
+        .reset = bbr_cc_reset,
+      },
+    .rst = rst,
+    .pcg = pcg,
+    .initial_cwnd = cstat->cwnd,
+  };
 
   bbr_on_init(bbr, cstat, initial_ts);
 }
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_bbr.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_bbr.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_bbr.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_bbr.h	2026-05-15 15:49:15.155978400 +0200
@@ -35,6 +35,7 @@
 #include "ngtcp2_window_filter.h"
 
 typedef struct ngtcp2_rst ngtcp2_rst;
+typedef struct ngtcp2_pcg32 ngtcp2_pcg32;
 
 typedef enum ngtcp2_bbr_state {
   NGTCP2_BBR_STATE_STARTUP,
@@ -62,8 +63,7 @@ typedef struct ngtcp2_cc_bbr {
 
   uint64_t initial_cwnd;
   ngtcp2_rst *rst;
-  ngtcp2_rand rand;
-  ngtcp2_rand_ctx rand_ctx;
+  ngtcp2_pcg32 *pcg;
 
   /* max_bw_filter for tracking the maximum recent delivery rate
     samples for estimating max_bw. */
@@ -75,8 +75,8 @@ typedef struct ngtcp2_cc_bbr {
   ngtcp2_tstamp min_rtt_stamp;
   ngtcp2_tstamp probe_rtt_done_stamp;
   int probe_rtt_round_done;
-  uint64_t prior_cwnd;
   int idle_restart;
+  uint64_t prior_cwnd;
   ngtcp2_tstamp extra_acked_interval_start;
   uint64_t extra_acked_delivered;
 
@@ -91,8 +91,8 @@ typedef struct ngtcp2_cc_bbr {
 
   /* Round counting */
   uint64_t next_round_delivered;
-  int round_start;
   uint64_t round_count;
+  int round_start;
 
   /* Full pipe */
   uint64_t full_bw;
@@ -106,7 +106,12 @@ typedef struct ngtcp2_cc_bbr {
   ngtcp2_bbr_state state;
   uint64_t cwnd_gain_h;
 
-  int loss_round_start;
+  /* Backup for spurious losses */
+  ngtcp2_bbr_state undo_state;
+  uint64_t undo_bw_shortterm;
+  uint64_t undo_inflight_shortterm;
+  uint64_t undo_inflight_longterm;
+
   uint64_t loss_round_delivered;
   uint64_t rounds_since_bw_probe;
   uint64_t max_bw;
@@ -120,23 +125,22 @@ typedef struct ngtcp2_cc_bbr {
   ngtcp2_tstamp cycle_stamp;
   ngtcp2_bbr_ack_phase ack_phase;
   ngtcp2_duration bw_probe_wait;
-  int bw_probe_samples;
   size_t bw_probe_up_rounds;
   uint64_t bw_probe_up_acks;
   uint64_t inflight_longterm;
-  int probe_rtt_expired;
   ngtcp2_duration probe_rtt_min_delay;
   ngtcp2_tstamp probe_rtt_min_stamp;
-  int in_loss_recovery;
   uint64_t round_count_at_recovery;
   uint64_t max_inflight;
-  ngtcp2_tstamp congestion_recovery_start_ts;
   uint64_t bdp;
+  int loss_round_start;
+  int bw_probe_samples;
+  int probe_rtt_expired;
+  int in_loss_recovery;
 } ngtcp2_cc_bbr;
 
 void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log,
                         ngtcp2_conn_stat *cstat, ngtcp2_rst *rst,
-                        ngtcp2_tstamp initial_ts, ngtcp2_rand rand,
-                        const ngtcp2_rand_ctx *rand_ctx);
+                        ngtcp2_tstamp initial_ts, ngtcp2_pcg32 *pcg);
 
 #endif /* !defined(NGTCP2_BBR_H) */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_buf.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_buf.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_buf.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_buf.c	2026-05-15 15:49:15.155978400 +0200
@@ -26,8 +26,12 @@
 #include "ngtcp2_mem.h"
 
 void ngtcp2_buf_init(ngtcp2_buf *buf, uint8_t *begin, size_t len) {
-  buf->begin = buf->pos = buf->last = begin;
-  buf->end = begin + len;
+  *buf = (ngtcp2_buf){
+    .begin = begin,
+    .end = begin + len,
+    .pos = begin,
+    .last = begin,
+  };
 }
 
 void ngtcp2_buf_reset(ngtcp2_buf *buf) { buf->pos = buf->last = buf->begin; }
@@ -36,6 +40,12 @@ size_t ngtcp2_buf_cap(const ngtcp2_buf *
   return (size_t)(buf->end - buf->begin);
 }
 
+void ngtcp2_buf_trunc(ngtcp2_buf *buf, size_t len) {
+  if (ngtcp2_buf_len(buf) > len) {
+    buf->last = buf->pos + len;
+  }
+}
+
 int ngtcp2_buf_chain_new(ngtcp2_buf_chain **pbufchain, size_t len,
                          const ngtcp2_mem *mem) {
   *pbufchain = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_buf_chain) + len);
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_buf.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_buf.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_buf.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_buf.h	2026-05-15 15:49:15.156978400 +0200
@@ -62,7 +62,9 @@ void ngtcp2_buf_reset(ngtcp2_buf *buf);
  * written to the underlying buffer.  In other words, it returns
  * buf->end - buf->last.
  */
-#define ngtcp2_buf_left(BUF) (size_t)((BUF)->end - (BUF)->last)
+static inline size_t ngtcp2_buf_left(const ngtcp2_buf *buf) {
+  return (size_t)(buf->end - buf->last);
+}
 
 /*
  * ngtcp2_buf_len returns the number of bytes left to read.  In other
@@ -77,6 +79,13 @@ void ngtcp2_buf_reset(ngtcp2_buf *buf);
 size_t ngtcp2_buf_cap(const ngtcp2_buf *buf);
 
 /*
+ * ngtcp2_buf_trunc truncates the number of bytes to read to at most
+ * |len|.  In other words, it sets buf->last = buf->pos + len if
+ * ngtcp2_buf_len(buf) > len.
+ */
+void ngtcp2_buf_trunc(ngtcp2_buf *buf, size_t len);
+
+/*
  * ngtcp2_buf_chain is a linked list of ngtcp2_buf.
  */
 typedef struct ngtcp2_buf_chain ngtcp2_buf_chain;
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_callbacks.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_callbacks.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_callbacks.c	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_callbacks.c	2026-05-15 15:49:15.156978400 +0200
@@ -0,0 +1,75 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2025 ngtcp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "ngtcp2_callbacks.h"
+
+#include <string.h>
+#include <assert.h>
+
+#include "ngtcp2_unreachable.h"
+
+static void callbacks_copy(ngtcp2_callbacks *dest, const ngtcp2_callbacks *src,
+                           int callbacks_version) {
+  assert(callbacks_version != NGTCP2_CALLBACKS_VERSION);
+
+  memcpy(dest, src, ngtcp2_callbackslen_version(callbacks_version));
+}
+
+const ngtcp2_callbacks *ngtcp2_callbacks_convert_to_latest(
+  ngtcp2_callbacks *dest, int callbacks_version, const ngtcp2_callbacks *src) {
+  if (callbacks_version == NGTCP2_CALLBACKS_VERSION) {
+    return src;
+  }
+
+  *dest = (ngtcp2_callbacks){0};
+
+  callbacks_copy(dest, src, callbacks_version);
+
+  return dest;
+}
+
+void ngtcp2_callbacks_convert_to_old(int callbacks_version,
+                                     ngtcp2_callbacks *dest,
+                                     const ngtcp2_callbacks *src) {
+  assert(callbacks_version != NGTCP2_CALLBACKS_VERSION);
+
+  callbacks_copy(dest, src, callbacks_version);
+}
+
+size_t ngtcp2_callbackslen_version(int callbacks_version) {
+  ngtcp2_callbacks callbacks;
+
+  switch (callbacks_version) {
+  case NGTCP2_CALLBACKS_VERSION:
+    return sizeof(callbacks);
+  case NGTCP2_CALLBACKS_V2:
+    return offsetof(ngtcp2_callbacks, begin_path_validation) +
+           sizeof(callbacks.begin_path_validation);
+  case NGTCP2_CALLBACKS_V1:
+    return offsetof(ngtcp2_callbacks, tls_early_data_rejected) +
+           sizeof(callbacks.tls_early_data_rejected);
+  default:
+    ngtcp2_unreachable();
+  }
+}
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_callbacks.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_callbacks.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_callbacks.h	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_callbacks.h	2026-05-15 15:49:15.156978400 +0200
@@ -0,0 +1,73 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2025 ngtcp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGTCP2_CALLBACKS_H
+#define NGTCP2_CALLBACKS_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif /* defined(HAVE_CONFIG_H) */
+
+#include <ngtcp2/ngtcp2.h>
+
+/*
+ * ngtcp2_callbacks_convert_to_latest converts |src| of version
+ * |callbacks_version| to the latest version NGTCP2_CALLBACKS_VERSION.
+ *
+ * |dest| must point to the latest version.  |src| may be the older
+ * version, and if so, it may have fewer fields.  Accessing those
+ * fields causes undefined behavior.
+ *
+ * If |callbacks_version| == NGTCP2_CALLBACKS_VERSION, no conversion
+ * is made, and |src| is returned.  Otherwise, first |dest| is
+ * zero-initialized, and then all valid fields in |src| are copied
+ * into |dest|.  Finally, |dest| is returned.
+ */
+const ngtcp2_callbacks *ngtcp2_callbacks_convert_to_latest(
+  ngtcp2_callbacks *dest, int callbacks_version, const ngtcp2_callbacks *src);
+
+/*
+ * ngtcp2_callbacks_convert_to_old converts |src| of the latest
+ * version to |dest| of version |callbacks_version|.
+ *
+ * |callbacks_version| must not be the latest version
+ *  NGTCP2_CALLBACKS_VERSION.
+ *
+ * |dest| points to the older version, and it may have fewer fields.
+ * Accessing those fields causes undefined behavior.
+ *
+ * This function copies all valid fields in version
+ * |callbacks_version| from |src| to |dest|.
+ */
+void ngtcp2_callbacks_convert_to_old(int callbacks_version,
+                                     ngtcp2_callbacks *dest,
+                                     const ngtcp2_callbacks *src);
+
+/*
+ * ngtcp2_callbackslen_version returns the effective length of
+ * ngtcp2_callbacks at the version |callbacks_version|.
+ */
+size_t ngtcp2_callbackslen_version(int callbacks_version);
+
+#endif /* !defined(NGTCP2_CALLBACKS_H) */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_cc.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_cc.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_cc.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_cc.c	2026-05-15 15:49:15.156978400 +0200
@@ -41,6 +41,40 @@ uint64_t ngtcp2_cc_compute_initcwnd(size
   return ngtcp2_min_uint64(10 * max_udp_payload_size, n);
 }
 
+/* 1.25 is the under-utilization avoidance factor described in
+   https://datatracker.ietf.org/doc/html/rfc9002#section-7.7 */
+#define NGTCP2_CC_PACING_GAIN_H 125
+
+static void init_pacing_rate(ngtcp2_conn_stat *cstat) {
+  assert(cstat->cwnd);
+
+  cstat->pacing_interval_m = ngtcp2_max_uint64(
+    (NGTCP2_MILLISECONDS << 10) * 100 / NGTCP2_CC_PACING_GAIN_H / cstat->cwnd,
+    1);
+  cstat->send_quantum = 10 * cstat->max_tx_udp_payload_size;
+}
+
+static void set_pacing_rate(ngtcp2_conn_stat *cstat) {
+  size_t send_quantum = 64 * 1024;
+
+  assert(cstat->cwnd);
+
+  cstat->pacing_interval_m =
+    ((cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS
+                                               : cstat->smoothed_rtt)
+     << 10) *
+    100 / NGTCP2_CC_PACING_GAIN_H / cstat->cwnd;
+
+  cstat->pacing_interval_m = ngtcp2_max_uint64(cstat->pacing_interval_m, 1);
+
+  send_quantum =
+    ngtcp2_min_size(send_quantum, (size_t)((NGTCP2_MILLISECONDS << 10) /
+                                           cstat->pacing_interval_m));
+
+  cstat->send_quantum =
+    ngtcp2_max_size(send_quantum, 10 * cstat->max_tx_udp_payload_size);
+}
+
 ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num,
                                   size_t pktlen, ngtcp2_pktns_id pktns_id,
                                   ngtcp2_tstamp sent_ts, uint64_t lost,
@@ -56,19 +90,26 @@ ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2
   return pkt;
 }
 
-static void reno_cc_reset(ngtcp2_cc_reno *reno) { reno->pending_add = 0; }
+static void reno_cc_reset(ngtcp2_cc_reno *reno, ngtcp2_conn_stat *cstat) {
+  reno->pending_add = 0;
 
-void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log) {
-  memset(reno, 0, sizeof(*reno));
+  init_pacing_rate(cstat);
+}
 
-  reno->cc.log = log;
-  reno->cc.on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked;
-  reno->cc.congestion_event = ngtcp2_cc_reno_cc_congestion_event;
-  reno->cc.on_persistent_congestion =
-    ngtcp2_cc_reno_cc_on_persistent_congestion;
-  reno->cc.reset = ngtcp2_cc_reno_cc_reset;
+void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log,
+                         ngtcp2_conn_stat *cstat) {
+  *reno = (ngtcp2_cc_reno){
+    .cc =
+      {
+        .log = log,
+        .on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked,
+        .congestion_event = ngtcp2_cc_reno_cc_congestion_event,
+        .on_persistent_congestion = ngtcp2_cc_reno_cc_on_persistent_congestion,
+        .reset = ngtcp2_cc_reno_cc_reset,
+      },
+  };
 
-  reno_cc_reset(reno);
+  reno_cc_reset(reno, cstat);
 }
 
 static int in_congestion_recovery(const ngtcp2_conn_stat *cstat,
@@ -90,9 +131,12 @@ void ngtcp2_cc_reno_cc_on_pkt_acked(ngtc
 
   if (cstat->cwnd < cstat->ssthresh) {
     cstat->cwnd += pkt->pktlen;
-    ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
-                    "pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64,
-                    pkt->pkt_num, cstat->cwnd);
+
+    set_pacing_rate(cstat);
+
+    ngtcp2_log_infof(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
+                     "pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64,
+                     pkt->pkt_num, cstat->cwnd);
     return;
   }
 
@@ -100,14 +144,17 @@ void ngtcp2_cc_reno_cc_on_pkt_acked(ngtc
   reno->pending_add = m % cstat->cwnd;
 
   cstat->cwnd += m / cstat->cwnd;
+
+  set_pacing_rate(cstat);
 }
 
 void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                                         ngtcp2_tstamp sent_ts,
-                                        uint64_t bytes_lost, ngtcp2_tstamp ts) {
+                                        const ngtcp2_cc_ack *ack,
+                                        ngtcp2_tstamp ts) {
   ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc);
   uint64_t min_cwnd;
-  (void)bytes_lost;
+  (void)ack;
 
   if (in_congestion_recovery(cstat, sent_ts)) {
     return;
@@ -121,9 +168,11 @@ void ngtcp2_cc_reno_cc_congestion_event(
 
   reno->pending_add = 0;
 
-  ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
-                  "reduce cwnd because of packet loss cwnd=%" PRIu64,
-                  cstat->cwnd);
+  set_pacing_rate(cstat);
+
+  ngtcp2_log_infof(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
+                   "reduce cwnd because of packet loss cwnd=%" PRIu64,
+                   cstat->cwnd);
 }
 
 void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc,
@@ -134,31 +183,32 @@ void ngtcp2_cc_reno_cc_on_persistent_con
 
   cstat->cwnd = 2 * cstat->max_tx_udp_payload_size;
   cstat->congestion_recovery_start_ts = UINT64_MAX;
+
+  set_pacing_rate(cstat);
 }
 
 void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                              ngtcp2_tstamp ts) {
   ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc);
-  (void)cstat;
   (void)ts;
 
-  reno_cc_reset(reno);
+  reno_cc_reset(reno, cstat);
 }
 
 static void cubic_vars_reset(ngtcp2_cubic_vars *v) {
   v->cwnd_prior = 0;
   v->w_max = 0;
-  v->k = 0;
+  v->k_m = 0;
   v->epoch_start = UINT64_MAX;
   v->w_est = 0;
 
   v->app_limited_start_ts = UINT64_MAX;
   v->app_limited_duration = 0;
-  v->pending_bytes_delivered = 0;
-  v->pending_est_bytes_delivered = 0;
+  v->pending_bytes_acked = 0;
+  v->pending_est_bytes_acked = 0;
 }
 
-static void cubic_cc_reset(ngtcp2_cc_cubic *cubic) {
+static void cubic_cc_reset(ngtcp2_cc_cubic *cubic, ngtcp2_conn_stat *cstat) {
   cubic_vars_reset(&cubic->current);
   cubic_vars_reset(&cubic->undo.v);
   cubic->undo.cwnd = 0;
@@ -172,23 +222,26 @@ static void cubic_cc_reset(ngtcp2_cc_cub
   cubic->hs.css_round = 0;
 
   cubic->next_round_delivered = 0;
+
+  init_pacing_rate(cstat);
 }
 
 void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cubic, ngtcp2_log *log,
-                          ngtcp2_rst *rst) {
-  memset(cubic, 0, sizeof(*cubic));
-
-  cubic->cc.log = log;
-  cubic->cc.on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv;
-  cubic->cc.congestion_event = ngtcp2_cc_cubic_cc_congestion_event;
-  cubic->cc.on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion;
-  cubic->cc.on_persistent_congestion =
-    ngtcp2_cc_cubic_cc_on_persistent_congestion;
-  cubic->cc.reset = ngtcp2_cc_cubic_cc_reset;
+                          ngtcp2_conn_stat *cstat, ngtcp2_rst *rst) {
+  *cubic = (ngtcp2_cc_cubic){
+    .cc =
+      {
+        .log = log,
+        .on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv,
+        .congestion_event = ngtcp2_cc_cubic_cc_congestion_event,
+        .on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion,
+        .on_persistent_congestion = ngtcp2_cc_cubic_cc_on_persistent_congestion,
+        .reset = ngtcp2_cc_cubic_cc_reset,
+      },
+    .rst = rst,
+  };
 
-  cubic->rst = rst;
-
-  cubic_cc_reset(cubic);
+  cubic_cc_reset(cubic, cstat);
 }
 
 uint64_t ngtcp2_cbrt(uint64_t n) {
@@ -208,7 +261,6 @@ uint64_t ngtcp2_cbrt(uint64_t n) {
   y <<= 1;
   b = 3 * y * (y + 1) + 1;
   if (n >= b) {
-    n -= b;
     y++;
   }
 
@@ -223,30 +275,54 @@ uint64_t ngtcp2_cbrt(uint64_t n) {
 #define NGTCP2_HS_CSS_GROWTH_DIVISOR 4
 #define NGTCP2_HS_CSS_ROUNDS 5
 
-static int64_t cubic_cc_compute_w_cubic(ngtcp2_cc_cubic *cubic,
-                                        const ngtcp2_conn_stat *cstat,
-                                        ngtcp2_tstamp ts) {
+static uint64_t cubic_cc_compute_w_cubic(ngtcp2_cc_cubic *cubic,
+                                         const ngtcp2_conn_stat *cstat,
+                                         ngtcp2_tstamp ts) {
   ngtcp2_duration t = ts - cubic->current.epoch_start;
-  int64_t tx = (int64_t)((t << 10) / NGTCP2_SECONDS);
-  int64_t time_delta = ngtcp2_min_int64(tx - cubic->current.k, 3600 << 10);
-  int64_t delta = ((((time_delta * time_delta) >> 10) * time_delta) >> 20) *
-                  (int64_t)cstat->max_tx_udp_payload_size * 4 / 10;
+  uint64_t tx_m = (t << 10) / NGTCP2_SECONDS;
+  int neg = tx_m < cubic->current.k_m;
+  uint64_t time_delta_m;
+  uint64_t delta;
+
+  /* Avoid signed bit-shift */
+  if (neg) {
+    time_delta_m = cubic->current.k_m - tx_m;
+  } else {
+    time_delta_m = tx_m - cubic->current.k_m;
+  }
+
+  time_delta_m = ngtcp2_min_uint64(time_delta_m, 3600 << 10);
+
+  delta = ((((time_delta_m * time_delta_m) >> 10) * time_delta_m) >> 10) *
+          cstat->max_tx_udp_payload_size * 4 / 10;
+  delta >>= 10;
+
+  if (neg) {
+    if (cubic->current.w_max < delta) {
+      /* Negative w_cubic is not interesting. */
+      return 0;
+    }
 
-  return (int64_t)cubic->current.w_max + delta;
+    return cubic->current.w_max - delta;
+  }
+
+  return cubic->current.w_max + delta;
 }
 
 void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                                     const ngtcp2_cc_ack *ack,
                                     ngtcp2_tstamp ts) {
   ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
-  int64_t w_cubic, w_cubic_next;
+  uint64_t w_cubic, w_cubic_next;
   uint64_t target, m;
+  uint64_t bytes_acked;
   ngtcp2_duration rtt_thresh;
   int round_start;
   int is_app_limited =
     cubic->rst->rs.is_app_limited && !cubic->rst->is_cwnd_limited;
 
-  if (in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
+  if (ack->bytes_delivered == 0 ||
+      in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
     return;
   }
 
@@ -266,9 +342,11 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtc
         cstat->cwnd += ack->bytes_delivered;
       }
 
-      ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
-                      "%" PRIu64 " bytes acked, slow start cwnd=%" PRIu64,
-                      ack->bytes_delivered, cstat->cwnd);
+      set_pacing_rate(cstat);
+
+      ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
+                       "%" PRIu64 " bytes acked, slow start cwnd=%" PRIu64,
+                       ack->bytes_delivered, cstat->cwnd);
     }
 
     if (round_start) {
@@ -346,44 +424,54 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtc
     cubic, cstat,
     ts - cubic->current.app_limited_duration + cstat->smoothed_rtt);
 
-  if (w_cubic_next < (int64_t)cstat->cwnd) {
+  if (w_cubic_next < cstat->cwnd) {
     target = cstat->cwnd;
-  } else if (2 * w_cubic_next > 3 * (int64_t)cstat->cwnd) {
+  } else if (2 * w_cubic_next > 3 * cstat->cwnd) {
     target = cstat->cwnd * 3 / 2;
   } else {
-    assert(w_cubic_next >= 0);
-    target = (uint64_t)w_cubic_next;
+    target = w_cubic_next;
   }
 
-  m = ack->bytes_delivered * cstat->max_tx_udp_payload_size +
-      cubic->current.pending_est_bytes_delivered;
-  cubic->current.pending_est_bytes_delivered = m % cstat->cwnd;
+  bytes_acked = ack->bytes_delivered * cstat->max_tx_udp_payload_size;
+  m = (bytes_acked + cubic->current.pending_est_bytes_acked) / cstat->cwnd;
+
+  cubic->current.pending_est_bytes_acked += bytes_acked;
+  cubic->current.pending_est_bytes_acked -= m * cstat->cwnd;
+
+  assert(cubic->current.pending_est_bytes_acked < cstat->cwnd);
 
   if (cubic->current.w_est < cubic->current.cwnd_prior) {
-    cubic->current.w_est += m * 9 / 17 / cstat->cwnd;
+    cubic->current.w_est += m * 9 / 17;
   } else {
-    cubic->current.w_est += m / cstat->cwnd;
+    cubic->current.w_est += m;
   }
 
-  if ((int64_t)cubic->current.w_est > w_cubic) {
+  if (cubic->current.w_est > w_cubic) {
     cstat->cwnd = cubic->current.w_est;
   } else {
-    m = (target - cstat->cwnd) * cstat->max_tx_udp_payload_size +
-        cubic->current.pending_bytes_delivered;
-    cstat->cwnd += m / cstat->cwnd;
-    cubic->current.pending_bytes_delivered = m % cstat->cwnd;
+    bytes_acked = (target - cstat->cwnd) * cstat->max_tx_udp_payload_size;
+    m = (bytes_acked + cubic->current.pending_bytes_acked) / cstat->cwnd;
+
+    cubic->current.pending_bytes_acked += bytes_acked;
+    cubic->current.pending_bytes_acked -= m * cstat->cwnd;
+
+    assert(cubic->current.pending_bytes_acked < cstat->cwnd);
+
+    cstat->cwnd += m;
   }
 
-  ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
-                  "%" PRIu64 " bytes acked, cubic-ca cwnd=%" PRIu64
-                  " k=%" PRIi64 " target=%" PRIu64 " w_est=%" PRIu64,
-                  ack->bytes_delivered, cstat->cwnd, cubic->current.k, target,
-                  cubic->current.w_est);
+  set_pacing_rate(cstat);
+
+  ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
+                   "%" PRIu64 " bytes acked, cubic-ca cwnd=%" PRIu64
+                   " k_m=%" PRIu64 " target=%" PRIu64 " w_est=%" PRIu64,
+                   ack->bytes_delivered, cstat->cwnd, cubic->current.k_m,
+                   target, cubic->current.w_est);
 }
 
 void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                                          ngtcp2_tstamp sent_ts,
-                                         uint64_t bytes_lost,
+                                         const ngtcp2_cc_ack *ack,
                                          ngtcp2_tstamp ts) {
   ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
   uint64_t flight_size;
@@ -404,8 +492,8 @@ void ngtcp2_cc_cubic_cc_congestion_event
   cubic->current.epoch_start = ts;
   cubic->current.app_limited_start_ts = UINT64_MAX;
   cubic->current.app_limited_duration = 0;
-  cubic->current.pending_bytes_delivered = 0;
-  cubic->current.pending_est_bytes_delivered = 0;
+  cubic->current.pending_bytes_acked = 0;
+  cubic->current.pending_est_bytes_acked = 0;
 
   if (cstat->cwnd < cubic->current.w_max) {
     cubic->current.w_max = cstat->cwnd * 17 / 20;
@@ -413,10 +501,13 @@ void ngtcp2_cc_cubic_cc_congestion_event
     cubic->current.w_max = cstat->cwnd;
   }
 
+  cubic->current.w_max =
+    ngtcp2_max_uint64(cubic->current.w_max, 2 * cstat->max_tx_udp_payload_size);
+
   cstat->ssthresh = cstat->cwnd * 7 / 10;
 
   if (cubic->rst->rs.delivered * 2 < cstat->cwnd) {
-    flight_size = cstat->bytes_in_flight + bytes_lost;
+    flight_size = cstat->bytes_in_flight + ack->bytes_lost;
     cstat->ssthresh = ngtcp2_min_uint64(
       cstat->ssthresh,
       ngtcp2_max_uint64(cubic->rst->rs.delivered, flight_size));
@@ -430,21 +521,18 @@ void ngtcp2_cc_cubic_cc_congestion_event
 
   cubic->current.w_est = cstat->cwnd;
 
-  if (cstat->cwnd < cubic->current.w_max) {
-    cwnd_delta = cubic->current.w_max - cstat->cwnd;
-  } else {
-    cwnd_delta = cstat->cwnd - cubic->current.w_max;
-  }
+  assert(cubic->current.w_max >= cstat->cwnd);
 
-  cubic->current.k = (int64_t)ngtcp2_cbrt((cwnd_delta << 30) * 10 / 4 /
-                                          cstat->max_tx_udp_payload_size);
-  if (cstat->cwnd >= cubic->current.w_max) {
-    cubic->current.k = -cubic->current.k;
-  }
+  cwnd_delta = cubic->current.w_max - cstat->cwnd;
+
+  cubic->current.k_m =
+    ngtcp2_cbrt((cwnd_delta << 30) * 10 / 4 / cstat->max_tx_udp_payload_size);
 
-  ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
-                  "reduce cwnd because of packet loss cwnd=%" PRIu64,
-                  cstat->cwnd);
+  set_pacing_rate(cstat);
+
+  ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
+                   "reduce cwnd because of packet loss cwnd=%" PRIu64,
+                   cstat->cwnd);
 }
 
 void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *cc,
@@ -460,10 +548,12 @@ void ngtcp2_cc_cubic_cc_on_spurious_cong
     cstat->cwnd = cubic->undo.cwnd;
     cstat->ssthresh = cubic->undo.ssthresh;
 
-    ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
-                    "spurious congestion is detected and congestion state is "
-                    "restored cwnd=%" PRIu64,
-                    cstat->cwnd);
+    set_pacing_rate(cstat);
+
+    ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
+                     "spurious congestion is detected and congestion state is "
+                     "restored cwnd=%" PRIu64,
+                     cstat->cwnd);
   }
 
   cubic_vars_reset(&cubic->undo.v);
@@ -477,17 +567,18 @@ void ngtcp2_cc_cubic_cc_on_persistent_co
   ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
   (void)ts;
 
-  cubic_cc_reset(cubic);
+  cubic_cc_reset(cubic, cstat);
 
   cstat->cwnd = 2 * cstat->max_tx_udp_payload_size;
   cstat->congestion_recovery_start_ts = UINT64_MAX;
+
+  set_pacing_rate(cstat);
 }
 
 void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                               ngtcp2_tstamp ts) {
   ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
-  (void)cstat;
   (void)ts;
 
-  cubic_cc_reset(cubic);
+  cubic_cc_reset(cubic, cstat);
 }
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_cc.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_cc.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_cc.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_cc.h	2026-05-15 15:49:15.156978400 +0200
@@ -89,11 +89,6 @@ typedef struct ngtcp2_cc_pkt {
  */
 typedef struct ngtcp2_cc_ack {
   /**
-   * :member:`prior_bytes_in_flight` is the in-flight bytes before
-   * processing this ACK.
-   */
-  uint64_t prior_bytes_in_flight;
-  /**
    * :member:`bytes_delivered` is the number of bytes acknowledged.
    */
   uint64_t bytes_delivered;
@@ -143,13 +138,16 @@ typedef void (*ngtcp2_cc_on_pkt_lost)(ng
  * @functypedef
  *
  * :type:`ngtcp2_cc_congestion_event` is a callback function which is
- * called when congestion event happens (e.g., when packet is lost).
- * |bytes_lost| is the number of bytes lost in this congestion event.
+ * called when congestion event happens (e.g., when packet is lost or
+ * due to ECN).  |ack| contains information after ACK processing.
+ * This callback may be called from non-ACK processing context.  In
+ * that case, the information only taken from |ack| processing has
+ * default values, like 0 or UINT64_MAX;
  */
 typedef void (*ngtcp2_cc_congestion_event)(ngtcp2_cc *cc,
                                            ngtcp2_conn_stat *cstat,
                                            ngtcp2_tstamp sent_ts,
-                                           uint64_t bytes_lost,
+                                           const ngtcp2_cc_ack *ack,
                                            ngtcp2_tstamp ts);
 
 /**
@@ -186,7 +184,8 @@ typedef void (*ngtcp2_cc_on_ack_recv)(ng
  * @functypedef
  *
  * :type:`ngtcp2_cc_on_pkt_sent` is a callback function which is
- * called when an ack-eliciting packet is sent.
+ * called when an ack-eliciting packet is sent.  The lost,
+ * tx_in_flight, and is_app_limited fields in |pkt| are set to 0.
  */
 typedef void (*ngtcp2_cc_on_pkt_sent)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                                       const ngtcp2_cc_pkt *pkt);
@@ -194,15 +193,6 @@ typedef void (*ngtcp2_cc_on_pkt_sent)(ng
 /**
  * @functypedef
  *
- * :type:`ngtcp2_cc_new_rtt_sample` is a callback function which is
- * called when new RTT sample is obtained.
- */
-typedef void (*ngtcp2_cc_new_rtt_sample)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
-                                         ngtcp2_tstamp ts);
-
-/**
- * @functypedef
- *
  * :type:`ngtcp2_cc_reset` is a callback function which is called when
  * congestion state must be reset.
  */
@@ -210,28 +200,6 @@ typedef void (*ngtcp2_cc_reset)(ngtcp2_c
                                 ngtcp2_tstamp ts);
 
 /**
- * @enum
- *
- * :type:`ngtcp2_cc_event_type` defines congestion control events.
- */
-typedef enum ngtcp2_cc_event_type {
-  /**
-   * :enum:`NGTCP2_CC_EVENT_TX_START` occurs when ack-eliciting packet
-   * is sent and no other ack-eliciting packet is present.
-   */
-  NGTCP2_CC_EVENT_TYPE_TX_START
-} ngtcp2_cc_event_type;
-
-/**
- * @functypedef
- *
- * :type:`ngtcp2_cc_event` is a callback function which is called when
- * a specific event happens.
- */
-typedef void (*ngtcp2_cc_event)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
-                                ngtcp2_cc_event_type event, ngtcp2_tstamp ts);
-
-/**
  * @struct
  *
  * :type:`ngtcp2_cc` is congestion control algorithm interface shared
@@ -254,7 +222,7 @@ typedef struct ngtcp2_cc {
   ngtcp2_cc_on_pkt_lost on_pkt_lost;
   /**
    * :member:`congestion_event` is a callback function which is called
-   * when congestion event happens (.e.g, packet is lost).
+   * when congestion event happens (e.g., packet is lost).
    */
   ngtcp2_cc_congestion_event congestion_event;
   /**
@@ -278,20 +246,10 @@ typedef struct ngtcp2_cc {
    */
   ngtcp2_cc_on_pkt_sent on_pkt_sent;
   /**
-   * :member:`new_rtt_sample` is a callback function which is called
-   * when new RTT sample is obtained.
-   */
-  ngtcp2_cc_new_rtt_sample new_rtt_sample;
-  /**
    * :member:`reset` is a callback function which is called when
    * congestion control state must be reset.
    */
   ngtcp2_cc_reset reset;
-  /**
-   * :member:`event` is a callback function which is called when a
-   * specific event happens.
-   */
-  ngtcp2_cc_event event;
 } ngtcp2_cc;
 
 /*
@@ -310,14 +268,16 @@ typedef struct ngtcp2_cc_reno {
   uint64_t pending_add;
 } ngtcp2_cc_reno;
 
-void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log);
+void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log,
+                         ngtcp2_conn_stat *cstat);
 
 void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                                     const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
 
 void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                                         ngtcp2_tstamp sent_ts,
-                                        uint64_t bytes_lost, ngtcp2_tstamp ts);
+                                        const ngtcp2_cc_ack *ack,
+                                        ngtcp2_tstamp ts);
 
 void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc,
                                                 ngtcp2_conn_stat *cstat,
@@ -329,7 +289,8 @@ void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *
 typedef struct ngtcp2_cubic_vars {
   uint64_t cwnd_prior;
   uint64_t w_max;
-  int64_t k;
+  /* CUBIC K with 10 bits extra precision. */
+  uint64_t k_m;
   ngtcp2_tstamp epoch_start;
   uint64_t w_est;
 
@@ -339,8 +300,8 @@ typedef struct ngtcp2_cubic_vars {
   /* app_limited_duration is the cumulative duration where a
      connection is under app limited when ACK is received. */
   ngtcp2_duration app_limited_duration;
-  uint64_t pending_bytes_delivered;
-  uint64_t pending_est_bytes_delivered;
+  uint64_t pending_bytes_acked;
+  uint64_t pending_est_bytes_acked;
 } ngtcp2_cubic_vars;
 
 /* ngtcp2_cc_cubic is CUBIC congestion controller. */
@@ -370,14 +331,15 @@ typedef struct ngtcp2_cc_cubic {
 } ngtcp2_cc_cubic;
 
 void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cc, ngtcp2_log *log,
-                          ngtcp2_rst *rst);
+                          ngtcp2_conn_stat *cstat, ngtcp2_rst *rst);
 
 void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                                     const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
 
 void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                                          ngtcp2_tstamp sent_ts,
-                                         uint64_t bytes_lost, ngtcp2_tstamp ts);
+                                         const ngtcp2_cc_ack *ack,
+                                         ngtcp2_tstamp ts);
 
 void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *ccx,
                                                ngtcp2_conn_stat *cstat,
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_cid.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_cid.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_cid.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_cid.c	2026-05-15 15:49:15.156978400 +0200
@@ -29,8 +29,9 @@
 
 #include "ngtcp2_path.h"
 #include "ngtcp2_str.h"
+#include "ngtcp2_pkt.h"
 
-void ngtcp2_cid_zero(ngtcp2_cid *cid) { memset(cid, 0, sizeof(*cid)); }
+void ngtcp2_cid_zero(ngtcp2_cid *cid) { *cid = (ngtcp2_cid){0}; }
 
 void ngtcp2_cid_init(ngtcp2_cid *cid, const uint8_t *data, size_t datalen) {
   assert(datalen <= NGTCP2_MAX_CIDLEN);
@@ -58,11 +59,13 @@ int ngtcp2_cid_less(const ngtcp2_cid *lh
 int ngtcp2_cid_empty(const ngtcp2_cid *cid) { return cid->datalen == 0; }
 
 void ngtcp2_scid_init(ngtcp2_scid *scid, uint64_t seq, const ngtcp2_cid *cid) {
-  scid->pe.index = NGTCP2_PQ_BAD_INDEX;
-  scid->seq = seq;
-  scid->cid = *cid;
-  scid->retired_ts = UINT64_MAX;
-  scid->flags = NGTCP2_SCID_FLAG_NONE;
+  *scid = (ngtcp2_scid){
+    .pe.index = NGTCP2_PQ_BAD_INDEX,
+    .seq = seq,
+    .cid = *cid,
+    .retired_ts = UINT64_MAX,
+    .flags = NGTCP2_SCID_FLAG_NONE,
+  };
 }
 
 void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src) {
@@ -72,12 +75,12 @@ void ngtcp2_scid_copy(ngtcp2_scid *dest,
 }
 
 void ngtcp2_dcid_init(ngtcp2_dcid *dcid, uint64_t seq, const ngtcp2_cid *cid,
-                      const uint8_t *token) {
+                      const ngtcp2_stateless_reset_token *token) {
   dcid->seq = seq;
   dcid->cid = *cid;
 
   if (token) {
-    memcpy(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN);
+    dcid->token = *token;
     dcid->flags = NGTCP2_DCID_FLAG_TOKEN_PRESENT;
   } else {
     dcid->flags = NGTCP2_DCID_FLAG_NONE;
@@ -91,11 +94,12 @@ void ngtcp2_dcid_init(ngtcp2_dcid *dcid,
   dcid->max_udp_payload_size = NGTCP2_MAX_UDP_PAYLOAD_SIZE;
 }
 
-void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid, const uint8_t *token) {
+void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid,
+                           const ngtcp2_stateless_reset_token *token) {
   assert(token);
 
   dcid->flags |= NGTCP2_DCID_FLAG_TOKEN_PRESENT;
-  memcpy(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN);
+  dcid->token = *token;
 }
 
 void ngtcp2_dcid_set_path(ngtcp2_dcid *dcid, const ngtcp2_path *path) {
@@ -104,7 +108,7 @@ void ngtcp2_dcid_set_path(ngtcp2_dcid *d
 
 void ngtcp2_dcid_copy(ngtcp2_dcid *dest, const ngtcp2_dcid *src) {
   ngtcp2_dcid_init(dest, src->seq, &src->cid,
-                   (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? src->token
+                   (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? &src->token
                                                                  : NULL);
   ngtcp2_path_copy(&dest->ps.path, &src->ps.path);
   dest->retired_ts = src->retired_ts;
@@ -121,18 +125,19 @@ void ngtcp2_dcid_copy_cid_token(ngtcp2_d
 
   if (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) {
     dest->flags |= NGTCP2_DCID_FLAG_TOKEN_PRESENT;
-    memcpy(dest->token, src->token, NGTCP2_STATELESS_RESET_TOKENLEN);
+    dest->token = src->token;
   } else if (dest->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) {
     dest->flags &= (uint8_t)~NGTCP2_DCID_FLAG_TOKEN_PRESENT;
   }
 }
 
 int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq,
-                                  const ngtcp2_cid *cid, const uint8_t *token) {
+                                  const ngtcp2_cid *cid,
+                                  const ngtcp2_stateless_reset_token *token) {
   if (dcid->seq == seq) {
     return ngtcp2_cid_eq(&dcid->cid, cid) &&
                (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) &&
-               memcmp(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN) == 0
+               ngtcp2_stateless_reset_token_eq(&dcid->token, token)
              ? 0
              : NGTCP2_ERR_PROTO;
   }
@@ -140,12 +145,12 @@ int ngtcp2_dcid_verify_uniqueness(const
   return !ngtcp2_cid_eq(&dcid->cid, cid) ? 0 : NGTCP2_ERR_PROTO;
 }
 
-int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
-                                             const ngtcp2_path *path,
-                                             const uint8_t *token) {
+int ngtcp2_dcid_verify_stateless_reset_token(
+  const ngtcp2_dcid *dcid, const ngtcp2_path *path,
+  const ngtcp2_stateless_reset_token *token) {
   return ngtcp2_path_eq(&dcid->ps.path, path) &&
              (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) &&
-             ngtcp2_cmemeq(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN)
+             ngtcp2_cmemeq(dcid->token.data, token->data, sizeof(token->data))
            ? 0
            : NGTCP2_ERR_INVALID_ARGUMENT;
 }
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_cid.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_cid.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_cid.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_cid.h	2026-05-15 15:49:15.156978400 +0200
@@ -35,13 +35,13 @@
 #include "ngtcp2_path.h"
 
 /* NGTCP2_SCID_FLAG_NONE indicates that no flag is set. */
-#define NGTCP2_SCID_FLAG_NONE 0x00u
+#define NGTCP2_SCID_FLAG_NONE 0x00U
 /* NGTCP2_SCID_FLAG_USED indicates that a local endpoint observed that
    a remote endpoint uses this particular Connection ID. */
-#define NGTCP2_SCID_FLAG_USED 0x01u
+#define NGTCP2_SCID_FLAG_USED 0x01U
 /* NGTCP2_SCID_FLAG_RETIRED indicates that this particular Connection
    ID is retired. */
-#define NGTCP2_SCID_FLAG_RETIRED 0x02u
+#define NGTCP2_SCID_FLAG_RETIRED 0x02U
 
 typedef struct ngtcp2_scid {
   ngtcp2_pq_entry pe;
@@ -57,13 +57,13 @@ typedef struct ngtcp2_scid {
 } ngtcp2_scid;
 
 /* NGTCP2_DCID_FLAG_NONE indicates that no flag is set. */
-#define NGTCP2_DCID_FLAG_NONE 0x00u
+#define NGTCP2_DCID_FLAG_NONE 0x00U
 /* NGTCP2_DCID_FLAG_PATH_VALIDATED indicates that an associated path
    has been validated. */
-#define NGTCP2_DCID_FLAG_PATH_VALIDATED 0x01u
+#define NGTCP2_DCID_FLAG_PATH_VALIDATED 0x01U
 /* NGTCP2_DCID_FLAG_TOKEN_PRESENT indicates that a stateless reset
    token is set in token field. */
-#define NGTCP2_DCID_FLAG_TOKEN_PRESENT 0x02u
+#define NGTCP2_DCID_FLAG_TOKEN_PRESENT 0x02U
 
 typedef struct ngtcp2_dcid {
   /* seq is the sequence number associated to the Connection ID. */
@@ -93,7 +93,7 @@ typedef struct ngtcp2_dcid {
   /* token is a stateless reset token received along with this
      Connection ID.  The stateless reset token is tied to the
      connection, not to the particular Connection ID. */
-  uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN];
+  ngtcp2_stateless_reset_token token;
 } ngtcp2_dcid;
 
 /* ngtcp2_cid_zero makes |cid| zero-length. */
@@ -123,17 +123,18 @@ void ngtcp2_scid_copy(ngtcp2_scid *dest,
 
 /*
  * ngtcp2_dcid_init initializes |dcid| with the given parameters.  If
- * |token| is NULL, the function fills dcid->token with 0.  |token|
- * must be NGTCP2_STATELESS_RESET_TOKENLEN bytes long.
+ * |token| is not NULL, the function sets
+ * NGTCP2_DCID_FLAG_TOKEN_PRESENT flag.
  */
 void ngtcp2_dcid_init(ngtcp2_dcid *dcid, uint64_t seq, const ngtcp2_cid *cid,
-                      const uint8_t *token);
+                      const ngtcp2_stateless_reset_token *token);
 
 /*
  * ngtcp2_dcid_set_token sets |token| to |dcid|.  |token| must not be
- * NULL, and must be NGTCP2_STATELESS_RESET_TOKENLEN bytes long.
+ * NULL.
  */
-void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid, const uint8_t *token);
+void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid,
+                           const ngtcp2_stateless_reset_token *token);
 
 /*
  * ngtcp2_dcid_set_path sets |path| to |dcid|.  It sets
@@ -160,7 +161,8 @@ void ngtcp2_dcid_copy_cid_token(ngtcp2_d
  * |token|) tuple against |dcid|.
  */
 int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq,
-                                  const ngtcp2_cid *cid, const uint8_t *token);
+                                  const ngtcp2_cid *cid,
+                                  const ngtcp2_stateless_reset_token *token);
 
 /*
  * ngtcp2_dcid_verify_stateless_reset_token verifies stateless reset
@@ -172,9 +174,9 @@ int ngtcp2_dcid_verify_uniqueness(const
  * NGTCP2_ERR_INVALID_ARGUMENT
  *     Tokens do not match; or |dcid| does not contain a token.
  */
-int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
-                                             const ngtcp2_path *path,
-                                             const uint8_t *token);
+int ngtcp2_dcid_verify_stateless_reset_token(
+  const ngtcp2_dcid *dcid, const ngtcp2_path *path,
+  const ngtcp2_stateless_reset_token *token);
 
 /* TODO It might be performance win if we store congestion state in
    this entry, and restore it when migrate back to this path. */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conn.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conn.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conn.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conn.c	2026-05-15 15:49:15.160978300 +0200
@@ -39,8 +39,10 @@
 #include "ngtcp2_net.h"
 #include "ngtcp2_transport_params.h"
 #include "ngtcp2_settings.h"
+#include "ngtcp2_callbacks.h"
 #include "ngtcp2_tstamp.h"
 #include "ngtcp2_frame_chain.h"
+#include "ngtcp2_conn_info.h"
 
 /* NGTCP2_FLOW_WINDOW_RTT_FACTOR is the factor of RTT when flow
    control window auto-tuning is triggered. */
@@ -253,13 +255,20 @@ static int conn_call_extend_max_local_st
 }
 
 static int conn_call_get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid,
-                                           uint8_t *token, size_t cidlen) {
+                                           ngtcp2_stateless_reset_token *token,
+                                           size_t cidlen) {
   int rv;
 
-  assert(conn->callbacks.get_new_connection_id);
+  if (conn->callbacks.get_new_connection_id2) {
+    rv = conn->callbacks.get_new_connection_id2(conn, cid, token, cidlen,
+                                                conn->user_data);
+  } else {
+    assert(conn->callbacks.get_new_connection_id);
+
+    rv = conn->callbacks.get_new_connection_id(conn, cid, token->data, cidlen,
+                                               conn->user_data);
+  }
 
-  rv = conn->callbacks.get_new_connection_id(conn, cid, token, cidlen,
-                                             conn->user_data);
   if (rv != 0) {
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
@@ -283,11 +292,38 @@ static int conn_call_remove_connection_i
   return 0;
 }
 
+static int conn_call_begin_path_validation(ngtcp2_conn *conn,
+                                           const ngtcp2_pv *pv) {
+  int rv;
+  uint32_t flags = NGTCP2_PATH_VALIDATION_FLAG_NONE;
+  const ngtcp2_path *fallback_path = NULL;
+
+  if (!pv || !conn->callbacks.begin_path_validation) {
+    return 0;
+  }
+
+  if (pv->flags & NGTCP2_PV_FLAG_PREFERRED_ADDR) {
+    flags |= NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR;
+  }
+
+  if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT) {
+    fallback_path = &pv->fallback_dcid.ps.path;
+  }
+
+  rv = conn->callbacks.begin_path_validation(conn, flags, &pv->dcid.ps.path,
+                                             fallback_path, conn->user_data);
+  if (rv != 0) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
 static int conn_call_path_validation(ngtcp2_conn *conn, const ngtcp2_pv *pv,
                                      ngtcp2_path_validation_result res) {
   int rv;
   uint32_t flags = NGTCP2_PATH_VALIDATION_FLAG_NONE;
-  const ngtcp2_path *old_path = NULL;
+  const ngtcp2_path *fallback_path = NULL;
 
   if (!conn->callbacks.path_validation) {
     return 0;
@@ -298,17 +334,17 @@ static int conn_call_path_validation(ngt
   }
 
   if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT) {
-    old_path = &pv->fallback_dcid.ps.path;
+    fallback_path = &pv->fallback_dcid.ps.path;
   }
 
-  if (conn->server && old_path &&
-      (ngtcp2_addr_cmp(&pv->dcid.ps.path.remote, &old_path->remote) &
+  if (conn->server && fallback_path &&
+      (ngtcp2_addr_cmp(&pv->dcid.ps.path.remote, &fallback_path->remote) &
        (NGTCP2_ADDR_CMP_FLAG_ADDR | NGTCP2_ADDR_CMP_FLAG_FAMILY))) {
     flags |= NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN;
   }
 
-  rv = conn->callbacks.path_validation(conn, flags, &pv->dcid.ps.path, old_path,
-                                       res, conn->user_data);
+  rv = conn->callbacks.path_validation(conn, flags, &pv->dcid.ps.path,
+                                       fallback_path, res, conn->user_data);
   if (rv != 0) {
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
@@ -395,14 +431,20 @@ static int conn_call_dcid_status(ngtcp2_
                                  const ngtcp2_dcid *dcid) {
   int rv;
 
-  if (!conn->callbacks.dcid_status) {
+  if (conn->callbacks.dcid_status2) {
+    rv = conn->callbacks.dcid_status2(
+      conn, type, dcid->seq, &dcid->cid,
+      (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? &dcid->token : NULL,
+      conn->user_data);
+  } else if (conn->callbacks.dcid_status) {
+    rv = conn->callbacks.dcid_status(
+      conn, type, dcid->seq, &dcid->cid,
+      (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? dcid->token.data : NULL,
+      conn->user_data);
+  } else {
     return 0;
   }
 
-  rv = conn->callbacks.dcid_status(
-    conn, type, dcid->seq, &dcid->cid,
-    (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? dcid->token : NULL,
-    conn->user_data);
   if (rv != 0) {
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
@@ -475,12 +517,19 @@ static int conn_call_client_initial(ngtc
   return 0;
 }
 
-static int conn_call_get_path_challenge_data(ngtcp2_conn *conn, uint8_t *data) {
+static int conn_call_get_path_challenge_data(ngtcp2_conn *conn,
+                                             ngtcp2_path_challenge_data *data) {
   int rv;
 
-  assert(conn->callbacks.get_path_challenge_data);
+  if (conn->callbacks.get_path_challenge_data2) {
+    rv = conn->callbacks.get_path_challenge_data2(conn, data, conn->user_data);
+  } else {
+    assert(conn->callbacks.get_path_challenge_data);
+
+    rv = conn->callbacks.get_path_challenge_data(conn, data->data,
+                                                 conn->user_data);
+  }
 
-  rv = conn->callbacks.get_path_challenge_data(conn, data, conn->user_data);
   if (rv != 0) {
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
@@ -521,14 +570,24 @@ static int conn_call_recv_retry(ngtcp2_c
 
 static int
 conn_call_recv_stateless_reset(ngtcp2_conn *conn,
-                               const ngtcp2_pkt_stateless_reset *sr) {
+                               const ngtcp2_pkt_stateless_reset2 *sr) {
   int rv;
+  ngtcp2_pkt_stateless_reset legacy_sr;
+
+  if (conn->callbacks.recv_stateless_reset2) {
+    rv = conn->callbacks.recv_stateless_reset2(conn, sr, conn->user_data);
+  } else if (conn->callbacks.recv_stateless_reset) {
+    memcpy(legacy_sr.stateless_reset_token, sr->token.data,
+           sizeof(legacy_sr.stateless_reset_token));
+    legacy_sr.rand = sr->rand;
+    legacy_sr.randlen = sr->randlen;
 
-  if (!conn->callbacks.recv_stateless_reset) {
+    rv =
+      conn->callbacks.recv_stateless_reset(conn, &legacy_sr, conn->user_data);
+  } else {
     return 0;
   }
 
-  rv = conn->callbacks.recv_stateless_reset(conn, sr, conn->user_data);
   if (rv != 0) {
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
@@ -668,13 +727,15 @@ static int conn_call_recv_tx_key(ngtcp2_
   return 0;
 }
 
+/*
+ * pktns_init initializes |pktns|.  It assumes that the object pointed
+ * by |pktns| is zero-cleared.
+ */
 static void pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id,
                        ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num,
                        ngtcp2_log *log, ngtcp2_qlog *qlog,
                        ngtcp2_objalloc *rtb_entry_objalloc,
                        ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) {
-  memset(pktns, 0, sizeof(*pktns));
-
   ngtcp2_gaptr_init(&pktns->rx.pngap, mem);
 
   pktns->tx.last_pkt_num = initial_pkt_num - 1;
@@ -696,7 +757,7 @@ static int pktns_new(ngtcp2_pktns **ppkt
                      ngtcp2_log *log, ngtcp2_qlog *qlog,
                      ngtcp2_objalloc *rtb_entry_objalloc,
                      ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) {
-  *ppktns = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_pktns));
+  *ppktns = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_pktns));
   if (*ppktns == NULL) {
     return NGTCP2_ERR_NOMEM;
   }
@@ -809,8 +870,8 @@ static void conn_reset_conn_stat_cc(ngtc
  */
 static void reset_conn_stat_recovery(ngtcp2_conn_stat *cstat) {
   /* Initializes them with UINT64_MAX. */
-  memset(cstat->loss_time, 0xff, sizeof(cstat->loss_time));
-  memset(cstat->last_tx_pkt_ts, 0xff, sizeof(cstat->last_tx_pkt_ts));
+  memset(cstat->loss_time, 0xFF, sizeof(cstat->loss_time));
+  memset(cstat->last_tx_pkt_ts, 0xFF, sizeof(cstat->last_tx_pkt_ts));
 }
 
 /*
@@ -1033,16 +1094,31 @@ conn_set_local_transport_params(ngtcp2_c
 }
 
 static void conn_update_skip_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns) {
-  uint8_t gap;
+  const int64_t min_gap = 3;
+  uint8_t r;
+  int64_t gap;
 
-  conn->callbacks.rand(&gap, 1, &conn->local.settings.rand_ctx);
+  assert(INT64_MAX != pktns->tx.skip_pkt.next_pkt_num);
 
-  pktns->tx.skip_pkt.next_pkt_num =
-    pktns->tx.last_pkt_num + 3 +
-    (int64_t)gap * (1ll << pktns->tx.skip_pkt.exponent++);
+  conn->callbacks.rand(&r, 1, &conn->local.settings.rand_ctx);
 
-  ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "next skip pkn=%" PRId64,
-                  pktns->tx.skip_pkt.next_pkt_num);
+  if (1LL << pktns->tx.skip_pkt.exponent >
+      (NGTCP2_MAX_PKT_NUM - min_gap) / ((int64_t)r + 1)) {
+    pktns->tx.skip_pkt.next_pkt_num = INT64_MAX;
+    return;
+  }
+
+  gap = ((int64_t)r + 1) * (1LL << pktns->tx.skip_pkt.exponent++) + min_gap;
+
+  if (pktns->tx.last_pkt_num > NGTCP2_MAX_PKT_NUM - gap) {
+    pktns->tx.skip_pkt.next_pkt_num = INT64_MAX;
+    return;
+  }
+
+  pktns->tx.skip_pkt.next_pkt_num = pktns->tx.last_pkt_num + gap;
+
+  ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "next skip pkn=%" PRId64,
+                   pktns->tx.skip_pkt.next_pkt_num);
 }
 
 static int conn_handle_skip_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
@@ -1109,18 +1185,21 @@ static int conn_new(ngtcp2_conn **pconn,
   uint32_t *preferred_versions;
   ngtcp2_settings settingsbuf;
   ngtcp2_transport_params paramsbuf;
-  (void)callbacks_version;
+  ngtcp2_callbacks callbacksbuf;
+  uint64_t seed;
   (void)settings_version;
 
   settings =
     ngtcp2_settings_convert_to_latest(&settingsbuf, settings_version, settings);
   params = ngtcp2_transport_params_convert_to_latest(
     &paramsbuf, transport_params_version, params);
+  callbacks = ngtcp2_callbacks_convert_to_latest(&callbacksbuf,
+                                                 callbacks_version, callbacks);
 
   assert(settings->max_window <= NGTCP2_MAX_VARINT);
   assert(settings->max_stream_window <= NGTCP2_MAX_VARINT);
-  assert(settings->max_tx_udp_payload_size);
-  assert(settings->max_tx_udp_payload_size <= NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE);
+  assert(settings->max_tx_udp_payload_size >= NGTCP2_MAX_UDP_PAYLOAD_SIZE);
+  assert(settings->max_tx_udp_payload_size <= NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE);
   assert(settings->initial_pkt_num <= INT32_MAX);
   assert(settings->initial_rtt);
   assert(params->active_connection_id_limit >=
@@ -1147,15 +1226,17 @@ static int conn_new(ngtcp2_conn **pconn,
   assert(callbacks->hp_mask);
   assert(server || callbacks->recv_retry);
   assert(callbacks->rand);
-  assert(callbacks->get_new_connection_id);
+  assert(callbacks->get_new_connection_id2 || callbacks->get_new_connection_id);
   assert(callbacks->update_key);
   assert(callbacks->delete_crypto_aead_ctx);
   assert(callbacks->delete_crypto_cipher_ctx);
-  assert(callbacks->get_path_challenge_data);
+  assert(callbacks->get_path_challenge_data2 ||
+         callbacks->get_path_challenge_data);
   assert(!server || !ngtcp2_is_reserved_version(client_chosen_version));
 
   for (i = 0; i < settings->pmtud_probeslen; ++i) {
     assert(settings->pmtud_probes[i] > NGTCP2_MAX_UDP_PAYLOAD_SIZE);
+    assert(settings->pmtud_probes[i] <= NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE);
   }
 
   if (mem == NULL) {
@@ -1217,7 +1298,11 @@ static int conn_new(ngtcp2_conn **pconn,
 
   ngtcp2_pq_init(&(*pconn)->scid.used, retired_ts_less, mem);
 
-  ngtcp2_map_init(&(*pconn)->strms, mem);
+  callbacks->rand((uint8_t *)&seed, sizeof(seed), &settings->rand_ctx);
+  ngtcp2_map_init(&(*pconn)->strms, seed, mem);
+
+  callbacks->rand((uint8_t *)&seed, sizeof(seed), &settings->rand_ctx);
+  ngtcp2_pcg32_init(&(*pconn)->pcg, seed);
 
   ngtcp2_pq_init(&(*pconn)->tx.strmq, cycle_less, mem);
 
@@ -1284,17 +1369,17 @@ static int conn_new(ngtcp2_conn **pconn,
 
   switch (settings->cc_algo) {
   case NGTCP2_CC_ALGO_RENO:
-    ngtcp2_cc_reno_init(&(*pconn)->reno, &(*pconn)->log);
+    ngtcp2_cc_reno_init(&(*pconn)->reno, &(*pconn)->log, &(*pconn)->cstat);
 
     break;
   case NGTCP2_CC_ALGO_CUBIC:
-    ngtcp2_cc_cubic_init(&(*pconn)->cubic, &(*pconn)->log, &(*pconn)->rst);
+    ngtcp2_cc_cubic_init(&(*pconn)->cubic, &(*pconn)->log, &(*pconn)->cstat,
+                         &(*pconn)->rst);
 
     break;
   case NGTCP2_CC_ALGO_BBR:
     ngtcp2_cc_bbr_init(&(*pconn)->bbr, &(*pconn)->log, &(*pconn)->cstat,
-                       &(*pconn)->rst, settings->initial_ts, callbacks->rand,
-                       &settings->rand_ctx);
+                       &(*pconn)->rst, settings->initial_ts, &(*pconn)->pcg);
 
     break;
   default:
@@ -1303,6 +1388,9 @@ static int conn_new(ngtcp2_conn **pconn,
 
   ngtcp2_static_ringbuf_path_history_init(&(*pconn)->path_history);
 
+  ngtcp2_ratelim_init(&(*pconn)->glitch_rlim, settings->glitch_ratelim_burst,
+                      settings->glitch_ratelim_rate, settings->initial_ts);
+
   (*pconn)->callbacks = *callbacks;
 
   rv = pktns_new(&(*pconn)->in_pktns, NGTCP2_PKTNS_ID_INITIAL, &(*pconn)->rst,
@@ -1470,6 +1558,8 @@ fail_seqgap_push:
 fail_token:
   ngtcp2_mem_free(mem, *pconn);
 
+  *pconn = NULL;
+
   return rv;
 }
 
@@ -1492,10 +1582,13 @@ int ngtcp2_conn_client_new_versioned(
   (*pconn)->state = NGTCP2_CS_CLIENT_INITIAL;
   (*pconn)->local.bidi.next_stream_id = 0;
   (*pconn)->local.uni.next_stream_id = 2;
+  (*pconn)->flags |= NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO;
 
   rv = ngtcp2_conn_commit_local_transport_params(*pconn);
   if (rv != 0) {
     ngtcp2_conn_del(*pconn);
+    *pconn = NULL;
+
     return rv;
   }
 
@@ -1753,8 +1846,18 @@ static int conn_ppe_write_frame(ngtcp2_c
 static int conn_on_pkt_sent(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
                             ngtcp2_rtb_entry *ent) {
   ngtcp2_rtb *rtb = &pktns->rtb;
+  ngtcp2_cc_pkt cc_pkt;
   int rv;
 
+  if ((ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
+      conn->cc.on_pkt_sent) {
+    conn->cc.on_pkt_sent(
+      &conn->cc, &conn->cstat,
+      ngtcp2_cc_pkt_init(&cc_pkt, ent->hd.pkt_num, ent->pktlen, pktns->id,
+                         ent->ts, /* lost = */ 0,
+                         /* tx_in_flight = */ 0, /* is_app_limited = */ 0));
+  }
+
   /* This function implements OnPacketSent, but it handles only
      non-ACK-only packet. */
   rv = ngtcp2_rtb_add(rtb, ent, &conn->cstat);
@@ -1788,13 +1891,13 @@ static size_t pktns_select_pkt_numlen(ng
 
   n = n * 2 - 1;
 
-  if (n > 0xffffff) {
+  if (n > 0xFFFFFF) {
     return 4;
   }
-  if (n > 0xffff) {
+  if (n > 0xFFFF) {
     return 3;
   }
-  if (n > 0xff) {
+  if (n > 0xFF) {
     return 2;
   }
   return 1;
@@ -1809,9 +1912,9 @@ static int conn_cwnd_is_zero(ngtcp2_conn
   uint64_t cwnd = conn->cstat.cwnd;
 
   if (bytes_in_flight >= cwnd) {
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
-                    "cwnd limited bytes_in_flight=%lu cwnd=%lu",
-                    bytes_in_flight, cwnd);
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC,
+                     "cwnd limited bytes_in_flight=%lu cwnd=%lu",
+                     bytes_in_flight, cwnd);
   }
 
   return bytes_in_flight >= cwnd;
@@ -1902,6 +2005,16 @@ static int conn_verify_dcid(ngtcp2_conn
   return 0;
 }
 
+static int conn_can_send_next_pkt(ngtcp2_conn *conn, size_t left,
+                                  uint64_t min_payloadlen) {
+  /* TODO the next packet type should be taken into account */
+  return left >=
+         /* TODO Assuming that pkt_num is encoded in 1 byte. */
+         NGTCP2_MIN_LONG_HEADERLEN + conn->dcid.current.cid.datalen +
+           conn->oscid.datalen + NGTCP2_PKT_LENGTHLEN - 1 + min_payloadlen +
+           NGTCP2_MAX_AEAD_OVERHEAD;
+}
+
 /*
  * conn_should_pad_pkt returns nonzero if the packet should be padded.
  * |type| is the type of packet.  |left| is the space left in packet
@@ -1948,26 +2061,30 @@ static int conn_should_pad_pkt(ngtcp2_co
         return 1;
       }
     }
-  } else {
-    assert(type == NGTCP2_PKT_HANDSHAKE);
 
-    if (!require_padding) {
-      return 0;
-    }
+    return !conn_can_send_next_pkt(conn, left, min_payloadlen);
+  }
 
-    if (!conn->pktns.crypto.tx.ckm) {
-      return 1;
-    }
+  assert(type == NGTCP2_PKT_HANDSHAKE);
 
-    min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN;
+  if (!require_padding) {
+    /* If we have 1RTT key, pad this Handshake packet so that the next
+       1RTT packet can be squeezed into the same GSO buffer. */
+    return conn->pktns.crypto.tx.ckm &&
+           !conn_can_send_next_pkt(conn, left, NGTCP2_MIN_COALESCED_PAYLOADLEN);
   }
 
-  /* TODO the next packet type should be taken into account */
-  return left <
-         /* TODO Assuming that pkt_num is encoded in 1 byte. */
-         NGTCP2_MIN_LONG_HEADERLEN + conn->dcid.current.cid.datalen +
-           conn->oscid.datalen + NGTCP2_PKT_LENGTHLEN - 1 + min_payloadlen +
-           NGTCP2_MAX_AEAD_OVERHEAD;
+  if (!conn->pktns.crypto.tx.ckm) {
+    return 1;
+  }
+
+  /* We might send Handshake packet even if exceeding CWND.  In that
+     case, we do not write non-probe 1RTT packet. */
+  if (conn_cwnd_is_zero(conn) && conn->pktns.rtb.probe_pkt_left == 0) {
+    return 1;
+  }
+
+  return !conn_can_send_next_pkt(conn, left, NGTCP2_MIN_COALESCED_PAYLOADLEN);
 }
 
 static void conn_restart_timer_on_write(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
@@ -2095,6 +2212,215 @@ static uint8_t conn_pkt_flags_short(ngtc
                                              : NGTCP2_PKT_FLAG_NONE));
 }
 
+/*
+ * conn_cut_crypto_frame splits frc->fr.stream by removing
+ * |removed_data| from frc->fr.stream.data[0].  frc->fr.stream.data[0]
+ * must contain |removed_data|, and frc->fr.stream.datacnt >= 1.  New
+ * ngtcp2_frame_chain object that contains |removed_data| is created,
+ * and pushed to |crypto_strm| via ngtcp2_strm_streamfrq_push.  If
+ * there are data following the removed part of data, new
+ * ngtcp2_frame_chain object is created for it, and frc->next points
+ * to the object.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGTCP2_ERR_NOMEM
+ *     Out of memory
+ */
+static int conn_cut_crypto_frame(ngtcp2_conn *conn, ngtcp2_frame_chain *frc,
+                                 ngtcp2_strm *crypto_strm,
+                                 const ngtcp2_vec *removed_data) {
+  ngtcp2_vec *data = frc->fr.stream.data;
+  size_t datacnt = frc->fr.stream.datacnt;
+  size_t ndatacnt;
+  ngtcp2_frame_chain *right_frc = NULL, *removed_frc;
+  size_t offset;
+  int rv;
+
+  assert(datacnt);
+  assert(data[0].base < removed_data->base);
+  assert(ngtcp2_vec_end(removed_data) <= ngtcp2_vec_end(&data[0]));
+
+  offset = (size_t)(removed_data->base - data->base);
+
+  rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
+    &removed_frc, 1, &conn->frc_objalloc, conn->mem);
+  if (rv != 0) {
+    return rv;
+  }
+
+  /* ngtcp2_frame_chain for the removed data */
+  removed_frc->fr.stream.type = NGTCP2_FRAME_CRYPTO;
+  removed_frc->fr.stream.flags = 0;
+  removed_frc->fr.stream.fin = 0;
+  removed_frc->fr.stream.stream_id = 0;
+  removed_frc->fr.stream.offset = frc->fr.stream.offset + offset;
+  removed_frc->fr.stream.datacnt = 1;
+  removed_frc->fr.stream.data[0] = (ngtcp2_vec){
+    .base = data->base + offset,
+    .len = removed_data->len,
+  };
+
+  rv = ngtcp2_strm_streamfrq_push(crypto_strm, removed_frc);
+  if (rv != 0) {
+    ngtcp2_frame_chain_objalloc_del(removed_frc, &conn->frc_objalloc,
+                                    conn->mem);
+    return rv;
+  }
+
+  if (data[0].len == offset + removed_data->len) {
+    ndatacnt = datacnt - 1;
+  } else {
+    ndatacnt = datacnt;
+  }
+
+  if (ndatacnt) {
+    /* ngtcp2_frame_chain after the removed data */
+    rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
+      &right_frc, ndatacnt, &conn->frc_objalloc, conn->mem);
+    if (rv != 0) {
+      return rv;
+    }
+
+    right_frc->fr.stream.type = NGTCP2_FRAME_CRYPTO;
+    right_frc->fr.stream.offset =
+      removed_frc->fr.stream.offset + removed_frc->fr.stream.data->len;
+    right_frc->fr.stream.datacnt = 0;
+    ngtcp2_vec_split(right_frc->fr.stream.data, &right_frc->fr.stream.datacnt,
+                     data, &datacnt, offset + removed_data->len, ndatacnt);
+
+    assert(ndatacnt == right_frc->fr.stream.datacnt);
+    assert(1 == datacnt);
+  }
+
+  frc->fr.stream.datacnt = 1;
+  frc->fr.stream.data[0].len = offset;
+  frc->next = right_frc;
+
+  return 0;
+}
+
+/*
+ * conn_crumble_initial_crypto splits CRYPTO frame (*pfrc)->fr.stream
+ * into pieces and adds PADDING and PING frames, and reorder those
+ * frames.  Those frames are encoded in the buffer pointed by |data|
+ * and |offsets|.  |data| is the pointer to the array of ngtcp2_vec of
+ * at least NGTCP2_MAX_STREAM_DATACNT.  |offsets| contains the CRYPTO
+ * offset of the corresponding ngtcp2_vec in |data|, and it also
+ * should have the capacity at least NGTCP2_MAX_STREAM_DATACNT
+ * uint64_t.  |left| is the number of bytes available for the current
+ * packet.  |crypto_offset| is the next smallest CRYPTO offset.
+ * |crypto_strm| is the CRYPTO stream.
+ *
+ * This function returns the number of objects written to |data| and
+ * |offsets|, or one of the following negative error codes:
+ *
+ * NGTCP2_ERR_NOMEM
+ *     Out of memory
+ */
+static ngtcp2_ssize
+conn_crumble_initial_crypto(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc,
+                            ngtcp2_vec *data, uint64_t *offsets,
+                            ngtcp2_strm *crypto_strm, size_t left,
+                            uint64_t crypto_offset) {
+  ngtcp2_vec server_name;
+  ngtcp2_vec removed_data;
+  size_t max_add_frames = 10;
+  size_t single_crypto_overhead =
+    1 + ngtcp2_put_uvarintlen(crypto_offset + left - 1) +
+    ngtcp2_put_uvarintlen(left);
+  size_t total_crypto_overhead = single_crypto_overhead * max_add_frames;
+  size_t datacnt;
+  size_t i;
+  int rv;
+
+  if (left <= total_crypto_overhead) {
+    return 0;
+  }
+
+  left -= total_crypto_overhead;
+
+  left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left);
+  if (left == (size_t)-1) {
+    return 0;
+  }
+
+  rv = ngtcp2_strm_streamfrq_pop(crypto_strm, pfrc, left);
+  if (rv != 0) {
+    assert(ngtcp2_err_is_fatal(rv));
+    return rv;
+  }
+
+  if (*pfrc == NULL) {
+    return 0;
+  }
+
+  assert(crypto_offset == (*pfrc)->fr.stream.offset);
+
+  ngtcp2_vec_copy(data, (*pfrc)->fr.stream.data, (*pfrc)->fr.stream.datacnt);
+  datacnt = (*pfrc)->fr.stream.datacnt;
+
+  offsets[0] = (*pfrc)->fr.stream.offset;
+
+  for (i = 1; i < datacnt; ++i) {
+    offsets[i] = offsets[i - 1] + data[i - 1].len;
+  }
+
+  if (datacnt < NGTCP2_MAX_STREAM_DATACNT &&
+      ngtcp2_pkt_find_server_name(&server_name, data) && server_name.len > 1) {
+    if (ngtcp2_strm_streamfrq_empty(crypto_strm) ||
+        ngtcp2_strm_streamfrq_unacked_offset(crypto_strm) == (uint64_t)-1) {
+      datacnt = ngtcp2_pkt_split_vec_at(
+        data, datacnt, offsets,
+        (size_t)(server_name.base - data[0].base) + server_name.len / 2);
+    } else {
+      /* If we have another data to send (most likely in the another
+         packet), remove the part of SNI from this packet. */
+      datacnt = ngtcp2_pkt_remove_vec_partial(
+        &removed_data, data, datacnt, offsets, &conn->pcg, &server_name);
+
+      rv = conn_cut_crypto_frame(conn, *pfrc, crypto_strm, &removed_data);
+      if (rv != 0) {
+        ngtcp2_frame_chain_objalloc_del(*pfrc, &conn->frc_objalloc, conn->mem);
+        return rv;
+      }
+
+      /* Add the length of removed data to total_crypto_overhead so
+         that we can use them for inter CRYPTO frames padding. */
+      total_crypto_overhead += removed_data.len;
+    }
+  }
+
+  if (datacnt < max_add_frames + 1) {
+    max_add_frames -= datacnt - 1;
+
+    datacnt = ngtcp2_pkt_split_vec_rand(data, datacnt, offsets, &conn->pcg,
+                                        max_add_frames);
+  }
+
+  for (i = 1; i < datacnt; ++i) {
+    total_crypto_overhead -= 1 + ngtcp2_put_uvarintlen(offsets[i]) +
+                             ngtcp2_put_uvarintlen(data[i].len);
+  }
+
+  datacnt = ngtcp2_pkt_append_ping_and_padding(data, datacnt, &conn->pcg,
+                                               total_crypto_overhead);
+
+  ngtcp2_pkt_permutate_vec(data, datacnt, offsets, &conn->pcg);
+
+  return (ngtcp2_ssize)datacnt;
+}
+
+static size_t conn_dgram_padding(ngtcp2_conn *conn, ngtcp2_ppe *ppe) {
+  if (conn->local.settings.no_tx_udp_payload_size_shaping) {
+    return ngtcp2_ppe_dgram_padding_size(
+      ppe, conn->local.settings.max_tx_udp_payload_size);
+  }
+
+  return ngtcp2_ppe_dgram_padding(ppe);
+}
+
 static size_t conn_min_pktlen(ngtcp2_conn *conn);
 
 /*
@@ -2125,8 +2451,8 @@ conn_write_handshake_pkt(ngtcp2_conn *co
   ngtcp2_pkt_hd hd;
   ngtcp2_frame_chain *frq = NULL, **pfrc = &frq;
   ngtcp2_frame_chain *nfrc;
-  ngtcp2_max_frame mfr;
-  ngtcp2_frame *ackfr = NULL, lfr;
+  ngtcp2_ack_range ack_ranges[NGTCP2_MAX_ACK_RANGES];
+  ngtcp2_frame lfr;
   ngtcp2_ssize spktlen;
   ngtcp2_crypto_cc cc;
   ngtcp2_rtb_entry *rtbent;
@@ -2201,16 +2527,16 @@ conn_write_handshake_pkt(ngtcp2_conn *co
     return 0;
   }
 
-  ackfr = ngtcp2_acktr_create_ack_frame(&pktns->acktr, &mfr.fr, type, ts,
-                                        /* ack_delay = */ 0,
-                                        NGTCP2_DEFAULT_ACK_DELAY_EXPONENT);
-  if (ackfr) {
-    rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, ackfr);
+  lfr.ack.ranges = ack_ranges;
+  if (ngtcp2_acktr_create_ack_frame(&pktns->acktr, &lfr.ack, type, ts,
+                                    /* ack_delay = */ 0,
+                                    NGTCP2_DEFAULT_ACK_DELAY_EXPONENT) == 0) {
+    rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr);
     if (rv != 0) {
       assert(NGTCP2_ERR_NOBUF == rv);
     } else {
       ngtcp2_acktr_commit_ack(&pktns->acktr);
-      ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, ackfr->ack.largest_ack);
+      ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, lfr.ack.largest_ack);
       pkt_empty = 0;
     }
   }
@@ -2221,38 +2547,94 @@ conn_write_handshake_pkt(ngtcp2_conn *co
       destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
   build_pkt:
     for (; !ngtcp2_strm_streamfrq_empty(&pktns->crypto.strm);) {
-      left = ngtcp2_ppe_left(&ppe);
-
       crypto_offset = ngtcp2_strm_streamfrq_unacked_offset(&pktns->crypto.strm);
       if (crypto_offset == (uint64_t)-1) {
         ngtcp2_strm_streamfrq_clear(&pktns->crypto.strm);
         break;
       }
 
-      left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left);
-      if (left == (size_t)-1) {
+      left = ngtcp2_ppe_left(&ppe);
+      if (left == 0) {
         break;
       }
 
-      rv = ngtcp2_strm_streamfrq_pop(&pktns->crypto.strm, &nfrc, left);
-      if (rv != 0) {
-        assert(ngtcp2_err_is_fatal(rv));
-        ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc,
-                                             conn->mem);
-        return rv;
-      }
+      if (type == NGTCP2_PKT_INITIAL &&
+          (conn->flags & NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO)) {
+        ngtcp2_vec data[NGTCP2_MAX_STREAM_DATACNT];
+        uint64_t offsets[NGTCP2_MAX_STREAM_DATACNT];
+        ngtcp2_ssize datacnt;
+        size_t i;
+
+        datacnt = conn_crumble_initial_crypto(
+          conn, &nfrc, data, offsets, &pktns->crypto.strm, left, crypto_offset);
+        if (datacnt < 0) {
+          assert(ngtcp2_err_is_fatal((int)datacnt));
+          ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc,
+                                               conn->mem);
 
-      if (nfrc == NULL) {
-        break;
-      }
+          return datacnt;
+        }
 
-      rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &nfrc->fr);
-      if (rv != 0) {
-        ngtcp2_unreachable();
+        if (datacnt == 0) {
+          break;
+        }
+
+        for (i = 0; i < (size_t)datacnt; ++i) {
+          if (data[i].base == NULL) {
+            if (data[i].len == 0) {
+              lfr.ping.type = NGTCP2_FRAME_PING;
+            } else {
+              lfr.padding = (ngtcp2_padding){
+                .type = NGTCP2_FRAME_PADDING,
+                .len = data[i].len,
+              };
+            }
+          } else {
+            lfr.stream = (ngtcp2_stream){
+              .type = NGTCP2_FRAME_CRYPTO,
+              .offset = offsets[i],
+              .datacnt = 1,
+              .data = &data[i],
+            };
+          }
+
+          rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr);
+          if (rv != 0) {
+            ngtcp2_unreachable();
+          }
+        }
+      } else {
+        left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left);
+        if (left == (size_t)-1) {
+          break;
+        }
+
+        rv = ngtcp2_strm_streamfrq_pop(&pktns->crypto.strm, &nfrc, left);
+        if (rv != 0) {
+          assert(ngtcp2_err_is_fatal(rv));
+          ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc,
+                                               conn->mem);
+          return rv;
+        }
+
+        if (nfrc == NULL) {
+          break;
+        }
+
+        rv =
+          conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &nfrc->fr);
+        if (rv != 0) {
+          ngtcp2_unreachable();
+        }
       }
 
       *pfrc = nfrc;
-      pfrc = &(*pfrc)->next;
+
+      for (; nfrc->next;) {
+        nfrc = nfrc->next;
+      }
+
+      pfrc = &nfrc->next;
 
       pkt_empty = 0;
       rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING |
@@ -2262,7 +2644,9 @@ conn_write_handshake_pkt(ngtcp2_conn *co
 
     if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
         pktns->rtb.num_retransmittable && pktns->rtb.probe_pkt_left) {
-      num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns, 1);
+      num_reclaimed = ngtcp2_rtb_reclaim_on_pto(
+        &pktns->rtb, conn, pktns,
+        !conn->server && type == NGTCP2_PKT_INITIAL ? 2 : 1);
       if (num_reclaimed < 0) {
         ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc,
                                              conn->mem);
@@ -2289,7 +2673,7 @@ conn_write_handshake_pkt(ngtcp2_conn *co
 
     if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
         pktns->rtb.probe_pkt_left) {
-      lfr.type = NGTCP2_FRAME_PING;
+      lfr.ping.type = NGTCP2_FRAME_PING;
 
       rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr);
       if (rv != 0) {
@@ -2305,7 +2689,7 @@ conn_write_handshake_pkt(ngtcp2_conn *co
       if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
         if (ngtcp2_tstamp_elapsed(pktns->tx.non_ack_pkt_start_ts,
                                   conn->cstat.smoothed_rtt, ts)) {
-          lfr.type = NGTCP2_FRAME_PING;
+          lfr.ping.type = NGTCP2_FRAME_PING;
 
           rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr);
           if (rv != 0) {
@@ -2334,12 +2718,12 @@ conn_write_handshake_pkt(ngtcp2_conn *co
         conn, type, ngtcp2_ppe_left(&ppe), write_datalen,
         (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) != 0,
         require_padding)) {
-    lfr.type = NGTCP2_FRAME_PADDING;
-    lfr.padding.len = ngtcp2_ppe_dgram_padding(&ppe);
+    lfr.padding.type = NGTCP2_FRAME_PADDING;
+    lfr.padding.len = conn_dgram_padding(conn, &ppe);
   } else if (pkt_empty) {
     return 0;
   } else {
-    lfr.type = NGTCP2_FRAME_PADDING;
+    lfr.padding.type = NGTCP2_FRAME_PADDING;
     lfr.padding.len = ngtcp2_ppe_padding_size(&ppe, conn_min_pktlen(conn));
     min_padded = 1;
   }
@@ -2402,6 +2786,9 @@ conn_write_handshake_pkt(ngtcp2_conn *co
 
   conn->tx.pacing.pktlen += (size_t)spktlen;
 
+  ++conn->cstat.pkt_sent;
+  conn->cstat.bytes_sent += (uint64_t)spktlen;
+
   ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
 
   ++pktns->tx.last_pkt_num;
@@ -2425,12 +2812,12 @@ conn_write_handshake_pkt(ngtcp2_conn *co
 static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
                                        uint8_t *dest, size_t destlen,
                                        uint8_t type, ngtcp2_tstamp ts) {
-  ngtcp2_frame *ackfr;
   ngtcp2_pktns *pktns;
   ngtcp2_duration ack_delay;
   uint64_t ack_delay_exponent;
   ngtcp2_ssize spktlen;
-  ngtcp2_max_frame mfr;
+  ngtcp2_ack_range ack_ranges[NGTCP2_MAX_ACK_RANGES];
+  ngtcp2_frame fr;
 
   assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING));
 
@@ -2459,15 +2846,15 @@ static ngtcp2_ssize conn_write_ack_pkt(n
     return 0;
   }
 
-  ackfr = ngtcp2_acktr_create_ack_frame(&pktns->acktr, &mfr.fr, type, ts,
-                                        ack_delay, ack_delay_exponent);
-  if (!ackfr) {
+  fr.ack.ranges = ack_ranges;
+  if (ngtcp2_acktr_create_ack_frame(&pktns->acktr, &fr.ack, type, ts, ack_delay,
+                                    ack_delay_exponent) != 0) {
     return 0;
   }
 
   spktlen = ngtcp2_conn_write_single_frame_pkt(
     conn, pi, dest, destlen, type, NGTCP2_WRITE_PKT_FLAG_NONE,
-    &conn->dcid.current.cid, ackfr, NGTCP2_RTB_ENTRY_FLAG_NONE, NULL, ts);
+    &conn->dcid.current.cid, &fr, NGTCP2_RTB_ENTRY_FLAG_NONE, NULL, ts);
 
   if (spktlen <= 0) {
     return spktlen;
@@ -2540,7 +2927,7 @@ static void conn_discard_early_key(ngtcp
 
   conn_call_delete_crypto_aead_ctx(conn, &conn->early.ckm->aead_ctx);
   conn_call_delete_crypto_cipher_ctx(conn, &conn->early.hp_ctx);
-  memset(&conn->early.hp_ctx, 0, sizeof(conn->early.hp_ctx));
+  conn->early.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
 
   ngtcp2_crypto_km_del(conn->early.ckm, conn->mem);
   conn->early.ckm = NULL;
@@ -2730,21 +3117,16 @@ static ngtcp2_ssize conn_write_handshake
       dest += nwrite;
       destlen -= (size_t)nwrite;
 
-      /* If initial packet size is at least
-         NGTCP2_MAX_UDP_PAYLOAD_SIZE, no extra padding is needed in a
-         subsequent packet. */
-      if (nwrite < NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
-        if (conn->server) {
-          it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
-          if (!ngtcp2_ksl_it_end(&it)) {
-            rtbent = ngtcp2_ksl_it_get(&it);
-            if (rtbent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
-              wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
-            }
+      if (conn->server) {
+        it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
+        if (!ngtcp2_ksl_it_end(&it)) {
+          rtbent = ngtcp2_ksl_it_get(&it);
+          if (rtbent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
+            wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
           }
-        } else {
-          wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
         }
+      } else {
+        wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
       }
     }
   }
@@ -2862,58 +3244,59 @@ static size_t conn_required_num_new_conn
 static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) {
   size_t i, need = conn_required_num_new_connection_id(conn);
   size_t cidlen = conn->oscid.datalen;
-  ngtcp2_cid cid;
-  uint64_t seq;
   int rv;
-  uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN];
   ngtcp2_frame_chain *nfrc;
   ngtcp2_pktns *pktns = &conn->pktns;
   ngtcp2_scid *scid;
   ngtcp2_ksl_it it;
 
   for (i = 0; i < need; ++i) {
-    rv = conn_call_get_new_connection_id(conn, &cid, token, cidlen);
+    rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
     if (rv != 0) {
       return rv;
     }
 
-    if (cid.datalen != cidlen) {
-      return NGTCP2_ERR_CALLBACK_FAILURE;
+    nfrc->fr.new_connection_id.type = NGTCP2_FRAME_NEW_CONNECTION_ID;
+    nfrc->fr.new_connection_id.seq = ++conn->scid.last_seq;
+    nfrc->fr.new_connection_id.retire_prior_to = 0;
+
+    rv = conn_call_get_new_connection_id(conn, &nfrc->fr.new_connection_id.cid,
+                                         &nfrc->fr.new_connection_id.token,
+                                         cidlen);
+    if (rv != 0) {
+      goto fail;
+    }
+
+    if (nfrc->fr.new_connection_id.cid.datalen != cidlen) {
+      rv = NGTCP2_ERR_CALLBACK_FAILURE;
+      goto fail;
     }
 
     /* Assert uniqueness */
-    it = ngtcp2_ksl_lower_bound(&conn->scid.set, &cid);
+    it =
+      ngtcp2_ksl_lower_bound(&conn->scid.set, &nfrc->fr.new_connection_id.cid);
     if (!ngtcp2_ksl_it_end(&it) &&
-        ngtcp2_cid_eq(ngtcp2_ksl_it_key(&it), &cid)) {
-      return NGTCP2_ERR_CALLBACK_FAILURE;
+        ngtcp2_cid_eq(ngtcp2_ksl_it_key(&it),
+                      &nfrc->fr.new_connection_id.cid)) {
+      rv = NGTCP2_ERR_CALLBACK_FAILURE;
+      goto fail;
     }
 
-    seq = ++conn->scid.last_seq;
-
     scid = ngtcp2_mem_malloc(conn->mem, sizeof(*scid));
     if (scid == NULL) {
-      return NGTCP2_ERR_NOMEM;
+      rv = NGTCP2_ERR_NOMEM;
+      goto fail;
     }
 
-    ngtcp2_scid_init(scid, seq, &cid);
+    ngtcp2_scid_init(scid, nfrc->fr.new_connection_id.seq,
+                     &nfrc->fr.new_connection_id.cid);
 
     rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scid->cid, scid);
     if (rv != 0) {
       ngtcp2_mem_free(conn->mem, scid);
-      return rv;
-    }
-
-    rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc);
-    if (rv != 0) {
-      return rv;
+      goto fail;
     }
 
-    nfrc->fr.type = NGTCP2_FRAME_NEW_CONNECTION_ID;
-    nfrc->fr.new_connection_id.seq = seq;
-    nfrc->fr.new_connection_id.retire_prior_to = 0;
-    nfrc->fr.new_connection_id.cid = cid;
-    memcpy(nfrc->fr.new_connection_id.stateless_reset_token, token,
-           sizeof(token));
     nfrc->next = pktns->tx.frq;
     pktns->tx.frq = nfrc;
 
@@ -2923,6 +3306,11 @@ static int conn_enqueue_new_connection_i
   }
 
   return 0;
+
+fail:
+  ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem);
+
+  return rv;
 }
 
 static int dcidtr_on_deactivate(const ngtcp2_dcid *dcid, void *user_data) {
@@ -3082,14 +3470,15 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
   ngtcp2_crypto_cc *cc = &conn->pkt.cc;
   ngtcp2_ppe *ppe = &conn->pkt.ppe;
   ngtcp2_pkt_hd *hd = &conn->pkt.hd;
-  ngtcp2_max_frame mfr;
-  ngtcp2_frame *ackfr = NULL, lfr;
+  ngtcp2_ack_range ack_ranges[NGTCP2_MAX_ACK_RANGES];
+  ngtcp2_frame lfr;
   ngtcp2_ssize nwrite;
   ngtcp2_frame_chain **pfrc, *nfrc, *frc;
   ngtcp2_rtb_entry *ent;
   ngtcp2_strm *strm;
   int pkt_empty = 1;
   uint64_t ndatalen = 0;
+  uint64_t wdatalen;
   int send_stream = 0;
   int stream_blocked = 0;
   int send_datagram = 0;
@@ -3108,11 +3497,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
   size_t min_pktlen = conn_min_pktlen(conn);
   int min_padded = 0;
   int padded = 0;
-  ngtcp2_cc_pkt cc_pkt;
   uint64_t crypto_offset;
   uint64_t stream_offset;
   ngtcp2_ssize num_reclaimed;
-  int fin;
   uint64_t target_max_data;
   ngtcp2_conn_stat *cstat = &conn->cstat;
   uint64_t delta;
@@ -3225,8 +3612,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
 
       conn->tx.last_max_data_ts = ts;
 
-      nfrc->fr.type = NGTCP2_FRAME_MAX_DATA;
-      nfrc->fr.max_data.max_data = conn->rx.unsent_max_offset + delta;
+      nfrc->fr.max_data = (ngtcp2_max_data){
+        .type = NGTCP2_FRAME_MAX_DATA,
+        .max_data = conn->rx.unsent_max_offset + delta,
+      };
       nfrc->next = pktns->tx.frq;
       pktns->tx.frq = nfrc;
 
@@ -3261,9 +3650,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
       /* PATH_RESPONSE is bound to the path that the corresponding
          PATH_CHALLENGE is received. */
       if (ngtcp2_path_eq(&conn->dcid.current.ps.path, &pcent->ps.path)) {
-        lfr.type = NGTCP2_FRAME_PATH_RESPONSE;
-        memcpy(lfr.path_response.data, pcent->data,
-               sizeof(lfr.path_response.data));
+        lfr.path_response = (ngtcp2_path_response){
+          .type = NGTCP2_FRAME_PATH_RESPONSE,
+          .data = pcent->data,
+        };
 
         rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
         if (rv != 0) {
@@ -3282,7 +3672,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
 
              An endpoint that receives a PATH_CHALLENGE on an active
              path SHOULD send a non-probing packet in response. */
-          lfr.type = NGTCP2_FRAME_PING;
+          lfr.ping.type = NGTCP2_FRAME_PING;
           rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
           if (rv != 0) {
             assert(NGTCP2_ERR_NOBUF == rv);
@@ -3291,20 +3681,19 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
       }
     }
 
-    ackfr = ngtcp2_acktr_create_ack_frame(
-      &pktns->acktr, &mfr.fr, type, ts, conn_compute_ack_delay(conn),
-      conn->local.transport_params.ack_delay_exponent);
-    if (ackfr) {
-      rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, ackfr);
+    lfr.ack.ranges = ack_ranges;
+    if (ngtcp2_acktr_create_ack_frame(
+          &pktns->acktr, &lfr.ack, type, ts, conn_compute_ack_delay(conn),
+          conn->local.transport_params.ack_delay_exponent) == 0) {
+      rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
       if (rv != 0) {
         assert(NGTCP2_ERR_NOBUF == rv);
       } else {
         ngtcp2_acktr_commit_ack(&pktns->acktr);
-        ngtcp2_acktr_add_ack(&pktns->acktr, hd->pkt_num,
-                             ackfr->ack.largest_ack);
+        ngtcp2_acktr_add_ack(&pktns->acktr, hd->pkt_num, lfr.ack.largest_ack);
         assert(NGTCP2_PKT_1RTT == type);
-        conn_handle_unconfirmed_key_update_from_remote(
-          conn, ackfr->ack.largest_ack, ts);
+        conn_handle_unconfirmed_key_update_from_remote(conn,
+                                                       lfr.ack.largest_ack, ts);
         pkt_empty = 0;
       }
     }
@@ -3319,7 +3708,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
         continue;
       }
 
-      switch ((*pfrc)->fr.type) {
+      switch ((*pfrc)->fr.hd.type) {
       case NGTCP2_FRAME_RESET_STREAM:
         strm =
           ngtcp2_conn_find_stream(conn, (*pfrc)->fr.reset_stream.stream_id);
@@ -3469,11 +3858,12 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
             return rv;
           }
 
-          nfrc->fr.type = NGTCP2_FRAME_RESET_STREAM;
-          nfrc->fr.reset_stream.stream_id = strm->stream_id;
-          nfrc->fr.reset_stream.app_error_code =
-            strm->tx.reset_stream_app_error_code;
-          nfrc->fr.reset_stream.final_size = strm->tx.offset;
+          nfrc->fr.reset_stream = (ngtcp2_reset_stream){
+            .type = NGTCP2_FRAME_RESET_STREAM,
+            .stream_id = strm->stream_id,
+            .app_error_code = strm->tx.reset_stream_app_error_code,
+            .final_size = strm->tx.offset,
+          };
           *pfrc = nfrc;
 
           strm->flags &= ~NGTCP2_STRM_FLAG_SEND_RESET_STREAM;
@@ -3512,10 +3902,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
               return rv;
             }
 
-            nfrc->fr.type = NGTCP2_FRAME_STOP_SENDING;
-            nfrc->fr.stop_sending.stream_id = strm->stream_id;
-            nfrc->fr.stop_sending.app_error_code =
-              strm->tx.stop_sending_app_error_code;
+            nfrc->fr.stop_sending = (ngtcp2_stop_sending){
+              .type = NGTCP2_FRAME_STOP_SENDING,
+              .stream_id = strm->stream_id,
+              .app_error_code = strm->tx.stop_sending_app_error_code,
+            };
             *pfrc = nfrc;
 
             strm->flags &= ~NGTCP2_STRM_FLAG_SEND_STOP_SENDING;
@@ -3543,9 +3934,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
             return rv;
           }
 
-          nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED;
-          nfrc->fr.stream_data_blocked.stream_id = strm->stream_id;
-          nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset;
+          nfrc->fr.stream_data_blocked = (ngtcp2_stream_data_blocked){
+            .type = NGTCP2_FRAME_STREAM_DATA_BLOCKED,
+            .stream_id = strm->stream_id,
+            .offset = strm->tx.max_offset,
+          };
           *pfrc = nfrc;
 
           strm->tx.last_blocked_offset = strm->tx.max_offset;
@@ -3597,10 +3990,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
 
           strm->tx.last_max_stream_data_ts = ts;
 
-          nfrc->fr.type = NGTCP2_FRAME_MAX_STREAM_DATA;
-          nfrc->fr.max_stream_data.stream_id = strm->stream_id;
-          nfrc->fr.max_stream_data.max_stream_data =
-            strm->rx.unsent_max_offset + delta;
+          nfrc->fr.max_stream_data = (ngtcp2_max_stream_data){
+            .type = NGTCP2_FRAME_MAX_STREAM_DATA,
+            .stream_id = strm->stream_id,
+            .max_stream_data = strm->rx.unsent_max_offset + delta,
+          };
           *pfrc = nfrc;
 
           strm->rx.max_offset = strm->rx.unsent_max_offset =
@@ -3696,8 +4090,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
         assert(ngtcp2_err_is_fatal(rv));
         return rv;
       }
-      nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_BIDI;
-      nfrc->fr.max_streams.max_streams = conn->remote.bidi.unsent_max_streams;
+      nfrc->fr.max_streams = (ngtcp2_max_streams){
+        .type = NGTCP2_FRAME_MAX_STREAMS_BIDI,
+        .max_streams = conn->remote.bidi.unsent_max_streams,
+      };
       *pfrc = nfrc;
 
       conn->remote.bidi.max_streams = conn->remote.bidi.unsent_max_streams;
@@ -3728,8 +4124,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
         assert(ngtcp2_err_is_fatal(rv));
         return rv;
       }
-      nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_UNI;
-      nfrc->fr.max_streams.max_streams = conn->remote.uni.unsent_max_streams;
+      nfrc->fr.max_streams = (ngtcp2_max_streams){
+        .type = NGTCP2_FRAME_MAX_STREAMS_UNI,
+        .max_streams = conn->remote.uni.unsent_max_streams,
+      };
       *pfrc = nfrc;
 
       conn->remote.uni.max_streams = conn->remote.uni.unsent_max_streams;
@@ -3780,10 +4178,12 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
   left = ngtcp2_ppe_left(ppe);
 
   if (*pfrc == NULL && send_stream && ngtcp2_pq_empty(&conn->tx.strmq) &&
-      (ndatalen = ngtcp2_pkt_stream_max_datalen(
+      (wdatalen = ngtcp2_pkt_stream_max_datalen(
          vmsg->stream.strm->stream_id, vmsg->stream.strm->tx.offset, ndatalen,
          left)) != (size_t)-1 &&
-      (ndatalen || datalen == 0)) {
+      (wdatalen == ndatalen || wdatalen >= NGTCP2_MIN_STREAM_DATALEN) &&
+      (wdatalen || datalen == 0)) {
+    ndatalen = wdatalen;
     datacnt = ngtcp2_vec_copy_at_most(data, NGTCP2_MAX_STREAM_DATACNT,
                                       vmsg->stream.data, vmsg->stream.datacnt,
                                       (size_t)ndatalen);
@@ -3800,14 +4200,14 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
 
     nfrc->fr.stream.type = NGTCP2_FRAME_STREAM;
     nfrc->fr.stream.flags = 0;
+    nfrc->fr.stream.fin = 0;
     nfrc->fr.stream.stream_id = vmsg->stream.strm->stream_id;
     nfrc->fr.stream.offset = vmsg->stream.strm->tx.offset;
     nfrc->fr.stream.datacnt = datacnt;
     ngtcp2_vec_copy(nfrc->fr.stream.data, data, datacnt);
 
-    fin = (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_FIN) &&
-          ndatalen == datalen;
-    nfrc->fr.stream.fin = (uint8_t)fin;
+    nfrc->fr.stream.fin = (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_FIN) &&
+                          ndatalen == datalen;
 
     rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
     if (rv != 0) {
@@ -3826,7 +4226,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
     conn->tx.offset += ndatalen;
     vmsg->stream.strm->flags |= NGTCP2_STRM_FLAG_ANY_SENT;
 
-    if (fin) {
+    if (nfrc->fr.stream.fin) {
       ngtcp2_strm_shutdown(vmsg->stream.strm, NGTCP2_STRM_FLAG_SHUT_WR);
     }
 
@@ -3849,8 +4249,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
         return rv;
       }
 
-      nfrc->fr.type = NGTCP2_FRAME_DATA_BLOCKED;
-      nfrc->fr.data_blocked.offset = conn->tx.offset;
+      nfrc->fr.data_blocked = (ngtcp2_data_blocked){
+        .type = NGTCP2_FRAME_DATA_BLOCKED,
+        .offset = conn->tx.offset,
+      };
 
       rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
       if (rv != 0) {
@@ -3881,9 +4283,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
         return rv;
       }
 
-      nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED;
-      nfrc->fr.stream_data_blocked.stream_id = strm->stream_id;
-      nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset;
+      nfrc->fr.stream_data_blocked = (ngtcp2_stream_data_blocked){
+        .type = NGTCP2_FRAME_STREAM_DATA_BLOCKED,
+        .stream_id = strm->stream_id,
+        .offset = strm->tx.max_offset,
+      };
 
       rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
       if (rv != 0) {
@@ -4026,7 +4430,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
     if (ngtcp2_tstamp_elapsed(pktns->tx.non_ack_pkt_start_ts,
                               cstat->smoothed_rtt, ts) ||
         keep_alive_expired || conn->pktns.rtb.probe_pkt_left) {
-      lfr.type = NGTCP2_FRAME_PING;
+      lfr.ping.type = NGTCP2_FRAME_PING;
 
       rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
       if (rv != 0) {
@@ -4041,7 +4445,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
           rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING;
         }
         pktns->tx.non_ack_pkt_start_ts = UINT64_MAX;
-        pkt_empty = 0;
       }
     } else if (pktns->tx.non_ack_pkt_start_ts == UINT64_MAX) {
       pktns->tx.non_ack_pkt_start_ts = ts;
@@ -4056,7 +4459,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
       (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
     lfr.padding.len = ngtcp2_ppe_padding_size(ppe, destlen);
   } else if (require_padding) {
-    lfr.padding.len = ngtcp2_ppe_dgram_padding(ppe);
+    lfr.padding.len = conn_dgram_padding(conn, ppe);
   } else {
     lfr.padding.len = ngtcp2_ppe_padding_size(ppe, min_pktlen);
     min_padded = 1;
@@ -4067,7 +4470,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
         (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
       padded = 1;
     }
-    lfr.type = NGTCP2_FRAME_PADDING;
+    lfr.padding.type = NGTCP2_FRAME_PADDING;
     ngtcp2_log_tx_fr(&conn->log, hd, &lfr);
     ngtcp2_qlog_write_frame(&conn->qlog, &lfr);
   }
@@ -4103,12 +4506,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
       *pfrc = NULL;
     }
 
-    if ((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
-        pktns->rtb.num_ack_eliciting == 0 && conn->cc.event) {
-      conn->cc.event(&conn->cc, &conn->cstat, NGTCP2_CC_EVENT_TYPE_TX_START,
-                     ts);
-    }
-
     rv = conn_on_pkt_sent(conn, pktns, ent);
     if (rv != 0) {
       assert(ngtcp2_err_is_fatal(rv));
@@ -4117,18 +4514,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
       return rv;
     }
 
-    if (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
-      if (conn->cc.on_pkt_sent) {
-        conn->cc.on_pkt_sent(
-          &conn->cc, &conn->cstat,
-          ngtcp2_cc_pkt_init(&cc_pkt, hd->pkt_num, (size_t)nwrite,
-                             NGTCP2_PKTNS_ID_APPLICATION, ts, ent->rst.lost,
-                             ent->rst.tx_in_flight, ent->rst.is_app_limited));
-      }
-
-      if (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE) {
-        conn_restart_timer_on_write(conn, ts);
-      }
+    if ((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
+        (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE)) {
+      conn_restart_timer_on_write(conn, ts);
     }
   } else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) {
     conn_handle_tx_ecn(conn, pi, NULL, pktns, hd, ts);
@@ -4140,8 +4528,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
       (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) {
     --pktns->rtb.probe_pkt_left;
 
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td",
-                    nwrite);
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td",
+                     nwrite);
   }
 
   conn_update_keep_alive_last_ts(conn, ts);
@@ -4150,6 +4538,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp
 
   conn->tx.pacing.pktlen += (size_t)nwrite;
 
+  ++conn->cstat.pkt_sent;
+  conn->cstat.bytes_sent += (uint64_t)nwrite;
+
   ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
 
   ++pktns->tx.last_pkt_num;
@@ -4248,17 +4639,17 @@ ngtcp2_ssize ngtcp2_conn_write_single_fr
     return 0;
   }
 
-  lfr.type = NGTCP2_FRAME_PADDING;
+  lfr.padding.type = NGTCP2_FRAME_PADDING;
   if (flags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL) {
     lfr.padding.len = ngtcp2_ppe_dgram_padding_size(&ppe, destlen);
   } else if (flags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING) {
-    lfr.padding.len = ngtcp2_ppe_dgram_padding(&ppe);
+    lfr.padding.len = conn_dgram_padding(conn, &ppe);
   } else {
-    switch (fr->type) {
+    switch (fr->hd.type) {
     case NGTCP2_FRAME_PATH_CHALLENGE:
     case NGTCP2_FRAME_PATH_RESPONSE:
       if (!conn->server || destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
-        lfr.padding.len = ngtcp2_ppe_dgram_padding(&ppe);
+        lfr.padding.len = conn_dgram_padding(conn, &ppe);
       } else {
         lfr.padding.len = 0;
       }
@@ -4285,7 +4676,7 @@ ngtcp2_ssize ngtcp2_conn_write_single_fr
   ngtcp2_qlog_pkt_sent_end(&conn->qlog, &hd, (size_t)nwrite);
 
   /* Do this when we are sure that there is no error. */
-  switch (fr->type) {
+  switch (fr->hd.type) {
   case NGTCP2_FRAME_ACK:
   case NGTCP2_FRAME_ACK_ECN:
     ngtcp2_acktr_commit_ack(&pktns->acktr);
@@ -4301,6 +4692,13 @@ ngtcp2_ssize ngtcp2_conn_write_single_fr
     }
 
     break;
+  case NGTCP2_FRAME_CONNECTION_CLOSE:
+  case NGTCP2_FRAME_CONNECTION_CLOSE_APP:
+    /* Clear padded so that we never store the terminal packet in
+       ngtcp2_rtb. */
+    padded = 0;
+
+    break;
   }
 
   if (((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) || padded) &&
@@ -4333,8 +4731,8 @@ ngtcp2_ssize ngtcp2_conn_write_single_fr
           ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
         --pktns->rtb.probe_pkt_left;
 
-        ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td",
-                        nwrite);
+        ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td",
+                         nwrite);
       }
     }
   } else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) {
@@ -4346,7 +4744,7 @@ ngtcp2_ssize ngtcp2_conn_write_single_fr
   }
 
   if (!padded) {
-    switch (fr->type) {
+    switch (fr->hd.type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
       break;
@@ -4357,6 +4755,9 @@ ngtcp2_ssize ngtcp2_conn_write_single_fr
     conn->tx.pacing.pktlen += (size_t)nwrite;
   }
 
+  ++conn->cstat.pkt_sent;
+  conn->cstat.bytes_sent += (uint64_t)nwrite;
+
   ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat);
 
   ++pktns->tx.last_pkt_num;
@@ -4423,8 +4824,10 @@ static int conn_enqueue_retire_connectio
     return rv;
   }
 
-  nfrc->fr.type = NGTCP2_FRAME_RETIRE_CONNECTION_ID;
-  nfrc->fr.retire_connection_id.seq = seq;
+  nfrc->fr.retire_connection_id = (ngtcp2_retire_connection_id){
+    .type = NGTCP2_FRAME_RETIRE_CONNECTION_ID,
+    .seq = seq,
+  };
   nfrc->next = pktns->tx.frq;
   pktns->tx.frq = nfrc;
 
@@ -4563,10 +4966,10 @@ static ngtcp2_ssize conn_write_pmtud_pro
     return 0;
   }
 
-  ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
-                  "sending PMTUD probe packet len=%zu", probelen);
+  ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
+                   "sending PMTUD probe packet len=%zu", probelen);
 
-  lfr.type = NGTCP2_FRAME_PING;
+  lfr.ping.type = NGTCP2_FRAME_PING;
 
   nwrite = ngtcp2_conn_write_single_frame_pkt(
     conn, pi, dest, probelen, NGTCP2_PKT_1RTT,
@@ -4764,12 +5167,12 @@ static ngtcp2_ssize conn_write_path_chal
     return 0;
   }
 
-  rv = conn_call_get_path_challenge_data(conn, lfr.path_challenge.data);
+  rv = conn_call_get_path_challenge_data(conn, &lfr.path_challenge.data);
   if (rv != 0) {
     return rv;
   }
 
-  lfr.type = NGTCP2_FRAME_PATH_CHALLENGE;
+  lfr.path_challenge.type = NGTCP2_FRAME_PATH_CHALLENGE;
 
   initial_pto = conn_compute_initial_pto(conn, &conn->pktns);
   timeout = conn_compute_pto(conn, &conn->pktns);
@@ -4796,7 +5199,7 @@ static ngtcp2_ssize conn_write_path_chal
     flags = NGTCP2_PV_ENTRY_FLAG_NONE;
   }
 
-  ngtcp2_pv_add_entry(pv, lfr.path_challenge.data, expiry, flags, ts);
+  ngtcp2_pv_add_entry(pv, &lfr.path_challenge.data, expiry, flags, ts);
 
   nwrite = ngtcp2_conn_write_single_frame_pkt(
     conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE,
@@ -4902,8 +5305,10 @@ static ngtcp2_ssize conn_write_path_resp
     }
   }
 
-  lfr.type = NGTCP2_FRAME_PATH_RESPONSE;
-  memcpy(lfr.path_response.data, pcent->data, sizeof(lfr.path_response.data));
+  lfr.path_response = (ngtcp2_path_response){
+    .type = NGTCP2_FRAME_PATH_RESPONSE,
+    .data = pcent->data,
+  };
 
   nwrite = ngtcp2_conn_write_single_frame_pkt(
     conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE,
@@ -5060,11 +5465,11 @@ static int conn_on_retry(ngtcp2_conn *co
   ngtcp2_pktns *in_pktns = conn->in_pktns;
   ngtcp2_rtb *rtb = &conn->pktns.rtb;
   ngtcp2_rtb *in_rtb;
-  uint8_t cidbuf[sizeof(retry.odcid.data) * 2 + 1];
+  char cidbuf[sizeof(retry.odcid.data) * 2 + 1];
   uint8_t *token;
 
-  if (!in_pktns || conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) {
-    return 0;
+  if (!in_pktns || (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY)) {
+    return NGTCP2_ERR_DISCARD_PKT;
   }
 
   in_rtb = &in_pktns->rtb;
@@ -5085,9 +5490,9 @@ static int conn_on_retry(ngtcp2_conn *co
     return rv;
   }
 
-  ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "odcid=0x%s",
-                  (const char *)ngtcp2_encode_hex(cidbuf, retry.odcid.data,
-                                                  retry.odcid.datalen));
+  ngtcp2_log_infof(
+    &conn->log, NGTCP2_LOG_EVENT_PKT, "odcid=0x%s",
+    ngtcp2_encode_hex_cstr(cidbuf, retry.odcid.data, retry.odcid.datalen));
 
   if (retry.tokenlen == 0) {
     return NGTCP2_ERR_PROTO;
@@ -5181,14 +5586,10 @@ static int conn_recv_ack(ngtcp2_conn *co
 
   num_acked =
     ngtcp2_rtb_recv_ack(&pktns->rtb, fr, &conn->cstat, conn, pktns, pkt_ts, ts);
-  if (num_acked < 0) {
+  if (num_acked <= 0) {
     return (int)num_acked;
   }
 
-  if (num_acked == 0) {
-    return 0;
-  }
-
   pktns->rtb.probe_pkt_left = 0;
 
   if (cstat->pto_count &&
@@ -5235,9 +5636,12 @@ static void assign_recved_ack_delay_unsc
  *     Stream ID exceeds allowed limit.
  * NGTCP2_ERR_NOMEM
  *     Out of memory.
+ * NGTCP2_ERR_INTERNAL
+ *     Suspicious remote endpoint activity exceeded threshold.
  */
 static int conn_recv_max_stream_data(ngtcp2_conn *conn,
-                                     const ngtcp2_max_stream_data *fr) {
+                                     const ngtcp2_max_stream_data *fr,
+                                     ngtcp2_tstamp ts) {
   ngtcp2_strm *strm;
   ngtcp2_idtr *idtr;
   int local_stream = conn_local_stream(conn, fr->stream_id);
@@ -5267,6 +5671,10 @@ static int conn_recv_max_stream_data(ngt
   if (strm == NULL) {
     if (local_stream) {
       /* Stream has been closed. */
+      if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+        return NGTCP2_ERR_INTERNAL;
+      }
+
       return 0;
     }
 
@@ -5277,6 +5685,10 @@ static int conn_recv_max_stream_data(ngt
       }
       assert(rv == NGTCP2_ERR_STREAM_IN_USE);
       /* Stream has been closed. */
+      if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+        return NGTCP2_ERR_INTERNAL;
+      }
+
       return 0;
     }
 
@@ -5296,19 +5708,29 @@ static int conn_recv_max_stream_data(ngt
     }
   }
 
-  if (strm->tx.max_offset < fr->max_stream_data) {
-    strm->tx.max_offset = fr->max_stream_data;
-
-    /* Don't call callback if stream is half-closed local */
-    if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) {
-      return 0;
+  if (strm->tx.max_offset >= fr->max_stream_data) {
+    if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+      return NGTCP2_ERR_INTERNAL;
     }
 
-    rv = conn_call_extend_max_stream_data(conn, strm, fr->stream_id,
-                                          fr->max_stream_data);
-    if (rv != 0) {
-      return rv;
+    return 0;
+  }
+
+  strm->tx.max_offset = fr->max_stream_data;
+
+  /* Don't call callback if stream is half-closed local */
+  if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) {
+    if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+      return NGTCP2_ERR_INTERNAL;
     }
+
+    return 0;
+  }
+
+  rv = conn_call_extend_max_stream_data(conn, strm, fr->stream_id,
+                                        fr->max_stream_data);
+  if (rv != 0) {
+    return rv;
   }
 
   return 0;
@@ -5503,9 +5925,9 @@ decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *d
   }
 
   if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) {
-    dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x0f));
+    dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x0F));
   } else {
-    dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x1f));
+    dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x1F));
     if (dest[0] & NGTCP2_SHORT_KEY_PHASE_BIT) {
       hd->flags |= NGTCP2_PKT_FLAG_KEY_PHASE;
     }
@@ -5620,7 +6042,7 @@ static void conn_recv_path_challenge(ngt
   }
 
   ent = ngtcp2_ringbuf_push_front(&conn->rx.path_challenge.rb);
-  ngtcp2_path_challenge_entry_init(ent, path, fr->data);
+  ngtcp2_path_challenge_entry_init(ent, path, &fr->data);
 }
 
 /*
@@ -5690,7 +6112,7 @@ static int conn_recv_path_response(ngtcp
     return 0;
   }
 
-  rv = ngtcp2_pv_validate(pv, &ent_flags, fr->data);
+  rv = ngtcp2_pv_validate(pv, &ent_flags, &fr->data);
   if (rv != 0) {
     assert(!ngtcp2_err_is_fatal(rv));
 
@@ -5786,7 +6208,7 @@ static int conn_recv_path_response(ngtcp
 
   conn->pv = npv;
 
-  return 0;
+  return conn_call_begin_path_validation(conn, conn->pv);
 }
 
 /*
@@ -5941,7 +6363,8 @@ static int conn_verify_fixed_bit(ngtcp2_
 
 static int conn_recv_crypto(ngtcp2_conn *conn,
                             ngtcp2_encryption_level encryption_level,
-                            ngtcp2_strm *strm, const ngtcp2_stream *fr);
+                            ngtcp2_strm *strm, const ngtcp2_stream *fr,
+                            ngtcp2_tstamp ts);
 
 static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
                                   const ngtcp2_pkt_info *pi, const uint8_t *pkt,
@@ -5980,6 +6403,8 @@ static int conn_process_buffered_protect
  *     TLS stack reported error.
  * NGTCP2_ERR_PROTO
  *     Generic QUIC protocol error.
+ * NGTCP2_ERR_INTERNAL
+ *     Suspicious remote endpoint activity exceeded threshold.
  *
  * In addition to the above error codes, error codes returned from
  * conn_recv_pkt are also returned.
@@ -5991,8 +6416,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
                         ngtcp2_tstamp ts) {
   ngtcp2_ssize nread;
   ngtcp2_pkt_hd hd;
-  ngtcp2_max_frame mfr;
-  ngtcp2_frame *fr = &mfr.fr;
+  ngtcp2_frame_decoder frd;
+  ngtcp2_frame fr;
   int rv;
   int require_ack = 0;
   size_t hdpktlen;
@@ -6023,8 +6448,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
       return 0;
     }
 
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
-                    "buffering 1RTT packet len=%zu", pktlen);
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
+                     "buffering 1RTT packet len=%zu", pktlen);
 
     rv =
       conn_buffer_pkt(conn, &conn->pktns, path, pi, pkt, pktlen, dgramlen, ts);
@@ -6171,8 +6596,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
     }
 
     /* Buffer re-ordered 0-RTT packet. */
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
-                    "buffering 0-RTT packet len=%zu", pktlen);
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
+                     "buffering 0-RTT packet len=%zu", pktlen);
 
     rv = conn_buffer_pkt(conn, conn->in_pktns, path, pi, pkt, pktlen, dgramlen,
                          ts);
@@ -6194,10 +6619,10 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
 
     if (conn->server) {
       if (dgramlen < NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
-        ngtcp2_log_info(
+        ngtcp2_log_infof(
           &conn->log, NGTCP2_LOG_EVENT_PKT,
           "Initial packet was ignored because it is included in UDP datagram "
-          "less than %zu bytes: %zu bytes",
+          "less than %d bytes: %zu bytes",
           NGTCP2_MAX_UDP_PAYLOAD_SIZE, dgramlen);
         return NGTCP2_ERR_DISCARD_PKT;
       }
@@ -6277,8 +6702,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
           "Handshake packet at this point is unexpected and discarded");
         return (ngtcp2_ssize)pktlen;
       }
-      ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
-                      "buffering Handshake packet len=%zu", pktlen);
+      ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
+                       "buffering Handshake packet len=%zu", pktlen);
 
       rv = conn_buffer_pkt(conn, conn->hs_pktns, path, pi, pkt, pktlen,
                            dgramlen, ts);
@@ -6332,8 +6757,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
   hd.pkt_num = ngtcp2_pkt_adjust_pkt_num(pktns->acktr.max_pkt_num, hd.pkt_num,
                                          hd.pkt_numlen);
   if (hd.pkt_num > NGTCP2_MAX_PKT_NUM) {
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
-                    "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num);
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT,
+                     "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num);
     return NGTCP2_ERR_DISCARD_PKT;
   }
 
@@ -6380,9 +6805,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
       !conn->negotiated_version) {
     conn->negotiated_version = hd.version;
 
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
-                    "the negotiated version is 0x%08x",
-                    conn->negotiated_version);
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
+                     "the negotiated version is 0x%08x",
+                     conn->negotiated_version);
   }
 
   payload = conn->crypto.decrypt_buf.base;
@@ -6438,7 +6863,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
   ngtcp2_qlog_pkt_received_start(&conn->qlog);
 
   for (; payloadlen;) {
-    nread = ngtcp2_pkt_decode_frame(fr, payload, payloadlen);
+    nread = ngtcp2_frame_decoder_decode(&frd, &fr, payload, payloadlen);
     if (nread < 0) {
       return nread;
     }
@@ -6446,14 +6871,14 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
     payload += nread;
     payloadlen -= (size_t)nread;
 
-    switch (fr->type) {
+    switch (fr.hd.type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
-      fr->ack.ack_delay = 0;
-      fr->ack.ack_delay_unscaled = 0;
+      fr.ack.ack_delay = 0;
+      fr.ack.ack_delay_unscaled = 0;
 
       rv =
-        ngtcp2_pkt_validate_ack(&fr->ack, conn->local.settings.initial_pkt_num);
+        ngtcp2_pkt_validate_ack(&fr.ack, conn->local.settings.initial_pkt_num);
       if (rv != 0) {
         return rv;
       }
@@ -6461,9 +6886,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
       break;
     }
 
-    ngtcp2_log_rx_fr(&conn->log, &hd, fr);
+    ngtcp2_log_rx_fr(&conn->log, &hd, &fr);
 
-    switch (fr->type) {
+    switch (fr.hd.type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
       if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
@@ -6472,7 +6897,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
       if (!conn->server && hd.type == NGTCP2_PKT_HANDSHAKE) {
         conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
       }
-      rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts);
+      rv = conn_recv_ack(conn, pktns, &fr.ack, pkt_ts, ts);
       if (rv != 0) {
         return rv;
       }
@@ -6482,34 +6907,35 @@ conn_recv_handshake_pkt(ngtcp2_conn *con
       break;
     case NGTCP2_FRAME_CRYPTO:
       if (!conn->server && !conn->negotiated_version &&
-          ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt)) {
+          ngtcp2_vec_len(fr.stream.data, fr.stream.datacnt)) {
         conn->negotiated_version = hd.version;
 
-        ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
-                        "the negotiated version is 0x%08x",
-                        conn->negotiated_version);
+        ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
+                         "the negotiated version is 0x%08x",
+                         conn->negotiated_version);
       }
 
-      rv = conn_recv_crypto(conn, encryption_level, crypto, &fr->stream);
+      rv = conn_recv_crypto(conn, encryption_level, crypto, &fr.stream, ts);
       if (rv != 0) {
         return rv;
       }
       require_ack = 1;
       break;
     case NGTCP2_FRAME_CONNECTION_CLOSE:
-      rv = conn_recv_connection_close(conn, &fr->connection_close);
+      rv = conn_recv_connection_close(conn, &fr.connection_close);
       if (rv != 0) {
         return rv;
       }
       break;
     case NGTCP2_FRAME_PING:
+      ++conn->cstat.ping_recv;
       require_ack = 1;
       break;
     default:
       return NGTCP2_ERR_PROTO;
     }
 
-    ngtcp2_qlog_write_frame(&conn->qlog, fr);
+    ngtcp2_qlog_write_frame(&conn->qlog, &fr);
   }
 
   if (hd.type == NGTCP2_PKT_HANDSHAKE) {
@@ -6543,6 +6969,7 @@ static int is_unrecoverable_error(int li
   case NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM:
   case NGTCP2_ERR_TRANSPORT_PARAM:
   case NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE:
+  case NGTCP2_ERR_INTERNAL:
     return 1;
   }
 
@@ -6568,6 +6995,10 @@ static ngtcp2_ssize conn_recv_handshake_
   const uint8_t *origpkt = pkt;
   uint32_t version;
 
+  if (pktlen == 0) {
+    return 0;
+  }
+
   if (ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) {
     conn->dcid.current.bytes_recv += dgramlen;
   }
@@ -6595,6 +7026,8 @@ static ngtcp2_ssize conn_recv_handshake_
               return nread;
             }
 
+            ++conn->cstat.pkt_discarded;
+
             /* If server discards first Initial, then drop connection
                state.  This is because SCID in packet might be corrupted
                and the current connection state might wrongly discard
@@ -6612,11 +7045,15 @@ static ngtcp2_ssize conn_recv_handshake_
                unrecoverable, therefore drop connection. */
             return nread;
           }
+
+          ++conn->cstat.pkt_discarded;
+
           return (ngtcp2_ssize)dgramlen;
         }
       }
 
       if (nread == NGTCP2_ERR_DISCARD_PKT) {
+        ++conn->cstat.pkt_discarded;
         return (ngtcp2_ssize)dgramlen;
       }
 
@@ -6632,8 +7069,11 @@ static ngtcp2_ssize conn_recv_handshake_
     pkt += nread;
     pktlen -= (size_t)nread;
 
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
-                    "read packet %td left %zu", nread, pktlen);
+    ++conn->cstat.pkt_recv;
+    conn->cstat.bytes_recv += (uint64_t)nread;
+
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT,
+                     "read packet %td left %zu", nread, pktlen);
   }
 
   return (ngtcp2_ssize)dgramlen;
@@ -6778,15 +7218,24 @@ static int conn_emit_pending_stream_data
  *     The end offset exceeds the maximum value.
  * NGTCP2_ERR_CALLBACK_FAILURE
  *     User-defined callback function failed.
+ * NGTCP2_ERR_INTERNAL
+ *     Suspicious remote endpoint activity exceeded threshold.
  */
 static int conn_recv_crypto(ngtcp2_conn *conn,
                             ngtcp2_encryption_level encryption_level,
-                            ngtcp2_strm *crypto, const ngtcp2_stream *fr) {
+                            ngtcp2_strm *crypto, const ngtcp2_stream *fr,
+                            ngtcp2_tstamp ts) {
   uint64_t fr_end_offset;
   uint64_t rx_offset;
   int rv;
+  ngtcp2_ssize nwrite;
 
   if (fr->datacnt == 0) {
+    if (encryption_level != NGTCP2_ENCRYPTION_LEVEL_INITIAL &&
+        ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+      return NGTCP2_ERR_INTERNAL;
+    }
+
     return 0;
   }
 
@@ -6799,6 +7248,11 @@ static int conn_recv_crypto(ngtcp2_conn
   rx_offset = ngtcp2_strm_rx_offset(crypto);
 
   if (fr_end_offset <= rx_offset) {
+    if (encryption_level != NGTCP2_ENCRYPTION_LEVEL_INITIAL &&
+        ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+      return NGTCP2_ERR_INTERNAL;
+    }
+
     if (conn->server &&
         !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT) &&
         encryption_level == NGTCP2_ENCRYPTION_LEVEL_INITIAL) {
@@ -6856,8 +7310,18 @@ static int conn_recv_crypto(ngtcp2_conn
     return NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED;
   }
 
-  return ngtcp2_strm_recv_reordering(crypto, fr->data[0].base, fr->data[0].len,
-                                     fr->offset);
+  nwrite = ngtcp2_strm_recv_reordering(crypto, fr->data[0].base,
+                                       fr->data[0].len, fr->offset);
+  if (nwrite < 0) {
+    return (int)nwrite;
+  }
+
+  if (encryption_level != NGTCP2_ENCRYPTION_LEVEL_INITIAL && nwrite == 0 &&
+      ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+    return NGTCP2_ERR_INTERNAL;
+  }
+
+  return 0;
 }
 
 /*
@@ -6891,8 +7355,11 @@ static int conn_max_data_violated(ngtcp2
  * NGTCP2_ERR_FINAL_SIZE
  *     STREAM frame has strictly larger end offset than it is
  *     permitted.
+ * NGTCP2_ERR_INTERNAL
+ *     Suspicious remote endpoint activity exceeded threshold.
  */
-static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
+static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr,
+                            ngtcp2_tstamp ts) {
   int rv;
   ngtcp2_strm *strm;
   ngtcp2_idtr *idtr;
@@ -6901,6 +7368,8 @@ static int conn_recv_stream(ngtcp2_conn
   int bidi;
   uint64_t datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
   uint32_t sdflags = NGTCP2_STREAM_DATA_FLAG_NONE;
+  ngtcp2_ssize nwrite;
+  int new_strm = 0;
 
   local_stream = conn_local_stream(conn, fr->stream_id);
   bidi = bidi_stream(fr->stream_id);
@@ -6934,8 +7403,11 @@ static int conn_recv_stream(ngtcp2_conn
   strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
   if (strm == NULL) {
     if (local_stream) {
-      /* TODO The stream has been closed.  This should be responded
-         with RESET_STREAM, or simply ignored. */
+      /* The stream has been closed. */
+      if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+        return NGTCP2_ERR_INTERNAL;
+      }
+
       return 0;
     }
 
@@ -6945,8 +7417,11 @@ static int conn_recv_stream(ngtcp2_conn
         return rv;
       }
       assert(rv == NGTCP2_ERR_STREAM_IN_USE);
-      /* TODO The stream has been closed.  This should be responded
-         with RESET_STREAM, or simply ignored. */
+      /* The stream has been closed. */
+      if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+        return NGTCP2_ERR_INTERNAL;
+      }
+
       return 0;
     }
 
@@ -6961,6 +7436,8 @@ static int conn_recv_stream(ngtcp2_conn
       return rv;
     }
 
+    new_strm = 1;
+
     if (!bidi) {
       ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR);
       strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED;
@@ -7001,10 +7478,18 @@ static int conn_recv_stream(ngtcp2_conn
       }
 
       if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) {
+        if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+          return NGTCP2_ERR_INTERNAL;
+        }
+
         return 0;
       }
 
       if (rx_offset == fr_end_offset) {
+        if (!new_strm && ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+          return NGTCP2_ERR_INTERNAL;
+        }
+
         return 0;
       }
     } else if (strm->rx.last_offset > fr_end_offset) {
@@ -7024,10 +7509,18 @@ static int conn_recv_stream(ngtcp2_conn
       ngtcp2_max_uint64(strm->rx.last_offset, fr_end_offset);
 
     if (fr_end_offset <= rx_offset) {
+      if (!new_strm && ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+        return NGTCP2_ERR_INTERNAL;
+      }
+
       return 0;
     }
 
     if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) {
+      if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+        return NGTCP2_ERR_INTERNAL;
+      }
+
       return 0;
     }
   }
@@ -7056,30 +7549,34 @@ static int conn_recv_stream(ngtcp2_conn
     fin = (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) &&
           rx_offset == strm->rx.last_offset;
 
-    if (fin || datalen) {
-      if (fin) {
-        sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN;
-      }
-      if (!conn_is_tls_handshake_completed(conn)) {
-        sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT;
-      }
-      rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data,
-                                      (size_t)datalen);
-      if (rv != 0) {
-        return rv;
-      }
+    assert(fin || datalen);
 
-      rv = conn_emit_pending_stream_data(conn, strm, rx_offset);
-      if (rv != 0) {
-        return rv;
-      }
+    if (fin) {
+      sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN;
     }
-  } else if (fr->datacnt && !(strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING)) {
-    rv = ngtcp2_strm_recv_reordering(strm, fr->data[0].base, fr->data[0].len,
-                                     fr->offset);
+    if (!conn_is_tls_handshake_completed(conn)) {
+      sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT;
+    }
+    rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data,
+                                    (size_t)datalen);
     if (rv != 0) {
       return rv;
     }
+
+    rv = conn_emit_pending_stream_data(conn, strm, rx_offset);
+    if (rv != 0) {
+      return rv;
+    }
+  } else if (fr->datacnt && !(strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING)) {
+    nwrite = ngtcp2_strm_recv_reordering(strm, fr->data[0].base,
+                                         fr->data[0].len, fr->offset);
+    if (nwrite < 0) {
+      return (int)nwrite;
+    }
+
+    if (nwrite == 0 && ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+      return NGTCP2_ERR_INTERNAL;
+    }
   }
   return ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm);
 }
@@ -7175,9 +7672,12 @@ handle_max_remote_streams_extension(uint
  *     NGTCP2_MAX_VARINT.
  * NGTCP2_ERR_FINAL_SIZE
  *     The final offset is strictly larger than it is permitted.
+ * NGTCP2_ERR_INTERNAL
+ *     Suspicious remote endpoint activity exceeded threshold.
  */
 static int conn_recv_reset_stream(ngtcp2_conn *conn,
-                                  const ngtcp2_reset_stream *fr) {
+                                  const ngtcp2_reset_stream *fr,
+                                  ngtcp2_tstamp ts) {
   ngtcp2_strm *strm;
   int local_stream = conn_local_stream(conn, fr->stream_id);
   int bidi = bidi_stream(fr->stream_id);
@@ -7215,6 +7715,10 @@ static int conn_recv_reset_stream(ngtcp2
   strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
   if (strm == NULL) {
     if (local_stream) {
+      if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+        return NGTCP2_ERR_INTERNAL;
+      }
+
       return 0;
     }
 
@@ -7224,6 +7728,11 @@ static int conn_recv_reset_stream(ngtcp2
         return rv;
       }
       assert(rv == NGTCP2_ERR_STREAM_IN_USE);
+
+      if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+        return NGTCP2_ERR_INTERNAL;
+      }
+
       return 0;
     }
 
@@ -7258,6 +7767,10 @@ static int conn_recv_reset_stream(ngtcp2
   }
 
   if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) {
+    if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+      return NGTCP2_ERR_INTERNAL;
+    }
+
     return 0;
   }
 
@@ -7313,9 +7826,12 @@ static int conn_recv_reset_stream(ngtcp2
  *     Out of memory.
  * NGTCP2_ERR_CALLBACK_FAILURE
  *     User-defined callback function failed.
+ * NGTCP2_ERR_INTERNAL
+ *     Suspicious remote endpoint activity exceeded threshold.
  */
 static int conn_recv_stop_sending(ngtcp2_conn *conn,
-                                  const ngtcp2_stop_sending *fr) {
+                                  const ngtcp2_stop_sending *fr,
+                                  ngtcp2_tstamp ts) {
   int rv;
   ngtcp2_strm *strm;
   ngtcp2_idtr *idtr;
@@ -7344,6 +7860,10 @@ static int conn_recv_stop_sending(ngtcp2
   strm = ngtcp2_conn_find_stream(conn, fr->stream_id);
   if (strm == NULL) {
     if (local_stream) {
+      if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+        return NGTCP2_ERR_INTERNAL;
+      }
+
       return 0;
     }
     rv = ngtcp2_idtr_open(idtr, fr->stream_id);
@@ -7352,6 +7872,11 @@ static int conn_recv_stop_sending(ngtcp2
         return rv;
       }
       assert(rv == NGTCP2_ERR_STREAM_IN_USE);
+
+      if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+        return NGTCP2_ERR_INTERNAL;
+      }
+
       return 0;
     }
 
@@ -7374,6 +7899,10 @@ static int conn_recv_stop_sending(ngtcp2
   }
 
   if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING_RECVED) {
+    if (ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) {
+      return NGTCP2_ERR_INTERNAL;
+    }
+
     return 0;
   }
 
@@ -7405,9 +7934,8 @@ static int conn_recv_stop_sending(ngtcp2
  */
 static int check_stateless_reset(const ngtcp2_dcid *dcid,
                                  const ngtcp2_path *path,
-                                 const ngtcp2_pkt_stateless_reset *sr) {
-  return ngtcp2_dcid_verify_stateless_reset_token(
-           dcid, path, sr->stateless_reset_token) == 0;
+                                 const ngtcp2_pkt_stateless_reset2 *sr) {
+  return ngtcp2_dcid_verify_stateless_reset_token(dcid, path, &sr->token) == 0;
 }
 
 /*
@@ -7431,7 +7959,7 @@ static int conn_on_stateless_reset(ngtcp
                                    const uint8_t *payload, size_t payloadlen) {
   int rv;
   ngtcp2_pv *pv = conn->pv;
-  ngtcp2_pkt_stateless_reset sr;
+  ngtcp2_pkt_stateless_reset2 sr;
 
   rv = ngtcp2_pkt_decode_stateless_reset(&sr, payload, payloadlen);
   if (rv != 0) {
@@ -7442,8 +7970,7 @@ static int conn_on_stateless_reset(ngtcp
       (!pv || (!check_stateless_reset(&pv->dcid, path, &sr) &&
                (!(pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT) ||
                 !check_stateless_reset(&pv->fallback_dcid, path, &sr))))) {
-    rv = ngtcp2_dcidtr_verify_stateless_reset(&conn->dcid.dtr, path,
-                                              sr.stateless_reset_token);
+    rv = ngtcp2_dcidtr_verify_stateless_reset(&conn->dcid.dtr, path, &sr.token);
     if (rv != 0) {
       return rv;
     }
@@ -7523,7 +8050,7 @@ static int conn_recv_new_connection_id(n
   }
 
   rv = ngtcp2_dcid_verify_uniqueness(&conn->dcid.current, fr->seq, &fr->cid,
-                                     fr->stateless_reset_token);
+                                     &fr->token);
   if (rv != 0) {
     return rv;
   }
@@ -7532,8 +8059,8 @@ static int conn_recv_new_connection_id(n
   }
 
   if (pv) {
-    rv = ngtcp2_dcid_verify_uniqueness(&pv->dcid, fr->seq, &fr->cid,
-                                       fr->stateless_reset_token);
+    rv =
+      ngtcp2_dcid_verify_uniqueness(&pv->dcid, fr->seq, &fr->cid, &fr->token);
     if (rv != 0) {
       return rv;
     }
@@ -7542,8 +8069,8 @@ static int conn_recv_new_connection_id(n
     }
   }
 
-  rv = ngtcp2_dcidtr_verify_token_uniqueness(
-    &conn->dcid.dtr, &found, fr->seq, &fr->cid, fr->stateless_reset_token);
+  rv = ngtcp2_dcidtr_verify_token_uniqueness(&conn->dcid.dtr, &found, fr->seq,
+                                             &fr->cid, &fr->token);
   if (rv != 0) {
     return rv;
   }
@@ -7621,8 +8148,7 @@ static int conn_recv_new_connection_id(n
     return 0;
   }
 
-  ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, fr->seq, &fr->cid,
-                            fr->stateless_reset_token);
+  ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, fr->seq, &fr->cid, &fr->token);
 
   return 0;
 }
@@ -8030,7 +8556,12 @@ static int conn_select_preferred_addr(ng
 
   conn->pv = pv;
 
-  return conn_call_activate_dcid(conn, &pv->dcid);
+  rv = conn_call_activate_dcid(conn, &pv->dcid);
+  if (rv != 0) {
+    return rv;
+  }
+
+  return conn_call_begin_path_validation(conn, conn->pv);
 }
 
 /*
@@ -8258,7 +8789,6 @@ static int conn_recv_non_probing_pkt_on_
   ngtcp2_pv *pv = NULL;
   int rv;
   ngtcp2_duration pto;
-  int require_new_cid;
   int local_addr_eq;
   int pref_addr_migration;
   uint32_t remote_addr_cmp;
@@ -8316,9 +8846,6 @@ static int conn_recv_non_probing_pkt_on_
    * continue to use the current connection ID with the new remote
    * address while still sending from the same local address.
    */
-  require_new_cid = conn->dcid.current.cid.datalen &&
-                    ((new_cid_used && remote_addr_cmp) || !local_addr_eq);
-
   ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
                   "non-probing packet was received from new remote address");
 
@@ -8326,8 +8853,6 @@ static int conn_recv_non_probing_pkt_on_
     ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
                     "Found DCID which has already been bound to the new path");
 
-    require_new_cid = 0;
-
     if (dcid.cid.datalen) {
       rv = conn_call_activate_dcid(conn, &dcid);
       if (rv != 0) {
@@ -8335,7 +8860,9 @@ static int conn_recv_non_probing_pkt_on_
       }
     }
   } else {
-    if (require_new_cid) {
+    if (conn->dcid.current.cid.datalen &&
+        ((new_cid_used && remote_addr_cmp) || !local_addr_eq)) {
+      /* New DCID is required. */
       if (ngtcp2_dcidtr_unused_empty(&conn->dcid.dtr)) {
         return NGTCP2_ERR_CONN_ID_BLOCKED;
       }
@@ -8421,7 +8948,7 @@ static int conn_recv_non_probing_pkt_on_
 
   conn->pv = pv;
 
-  return 0;
+  return conn_call_begin_path_validation(conn, conn->pv);
 }
 
 /*
@@ -8500,8 +9027,8 @@ conn_recv_delayed_handshake_pkt(ngtcp2_c
                                 const uint8_t *payload, size_t payloadlen,
                                 ngtcp2_tstamp pkt_ts, ngtcp2_tstamp ts) {
   ngtcp2_ssize nread;
-  ngtcp2_max_frame mfr;
-  ngtcp2_frame *fr = &mfr.fr;
+  ngtcp2_frame_decoder frd;
+  ngtcp2_frame fr;
   int rv;
   int require_ack = 0;
   ngtcp2_pktns *pktns;
@@ -8519,7 +9046,7 @@ conn_recv_delayed_handshake_pkt(ngtcp2_c
   ngtcp2_qlog_pkt_received_start(&conn->qlog);
 
   for (; payloadlen;) {
-    nread = ngtcp2_pkt_decode_frame(fr, payload, payloadlen);
+    nread = ngtcp2_frame_decoder_decode(&frd, &fr, payload, payloadlen);
     if (nread < 0) {
       return (int)nread;
     }
@@ -8527,14 +9054,14 @@ conn_recv_delayed_handshake_pkt(ngtcp2_c
     payload += nread;
     payloadlen -= (size_t)nread;
 
-    switch (fr->type) {
+    switch (fr.hd.type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
-      fr->ack.ack_delay = 0;
-      fr->ack.ack_delay_unscaled = 0;
+      fr.ack.ack_delay = 0;
+      fr.ack.ack_delay_unscaled = 0;
 
       rv =
-        ngtcp2_pkt_validate_ack(&fr->ack, conn->local.settings.initial_pkt_num);
+        ngtcp2_pkt_validate_ack(&fr.ack, conn->local.settings.initial_pkt_num);
       if (rv != 0) {
         return rv;
       }
@@ -8542,9 +9069,9 @@ conn_recv_delayed_handshake_pkt(ngtcp2_c
       break;
     }
 
-    ngtcp2_log_rx_fr(&conn->log, hd, fr);
+    ngtcp2_log_rx_fr(&conn->log, hd, &fr);
 
-    switch (fr->type) {
+    switch (fr.hd.type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
       if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
@@ -8553,7 +9080,7 @@ conn_recv_delayed_handshake_pkt(ngtcp2_c
       if (!conn->server) {
         conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
       }
-      rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts);
+      rv = conn_recv_ack(conn, pktns, &fr.ack, pkt_ts, ts);
       if (rv != 0) {
         return rv;
       }
@@ -8562,20 +9089,22 @@ conn_recv_delayed_handshake_pkt(ngtcp2_c
     case NGTCP2_FRAME_PADDING:
       break;
     case NGTCP2_FRAME_CONNECTION_CLOSE:
-      rv = conn_recv_connection_close(conn, &fr->connection_close);
+      rv = conn_recv_connection_close(conn, &fr.connection_close);
       if (rv != 0) {
         return rv;
       }
       break;
-    case NGTCP2_FRAME_CRYPTO:
     case NGTCP2_FRAME_PING:
+      ++conn->cstat.ping_recv;
+      /* fall through */
+    case NGTCP2_FRAME_CRYPTO:
       require_ack = 1;
       break;
     default:
       return NGTCP2_ERR_PROTO;
     }
 
-    ngtcp2_qlog_write_frame(&conn->qlog, fr);
+    ngtcp2_qlog_write_frame(&conn->qlog, &fr);
   }
 
   ngtcp2_qlog_pkt_received_end(&conn->qlog, hd, pktlen);
@@ -8630,6 +9159,8 @@ conn_recv_delayed_handshake_pkt(ngtcp2_c
  *     Flow control limit is violated.
  * NGTCP2_ERR_FINAL_SIZE
  *     Frame has strictly larger end offset than it is permitted.
+ * NGTCP2_ERR_INTERNAL
+ *     Suspicious remote endpoint activity exceeded threshold.
  */
 static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
                                   const ngtcp2_pkt_info *pi, const uint8_t *pkt,
@@ -8641,8 +9172,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
   const uint8_t *payload;
   size_t payloadlen;
   ngtcp2_ssize nread, nwrite;
-  ngtcp2_max_frame mfr;
-  ngtcp2_frame *fr = &mfr.fr;
+  ngtcp2_frame_decoder frd;
+  ngtcp2_frame fr;
   int require_ack = 0;
   ngtcp2_crypto_aead *aead;
   ngtcp2_crypto_cipher *hp;
@@ -8736,8 +9267,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       break;
     default:
       ngtcp2_log_rx_pkt_hd(&conn->log, &hd);
-      ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
-                      "packet type 0x%02x was ignored", hd.type);
+      ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT,
+                       "packet type 0x%02x was ignored", hd.type);
       return (ngtcp2_ssize)pktlen;
     }
   } else {
@@ -8784,8 +9315,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
   hd.pkt_num = ngtcp2_pkt_adjust_pkt_num(pktns->acktr.max_pkt_num, hd.pkt_num,
                                          hd.pkt_numlen);
   if (hd.pkt_num > NGTCP2_MAX_PKT_NUM) {
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
-                    "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num);
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT,
+                     "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num);
     return NGTCP2_ERR_DISCARD_PKT;
   }
 
@@ -8796,7 +9327,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
         conn->rx.preferred_addr.pkt_num < hd.pkt_num &&
         ngtcp2_sockaddr_eq((const ngtcp2_sockaddr *)&conn->hs_local_addr,
                            path->local.addr)) {
-      ngtcp2_log_info(
+      ngtcp2_log_infof(
         &conn->log, NGTCP2_LOG_EVENT_PKT,
         "pkt=%" PRId64
         " is discarded because it was received on handshake local "
@@ -8948,7 +9479,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
   ngtcp2_qlog_pkt_received_start(&conn->qlog);
 
   for (; payloadlen;) {
-    nread = ngtcp2_pkt_decode_frame(fr, payload, payloadlen);
+    nread = ngtcp2_frame_decoder_decode(&frd, &fr, payload, payloadlen);
     if (nread < 0) {
       return nread;
     }
@@ -8956,7 +9487,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
     payload += nread;
     payloadlen -= (size_t)nread;
 
-    switch (fr->type) {
+    switch (fr.hd.type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
       if ((hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) &&
@@ -8965,10 +9496,10 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       }
       assert(conn->remote.transport_params);
       assign_recved_ack_delay_unscaled(
-        &fr->ack, conn->remote.transport_params->ack_delay_exponent);
+        &fr.ack, conn->remote.transport_params->ack_delay_exponent);
 
       rv =
-        ngtcp2_pkt_validate_ack(&fr->ack, conn->local.settings.initial_pkt_num);
+        ngtcp2_pkt_validate_ack(&fr.ack, conn->local.settings.initial_pkt_num);
       if (rv != 0) {
         return rv;
       }
@@ -8976,10 +9507,10 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       break;
     }
 
-    ngtcp2_log_rx_fr(&conn->log, &hd, fr);
+    ngtcp2_log_rx_fr(&conn->log, &hd, &fr);
 
     if (hd.type == NGTCP2_PKT_0RTT) {
-      switch (fr->type) {
+      switch (fr.hd.type) {
       case NGTCP2_FRAME_PADDING:
       case NGTCP2_FRAME_PING:
       case NGTCP2_FRAME_RESET_STREAM:
@@ -9005,7 +9536,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       }
     }
 
-    switch (fr->type) {
+    switch (fr.hd.type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
     case NGTCP2_FRAME_PADDING:
@@ -9016,7 +9547,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       require_ack = 1;
     }
 
-    switch (fr->type) {
+    switch (fr.hd.type) {
     case NGTCP2_FRAME_ACK:
     case NGTCP2_FRAME_ACK_ECN:
       if (num_ack_processed >= NGTCP2_MAX_ACK_PER_PKT) {
@@ -9025,7 +9556,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       if (!conn->server) {
         conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
       }
-      rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts);
+      rv = conn_recv_ack(conn, pktns, &fr.ack, pkt_ts, ts);
       if (rv != 0) {
         return rv;
       }
@@ -9033,7 +9564,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       ++num_ack_processed;
       break;
     case NGTCP2_FRAME_STREAM:
-      rv = conn_recv_stream(conn, &fr->stream);
+      rv = conn_recv_stream(conn, &fr.stream, ts);
       if (rv != 0) {
         return rv;
       }
@@ -9041,40 +9572,40 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       break;
     case NGTCP2_FRAME_CRYPTO:
       rv = conn_recv_crypto(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT,
-                            &pktns->crypto.strm, &fr->stream);
+                            &pktns->crypto.strm, &fr.stream, ts);
       if (rv != 0) {
         return rv;
       }
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_RESET_STREAM:
-      rv = conn_recv_reset_stream(conn, &fr->reset_stream);
+      rv = conn_recv_reset_stream(conn, &fr.reset_stream, ts);
       if (rv != 0) {
         return rv;
       }
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_STOP_SENDING:
-      rv = conn_recv_stop_sending(conn, &fr->stop_sending);
+      rv = conn_recv_stop_sending(conn, &fr.stop_sending, ts);
       if (rv != 0) {
         return rv;
       }
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_MAX_STREAM_DATA:
-      rv = conn_recv_max_stream_data(conn, &fr->max_stream_data);
+      rv = conn_recv_max_stream_data(conn, &fr.max_stream_data, ts);
       if (rv != 0) {
         return rv;
       }
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_MAX_DATA:
-      conn_recv_max_data(conn, &fr->max_data);
+      conn_recv_max_data(conn, &fr.max_data);
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_MAX_STREAMS_BIDI:
     case NGTCP2_FRAME_MAX_STREAMS_UNI:
-      rv = conn_recv_max_streams(conn, &fr->max_streams);
+      rv = conn_recv_max_streams(conn, &fr.max_streams);
       if (rv != 0) {
         return rv;
       }
@@ -9082,41 +9613,42 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       break;
     case NGTCP2_FRAME_CONNECTION_CLOSE:
     case NGTCP2_FRAME_CONNECTION_CLOSE_APP:
-      rv = conn_recv_connection_close(conn, &fr->connection_close);
+      rv = conn_recv_connection_close(conn, &fr.connection_close);
       if (rv != 0) {
         return rv;
       }
       break;
     case NGTCP2_FRAME_PING:
+      ++conn->cstat.ping_recv;
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_PATH_CHALLENGE:
-      conn_recv_path_challenge(conn, path, &fr->path_challenge);
+      conn_recv_path_challenge(conn, path, &fr.path_challenge);
       path_challenge_recved = 1;
       break;
     case NGTCP2_FRAME_PATH_RESPONSE:
-      rv = conn_recv_path_response(conn, &hd, &fr->path_response, ts);
+      rv = conn_recv_path_response(conn, &hd, &fr.path_response, ts);
       if (rv != 0) {
         return rv;
       }
       break;
     case NGTCP2_FRAME_NEW_CONNECTION_ID:
-      rv = conn_recv_new_connection_id(conn, &fr->new_connection_id);
+      rv = conn_recv_new_connection_id(conn, &fr.new_connection_id);
       if (rv != 0) {
         return rv;
       }
       recv_ncid = 1;
       break;
     case NGTCP2_FRAME_RETIRE_CONNECTION_ID:
-      rv = conn_recv_retire_connection_id(conn, &hd, &fr->retire_connection_id,
-                                          ts);
+      rv =
+        conn_recv_retire_connection_id(conn, &hd, &fr.retire_connection_id, ts);
       if (rv != 0) {
         return rv;
       }
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_NEW_TOKEN:
-      rv = conn_recv_new_token(conn, &fr->new_token);
+      rv = conn_recv_new_token(conn, &fr.new_token);
       if (rv != 0) {
         return rv;
       }
@@ -9130,28 +9662,28 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_STREAMS_BLOCKED_BIDI:
-      rv = conn_recv_streams_blocked_bidi(conn, &fr->streams_blocked);
+      rv = conn_recv_streams_blocked_bidi(conn, &fr.streams_blocked);
       if (rv != 0) {
         return rv;
       }
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_STREAMS_BLOCKED_UNI:
-      rv = conn_recv_streams_blocked_uni(conn, &fr->streams_blocked);
+      rv = conn_recv_streams_blocked_uni(conn, &fr.streams_blocked);
       if (rv != 0) {
         return rv;
       }
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_STREAM_DATA_BLOCKED:
-      rv = conn_recv_stream_data_blocked(conn, &fr->stream_data_blocked);
+      rv = conn_recv_stream_data_blocked(conn, &fr.stream_data_blocked);
       if (rv != 0) {
         return rv;
       }
       non_probing_pkt = 1;
       break;
     case NGTCP2_FRAME_DATA_BLOCKED:
-      rv = conn_recv_data_blocked(conn, &fr->data_blocked);
+      rv = conn_recv_data_blocked(conn, &fr.data_blocked);
       if (rv != 0) {
         return rv;
       }
@@ -9163,7 +9695,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
           conn->local.transport_params.max_datagram_frame_size) {
         return NGTCP2_ERR_PROTO;
       }
-      rv = conn_recv_datagram(conn, &fr->datagram);
+      rv = conn_recv_datagram(conn, &fr.datagram);
       if (rv != 0) {
         return rv;
       }
@@ -9171,7 +9703,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2
       break;
     }
 
-    ngtcp2_qlog_write_frame(&conn->qlog, fr);
+    ngtcp2_qlog_write_frame(&conn->qlog, &fr);
   }
 
   ngtcp2_qlog_pkt_received_end(&conn->qlog, &hd, pktlen);
@@ -9286,6 +9818,7 @@ static int conn_process_buffered_protect
     *ppc = next;
     if (nread < 0) {
       if (nread == NGTCP2_ERR_DISCARD_PKT) {
+        ++conn->cstat.pkt_discarded;
         continue;
       }
       return (int)nread;
@@ -9320,6 +9853,7 @@ static int conn_process_buffered_handsha
     *ppc = next;
     if (nread < 0) {
       if (nread == NGTCP2_ERR_DISCARD_PKT) {
+        ++conn->cstat.pkt_discarded;
         continue;
       }
       return (int)nread;
@@ -9465,6 +9999,7 @@ static int conn_recv_cpkt(ngtcp2_conn *c
         }
       }
       if (nread == NGTCP2_ERR_DISCARD_PKT) {
+        ++conn->cstat.pkt_discarded;
         return 0;
       }
       return (int)nread;
@@ -9474,8 +10009,11 @@ static int conn_recv_cpkt(ngtcp2_conn *c
     pkt += nread;
     pktlen -= (size_t)nread;
 
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
-                    "read packet %td left %zu", nread, pktlen);
+    ++conn->cstat.pkt_recv;
+    conn->cstat.bytes_recv += (uint64_t)nread;
+
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT,
+                     "read packet %td left %zu", nread, pktlen);
   }
 
   return 0;
@@ -9497,7 +10035,7 @@ static int conn_enqueue_handshake_done(n
     return rv;
   }
 
-  nfrc->fr.type = NGTCP2_FRAME_HANDSHAKE_DONE;
+  nfrc->fr.handshake_done.type = NGTCP2_FRAME_HANDSHAKE_DONE;
   nfrc->next = pktns->tx.frq;
   pktns->tx.frq = nfrc;
 
@@ -9647,9 +10185,9 @@ static ngtcp2_ssize conn_read_handshake(
       if ((size_t)nread < pktlen) {
         /* We have 1RTT packet and application rx key, but the
            handshake has not completed yet. */
-        ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
-                        "buffering 1RTT packet len=%zu",
-                        pktlen - (size_t)nread);
+        ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
+                         "buffering 1RTT packet len=%zu",
+                         pktlen - (size_t)nread);
 
         rv = conn_buffer_pkt(conn, &conn->pktns, path, pi, pkt + nread,
                              pktlen - (size_t)nread, pktlen, ts);
@@ -9728,8 +10266,8 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp
 
   conn_update_timestamp(conn, ts);
 
-  ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "recv packet len=%zu",
-                  pktlen);
+  ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "recv packet len=%zu",
+                   pktlen);
 
   if (pktlen == 0) {
     return 0;
@@ -9741,6 +10279,8 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp
       !ngtcp2_dcidtr_check_path_retired(&conn->dcid.dtr, path)) {
     ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
                     "ignore packet from unknown path");
+    ++conn->cstat.pkt_discarded;
+
     return 0;
   }
 
@@ -9814,6 +10354,49 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp
   return conn_recv_cpkt(conn, path, pi, pkt, pktlen, ts);
 }
 
+int ngtcp2_conn_continue_handshake(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
+  int rv;
+  ngtcp2_encryption_level encryption_level;
+  uint64_t offset;
+
+  conn_update_timestamp(conn, ts);
+
+  switch (conn->state) {
+  case NGTCP2_CS_CLIENT_INITIAL:
+  case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE:
+  case NGTCP2_CS_SERVER_INITIAL:
+  case NGTCP2_CS_SERVER_WAIT_HANDSHAKE:
+    /* Most of the handshake interruption happens in Initial
+       encryption level, but this might not be the case depending on
+       the TLS stack and its functionality and where interruption
+       occurs.  After all, we do not need to support all kinds of
+       interruptions. */
+    if (conn->in_pktns) {
+      encryption_level = NGTCP2_ENCRYPTION_LEVEL_INITIAL;
+      offset = ngtcp2_strm_rx_offset(&conn->in_pktns->crypto.strm);
+    } else if (conn->hs_pktns) {
+      encryption_level = NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE;
+      offset = ngtcp2_strm_rx_offset(&conn->hs_pktns->crypto.strm);
+    } else {
+      return 0;
+    }
+
+    rv = conn_call_recv_crypto_data(conn, encryption_level, offset, NULL, 0);
+    if (rv != 0) {
+      return rv;
+    }
+
+    return (int)conn_read_handshake(conn, /* path = */ NULL, /* pi = */ NULL,
+                                    /* pkt = */ NULL, 0, ts);
+  case NGTCP2_CS_CLOSING:
+    return NGTCP2_ERR_CLOSING;
+  case NGTCP2_CS_DRAINING:
+    return NGTCP2_ERR_DRAINING;
+  default:
+    return 0;
+  }
+}
+
 /*
  * conn_check_pkt_num_exhausted returns nonzero if packet number is
  * exhausted in at least one of packet number space.
@@ -9915,6 +10498,7 @@ static ngtcp2_ssize conn_write_handshake
   size_t origlen = destlen;
   uint64_t pending_early_datalen;
   ngtcp2_preferred_addr *paddr;
+  ngtcp2_stateless_reset_token token;
 
   switch (conn->state) {
   case NGTCP2_CS_CLIENT_INITIAL:
@@ -10042,8 +10626,8 @@ static ngtcp2_ssize conn_write_handshake
       assert(!ngtcp2_dcidtr_unused_full(&conn->dcid.dtr));
 
       paddr = &conn->remote.transport_params->preferred_addr;
-      ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, 1, &paddr->cid,
-                                paddr->stateless_reset_token);
+      memcpy(token.data, paddr->stateless_reset_token, sizeof(token.data));
+      ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, 1, &paddr->cid, &token);
 
       rv = ngtcp2_gaptr_push(&conn->dcid.seqgap, 1, 1);
       if (rv != 0) {
@@ -10051,12 +10635,12 @@ static ngtcp2_ssize conn_write_handshake
       }
     }
 
-    if (conn->remote.transport_params->stateless_reset_token_present) {
-      assert(conn->dcid.current.seq == 0);
+    if (conn->remote.transport_params->stateless_reset_token_present &&
+        conn->dcid.current.seq == 0) {
       assert(!(conn->dcid.current.flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT));
-      ngtcp2_dcid_set_token(
-        &conn->dcid.current,
-        conn->remote.transport_params->stateless_reset_token);
+      memcpy(token.data, conn->remote.transport_params->stateless_reset_token,
+             sizeof(token.data));
+      ngtcp2_dcid_set_token(&conn->dcid.current, &token);
     }
 
     rv = conn_call_activate_dcid(conn, &conn->dcid.current);
@@ -10095,8 +10679,6 @@ static ngtcp2_ssize conn_write_handshake
       }
 
       res += nwrite;
-      dest += nwrite;
-      destlen -= (size_t)nwrite;
     }
 
     if (res == 0) {
@@ -10106,8 +10688,6 @@ static ngtcp2_ssize conn_write_handshake
       }
 
       res += nwrite;
-      dest += nwrite;
-      origlen -= (size_t)nwrite;
     }
 
     return res;
@@ -10343,6 +10923,9 @@ int ngtcp2_conn_install_initial_key(
   rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, NULL, tx_iv, ivlen,
                             conn->mem);
   if (rv != 0) {
+    ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
+    pktns->crypto.rx.ckm = NULL;
+
     return rv;
   }
 
@@ -10393,6 +10976,9 @@ int ngtcp2_conn_install_vneg_initial_key
   rv = ngtcp2_crypto_km_new(&conn->vneg.tx.ckm, NULL, 0, NULL, tx_iv, ivlen,
                             conn->mem);
   if (rv != 0) {
+    ngtcp2_crypto_km_del(conn->vneg.rx.ckm, conn->mem);
+    conn->vneg.rx.ckm = NULL;
+
     return rv;
   }
 
@@ -10430,8 +11016,7 @@ int ngtcp2_conn_install_rx_handshake_key
   if (rv != 0) {
     ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
     pktns->crypto.rx.ckm = NULL;
-
-    memset(&pktns->crypto.rx.hp_ctx, 0, sizeof(pktns->crypto.rx.hp_ctx));
+    pktns->crypto.rx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
 
     return rv;
   }
@@ -10461,21 +11046,26 @@ int ngtcp2_conn_install_tx_handshake_key
   if (conn->server) {
     rv = ngtcp2_conn_commit_local_transport_params(conn);
     if (rv != 0) {
-      return rv;
+      goto fail;
     }
   }
 
   rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE);
   if (rv != 0) {
-    ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
-    pktns->crypto.tx.ckm = NULL;
-
-    memset(&pktns->crypto.tx.hp_ctx, 0, sizeof(pktns->crypto.tx.hp_ctx));
-
-    return rv;
+    goto fail;
   }
 
   return 0;
+
+fail:
+  /* If this function fails, aead_ctx and hp_ctx are still owned by
+     the caller.  Delete the install key to remove the any reference
+     to them. */
+  ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
+  pktns->crypto.tx.ckm = NULL;
+  pktns->crypto.tx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
+
+  return rv;
 }
 
 int ngtcp2_conn_install_0rtt_key(ngtcp2_conn *conn,
@@ -10506,8 +11096,7 @@ int ngtcp2_conn_install_0rtt_key(ngtcp2_
   if (rv != 0) {
     ngtcp2_crypto_km_del(conn->early.ckm, conn->mem);
     conn->early.ckm = NULL;
-
-    memset(&conn->early.hp_ctx, 0, sizeof(conn->early.hp_ctx));
+    conn->early.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
 
     return rv;
   }
@@ -10554,8 +11143,7 @@ int ngtcp2_conn_install_rx_key(ngtcp2_co
   if (rv != 0) {
     ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
     pktns->crypto.rx.ckm = NULL;
-
-    memset(&pktns->crypto.rx.hp_ctx, 0, sizeof(pktns->crypto.rx.hp_ctx));
+    pktns->crypto.rx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
 
     return rv;
   }
@@ -10600,8 +11188,7 @@ int ngtcp2_conn_install_tx_key(ngtcp2_co
   if (rv != 0) {
     ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
     pktns->crypto.tx.ckm = NULL;
-
-    memset(&pktns->crypto.tx.hp_ctx, 0, sizeof(pktns->crypto.tx.hp_ctx));
+    pktns->crypto.tx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0};
 
     return rv;
   }
@@ -11059,9 +11646,9 @@ int ngtcp2_conn_set_remote_transport_par
     conn->local.transport_params.version_info.chosen_version =
       conn->negotiated_version;
 
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
-                    "the negotiated version is 0x%08x",
-                    conn->negotiated_version);
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
+                     "the negotiated version is 0x%08x",
+                     conn->negotiated_version);
   } else {
     rv = conn_client_validate_transport_params(conn, params);
     if (rv != 0) {
@@ -11213,21 +11800,18 @@ int ngtcp2_conn_set_0rtt_remote_transpor
   /* These parameters are treated specially.  If server accepts early
      data, it must not set values for these parameters that are
      smaller than these remembered values. */
-  conn->early.transport_params.initial_max_streams_bidi =
-    params->initial_max_streams_bidi;
-  conn->early.transport_params.initial_max_streams_uni =
-    params->initial_max_streams_uni;
-  conn->early.transport_params.initial_max_stream_data_bidi_local =
-    params->initial_max_stream_data_bidi_local;
-  conn->early.transport_params.initial_max_stream_data_bidi_remote =
-    params->initial_max_stream_data_bidi_remote;
-  conn->early.transport_params.initial_max_stream_data_uni =
-    params->initial_max_stream_data_uni;
-  conn->early.transport_params.initial_max_data = params->initial_max_data;
-  conn->early.transport_params.active_connection_id_limit =
-    params->active_connection_id_limit;
-  conn->early.transport_params.max_datagram_frame_size =
-    params->max_datagram_frame_size;
+  conn->early.transport_params = (ngtcp2_early_transport_params){
+    .initial_max_streams_bidi = params->initial_max_streams_bidi,
+    .initial_max_streams_uni = params->initial_max_streams_uni,
+    .initial_max_stream_data_bidi_local =
+      params->initial_max_stream_data_bidi_local,
+    .initial_max_stream_data_bidi_remote =
+      params->initial_max_stream_data_bidi_remote,
+    .initial_max_stream_data_uni = params->initial_max_stream_data_uni,
+    .initial_max_data = params->initial_max_data,
+    .active_connection_id_limit = params->active_connection_id_limit,
+    .max_datagram_frame_size = params->max_datagram_frame_size,
+  };
 
   conn_sync_stream_id_limit(conn);
 
@@ -11417,17 +12001,20 @@ conn_write_vmsg_wrapper(ngtcp2_conn *con
     return nwrite;
   }
 
+  assert((size_t)nwrite <= destlen);
+
   if (cstat->bytes_in_flight >= cstat->cwnd) {
     conn->rst.is_cwnd_limited = 1;
   } 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) {
-      conn->rst.app_limited = cstat->max_tx_udp_payload_size;
-    }
+             (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) &&
+             /* Because NGTCP2_CONN_FLAG_AGGREGATE_PKTS is set after a
+                packet is produced, if it is set, we are sure that we
+                are not app-limited. */
+             !(conn->flags & NGTCP2_CONN_FLAG_AGGREGATE_PKTS)) {
+    conn->rst.app_limited =
+      ngtcp2_max_uint64(conn->rst.delivered + cstat->bytes_in_flight, 1);
   }
 
   return nwrite;
@@ -11471,12 +12058,17 @@ ngtcp2_ssize ngtcp2_conn_writev_stream_v
         return NGTCP2_ERR_INVALID_ARGUMENT;
       }
 
-      vmsg.type = NGTCP2_VMSG_TYPE_STREAM;
-      vmsg.stream.strm = strm;
-      vmsg.stream.flags = flags;
-      vmsg.stream.data = datav;
-      vmsg.stream.datacnt = datavcnt;
-      vmsg.stream.pdatalen = pdatalen;
+      vmsg = (ngtcp2_vmsg){
+        .type = NGTCP2_VMSG_TYPE_STREAM,
+        .stream =
+          {
+            .strm = strm,
+            .data = datav,
+            .datacnt = datavcnt,
+            .pdatalen = pdatalen,
+            .flags = flags,
+          },
+      };
 
       pvmsg = &vmsg;
     }
@@ -11549,12 +12141,17 @@ ngtcp2_ssize ngtcp2_conn_writev_datagram
     return NGTCP2_ERR_INVALID_ARGUMENT;
   }
 
-  vmsg.type = NGTCP2_VMSG_TYPE_DATAGRAM;
-  vmsg.datagram.dgram_id = dgram_id;
-  vmsg.datagram.flags = flags;
-  vmsg.datagram.data = datav;
-  vmsg.datagram.datacnt = datavcnt;
-  vmsg.datagram.paccepted = paccepted;
+  vmsg = (ngtcp2_vmsg){
+    .type = NGTCP2_VMSG_TYPE_DATAGRAM,
+    .datagram =
+      {
+        .data = datav,
+        .datacnt = datavcnt,
+        .dgram_id = dgram_id,
+        .paccepted = paccepted,
+        .flags = flags,
+      },
+  };
 
   if (flags & NGTCP2_WRITE_DATAGRAM_FLAG_PADDING) {
     wflags = NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY;
@@ -11610,27 +12207,29 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtc
       conn_client_write_handshake(conn, pi, dest, destlen, wflags, vmsg, ts);
     /* We might be unable to write a packet because of depletion of
        congestion window budget, perhaps due to packet loss that
-       shrinks the window drastically. */
-    if (nwrite <= 0) {
+       shrinks the window drastically.  Then continue if we are in
+       post-handshake.  There, we might be able to write packets
+       exceeding CWND to avoid deadlock. */
+    if (nwrite < 0) {
       return nwrite;
     }
     if (conn->state != NGTCP2_CS_POST_HANDSHAKE) {
       return nwrite;
     }
 
-    assert(nwrite);
-    assert(dest[0] & NGTCP2_HEADER_FORM_BIT);
-    assert(conn->negotiated_version);
+    if (nwrite) {
+      assert(dest[0] & NGTCP2_HEADER_FORM_BIT);
+      assert(conn->negotiated_version);
 
-    if (nwrite < NGTCP2_MAX_UDP_PAYLOAD_SIZE &&
-        ngtcp2_pkt_get_type_long(conn->negotiated_version, dest[0]) ==
+      if (ngtcp2_pkt_get_type_long(conn->negotiated_version, dest[0]) ==
           NGTCP2_PKT_INITIAL) {
-      wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
-    }
+        wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
+      }
 
-    res = nwrite;
-    dest += nwrite;
-    destlen -= (size_t)nwrite;
+      res = nwrite;
+      dest += nwrite;
+      destlen -= (size_t)nwrite;
+    }
     /* Break here so that we can coalesces 1RTT packet. */
     break;
   case NGTCP2_CS_SERVER_INITIAL:
@@ -11685,7 +12284,7 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtc
       dest += nwrite;
       destlen -= (size_t)nwrite;
 
-      if (res < NGTCP2_MAX_UDP_PAYLOAD_SIZE && conn->in_pktns && nwrite > 0) {
+      if (conn->in_pktns && nwrite > 0) {
         it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
         if (!ngtcp2_ksl_it_end(&it)) {
           rtbent = ngtcp2_ksl_it_get(&it);
@@ -11770,7 +12369,7 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtc
     if (!conn->pktns.rtb.probe_pkt_left && conn_cwnd_is_zero(conn)) {
       destlen = 0;
     } else {
-      if (res == 0) {
+      if (res == 0 && !(conn->flags & NGTCP2_CONN_FLAG_AGGREGATE_PKTS)) {
         nwrite =
           conn_write_path_response(conn, path, pi, dest, origdestlen, ts);
         if (nwrite) {
@@ -11832,9 +12431,22 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtc
         return nwrite;
       }
       if (nwrite > 0) {
+        /* This makes 1RTT packet padded.  If 1RTT packet is not going
+           to be sent, packet is already padded. */
+        if (ngtcp2_pkt_get_type_long(conn->negotiated_version, dest[0]) ==
+            NGTCP2_PKT_INITIAL) {
+          wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
+        }
+
         res = nwrite;
         dest += nwrite;
         destlen -= (size_t)nwrite;
+
+        /* We only exceed CWND to avoid deadlock.  Do no write 1RTT
+           packet if CWND is depleted. */
+        if (conn_cwnd_is_zero(conn) && conn->pktns.rtb.probe_pkt_left == 0) {
+          return res;
+        }
       } else if (destlen == 0) {
         res = conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts);
         if (res) {
@@ -11845,9 +12457,9 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtc
   }
 
   if (conn->pktns.rtb.probe_pkt_left) {
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
-                    "transmit probe pkt left=%zu",
-                    conn->pktns.rtb.probe_pkt_left);
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON,
+                     "transmit probe pkt left=%zu",
+                     conn->pktns.rtb.probe_pkt_left);
 
     nwrite = conn_write_pkt(conn, pi, dest, destlen, (size_t)res, vmsg,
                             NGTCP2_PKT_1RTT, wflags, ts);
@@ -11901,11 +12513,12 @@ conn_write_connection_close(ngtcp2_conn
   ngtcp2_frame fr;
   uint8_t flags = NGTCP2_WRITE_PKT_FLAG_NONE;
 
-  fr.type = NGTCP2_FRAME_CONNECTION_CLOSE;
-  fr.connection_close.error_code = error_code;
-  fr.connection_close.frame_type = 0;
-  fr.connection_close.reasonlen = reasonlen;
-  fr.connection_close.reason = (uint8_t *)reason;
+  fr.connection_close = (ngtcp2_connection_close){
+    .type = NGTCP2_FRAME_CONNECTION_CLOSE,
+    .error_code = error_code,
+    .reasonlen = reasonlen,
+    .reason = (uint8_t *)reason,
+  };
 
   if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) &&
       pkt_type != NGTCP2_PKT_INITIAL) {
@@ -12080,11 +12693,12 @@ ngtcp2_ssize ngtcp2_conn_write_applicati
 
   assert(conn->pktns.crypto.tx.ckm);
 
-  fr.type = NGTCP2_FRAME_CONNECTION_CLOSE_APP;
-  fr.connection_close.error_code = app_error_code;
-  fr.connection_close.frame_type = 0;
-  fr.connection_close.reasonlen = reasonlen;
-  fr.connection_close.reason = (uint8_t *)reason;
+  fr.connection_close = (ngtcp2_connection_close){
+    .type = NGTCP2_FRAME_CONNECTION_CLOSE_APP,
+    .error_code = app_error_code,
+    .reasonlen = reasonlen,
+    .reason = (uint8_t *)reason,
+  };
 
   nwrite = ngtcp2_conn_write_single_frame_pkt(
     conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE,
@@ -12108,11 +12722,12 @@ ngtcp2_ssize ngtcp2_conn_write_applicati
 static void ccerr_init(ngtcp2_ccerr *ccerr, ngtcp2_ccerr_type type,
                        uint64_t error_code, const uint8_t *reason,
                        size_t reasonlen) {
-  ccerr->type = type;
-  ccerr->error_code = error_code;
-  ccerr->frame_type = 0;
-  ccerr->reason = (uint8_t *)reason;
-  ccerr->reasonlen = reasonlen;
+  *ccerr = (ngtcp2_ccerr){
+    .type = type,
+    .error_code = error_code,
+    .reason = (uint8_t *)reason,
+    .reasonlen = reasonlen,
+  };
 }
 
 void ngtcp2_ccerr_default(ngtcp2_ccerr *ccerr) {
@@ -12147,7 +12762,7 @@ void ngtcp2_ccerr_set_liberr(ngtcp2_ccer
                reasonlen);
 
     return;
-  };
+  }
 
   ngtcp2_ccerr_set_transport_error(
     ccerr, ngtcp2_err_infer_quic_transport_error_code(liberr), reason,
@@ -12528,8 +13143,8 @@ int ngtcp2_conn_get_tls_early_data_rejec
   return (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) != 0;
 }
 
-int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
-                           ngtcp2_duration ack_delay, ngtcp2_tstamp ts) {
+void 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);
@@ -12550,13 +13165,13 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *
                rtt < cstat->min_rtt + ack_delay) {
       /* Ignore RTT sample if adjusting ack_delay causes the sample
          less than min_rtt before handshake confirmation. */
-      ngtcp2_log_info(
+      ngtcp2_log_infof(
         &conn->log, NGTCP2_LOG_EVENT_LDC,
         "ignore rtt sample because ack_delay is too large latest_rtt=%" PRIu64
         " min_rtt=%" PRIu64 " ack_delay=%" PRIu64,
         rtt / NGTCP2_MILLISECONDS, cstat->min_rtt / NGTCP2_MILLISECONDS,
         ack_delay / NGTCP2_MILLISECONDS);
-      return NGTCP2_ERR_INVALID_ARGUMENT;
+      return;
     }
 
     cstat->latest_rtt = rtt;
@@ -12573,7 +13188,7 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *
     cstat->smoothed_rtt = (cstat->smoothed_rtt * 7 + rtt) / 8;
   }
 
-  ngtcp2_log_info(
+  ngtcp2_log_infof(
     &conn->log, NGTCP2_LOG_EVENT_LDC,
     "latest_rtt=%" PRIu64 " min_rtt=%" PRIu64 " smoothed_rtt=%" PRIu64
     " rttvar=%" PRIu64 " ack_delay=%" PRIu64,
@@ -12581,23 +13196,12 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *
     cstat->min_rtt / NGTCP2_MILLISECONDS,
     cstat->smoothed_rtt / NGTCP2_MILLISECONDS,
     cstat->rttvar / NGTCP2_MILLISECONDS, ack_delay / NGTCP2_MILLISECONDS);
-
-  return 0;
 }
 
 void ngtcp2_conn_get_conn_info_versioned(ngtcp2_conn *conn,
                                          int conn_info_version,
                                          ngtcp2_conn_info *cinfo) {
-  const ngtcp2_conn_stat *cstat = &conn->cstat;
-  (void)conn_info_version;
-
-  cinfo->latest_rtt = cstat->latest_rtt;
-  cinfo->min_rtt = cstat->min_rtt;
-  cinfo->smoothed_rtt = cstat->smoothed_rtt;
-  cinfo->rttvar = cstat->rttvar;
-  cinfo->cwnd = cstat->cwnd;
-  cinfo->ssthresh = cstat->ssthresh;
-  cinfo->bytes_in_flight = cstat->bytes_in_flight;
+  ngtcp2_conn_info_init_versioned(conn_info_version, cinfo, &conn->cstat);
 }
 
 static void conn_get_loss_time_and_pktns(ngtcp2_conn *conn,
@@ -12679,9 +13283,10 @@ void ngtcp2_conn_set_loss_detection_time
   if (earliest_loss_time != UINT64_MAX) {
     cstat->loss_detection_timer = earliest_loss_time;
 
-    ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
-                    "loss_detection_timer=%" PRIu64 " nonzero crypto loss time",
-                    cstat->loss_detection_timer);
+    ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC,
+                     "loss_detection_timer=%" PRIu64
+                     " nonzero crypto loss time",
+                     cstat->loss_detection_timer);
     return;
   }
 
@@ -12705,9 +13310,9 @@ void ngtcp2_conn_set_loss_detection_time
   timeout =
     cstat->loss_detection_timer > ts ? cstat->loss_detection_timer - ts : 0;
 
-  ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC,
-                  "loss_detection_timer=%" PRIu64 " timeout=%" PRIu64,
-                  cstat->loss_detection_timer, timeout / NGTCP2_MILLISECONDS);
+  ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC,
+                   "loss_detection_timer=%" PRIu64 " timeout=%" PRIu64,
+                   cstat->loss_detection_timer, timeout / NGTCP2_MILLISECONDS);
 }
 
 void ngtcp2_conn_cancel_loss_detection_timer(ngtcp2_conn *conn) {
@@ -12779,8 +13384,8 @@ int ngtcp2_conn_on_loss_detection_timer(
 
   ++cstat->pto_count;
 
-  ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "pto_count=%zu",
-                  cstat->pto_count);
+  ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC, "pto_count=%zu",
+                   cstat->pto_count);
 
   ngtcp2_conn_set_loss_detection_timer(conn, ts);
 
@@ -12821,7 +13426,6 @@ int ngtcp2_conn_submit_crypto_data(ngtcp
                                    const uint8_t *data, const size_t datalen) {
   ngtcp2_pktns *pktns;
   ngtcp2_frame_chain *frc;
-  ngtcp2_stream *fr;
   int rv;
 
   if (datalen == 0) {
@@ -12849,21 +13453,22 @@ int ngtcp2_conn_submit_crypto_data(ngtcp
     return rv;
   }
 
-  rv = ngtcp2_frame_chain_objalloc_new(&frc, &conn->frc_objalloc);
+  rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
+    &frc, 1, &conn->frc_objalloc, conn->mem);
   if (rv != 0) {
     return rv;
   }
 
-  fr = &frc->fr.stream;
-
-  fr->type = NGTCP2_FRAME_CRYPTO;
-  fr->flags = 0;
-  fr->fin = 0;
-  fr->stream_id = 0;
-  fr->offset = pktns->crypto.tx.offset;
-  fr->datacnt = 1;
-  fr->data[0].len = datalen;
-  fr->data[0].base = (uint8_t *)data;
+  frc->fr.stream.type = NGTCP2_FRAME_CRYPTO;
+  frc->fr.stream.flags = 0;
+  frc->fr.stream.fin = 0;
+  frc->fr.stream.stream_id = 0;
+  frc->fr.stream.offset = pktns->crypto.tx.offset;
+  frc->fr.stream.datacnt = 1;
+  frc->fr.stream.data[0] = (ngtcp2_vec){
+    .base = (uint8_t *)data,
+    .len = datalen,
+  };
 
   rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, frc);
   if (rv != 0) {
@@ -12968,20 +13573,46 @@ static size_t conn_get_num_active_dcid(n
   return n;
 }
 
-static void copy_dcid_to_cid_token(ngtcp2_cid_token *dest,
+size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest) {
+  ngtcp2_cid_token2 cid_tokens[/* current */ 1 + /* pv */ 2 +
+                               NGTCP2_DCIDTR_MAX_RETIRED_DCID_SIZE];
+  size_t n, i;
+
+  if (!dest) {
+    return ngtcp2_conn_get_active_dcid2(conn, NULL);
+  }
+
+  n = ngtcp2_conn_get_active_dcid2(conn, cid_tokens);
+
+  for (i = 0; i < n; ++i) {
+    dest[i].seq = cid_tokens[i].seq;
+    dest[i].cid = cid_tokens[i].cid;
+    ngtcp2_path_storage_init2(&dest[i].ps, &cid_tokens[i].ps.path);
+    dest[i].token_present = cid_tokens[i].token_present;
+
+    if (dest[i].token_present) {
+      memcpy(dest[i].token, cid_tokens[i].token.data, sizeof(dest[i].token));
+    }
+  }
+
+  return n;
+}
+
+static void copy_dcid_to_cid_token(ngtcp2_cid_token2 *dest,
                                    const ngtcp2_dcid *src) {
   dest->seq = src->seq;
   dest->cid = src->cid;
   ngtcp2_path_storage_init2(&dest->ps, &src->ps.path);
   if ((dest->token_present =
          (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) != 0)) {
-    memcpy(dest->token, src->token, NGTCP2_STATELESS_RESET_TOKENLEN);
+    dest->token = src->token;
   }
 }
 
-size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest) {
+size_t ngtcp2_conn_get_active_dcid2(ngtcp2_conn *conn,
+                                    ngtcp2_cid_token2 *dest) {
   ngtcp2_pv *pv = conn->pv;
-  ngtcp2_cid_token *orig = dest;
+  ngtcp2_cid_token2 *orig = dest;
   ngtcp2_dcid *dcid;
   size_t len, i;
 
@@ -13138,7 +13769,12 @@ int ngtcp2_conn_initiate_immediate_migra
     conn->pv = pv;
   }
 
-  return conn_call_activate_dcid(conn, &conn->dcid.current);
+  rv = conn_call_activate_dcid(conn, &conn->dcid.current);
+  if (rv != 0) {
+    return rv;
+  }
+
+  return conn_call_begin_path_validation(conn, conn->pv);
 }
 
 int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path,
@@ -13178,7 +13814,12 @@ int ngtcp2_conn_initiate_migration(ngtcp
 
   conn->pv = pv;
 
-  return conn_call_activate_dcid(conn, &pv->dcid);
+  rv = conn_call_activate_dcid(conn, &pv->dcid);
+  if (rv != 0) {
+    return rv;
+  }
+
+  return conn_call_begin_path_validation(conn, conn->pv);
 }
 
 uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn) {
@@ -13354,8 +13995,17 @@ int ngtcp2_conn_set_stream_user_data(ngt
   return 0;
 }
 
+void *ngtcp2_conn_get_stream_user_data(ngtcp2_conn *conn, int64_t stream_id) {
+  ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id);
+
+  if (strm == NULL) {
+    return NULL;
+  }
+
+  return strm->stream_user_data;
+}
+
 void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
-  uint64_t pacing_interval_m;
   ngtcp2_duration wait, d;
 
   conn_update_timestamp(conn, ts);
@@ -13364,20 +14014,9 @@ void ngtcp2_conn_update_pkt_tx_time(ngtc
     return;
   }
 
-  if (conn->cstat.pacing_interval_m) {
-    pacing_interval_m = conn->cstat.pacing_interval_m;
-  } else {
-    /* 1.25 is the under-utilization avoidance factor described in
-       https://datatracker.ietf.org/doc/html/rfc9002#section-7.7 */
-    pacing_interval_m = ((conn->cstat.first_rtt_sample_ts == UINT64_MAX
-                            ? NGTCP2_MILLISECONDS
-                            : conn->cstat.smoothed_rtt)
-                         << 10) *
-                        100 / 125 / conn->cstat.cwnd;
-    pacing_interval_m = ngtcp2_max_uint64(pacing_interval_m, 1);
-  }
-
-  wait = (ngtcp2_duration)((conn->tx.pacing.pktlen * pacing_interval_m) >> 10);
+  wait = (ngtcp2_duration)((conn->tx.pacing.pktlen *
+                            conn->cstat.pacing_interval_m) >>
+                           10);
 
   d = ngtcp2_min_uint64(wait / 2, conn->tx.pacing.compensation);
   wait -= d;
@@ -13411,6 +14050,115 @@ void ngtcp2_conn_add_path_history(ngtcp2
   ent->ts = ts;
 }
 
+ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt_versioned(
+  ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
+  ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen,
+  ngtcp2_write_pkt write_pkt, ngtcp2_tstamp ts) {
+  ngtcp2_ssize nwrite;
+
+  buflen = ngtcp2_min_size(buflen, ngtcp2_conn_get_send_quantum(conn));
+
+  nwrite = ngtcp2_conn_write_aggregate_pkt2_versioned(
+    conn, path, pkt_info_version, pi, buf, buflen, pgsolen, write_pkt, 0, ts);
+  if (nwrite < 0) {
+    return nwrite;
+  }
+
+  ngtcp2_conn_update_pkt_tx_time(conn, ts);
+
+  return nwrite;
+}
+
+ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt2_versioned(
+  ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
+  ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen,
+  ngtcp2_write_pkt write_pkt, size_t num_pkts, ngtcp2_tstamp ts) {
+  size_t max_udp_payloadlen = ngtcp2_conn_get_max_tx_udp_payload_size(conn);
+  size_t path_max_udp_payloadlen =
+    ngtcp2_conn_get_path_max_tx_udp_payload_size(conn);
+  ngtcp2_ssize nwrite;
+  uint8_t *wbuf = buf;
+  size_t wbuflen;
+  ngtcp2_ecn_state ecn_state;
+  int first_pkt;
+  ngtcp2_pkt_info pi_discard;
+  ngtcp2_path_storage path_discard;
+  (void)pkt_info_version;
+
+  assert(buflen >= path_max_udp_payloadlen);
+
+  if (num_pkts == 0) {
+    num_pkts = SIZE_MAX;
+  }
+
+  for (;;) {
+    ecn_state = conn->tx.ecn.state;
+
+    wbuflen = buflen >= max_udp_payloadlen ? max_udp_payloadlen
+                                           : path_max_udp_payloadlen;
+
+    nwrite = write_pkt(conn, path, pi, wbuf, wbuflen, ts, conn->user_data);
+    if (nwrite < 0) {
+      break;
+    }
+
+    if (nwrite == 0) {
+      nwrite = wbuf - buf;
+      break;
+    }
+
+    first_pkt = buf == wbuf;
+    wbuf += nwrite;
+    buflen -= (size_t)nwrite;
+
+    --num_pkts;
+
+    if (first_pkt) {
+      assert(!(conn->flags & NGTCP2_CONN_FLAG_AGGREGATE_PKTS));
+
+      *pgsolen = (size_t)nwrite;
+
+      if ((size_t)nwrite != path_max_udp_payloadlen ||
+          buflen < path_max_udp_payloadlen || ecn_state != conn->tx.ecn.state ||
+          num_pkts == 0) {
+        nwrite = wbuf - buf;
+        break;
+      }
+
+      /* All aggregated packets should share the same path and pi.
+         Pass the placeholder values to the callback because they
+         might be overwritten by later calls, especially pi is set to
+         empty when no packet is produced. */
+      if (path) {
+        ngtcp2_path_storage_zero(&path_discard);
+        path = &path_discard.path;
+      }
+
+      if (pi) {
+        pi = &pi_discard;
+      }
+
+      conn->flags |= NGTCP2_CONN_FLAG_AGGREGATE_PKTS;
+
+      continue;
+    }
+
+    if (buflen < path_max_udp_payloadlen || (size_t)nwrite < *pgsolen ||
+        ecn_state != conn->tx.ecn.state || num_pkts == 0) {
+      nwrite = wbuf - buf;
+      break;
+    }
+  }
+
+  conn->flags &= ~NGTCP2_CONN_FLAG_AGGREGATE_PKTS;
+
+  return nwrite;
+}
+
+ngtcp2_tstamp ngtcp2_conn_get_timestamp(const ngtcp2_conn *conn) {
+  return conn->log.last_ts;
+}
+
 const ngtcp2_path_history_entry *
 ngtcp2_conn_find_path_history(ngtcp2_conn *conn, const ngtcp2_path *path,
                               ngtcp2_tstamp ts) {
@@ -13434,9 +14182,9 @@ ngtcp2_conn_find_path_history(ngtcp2_con
 
 void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent,
                                       const ngtcp2_path *path,
-                                      const uint8_t *data) {
+                                      const ngtcp2_path_challenge_data *data) {
   ngtcp2_path_storage_init2(&pcent->ps, path);
-  memcpy(pcent->data, data, sizeof(pcent->data));
+  pcent->data = *data;
 }
 
 /* The functions prefixed with ngtcp2_pkt_ are usually put inside
@@ -13454,7 +14202,7 @@ ngtcp2_ssize ngtcp2_pkt_write_connection
   ngtcp2_crypto_km ckm;
   ngtcp2_crypto_cc cc;
   ngtcp2_ppe ppe;
-  ngtcp2_frame fr = {0};
+  ngtcp2_frame fr;
   int rv;
 
   ngtcp2_pkt_hd_init(&hd, NGTCP2_PKT_FLAG_LONG_FORM, NGTCP2_PKT_INITIAL, dcid,
@@ -13485,11 +14233,12 @@ ngtcp2_ssize ngtcp2_pkt_write_connection
     return NGTCP2_ERR_NOBUF;
   }
 
-  fr.type = NGTCP2_FRAME_CONNECTION_CLOSE;
-  fr.connection_close.error_code = error_code;
-  fr.connection_close.frame_type = 0;
-  fr.connection_close.reasonlen = reasonlen;
-  fr.connection_close.reason = (uint8_t *)reason;
+  fr.connection_close = (ngtcp2_connection_close){
+    .type = NGTCP2_FRAME_CONNECTION_CLOSE,
+    .error_code = error_code,
+    .reasonlen = reasonlen,
+    .reason = (uint8_t *)reason,
+  };
 
   rv = ngtcp2_ppe_encode_frame(&ppe, &fr);
   if (rv != 0) {
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conn.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conn.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conn.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conn.h	2026-05-15 15:49:15.160978300 +0200
@@ -52,6 +52,8 @@
 #include "ngtcp2_rst.h"
 #include "ngtcp2_conn_stat.h"
 #include "ngtcp2_dcidtr.h"
+#include "ngtcp2_pcg.h"
+#include "ngtcp2_ratelim.h"
 
 typedef enum {
   /* Client specific handshake states */
@@ -75,10 +77,6 @@ typedef enum {
    unreceived data. */
 #define NGTCP2_MAX_REORDERED_CRYPTO_DATA 65536
 
-/* NGTCP2_MAX_RETRIES is the number of Retry packet which client can
-   accept. */
-#define NGTCP2_MAX_RETRIES 3
-
 /* NGTCP2_MAX_SCID_POOL_SIZE is the maximum number of source
    connection ID the local endpoint provides to the remote endpoint.
    The chosen value was described in old draft.  Now a remote endpoint
@@ -96,48 +94,35 @@ typedef enum {
 #define NGTCP2_CCERR_MAX_REASONLEN 1024
 
 /* NGTCP2_WRITE_PKT_FLAG_NONE indicates that no flag is set. */
-#define NGTCP2_WRITE_PKT_FLAG_NONE 0x00u
+#define NGTCP2_WRITE_PKT_FLAG_NONE 0x00U
 /* NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING indicates that packet other
    than Initial packet should be padded so that UDP datagram payload
    is at least NGTCP2_MAX_UDP_PAYLOAD_SIZE bytes.  Initial packet
    might be padded based on QUIC requirement regardless of this
    flag. */
-#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING 0x01u
+#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING 0x01U
 /* NGTCP2_WRITE_PKT_FLAG_MORE indicates that more frames might come
    and it should be encoded into the current packet. */
-#define NGTCP2_WRITE_PKT_FLAG_MORE 0x02u
+#define NGTCP2_WRITE_PKT_FLAG_MORE 0x02U
 /* NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL is just like
    NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING, but it requests to add
    padding to the full UDP datagram payload size. */
-#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL 0x04u
+#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL 0x04U
 /* NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY adds padding to the QUIC
    packet as much as possible if the packet is not empty. */
-#define NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY 0x08u
-
-/*
- * ngtcp2_max_frame is defined so that it covers the largest ACK
- * frame.
- */
-typedef union ngtcp2_max_frame {
-  ngtcp2_frame fr;
-  struct {
-    ngtcp2_ack ack;
-    /* ack includes 1 ngtcp2_ack_range. */
-    ngtcp2_ack_range ranges[NGTCP2_MAX_ACK_RANGES - 1];
-  } ackfr;
-} ngtcp2_max_frame;
+#define NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY 0x08U
 
 typedef struct ngtcp2_path_challenge_entry {
   ngtcp2_path_storage ps;
-  uint8_t data[8];
+  ngtcp2_path_challenge_data data;
 } ngtcp2_path_challenge_entry;
 
 void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent,
                                       const ngtcp2_path *path,
-                                      const uint8_t *data);
+                                      const ngtcp2_path_challenge_data *data);
 
 /* NGTCP2_CONN_FLAG_NONE indicates that no flag is set. */
-#define NGTCP2_CONN_FLAG_NONE 0x00u
+#define NGTCP2_CONN_FLAG_NONE 0x00U
 /* NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED is set when TLS stack
    declares that TLS handshake has completed.  The condition of this
    declaration varies between TLS implementations and this flag does
@@ -145,61 +130,69 @@ void ngtcp2_path_challenge_entry_init(ng
    implementations declare TLS handshake completion as server when
    they write off Server Finished and before deriving application rx
    secret. */
-#define NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED 0x01u
+#define NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED 0x01U
 /* NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED is set when the first
    Initial packet has successfully been processed. */
-#define NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED 0x02u
+#define NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED 0x02U
 /* NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED is set if transport
    parameters are received. */
-#define NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED 0x04u
+#define NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED 0x04U
 /* NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED is set when a
    local transport parameters are applied. */
-#define NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED 0x08u
+#define NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED 0x08U
 /* NGTCP2_CONN_FLAG_RECV_RETRY is set when a client receives Retry
    packet. */
-#define NGTCP2_CONN_FLAG_RECV_RETRY 0x10u
+#define NGTCP2_CONN_FLAG_RECV_RETRY 0x10U
 /* NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED is set when 0-RTT packet is
    rejected by a peer. */
-#define NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED 0x20u
+#define NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED 0x20U
 /* NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED is set when the expired
    keep-alive timer has been cancelled. */
-#define NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED 0x40u
+#define NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED 0x40U
 /* NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED is set when an endpoint
    confirmed completion of handshake. */
-#define NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED 0x80u
+#define NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED 0x80U
 /* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED is set when the library
    transitions its state to "post handshake". */
-#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x0100u
+#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x0100U
 /* NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT is set when the early
    handshake retransmission has done when server receives overlapping
    Initial crypto data. */
-#define NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT 0x0200u
+#define NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT 0x0200U
 /* NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT indicates that the local endpoint
    sends a QUIC packet without Fixed Bit set if a remote endpoint
    supports Greasing QUIC Bit extension. */
-#define NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT 0x0400u
+#define NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT 0x0400U
 /* NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED is set when key update is
    not confirmed by the local endpoint.  That is, it has not received
    ACK frame which acknowledges packet which is encrypted with new
    key. */
-#define NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED 0x0800u
+#define NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED 0x0800U
 /* NGTCP2_CONN_FLAG_PPE_PENDING is set when
    NGTCP2_WRITE_STREAM_FLAG_MORE is used and the intermediate state of
    ngtcp2_ppe is stored in pkt struct of ngtcp2_conn. */
-#define NGTCP2_CONN_FLAG_PPE_PENDING 0x1000u
+#define NGTCP2_CONN_FLAG_PPE_PENDING 0x1000U
 /* NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE is set when idle timer
    should be restarted on next write. */
-#define NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE 0x2000u
+#define NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE 0x2000U
 /* NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED indicates that server as peer
    verified client address.  This flag is only used by client. */
-#define NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED 0x4000u
+#define NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED 0x4000U
 /* NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED indicates that an early key is
    installed.  conn->early.ckm cannot be used for this purpose because
    it might be discarded when a certain condition is met. */
-#define NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED 0x8000u
+#define NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED 0x8000U
 /* NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR is set when the local
    endpoint has initiated key update. */
-#define NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR 0x10000u
+#define NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR 0x10000U
+/* NGTCP2_CONN_FLAG_AGGREGATE_PKTS is set when
+   ngtcp2_conn_writev_stream is called inside the callback invoked by
+   ngtcp2_conn_write_aggregate_pkt. */
+#define NGTCP2_CONN_FLAG_AGGREGATE_PKTS 0x20000U
+/* NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO, if set, crumbles an
+   Initial CRYPTO frame into pieces as a countermeasure against Deep
+   Packet Inspection. */
+#define NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO 0x40000U
 
 typedef struct ngtcp2_pktns {
   struct {
@@ -394,14 +387,14 @@ struct ngtcp2_conn {
     ngtcp2_tstamp last_max_data_ts;
 
     struct {
-      /* state is the state of ECN validation */
-      ngtcp2_ecn_state state;
       /* validation_start_ts is the timestamp when ECN validation is
          started.  It is UINT64_MAX if it has not started yet. */
       ngtcp2_tstamp validation_start_ts;
       /* dgram_sent is the number of UDP datagram sent during ECN
          validation period. */
       size_t dgram_sent;
+      /* state is the state of ECN validation */
+      ngtcp2_ecn_state state;
     } ecn;
 
     struct {
@@ -552,13 +545,13 @@ struct ngtcp2_conn {
     /* retry_aead_ctx is AEAD cipher context to verify Retry packet
        integrity.  It is used by client only. */
     ngtcp2_crypto_aead_ctx retry_aead_ctx;
+    /* decryption_failure_count is the number of received packets that
+       fail authentication. */
+    uint64_t decryption_failure_count;
     /* tls_error is TLS related error. */
     int tls_error;
     /* tls_alert is TLS alert generated by the local endpoint. */
     uint8_t tls_alert;
-    /* decryption_failure_count is the number of received packets that
-       fail authentication. */
-    uint64_t decryption_failure_count;
   } crypto;
 
   /* pkt contains the packet intermediate construction data to support
@@ -568,13 +561,13 @@ struct ngtcp2_conn {
     ngtcp2_pkt_hd hd;
     ngtcp2_ppe ppe;
     ngtcp2_frame_chain **pfrc;
+    ngtcp2_ssize hs_spktlen;
     int pkt_empty;
     int hd_logged;
+    int require_padding;
     /* flags is bitwise OR of zero or more of
        NGTCP2_RTB_ENTRY_FLAG_*. */
     uint16_t rtb_entry_flags;
-    ngtcp2_ssize hs_spktlen;
-    int require_padding;
   } pkt;
 
   struct {
@@ -630,7 +623,6 @@ struct ngtcp2_conn {
   ngtcp2_log log;
   ngtcp2_qlog qlog;
   ngtcp2_rst rst;
-  ngtcp2_cc_algo cc_algo;
   union {
     ngtcp2_cc cc;
     ngtcp2_cc_reno reno;
@@ -641,17 +633,23 @@ struct ngtcp2_conn {
      successfully.  The path is added to this history when a local
      endpoint migrates to the another path. */
   ngtcp2_static_ringbuf_path_history path_history;
+  /* glitch_rlim is the rate limit of glitches that can be tolerated.
+     If more than those glitches are detected, a connection is
+     closed. */
+  ngtcp2_ratelim glitch_rlim;
   const ngtcp2_mem *mem;
   /* idle_ts is the time instant when idle timer started. */
   ngtcp2_tstamp idle_ts;
   /* handshake_confirmed_ts is the time instant when handshake is
      confirmed.  For server, it is confirmed when completed. */
   ngtcp2_tstamp handshake_confirmed_ts;
+  ngtcp2_pcg32 pcg;
   void *user_data;
   uint32_t client_chosen_version;
   uint32_t negotiated_version;
   /* flags is bitwise OR of zero or more of NGTCP2_CONN_FLAG_*. */
   uint32_t flags;
+  ngtcp2_cc_algo cc_algo;
   int server;
 };
 
@@ -663,9 +661,6 @@ typedef enum ngtcp2_vmsg_type {
 typedef struct ngtcp2_vmsg_stream {
   /* strm is a stream that data is sent to. */
   ngtcp2_strm *strm;
-  /* flags is bitwise OR of zero or more of
-     NGTCP2_WRITE_STREAM_FLAG_*. */
-  uint32_t flags;
   /* data is the pointer to ngtcp2_vec array which contains the stream
      data to send. */
   const ngtcp2_vec *data;
@@ -674,6 +669,9 @@ typedef struct ngtcp2_vmsg_stream {
   /* pdatalen is the pointer to the variable which the number of bytes
      written is assigned to if pdatalen is not NULL. */
   ngtcp2_ssize *pdatalen;
+  /* flags is bitwise OR of zero or more of
+     NGTCP2_WRITE_STREAM_FLAG_*. */
+  uint32_t flags;
 } ngtcp2_vmsg_stream;
 
 typedef struct ngtcp2_vmsg_datagram {
@@ -684,12 +682,12 @@ typedef struct ngtcp2_vmsg_datagram {
   size_t datacnt;
   /* dgram_id is an opaque identifier chosen by an application. */
   uint64_t dgram_id;
-  /* flags is bitwise OR of zero or more of
-     NGTCP2_WRITE_DATAGRAM_FLAG_*. */
-  uint32_t flags;
   /* paccepted is the pointer to the variable which, if it is not
      NULL, is assigned nonzero if data is written to a packet. */
   int *paccepted;
+  /* flags is bitwise OR of zero or more of
+     NGTCP2_WRITE_DATAGRAM_FLAG_*. */
+  uint32_t flags;
 } ngtcp2_vmsg_datagram;
 
 typedef struct ngtcp2_vmsg {
@@ -757,15 +755,9 @@ int ngtcp2_conn_close_stream_if_shut_rdw
  * ack_delay included in ACK frame.  |ack_delay| is actually tainted
  * (sent by peer), so don't assume that |ack_delay| is always smaller
  * than, or equals to |rtt|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_INVALID_ARGUMENT
- *     RTT sample is ignored.
  */
-int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
-                           ngtcp2_duration ack_delay, ngtcp2_tstamp ts);
+void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
+                            ngtcp2_duration ack_delay, ngtcp2_tstamp ts);
 
 void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts);
 
@@ -951,7 +943,7 @@ ngtcp2_conn_server_negotiate_version(ngt
  * @function
  *
  * `ngtcp2_conn_write_connection_close_pkt` writes a packet which
- * contains a CONNECTION_CLOSE frame (type 0x1c) in the buffer pointed
+ * contains a CONNECTION_CLOSE frame (type 0x1C) in the buffer pointed
  * by |dest| whose capacity is |datalen|.
  *
  * If |path| is not ``NULL``, this function stores the network path
@@ -993,7 +985,7 @@ ngtcp2_ssize ngtcp2_conn_write_connectio
  * @function
  *
  * `ngtcp2_conn_write_application_close_pkt` writes a packet which
- * contains a CONNECTION_CLOSE frame (type 0x1d) in the buffer pointed
+ * contains a CONNECTION_CLOSE frame (type 0x1D) in the buffer pointed
  * by |dest| whose capacity is |datalen|.
  *
  * If |path| is not ``NULL``, this function stores the network path
@@ -1006,7 +998,7 @@ ngtcp2_ssize ngtcp2_conn_write_connectio
  * if it succeeds.  The metadata includes ECN markings.
  *
  * If handshake has not been confirmed yet, CONNECTION_CLOSE (type
- * 0x1c) with error code :macro:`NGTCP2_APPLICATION_ERROR` is written
+ * 0x1C) with error code :macro:`NGTCP2_APPLICATION_ERROR` is written
  * instead.
  *
  * This function must not be called from inside the callback
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conn_info.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conn_info.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conn_info.c	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conn_info.c	2026-05-15 15:49:15.160978300 +0200
@@ -0,0 +1,50 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2025 ngtcp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "ngtcp2_conn_info.h"
+#include "ngtcp2_conn_stat.h"
+
+void ngtcp2_conn_info_init_versioned(int conn_info_version,
+                                     ngtcp2_conn_info *cinfo,
+                                     const ngtcp2_conn_stat *cstat) {
+  cinfo->latest_rtt = cstat->latest_rtt;
+  cinfo->min_rtt = cstat->min_rtt;
+  cinfo->smoothed_rtt = cstat->smoothed_rtt;
+  cinfo->rttvar = cstat->rttvar;
+  cinfo->cwnd = cstat->cwnd;
+  cinfo->ssthresh = cstat->ssthresh;
+  cinfo->bytes_in_flight = cstat->bytes_in_flight;
+
+  switch (conn_info_version) {
+  case NGTCP2_CONN_INFO_V2:
+    cinfo->pkt_sent = cstat->pkt_sent;
+    cinfo->bytes_sent = cstat->bytes_sent;
+    cinfo->pkt_recv = cstat->pkt_recv;
+    cinfo->bytes_recv = cstat->bytes_recv;
+    cinfo->pkt_lost = cstat->pkt_lost;
+    cinfo->bytes_lost = cstat->bytes_lost;
+    cinfo->ping_recv = cstat->ping_recv;
+    cinfo->pkt_discarded = cstat->pkt_discarded;
+  }
+}
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conn_info.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conn_info.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conn_info.h	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conn_info.h	2026-05-15 15:49:15.160978300 +0200
@@ -0,0 +1,45 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2025 ngtcp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGTCP2_CONN_INFO_H
+#define NGTCP2_CONN_INFO_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif /* defined(HAVE_CONFIG_H) */
+
+#include <ngtcp2/ngtcp2.h>
+
+typedef struct ngtcp2_conn_stat ngtcp2_conn_stat;
+
+/*
+ * ngtcp2_conn_info_init_versioned initializes |cinfo| of version
+ * |conn_info_version| from |cstat|.  This function only fills the
+ * fields of |cinfo| that are available in the specified version.
+ */
+void ngtcp2_conn_info_init_versioned(int conn_info_version,
+                                     ngtcp2_conn_info *cinfo,
+                                     const ngtcp2_conn_stat *cstat);
+
+#endif /* !defined(NGTCP2_CONN_INFO_H) */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conn_stat.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conn_stat.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conn_stat.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conn_stat.h	2026-05-15 15:49:15.161978500 +0200
@@ -31,6 +31,8 @@
 
 #include <ngtcp2/ngtcp2.h>
 
+#include "ngtcp2_pktns_id.h"
+
 /**
  * @struct
  *
@@ -128,6 +130,43 @@ typedef struct ngtcp2_conn_stat {
    * scheduled and transmitted together.
    */
   size_t send_quantum;
+  /*
+   * pkt_sent is the number of QUIC packets sent.
+   */
+  uint64_t pkt_sent;
+  /*
+   * bytes_sent is the number of bytes (the sum of QUIC packet length)
+   * sent.
+   */
+  uint64_t bytes_sent;
+  /*
+   * pkt_recv is the number of QUIC packets received, excluding
+   * discarded ones.
+   */
+  uint64_t pkt_recv;
+  /*
+   * bytes_recv is the number of bytes (the sum of QUIC packet length)
+   * received, excluding discarded ones.
+   */
+  uint64_t bytes_recv;
+  /*
+   * pkt_lost is the number of QUIC packets that are considered lost,
+   * excluding PMTUD packets.
+   */
+  uint64_t pkt_lost;
+  /*
+   * bytes_lost is the number of bytes (the sum of QUIC packet length)
+   * lost, excluding PMTUD packets.
+   */
+  uint64_t bytes_lost;
+  /*
+   * ping_recv is the number of PING frames received.
+   */
+  uint64_t ping_recv;
+  /*
+   * pkt_discarded is the number of QUIC packets discarded.
+   */
+  uint64_t pkt_discarded;
 } ngtcp2_conn_stat;
 
 #endif /* !defined(NGTCP2_CONN_STAT_H) */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conv.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conv.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_conv.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_conv.c	2026-05-15 15:49:15.161978500 +0200
@@ -63,33 +63,33 @@ const uint8_t *ngtcp2_get_uint16(uint16_
 }
 
 static const uint8_t *get_uvarint(uint64_t *dest, const uint8_t *p) {
-  union {
-    uint8_t n8;
-    uint16_t n16;
-    uint32_t n32;
-    uint64_t n64;
-  } n;
+  uint16_t n16;
+  uint32_t n32;
+  uint64_t n64;
 
   switch (*p >> 6) {
   case 0:
     *dest = *p++;
     return p;
   case 1:
-    memcpy(&n, p, 2);
-    n.n8 &= 0x3f;
-    *dest = ngtcp2_ntohs(n.n16);
+    memcpy(&n16, p, 2);
+    n16 = ngtcp2_ntohs(n16);
+    n16 &= 0x3FFF;
+    *dest = n16;
 
     return p + 2;
   case 2:
-    memcpy(&n, p, 4);
-    n.n8 &= 0x3f;
-    *dest = ngtcp2_ntohl(n.n32);
+    memcpy(&n32, p, 4);
+    n32 = ngtcp2_ntohl(n32);
+    n32 &= 0x3FFFFFFF;
+    *dest = n32;
 
     return p + 4;
   case 3:
-    memcpy(&n, p, 8);
-    n.n8 &= 0x3f;
-    *dest = ngtcp2_ntohl64(n.n64);
+    memcpy(&n64, p, 8);
+    n64 = ngtcp2_ntohl64(n64);
+    n64 &= 0x3FFFFFFFFFFFFFFF;
+    *dest = n64;
 
     return p + 8;
   default:
@@ -168,7 +168,7 @@ uint8_t *ngtcp2_put_uvarint(uint8_t *p,
   }
   assert(n < 4611686018427387904ULL);
   rv = ngtcp2_put_uint64be(p, n);
-  *p |= 0xc0;
+  *p |= 0xC0;
   return rv;
 }
 
@@ -200,7 +200,7 @@ uint8_t *ngtcp2_put_pkt_num(uint8_t *p,
 }
 
 size_t ngtcp2_get_uvarintlen(const uint8_t *p) {
-  return (size_t)(1u << (*p >> 6));
+  return (size_t)(1U << (*p >> 6));
 }
 
 size_t ngtcp2_put_uvarintlen(uint64_t n) {
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_crypto.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_crypto.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_crypto.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_crypto.c	2026-05-15 15:49:15.161978500 +0200
@@ -65,15 +65,21 @@ int ngtcp2_crypto_km_nocopy_new(ngtcp2_c
   }
 
   p = (uint8_t *)(*pckm) + sizeof(ngtcp2_crypto_km);
-  (*pckm)->secret.base = p;
-  (*pckm)->secret.len = secretlen;
-  p += secretlen;
-  (*pckm)->iv.base = p;
-  (*pckm)->iv.len = ivlen;
-  (*pckm)->aead_ctx.native_handle = NULL;
-  (*pckm)->pkt_num = -1;
-  (*pckm)->use_count = 0;
-  (*pckm)->flags = NGTCP2_CRYPTO_KM_FLAG_NONE;
+
+  **pckm = (ngtcp2_crypto_km){
+    .secret =
+      {
+        .base = p,
+        .len = secretlen,
+      },
+    .iv =
+      {
+        .base = p + secretlen,
+        .len = ivlen,
+      },
+    .pkt_num = -1,
+    .flags = NGTCP2_CRYPTO_KM_FLAG_NONE,
+  };
 
   return 0;
 }
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_crypto.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_crypto.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_crypto.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_crypto.h	2026-05-15 15:49:15.161978500 +0200
@@ -42,10 +42,10 @@
 #define NGTCP2_MAX_AEAD_OVERHEAD 16
 
 /* NGTCP2_CRYPTO_KM_FLAG_NONE indicates that no flag is set. */
-#define NGTCP2_CRYPTO_KM_FLAG_NONE 0x00u
+#define NGTCP2_CRYPTO_KM_FLAG_NONE 0x00U
 /* NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE is set if key phase bit is
    set. */
-#define NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE 0x01u
+#define NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE 0x01U
 
 typedef struct ngtcp2_crypto_km {
   ngtcp2_vec secret;
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_dcidtr.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_dcidtr.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_dcidtr.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_dcidtr.c	2026-05-15 15:49:15.161978500 +0200
@@ -157,9 +157,9 @@ int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidt
   return 0;
 }
 
-int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr,
-                                         const ngtcp2_path *path,
-                                         const uint8_t *token) {
+int ngtcp2_dcidtr_verify_stateless_reset(
+  const ngtcp2_dcidtr *dtr, const ngtcp2_path *path,
+  const ngtcp2_stateless_reset_token *token) {
   const ngtcp2_dcid *dcid;
   const ngtcp2_ringbuf *rb = &dtr->bound.rb;
   size_t i, len = ngtcp2_ringbuf_len(rb);
@@ -176,7 +176,7 @@ int ngtcp2_dcidtr_verify_stateless_reset
 
 static int verify_token_uniqueness(const ngtcp2_ringbuf *rb, int *pfound,
                                    uint64_t seq, const ngtcp2_cid *cid,
-                                   const uint8_t *token) {
+                                   const ngtcp2_stateless_reset_token *token) {
   const ngtcp2_dcid *dcid;
   size_t i, len = ngtcp2_ringbuf_len(rb);
   int rv;
@@ -196,9 +196,9 @@ static int verify_token_uniqueness(const
   return 0;
 }
 
-int ngtcp2_dcidtr_verify_token_uniqueness(const ngtcp2_dcidtr *dtr, int *pfound,
-                                          uint64_t seq, const ngtcp2_cid *cid,
-                                          const uint8_t *token) {
+int ngtcp2_dcidtr_verify_token_uniqueness(
+  const ngtcp2_dcidtr *dtr, int *pfound, uint64_t seq, const ngtcp2_cid *cid,
+  const ngtcp2_stateless_reset_token *token) {
   int rv;
 
   rv = verify_token_uniqueness(&dtr->bound.rb, pfound, seq, cid, token);
@@ -406,7 +406,8 @@ ngtcp2_tstamp ngtcp2_dcidtr_earliest_ret
 }
 
 void ngtcp2_dcidtr_push_unused(ngtcp2_dcidtr *dtr, uint64_t seq,
-                               const ngtcp2_cid *cid, const uint8_t *token) {
+                               const ngtcp2_cid *cid,
+                               const ngtcp2_stateless_reset_token *token) {
   ngtcp2_dcid *dcid = ngtcp2_ringbuf_push_back(&dtr->unused.rb);
 
   ngtcp2_dcid_init(dcid, seq, cid, token);
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_dcidtr.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_dcidtr.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_dcidtr.h	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_dcidtr.h	2026-05-15 15:49:15.161978500 +0200
@@ -154,9 +154,9 @@ int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidt
  *     There is no Destination Connection ID that matches the given
  *     |path| and |token|.
  */
-int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr,
-                                         const ngtcp2_path *path,
-                                         const uint8_t *token);
+int ngtcp2_dcidtr_verify_stateless_reset(
+  const ngtcp2_dcidtr *dtr, const ngtcp2_path *path,
+  const ngtcp2_stateless_reset_token *token);
 
 /*
  * ngtcp2_dcidtr_verify_token_uniqueness verifies that the uniqueness
@@ -180,9 +180,9 @@ int ngtcp2_dcidtr_verify_stateless_reset
  *     The given combination of values does not satisfy the above
  *     conditions.
  */
-int ngtcp2_dcidtr_verify_token_uniqueness(const ngtcp2_dcidtr *dtr, int *pfound,
-                                          uint64_t seq, const ngtcp2_cid *cid,
-                                          const uint8_t *token);
+int ngtcp2_dcidtr_verify_token_uniqueness(
+  const ngtcp2_dcidtr *dtr, int *pfound, uint64_t seq, const ngtcp2_cid *cid,
+  const ngtcp2_stateless_reset_token *token);
 
 /*
  * ngtcp2_dcidtr_retire_inactive_dcid_prior_to retires inactive
@@ -273,7 +273,8 @@ ngtcp2_tstamp ngtcp2_dcidtr_earliest_ret
  * buffer space is full, the earliest ngtcp2_dcid is removed.
  */
 void ngtcp2_dcidtr_push_unused(ngtcp2_dcidtr *dtr, uint64_t seq,
-                               const ngtcp2_cid *cid, const uint8_t *token);
+                               const ngtcp2_cid *cid,
+                               const ngtcp2_stateless_reset_token *token);
 
 /*
  * ngtcp2_dcidtr_pop_unused_cid_token removes an unused Destination
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_frame_chain.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_frame_chain.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_frame_chain.c	2026-01-23 11:53:43.289756800 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_frame_chain.c	2026-05-15 15:49:15.161978500 +0200
@@ -36,7 +36,7 @@ int ngtcp2_frame_chain_objalloc_new(ngtc
     return NGTCP2_ERR_NOMEM;
   }
 
-  ngtcp2_frame_chain_init(*pfrc);
+  ngtcp2_frame_chain_init(*pfrc, NGTCP2_FRAME_CHAIN_FLAG_NONE);
 
   return 0;
 }
@@ -48,7 +48,7 @@ int ngtcp2_frame_chain_extralen_new(ngtc
     return NGTCP2_ERR_NOMEM;
   }
 
-  ngtcp2_frame_chain_init(*pfrc);
+  ngtcp2_frame_chain_init(*pfrc, NGTCP2_FRAME_CHAIN_FLAG_MALLOC);
 
   return 0;
 }
@@ -57,14 +57,26 @@ int ngtcp2_frame_chain_stream_datacnt_ob
                                                    size_t datacnt,
                                                    ngtcp2_objalloc *objalloc,
                                                    const ngtcp2_mem *mem) {
+  int rv;
+
   if (datacnt > NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES) {
-    return ngtcp2_frame_chain_extralen_new(pfrc,
-                                           sizeof(ngtcp2_vec) * (datacnt - 1) -
-                                             NGTCP2_FRAME_CHAIN_STREAM_AVAIL,
-                                           mem);
+    rv = ngtcp2_frame_chain_extralen_new(
+      pfrc,
+      sizeof(ngtcp2_vec) * (datacnt - NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES),
+      mem);
+  } else {
+    rv = ngtcp2_frame_chain_objalloc_new(pfrc, objalloc);
+  }
+
+  if (rv != 0) {
+    return rv;
   }
 
-  return ngtcp2_frame_chain_objalloc_new(pfrc, objalloc);
+  (*pfrc)->fr.stream.data =
+    (ngtcp2_vec *)(void *)((uint8_t *)*pfrc +
+                           offsetof(ngtcp2_frame_chain, buf));
+
+  return 0;
 }
 
 int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc,
@@ -87,9 +99,9 @@ int ngtcp2_frame_chain_new_token_objallo
   }
 
   fr = &(*pfrc)->fr;
-  fr->type = NGTCP2_FRAME_NEW_TOKEN;
+  fr->new_token.type = NGTCP2_FRAME_NEW_TOKEN;
 
-  p = (uint8_t *)fr + sizeof(ngtcp2_new_token);
+  p = (uint8_t *)*pfrc + offsetof(ngtcp2_frame_chain, buf);
   memcpy(p, token, tokenlen);
 
   fr->new_token.token = p;
@@ -98,21 +110,6 @@ int ngtcp2_frame_chain_new_token_objallo
   return 0;
 }
 
-void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem) {
-  ngtcp2_frame_chain_binder *binder;
-
-  if (frc == NULL) {
-    return;
-  }
-
-  binder = frc->binder;
-  if (binder && --binder->refcount == 0) {
-    ngtcp2_mem_free(mem, binder);
-  }
-
-  ngtcp2_mem_free(mem, frc);
-}
-
 void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc,
                                      ngtcp2_objalloc *objalloc,
                                      const ngtcp2_mem *mem) {
@@ -122,39 +119,23 @@ void ngtcp2_frame_chain_objalloc_del(ngt
     return;
   }
 
-  switch (frc->fr.type) {
-  case NGTCP2_FRAME_CRYPTO:
-  case NGTCP2_FRAME_STREAM:
-    if (frc->fr.stream.datacnt > NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES) {
-      ngtcp2_frame_chain_del(frc, mem);
-
-      return;
-    }
-
-    break;
-  case NGTCP2_FRAME_NEW_TOKEN:
-    if (frc->fr.new_token.tokenlen > NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES) {
-      ngtcp2_frame_chain_del(frc, mem);
-
-      return;
-    }
-
-    break;
-  }
-
   binder = frc->binder;
   if (binder && --binder->refcount == 0) {
     ngtcp2_mem_free(mem, binder);
   }
 
-  frc->binder = NULL;
+  if (frc->flags & NGTCP2_FRAME_CHAIN_FLAG_MALLOC) {
+    ngtcp2_mem_free(mem, frc);
+    return;
+  }
 
   ngtcp2_objalloc_frame_chain_release(objalloc, frc);
 }
 
-void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc) {
+void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc, uint32_t flags) {
   frc->next = NULL;
   frc->binder = NULL;
+  frc->flags = flags;
 }
 
 void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc,
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_frame_chain.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_frame_chain.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_frame_chain.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_frame_chain.h	2026-05-15 15:49:15.161978500 +0200
@@ -36,10 +36,10 @@
 
 /* NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE indicates that no flag is
    set. */
-#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00u
+#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00U
 /* NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK indicates that an information
    which a frame carries has been acknowledged. */
-#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01u
+#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01U
 
 /*
  * ngtcp2_frame_chain_binder binds 2 or more of ngtcp2_frame_chain to
@@ -57,6 +57,25 @@ typedef struct ngtcp2_frame_chain_binder
 int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder,
                                   const ngtcp2_mem *mem);
 
+/* NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES is the number of datacnt
+   that changes allocation method.  If datacnt is more than this
+   value, ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
+   Otherwise, it is allocated using ngtcp2_objalloc.  */
+#define NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES 4
+
+/* NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES is the length of a token that
+   changes allocation method.  If the length is more than this value,
+   ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
+   Otherwise, it is allocated using ngtcp2_objalloc. */
+#define NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES                                     \
+  (NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES * sizeof(ngtcp2_vec))
+
+/* NGTCP2_FRAME_CHAIN_FLAG_NONE indicates no flag is set. */
+#define NGTCP2_FRAME_CHAIN_FLAG_NONE 0x0
+/* NGTCP2_FRAME_CHAIN_FLAG_MALLOC indicates that ngtcp2_frame_chain is
+   allocated by ngtcp2_mem_malloc. */
+#define NGTCP2_FRAME_CHAIN_FLAG_MALLOC 0x1
+
 typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
 
 /*
@@ -67,7 +86,9 @@ struct ngtcp2_frame_chain {
     struct {
       ngtcp2_frame_chain *next;
       ngtcp2_frame_chain_binder *binder;
+      uint32_t flags;
       ngtcp2_frame fr;
+      uint8_t buf[sizeof(ngtcp2_vec) * NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES];
     };
 
     ngtcp2_opl_entry oplent;
@@ -90,10 +111,6 @@ ngtcp2_objalloc_decl(frame_chain, ngtcp2
 int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b,
                              const ngtcp2_mem *mem);
 
-/* NGTCP2_MAX_STREAM_DATACNT is the maximum number of ngtcp2_vec that
-   a ngtcp2_stream can include. */
-#define NGTCP2_MAX_STREAM_DATACNT 256
-
 /*
  * ngtcp2_frame_chain_objalloc_new allocates ngtcp2_frame_chain using
  * |objalloc|.
@@ -108,26 +125,6 @@ int ngtcp2_frame_chain_objalloc_new(ngtc
 int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen,
                                     const ngtcp2_mem *mem);
 
-/* NGTCP2_FRAME_CHAIN_STREAM_AVAIL is the number of additional bytes
-   available after ngtcp2_stream when it is embedded in
-   ngtcp2_frame. */
-#define NGTCP2_FRAME_CHAIN_STREAM_AVAIL                                        \
-  (sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream))
-
-/* NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES is the number of datacnt
-   that changes allocation method.  If datacnt is more than this
-   value, ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
-   Otherwise, it is allocated using ngtcp2_objalloc.  */
-#define NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES                                \
-  (NGTCP2_FRAME_CHAIN_STREAM_AVAIL / sizeof(ngtcp2_vec) + 1)
-
-/* NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES is the length of a token that
-   changes allocation method.  If the length is more than this value,
-   ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
-   Otherwise, it is allocated using ngtcp2_objalloc. */
-#define NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES                                     \
-  (sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token))
-
 /*
  * ngtcp2_frame_chain_stream_datacnt_objalloc_new allocates enough
  * data to store additional |datacnt| - 1 ngtcp2_vec object after
@@ -135,8 +132,6 @@ int ngtcp2_frame_chain_extralen_new(ngtc
  * words, |datacnt| <= NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES,
  * ngtcp2_frame_chain_objalloc_new is called internally.  Otherwise,
  * ngtcp2_frame_chain_extralen_new is used and objalloc is not used.
- * Therefore, it is important to call ngtcp2_frame_chain_objalloc_del
- * without changing datacnt field.
  */
 int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc,
                                                    size_t datacnt,
@@ -157,24 +152,19 @@ int ngtcp2_frame_chain_new_token_objallo
                                               const ngtcp2_mem *mem);
 
 /*
- * ngtcp2_frame_chain_del deallocates |frc|.  It also deallocates the
- * memory pointed by |frc|.
- */
-void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem);
-
-/*
- * ngtcp2_frame_chain_objalloc_del adds |frc| to |objalloc| for reuse.
- * It might just delete |frc| depending on the frame type and the size
- * of |frc|.
+ * ngtcp2_frame_chain_objalloc_del adds |frc| to |objalloc| for reuse
+ * if NGTCP2_FRAME_CHAIN_FLAG_MALLOC is not set in |frc|->flags.
+ * Otherwise, it deletes |frc|.
  */
 void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc,
                                      ngtcp2_objalloc *objalloc,
                                      const ngtcp2_mem *mem);
 
 /*
- * ngtcp2_frame_chain_init initializes |frc|.
+ * ngtcp2_frame_chain_init initializes |frc|.  |flags| is bitwise-OR
+ * of zero or more of NGTCP2_FRAME_CHAIN_FLAG_*.
  */
-void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc);
+void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc, uint32_t flags);
 
 /*
  * ngtcp2_frame_chain_list_objalloc_del adds all ngtcp2_frame_chain
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_gaptr.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_gaptr.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_gaptr.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_gaptr.c	2026-05-15 15:49:15.162978400 +0200
@@ -35,11 +35,11 @@ void ngtcp2_gaptr_init(ngtcp2_gaptr *gap
 }
 
 static int gaptr_gap_init(ngtcp2_gaptr *gaptr) {
-  ngtcp2_range range = {
-    .end = UINT64_MAX,
-  };
-
-  return ngtcp2_ksl_insert(&gaptr->gap, NULL, &range, NULL);
+  return ngtcp2_ksl_insert(&gaptr->gap, NULL,
+                           &(ngtcp2_range){
+                             .end = UINT64_MAX,
+                           },
+                           NULL);
 }
 
 void ngtcp2_gaptr_free(ngtcp2_gaptr *gaptr) {
@@ -116,10 +116,6 @@ uint64_t ngtcp2_gaptr_first_gap_offset(c
 
 ngtcp2_range ngtcp2_gaptr_get_first_gap_after(const ngtcp2_gaptr *gaptr,
                                               uint64_t offset) {
-  ngtcp2_range q = {
-    .begin = offset,
-    .end = offset + 1,
-  };
   ngtcp2_ksl_it it;
 
   if (ngtcp2_ksl_len(&gaptr->gap) == 0) {
@@ -129,7 +125,11 @@ ngtcp2_range ngtcp2_gaptr_get_first_gap_
     return r;
   }
 
-  it = ngtcp2_ksl_lower_bound_search(&gaptr->gap, &q,
+  it = ngtcp2_ksl_lower_bound_search(&gaptr->gap,
+                                     &(ngtcp2_range){
+                                       .begin = offset,
+                                       .end = offset + 1,
+                                     },
                                      ngtcp2_ksl_range_exclusive_search);
 
   assert(!ngtcp2_ksl_it_end(&it));
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ksl.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ksl.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ksl.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ksl.c	2026-05-15 15:49:15.162978400 +0200
@@ -31,71 +31,78 @@
 
 #include "ngtcp2_macro.h"
 #include "ngtcp2_mem.h"
-#include "ngtcp2_range.h"
 
 static ngtcp2_ksl_blk null_blk;
 
 ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent)
 
-static size_t ksl_nodelen(size_t keylen) {
-  assert(keylen >= sizeof(uint64_t));
-
-  return (sizeof(ngtcp2_ksl_node) + keylen - sizeof(uint64_t) + 0x7u) &
-         ~(uintptr_t)0x7u;
-}
-
-static size_t ksl_blklen(size_t nodelen) {
-  return sizeof(ngtcp2_ksl_blk) + nodelen * NGTCP2_KSL_MAX_NBLK -
-         sizeof(uint64_t);
+static size_t ksl_blklen(size_t aligned_keylen) {
+  return sizeof(ngtcp2_ksl_blk) + NGTCP2_KSL_MAX_NBLK * aligned_keylen;
 }
 
 /*
- * ksl_node_set_key sets |key| to |node|.
+ * ksl_set_nth_key sets |key| to |n|th node under |blk|.
  */
-static void ksl_node_set_key(ngtcp2_ksl *ksl, ngtcp2_ksl_node *node,
-                             const void *key) {
-  memcpy(node->key, key, ksl->keylen);
+static void ksl_set_nth_key(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
+                            size_t n, const ngtcp2_ksl_key *key) {
+  memcpy(blk->keys + n * ksl->aligned_keylen, key, ksl->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);
+  size_t aligned_keylen;
+
+  assert(keylen >= sizeof(uint64_t));
+
+  aligned_keylen = (keylen + 0x7U) & ~0x7U;
+
+  assert(aligned_keylen <= UINT16_MAX);
 
   ngtcp2_objalloc_init(&ksl->blkalloc,
-                       (ksl_blklen(nodelen) + 0xfu) & ~(uintptr_t)0xfu, mem);
+                       (ksl_blklen(aligned_keylen) + 0xFU) & ~(uintptr_t)0xFU,
+                       mem);
 
-  ksl->head = NULL;
+  ksl->root = NULL;
   ksl->front = ksl->back = NULL;
   ksl->compar = compar;
   ksl->search = search;
   ksl->n = 0;
   ksl->keylen = keylen;
-  ksl->nodelen = nodelen;
+  ksl->aligned_keylen = aligned_keylen;
 }
 
 static ngtcp2_ksl_blk *ksl_blk_objalloc_new(ngtcp2_ksl *ksl) {
-  return ngtcp2_objalloc_ksl_blk_len_get(&ksl->blkalloc,
-                                         ksl_blklen(ksl->nodelen));
+  ngtcp2_ksl_blk *blk = ngtcp2_objalloc_ksl_blk_len_get(
+    &ksl->blkalloc, ksl_blklen(ksl->aligned_keylen));
+
+  if (!blk) {
+    return NULL;
+  }
+
+  blk->keys = (uint8_t *)blk + sizeof(*blk);
+  blk->aligned_keylen = (uint16_t)ksl->aligned_keylen;
+
+  return blk;
 }
 
 static void ksl_blk_objalloc_del(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) {
   ngtcp2_objalloc_ksl_blk_release(&ksl->blkalloc, blk);
 }
 
-static int ksl_head_init(ngtcp2_ksl *ksl) {
-  ngtcp2_ksl_blk *head = ksl_blk_objalloc_new(ksl);
+static int ksl_root_init(ngtcp2_ksl *ksl) {
+  ngtcp2_ksl_blk *root = ksl_blk_objalloc_new(ksl);
 
-  if (!head) {
+  if (!root) {
     return NGTCP2_ERR_NOMEM;
   }
 
-  head->next = head->prev = NULL;
-  head->n = 0;
-  head->leaf = 1;
+  root->next = root->prev = NULL;
+  root->n = 0;
+  root->leaf = 1;
 
-  ksl->head = head;
-  ksl->front = ksl->back = head;
+  ksl->root = root;
+  ksl->front = ksl->back = root;
 
   return 0;
 }
@@ -109,7 +116,7 @@ static void ksl_free_blk(ngtcp2_ksl *ksl
 
   if (!blk->leaf) {
     for (i = 0; i < blk->n; ++i) {
-      ksl_free_blk(ksl, ngtcp2_ksl_nth_node(ksl, blk, i)->blk);
+      ksl_free_blk(ksl, blk->nodes[i].blk);
     }
   }
 
@@ -118,12 +125,12 @@ static void ksl_free_blk(ngtcp2_ksl *ksl
 #endif /* defined(NOMEMPOOL) */
 
 void ngtcp2_ksl_free(ngtcp2_ksl *ksl) {
-  if (!ksl || !ksl->head) {
+  if (!ksl || !ksl->root) {
     return;
   }
 
 #ifdef NOMEMPOOL
-  ksl_free_blk(ksl, ksl->head);
+  ksl_free_blk(ksl, ksl->root);
 #endif /* defined(NOMEMPOOL) */
 
   ngtcp2_objalloc_free(&ksl->blkalloc);
@@ -160,8 +167,10 @@ static ngtcp2_ksl_blk *ksl_split_blk(ngt
   rblk->n = blk->n / 2;
   blk->n -= rblk->n;
 
-  memcpy(rblk->nodes, blk->nodes + ksl->nodelen * blk->n,
-         ksl->nodelen * rblk->n);
+  memcpy(rblk->nodes, blk->nodes + blk->n, rblk->n * sizeof(ngtcp2_ksl_node));
+
+  memcpy(rblk->keys, blk->keys + blk->n * ksl->aligned_keylen,
+         rblk->n * ksl->aligned_keylen);
 
   assert(blk->n >= NGTCP2_KSL_MIN_NBLK);
   assert(rblk->n >= NGTCP2_KSL_MIN_NBLK);
@@ -181,32 +190,31 @@ static ngtcp2_ksl_blk *ksl_split_blk(ngt
  *     Out of memory.
  */
 static int ksl_split_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
-  ngtcp2_ksl_node *node;
-  ngtcp2_ksl_blk *lblk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk, *rblk;
+  ngtcp2_ksl_blk *lblk = blk->nodes[i].blk, *rblk;
 
   rblk = ksl_split_blk(ksl, lblk);
   if (rblk == NULL) {
     return NGTCP2_ERR_NOMEM;
   }
 
-  memmove(blk->nodes + (i + 2) * ksl->nodelen,
-          blk->nodes + (i + 1) * ksl->nodelen,
-          ksl->nodelen * (blk->n - (i + 1)));
+  memmove(blk->nodes + (i + 2), blk->nodes + (i + 1),
+          (blk->n - (i + 1)) * sizeof(ngtcp2_ksl_node));
+
+  memmove(blk->keys + (i + 1) * ksl->aligned_keylen,
+          blk->keys + i * ksl->aligned_keylen,
+          (blk->n - i) * ksl->aligned_keylen);
 
-  node = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
-  node->blk = rblk;
+  blk->nodes[i + 1].blk = rblk;
   ++blk->n;
-  ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
 
-  node = ngtcp2_ksl_nth_node(ksl, blk, i);
-  ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
+  ksl_set_nth_key(ksl, blk, i, ngtcp2_ksl_blk_nth_key(lblk, lblk->n - 1));
 
   return 0;
 }
 
 /*
- * ksl_split_head splits a head (root) block.  It increases the height
- * of skip list by 1.
+ * ksl_split_root splits a root block.  It increases the height of
+ * skip list by 1.
  *
  * It returns 0 if it succeeds, or one of the following negative error
  * codes:
@@ -214,37 +222,34 @@ static int ksl_split_node(ngtcp2_ksl *ks
  * NGTCP2_ERR_NOMEM
  *     Out of memory.
  */
-static int ksl_split_head(ngtcp2_ksl *ksl) {
-  ngtcp2_ksl_blk *rblk = NULL, *lblk, *nhead = NULL;
-  ngtcp2_ksl_node *node;
+static int ksl_split_root(ngtcp2_ksl *ksl) {
+  ngtcp2_ksl_blk *rblk = NULL, *lblk, *nroot = NULL;
 
-  rblk = ksl_split_blk(ksl, ksl->head);
+  rblk = ksl_split_blk(ksl, ksl->root);
   if (rblk == NULL) {
     return NGTCP2_ERR_NOMEM;
   }
 
-  lblk = ksl->head;
+  lblk = ksl->root;
 
-  nhead = ksl_blk_objalloc_new(ksl);
+  nroot = ksl_blk_objalloc_new(ksl);
 
-  if (nhead == NULL) {
+  if (nroot == NULL) {
     ksl_blk_objalloc_del(ksl, rblk);
     return NGTCP2_ERR_NOMEM;
   }
 
-  nhead->next = nhead->prev = NULL;
-  nhead->n = 2;
-  nhead->leaf = 0;
-
-  node = ngtcp2_ksl_nth_node(ksl, nhead, 0);
-  ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
-  node->blk = lblk;
-
-  node = ngtcp2_ksl_nth_node(ksl, nhead, 1);
-  ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
-  node->blk = rblk;
+  nroot->next = nroot->prev = NULL;
+  nroot->n = 2;
+  nroot->leaf = 0;
+
+  ksl_set_nth_key(ksl, nroot, 0, ngtcp2_ksl_blk_nth_key(lblk, lblk->n - 1));
+  nroot->nodes[0].blk = lblk;
+
+  ksl_set_nth_key(ksl, nroot, 1, ngtcp2_ksl_blk_nth_key(rblk, rblk->n - 1));
+  nroot->nodes[1].blk = rblk;
 
-  ksl->head = nhead;
+  ksl->root = nroot;
 
   return 0;
 }
@@ -257,16 +262,17 @@ static int ksl_split_head(ngtcp2_ksl *ks
  */
 static void ksl_insert_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i,
                             const ngtcp2_ksl_key *key, void *data) {
-  ngtcp2_ksl_node *node;
-
   assert(blk->n < NGTCP2_KSL_MAX_NBLK);
 
-  memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen,
-          ksl->nodelen * (blk->n - i));
+  memmove(blk->nodes + (i + 1), blk->nodes + i,
+          (blk->n - i) * sizeof(ngtcp2_ksl_node));
+
+  memmove(blk->keys + (i + 1) * ksl->aligned_keylen,
+          blk->keys + i * ksl->aligned_keylen,
+          (blk->n - i) * ksl->aligned_keylen);
 
-  node = ngtcp2_ksl_nth_node(ksl, blk, i);
-  ksl_node_set_key(ksl, node, key);
-  node->data = data;
+  ksl_set_nth_key(ksl, blk, i, key);
+  blk->nodes[i].data = data;
 
   ++blk->n;
 }
@@ -278,28 +284,27 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, n
   size_t i;
   int rv;
 
-  if (!ksl->head) {
-    rv = ksl_head_init(ksl);
+  if (!ksl->root) {
+    rv = ksl_root_init(ksl);
     if (rv != 0) {
       return rv;
     }
   }
 
-  if (ksl->head->n == NGTCP2_KSL_MAX_NBLK) {
-    rv = ksl_split_head(ksl);
+  if (ksl->root->n == NGTCP2_KSL_MAX_NBLK) {
+    rv = ksl_split_root(ksl);
     if (rv != 0) {
       return rv;
     }
   }
 
-  blk = ksl->head;
+  blk = ksl->root;
 
   for (;;) {
     i = ksl->search(ksl, blk, key);
 
     if (blk->leaf) {
-      if (i < blk->n &&
-          !ksl->compar(key, ngtcp2_ksl_nth_node(ksl, blk, i)->key)) {
+      if (i < blk->n && !ksl->compar(key, ngtcp2_ksl_blk_nth_key(blk, i))) {
         if (it) {
           *it = ngtcp2_ksl_end(ksl);
         }
@@ -311,7 +316,7 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, n
       ++ksl->n;
 
       if (it) {
-        ngtcp2_ksl_it_init(it, ksl, blk, i);
+        ngtcp2_ksl_it_init(it, blk, i);
       }
 
       return 0;
@@ -320,17 +325,17 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, n
     if (i == blk->n) {
       /* This insertion extends the largest key in this subtree. */
       for (; !blk->leaf;) {
-        node = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1);
+        node = &blk->nodes[blk->n - 1];
         if (node->blk->n == NGTCP2_KSL_MAX_NBLK) {
           rv = ksl_split_node(ksl, blk, blk->n - 1);
           if (rv != 0) {
             return rv;
           }
 
-          node = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1);
+          node = &blk->nodes[blk->n - 1];
         }
 
-        ksl_node_set_key(ksl, node, key);
+        ksl_set_nth_key(ksl, blk, blk->n - 1, key);
         blk = node->blk;
       }
 
@@ -338,13 +343,13 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, n
       ++ksl->n;
 
       if (it) {
-        ngtcp2_ksl_it_init(it, ksl, blk, blk->n - 1);
+        ngtcp2_ksl_it_init(it, blk, blk->n - 1);
       }
 
       return 0;
     }
 
-    node = ngtcp2_ksl_nth_node(ksl, blk, i);
+    node = &blk->nodes[i];
 
     if (node->blk->n == NGTCP2_KSL_MAX_NBLK) {
       rv = ksl_split_node(ksl, blk, i);
@@ -352,12 +357,8 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, n
         return rv;
       }
 
-      if (ksl->compar((ngtcp2_ksl_key *)node->key, key)) {
-        node = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
-
-        if (ksl->compar((ngtcp2_ksl_key *)node->key, key)) {
-          ksl_node_set_key(ksl, node, key);
-        }
+      if (ksl->compar(ngtcp2_ksl_blk_nth_key(blk, i), key)) {
+        node = &blk->nodes[i + 1];
       }
     }
 
@@ -370,8 +371,12 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, n
  * |i|.
  */
 static void ksl_remove_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
-  memmove(blk->nodes + i * ksl->nodelen, blk->nodes + (i + 1) * ksl->nodelen,
-          ksl->nodelen * (blk->n - (i + 1)));
+  memmove(blk->nodes + i, blk->nodes + (i + 1),
+          (blk->n - (i + 1)) * sizeof(ngtcp2_ksl_node));
+
+  memmove(blk->keys + i * ksl->aligned_keylen,
+          blk->keys + (i + 1) * ksl->aligned_keylen,
+          (blk->n - (i + 1)) * ksl->aligned_keylen);
 
   --blk->n;
 }
@@ -380,9 +385,9 @@ static void ksl_remove_node(ngtcp2_ksl *
  * ksl_merge_node merges 2 nodes which are the nodes at the index of
  * |i| and |i + 1|.
  *
- * If |blk| is the head (root) block and it contains just 2 nodes
- * before merging nodes, the merged block becomes head block, which
- * decreases the height of |ksl| by 1.
+ * If |blk| is the root block and it contains just 2 nodes before
+ * merging nodes, the merged block becomes root block, which decreases
+ * the height of |ksl| by 1.
  *
  * This function returns the pointer to the merged block.
  */
@@ -393,15 +398,17 @@ static ngtcp2_ksl_blk *ksl_merge_node(ng
 
   assert(i + 1 < blk->n);
 
-  lnode = ngtcp2_ksl_nth_node(ksl, blk, i);
+  lnode = &blk->nodes[i];
 
   lblk = lnode->blk;
-  rblk = ngtcp2_ksl_nth_node(ksl, blk, i + 1)->blk;
+  rblk = blk->nodes[i + 1].blk;
+
+  assert(lblk->n + rblk->n <= NGTCP2_KSL_MAX_NBLK);
 
-  assert(lblk->n + rblk->n < NGTCP2_KSL_MAX_NBLK);
+  memcpy(lblk->nodes + lblk->n, rblk->nodes, rblk->n * sizeof(ngtcp2_ksl_node));
 
-  memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes,
-         ksl->nodelen * rblk->n);
+  memcpy(lblk->keys + lblk->n * ksl->aligned_keylen, rblk->keys,
+         rblk->n * ksl->aligned_keylen);
 
   lblk->n += rblk->n;
   lblk->next = rblk->next;
@@ -414,13 +421,12 @@ static ngtcp2_ksl_blk *ksl_merge_node(ng
 
   ksl_blk_objalloc_del(ksl, rblk);
 
-  if (ksl->head == blk && blk->n == 2) {
-    ksl_blk_objalloc_del(ksl, ksl->head);
-    ksl->head = lblk;
+  if (ksl->root == blk && blk->n == 2) {
+    ksl_blk_objalloc_del(ksl, ksl->root);
+    ksl->root = lblk;
   } else {
     ksl_remove_node(ksl, blk, i + 1);
-    ksl_node_set_key(ksl, lnode,
-                     ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
+    ksl_set_nth_key(ksl, blk, i, ngtcp2_ksl_blk_nth_key(lblk, lblk->n - 1));
   }
 
   return lblk;
@@ -438,8 +444,8 @@ static void ksl_shift_left(ngtcp2_ksl *k
 
   assert(i > 0);
 
-  lnode = ngtcp2_ksl_nth_node(ksl, blk, i - 1);
-  rnode = ngtcp2_ksl_nth_node(ksl, blk, i);
+  lnode = &blk->nodes[i - 1];
+  rnode = &blk->nodes[i];
 
   lblk = lnode->blk;
   rblk = rnode->blk;
@@ -453,15 +459,20 @@ static void ksl_shift_left(ngtcp2_ksl *k
   assert(lblk->n <= NGTCP2_KSL_MAX_NBLK - n);
   assert(rblk->n >= NGTCP2_KSL_MIN_NBLK + n);
 
-  memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes, ksl->nodelen * n);
+  memcpy(lblk->nodes + lblk->n, rblk->nodes, n * sizeof(ngtcp2_ksl_node));
+
+  memcpy(lblk->keys + lblk->n * ksl->aligned_keylen, rblk->keys,
+         n * ksl->aligned_keylen);
 
   lblk->n += (uint32_t)n;
   rblk->n -= (uint32_t)n;
 
-  ksl_node_set_key(ksl, lnode,
-                   ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
+  ksl_set_nth_key(ksl, blk, i - 1, ngtcp2_ksl_blk_nth_key(lblk, lblk->n - 1));
 
-  memmove(rblk->nodes, rblk->nodes + ksl->nodelen * n, ksl->nodelen * rblk->n);
+  memmove(rblk->nodes, rblk->nodes + n, rblk->n * sizeof(ngtcp2_ksl_node));
+
+  memmove(rblk->keys, rblk->keys + n * ksl->aligned_keylen,
+          rblk->n * ksl->aligned_keylen);
 }
 
 /*
@@ -476,8 +487,8 @@ static void ksl_shift_right(ngtcp2_ksl *
 
   assert(i < blk->n - 1);
 
-  lnode = ngtcp2_ksl_nth_node(ksl, blk, i);
-  rnode = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
+  lnode = &blk->nodes[i];
+  rnode = &blk->nodes[i + 1];
 
   lblk = lnode->blk;
   rblk = rnode->blk;
@@ -491,15 +502,20 @@ static void ksl_shift_right(ngtcp2_ksl *
   assert(lblk->n >= NGTCP2_KSL_MIN_NBLK + n);
   assert(rblk->n <= NGTCP2_KSL_MAX_NBLK - n);
 
-  memmove(rblk->nodes + ksl->nodelen * n, rblk->nodes, ksl->nodelen * rblk->n);
+  memmove(rblk->nodes + n, rblk->nodes, rblk->n * sizeof(ngtcp2_ksl_node));
+
+  memmove(rblk->keys + n * ksl->aligned_keylen, rblk->keys,
+          rblk->n * ksl->aligned_keylen);
 
   rblk->n += (uint32_t)n;
   lblk->n -= (uint32_t)n;
 
-  memcpy(rblk->nodes, lblk->nodes + ksl->nodelen * lblk->n, ksl->nodelen * n);
+  memcpy(rblk->nodes, lblk->nodes + lblk->n, n * sizeof(ngtcp2_ksl_node));
 
-  ksl_node_set_key(ksl, lnode,
-                   ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
+  memcpy(rblk->keys, lblk->keys + lblk->n * ksl->aligned_keylen,
+         n * ksl->aligned_keylen);
+
+  ksl_set_nth_key(ksl, blk, i, ngtcp2_ksl_blk_nth_key(lblk, lblk->n - 1));
 }
 
 /*
@@ -516,9 +532,9 @@ int ngtcp2_ksl_remove_hint(ngtcp2_ksl *k
                            const ngtcp2_ksl_key *key) {
   ngtcp2_ksl_blk *blk = hint->blk;
 
-  assert(ksl->head);
+  assert(ksl->root);
 
-  if (blk->n <= NGTCP2_KSL_MIN_NBLK) {
+  if (blk != ksl->root && blk->n == NGTCP2_KSL_MIN_NBLK) {
     return ngtcp2_ksl_remove(ksl, it, key);
   }
 
@@ -528,9 +544,9 @@ int ngtcp2_ksl_remove_hint(ngtcp2_ksl *k
 
   if (it) {
     if (hint->i == blk->n && blk->next) {
-      ngtcp2_ksl_it_init(it, ksl, blk->next, 0);
+      ngtcp2_ksl_it_init(it, blk->next, 0);
     } else {
-      ngtcp2_ksl_it_init(it, ksl, blk, hint->i);
+      ngtcp2_ksl_it_init(it, blk, hint->i);
     }
   }
 
@@ -539,7 +555,7 @@ int ngtcp2_ksl_remove_hint(ngtcp2_ksl *k
 
 int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
                       const ngtcp2_ksl_key *key) {
-  ngtcp2_ksl_blk *blk = ksl->head;
+  ngtcp2_ksl_blk *blk = ksl->root;
   ngtcp2_ksl_node *node;
   size_t i;
 
@@ -548,8 +564,8 @@ int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, n
   }
 
   if (!blk->leaf && blk->n == 2 &&
-      ngtcp2_ksl_nth_node(ksl, blk, 0)->blk->n == NGTCP2_KSL_MIN_NBLK &&
-      ngtcp2_ksl_nth_node(ksl, blk, 1)->blk->n == NGTCP2_KSL_MIN_NBLK) {
+      blk->nodes[0].blk->n == NGTCP2_KSL_MIN_NBLK &&
+      blk->nodes[1].blk->n == NGTCP2_KSL_MIN_NBLK) {
     blk = ksl_merge_node(ksl, blk, 0);
   }
 
@@ -565,7 +581,7 @@ int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, n
     }
 
     if (blk->leaf) {
-      if (ksl->compar(key, ngtcp2_ksl_nth_node(ksl, blk, i)->key)) {
+      if (ksl->compar(key, ngtcp2_ksl_blk_nth_key(blk, i))) {
         if (it) {
           *it = ngtcp2_ksl_end(ksl);
         }
@@ -578,16 +594,16 @@ int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, n
 
       if (it) {
         if (blk->n == i && blk->next) {
-          ngtcp2_ksl_it_init(it, ksl, blk->next, 0);
+          ngtcp2_ksl_it_init(it, blk->next, 0);
         } else {
-          ngtcp2_ksl_it_init(it, ksl, blk, i);
+          ngtcp2_ksl_it_init(it, blk, i);
         }
       }
 
       return 0;
     }
 
-    node = ngtcp2_ksl_nth_node(ksl, blk, i);
+    node = &blk->nodes[i];
 
     if (node->blk->n > NGTCP2_KSL_MIN_NBLK) {
       blk = node->blk;
@@ -596,16 +612,14 @@ int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, n
 
     assert(node->blk->n == NGTCP2_KSL_MIN_NBLK);
 
-    if (i + 1 < blk->n &&
-        ngtcp2_ksl_nth_node(ksl, blk, i + 1)->blk->n > NGTCP2_KSL_MIN_NBLK) {
+    if (i + 1 < blk->n && blk->nodes[i + 1].blk->n > NGTCP2_KSL_MIN_NBLK) {
       ksl_shift_left(ksl, blk, i + 1);
       blk = node->blk;
 
       continue;
     }
 
-    if (i > 0 &&
-        ngtcp2_ksl_nth_node(ksl, blk, i - 1)->blk->n > NGTCP2_KSL_MIN_NBLK) {
+    if (i > 0 && blk->nodes[i - 1].blk->n > NGTCP2_KSL_MIN_NBLK) {
       ksl_shift_right(ksl, blk, i - 1);
       blk = node->blk;
 
@@ -631,12 +645,12 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound(con
 ngtcp2_ksl_it ngtcp2_ksl_lower_bound_search(const ngtcp2_ksl *ksl,
                                             const ngtcp2_ksl_key *key,
                                             ngtcp2_ksl_search search) {
-  ngtcp2_ksl_blk *blk = ksl->head;
+  ngtcp2_ksl_blk *blk = ksl->root;
   ngtcp2_ksl_it it;
   size_t i;
 
   if (!blk) {
-    ngtcp2_ksl_it_init(&it, ksl, &null_blk, 0);
+    ngtcp2_ksl_it_init(&it, &null_blk, 0);
     return it;
   }
 
@@ -649,7 +663,7 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound_sea
         i = 0;
       }
 
-      ngtcp2_ksl_it_init(&it, ksl, blk, i);
+      ngtcp2_ksl_it_init(&it, blk, i);
 
       return it;
     }
@@ -657,7 +671,7 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound_sea
     if (i == blk->n) {
       /* This happens if descendant has smaller key.  Fast forward to
          find last node in this subtree. */
-      for (; !blk->leaf; blk = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
+      for (; !blk->leaf; blk = blk->nodes[blk->n - 1].blk)
         ;
 
       if (blk->next) {
@@ -667,39 +681,41 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound_sea
         i = blk->n;
       }
 
-      ngtcp2_ksl_it_init(&it, ksl, blk, i);
+      ngtcp2_ksl_it_init(&it, blk, i);
 
       return it;
     }
 
-    blk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk;
+    blk = blk->nodes[i].blk;
   }
 }
 
 void ngtcp2_ksl_update_key(ngtcp2_ksl *ksl, const ngtcp2_ksl_key *old_key,
                            const ngtcp2_ksl_key *new_key) {
-  ngtcp2_ksl_blk *blk = ksl->head;
+  ngtcp2_ksl_blk *blk = ksl->root;
   ngtcp2_ksl_node *node;
+  const ngtcp2_ksl_key *node_key;
   size_t i;
 
-  assert(ksl->head);
+  assert(ksl->root);
 
   for (;;) {
     i = ksl->search(ksl, blk, old_key);
 
     assert(i < blk->n);
-    node = ngtcp2_ksl_nth_node(ksl, blk, i);
+    node = &blk->nodes[i];
+    node_key = ngtcp2_ksl_blk_nth_key(blk, i);
 
     if (blk->leaf) {
-      assert(key_equal(ksl->compar, (ngtcp2_ksl_key *)node->key, old_key));
-      ksl_node_set_key(ksl, node, new_key);
+      assert(key_equal(ksl->compar, node_key, old_key));
+      ksl_set_nth_key(ksl, blk, i, new_key);
 
       return;
     }
 
-    if (key_equal(ksl->compar, (ngtcp2_ksl_key *)node->key, old_key) ||
-        ksl->compar((ngtcp2_ksl_key *)node->key, new_key)) {
-      ksl_node_set_key(ksl, node, new_key);
+    if (key_equal(ksl->compar, node_key, old_key) ||
+        ksl->compar(node_key, new_key)) {
+      ksl_set_nth_key(ksl, blk, i, new_key);
     }
 
     blk = node->blk;
@@ -709,15 +725,15 @@ void ngtcp2_ksl_update_key(ngtcp2_ksl *k
 size_t ngtcp2_ksl_len(const ngtcp2_ksl *ksl) { return ksl->n; }
 
 void ngtcp2_ksl_clear(ngtcp2_ksl *ksl) {
-  if (!ksl->head) {
+  if (!ksl->root) {
     return;
   }
 
 #ifdef NOMEMPOOL
-  ksl_free_blk(ksl, ksl->head);
+  ksl_free_blk(ksl, ksl->root);
 #endif /* defined(NOMEMPOOL) */
 
-  ksl->front = ksl->back = ksl->head = NULL;
+  ksl->front = ksl->back = ksl->root = NULL;
   ksl->n = 0;
 
   ngtcp2_objalloc_clear(&ksl->blkalloc);
@@ -727,14 +743,12 @@ void ngtcp2_ksl_clear(ngtcp2_ksl *ksl) {
 static void ksl_print(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
                       size_t level) {
   size_t i;
-  ngtcp2_ksl_node *node;
 
   fprintf(stderr, "LV=%zu n=%u\n", level, blk->n);
 
   if (blk->leaf) {
     for (i = 0; i < blk->n; ++i) {
-      node = ngtcp2_ksl_nth_node(ksl, blk, i);
-      fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key);
+      fprintf(stderr, " %" PRId64, *(int64_t *)ngtcp2_ksl_blk_nth_key(blk, i));
     }
 
     fprintf(stderr, "\n");
@@ -743,26 +757,26 @@ static void ksl_print(const ngtcp2_ksl *
   }
 
   for (i = 0; i < blk->n; ++i) {
-    ksl_print(ksl, ngtcp2_ksl_nth_node(ksl, blk, i)->blk, level + 1);
+    ksl_print(ksl, blk->nodes[i].blk, level + 1);
   }
 }
 
 void ngtcp2_ksl_print(const ngtcp2_ksl *ksl) {
-  if (!ksl->head) {
+  if (!ksl->root) {
     return;
   }
 
-  ksl_print(ksl, ksl->head, 0);
+  ksl_print(ksl, ksl->root, 0);
 }
 #endif /* !defined(WIN32) */
 
 ngtcp2_ksl_it ngtcp2_ksl_begin(const ngtcp2_ksl *ksl) {
   ngtcp2_ksl_it it;
 
-  if (ksl->head) {
-    ngtcp2_ksl_it_init(&it, ksl, ksl->front, 0);
+  if (ksl->root) {
+    ngtcp2_ksl_it_init(&it, ksl->front, 0);
   } else {
-    ngtcp2_ksl_it_init(&it, ksl, &null_blk, 0);
+    ngtcp2_ksl_it_init(&it, &null_blk, 0);
   }
 
   return it;
@@ -771,18 +785,16 @@ ngtcp2_ksl_it ngtcp2_ksl_begin(const ngt
 ngtcp2_ksl_it ngtcp2_ksl_end(const ngtcp2_ksl *ksl) {
   ngtcp2_ksl_it it;
 
-  if (ksl->head) {
-    ngtcp2_ksl_it_init(&it, ksl, ksl->back, ksl->back->n);
+  if (ksl->root) {
+    ngtcp2_ksl_it_init(&it, ksl->back, ksl->back->n);
   } else {
-    ngtcp2_ksl_it_init(&it, ksl, &null_blk, 0);
+    ngtcp2_ksl_it_init(&it, &null_blk, 0);
   }
 
   return it;
 }
 
-void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, const ngtcp2_ksl *ksl,
-                        ngtcp2_ksl_blk *blk, size_t i) {
-  it->ksl = ksl;
+void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, ngtcp2_ksl_blk *blk, size_t i) {
   it->blk = blk;
   it->i = i;
 }
@@ -802,12 +814,6 @@ int ngtcp2_ksl_it_begin(const ngtcp2_ksl
   return it->i == 0 && it->blk->prev == NULL;
 }
 
-int ngtcp2_ksl_range_compar(const ngtcp2_ksl_key *lhs,
-                            const ngtcp2_ksl_key *rhs) {
-  const ngtcp2_range *a = lhs, *b = rhs;
-  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,
@@ -815,13 +821,6 @@ size_t ngtcp2_ksl_range_search(const ngt
   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,
@@ -830,11 +829,6 @@ size_t ngtcp2_ksl_range_exclusive_search
   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,
@@ -842,11 +836,6 @@ size_t ngtcp2_ksl_uint64_less_search(con
   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,
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ksl.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ksl.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ksl.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ksl.h	2026-05-15 15:49:15.162978400 +0200
@@ -34,14 +34,15 @@
 #include <ngtcp2/ngtcp2.h>
 
 #include "ngtcp2_objalloc.h"
+#include "ngtcp2_range.h"
 
 #define NGTCP2_KSL_DEGR 16
 /* NGTCP2_KSL_MAX_NBLK is the maximum number of nodes which a single
    block can contain. */
-#define NGTCP2_KSL_MAX_NBLK (2 * NGTCP2_KSL_DEGR - 1)
+#define NGTCP2_KSL_MAX_NBLK (2 * NGTCP2_KSL_DEGR)
 /* NGTCP2_KSL_MIN_NBLK is the minimum number of nodes which a single
    block other than root must contain. */
-#define NGTCP2_KSL_MIN_NBLK (NGTCP2_KSL_DEGR - 1)
+#define NGTCP2_KSL_MIN_NBLK NGTCP2_KSL_DEGR
 
 /*
  * ngtcp2_ksl_key represents key in ngtcp2_ksl.
@@ -55,22 +56,13 @@ typedef struct ngtcp2_ksl_blk ngtcp2_ksl
 /*
  * ngtcp2_ksl_node is a node which contains either ngtcp2_ksl_blk or
  * opaque data.  If a node is an internal node, it contains
- * ngtcp2_ksl_blk.  Otherwise, it has data.  The key is stored at the
- * location starting at key.
+ * ngtcp2_ksl_blk.  Otherwise, it has data.
  */
 struct ngtcp2_ksl_node {
   union {
     ngtcp2_ksl_blk *blk;
     void *data;
   };
-  union {
-    uint64_t align;
-    /* key is a buffer to include key associated to this node.
-       Because the length of key is unknown until ngtcp2_ksl_init is
-       called, the actual buffer will be allocated after this
-       field. */
-    uint8_t key[1];
-  };
 };
 
 /*
@@ -84,19 +76,19 @@ struct ngtcp2_ksl_blk {
       /* prev points to the previous block if leaf field is
          nonzero. */
       ngtcp2_ksl_blk *prev;
+      ngtcp2_ksl_node nodes[NGTCP2_KSL_MAX_NBLK];
+      /* keys is a pointer to the buffer to include
+         NGTCP2_KSL_MAX_NBLK keys.  Because the length of key is
+         unknown until ngtcp2_ksl_init is called, the actual buffer
+         will be allocated after this object. */
+      uint8_t *keys;
       /* n is the number of nodes this object contains in nodes. */
       uint32_t n;
+      /* aligned_keylen is the length of the single key including
+         alignment. */
+      uint16_t aligned_keylen;
       /* leaf is nonzero if this block contains leaf nodes. */
-      uint32_t leaf;
-      union {
-        uint64_t align;
-        /* nodes is a buffer to contain NGTCP2_KSL_MAX_NBLK
-           ngtcp2_ksl_node objects.  Because ngtcp2_ksl_node object is
-           allocated along with the additional variable length key
-           storage, the size of buffer is unknown until ngtcp2_ksl_init is
-           called. */
-        uint8_t nodes[1];
-      };
+      uint8_t leaf;
     };
 
     ngtcp2_opl_entry oplent;
@@ -131,11 +123,10 @@ typedef size_t (*ngtcp2_ksl_search)(cons
   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;                                                     \
+    uint8_t *node_key;                                                         \
                                                                                \
-    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))    \
+    for (i = 0, node_key = blk->keys; i < blk->n && COMPAR(node_key, key);     \
+         ++i, node_key += ksl->aligned_keylen)                                 \
       ;                                                                        \
                                                                                \
     return i;                                                                  \
@@ -147,7 +138,6 @@ typedef struct ngtcp2_ksl_it ngtcp2_ksl_
  * ngtcp2_ksl_it is a bidirectional iterator to iterate nodes.
  */
 struct ngtcp2_ksl_it {
-  const ngtcp2_ksl *ksl;
   ngtcp2_ksl_blk *blk;
   size_t i;
 };
@@ -157,8 +147,8 @@ struct ngtcp2_ksl_it {
  */
 struct ngtcp2_ksl {
   ngtcp2_objalloc blkalloc;
-  /* head points to the root block. */
-  ngtcp2_ksl_blk *head;
+  /* root points to the root block. */
+  ngtcp2_ksl_blk *root;
   /* front points to the first leaf block. */
   ngtcp2_ksl_blk *front;
   /* back points to the last leaf block. */
@@ -169,9 +159,7 @@ struct ngtcp2_ksl {
   size_t n;
   /* keylen is the size of key */
   size_t keylen;
-  /* nodelen is the actual size of ngtcp2_ksl_node including key
-     storage. */
-  size_t nodelen;
+  size_t aligned_keylen;
 };
 
 /*
@@ -290,10 +278,12 @@ size_t ngtcp2_ksl_len(const ngtcp2_ksl *
 void ngtcp2_ksl_clear(ngtcp2_ksl *ksl);
 
 /*
- * ngtcp2_ksl_nth_node returns the |n|th node under |blk|.
+ * ngtcp2_ksl_blk_nth_key returns the |n|th key under |blk|.
  */
-#define ngtcp2_ksl_nth_node(KSL, BLK, N)                                       \
-  ((ngtcp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
+static inline const ngtcp2_ksl_key *
+ngtcp2_ksl_blk_nth_key(const ngtcp2_ksl_blk *blk, size_t n) {
+  return blk->keys + n * blk->aligned_keylen;
+}
 
 #ifndef WIN32
 /*
@@ -307,26 +297,28 @@ void ngtcp2_ksl_print(const ngtcp2_ksl *
 /*
  * ngtcp2_ksl_it_init initializes |it|.
  */
-void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, const ngtcp2_ksl *ksl,
-                        ngtcp2_ksl_blk *blk, size_t i);
+void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, ngtcp2_ksl_blk *blk, size_t i);
 
 /*
  * ngtcp2_ksl_it_get returns the data associated to the node which
  * |it| points to.  It is undefined to call this function when
  * ngtcp2_ksl_it_end(it) returns nonzero.
  */
-#define ngtcp2_ksl_it_get(IT)                                                  \
-  ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->data
+static inline void *ngtcp2_ksl_it_get(const ngtcp2_ksl_it *it) {
+  return it->blk->nodes[it->i].data;
+}
 
 /*
  * ngtcp2_ksl_it_next advances the iterator by one.  It is undefined
  * if this function is called when ngtcp2_ksl_it_end(it) returns
  * nonzero.
  */
-#define ngtcp2_ksl_it_next(IT)                                                 \
-  (++(IT)->i == (IT)->blk->n && (IT)->blk->next                                \
-     ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0)                              \
-     : 0)
+static inline void ngtcp2_ksl_it_next(ngtcp2_ksl_it *it) {
+  if (++it->i == it->blk->n && it->blk->next) {
+    it->blk = it->blk->next;
+    it->i = 0;
+  }
+}
 
 /*
  * ngtcp2_ksl_it_prev moves backward the iterator by one.  It is
@@ -339,8 +331,9 @@ void ngtcp2_ksl_it_prev(ngtcp2_ksl_it *i
  * ngtcp2_ksl_it_end returns nonzero if |it| points to the one beyond
  * the last node.
  */
-#define ngtcp2_ksl_it_end(IT)                                                  \
-  ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
+static inline int ngtcp2_ksl_it_end(const ngtcp2_ksl_it *it) {
+  return it->blk->n == it->i && it->blk->next == NULL;
+}
 
 /*
  * ngtcp2_ksl_it_begin returns nonzero if |it| points to the first
@@ -354,8 +347,9 @@ int ngtcp2_ksl_it_begin(const ngtcp2_ksl
  * It is undefined to call this function when ngtcp2_ksl_it_end(it)
  * returns nonzero.
  */
-#define ngtcp2_ksl_it_key(IT)                                                  \
-  ((ngtcp2_ksl_key *)ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
+static inline const ngtcp2_ksl_key *ngtcp2_ksl_it_key(const ngtcp2_ksl_it *it) {
+  return ngtcp2_ksl_blk_nth_key(it->blk, it->i);
+}
 
 /*
  * ngtcp2_ksl_range_compar is an implementation of ngtcp2_ksl_compar.
@@ -363,8 +357,12 @@ int ngtcp2_ksl_it_begin(const ngtcp2_ksl
  * 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);
+static inline int ngtcp2_ksl_range_compar(const ngtcp2_ksl_key *lhs,
+                                          const ngtcp2_ksl_key *rhs) {
+  const ngtcp2_range *a = (const ngtcp2_range *)lhs,
+                     *b = (const ngtcp2_range *)rhs;
+  return a->begin < b->begin;
+}
 
 /*
  * ngtcp2_ksl_range_search is an implementation of ngtcp2_ksl_search
@@ -380,8 +378,13 @@ size_t ngtcp2_ksl_range_search(const ngt
  * *)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);
+static inline int ngtcp2_ksl_range_exclusive_compar(const ngtcp2_ksl_key *lhs,
+                                                    const ngtcp2_ksl_key *rhs) {
+  const ngtcp2_range *a = (const ngtcp2_range *)lhs,
+                     *b = (const ngtcp2_range *)rhs;
+  return a->begin < b->begin && !(ngtcp2_max_uint64(a->begin, b->begin) <
+                                  ngtcp2_min_uint64(a->end, b->end));
+}
 
 /*
  * ngtcp2_ksl_range_exclusive_search is an implementation of
@@ -396,8 +399,10 @@ size_t ngtcp2_ksl_range_exclusive_search
  * |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);
+static inline int ngtcp2_ksl_uint64_less(const ngtcp2_ksl_key *lhs,
+                                         const ngtcp2_ksl_key *rhs) {
+  return *(const uint64_t *)lhs < *(const uint64_t *)rhs;
+}
 
 /*
  * ngtcp2_ksl_uint64_less_search is an implementation of
@@ -411,8 +416,10 @@ size_t ngtcp2_ksl_uint64_less_search(con
  * |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);
+static inline int ngtcp2_ksl_int64_greater(const ngtcp2_ksl_key *lhs,
+                                           const ngtcp2_ksl_key *rhs) {
+  return *(const int64_t *)lhs > *(const int64_t *)rhs;
+}
 
 /*
  * ngtcp2_ksl_int64_greater_search is an implementation of
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_log.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_log.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_log.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_log.c	2026-05-15 15:49:15.162978400 +0200
@@ -42,12 +42,12 @@ void ngtcp2_log_init(ngtcp2_log *log, co
                      ngtcp2_printf log_printf, ngtcp2_tstamp ts,
                      void *user_data) {
   if (scid) {
-    ngtcp2_encode_hex(log->scid, scid->data, scid->datalen);
+    ngtcp2_encode_hex_cstr(log->scid, scid->data, scid->datalen);
   } else {
     log->scid[0] = '\0';
   }
   log->log_printf = log_printf;
-  log->events = 0xff;
+  log->events = 0xFF;
   log->ts = log->last_ts = ts;
   log->user_data = user_data;
 }
@@ -90,23 +90,10 @@ void ngtcp2_log_init(ngtcp2_log *log, co
  *   Frame type in hex string.
  */
 
-#define NGTCP2_LOG_BUFLEN 4096
+#define NGTCP2_LOG_PKT "%s %" PRId64 " %s"
+#define NGTCP2_LOG_TP "remote transport_parameters"
 
-/* TODO Split second and remaining fraction with comma */
-#define NGTCP2_LOG_HD "I%08" PRIu64 " 0x%s %s"
-#define NGTCP2_LOG_PKT NGTCP2_LOG_HD " %s %" PRId64 " %s"
-#define NGTCP2_LOG_TP NGTCP2_LOG_HD " remote transport_parameters"
-
-#define NGTCP2_LOG_FRM_HD_FIELDS(DIR)                                          \
-  timestamp_cast(log->last_ts - log->ts), (const char *)log->scid, "frm",      \
-    (DIR), hd->pkt_num, strpkttype(hd)
-
-#define NGTCP2_LOG_PKT_HD_FIELDS(DIR)                                          \
-  timestamp_cast(log->last_ts - log->ts), (const char *)log->scid, "pkt",      \
-    (DIR), hd->pkt_num, strpkttype(hd)
-
-#define NGTCP2_LOG_TP_HD_FIELDS                                                \
-  timestamp_cast(log->last_ts - log->ts), (const char *)log->scid, "cry"
+#define NGTCP2_LOG_PKT_HD_FIELDS(DIR) (DIR), hd->pkt_num, strpkttype(hd)
 
 static const char *strerrorcode(uint64_t error_code) {
   switch (error_code) {
@@ -140,10 +127,14 @@ static const char *strerrorcode(uint64_t
     return "CRYPTO_BUFFER_EXCEEDED";
   case NGTCP2_KEY_UPDATE_ERROR:
     return "KEY_UPDATE_ERROR";
+  case NGTCP2_AEAD_LIMIT_REACHED:
+    return "AEAD_LIMIT_REACHED";
+  case NGTCP2_NO_VIABLE_PATH:
+    return "NO_VIABLE_PATH";
   case NGTCP2_VERSION_NEGOTIATION_ERROR:
     return "VERSION_NEGOTIATION_ERROR";
   default:
-    if (0x100u <= error_code && error_code <= 0x1ffu) {
+    if (0x100U <= error_code && error_code <= 0x1FFU) {
       return "CRYPTO_ERROR";
     }
     return "(unknown)";
@@ -155,78 +146,41 @@ static const char *strapperrorcode(uint6
   return "(unknown)";
 }
 
-static const char *strpkttype_long(uint8_t type) {
-  switch (type) {
+static const char *strpkttype(const ngtcp2_pkt_hd *hd) {
+  switch (hd->type) {
   case NGTCP2_PKT_INITIAL:
     return "Initial";
-  case NGTCP2_PKT_RETRY:
-    return "Retry";
-  case NGTCP2_PKT_HANDSHAKE:
-    return "Handshake";
   case NGTCP2_PKT_0RTT:
     return "0RTT";
-  default:
-    return "(unknown)";
-  }
-}
-
-static const char *strpkttype(const ngtcp2_pkt_hd *hd) {
-  if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) {
-    return strpkttype_long(hd->type);
-  }
-
-  switch (hd->type) {
+  case NGTCP2_PKT_HANDSHAKE:
+    return "Handshake";
+  case NGTCP2_PKT_RETRY:
+    return "Retry";
+  case NGTCP2_PKT_1RTT:
+    return "1RTT";
   case NGTCP2_PKT_VERSION_NEGOTIATION:
     return "VN";
   case NGTCP2_PKT_STATELESS_RESET:
     return "SR";
-  case NGTCP2_PKT_1RTT:
-    return "1RTT";
   default:
     return "(unknown)";
   }
 }
 
 static const char *strpkttype_type_flags(uint8_t type, uint8_t flags) {
-  ngtcp2_pkt_hd hd = {0};
-
-  hd.type = type;
-  hd.flags = flags;
-
-  return strpkttype(&hd);
+  return strpkttype(&(ngtcp2_pkt_hd){
+    .type = type,
+    .flags = flags,
+  });
 }
 
-static const char *strevent(ngtcp2_log_event ev) {
-  switch (ev) {
-  case NGTCP2_LOG_EVENT_CON:
-    return "con";
-  case NGTCP2_LOG_EVENT_PKT:
-    return "pkt";
-  case NGTCP2_LOG_EVENT_FRM:
-    return "frm";
-  case NGTCP2_LOG_EVENT_LDC:
-    return "ldc";
-  case NGTCP2_LOG_EVENT_CRY:
-    return "cry";
-  case NGTCP2_LOG_EVENT_PTV:
-    return "ptv";
-  case NGTCP2_LOG_EVENT_CCA:
-    return "cca";
-  case NGTCP2_LOG_EVENT_NONE:
-  default:
-    return "non";
-  }
-}
-
-static uint64_t timestamp_cast(uint64_t ns) { return ns / NGTCP2_MILLISECONDS; }
-
 static void log_fr_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                           const ngtcp2_stream *fr, const char *dir) {
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " STREAM(0x%02" PRIx64 ") id=0x%" PRIx64
-                    " fin=%d offset=%" PRIu64 " len=%" PRIu64 " uni=%d"),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type | fr->flags, fr->stream_id, fr->fin,
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_FRM,
+    NGTCP2_LOG_PKT " STREAM(0x%02" PRIx64 ") id=0x%" PRIx64
+                   " fin=%d offset=%" PRIu64 " len=%" PRIu64 " uni=%d",
+    NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type | fr->flags, fr->stream_id, fr->fin,
     fr->offset, ngtcp2_vec_len(fr->data, fr->datacnt),
     (fr->stream_id & 0x2) != 0);
 }
@@ -236,58 +190,58 @@ static void log_fr_ack(ngtcp2_log *log,
   int64_t largest_ack, min_ack;
   size_t i;
 
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") largest_ack=%" PRId64
-                    " ack_delay=%" PRIu64 "(%" PRIu64 ") ack_range_count=%zu"),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->largest_ack,
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_FRM,
+    NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") largest_ack=%" PRId64
+                   " ack_delay=%" PRIu64 "(%" PRIu64 ") ack_range_count=%zu",
+    NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->largest_ack,
     fr->ack_delay_unscaled / NGTCP2_MILLISECONDS, fr->ack_delay, fr->rangecnt);
 
   largest_ack = fr->largest_ack;
   min_ack = fr->largest_ack - (int64_t)fr->first_ack_range;
 
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64
-                                  "..%" PRId64 "] len=%" PRIu64),
-                  NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack, min_ack,
-                  fr->first_ack_range);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64
+                                      "..%" PRId64 "] len=%" PRIu64,
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, largest_ack,
+                       min_ack, fr->first_ack_range);
 
   for (i = 0; i < fr->rangecnt; ++i) {
     const ngtcp2_ack_range *range = &fr->ranges[i];
     largest_ack = min_ack - (int64_t)range->gap - 2;
     min_ack = largest_ack - (int64_t)range->len;
-    log->log_printf(log->user_data,
-                    (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64
-                                    "..%" PRId64 "] gap=%" PRIu64
-                                    " len=%" PRIu64),
-                    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack,
-                    min_ack, range->gap, range->len);
+    ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                         NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64
+                                        "..%" PRId64 "] gap=%" PRIu64
+                                        " len=%" PRIu64,
+                         NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, largest_ack,
+                         min_ack, range->gap, range->len);
   }
 
   if (fr->type == NGTCP2_FRAME_ACK_ECN) {
-    log->log_printf(log->user_data,
-                    (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") ect0=%" PRIu64
-                                    " ect1=%" PRIu64 " ce=%" PRIu64),
-                    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->ecn.ect0,
-                    fr->ecn.ect1, fr->ecn.ce);
+    ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                         NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") ect0=%" PRIu64
+                                        " ect1=%" PRIu64 " ce=%" PRIu64,
+                         NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->ecn.ect0,
+                         fr->ecn.ect1, fr->ecn.ce);
   }
 }
 
 static void log_fr_padding(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                            const ngtcp2_padding *fr, const char *dir) {
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_PKT " PADDING(0x%02" PRIx64 ") len=%zu"),
-                  NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->len);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " PADDING(0x%02" PRIx64 ") len=%zu",
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->len);
 }
 
 static void log_fr_reset_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                 const ngtcp2_reset_stream *fr,
                                 const char *dir) {
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " RESET_STREAM(0x%02" PRIx64 ") id=0x%" PRIx64
-                    " app_error_code=%s(0x%" PRIx64 ") final_size=%" PRIu64),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_FRM,
+    NGTCP2_LOG_PKT " RESET_STREAM(0x%02" PRIx64 ") id=0x%" PRIx64
+                   " app_error_code=%s(0x%" PRIx64 ") final_size=%" PRIu64,
+    NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id,
     strapperrorcode(fr->app_error_code), fr->app_error_code, fr->final_size);
 }
 
@@ -297,189 +251,191 @@ static void log_fr_connection_close(ngtc
   char reason[256];
   size_t reasonlen = ngtcp2_min_size(sizeof(reason) - 1, fr->reasonlen);
 
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " CONNECTION_CLOSE(0x%02" PRIx64
-                    ") error_code=%s(0x%" PRIx64 ") "
-                    "frame_type=%" PRIx64 " reason_len=%zu reason=[%s]"),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_FRM,
+    NGTCP2_LOG_PKT " CONNECTION_CLOSE(0x%02" PRIx64 ") error_code=%s(0x%" PRIx64
+                   ") "
+                   "frame_type=0x%" PRIx64 " reason_len=%zu reason=[%s]",
+    NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
     fr->type == NGTCP2_FRAME_CONNECTION_CLOSE ? strerrorcode(fr->error_code)
                                               : strapperrorcode(fr->error_code),
     fr->error_code, fr->frame_type, fr->reasonlen,
-    ngtcp2_encode_printable_ascii(reason, fr->reason, reasonlen));
+    ngtcp2_encode_printable_ascii_cstr(reason, fr->reason, reasonlen));
 }
 
 static void log_fr_max_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                             const ngtcp2_max_data *fr, const char *dir) {
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " MAX_DATA(0x%02" PRIx64 ") max_data=%" PRIu64),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_data);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " MAX_DATA(0x%02" PRIx64
+                                      ") max_data=%" PRIu64,
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->max_data);
 }
 
 static void log_fr_max_stream_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                    const ngtcp2_max_stream_data *fr,
                                    const char *dir) {
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_PKT " MAX_STREAM_DATA(0x%02" PRIx64
-                                  ") id=0x%" PRIx64
-                                  " max_stream_data=%" PRIu64),
-                  NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
-                  fr->max_stream_data);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " MAX_STREAM_DATA(0x%02" PRIx64
+                                      ") id=0x%" PRIx64
+                                      " max_stream_data=%" PRIu64,
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id,
+                       fr->max_stream_data);
 }
 
 static void log_fr_max_streams(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                const ngtcp2_max_streams *fr, const char *dir) {
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " MAX_STREAMS(0x%02" PRIx64 ") max_streams=%" PRIu64),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams);
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_FRM,
+    NGTCP2_LOG_PKT " MAX_STREAMS(0x%02" PRIx64 ") max_streams=%" PRIu64,
+    NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->max_streams);
 }
 
 static void log_fr_ping(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                         const ngtcp2_ping *fr, const char *dir) {
-  log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PING(0x%02" PRIx64 ")"),
-                  NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " PING(0x%02" PRIx64 ")",
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type);
 }
 
 static void log_fr_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                 const ngtcp2_data_blocked *fr,
                                 const char *dir) {
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " DATA_BLOCKED(0x%02" PRIx64 ") offset=%" PRIu64),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " DATA_BLOCKED(0x%02" PRIx64
+                                      ") offset=%" PRIu64,
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->offset);
 }
 
 static void log_fr_stream_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                        const ngtcp2_stream_data_blocked *fr,
                                        const char *dir) {
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02" PRIx64
-                                  ") id=0x%" PRIx64 " offset=%" PRIu64),
-                  NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
-                  fr->offset);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02" PRIx64
+                                      ") id=0x%" PRIx64 " offset=%" PRIu64,
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id,
+                       fr->offset);
 }
 
 static void log_fr_streams_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                    const ngtcp2_streams_blocked *fr,
                                    const char *dir) {
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " STREAMS_BLOCKED(0x%02" PRIx64 ") max_streams=%" PRIu64),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams);
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_FRM,
+    NGTCP2_LOG_PKT " STREAMS_BLOCKED(0x%02" PRIx64 ") max_streams=%" PRIu64,
+    NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->max_streams);
 }
 
 static void log_fr_new_connection_id(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                      const ngtcp2_new_connection_id *fr,
                                      const char *dir) {
-  uint8_t buf[sizeof(fr->stateless_reset_token) * 2 + 1];
-  uint8_t cid[sizeof(fr->cid.data) * 2 + 1];
+  char buf[sizeof(fr->token.data) * 2 + 1];
+  char cid[sizeof(fr->cid.data) * 2 + 1];
 
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " NEW_CONNECTION_ID(0x%02" PRIx64 ") seq=%" PRIu64
-                    " cid=0x%s retire_prior_to=%" PRIu64
-                    " stateless_reset_token=0x%s"),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq,
-    (const char *)ngtcp2_encode_hex(cid, fr->cid.data, fr->cid.datalen),
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_FRM,
+    NGTCP2_LOG_PKT " NEW_CONNECTION_ID(0x%02" PRIx64 ") seq=%" PRIu64
+                   " cid=0x%s retire_prior_to=%" PRIu64
+                   " stateless_reset_token=0x%s",
+    NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->seq,
+    ngtcp2_encode_hex_cstr(cid, fr->cid.data, fr->cid.datalen),
     fr->retire_prior_to,
-    (const char *)ngtcp2_encode_hex(buf, fr->stateless_reset_token,
-                                    sizeof(fr->stateless_reset_token)));
+    ngtcp2_encode_hex_cstr(buf, fr->token.data, sizeof(fr->token.data)));
 }
 
 static void log_fr_stop_sending(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                 const ngtcp2_stop_sending *fr,
                                 const char *dir) {
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_PKT " STOP_SENDING(0x%02" PRIx64 ") id=0x%" PRIx64
-                                  " app_error_code=%s(0x%" PRIx64 ")"),
-                  NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
-                  strapperrorcode(fr->app_error_code), fr->app_error_code);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " STOP_SENDING(0x%02" PRIx64
+                                      ") id=0x%" PRIx64
+                                      " app_error_code=%s(0x%" PRIx64 ")",
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id,
+                       strapperrorcode(fr->app_error_code), fr->app_error_code);
 }
 
 static void log_fr_path_challenge(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                   const ngtcp2_path_challenge *fr,
                                   const char *dir) {
-  uint8_t buf[sizeof(fr->data) * 2 + 1];
+  char buf[sizeof(fr->data.data) * 2 + 1];
 
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64 ") data=0x%s"),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
-    (const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data)));
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_FRM,
+    NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64 ") data=0x%s",
+    NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
+    ngtcp2_encode_hex_cstr(buf, fr->data.data, sizeof(fr->data.data)));
 }
 
 static void log_fr_path_response(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                  const ngtcp2_path_response *fr,
                                  const char *dir) {
-  uint8_t buf[sizeof(fr->data) * 2 + 1];
+  char buf[sizeof(fr->data.data) * 2 + 1];
 
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64 ") data=0x%s"),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
-    (const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data)));
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_FRM,
+    NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64 ") data=0x%s",
+    NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
+    ngtcp2_encode_hex_cstr(buf, fr->data.data, sizeof(fr->data.data)));
 }
 
 static void log_fr_crypto(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                           const ngtcp2_stream *fr, const char *dir) {
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " CRYPTO(0x%02" PRIx64 ") offset=%" PRIu64 " len=%" PRIu64),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset,
-    ngtcp2_vec_len(fr->data, fr->datacnt));
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " CRYPTO(0x%02" PRIx64 ") offset=%" PRIu64
+                                      " len=%" PRIu64,
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->offset,
+                       ngtcp2_vec_len(fr->data, fr->datacnt));
 }
 
 static void log_fr_new_token(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                              const ngtcp2_new_token *fr, const char *dir) {
   /* Show at most first 64 bytes of token.  If token is longer than 64
      bytes, log first 64 bytes and then append "*" */
-  uint8_t buf[128 + 1 + 1];
-  uint8_t *p;
+  char buf[128 + 1 + 1];
+  char *p;
 
   if (fr->tokenlen > 64) {
-    p = ngtcp2_encode_hex(buf, fr->token, 64);
+    p = ngtcp2_encode_hex_cstr(buf, fr->token, 64);
     p[128] = '*';
     p[129] = '\0';
   } else {
-    p = ngtcp2_encode_hex(buf, fr->token, fr->tokenlen);
+    p = ngtcp2_encode_hex_cstr(buf, fr->token, fr->tokenlen);
   }
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " NEW_TOKEN(0x%02" PRIx64 ") token=0x%s len=%zu"),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)p, fr->tokenlen);
+
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_FRM,
+    NGTCP2_LOG_PKT " NEW_TOKEN(0x%02" PRIx64 ") token=0x%s len=%zu",
+    NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, p, fr->tokenlen);
 }
 
 static void log_fr_retire_connection_id(ngtcp2_log *log,
                                         const ngtcp2_pkt_hd *hd,
                                         const ngtcp2_retire_connection_id *fr,
                                         const char *dir) {
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_PKT " RETIRE_CONNECTION_ID(0x%02" PRIx64 ") seq=%" PRIu64),
-    NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " RETIRE_CONNECTION_ID(0x%02" PRIx64
+                                      ") seq=%" PRIu64,
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->seq);
 }
 
 static void log_fr_handshake_done(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                                   const ngtcp2_handshake_done *fr,
                                   const char *dir) {
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_PKT " HANDSHAKE_DONE(0x%02" PRIx64 ")"),
-                  NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " HANDSHAKE_DONE(0x%02" PRIx64 ")",
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type);
 }
 
 static void log_fr_datagram(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                             const ngtcp2_datagram *fr, const char *dir) {
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_PKT " DATAGRAM(0x%02" PRIx64 ") len=%" PRIu64),
-                  NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
-                  ngtcp2_vec_len(fr->data, fr->datacnt));
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+                       NGTCP2_LOG_PKT " DATAGRAM(0x%02" PRIx64 ") len=%" PRIu64,
+                       NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
+                       ngtcp2_vec_len(fr->data, fr->datacnt));
 }
 
 static void log_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                    const ngtcp2_frame *fr, const char *dir) {
-  switch (fr->type) {
+  switch (fr->hd.type) {
   case NGTCP2_FRAME_STREAM:
     log_fr_stream(log, hd, &fr->stream, dir);
     break;
@@ -580,13 +536,13 @@ void ngtcp2_log_rx_vn(ngtcp2_log *log, c
   }
 
   for (i = 0; i < nsv; ++i) {
-    log->log_printf(log->user_data, (NGTCP2_LOG_PKT " v=0x%08x"),
-                    NGTCP2_LOG_PKT_HD_FIELDS("rx"), sv[i]);
+    ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_PKT, NGTCP2_LOG_PKT " v=0x%08x",
+                         NGTCP2_LOG_PKT_HD_FIELDS("rx"), sv[i]);
   }
 }
 
-void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) {
-  uint8_t buf[sizeof(sr->stateless_reset_token) * 2 + 1];
+void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset2 *sr) {
+  char buf[sizeof(sr->token.data) * 2 + 1];
   ngtcp2_pkt_hd shd;
   ngtcp2_pkt_hd *hd = &shd;
 
@@ -594,23 +550,22 @@ void ngtcp2_log_rx_sr(ngtcp2_log *log, c
     return;
   }
 
-  memset(&shd, 0, sizeof(shd));
-
-  shd.type = NGTCP2_PKT_STATELESS_RESET;
+  shd = (ngtcp2_pkt_hd){
+    .type = NGTCP2_PKT_STATELESS_RESET,
+  };
 
-  log->log_printf(
-    log->user_data, (NGTCP2_LOG_PKT " token=0x%s randlen=%zu"),
+  ngtcp2_log_infof_raw(
+    log, NGTCP2_LOG_EVENT_PKT, NGTCP2_LOG_PKT " token=0x%s randlen=%zu",
     NGTCP2_LOG_PKT_HD_FIELDS("rx"),
-    (const char *)ngtcp2_encode_hex(buf, sr->stateless_reset_token,
-                                    sizeof(sr->stateless_reset_token)),
+    ngtcp2_encode_hex_cstr(buf, sr->token.data, sizeof(sr->token.data)),
     sr->randlen);
 }
 
 void ngtcp2_log_remote_tp(ngtcp2_log *log,
                           const ngtcp2_transport_params *params) {
-  uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN * 2 + 1];
-  uint8_t addr[16 * 2 + 7 + 1];
-  uint8_t cid[NGTCP2_MAX_CIDLEN * 2 + 1];
+  char token[sizeof(params->stateless_reset_token) * 2 + 1];
+  char addr[16 * 2 + 7 + 1];
+  char cid[NGTCP2_MAX_CIDLEN * 2 + 1];
   size_t i;
   const ngtcp2_sockaddr_in *sa_in;
   const ngtcp2_sockaddr_in6 *sa_in6;
@@ -622,127 +577,121 @@ void ngtcp2_log_remote_tp(ngtcp2_log *lo
   }
 
   if (params->stateless_reset_token_present) {
-    log->log_printf(
-      log->user_data, (NGTCP2_LOG_TP " stateless_reset_token=0x%s"),
-      NGTCP2_LOG_TP_HD_FIELDS,
-      (const char *)ngtcp2_encode_hex(token, params->stateless_reset_token,
-                                      sizeof(params->stateless_reset_token)));
+    ngtcp2_log_infof_raw(
+      log, NGTCP2_LOG_EVENT_CRY, NGTCP2_LOG_TP " stateless_reset_token=0x%s",
+      ngtcp2_encode_hex_cstr(token, params->stateless_reset_token,
+                             sizeof(params->stateless_reset_token)));
   }
 
   if (params->preferred_addr_present) {
     if (params->preferred_addr.ipv4_present) {
       sa_in = &params->preferred_addr.ipv4;
 
-      log->log_printf(log->user_data,
-                      (NGTCP2_LOG_TP " preferred_address.ipv4_addr=%s"),
-                      NGTCP2_LOG_TP_HD_FIELDS,
-                      (const char *)ngtcp2_encode_ipv4(
-                        addr, (const uint8_t *)&sa_in->sin_addr));
-      log->log_printf(log->user_data,
-                      (NGTCP2_LOG_TP " preferred_address.ipv4_port=%u"),
-                      NGTCP2_LOG_TP_HD_FIELDS, ngtcp2_ntohs(sa_in->sin_port));
+      ngtcp2_log_infof_raw(
+        log, NGTCP2_LOG_EVENT_CRY,
+        NGTCP2_LOG_TP " preferred_address.ipv4_addr=%s",
+        ngtcp2_encode_ipv4_cstr(addr, (const uint8_t *)&sa_in->sin_addr));
+      ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                           NGTCP2_LOG_TP " preferred_address.ipv4_port=%u",
+                           ngtcp2_ntohs(sa_in->sin_port));
     }
 
     if (params->preferred_addr.ipv6_present) {
       sa_in6 = &params->preferred_addr.ipv6;
 
-      log->log_printf(log->user_data,
-                      (NGTCP2_LOG_TP " preferred_address.ipv6_addr=%s"),
-                      NGTCP2_LOG_TP_HD_FIELDS,
-                      (const char *)ngtcp2_encode_ipv6(
-                        addr, (const uint8_t *)&sa_in6->sin6_addr));
-      log->log_printf(log->user_data,
-                      (NGTCP2_LOG_TP " preferred_address.ipv6_port=%u"),
-                      NGTCP2_LOG_TP_HD_FIELDS, ngtcp2_ntohs(sa_in6->sin6_port));
+      ngtcp2_log_infof_raw(
+        log, NGTCP2_LOG_EVENT_CRY,
+        NGTCP2_LOG_TP " preferred_address.ipv6_addr=%s",
+        ngtcp2_encode_ipv6_cstr(addr, (const uint8_t *)&sa_in6->sin6_addr));
+      ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                           NGTCP2_LOG_TP " preferred_address.ipv6_port=%u",
+                           ngtcp2_ntohs(sa_in6->sin6_port));
     }
 
-    log->log_printf(
-      log->user_data, (NGTCP2_LOG_TP " preferred_address.cid=0x%s"),
-      NGTCP2_LOG_TP_HD_FIELDS,
-      (const char *)ngtcp2_encode_hex(cid, params->preferred_addr.cid.data,
-                                      params->preferred_addr.cid.datalen));
-    log->log_printf(
-      log->user_data,
-      (NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s"),
-      NGTCP2_LOG_TP_HD_FIELDS,
-      (const char *)ngtcp2_encode_hex(
+    ngtcp2_log_infof_raw(
+      log, NGTCP2_LOG_EVENT_CRY, NGTCP2_LOG_TP " preferred_address.cid=0x%s",
+      ngtcp2_encode_hex_cstr(cid, params->preferred_addr.cid.data,
+                             params->preferred_addr.cid.datalen));
+    ngtcp2_log_infof_raw(
+      log, NGTCP2_LOG_EVENT_CRY,
+      NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s",
+      ngtcp2_encode_hex_cstr(
         token, params->preferred_addr.stateless_reset_token,
         sizeof(params->preferred_addr.stateless_reset_token)));
   }
 
   if (params->original_dcid_present) {
-    log->log_printf(
-      log->user_data,
-      (NGTCP2_LOG_TP " original_destination_connection_id=0x%s"),
-      NGTCP2_LOG_TP_HD_FIELDS,
-      (const char *)ngtcp2_encode_hex(cid, params->original_dcid.data,
-                                      params->original_dcid.datalen));
+    ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                         NGTCP2_LOG_TP
+                         " original_destination_connection_id=0x%s",
+                         ngtcp2_encode_hex_cstr(cid, params->original_dcid.data,
+                                                params->original_dcid.datalen));
   }
 
   if (params->retry_scid_present) {
-    log->log_printf(
-      log->user_data, (NGTCP2_LOG_TP " retry_source_connection_id=0x%s"),
-      NGTCP2_LOG_TP_HD_FIELDS,
-      (const char *)ngtcp2_encode_hex(cid, params->retry_scid.data,
-                                      params->retry_scid.datalen));
+    ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                         NGTCP2_LOG_TP " retry_source_connection_id=0x%s",
+                         ngtcp2_encode_hex_cstr(cid, params->retry_scid.data,
+                                                params->retry_scid.datalen));
   }
 
   if (params->initial_scid_present) {
-    log->log_printf(
-      log->user_data, (NGTCP2_LOG_TP " initial_source_connection_id=0x%s"),
-      NGTCP2_LOG_TP_HD_FIELDS,
-      (const char *)ngtcp2_encode_hex(cid, params->initial_scid.data,
-                                      params->initial_scid.datalen));
-  }
-
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_TP " initial_max_stream_data_bidi_local=%" PRIu64),
-    NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_bidi_local);
-  log->log_printf(
-    log->user_data,
-    (NGTCP2_LOG_TP " initial_max_stream_data_bidi_remote=%" PRIu64),
-    NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_bidi_remote);
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_TP " initial_max_stream_data_uni=%" PRIu64),
-                  NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_uni);
-  log->log_printf(log->user_data, (NGTCP2_LOG_TP " initial_max_data=%" PRIu64),
-                  NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_data);
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_TP " initial_max_streams_bidi=%" PRIu64),
-                  NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_streams_bidi);
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_TP " initial_max_streams_uni=%" PRIu64),
-                  NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_streams_uni);
-  log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_idle_timeout=%" PRIu64),
-                  NGTCP2_LOG_TP_HD_FIELDS,
-                  params->max_idle_timeout / NGTCP2_MILLISECONDS);
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_TP " max_udp_payload_size=%" PRIu64),
-                  NGTCP2_LOG_TP_HD_FIELDS, params->max_udp_payload_size);
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_TP " ack_delay_exponent=%" PRIu64),
-                  NGTCP2_LOG_TP_HD_FIELDS, params->ack_delay_exponent);
-  log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_ack_delay=%" PRIu64),
-                  NGTCP2_LOG_TP_HD_FIELDS,
-                  params->max_ack_delay / NGTCP2_MILLISECONDS);
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_TP " active_connection_id_limit=%" PRIu64),
-                  NGTCP2_LOG_TP_HD_FIELDS, params->active_connection_id_limit);
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_TP " disable_active_migration=%d"),
-                  NGTCP2_LOG_TP_HD_FIELDS, params->disable_active_migration);
-  log->log_printf(log->user_data,
-                  (NGTCP2_LOG_TP " max_datagram_frame_size=%" PRIu64),
-                  NGTCP2_LOG_TP_HD_FIELDS, params->max_datagram_frame_size);
-  log->log_printf(log->user_data, (NGTCP2_LOG_TP " grease_quic_bit=%d"),
-                  NGTCP2_LOG_TP_HD_FIELDS, params->grease_quic_bit);
+    ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                         NGTCP2_LOG_TP " initial_source_connection_id=0x%s",
+                         ngtcp2_encode_hex_cstr(cid, params->initial_scid.data,
+                                                params->initial_scid.datalen));
+  }
+
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP
+                       " initial_max_stream_data_bidi_local=%" PRIu64,
+                       params->initial_max_stream_data_bidi_local);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP
+                       " initial_max_stream_data_bidi_remote=%" PRIu64,
+                       params->initial_max_stream_data_bidi_remote);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " initial_max_stream_data_uni=%" PRIu64,
+                       params->initial_max_stream_data_uni);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " initial_max_data=%" PRIu64,
+                       params->initial_max_data);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " initial_max_streams_bidi=%" PRIu64,
+                       params->initial_max_streams_bidi);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " initial_max_streams_uni=%" PRIu64,
+                       params->initial_max_streams_uni);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " max_idle_timeout=%" PRIu64,
+                       params->max_idle_timeout / NGTCP2_MILLISECONDS);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " max_udp_payload_size=%" PRIu64,
+                       params->max_udp_payload_size);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " ack_delay_exponent=%" PRIu64,
+                       params->ack_delay_exponent);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " max_ack_delay=%" PRIu64,
+                       params->max_ack_delay / NGTCP2_MILLISECONDS);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " active_connection_id_limit=%" PRIu64,
+                       params->active_connection_id_limit);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " disable_active_migration=%d",
+                       params->disable_active_migration);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " max_datagram_frame_size=%" PRIu64,
+                       params->max_datagram_frame_size);
+  ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                       NGTCP2_LOG_TP " grease_quic_bit=%d",
+                       params->grease_quic_bit);
 
   if (params->version_info_present) {
-    log->log_printf(
-      log->user_data,
-      (NGTCP2_LOG_TP " version_information.chosen_version=0x%08x"),
-      NGTCP2_LOG_TP_HD_FIELDS, params->version_info.chosen_version);
+    ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+                         NGTCP2_LOG_TP
+                         " version_information.chosen_version=0x%08x",
+                         params->version_info.chosen_version);
 
     assert(!(params->version_info.available_versionslen & 0x3));
 
@@ -751,10 +700,10 @@ void ngtcp2_log_remote_tp(ngtcp2_log *lo
          i += sizeof(uint32_t)) {
       p = ngtcp2_get_uint32be(&version, p);
 
-      log->log_printf(
-        log->user_data,
-        (NGTCP2_LOG_TP " version_information.available_versions[%zu]=0x%08x"),
-        NGTCP2_LOG_TP_HD_FIELDS, i >> 2, version);
+      ngtcp2_log_infof_raw(
+        log, NGTCP2_LOG_EVENT_CRY,
+        NGTCP2_LOG_TP " version_information.available_versions[%zu]=0x%08x",
+        i >> 2, version);
     }
   }
 }
@@ -765,33 +714,33 @@ void ngtcp2_log_pkt_lost(ngtcp2_log *log
     return;
   }
 
-  ngtcp2_log_info(log, NGTCP2_LOG_EVENT_LDC,
-                  "pkn=%" PRId64 " lost type=%s sent_ts=%" PRIu64, pkt_num,
-                  strpkttype_type_flags(type, flags), sent_ts);
+  ngtcp2_log_infof(log, NGTCP2_LOG_EVENT_LDC,
+                   "pkn=%" PRId64 " lost type=%s sent_ts=%" PRIu64, pkt_num,
+                   strpkttype_type_flags(type, flags), sent_ts);
 }
 
 static void log_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                        const char *dir) {
-  uint8_t dcid[sizeof(hd->dcid.data) * 2 + 1];
-  uint8_t scid[sizeof(hd->scid.data) * 2 + 1];
+  char dcid[sizeof(hd->dcid.data) * 2 + 1];
+  char scid[sizeof(hd->scid.data) * 2 + 1];
 
   if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) {
     return;
   }
 
   if (hd->type == NGTCP2_PKT_1RTT) {
-    ngtcp2_log_info(
+    ngtcp2_log_infof(
       log, NGTCP2_LOG_EVENT_PKT, "%s pkn=%" PRId64 " dcid=0x%s type=%s k=%d",
       dir, hd->pkt_num,
-      (const char *)ngtcp2_encode_hex(dcid, hd->dcid.data, hd->dcid.datalen),
+      ngtcp2_encode_hex_cstr(dcid, hd->dcid.data, hd->dcid.datalen),
       strpkttype(hd), (hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE) != 0);
   } else {
-    ngtcp2_log_info(
+    ngtcp2_log_infof(
       log, NGTCP2_LOG_EVENT_PKT,
       "%s pkn=%" PRId64 " dcid=0x%s scid=0x%s version=0x%08x type=%s len=%zu",
       dir, hd->pkt_num,
-      (const char *)ngtcp2_encode_hex(dcid, hd->dcid.data, hd->dcid.datalen),
-      (const char *)ngtcp2_encode_hex(scid, hd->scid.data, hd->scid.datalen),
+      ngtcp2_encode_hex_cstr(dcid, hd->dcid.data, hd->dcid.datalen),
+      ngtcp2_encode_hex_cstr(scid, hd->scid.data, hd->scid.datalen),
       hd->version, strpkttype(hd), hd->len);
   }
 }
@@ -804,31 +753,6 @@ void ngtcp2_log_tx_pkt_hd(ngtcp2_log *lo
   log_pkt_hd(log, hd, "tx");
 }
 
-void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, const char *fmt,
-                     ...) {
-  va_list ap;
-  int n;
-  char buf[NGTCP2_LOG_BUFLEN];
-
-  if (!log->log_printf || !(log->events & ev)) {
-    return;
-  }
-
-  va_start(ap, fmt);
-  n = vsnprintf(buf, sizeof(buf), fmt, ap);
-  va_end(ap);
-
-  if (n < 0 || (size_t)n >= sizeof(buf)) {
-    return;
-  }
-
-  log->log_printf(log->user_data, (NGTCP2_LOG_HD " %s"),
-                  timestamp_cast(log->last_ts - log->ts), log->scid,
-                  strevent(ev), buf);
-}
-
-void ngtcp2_log_tx_cancel(ngtcp2_log *log, const ngtcp2_pkt_hd *hd) {
-  ngtcp2_log_info(log, NGTCP2_LOG_EVENT_PKT,
-                  "cancel tx pkn=%" PRId64 " type=%s", hd->pkt_num,
-                  strpkttype(hd));
+uint64_t ngtcp2_log_timestamp(const ngtcp2_log *log) {
+  return (log->last_ts - log->ts) / NGTCP2_MILLISECONDS;
 }
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_log.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_log.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_log.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_log.h	2026-05-15 15:49:15.162978400 +0200
@@ -49,7 +49,7 @@ typedef struct ngtcp2_log {
      log_pritnf. */
   void *user_data;
   /* scid is SCID encoded as NULL-terminated hex string. */
-  uint8_t scid[NGTCP2_MAX_CIDLEN * 2 + 1];
+  char scid[NGTCP2_MAX_CIDLEN * 2 + 1];
 } ngtcp2_log;
 
 /**
@@ -107,7 +107,7 @@ void ngtcp2_log_tx_fr(ngtcp2_log *log, c
 void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
                       const uint32_t *sv, size_t nsv);
 
-void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr);
+void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset2 *sr);
 
 void ngtcp2_log_remote_tp(ngtcp2_log *log,
                           const ngtcp2_transport_params *params);
@@ -119,14 +119,71 @@ void ngtcp2_log_rx_pkt_hd(ngtcp2_log *lo
 
 void ngtcp2_log_tx_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd);
 
-void ngtcp2_log_tx_cancel(ngtcp2_log *log, const ngtcp2_pkt_hd *hd);
+#define NGTCP2_LOG_HD "I%08" PRIu64 " 0x%s %s"
+
+uint64_t ngtcp2_log_timestamp(const ngtcp2_log *log);
+
+static inline const char *ngtcp2_log_event_str(ngtcp2_log_event ev) {
+  switch (ev) {
+  case NGTCP2_LOG_EVENT_CON:
+    return "con";
+  case NGTCP2_LOG_EVENT_PKT:
+    return "pkt";
+  case NGTCP2_LOG_EVENT_FRM:
+    return "frm";
+  case NGTCP2_LOG_EVENT_LDC:
+    return "ldc";
+  case NGTCP2_LOG_EVENT_CRY:
+    return "cry";
+  case NGTCP2_LOG_EVENT_PTV:
+    return "ptv";
+  case NGTCP2_LOG_EVENT_CCA:
+    return "cca";
+  case NGTCP2_LOG_EVENT_NONE:
+  default:
+    return "non";
+  }
+}
+
+#define ngtcp2_log_infof_raw(LOG, EV, FMT, ...)                                \
+  (LOG)->log_printf((LOG)->user_data, NGTCP2_LOG_HD " " FMT,                   \
+                    ngtcp2_log_timestamp(LOG), (LOG)->scid,                    \
+                    ngtcp2_log_event_str(EV), __VA_ARGS__);
+
+/**
+ * @function
+ *
+ * `ngtcp2_log_infof` writes info level log with printf like
+ * formatting.
+ */
+#define ngtcp2_log_infof(LOG, EV, FMT, ...)                                    \
+  do {                                                                         \
+    if (!(LOG)->log_printf || !((LOG)->events & (EV))) {                       \
+      break;                                                                   \
+    }                                                                          \
+                                                                               \
+    ngtcp2_log_infof_raw((LOG), (EV), FMT, __VA_ARGS__);                       \
+  } while (0)
+
+#define ngtcp2_log_info_raw(LOG, EV, FMT)                                      \
+  (LOG)->log_printf((LOG)->user_data, NGTCP2_LOG_HD " " FMT,                   \
+                    ngtcp2_log_timestamp(LOG), (LOG)->scid,                    \
+                    ngtcp2_log_event_str(EV))
 
 /**
  * @function
  *
- * `ngtcp2_log_info` writes info level log.
+ * `ngtcp2_log_info` writes info level log.  FMT should not contain
+ * formatting directive.  This function exists to workaround the issue
+ * that __VA_ARGS__ cannot be empty.
  */
-void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, const char *fmt,
-                     ...);
+#define ngtcp2_log_info(LOG, EV, FMT)                                          \
+  do {                                                                         \
+    if (!(LOG)->log_printf || !((LOG)->events & (EV))) {                       \
+      break;                                                                   \
+    }                                                                          \
+                                                                               \
+    ngtcp2_log_info_raw((LOG), (EV), FMT);                                     \
+  } while (0)
 
 #endif /* !defined(NGTCP2_LOG_H) */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_macro.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_macro.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_macro.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_macro.h	2026-05-15 15:49:15.163978600 +0200
@@ -52,6 +52,13 @@
  */
 #define ngtcp2_arraylen(A) (sizeof(A) / sizeof(A[0]))
 
+/*
+ * ngtcp2_strlen_lit returns the length of string literal |S|.  This
+ * macro assumes |S| is NULL-terminated string literal.  It must not
+ * be used with pointers.
+ */
+#define ngtcp2_strlen_lit(S) (sizeof(S) - 1)
+
 #define ngtcp2_max_def(SUFFIX, T)                                              \
   static inline T ngtcp2_max_##SUFFIX(T a, T b) { return a < b ? b : a; }
 
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_map.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_map.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_map.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_map.c	2026-05-15 15:49:15.163978600 +0200
@@ -33,11 +33,11 @@
 
 #define NGTCP2_INITIAL_HASHBITS 4
 
-void ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem) {
-  map->mem = mem;
-  map->hashbits = 0;
-  map->table = NULL;
-  map->size = 0;
+void ngtcp2_map_init(ngtcp2_map *map, uint64_t seed, const ngtcp2_mem *mem) {
+  *map = (ngtcp2_map){
+    .mem = mem,
+    .seed = seed,
+  };
 }
 
 void ngtcp2_map_free(ngtcp2_map *map) {
@@ -45,30 +45,27 @@ void ngtcp2_map_free(ngtcp2_map *map) {
     return;
   }
 
-  ngtcp2_mem_free(map->mem, map->table);
+  ngtcp2_mem_free(map->mem, map->keys);
 }
 
 int ngtcp2_map_each(const ngtcp2_map *map, int (*func)(void *data, void *ptr),
                     void *ptr) {
   int rv;
   size_t i;
-  ngtcp2_map_bucket *bkt;
   size_t tablelen;
 
   if (map->size == 0) {
     return 0;
   }
 
-  tablelen = 1u << map->hashbits;
+  tablelen = (size_t)1 << map->hashbits;
 
   for (i = 0; i < tablelen; ++i) {
-    bkt = &map->table[i];
-
-    if (bkt->data == NULL) {
+    if (map->psl[i] == 0) {
       continue;
     }
 
-    rv = func(bkt->data, ptr);
+    rv = func(map->data[i], ptr);
     if (rv != 0) {
       return rv;
     }
@@ -77,168 +74,228 @@ int ngtcp2_map_each(const ngtcp2_map *ma
   return 0;
 }
 
-static size_t hash(ngtcp2_map_key_type key, size_t bits) {
-  return (size_t)((key * 11400714819323198485llu) >> (64 - bits));
-}
-
-static void map_bucket_swap(ngtcp2_map_bucket *a, ngtcp2_map_bucket *b) {
-  ngtcp2_map_bucket c = *a;
-
-  *a = *b;
-  *b = c;
+/* Hasher from
+   https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
+   to maximize the output's sensitivity to all input bits. */
+#define NGTCP2_MAP_HASHER 0xF1357AEA2E62A9C5ULL
+/* 64-bit Fibonacci hashing constant, Golden Ratio constant, to get
+   the high bits with the good distribution. */
+#define NGTCP2_MAP_FIBO 0x9E3779B97F4A7C15ULL
+
+static size_t map_index(const ngtcp2_map *map, ngtcp2_map_key_type key) {
+  key += map->seed;
+  key *= NGTCP2_MAP_HASHER;
+  return (size_t)((key * NGTCP2_MAP_FIBO) >> (64 - map->hashbits));
 }
 
 #ifndef WIN32
 void ngtcp2_map_print_distance(const ngtcp2_map *map) {
   size_t i;
   size_t idx;
-  ngtcp2_map_bucket *bkt;
   size_t tablelen;
 
   if (map->size == 0) {
     return;
   }
 
-  tablelen = 1u << map->hashbits;
+  tablelen = (size_t)1 << map->hashbits;
 
   for (i = 0; i < tablelen; ++i) {
-    bkt = &map->table[i];
-
-    if (bkt->data == NULL) {
+    if (map->psl[i] == 0) {
       fprintf(stderr, "@%zu <EMPTY>\n", i);
       continue;
     }
 
-    idx = hash(bkt->key, map->hashbits);
-    fprintf(stderr, "@%zu hash=%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
-            hash(bkt->key, map->hashbits), bkt->key, idx, bkt->psl);
+    idx = map_index(map, map->keys[i]);
+    fprintf(stderr, "@%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
+            map->keys[i], idx, map->psl[i] - 1);
   }
 }
 #endif /* !defined(WIN32) */
 
-static int insert(ngtcp2_map_bucket *table, size_t hashbits,
-                  ngtcp2_map_key_type key, void *data) {
-  size_t idx = hash(key, hashbits);
-  ngtcp2_map_bucket b = {
-    .key = key,
-    .data = data,
-  };
-  ngtcp2_map_bucket *bkt;
-  size_t mask = (1u << hashbits) - 1;
+static void map_set_entry(ngtcp2_map *map, size_t idx, ngtcp2_map_key_type key,
+                          void *data, size_t psl) {
+  map->keys[idx] = key;
+  map->data[idx] = data;
+  map->psl[idx] = (uint8_t)psl;
+}
+
+#define NGTCP2_SWAP(TYPE, A, B)                                                \
+  do {                                                                         \
+    TYPE t = (TYPE) * (A);                                                     \
+                                                                               \
+    *(A) = *(B);                                                               \
+    *(B) = t;                                                                  \
+  } while (0)
+
+/*
+ * map_insert inserts |key| and |data| to |map|, and returns the index
+ * where the pair is stored if it succeeds.  Otherwise, it returns one
+ * of the following negative error codes:
+ *
+ * NGTCP2_ERR_INVALID_ARGUMENT
+ *     The another data associated to |key| is already present.
+ */
+static ngtcp2_ssize map_insert(ngtcp2_map *map, ngtcp2_map_key_type key,
+                               void *data) {
+  size_t idx = map_index(map, key);
+  size_t mask = ((size_t)1 << map->hashbits) - 1;
+  size_t psl = 1;
+  size_t kpsl;
 
   for (;;) {
-    bkt = &table[idx];
-
-    if (bkt->data == NULL) {
-      *bkt = b;
-      return 0;
-    }
+    kpsl = map->psl[idx];
 
-    if (b.psl > bkt->psl) {
-      map_bucket_swap(bkt, &b);
-    } else if (bkt->key == key) {
-      /* TODO This check is just a waste after first swap or if this
-         function is called from map_resize.  That said, there is no
-         difference with or without this conditional in performance
-         wise. */
+    if (kpsl == 0) {
+      map_set_entry(map, idx, key, data, psl);
+      ++map->size;
+
+      return (ngtcp2_ssize)idx;
+    }
+
+    if (psl > kpsl) {
+      NGTCP2_SWAP(ngtcp2_map_key_type, &key, &map->keys[idx]);
+      NGTCP2_SWAP(void *, &data, &map->data[idx]);
+      NGTCP2_SWAP(uint8_t, &psl, &map->psl[idx]);
+    } else if (map->keys[idx] == key) {
+      /* This check ensures that no duplicate keys are inserted.  But
+         it is just a waste after first swap or if this function is
+         called from map_resize.  That said, there is no difference
+         with or without this conditional in performance wise. */
       return NGTCP2_ERR_INVALID_ARGUMENT;
     }
 
-    ++b.psl;
+    ++psl;
     idx = (idx + 1) & mask;
   }
 }
 
+/* NGTCP2_MAP_MAX_HASHBITS is the maximum number of bits used for hash
+   table.  The theoretical limit of the maximum number of keys that
+   can be stored is 1 << NGTCP2_MAP_MAX_HASHBITS. */
+#define NGTCP2_MAP_MAX_HASHBITS (sizeof(size_t) * 8 - 1)
+
 static int map_resize(ngtcp2_map *map, size_t new_hashbits) {
   size_t i;
-  ngtcp2_map_bucket *new_table;
-  ngtcp2_map_bucket *bkt;
   size_t tablelen;
-  int rv;
-  (void)rv;
+  ngtcp2_ssize idx;
+  ngtcp2_map new_map = {
+    .mem = map->mem,
+    .seed = map->seed,
+    .hashbits = new_hashbits,
+  };
+  void *buf;
+  (void)idx;
+
+  if (new_hashbits > NGTCP2_MAP_MAX_HASHBITS) {
+    return NGTCP2_ERR_NOMEM;
+  }
 
-  new_table =
-    ngtcp2_mem_calloc(map->mem, 1u << new_hashbits, sizeof(ngtcp2_map_bucket));
-  if (new_table == NULL) {
+  tablelen = (size_t)1 << new_hashbits;
+
+  buf = ngtcp2_mem_calloc(map->mem, tablelen,
+                          sizeof(ngtcp2_map_key_type) + sizeof(void *) +
+                            sizeof(uint8_t));
+  if (buf == NULL) {
     return NGTCP2_ERR_NOMEM;
   }
 
+  new_map.keys = buf;
+  new_map.data =
+    (void *)((uint8_t *)new_map.keys + tablelen * sizeof(ngtcp2_map_key_type));
+  new_map.psl = (uint8_t *)new_map.data + tablelen * sizeof(void *);
+
   if (map->size) {
-    tablelen = 1u << map->hashbits;
+    tablelen = (size_t)1 << map->hashbits;
 
     for (i = 0; i < tablelen; ++i) {
-      bkt = &map->table[i];
-      if (bkt->data == NULL) {
+      if (map->psl[i] == 0) {
         continue;
       }
 
-      rv = insert(new_table, new_hashbits, bkt->key, bkt->data);
+      idx = map_insert(&new_map, map->keys[i], map->data[i]);
 
-      assert(0 == rv);
+      /* map_insert must not fail because all keys are unique during
+         resize. */
+      assert(idx >= 0);
     }
   }
 
-  ngtcp2_mem_free(map->mem, map->table);
+  ngtcp2_mem_free(map->mem, map->keys);
+  map->keys = new_map.keys;
+  map->data = new_map.data;
+  map->psl = new_map.psl;
   map->hashbits = new_hashbits;
-  map->table = new_table;
 
   return 0;
 }
 
+/* NGTCP2_MAX_PSL_RESIZE_THRESH is the maximum psl threshold.  If
+   reached, resize the table. */
+#define NGTCP2_MAX_PSL_RESIZE_THRESH 128
+
 int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
   int rv;
+  size_t tablelen;
+  ngtcp2_ssize idx;
 
   assert(data);
 
-  /* Load factor is 0.75 */
-  /* Under the very initial condition, that is map->size == 0 and
-     map->hashbits == 0, 4 > 3 still holds nicely. */
-  if ((map->size + 1) * 4 > (1u << map->hashbits) * 3) {
-    if (map->hashbits) {
-      rv = map_resize(map, map->hashbits + 1);
-      if (rv != 0) {
-        return rv;
-      }
-    } else {
-      rv = map_resize(map, NGTCP2_INITIAL_HASHBITS);
-      if (rv != 0) {
-        return rv;
-      }
+  /* tablelen is incorrect if map->hashbits == 0 which leads to
+     tablelen = 1, but it is only used to check the load factor, and
+     it works in this special case. */
+  tablelen = (size_t)1 << map->hashbits;
+
+  /* Load factor is 7 / 8.  Because tablelen is power of 2, (tablelen
+     - (tablelen >> 3)) computes tablelen * 7 / 8. */
+  if (map->size + 1 >= (tablelen - (tablelen >> 3))) {
+    rv = map_resize(map, map->hashbits ? map->hashbits + 1
+                                       : NGTCP2_INITIAL_HASHBITS);
+    if (rv != 0) {
+      return rv;
+    }
+
+    idx = map_insert(map, key, data);
+    if (idx < 0) {
+      return (int)idx;
     }
+
+    return 0;
   }
 
-  rv = insert(map->table, map->hashbits, key, data);
-  if (rv != 0) {
-    return rv;
+  idx = map_insert(map, key, data);
+  if (idx < 0) {
+    return (int)idx;
   }
 
-  ++map->size;
+  /* Resize if psl reaches really large value which is almost
+     improbable, but just in case. */
+  if (map->psl[idx] - 1 < NGTCP2_MAX_PSL_RESIZE_THRESH) {
+    return 0;
+  }
 
-  return 0;
+  return map_resize(map, map->hashbits + 1);
 }
 
 void *ngtcp2_map_find(const ngtcp2_map *map, ngtcp2_map_key_type key) {
   size_t idx;
-  ngtcp2_map_bucket *bkt;
-  size_t psl = 0;
+  size_t psl = 1;
   size_t mask;
 
   if (map->size == 0) {
     return NULL;
   }
 
-  idx = hash(key, map->hashbits);
-  mask = (1u << map->hashbits) - 1;
+  idx = map_index(map, key);
+  mask = ((size_t)1 << map->hashbits) - 1;
 
   for (;;) {
-    bkt = &map->table[idx];
-
-    if (bkt->data == NULL || psl > bkt->psl) {
+    if (psl > map->psl[idx]) {
       return NULL;
     }
 
-    if (bkt->key == key) {
-      return bkt->data;
+    if (map->keys[idx] == key) {
+      return map->data[idx];
     }
 
     ++psl;
@@ -248,38 +305,36 @@ void *ngtcp2_map_find(const ngtcp2_map *
 
 int ngtcp2_map_remove(ngtcp2_map *map, ngtcp2_map_key_type key) {
   size_t idx;
-  ngtcp2_map_bucket *b, *bkt;
-  size_t psl = 0;
+  size_t dest;
+  size_t psl = 1, kpsl;
   size_t mask;
 
   if (map->size == 0) {
     return NGTCP2_ERR_INVALID_ARGUMENT;
   }
 
-  idx = hash(key, map->hashbits);
-  mask = (1u << map->hashbits) - 1;
+  idx = map_index(map, key);
+  mask = ((size_t)1 << map->hashbits) - 1;
 
   for (;;) {
-    bkt = &map->table[idx];
-
-    if (bkt->data == NULL || psl > bkt->psl) {
+    if (psl > map->psl[idx]) {
       return NGTCP2_ERR_INVALID_ARGUMENT;
     }
 
-    if (bkt->key == key) {
-      b = bkt;
+    if (map->keys[idx] == key) {
+      dest = idx;
       idx = (idx + 1) & mask;
 
       for (;;) {
-        bkt = &map->table[idx];
-        if (bkt->data == NULL || bkt->psl == 0) {
-          b->data = NULL;
+        kpsl = map->psl[idx];
+        if (kpsl <= 1) {
+          map->psl[dest] = 0;
           break;
         }
 
-        --bkt->psl;
-        *b = *bkt;
-        b = bkt;
+        map_set_entry(map, dest, map->keys[idx], map->data[idx], kpsl - 1);
+
+        dest = idx;
 
         idx = (idx + 1) & mask;
       }
@@ -299,7 +354,7 @@ void ngtcp2_map_clear(ngtcp2_map *map) {
     return;
   }
 
-  memset(map->table, 0, sizeof(*map->table) * (1u << map->hashbits));
+  memset(map->psl, 0, sizeof(*map->psl) * ((size_t)1 << map->hashbits));
   map->size = 0;
 }
 
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_map.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_map.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_map.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_map.h	2026-05-15 15:49:15.163978600 +0200
@@ -38,15 +38,15 @@
 
 typedef uint64_t ngtcp2_map_key_type;
 
-typedef struct ngtcp2_map_bucket {
-  uint32_t psl;
-  ngtcp2_map_key_type key;
-  void *data;
-} ngtcp2_map_bucket;
-
 typedef struct ngtcp2_map {
-  ngtcp2_map_bucket *table;
+  ngtcp2_map_key_type *keys;
+  void **data;
+  /* psl is the Probe Sequence Length.  0 has special meaning that the
+     element is not stored at i-th position if psl[i] == 0.  Because
+     of this, the actual psl value is psl[i] - 1 if psl[i] > 0. */
+  uint8_t *psl;
   const ngtcp2_mem *mem;
+  uint64_t seed;
   size_t size;
   size_t hashbits;
 } ngtcp2_map;
@@ -54,7 +54,7 @@ typedef struct ngtcp2_map {
 /*
  * ngtcp2_map_init initializes the map |map|.
  */
-void ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem);
+void ngtcp2_map_init(ngtcp2_map *map, uint64_t seed, const ngtcp2_mem *mem);
 
 /*
  * ngtcp2_map_free deallocates any resources allocated for |map|.  The
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_net.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_net.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_net.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_net.h	2026-05-15 15:49:15.163978600 +0200
@@ -97,9 +97,9 @@ STIN uint32_t ngtcp2_htonl(uint32_t host
   uint32_t res;
   unsigned char *p = (unsigned char *)&res;
   *p++ = (unsigned char)(hostlong >> 24);
-  *p++ = (hostlong >> 16) & 0xffu;
-  *p++ = (hostlong >> 8) & 0xffu;
-  *p = hostlong & 0xffu;
+  *p++ = (hostlong >> 16) & 0xFFU;
+  *p++ = (hostlong >> 8) & 0xFFU;
+  *p = hostlong & 0xFFU;
   return res;
 }
 
@@ -107,7 +107,7 @@ STIN uint16_t ngtcp2_htons(uint16_t host
   uint16_t res;
   unsigned char *p = (unsigned char *)&res;
   *p++ = (unsigned char)(hostshort >> 8);
-  *p = hostshort & 0xffu;
+  *p = hostshort & 0xFFU;
   return res;
 }
 
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_objalloc.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_objalloc.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_objalloc.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_objalloc.h	2026-05-15 15:49:15.163978600 +0200
@@ -69,7 +69,7 @@ void ngtcp2_objalloc_clear(ngtcp2_objall
     inline static void ngtcp2_objalloc_##NAME##_init(                          \
       ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) {        \
       ngtcp2_objalloc_init(                                                    \
-        objalloc, ((sizeof(TYPE) + 0xfu) & ~(uintptr_t)0xfu) * nmemb, mem);    \
+        objalloc, ((sizeof(TYPE) + 0xFU) & ~(uintptr_t)0xFU) * nmemb, mem);    \
     }                                                                          \
                                                                                \
     TYPE *ngtcp2_objalloc_##NAME##_get(ngtcp2_objalloc *objalloc);             \
@@ -123,7 +123,7 @@ void ngtcp2_objalloc_clear(ngtcp2_objall
     inline static void ngtcp2_objalloc_##NAME##_init(                          \
       ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) {        \
       ngtcp2_objalloc_init(                                                    \
-        objalloc, ((sizeof(TYPE) + 0xfu) & ~(uintptr_t)0xfu) * nmemb, mem);    \
+        objalloc, ((sizeof(TYPE) + 0xFU) & ~(uintptr_t)0xFU) * nmemb, mem);    \
     }                                                                          \
                                                                                \
     inline static TYPE *ngtcp2_objalloc_##NAME##_get(                          \
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_path.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_path.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_path.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_path.c	2026-05-15 15:49:15.163978600 +0200
@@ -28,12 +28,6 @@
 
 #include "ngtcp2_addr.h"
 
-void ngtcp2_path_init(ngtcp2_path *path, const ngtcp2_addr *local,
-                      const ngtcp2_addr *remote) {
-  path->local = *local;
-  path->remote = *remote;
-}
-
 void ngtcp2_path_copy(ngtcp2_path *dest, const ngtcp2_path *src) {
   ngtcp2_addr_copy(&dest->local, &src->local);
   ngtcp2_addr_copy(&dest->remote, &src->remote);
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_path.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_path.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_path.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_path.h	2026-05-15 15:49:15.163978600 +0200
@@ -32,14 +32,6 @@
 #include <ngtcp2/ngtcp2.h>
 
 /*
- * ngtcp2_path_init initializes |path| with the given addresses.  Note
- * that the buffer pointed by local->addr and remote->addr are not
- * copied.  Their pointer values are assigned instead.
- */
-void ngtcp2_path_init(ngtcp2_path *path, const ngtcp2_addr *local,
-                      const ngtcp2_addr *remote);
-
-/*
  * ngtcp2_path_storage_init2 initializes |ps| using |path| as initial
  * data.
  */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pcg.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pcg.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pcg.c	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pcg.c	2026-05-15 15:49:15.163978600 +0200
@@ -0,0 +1,88 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2025 ngtcp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "ngtcp2_pcg.h"
+
+#include <assert.h>
+
+/*
+ * PCG implementation from
+ * https://github.com/imneme/pcg-c/blob/83252d9c23df9c82ecb42210afed61a7b42402d7/include/pcg_variants.h
+ *
+ * PCG Random Number Generation for C.
+ *
+ * Copyright 2014-2019 Melissa O'Neill <oneill@pcg-random.org>,
+ *                     and the PCG Project contributors.
+ *
+ * SPDX-License-Identifier: (Apache-2.0 OR MIT)
+ *
+ * Licensed under the Apache License, Version 2.0 (provided in
+ * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)
+ * or under the MIT license (provided in LICENSE-MIT.txt and at
+ * http://opensource.org/licenses/MIT), at your option. This file may not
+ * be copied, modified, or distributed except according to those terms.
+ *
+ * Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either
+ * express or implied.  See your chosen license for details.
+ *
+ * For additional information about the PCG random number generation scheme,
+ * visit http://www.pcg-random.org/.
+ */
+
+#define NGTCP2_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL
+#define NGTCP2_PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL
+
+static void pcg_oneseq_64_step_r(ngtcp2_pcg32 *pcg) {
+  pcg->state = pcg->state * NGTCP2_PCG_DEFAULT_MULTIPLIER_64 +
+               NGTCP2_PCG_DEFAULT_INCREMENT_64;
+}
+
+void ngtcp2_pcg32_init(ngtcp2_pcg32 *pcg, uint64_t seed) {
+  pcg->state = 0;
+  pcg_oneseq_64_step_r(pcg);
+  pcg->state += seed;
+  pcg_oneseq_64_step_r(pcg);
+}
+
+static uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) {
+  return (value >> rot) | (value << ((32 - rot) & 31));
+}
+
+static uint32_t pcg_output_xsh_rr_64_32(uint64_t state) {
+  return pcg_rotr_32((uint32_t)(((state >> 18U) ^ state) >> 27U),
+                     (unsigned int)(state >> 59U));
+}
+
+uint32_t ngtcp2_pcg32_rand(ngtcp2_pcg32 *pcg) {
+  uint64_t oldstate = pcg->state;
+
+  pcg_oneseq_64_step_r(pcg);
+
+  return pcg_output_xsh_rr_64_32(oldstate);
+}
+
+uint32_t ngtcp2_pcg32_rand_n(ngtcp2_pcg32 *pcg, uint32_t n) {
+  assert(n);
+  return (uint32_t)(((uint64_t)ngtcp2_pcg32_rand(pcg) * n) >> 32);
+}
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pcg.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pcg.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pcg.h	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pcg.h	2026-05-15 15:49:15.163978600 +0200
@@ -0,0 +1,54 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2025 ngtcp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGTCP2_PCG_H
+#define NGTCP2_PCG_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif /* defined(HAVE_CONFIG_H) */
+
+#include <ngtcp2/ngtcp2.h>
+
+typedef struct ngtcp2_pcg32 {
+  uint64_t state;
+} ngtcp2_pcg32;
+
+/*
+ * ngtcp2_pcg32_init initializes |pcg| with |seed|.
+ */
+void ngtcp2_pcg32_init(ngtcp2_pcg32 *pcg, uint64_t seed);
+
+/*
+ * ngtcp2_pcg32_rand returns a random value in [0, UINT32_MAX].
+ */
+uint32_t ngtcp2_pcg32_rand(ngtcp2_pcg32 *pcg);
+
+/*
+ * ngtcp2_pcg32_rand_n returns a random value in [0, n).  |n| must not
+ * be zero.
+ */
+uint32_t ngtcp2_pcg32_rand_n(ngtcp2_pcg32 *pcg, uint32_t n);
+
+#endif /* !defined(NGTCP2_PCG_H) */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pkt.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pkt.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pkt.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pkt.c	2026-05-15 15:49:15.164978500 +0200
@@ -33,7 +33,9 @@
 #include "ngtcp2_cid.h"
 #include "ngtcp2_mem.h"
 #include "ngtcp2_vec.h"
+#include "ngtcp2_buf.h"
 #include "ngtcp2_unreachable.h"
+#include "ngtcp2_pcg.h"
 
 int ngtcp2_pkt_chain_new(ngtcp2_pkt_chain **ppc, const ngtcp2_path *path,
                          const ngtcp2_pkt_info *pi, const uint8_t *pkt,
@@ -480,8 +482,10 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_short(
   return (ngtcp2_ssize)len;
 }
 
-ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload,
-                                     size_t payloadlen) {
+ngtcp2_ssize ngtcp2_frame_decoder_decode(ngtcp2_frame_decoder *frd,
+                                         ngtcp2_frame *dest,
+                                         const uint8_t *payload,
+                                         size_t payloadlen) {
   uint8_t type;
 
   if (payloadlen == 0) {
@@ -530,6 +534,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngt
                                                 payloadlen);
   case NGTCP2_FRAME_ACK:
   case NGTCP2_FRAME_ACK_ECN:
+    dest->ack.ranges = frd->buf.ack_ranges;
     return ngtcp2_pkt_decode_ack_frame(&dest->ack, payload, payloadlen);
   case NGTCP2_FRAME_PATH_CHALLENGE:
     return ngtcp2_pkt_decode_path_challenge_frame(&dest->path_challenge,
@@ -538,6 +543,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngt
     return ngtcp2_pkt_decode_path_response_frame(&dest->path_response, payload,
                                                  payloadlen);
   case NGTCP2_FRAME_CRYPTO:
+    dest->stream.data = &frd->buf.data;
     return ngtcp2_pkt_decode_crypto_frame(&dest->stream, payload, payloadlen);
   case NGTCP2_FRAME_NEW_TOKEN:
     return ngtcp2_pkt_decode_new_token_frame(&dest->new_token, payload,
@@ -550,14 +556,16 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngt
                                                   payload, payloadlen);
   case NGTCP2_FRAME_DATAGRAM:
   case NGTCP2_FRAME_DATAGRAM_LEN:
+    dest->datagram.data = &frd->buf.data;
     return ngtcp2_pkt_decode_datagram_frame(&dest->datagram, payload,
                                             payloadlen);
   default:
     if ((type & ~(NGTCP2_FRAME_STREAM - 1)) == NGTCP2_FRAME_STREAM) {
+      dest->stream.data = &frd->buf.data;
       return ngtcp2_pkt_decode_stream_frame(&dest->stream, payload, payloadlen);
     }
 
-    /* For frame types > 0xff, use ngtcp2_get_uvarintlen and
+    /* For frame types > 0xFF, use ngtcp2_get_uvarintlen and
        ngtcp2_get_uvarint to get a frame type, and then switch over
        it.  Verify that payloadlen >= ngtcp2_get_uvarintlen(payload)
        before calling ngtcp2_get_uvarint(payload). */
@@ -916,7 +924,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_connectio
     return NGTCP2_ERR_FRAME_ENCODING;
   }
 
-  p = ngtcp2_get_uvarint(&vi, p);
+  ngtcp2_get_uvarint(&vi, p);
   if (payloadlen - len < vi) {
     return NGTCP2_ERR_FRAME_ENCODING;
   }
@@ -1051,6 +1059,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_ping_fram
   (void)payload;
   (void)payloadlen;
 
+  assert(payloadlen > 0);
+
   dest->type = NGTCP2_FRAME_PING;
   return 1;
 }
@@ -1198,8 +1208,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_conne
   ++p;
   ngtcp2_cid_init(&dest->cid, p, cil);
   p += cil;
-  p = ngtcp2_get_bytes(dest->stateless_reset_token, p,
-                       NGTCP2_STATELESS_RESET_TOKENLEN);
+  p = ngtcp2_get_bytes(dest->token.data, p, sizeof(dest->token.data));
 
   assert((size_t)(p - payload) == len);
 
@@ -1258,7 +1267,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_path_chal
   p = payload + 1;
 
   dest->type = NGTCP2_FRAME_PATH_CHALLENGE;
-  ngtcp2_cpymem(dest->data, p, sizeof(dest->data));
+  ngtcp2_cpymem(dest->data.data, p, sizeof(dest->data.data));
   p += sizeof(dest->data);
 
   assert((size_t)(p - payload) == len);
@@ -1279,7 +1288,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_path_resp
   p = payload + 1;
 
   dest->type = NGTCP2_FRAME_PATH_RESPONSE;
-  ngtcp2_cpymem(dest->data, p, sizeof(dest->data));
+  ngtcp2_cpymem(dest->data.data, p, sizeof(dest->data.data));
   p += sizeof(dest->data);
 
   assert((size_t)(p - payload) == len);
@@ -1319,7 +1328,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_crypto_fr
     return NGTCP2_ERR_FRAME_ENCODING;
   }
 
-  p = ngtcp2_get_uvarint(&vi, p);
+  ngtcp2_get_uvarint(&vi, p);
   if (payloadlen - len < vi) {
     return NGTCP2_ERR_FRAME_ENCODING;
   }
@@ -1426,6 +1435,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_handshake
   (void)payload;
   (void)payloadlen;
 
+  assert(payloadlen > 0);
+
   dest->type = NGTCP2_FRAME_HANDSHAKE_DONE;
   return 1;
 }
@@ -1440,9 +1451,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_
   size_t n;
   uint64_t vi;
 
-  if (payloadlen < len) {
-    return NGTCP2_ERR_FRAME_ENCODING;
-  }
+  assert(payloadlen > 0);
 
   type = payload[0];
 
@@ -1481,16 +1490,13 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_
 
   dest->type = type;
 
-  if (datalen == 0) {
-    dest->datacnt = 0;
-    dest->data = NULL;
-  } else {
+  if (datalen) {
+    dest->data[0].len = datalen;
+    dest->data[0].base = (uint8_t *)p;
     dest->datacnt = 1;
-    dest->data = dest->rdata;
-    dest->rdata[0].len = datalen;
-
-    dest->rdata[0].base = (uint8_t *)p;
     p += datalen;
+  } else {
+    dest->datacnt = 0;
   }
 
   assert((size_t)(p - payload) == len);
@@ -1500,7 +1506,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_
 
 ngtcp2_ssize ngtcp2_pkt_encode_frame(uint8_t *out, size_t outlen,
                                      ngtcp2_frame *fr) {
-  switch (fr->type) {
+  switch (fr->hd.type) {
   case NGTCP2_FRAME_STREAM:
     return ngtcp2_pkt_encode_stream_frame(out, outlen, &fr->stream);
   case NGTCP2_FRAME_ACK:
@@ -1876,7 +1882,7 @@ ngtcp2_pkt_encode_new_connection_id_fram
                                           const ngtcp2_new_connection_id *fr) {
   size_t len = 1 + ngtcp2_put_uvarintlen(fr->seq) +
                ngtcp2_put_uvarintlen(fr->retire_prior_to) + 1 +
-               fr->cid.datalen + NGTCP2_STATELESS_RESET_TOKENLEN;
+               fr->cid.datalen + sizeof(fr->token.data);
   uint8_t *p;
 
   if (outlen < len) {
@@ -1890,8 +1896,7 @@ ngtcp2_pkt_encode_new_connection_id_fram
   p = ngtcp2_put_uvarint(p, fr->retire_prior_to);
   *p++ = (uint8_t)fr->cid.datalen;
   p = ngtcp2_cpymem(p, fr->cid.data, fr->cid.datalen);
-  p = ngtcp2_cpymem(p, fr->stateless_reset_token,
-                    NGTCP2_STATELESS_RESET_TOKENLEN);
+  p = ngtcp2_cpymem(p, fr->token.data, sizeof(fr->token.data));
 
   assert((size_t)(p - out) == len);
 
@@ -1933,7 +1938,7 @@ ngtcp2_pkt_encode_path_challenge_frame(u
   p = out;
 
   *p++ = NGTCP2_FRAME_PATH_CHALLENGE;
-  p = ngtcp2_cpymem(p, fr->data, sizeof(fr->data));
+  p = ngtcp2_cpymem(p, fr->data.data, sizeof(fr->data.data));
 
   assert((size_t)(p - out) == len);
 
@@ -1953,7 +1958,7 @@ ngtcp2_pkt_encode_path_response_frame(ui
   p = out;
 
   *p++ = NGTCP2_FRAME_PATH_RESPONSE;
-  p = ngtcp2_cpymem(p, fr->data, sizeof(fr->data));
+  p = ngtcp2_cpymem(p, fr->data.data, sizeof(fr->data.data));
 
   assert((size_t)(p - out) == len);
 
@@ -2109,7 +2114,7 @@ ngtcp2_ssize ngtcp2_pkt_write_version_ne
 
   p = dest;
 
-  *p++ = 0xc0 | unused_random;
+  *p++ = 0xC0 | unused_random;
   p = ngtcp2_put_uint32be(p, 0);
   *p++ = (uint8_t)dcidlen;
 
@@ -2146,20 +2151,20 @@ size_t ngtcp2_pkt_decode_version_negotia
   return payloadlen / sizeof(uint32_t);
 }
 
-int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset *sr,
+int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset2 *sr,
                                       const uint8_t *payload,
                                       size_t payloadlen) {
   const uint8_t *p = payload;
 
   if (payloadlen <
-      NGTCP2_MIN_STATELESS_RESET_RANDLEN + NGTCP2_STATELESS_RESET_TOKENLEN) {
+      NGTCP2_MIN_STATELESS_RESET_RANDLEN + sizeof(sr->token.data)) {
     return NGTCP2_ERR_INVALID_ARGUMENT;
   }
 
   sr->rand = p;
-  sr->randlen = payloadlen - NGTCP2_STATELESS_RESET_TOKENLEN;
+  sr->randlen = payloadlen - sizeof(sr->token.data);
   p += sr->randlen;
-  memcpy(sr->stateless_reset_token, p, NGTCP2_STATELESS_RESET_TOKENLEN);
+  memcpy(sr->token.data, p, sizeof(sr->token.data));
 
   return 0;
 }
@@ -2238,10 +2243,21 @@ ngtcp2_ssize
 ngtcp2_pkt_write_stateless_reset(uint8_t *dest, size_t destlen,
                                  const uint8_t *stateless_reset_token,
                                  const uint8_t *rand, size_t randlen) {
+  ngtcp2_stateless_reset_token token;
+
+  memcpy(token.data, stateless_reset_token, sizeof(token.data));
+
+  return ngtcp2_pkt_write_stateless_reset2(dest, destlen, &token, rand,
+                                           randlen);
+}
+
+ngtcp2_ssize
+ngtcp2_pkt_write_stateless_reset2(uint8_t *dest, size_t destlen,
+                                  const ngtcp2_stateless_reset_token *token,
+                                  const uint8_t *rand, size_t randlen) {
   uint8_t *p;
 
-  if (destlen <
-      NGTCP2_MIN_STATELESS_RESET_RANDLEN + NGTCP2_STATELESS_RESET_TOKENLEN) {
+  if (destlen < NGTCP2_MIN_STATELESS_RESET_RANDLEN + sizeof(token->data)) {
     return NGTCP2_ERR_NOBUF;
   }
 
@@ -2251,11 +2267,11 @@ ngtcp2_pkt_write_stateless_reset(uint8_t
 
   p = dest;
 
-  randlen = ngtcp2_min_size(destlen - NGTCP2_STATELESS_RESET_TOKENLEN, randlen);
+  randlen = ngtcp2_min_size(destlen - sizeof(token->data), randlen);
 
   p = ngtcp2_cpymem(p, rand, randlen);
-  p = ngtcp2_cpymem(p, stateless_reset_token, NGTCP2_STATELESS_RESET_TOKENLEN);
-  *dest = (uint8_t)((*dest & 0x7fu) | 0x40u);
+  p = ngtcp2_cpymem(p, token->data, sizeof(token->data));
+  *dest = (uint8_t)((*dest & 0x3FU) | 0x40U);
 
   return p - dest;
 }
@@ -2299,11 +2315,11 @@ ngtcp2_ssize ngtcp2_pkt_write_retry(
   case NGTCP2_PROTO_VER_V1:
   default:
     nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V1;
-    noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1;
+    noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V1);
     break;
   case NGTCP2_PROTO_VER_V2:
     nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2;
-    noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1;
+    noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V2);
     break;
   }
 
@@ -2349,7 +2365,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_pseudo_re
     return NGTCP2_ERR_NOBUF;
   }
 
-  *p &= 0xf0;
+  *p &= 0xF0;
   *p |= unused;
 
   p += nwrite;
@@ -2389,11 +2405,11 @@ int ngtcp2_pkt_verify_retry_tag(uint32_t
   case NGTCP2_PROTO_VER_V1:
   default:
     nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V1;
-    noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1;
+    noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V1);
     break;
   case NGTCP2_PROTO_VER_V2:
     nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2;
-    noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1;
+    noncelen = ngtcp2_strlen_lit(NGTCP2_RETRY_NONCE_V2);
     break;
   }
 
@@ -2423,7 +2439,7 @@ size_t ngtcp2_pkt_stream_max_datalen(int
   left -= n;
 
   if (left > 8 + 1073741823 && len > 1073741823) {
-    len = ngtcp2_min_uint64(len, 4611686018427387903lu);
+    len = ngtcp2_min_uint64(len, 4611686018427387903UL);
     return (size_t)ngtcp2_min_uint64(len, (uint64_t)(left - 8));
   }
 
@@ -2454,7 +2470,7 @@ size_t ngtcp2_pkt_crypto_max_datalen(uin
 
   if (left > 8 + 1073741823 && len > 1073741823) {
 #if SIZE_MAX == UINT64_MAX
-    len = ngtcp2_min_size(len, 4611686018427387903lu);
+    len = ngtcp2_min_size(len, 4611686018427387903UL);
 #endif /* SIZE_MAX == UINT64_MAX */
     return ngtcp2_min_size(len, left - 8);
   }
@@ -2571,3 +2587,299 @@ int ngtcp2_pkt_verify_reserved_bits(uint
 
   return (c & NGTCP2_SHORT_RESERVED_BIT_MASK) == 0 ? 0 : NGTCP2_ERR_PROTO;
 }
+
+size_t ngtcp2_pkt_split_vec_rand(ngtcp2_vec *data, size_t datacnt,
+                                 uint64_t *offsets, ngtcp2_pcg32 *pcg,
+                                 size_t max_add) {
+  ngtcp2_vec *v;
+  size_t idx;
+  size_t len;
+
+  for (; max_add; --max_add) {
+    idx = ngtcp2_pcg32_rand_n(pcg, (uint32_t)datacnt);
+    assert(idx < datacnt);
+
+    v = &data[idx];
+
+    if (v->len <= 1) {
+      continue;
+    }
+
+    len = v->len / 2;
+
+    ngtcp2_vec_split_at(&data[datacnt], v, len);
+
+    offsets[datacnt] = offsets[idx] + len;
+
+    ++datacnt;
+  }
+
+  return datacnt;
+}
+
+size_t ngtcp2_pkt_split_vec_at(ngtcp2_vec *data, size_t datacnt,
+                               uint64_t *offsets, size_t at) {
+  assert(at < data[0].len);
+
+  ngtcp2_vec_split_at(&data[datacnt], &data[0], at);
+
+  offsets[datacnt] = offsets[0] + at;
+
+  return datacnt + 1;
+}
+
+static int pkt_tls_skip8(ngtcp2_buf *buf) {
+  size_t len;
+
+  if (ngtcp2_buf_len(buf) < 1) {
+    return -1;
+  }
+
+  len = *buf->pos++;
+
+  if (ngtcp2_buf_len(buf) < len) {
+    return -1;
+  }
+
+  buf->pos += len;
+
+  return 0;
+}
+
+static int pkt_tls_skip16(ngtcp2_buf *buf) {
+  uint16_t len;
+
+  if (ngtcp2_buf_len(buf) < sizeof(len)) {
+    return -1;
+  }
+
+  buf->pos = (uint8_t *)ngtcp2_get_uint16be(&len, buf->pos);
+
+  if (ngtcp2_buf_len(buf) < len) {
+    return -1;
+  }
+
+  buf->pos += len;
+
+  return 0;
+}
+
+int ngtcp2_pkt_find_server_name(ngtcp2_vec *server_name, const ngtcp2_vec *v) {
+  ngtcp2_buf buf;
+  uint32_t msglen;
+  uint16_t len;
+  uint16_t legacy_ver;
+  uint16_t ext_type;
+
+  assert(v->len);
+
+  ngtcp2_buf_init(&buf, v->base, v->len);
+  buf.last += v->len;
+
+  /* Handshake msg_type and length */
+  if (ngtcp2_buf_len(&buf) < 1 + 3) {
+    return 0;
+  }
+
+  /* Keep parsing only when msg_type is client_hello(1). */
+  if (*buf.pos++ != 1) {
+    return 0;
+  }
+
+  buf.pos = (uint8_t *)ngtcp2_get_uint24be(&msglen, buf.pos);
+
+  /* Truncate the buffer to msglen */
+  ngtcp2_buf_trunc(&buf, msglen);
+
+  /* legacy_version(0x0303) */
+  if (ngtcp2_buf_len(&buf) < sizeof(uint16_t)) {
+    return 0;
+  }
+
+  buf.pos = (uint8_t *)ngtcp2_get_uint16be(&legacy_ver, buf.pos);
+  if (legacy_ver != 0x0303) {
+    return 0;
+  }
+
+  /* random */
+  if (ngtcp2_buf_len(&buf) < 32) {
+    return 0;
+  }
+
+  buf.pos += 32;
+
+  /* legacy_session_id */
+  if (pkt_tls_skip8(&buf) != 0) {
+    return 0;
+  }
+
+  /* cipher_suites */
+  if (pkt_tls_skip16(&buf) != 0) {
+    return 0;
+  }
+
+  /* legacy_compression_methods */
+  if (pkt_tls_skip8(&buf) != 0) {
+    return 0;
+  }
+
+  /* extensions */
+  if (ngtcp2_buf_len(&buf) < sizeof(uint16_t)) {
+    return 0;
+  }
+
+  buf.pos = (uint8_t *)ngtcp2_get_uint16be(&len, buf.pos);
+
+  /* Truncate the buffer to extensions length */
+  ngtcp2_buf_trunc(&buf, len);
+
+  for (;;) {
+    /* Verify that extension_type and length of extension_data are
+       available */
+    if (ngtcp2_buf_len(&buf) < sizeof(uint16_t) * 2) {
+      return 0;
+    }
+
+    /* extension_type */
+    buf.pos = (uint8_t *)ngtcp2_get_uint16be(&ext_type, buf.pos);
+    if (ext_type != 0) {
+      /* extension_data */
+      if (pkt_tls_skip16(&buf) != 0) {
+        return 0;
+      }
+
+      continue;
+    }
+
+    /* Server Name Indication extension(0) */
+
+    /* extension_data */
+    buf.pos = (uint8_t *)ngtcp2_get_uint16be(&len, buf.pos);
+    if (ngtcp2_buf_len(&buf) < len || len < 2) {
+      return 0;
+    }
+
+    /* Truncate the buffer to extension_data length */
+    ngtcp2_buf_trunc(&buf, len);
+
+    /* server_name_list */
+    buf.pos = (uint8_t *)ngtcp2_get_uint16be(&len, buf.pos);
+    if (ngtcp2_buf_len(&buf) < len || len < 1 + 2) {
+      return 0;
+    }
+
+    /* We deliberately do not check server_name_list length + 2 ==
+       extension_data length.  They most likely match, and even if
+       not, no problem at all. */
+
+    /* Truncate the buffer to server_name_list length */
+    ngtcp2_buf_trunc(&buf, len);
+
+    /* name_type */
+    if (*buf.pos++ != 0) {
+      return 0;
+    }
+
+    /* name */
+    buf.pos = (uint8_t *)ngtcp2_get_uint16be(&len, buf.pos);
+    if (ngtcp2_buf_len(&buf) < len) {
+      return 0;
+    }
+
+    server_name->base = buf.pos;
+    server_name->len = len;
+
+    return 1;
+  }
+}
+
+size_t ngtcp2_pkt_append_ping_and_padding(ngtcp2_vec *data, size_t datacnt,
+                                          ngtcp2_pcg32 *pcg, size_t n) {
+  uint32_t k;
+
+  for (; n && datacnt < NGTCP2_MAX_STREAM_DATACNT;) {
+    k = ngtcp2_pcg32_rand_n(pcg, (uint32_t)n + 1);
+    if (k == 0) {
+      /* PING */
+      data[datacnt] = (ngtcp2_vec){
+        .base = NULL,
+        .len = 0,
+      };
+
+      ++k;
+    } else {
+      /* PADDING of k length */
+      data[datacnt] = (ngtcp2_vec){
+        .base = NULL,
+        .len = k,
+      };
+    }
+
+    ++datacnt;
+    n -= k;
+  }
+
+  return datacnt;
+}
+
+void ngtcp2_pkt_permutate_vec(ngtcp2_vec *data, size_t datacnt,
+                              uint64_t *offsets, ngtcp2_pcg32 *pcg) {
+  size_t i, j;
+  ngtcp2_vec v;
+  uint64_t o;
+
+  if (datacnt < 2) {
+    return;
+  }
+
+  for (i = datacnt - 1; i > 0; --i) {
+    j = ngtcp2_pcg32_rand_n(pcg, (uint32_t)i);
+
+    if (i == j) {
+      continue;
+    }
+
+    v = data[i];
+    data[i] = data[j];
+    data[j] = v;
+
+    o = offsets[i];
+    offsets[i] = offsets[j];
+    offsets[j] = o;
+  }
+}
+
+size_t ngtcp2_pkt_remove_vec_partial(ngtcp2_vec *removed_data, ngtcp2_vec *data,
+                                     size_t datacnt, uint64_t *offsets,
+                                     ngtcp2_pcg32 *pcg,
+                                     const ngtcp2_vec *part) {
+  ngtcp2_vec *v = &data[0];
+  size_t len;
+
+  assert(datacnt);
+  assert(v->base < part->base);
+  assert(ngtcp2_vec_end(part) <= ngtcp2_vec_end(v));
+
+  len = (size_t)(part->base - v->base) + part->len / 2;
+
+  ngtcp2_vec_split_at(removed_data, v, len);
+
+  if (removed_data->len == 1) {
+    return datacnt;
+  }
+
+  len = 1 + ngtcp2_pcg32_rand_n(
+              pcg, (uint32_t)ngtcp2_min_size(30, removed_data->len - 1));
+  assert(len < removed_data->len);
+
+  ngtcp2_vec_split_at(&data[datacnt], removed_data, len);
+
+  offsets[datacnt] = offsets[0] + v->len + removed_data->len;
+
+  return datacnt + 1;
+}
+
+int ngtcp2_stateless_reset_token_eq(const ngtcp2_stateless_reset_token *a,
+                                    const ngtcp2_stateless_reset_token *b) {
+  return memcmp(a->data, b->data, sizeof(a->data)) == 0;
+}
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pkt.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pkt.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pkt.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pkt.h	2026-05-15 15:49:15.165978400 +0200
@@ -38,14 +38,14 @@
 
 /* Long header specific macros */
 #define NGTCP2_LONG_TYPE_MASK 0x30
-#define NGTCP2_LONG_RESERVED_BIT_MASK 0x0c
+#define NGTCP2_LONG_RESERVED_BIT_MASK 0x0C
 
 /* Short header specific macros */
 #define NGTCP2_SHORT_RESERVED_BIT_MASK 0x18
 #define NGTCP2_SHORT_KEY_PHASE_BIT 0x04
 
 /* NGTCP2_SR_TYPE is a Type field of Stateless Reset. */
-#define NGTCP2_SR_TYPE 0x1f
+#define NGTCP2_SR_TYPE 0x1F
 
 /* NGTCP2_MIN_LONG_HEADERLEN is the minimum length of long header.
    That is (1|1|TT|RR|PP)<1> + VERSION<4> + DCIL<1> + SCIL<1> +
@@ -78,23 +78,23 @@
 
 /* NGTCP2_MAX_SERVER_STREAM_ID_BIDI is the maximum bidirectional
    server stream ID. */
-#define NGTCP2_MAX_SERVER_STREAM_ID_BIDI ((int64_t)0x3ffffffffffffffdll)
+#define NGTCP2_MAX_SERVER_STREAM_ID_BIDI ((int64_t)0x3FFFFFFFFFFFFFFDLL)
 /* NGTCP2_MAX_CLIENT_STREAM_ID_BIDI is the maximum bidirectional
    client stream ID. */
-#define NGTCP2_MAX_CLIENT_STREAM_ID_BIDI ((int64_t)0x3ffffffffffffffcll)
+#define NGTCP2_MAX_CLIENT_STREAM_ID_BIDI ((int64_t)0x3FFFFFFFFFFFFFFCLL)
 /* NGTCP2_MAX_SERVER_STREAM_ID_UNI is the maximum unidirectional
    server stream ID. */
-#define NGTCP2_MAX_SERVER_STREAM_ID_UNI ((int64_t)0x3fffffffffffffffll)
+#define NGTCP2_MAX_SERVER_STREAM_ID_UNI ((int64_t)0x3FFFFFFFFFFFFFFFLL)
 /* NGTCP2_MAX_CLIENT_STREAM_ID_UNI is the maximum unidirectional
    client stream ID. */
-#define NGTCP2_MAX_CLIENT_STREAM_ID_UNI ((int64_t)0x3ffffffffffffffell)
+#define NGTCP2_MAX_CLIENT_STREAM_ID_UNI ((int64_t)0x3FFFFFFFFFFFFFFELL)
 
 /* NGTCP2_MAX_NUM_ACK_RANGES is the maximum number of Additional ACK
    ranges which this library can create, or decode. */
 #define NGTCP2_MAX_ACK_RANGES 32
 
 /* NGTCP2_MAX_PKT_NUM is the maximum packet number. */
-#define NGTCP2_MAX_PKT_NUM ((int64_t)((1ll << 62) - 1))
+#define NGTCP2_MAX_PKT_NUM ((int64_t)((1LL << 62) - 1))
 
 /* NGTCP2_MIN_PKT_EXPANDLEN is the minimum packet size expansion to
    hide/trigger Stateless Reset. */
@@ -103,10 +103,6 @@
 /* NGTCP2_RETRY_TAGLEN is the length of Retry packet integrity tag. */
 #define NGTCP2_RETRY_TAGLEN 16
 
-/* NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE is the maximum UDP datagram
-   payload size that this library can write. */
-#define NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE ((1 << 24) - 1)
-
 /* NGTCP2_PKT_LENGTHLEN is the number of bytes that is occupied by
    Length field in Long packet header. */
 #define NGTCP2_PKT_LENGTHLEN 4
@@ -137,6 +133,19 @@
    v2. */
 #define NGTCP2_PKT_TYPE_RETRY_V2 0x0
 
+/* NGTCP2_MIN_STREAM_DATALEN is the minimum length of STREAM frame to
+   avoid too small frame.  It is not always enforced for various
+   reasons.  For example, due to flow control, we might have fewer
+   bytes available to send.  Therefore, it is only applied when the
+   length of data to send is larger than this limit. */
+#define NGTCP2_MIN_STREAM_DATALEN 256
+
+/* NGTCP2_MAX_STREAM_DATACNT is the maximum number of ngtcp2_vec that
+   a ngtcp2_stream can include. */
+#define NGTCP2_MAX_STREAM_DATACNT 256
+
+typedef struct ngtcp2_pcg32 ngtcp2_pcg32;
+
 typedef struct ngtcp2_pkt_retry {
   ngtcp2_cid odcid;
   uint8_t *token;
@@ -163,14 +172,18 @@ typedef struct ngtcp2_pkt_retry {
 #define NGTCP2_FRAME_STREAMS_BLOCKED_UNI 0x17
 #define NGTCP2_FRAME_NEW_CONNECTION_ID 0x18
 #define NGTCP2_FRAME_RETIRE_CONNECTION_ID 0x19
-#define NGTCP2_FRAME_PATH_CHALLENGE 0x1a
-#define NGTCP2_FRAME_PATH_RESPONSE 0x1b
-#define NGTCP2_FRAME_CONNECTION_CLOSE 0x1c
-#define NGTCP2_FRAME_CONNECTION_CLOSE_APP 0x1d
-#define NGTCP2_FRAME_HANDSHAKE_DONE 0x1e
+#define NGTCP2_FRAME_PATH_CHALLENGE 0x1A
+#define NGTCP2_FRAME_PATH_RESPONSE 0x1B
+#define NGTCP2_FRAME_CONNECTION_CLOSE 0x1C
+#define NGTCP2_FRAME_CONNECTION_CLOSE_APP 0x1D
+#define NGTCP2_FRAME_HANDSHAKE_DONE 0x1E
 #define NGTCP2_FRAME_DATAGRAM 0x30
 #define NGTCP2_FRAME_DATAGRAM_LEN 0x31
 
+typedef struct ngtcp2_frame_hd {
+  uint64_t type;
+} ngtcp2_frame_hd;
+
 /* ngtcp2_stream represents STREAM and CRYPTO frames. */
 typedef struct ngtcp2_stream {
   uint64_t type;
@@ -182,7 +195,7 @@ typedef struct ngtcp2_stream {
   uint8_t flags;
   /* CRYPTO frame does not include this field, and must set it to
      0. */
-  uint8_t fin;
+  int fin;
   /* CRYPTO frame does not include this field, and must set it to
      0. */
   int64_t stream_id;
@@ -191,8 +204,9 @@ typedef struct ngtcp2_stream {
      the length of data is 1 in this definition, the library may
      allocate extra bytes to hold more elements. */
   size_t datacnt;
-  /* data is the array of ngtcp2_vec which references data. */
-  ngtcp2_vec data[1];
+  /* data points to ngtcp2_vec array which references data.  If
+     datacnt == 0, this field may be NULL. */
+  ngtcp2_vec *data;
 } ngtcp2_stream;
 
 typedef struct ngtcp2_ack_range {
@@ -216,7 +230,7 @@ typedef struct ngtcp2_ack {
   } ecn;
   uint64_t first_ack_range;
   size_t rangecnt;
-  ngtcp2_ack_range ranges[1];
+  ngtcp2_ack_range *ranges;
 } ngtcp2_ack;
 
 typedef struct ngtcp2_padding {
@@ -286,7 +300,7 @@ typedef struct ngtcp2_new_connection_id
   uint64_t seq;
   uint64_t retire_prior_to;
   ngtcp2_cid cid;
-  uint8_t stateless_reset_token[NGTCP2_STATELESS_RESET_TOKENLEN];
+  ngtcp2_stateless_reset_token token;
 } ngtcp2_new_connection_id;
 
 typedef struct ngtcp2_stop_sending {
@@ -297,12 +311,12 @@ typedef struct ngtcp2_stop_sending {
 
 typedef struct ngtcp2_path_challenge {
   uint64_t type;
-  uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN];
+  ngtcp2_path_challenge_data data;
 } ngtcp2_path_challenge;
 
 typedef struct ngtcp2_path_response {
   uint64_t type;
-  uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN];
+  ngtcp2_path_challenge_data data;
 } ngtcp2_path_response;
 
 typedef struct ngtcp2_new_token {
@@ -326,17 +340,13 @@ typedef struct ngtcp2_datagram {
   uint64_t dgram_id;
   /* datacnt is the number of elements that data contains. */
   size_t datacnt;
-  /* data is a pointer to ngtcp2_vec array that stores data. */
+  /* data is a pointer to ngtcp2_vec array that stores data.  If
+     datacnt == 0, this field may be NULL.*/
   ngtcp2_vec *data;
-  /* rdata is conveniently embedded to ngtcp2_datagram, so that data
-     field can just point to the address of this field to store a
-     single vector which is the case when DATAGRAM is received from a
-     remote endpoint. */
-  ngtcp2_vec rdata[1];
 } ngtcp2_datagram;
 
 typedef union ngtcp2_frame {
-  uint64_t type;
+  ngtcp2_frame_hd hd;
   ngtcp2_stream stream;
   ngtcp2_ack ack;
   ngtcp2_padding padding;
@@ -357,11 +367,6 @@ typedef union ngtcp2_frame {
   ngtcp2_retire_connection_id retire_connection_id;
   ngtcp2_handshake_done handshake_done;
   ngtcp2_datagram datagram;
-  /* Extend ngtcp2_frame so that ngtcp2_stream has at least additional
-     3 ngtcp2_vec, totaling 4 slots, which can store HEADERS header,
-     HEADERS payload, DATA header, and DATA payload in the standard
-     sized ngtcp2_frame_chain. */
-  uint8_t pad[sizeof(ngtcp2_stream) + sizeof(ngtcp2_vec) * 3];
 } ngtcp2_frame;
 
 typedef struct ngtcp2_pkt_chain ngtcp2_pkt_chain;
@@ -441,10 +446,22 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_long(u
 ngtcp2_ssize ngtcp2_pkt_encode_hd_short(uint8_t *out, size_t outlen,
                                         const ngtcp2_pkt_hd *hd);
 
+/*
+ * ngtcp2_frame_decoder is QUIC frame decoder.  For frames that
+ * require the external buffers (e.g., ngtcp2_stream and ngtcp2_ack),
+ * it provides those buffers on demand.
+ */
+typedef struct ngtcp2_frame_decoder {
+  union {
+    ngtcp2_vec data;
+    ngtcp2_ack_range ack_ranges[NGTCP2_MAX_ACK_RANGES];
+  } buf;
+} ngtcp2_frame_decoder;
+
 /**
  * @function
  *
- * `ngtcp2_pkt_decode_frame` decodes a QUIC frame from the buffer
+ * `ngtcp2_frame_decoder_decode` decodes a QUIC frame from the buffer
  * pointed by |payload| whose length is |payloadlen|.
  *
  * This function returns the number of bytes read to decode a single
@@ -454,8 +471,10 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_short(
  *     Frame is badly formatted; or frame type is unknown; or
  *     |payloadlen| is 0.
  */
-ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload,
-                                     size_t payloadlen);
+ngtcp2_ssize ngtcp2_frame_decoder_decode(ngtcp2_frame_decoder *frd,
+                                         ngtcp2_frame *dest,
+                                         const uint8_t *payload,
+                                         size_t payloadlen);
 
 /**
  * @function
@@ -495,7 +514,7 @@ size_t ngtcp2_pkt_decode_version_negotia
  * NGTCP2_ERR_INVALID_ARGUMENT
  *     Payloadlen is too short.
  */
-int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset *sr,
+int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset2 *sr,
                                       const uint8_t *payload,
                                       size_t payloadlen);
 
@@ -1227,4 +1246,88 @@ uint8_t ngtcp2_pkt_versioned_type(uint32
  */
 uint8_t ngtcp2_pkt_get_type_long(uint32_t version, uint8_t c);
 
+/*
+ * ngtcp2_pkt_split_vec_rand appends ngtcp2_vec at most |max_add|
+ * times to the array pointed by |data| of length |datacnt| by
+ * splitting the existing ngtcp2_vec into two.  Which ngtcp2_vec to
+ * split is chosen randomly.  |offsets| contains the offset of each
+ * ngtcp2_vec pointed by |data|.  |offsets| is also updated.  The
+ * arrays must have the capacity at least |datacnt| + |max_add|.
+ * |pcg| is a random number generator.
+ *
+ * This function returns |datacnt| plus the number of ngtcp2_vec that
+ * are appended.
+ */
+size_t ngtcp2_pkt_split_vec_rand(ngtcp2_vec *data, size_t datacnt,
+                                 uint64_t *offsets, ngtcp2_pcg32 *pcg,
+                                 size_t max_add);
+
+/*
+ * ngtcp2_pkt_split_vec_at splits data[0] at offset |at|, and the
+ * right side of ngtcp2_vec is assigned to data[datacnt].  Similarly,
+ * offsets[0] + |at| is assigned to offsets[datacnt].  |data| must
+ * point to the array of ngtcp2_vec of length |datacnt|, and |datacnt|
+ * must be greater than 0.  |at| must be strictly less than data->len.
+ *
+ * This function returns |datacnt| + 1.
+ */
+size_t ngtcp2_pkt_split_vec_at(ngtcp2_vec *data, size_t datacnt,
+                               uint64_t *offsets, size_t at);
+
+/*
+ * ngtcp2_pkt_find_server_name searches TLS Server Name Indication
+ * extension in |v|.  If it is found, assign the portion of server
+ * name to the object pointed by |server_name|, and returns nonzero.
+ * Otherwise, it returns 0.  If |v| contains the extension partially,
+ * the function returns 0.  |v| must not be empty.
+ */
+int ngtcp2_pkt_find_server_name(ngtcp2_vec *server_name, const ngtcp2_vec *v);
+
+/*
+ * ngtcp2_pkt_append_ping_and_padding appends PING and PADDING frames
+ * to the array pointed by |data| of length |datacnt|.  The capacity
+ * of array must be at least NGTCP2_MAX_STREAM_DATACNT.  |n| is the
+ * number of bytes available for serialized PING and PADDING frames.
+ * |pcg| is a random number generator.  Which frames to add is
+ * determined randomly.
+ *
+ * The special encoding of PING and PADDING frames into ngtcp2_vec:
+ *
+ * - .base is NULL.
+ * - If .len is 0, it represents PING.  Otherwise, PADDING of .len
+ *   length.
+ *
+ * This function returns |datacnt| plus the number of frames added.
+ */
+size_t ngtcp2_pkt_append_ping_and_padding(ngtcp2_vec *data, size_t datacnt,
+                                          ngtcp2_pcg32 *pcg, size_t n);
+
+/*
+ * ngtcp2_pkt_permutate_vec permutates |data| and |offsets|, both have
+ * the |datacnt| elements.  |pcg| is a random number generator.
+ */
+void ngtcp2_pkt_permutate_vec(ngtcp2_vec *data, size_t datacnt,
+                              uint64_t *offsets, ngtcp2_pcg32 *pcg);
+
+/*
+ * ngtcp2_pkt_remove_vec_partial removes the portion of data that
+ * contains part of |part| from data[0].  This function does not
+ * remove whole range of |part|.  The length of removed data is chosen
+ * randomly.  The removed portion of data is assigned to the object
+ * pointed by |removed_data|.  If there is data located after the
+ * removed data, it will be assigned to data[datacnt].
+ * offsets[datacnt] is also updated, and the function returns
+ * |datacnt| + 1.  Otherwise, this function returns |datacnt|.
+ */
+size_t ngtcp2_pkt_remove_vec_partial(ngtcp2_vec *removed_data, ngtcp2_vec *data,
+                                     size_t datacnt, uint64_t *offsets,
+                                     ngtcp2_pcg32 *pcg, const ngtcp2_vec *part);
+
+/*
+ * ngtcp2_stateless_reset_token_eq returns nonzero if |a| and |b|
+ * share the same token.
+ */
+int ngtcp2_stateless_reset_token_eq(const ngtcp2_stateless_reset_token *a,
+                                    const ngtcp2_stateless_reset_token *b);
+
 #endif /* !defined(NGTCP2_PKT_H) */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ppe.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ppe.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ppe.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ppe.c	2026-05-15 15:49:15.165978400 +0200
@@ -154,9 +154,9 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe
 
   p = buf->begin;
   if (*p & NGTCP2_HEADER_FORM_BIT) {
-    *p = (uint8_t)(*p ^ (mask[0] & 0x0f));
+    *p = (uint8_t)(*p ^ (mask[0] & 0x0F));
   } else {
-    *p = (uint8_t)(*p ^ (mask[0] & 0x1f));
+    *p = (uint8_t)(*p ^ (mask[0] & 0x1F));
   }
 
   p = buf->begin + ppe->pkt_num_offset;
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pv.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pv.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pv.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pv.c	2026-05-15 15:49:15.165978400 +0200
@@ -31,12 +31,16 @@
 #include "ngtcp2_log.h"
 #include "ngtcp2_macro.h"
 #include "ngtcp2_addr.h"
+#include "ngtcp2_str.h"
 
-void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data,
+void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent,
+                          const ngtcp2_path_challenge_data *data,
                           ngtcp2_tstamp expiry, uint8_t flags) {
-  memcpy(pvent->data, data, sizeof(pvent->data));
-  pvent->expiry = expiry;
-  pvent->flags = flags;
+  *pvent = (ngtcp2_pv_entry){
+    .expiry = expiry,
+    .flags = flags,
+    .data = *data,
+  };
 }
 
 int ngtcp2_pv_new(ngtcp2_pv **ppv, const ngtcp2_dcid *dcid,
@@ -70,7 +74,7 @@ void ngtcp2_pv_del(ngtcp2_pv *pv) {
   ngtcp2_mem_free(pv->mem, pv);
 }
 
-void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data,
+void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const ngtcp2_path_challenge_data *data,
                          ngtcp2_tstamp expiry, uint8_t flags,
                          ngtcp2_tstamp ts) {
   ngtcp2_pv_entry *ent;
@@ -88,7 +92,8 @@ void ngtcp2_pv_add_entry(ngtcp2_pv *pv,
   --pv->probe_pkt_left;
 }
 
-int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data) {
+int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags,
+                       const ngtcp2_path_challenge_data *data) {
   size_t len = ngtcp2_ringbuf_len(&pv->ents.rb);
   size_t i;
   ngtcp2_pv_entry *ent;
@@ -99,7 +104,7 @@ int ngtcp2_pv_validate(ngtcp2_pv *pv, ui
 
   for (i = 0; i < len; ++i) {
     ent = ngtcp2_ringbuf_get(&pv->ents.rb, i);
-    if (memcmp(ent->data, data, sizeof(ent->data)) == 0) {
+    if (ngtcp2_cmemeq(ent->data.data, data->data, sizeof(ent->data.data))) {
       *pflags = ent->flags;
       ngtcp2_log_info(pv->log, NGTCP2_LOG_EVENT_PTV, "path has been validated");
       return 0;
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pv.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pv.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_pv.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_pv.h	2026-05-15 15:49:15.165978400 +0200
@@ -46,10 +46,10 @@ typedef struct ngtcp2_log ngtcp2_log;
 typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
 
 /* NGTCP2_PV_ENTRY_FLAG_NONE indicates that no flag is set. */
-#define NGTCP2_PV_ENTRY_FLAG_NONE 0x00u
+#define NGTCP2_PV_ENTRY_FLAG_NONE 0x00U
 /* NGTCP2_PV_ENTRY_FLAG_UNDERSIZED indicates that UDP datagram which
    contains PATH_CHALLENGE is undersized (< 1200 bytes) */
-#define NGTCP2_PV_ENTRY_FLAG_UNDERSIZED 0x01u
+#define NGTCP2_PV_ENTRY_FLAG_UNDERSIZED 0x01U
 
 typedef struct ngtcp2_pv_entry {
   /* expiry is the timestamp when this PATH_CHALLENGE expires. */
@@ -57,30 +57,31 @@ typedef struct ngtcp2_pv_entry {
   /* flags is zero or more of NGTCP2_PV_ENTRY_FLAG_*. */
   uint8_t flags;
   /* data is a byte string included in PATH_CHALLENGE. */
-  uint8_t data[8];
+  ngtcp2_path_challenge_data data;
 } ngtcp2_pv_entry;
 
-void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data,
+void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent,
+                          const ngtcp2_path_challenge_data *data,
                           ngtcp2_tstamp expiry, uint8_t flags);
 
 /* NGTCP2_PV_FLAG_NONE indicates no flag is set. */
-#define NGTCP2_PV_FLAG_NONE 0x00u
+#define NGTCP2_PV_FLAG_NONE 0x00U
 /* NGTCP2_PV_FLAG_DONT_CARE indicates that the outcome of path
    validation should be ignored entirely. */
-#define NGTCP2_PV_FLAG_DONT_CARE 0x01u
+#define NGTCP2_PV_FLAG_DONT_CARE 0x01U
 /* NGTCP2_PV_FLAG_CANCEL_TIMER indicates that the expiry timer is
    cancelled. */
-#define NGTCP2_PV_FLAG_CANCEL_TIMER 0x02u
+#define NGTCP2_PV_FLAG_CANCEL_TIMER 0x02U
 /* NGTCP2_PV_FLAG_FALLBACK_PRESENT indicates that a fallback
    Destination Connection ID and PTO are available in ngtcp2_pv.  If
    path validation fails, then fallback to them.  If path validation
    succeeds, the fallback Destination Connection ID is retired if it
    is not zero length, and does not equal to the current Destination
    Connection ID. */
-#define NGTCP2_PV_FLAG_FALLBACK_PRESENT 0x04u
+#define NGTCP2_PV_FLAG_FALLBACK_PRESENT 0x04U
 /* NGTCP2_PV_FLAG_PREFERRED_ADDR indicates that client is migrating to
    server's preferred address.  This flag is only used by client. */
-#define NGTCP2_PV_FLAG_PREFERRED_ADDR 0x10u
+#define NGTCP2_PV_FLAG_PREFERRED_ADDR 0x10U
 
 typedef struct ngtcp2_pv ngtcp2_pv;
 
@@ -141,7 +142,7 @@ void ngtcp2_pv_del(ngtcp2_pv *pv);
  * ngtcp2_pv_add_entry adds new entry with |data|.  |expiry| is the
  * expiry time of the entry.
  */
-void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data,
+void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const ngtcp2_path_challenge_data *data,
                          ngtcp2_tstamp expiry, uint8_t flags, ngtcp2_tstamp ts);
 
 /*
@@ -164,7 +165,8 @@ int ngtcp2_pv_full(ngtcp2_pv *pv);
  * NGTCP2_ERR_INVALID_ARGUMENT
  *     |pv| does not have an entry which has |data| and |path|
  */
-int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data);
+int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags,
+                       const ngtcp2_path_challenge_data *data);
 
 /*
  * ngtcp2_pv_handle_entry_expiry checks expiry of existing entries.
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_qlog.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_qlog.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_qlog.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_qlog.c	2026-05-15 15:49:15.165978400 +0200
@@ -40,7 +40,7 @@ void ngtcp2_qlog_init(ngtcp2_qlog *qlog,
   qlog->user_data = user_data;
 }
 
-#define write_verbatim(DEST, S) ngtcp2_cpymem((DEST), (S), sizeof(S) - 1)
+#define write_verbatim(DEST, S) ngtcp2_cpymem((DEST), (S), ngtcp2_strlen_lit(S))
 
 static uint8_t *write_string_impl(uint8_t *p, const uint8_t *data,
                                   size_t datalen) {
@@ -53,17 +53,11 @@ static uint8_t *write_string_impl(uint8_
 }
 
 #define write_string(DEST, S)                                                  \
-  write_string_impl((DEST), (const uint8_t *)(S), sizeof(S) - 1)
-
-#define NGTCP2_LOWER_XDIGITS "0123456789abcdef"
+  write_string_impl((DEST), (const uint8_t *)(S), ngtcp2_strlen_lit(S))
 
 static uint8_t *write_hex(uint8_t *p, const uint8_t *data, size_t datalen) {
-  const uint8_t *b = data, *end = data + datalen;
   *p++ = '"';
-  for (; b != end; ++b) {
-    *p++ = (uint8_t)NGTCP2_LOWER_XDIGITS[*b >> 4];
-    *p++ = (uint8_t)NGTCP2_LOWER_XDIGITS[*b & 0xf];
-  }
+  p = ngtcp2_encode_hex(p, data, datalen);
   *p++ = '"';
   return p;
 }
@@ -72,38 +66,19 @@ static uint8_t *write_cid(uint8_t *p, co
   return write_hex(p, cid->data, cid->datalen);
 }
 
-static uint8_t *write_number(uint8_t *p, uint64_t n) {
-  size_t nlen = 0;
-  uint64_t t;
-  uint8_t *res;
-
-  if (n == 0) {
-    *p++ = '0';
-    return p;
-  }
-  for (t = n; t; t /= 10, ++nlen)
-    ;
-  p += nlen;
-  res = p;
-  for (; n; n /= 10) {
-    *--p = (uint8_t)((n % 10) + '0');
-  }
-  return res;
-}
-
 static uint8_t *write_tstamp(uint8_t *p, ngtcp2_tstamp ts) {
-  return write_number(p, ts / NGTCP2_MILLISECONDS);
+  return ngtcp2_encode_uint(p, ts / NGTCP2_MILLISECONDS);
 }
 
 static uint8_t *write_duration(uint8_t *p, ngtcp2_duration duration) {
-  return write_number(p, duration / NGTCP2_MILLISECONDS);
+  return ngtcp2_encode_uint(p, duration / NGTCP2_MILLISECONDS);
 }
 
 static uint8_t *write_bool(uint8_t *p, int b) {
   if (b) {
-    return ngtcp2_cpymem(p, "true", sizeof("true") - 1);
+    return ngtcp2_cpymem(p, "true", ngtcp2_strlen_lit("true"));
   }
-  return ngtcp2_cpymem(p, "false", sizeof("false") - 1);
+  return ngtcp2_cpymem(p, "false", ngtcp2_strlen_lit("false"));
 }
 
 static uint8_t *write_pair_impl(uint8_t *p, const uint8_t *name, size_t namelen,
@@ -114,7 +89,8 @@ static uint8_t *write_pair_impl(uint8_t
 }
 
 #define write_pair(DEST, NAME, VALUE)                                          \
-  write_pair_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1, (VALUE))
+  write_pair_impl((DEST), (const uint8_t *)(NAME), ngtcp2_strlen_lit(NAME),    \
+                  (VALUE))
 
 static uint8_t *write_pair_hex_impl(uint8_t *p, const uint8_t *name,
                                     size_t namelen, const uint8_t *value,
@@ -125,19 +101,19 @@ static uint8_t *write_pair_hex_impl(uint
 }
 
 #define write_pair_hex(DEST, NAME, VALUE, VALUELEN)                            \
-  write_pair_hex_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,       \
-                      (VALUE), (VALUELEN))
+  write_pair_hex_impl((DEST), (const uint8_t *)(NAME),                         \
+                      ngtcp2_strlen_lit(NAME), (VALUE), (VALUELEN))
 
 static uint8_t *write_pair_number_impl(uint8_t *p, const uint8_t *name,
                                        size_t namelen, uint64_t value) {
   p = write_string_impl(p, name, namelen);
   *p++ = ':';
-  return write_number(p, value);
+  return ngtcp2_encode_uint(p, value);
 }
 
 #define write_pair_number(DEST, NAME, VALUE)                                   \
-  write_pair_number_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,    \
-                         (VALUE))
+  write_pair_number_impl((DEST), (const uint8_t *)(NAME),                      \
+                         ngtcp2_strlen_lit(NAME), (VALUE))
 
 static uint8_t *write_pair_duration_impl(uint8_t *p, const uint8_t *name,
                                          size_t namelen,
@@ -148,8 +124,8 @@ static uint8_t *write_pair_duration_impl
 }
 
 #define write_pair_duration(DEST, NAME, VALUE)                                 \
-  write_pair_duration_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,  \
-                           (VALUE))
+  write_pair_duration_impl((DEST), (const uint8_t *)(NAME),                    \
+                           ngtcp2_strlen_lit(NAME), (VALUE))
 
 static uint8_t *write_pair_tstamp_impl(uint8_t *p, const uint8_t *name,
                                        size_t namelen, ngtcp2_tstamp ts) {
@@ -159,8 +135,8 @@ static uint8_t *write_pair_tstamp_impl(u
 }
 
 #define write_pair_tstamp(DEST, NAME, VALUE)                                   \
-  write_pair_tstamp_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,    \
-                         (VALUE))
+  write_pair_tstamp_impl((DEST), (const uint8_t *)(NAME),                      \
+                         ngtcp2_strlen_lit(NAME), (VALUE))
 
 static uint8_t *write_pair_bool_impl(uint8_t *p, const uint8_t *name,
                                      size_t namelen, int b) {
@@ -170,8 +146,8 @@ static uint8_t *write_pair_bool_impl(uin
 }
 
 #define write_pair_bool(DEST, NAME, VALUE)                                     \
-  write_pair_bool_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,      \
-                       (VALUE))
+  write_pair_bool_impl((DEST), (const uint8_t *)(NAME),                        \
+                       ngtcp2_strlen_lit(NAME), (VALUE))
 
 static uint8_t *write_pair_cid_impl(uint8_t *p, const uint8_t *name,
                                     size_t namelen, const ngtcp2_cid *cid) {
@@ -181,10 +157,10 @@ static uint8_t *write_pair_cid_impl(uint
 }
 
 #define write_pair_cid(DEST, NAME, VALUE)                                      \
-  write_pair_cid_impl((DEST), (const uint8_t *)(NAME), sizeof(NAME) - 1,       \
-                      (VALUE))
+  write_pair_cid_impl((DEST), (const uint8_t *)(NAME),                         \
+                      ngtcp2_strlen_lit(NAME), (VALUE))
 
-#define ngtcp2_make_vec_lit(S) {(uint8_t *)(S), sizeof((S)) - 1}
+#define ngtcp2_make_vec_lit(S) {(uint8_t *)(S), ngtcp2_strlen_lit((S))}
 
 static uint8_t *write_common_fields(uint8_t *p, const ngtcp2_cid *odcid) {
   p = write_verbatim(
@@ -218,7 +194,7 @@ void ngtcp2_qlog_start(ngtcp2_qlog *qlog
   }
 
   p = write_verbatim(
-    p, "\x1e{\"qlog_format\":\"JSON-SEQ\",\"qlog_version\":\"0.3\",");
+    p, "\x1E{\"qlog_format\":\"JSON-SEQ\",\"qlog_version\":\"0.3\",");
   p = write_trace(p, server, odcid);
   p = write_verbatim(p, "}\n");
 
@@ -227,49 +203,41 @@ void ngtcp2_qlog_start(ngtcp2_qlog *qlog
 }
 
 void ngtcp2_qlog_end(ngtcp2_qlog *qlog) {
-  uint8_t buf[1] = {0};
-
   if (!qlog->write) {
     return;
   }
 
-  qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_FIN, &buf, 0);
+  qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_FIN, "", 0);
 }
 
-static ngtcp2_vec vec_pkt_type_initial = ngtcp2_make_vec_lit("initial");
-static ngtcp2_vec vec_pkt_type_handshake = ngtcp2_make_vec_lit("handshake");
-static ngtcp2_vec vec_pkt_type_0rtt = ngtcp2_make_vec_lit("0RTT");
-static ngtcp2_vec vec_pkt_type_1rtt = ngtcp2_make_vec_lit("1RTT");
-static ngtcp2_vec vec_pkt_type_retry = ngtcp2_make_vec_lit("retry");
-static ngtcp2_vec vec_pkt_type_version_negotiation =
+static const ngtcp2_vec vec_pkt_type_initial = ngtcp2_make_vec_lit("initial");
+static const ngtcp2_vec vec_pkt_type_handshake =
+  ngtcp2_make_vec_lit("handshake");
+static const ngtcp2_vec vec_pkt_type_0rtt = ngtcp2_make_vec_lit("0RTT");
+static const ngtcp2_vec vec_pkt_type_1rtt = ngtcp2_make_vec_lit("1RTT");
+static const ngtcp2_vec vec_pkt_type_retry = ngtcp2_make_vec_lit("retry");
+static const ngtcp2_vec vec_pkt_type_version_negotiation =
   ngtcp2_make_vec_lit("version_negotiation");
-static ngtcp2_vec vec_pkt_type_stateless_reset =
+static const ngtcp2_vec vec_pkt_type_stateless_reset =
   ngtcp2_make_vec_lit("stateless_reset");
-static ngtcp2_vec vec_pkt_type_unknown = ngtcp2_make_vec_lit("unknown");
+static const ngtcp2_vec vec_pkt_type_unknown = ngtcp2_make_vec_lit("unknown");
 
 static const ngtcp2_vec *qlog_pkt_type(const ngtcp2_pkt_hd *hd) {
-  if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) {
-    switch (hd->type) {
-    case NGTCP2_PKT_INITIAL:
-      return &vec_pkt_type_initial;
-    case NGTCP2_PKT_HANDSHAKE:
-      return &vec_pkt_type_handshake;
-    case NGTCP2_PKT_0RTT:
-      return &vec_pkt_type_0rtt;
-    case NGTCP2_PKT_RETRY:
-      return &vec_pkt_type_retry;
-    default:
-      return &vec_pkt_type_unknown;
-    }
-  }
-
   switch (hd->type) {
+  case NGTCP2_PKT_INITIAL:
+    return &vec_pkt_type_initial;
+  case NGTCP2_PKT_0RTT:
+    return &vec_pkt_type_0rtt;
+  case NGTCP2_PKT_HANDSHAKE:
+    return &vec_pkt_type_handshake;
+  case NGTCP2_PKT_RETRY:
+    return &vec_pkt_type_retry;
+  case NGTCP2_PKT_1RTT:
+    return &vec_pkt_type_1rtt;
   case NGTCP2_PKT_VERSION_NEGOTIATION:
     return &vec_pkt_type_version_negotiation;
   case NGTCP2_PKT_STATELESS_RESET:
     return &vec_pkt_type_stateless_reset;
-  case NGTCP2_PKT_1RTT:
-    return &vec_pkt_type_1rtt;
   default:
     return &vec_pkt_type_unknown;
   }
@@ -340,10 +308,10 @@ static uint8_t *write_ack_frame(uint8_t
   min_ack = fr->largest_ack - (int64_t)fr->first_ack_range;
 
   *p++ = '[';
-  p = write_number(p, (uint64_t)min_ack);
+  p = ngtcp2_encode_uint(p, (uint64_t)min_ack);
   if (largest_ack != min_ack) {
     *p++ = ',';
-    p = write_number(p, (uint64_t)largest_ack);
+    p = ngtcp2_encode_uint(p, (uint64_t)largest_ack);
   }
   *p++ = ']';
 
@@ -353,10 +321,10 @@ static uint8_t *write_ack_frame(uint8_t
     min_ack = largest_ack - (int64_t)range->len;
     *p++ = ',';
     *p++ = '[';
-    p = write_number(p, (uint64_t)min_ack);
+    p = ngtcp2_encode_uint(p, (uint64_t)min_ack);
     if (largest_ack != min_ack) {
       *p++ = ',';
-      p = write_number(p, (uint64_t)largest_ack);
+      p = ngtcp2_encode_uint(p, (uint64_t)largest_ack);
     }
     *p++ = ']';
   }
@@ -579,8 +547,7 @@ write_new_connection_id_frame(uint8_t *p
   *p++ = ',';
   p = write_pair_cid(p, "connection_id", &fr->cid);
   p = write_verbatim(p, ",\"stateless_reset_token\":{");
-  p = write_pair_hex(p, "data", fr->stateless_reset_token,
-                     sizeof(fr->stateless_reset_token));
+  p = write_pair_hex(p, "data", fr->token.data, sizeof(fr->token.data));
   *p++ = '}';
   *p++ = '}';
 
@@ -610,7 +577,7 @@ static uint8_t *write_path_challenge_fra
 #define NGTCP2_QLOG_PATH_CHALLENGE_FRAME_OVERHEAD 57
 
   p = write_verbatim(p, "{\"frame_type\":\"path_challenge\",");
-  p = write_pair_hex(p, "data", fr->data, sizeof(fr->data));
+  p = write_pair_hex(p, "data", fr->data.data, sizeof(fr->data.data));
   *p++ = '}';
 
   return p;
@@ -624,7 +591,7 @@ static uint8_t *write_path_response_fram
 #define NGTCP2_QLOG_PATH_RESPONSE_FRAME_OVERHEAD 56
 
   p = write_verbatim(p, "{\"frame_type\":\"path_response\",");
-  p = write_pair_hex(p, "data", fr->data, sizeof(fr->data));
+  p = write_pair_hex(p, "data", fr->data.data, sizeof(fr->data.data));
   *p++ = '}';
 
   return p;
@@ -694,7 +661,7 @@ static void qlog_pkt_write_start(ngtcp2_
   ngtcp2_buf_reset(&qlog->buf);
   p = qlog->buf.last;
 
-  *p++ = '\x1e';
+  *p++ = '\x1E';
   *p++ = '{';
   p = qlog_write_time(qlog, p);
   p = write_verbatim(p, ",\"name\":");
@@ -738,7 +705,7 @@ static void qlog_pkt_write_end(ngtcp2_ql
   p = write_verbatim(p, "],\"header\":");
   p = write_pkt_hd(p, hd);
   p = write_verbatim(p, ",\"raw\":{\"length\":");
-  p = write_number(p, pktlen);
+  p = ngtcp2_encode_uint(p, pktlen);
   p = write_verbatim(p, "}}}\n");
 
   qlog->buf.last = p;
@@ -754,7 +721,7 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog
     return;
   }
 
-  switch (fr->type) {
+  switch (fr->hd.type) {
   case NGTCP2_FRAME_PADDING:
     if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_PADDING_FRAME_OVERHEAD + 1) {
       return;
@@ -771,7 +738,7 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog
   case NGTCP2_FRAME_ACK_ECN:
     if (ngtcp2_buf_left(&qlog->buf) <
         NGTCP2_QLOG_ACK_FRAME_BASE_OVERHEAD +
-          (size_t)(fr->type == NGTCP2_FRAME_ACK_ECN
+          (size_t)(fr->ack.type == NGTCP2_FRAME_ACK_ECN
                      ? NGTCP2_QLOG_ACK_FRAME_ECN_OVERHEAD
                      : 0) +
           NGTCP2_QLOG_ACK_FRAME_RANGE_OVERHEAD * (1 + fr->ack.rangecnt) + 1) {
@@ -935,7 +902,7 @@ void ngtcp2_qlog_pkt_sent_end(ngtcp2_qlo
 void ngtcp2_qlog_parameters_set_transport_params(
   ngtcp2_qlog *qlog, const ngtcp2_transport_params *params, int server,
   ngtcp2_qlog_side side) {
-  uint8_t buf[1024];
+  uint8_t buf[2048];
   uint8_t *p = buf;
   const ngtcp2_preferred_addr *paddr;
   const ngtcp2_sockaddr_in *sa_in;
@@ -945,7 +912,7 @@ void ngtcp2_qlog_parameters_set_transpor
     return;
   }
 
-  *p++ = '\x1e';
+  *p++ = '\x1E';
   *p++ = '{';
   p = qlog_write_time(qlog, p);
   p = write_verbatim(
@@ -1061,7 +1028,7 @@ void ngtcp2_qlog_metrics_updated(ngtcp2_
     return;
   }
 
-  *p++ = '\x1e';
+  *p++ = '\x1E';
   *p++ = '{';
   p = qlog_write_time(qlog, p);
   p = write_verbatim(p, ",\"name\":\"recovery:metrics_updated\",\"data\":{");
@@ -1095,23 +1062,22 @@ void ngtcp2_qlog_metrics_updated(ngtcp2_
 void ngtcp2_qlog_pkt_lost(ngtcp2_qlog *qlog, ngtcp2_rtb_entry *ent) {
   uint8_t buf[256];
   uint8_t *p = buf;
-  ngtcp2_pkt_hd hd = {0};
 
   if (!qlog->write) {
     return;
   }
 
-  *p++ = '\x1e';
+  *p++ = '\x1E';
   *p++ = '{';
   p = qlog_write_time(qlog, p);
   p = write_verbatim(
     p, ",\"name\":\"recovery:packet_lost\",\"data\":{\"header\":");
 
-  hd.type = ent->hd.type;
-  hd.flags = ent->hd.flags;
-  hd.pkt_num = ent->hd.pkt_num;
-
-  p = write_pkt_hd(p, &hd);
+  p = write_pkt_hd(p, &(ngtcp2_pkt_hd){
+                        .pkt_num = ent->hd.pkt_num,
+                        .type = ent->hd.type,
+                        .flags = ent->hd.flags,
+                      });
   p = write_verbatim(p, "}}\n");
 
   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
@@ -1129,7 +1095,7 @@ void ngtcp2_qlog_retry_pkt_received(ngtc
 
   ngtcp2_buf_init(&buf, rawbuf, sizeof(rawbuf));
 
-  *buf.last++ = '\x1e';
+  *buf.last++ = '\x1E';
   *buf.last++ = '{';
   buf.last = qlog_write_time(qlog, buf.last);
   buf.last = write_verbatim(
@@ -1151,26 +1117,25 @@ void ngtcp2_qlog_retry_pkt_received(ngtc
 }
 
 void ngtcp2_qlog_stateless_reset_pkt_received(
-  ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset *sr) {
+  ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset2 *sr) {
   uint8_t buf[256];
   uint8_t *p = buf;
-  ngtcp2_pkt_hd hd = {0};
 
   if (!qlog->write) {
     return;
   }
 
-  hd.type = NGTCP2_PKT_STATELESS_RESET;
-
-  *p++ = '\x1e';
+  *p++ = '\x1E';
   *p++ = '{';
   p = qlog_write_time(qlog, p);
   p = write_verbatim(
     p, ",\"name\":\"transport:packet_received\",\"data\":{\"header\":");
-  p = write_pkt_hd(p, &hd);
+  p = write_pkt_hd(p, &(ngtcp2_pkt_hd){
+                        .type = NGTCP2_PKT_STATELESS_RESET,
+                      });
   *p++ = ',';
-  p = write_pair_hex(p, "stateless_reset_token", sr->stateless_reset_token,
-                     NGTCP2_STATELESS_RESET_TOKENLEN);
+  p = write_pair_hex(p, "stateless_reset_token", sr->token.data,
+                     sizeof(sr->token.data));
   p = write_verbatim(p, "}}\n");
 
   qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
@@ -1192,7 +1157,7 @@ void ngtcp2_qlog_version_negotiation_pkt
 
   ngtcp2_buf_init(&buf, rawbuf, sizeof(rawbuf));
 
-  *buf.last++ = '\x1e';
+  *buf.last++ = '\x1E';
   *buf.last++ = '{';
   buf.last = qlog_write_time(qlog, buf.last);
   buf.last = write_verbatim(
@@ -1201,8 +1166,8 @@ void ngtcp2_qlog_version_negotiation_pkt
   buf.last = write_verbatim(buf.last, ",\"supported_versions\":[");
 
   if (nsv) {
-    if (ngtcp2_buf_left(&buf) <
-        (sizeof("\"xxxxxxxx\",") - 1) * nsv - 1 + sizeof("]}}\n") - 1) {
+    if (ngtcp2_buf_left(&buf) < ngtcp2_strlen_lit("\"xxxxxxxx\",") * nsv - 1 +
+                                  ngtcp2_strlen_lit("]}}\n")) {
       return;
     }
 
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_qlog.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_qlog.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_qlog.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_qlog.h	2026-05-15 15:49:15.165978400 +0200
@@ -147,7 +147,7 @@ void ngtcp2_qlog_retry_pkt_received(ngtc
  * event for a received Stateless Reset packet.
  */
 void ngtcp2_qlog_stateless_reset_pkt_received(
-  ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset *sr);
+  ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset2 *sr);
 
 /*
  * ngtcp2_qlog_version_negotiation_pkt_received writes packet_received
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_range.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_range.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_range.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_range.c	2026-05-15 15:49:15.166978600 +0200
@@ -26,18 +26,22 @@
 #include "ngtcp2_macro.h"
 
 void ngtcp2_range_init(ngtcp2_range *r, uint64_t begin, uint64_t end) {
-  r->begin = begin;
-  r->end = end;
+  *r = (ngtcp2_range){
+    .begin = begin,
+    .end = end,
+  };
 }
 
 ngtcp2_range ngtcp2_range_intersect(const ngtcp2_range *a,
                                     const ngtcp2_range *b) {
-  ngtcp2_range r = {0};
+  ngtcp2_range r;
   uint64_t begin = ngtcp2_max_uint64(a->begin, b->begin);
   uint64_t end = ngtcp2_min_uint64(a->end, b->end);
 
   if (begin < end) {
     ngtcp2_range_init(&r, begin, end);
+  } else {
+    r = (ngtcp2_range){0};
   }
 
   return r;
@@ -52,10 +56,14 @@ int ngtcp2_range_eq(const ngtcp2_range *
 void ngtcp2_range_cut(ngtcp2_range *left, ngtcp2_range *right,
                       const ngtcp2_range *a, const ngtcp2_range *b) {
   /* Assume that b is included in a */
-  left->begin = a->begin;
-  left->end = b->begin;
-  right->begin = b->end;
-  right->end = a->end;
+  *left = (ngtcp2_range){
+    .begin = a->begin,
+    .end = b->begin,
+  };
+  *right = (ngtcp2_range){
+    .begin = b->end,
+    .end = a->end,
+  };
 }
 
 int ngtcp2_range_not_after(const ngtcp2_range *a, const ngtcp2_range *b) {
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ratelim.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ratelim.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ratelim.c	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ratelim.c	2026-05-15 15:49:15.166978600 +0200
@@ -0,0 +1,84 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2025 ngtcp2 contributors
+ * Copyright (c) 2023 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "ngtcp2_ratelim.h"
+
+#include <assert.h>
+
+#include "ngtcp2_macro.h"
+
+void ngtcp2_ratelim_init(ngtcp2_ratelim *rlim, uint64_t burst, uint64_t rate,
+                         ngtcp2_tstamp ts) {
+  *rlim = (ngtcp2_ratelim){
+    .burst = burst,
+    .rate = rate,
+    .tokens = burst,
+    .ts = ts,
+  };
+}
+
+/* ratelim_update updates rlim->tokens with the current |ts|. */
+static void ratelim_update(ngtcp2_ratelim *rlim, ngtcp2_tstamp ts) {
+  uint64_t d, gain, gps;
+
+  assert(ts >= rlim->ts);
+
+  if (ts == rlim->ts) {
+    return;
+  }
+
+  d = ts - rlim->ts;
+  rlim->ts = ts;
+
+  if (rlim->rate > (UINT64_MAX - rlim->carry) / d) {
+    gain = UINT64_MAX;
+  } else {
+    gain = rlim->rate * d + rlim->carry;
+  }
+
+  gps = gain / NGTCP2_SECONDS;
+
+  if (gps < rlim->burst && rlim->tokens < rlim->burst - gps) {
+    rlim->tokens += gps;
+    rlim->carry = gain % NGTCP2_SECONDS;
+
+    return;
+  }
+
+  rlim->tokens = rlim->burst;
+  rlim->carry = 0;
+}
+
+int ngtcp2_ratelim_drain(ngtcp2_ratelim *rlim, uint64_t n, ngtcp2_tstamp ts) {
+  ratelim_update(rlim, ts);
+
+  if (rlim->tokens < n) {
+    return -1;
+  }
+
+  rlim->tokens -= n;
+
+  return 0;
+}
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ratelim.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ratelim.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ratelim.h	1970-01-01 01:00:00.000000000 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ratelim.h	2026-05-15 15:49:15.166978600 +0200
@@ -0,0 +1,59 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2025 ngtcp2 contributors
+ * Copyright (c) 2023 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGTCP2_RATELIM_H
+#define NGTCP2_RATELIM_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif /* defined(HAVE_CONFIG_H) */
+
+#include <ngtcp2/ngtcp2.h>
+
+typedef struct ngtcp2_ratelim {
+  /* burst is the maximum number of tokens. */
+  uint64_t burst;
+  /* rate is the rate of token generation measured by token /
+     second. */
+  uint64_t rate;
+  /* tokens is the amount of tokens available to drain. */
+  uint64_t tokens;
+  /* carry is the partial token gained in sub-second period.  It is
+     added to the computation in the next update round. */
+  uint64_t carry;
+  /* ts is the last timestamp that is known to this object. */
+  ngtcp2_tstamp ts;
+} ngtcp2_ratelim;
+
+/* ngtcp2_ratelim_init initializes |rlim| with the given
+   parameters. */
+void ngtcp2_ratelim_init(ngtcp2_ratelim *rlim, uint64_t burst, uint64_t rate,
+                         ngtcp2_tstamp ts);
+
+/* ngtcp2_ratelim_drain drains |n| from rlim->tokens.  It returns 0 if
+   it succeeds, or -1. */
+int ngtcp2_ratelim_drain(ngtcp2_ratelim *rlim, uint64_t n, ngtcp2_tstamp ts);
+
+#endif /* !defined(NGTCP2_RATELIM_H) */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ringbuf.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ringbuf.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ringbuf.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ringbuf.c	2026-05-15 15:49:15.166978600 +0200
@@ -32,18 +32,8 @@
 #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))
-  return n && !(n & (n - 1));
-#  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)) */
-  return 1 == __builtin_popcount((unsigned int)n);
-#  endif /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \
-            (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
-}
+/* Power-of-two test; simple portable bit trick. */
+static int ispow2(size_t n) { return n && !(n & (n - 1)); }
 #endif /* !defined(NDEBUG) */
 
 int ngtcp2_ringbuf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size,
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ringbuf.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ringbuf.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_ringbuf.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_ringbuf.h	2026-05-15 15:49:15.166978600 +0200
@@ -110,7 +110,9 @@ void ngtcp2_ringbuf_resize(ngtcp2_ringbu
 void *ngtcp2_ringbuf_get(const ngtcp2_ringbuf *rb, size_t offset);
 
 /* ngtcp2_ringbuf_len returns the number of elements stored. */
-#define ngtcp2_ringbuf_len(RB) ((RB)->len)
+static inline size_t ngtcp2_ringbuf_len(const ngtcp2_ringbuf *rb) {
+  return rb->len;
+}
 
 /* ngtcp2_ringbuf_full returns nonzero if |rb| is full. */
 int ngtcp2_ringbuf_full(const ngtcp2_ringbuf *rb);
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rob.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rob.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rob.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rob.c	2026-05-15 15:49:15.166978600 +0200
@@ -36,8 +36,13 @@ int ngtcp2_rob_gap_new(ngtcp2_rob_gap **
     return NGTCP2_ERR_NOMEM;
   }
 
-  (*pg)->range.begin = begin;
-  (*pg)->range.end = end;
+  **pg = (ngtcp2_rob_gap){
+    .range =
+      {
+        .begin = begin,
+        .end = end,
+      },
+  };
 
   return 0;
 }
@@ -53,9 +58,14 @@ int ngtcp2_rob_data_new(ngtcp2_rob_data
     return NGTCP2_ERR_NOMEM;
   }
 
-  (*pd)->range.begin = offset;
-  (*pd)->range.end = offset + chunk;
-  (*pd)->begin = (uint8_t *)(*pd) + sizeof(ngtcp2_rob_data);
+  **pd = (ngtcp2_rob_data){
+    .range =
+      {
+        .begin = offset,
+        .end = offset + chunk,
+      },
+    .begin = (uint8_t *)(*pd) + sizeof(ngtcp2_rob_data),
+  };
 
   return 0;
 }
@@ -162,8 +172,8 @@ static int rob_write_data(ngtcp2_rob *ro
   return 0;
 }
 
-int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
-                    size_t datalen) {
+ngtcp2_ssize ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset,
+                             const uint8_t *data, size_t datalen) {
   int rv;
   ngtcp2_rob_gap *g;
   ngtcp2_range m, l, r;
@@ -172,6 +182,8 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uin
     .end = offset + datalen,
   };
   ngtcp2_ksl_it it;
+  ngtcp2_ssize nwrite = 0;
+  size_t mlen;
 
   it = ngtcp2_ksl_lower_bound_search(&rob->gapksl, &q,
                                      ngtcp2_ksl_range_exclusive_search);
@@ -180,7 +192,9 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uin
     g = ngtcp2_ksl_it_get(&it);
 
     m = ngtcp2_range_intersect(&q, &g->range);
-    if (!ngtcp2_range_len(&m)) {
+
+    mlen = (size_t)ngtcp2_range_len(&m);
+    if (mlen == 0) {
       break;
     }
 
@@ -188,12 +202,13 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uin
       ngtcp2_ksl_remove_hint(&rob->gapksl, &it, &it, &g->range);
       ngtcp2_rob_gap_del(g, rob->mem);
 
-      rv = rob_write_data(rob, m.begin, data + (m.begin - offset),
-                          (size_t)ngtcp2_range_len(&m));
+      rv = rob_write_data(rob, m.begin, data + (m.begin - offset), mlen);
       if (rv != 0) {
         return rv;
       }
 
+      nwrite += (ngtcp2_ssize)mlen;
+
       continue;
     }
 
@@ -222,16 +237,17 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uin
       g->range = r;
     }
 
-    rv = rob_write_data(rob, m.begin, data + (m.begin - offset),
-                        (size_t)ngtcp2_range_len(&m));
+    rv = rob_write_data(rob, m.begin, data + (m.begin - offset), mlen);
     if (rv != 0) {
       return rv;
     }
 
+    nwrite += (ngtcp2_ssize)mlen;
+
     ngtcp2_ksl_it_next(&it);
   }
 
-  return 0;
+  return nwrite;
 }
 
 void ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) {
@@ -248,9 +264,11 @@ void ngtcp2_rob_remove_prefix(ngtcp2_rob
     }
 
     if (offset < g->range.end) {
-      ngtcp2_range r = {offset, g->range.end};
-
-      ngtcp2_ksl_update_key(&rob->gapksl, &g->range, &r);
+      ngtcp2_ksl_update_key(&rob->gapksl, &g->range,
+                            &(ngtcp2_range){
+                              .begin = offset,
+                              .end = g->range.end,
+                            });
       g->range.begin = offset;
 
       break;
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rob.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rob.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rob.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rob.h	2026-05-15 15:49:15.166978600 +0200
@@ -138,14 +138,14 @@ void ngtcp2_rob_free(ngtcp2_rob *rob);
  * ngtcp2_rob_push adds new data pointed by |data| of length |datalen|
  * at the stream offset |offset|.
  *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
+ * This function returns the number of data newly buffered if it
+ * succeeds, or one of the following negative error codes:
  *
  * NGTCP2_ERR_NOMEM
  *     Out of memory
  */
-int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
-                    size_t datalen);
+ngtcp2_ssize ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset,
+                             const uint8_t *data, size_t datalen);
 
 /*
  * ngtcp2_rob_remove_prefix removes gap up to |offset|, exclusive.  It
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rst.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rst.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rst.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rst.c	2026-05-15 15:49:15.166978600 +0200
@@ -32,17 +32,11 @@
 #include "ngtcp2_conn_stat.h"
 
 void ngtcp2_rs_init(ngtcp2_rs *rs) {
-  rs->interval = UINT64_MAX;
-  rs->delivered = 0;
-  rs->prior_delivered = 0;
-  rs->prior_ts = UINT64_MAX;
-  rs->tx_in_flight = 0;
-  rs->lost = 0;
-  rs->prior_lost = 0;
-  rs->send_elapsed = 0;
-  rs->ack_elapsed = 0;
-  rs->last_end_seq = -1;
-  rs->is_app_limited = 0;
+  *rs = (ngtcp2_rs){
+    .interval = UINT64_MAX,
+    .prior_ts = UINT64_MAX,
+    .last_end_seq = -1,
+  };
 }
 
 void ngtcp2_rst_init(ngtcp2_rst *rst) {
@@ -58,19 +52,29 @@ void ngtcp2_rst_reset(ngtcp2_rst *rst) {
   rst->app_limited = 0;
   rst->is_cwnd_limited = 0;
   rst->lost = 0;
-  rst->valid_after_seq = rst->last_seq;
+}
+
+void ngtcp2_rst_reset_rate_sample(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) {
+  ngtcp2_rs *rs = &rst->rs;
+
+  rs->interval = UINT64_MAX;
+  rs->prior_ts = UINT64_MAX;
+
+  cstat->delivery_rate_sec = 0;
 }
 
 void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent,
                             const ngtcp2_conn_stat *cstat) {
-  if (cstat->bytes_in_flight == 0) {
+  /* cstat->bytes_in_flight includes ent->pktlen.  If they are the
+     same, there is no in-flight packets. */
+  if (cstat->bytes_in_flight == ent->pktlen) {
     rst->first_sent_ts = rst->delivered_ts = ent->ts;
   }
   ent->rst.first_sent_ts = rst->first_sent_ts;
   ent->rst.delivered_ts = rst->delivered_ts;
   ent->rst.delivered = rst->delivered;
   ent->rst.is_app_limited = rst->app_limited != 0;
-  ent->rst.tx_in_flight = cstat->bytes_in_flight + ent->pktlen;
+  ent->rst.tx_in_flight = cstat->bytes_in_flight;
   ent->rst.lost = rst->lost;
   ent->rst.end_seq = ++rst->last_seq;
 }
@@ -89,10 +93,8 @@ void ngtcp2_rst_on_ack_recv(ngtcp2_rst *
   rs->interval = ngtcp2_max_uint64(rs->send_elapsed, rs->ack_elapsed);
 
   rs->delivered = rst->delivered - rs->prior_delivered;
-  rs->lost = rst->lost - rs->prior_lost;
 
   if (rs->interval < cstat->min_rtt) {
-    rs->interval = UINT64_MAX;
     return;
   }
 
@@ -103,31 +105,23 @@ void ngtcp2_rst_on_ack_recv(ngtcp2_rst *
   cstat->delivery_rate_sec = rs->delivered * NGTCP2_SECONDS / rs->interval;
 }
 
-static int rst_is_newest_pkt(const ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent,
-                             const ngtcp2_rs *rs) {
-  return ent->ts > rst->first_sent_ts ||
-         (ent->ts == rst->first_sent_ts && ent->rst.end_seq > rs->last_end_seq);
+static int is_newest_pkt(const ngtcp2_rtb_entry *ent, const ngtcp2_rs *rs) {
+  return ent->rst.end_seq > rs->last_end_seq;
 }
 
 void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent,
                                    ngtcp2_tstamp ts) {
   ngtcp2_rs *rs = &rst->rs;
 
-  if (ent->rst.end_seq <= rst->valid_after_seq) {
-    return;
-  }
-
   rst->delivered += ent->pktlen;
   rst->delivered_ts = ts;
 
-  if (rs->prior_ts == UINT64_MAX || rst_is_newest_pkt(rst, ent, rs)) {
+  if (rs->prior_ts == UINT64_MAX || is_newest_pkt(ent, rs)) {
     rs->prior_delivered = ent->rst.delivered;
     rs->prior_ts = ent->rst.delivered_ts;
     rs->is_app_limited = ent->rst.is_app_limited;
     rs->send_elapsed = ent->ts - ent->rst.first_sent_ts;
     rs->ack_elapsed = rst->delivered_ts - ent->rst.delivered_ts;
-    rs->tx_in_flight = ent->rst.tx_in_flight;
-    rs->prior_lost = ent->rst.lost;
     rs->last_end_seq = ent->rst.end_seq;
     rst->first_sent_ts = ent->ts;
   }
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rst.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rst.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rst.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rst.h	2026-05-15 15:49:15.167978500 +0200
@@ -48,7 +48,6 @@ typedef struct ngtcp2_rs {
   ngtcp2_tstamp prior_ts;
   uint64_t tx_in_flight;
   uint64_t lost;
-  uint64_t prior_lost;
   ngtcp2_duration send_elapsed;
   ngtcp2_duration ack_elapsed;
   int64_t last_end_seq;
@@ -73,10 +72,6 @@ typedef struct ngtcp2_rst {
      across all packet number spaces, we can replace this with a
      packet number. */
   int64_t last_seq;
-  /* valid_after_seq is the sequence number, and ignore a packet if
-     the sequence number of the packet is less than or equal to this
-     number. */
-  int64_t valid_after_seq;
   int is_cwnd_limited;
 } ngtcp2_rst;
 
@@ -84,6 +79,8 @@ void ngtcp2_rst_init(ngtcp2_rst *rst);
 
 void ngtcp2_rst_reset(ngtcp2_rst *rst);
 
+void ngtcp2_rst_reset_rate_sample(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat);
+
 void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent,
                             const ngtcp2_conn_stat *cstat);
 void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat);
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rtb.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rtb.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rtb.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rtb.c	2026-05-15 15:49:15.167978500 +0200
@@ -43,16 +43,19 @@ ngtcp2_objalloc_def(rtb_entry, ngtcp2_rt
 static void rtb_entry_init(ngtcp2_rtb_entry *ent, const ngtcp2_pkt_hd *hd,
                            ngtcp2_frame_chain *frc, ngtcp2_tstamp ts,
                            size_t pktlen, uint16_t flags) {
-  memset(ent, 0, sizeof(*ent));
-
-  ent->hd.pkt_num = hd->pkt_num;
-  ent->hd.type = hd->type;
-  ent->hd.flags = hd->flags;
-  ent->frc = frc;
-  ent->ts = ts;
-  ent->lost_ts = UINT64_MAX;
-  ent->pktlen = pktlen;
-  ent->flags = flags;
+  *ent = (ngtcp2_rtb_entry){
+    .hd =
+      {
+        .pkt_num = hd->pkt_num,
+        .type = hd->type,
+        .flags = hd->flags,
+      },
+    .frc = frc,
+    .ts = ts,
+    .lost_ts = UINT64_MAX,
+    .pktlen = pktlen,
+    .flags = flags,
+  };
 }
 
 int ngtcp2_rtb_entry_objalloc_new(ngtcp2_rtb_entry **pent,
@@ -125,13 +128,12 @@ void ngtcp2_rtb_free(ngtcp2_rtb *rtb) {
 
 static void rtb_on_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
                        ngtcp2_conn_stat *cstat) {
-  ngtcp2_rst_on_pkt_sent(rtb->rst, ent, cstat);
-
   assert(rtb->cc_pkt_num <= ent->hd.pkt_num);
 
   cstat->bytes_in_flight += ent->pktlen;
   rtb->cc_bytes_in_flight += ent->pktlen;
 
+  ngtcp2_rst_on_pkt_sent(rtb->rst, ent, cstat);
   ngtcp2_rst_update_app_limited(rtb->rst, cstat);
 
   if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
@@ -198,10 +200,10 @@ static size_t rtb_on_remove(ngtcp2_rtb *
 }
 
 /* NGTCP2_RECLAIM_FLAG_NONE indicates that no flag is set. */
-#define NGTCP2_RECLAIM_FLAG_NONE 0x00u
+#define NGTCP2_RECLAIM_FLAG_NONE 0x00U
 /* NGTCP2_RECLAIM_FLAG_ON_LOSS indicates that frames are reclaimed
    because of the packet loss.*/
-#define NGTCP2_RECLAIM_FLAG_ON_LOSS 0x01u
+#define NGTCP2_RECLAIM_FLAG_ON_LOSS 0x01U
 
 /*
  * rtb_reclaim_frame copies and queues frames included in |ent| for
@@ -231,7 +233,7 @@ static ngtcp2_ssize rtb_reclaim_frame(ng
       continue;
     }
 
-    switch (frc->fr.type) {
+    switch (frc->fr.hd.type) {
     case NGTCP2_FRAME_STREAM:
       strm = ngtcp2_conn_find_stream(conn, fr->stream.stream_id);
       if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM)) {
@@ -269,7 +271,12 @@ static ngtcp2_ssize rtb_reclaim_frame(ng
         return rv;
       }
 
-      nfrc->fr = *fr;
+      nfrc->fr.stream.type = fr->stream.type;
+      nfrc->fr.stream.flags = fr->stream.flags;
+      nfrc->fr.stream.fin = fr->stream.fin;
+      nfrc->fr.stream.stream_id = fr->stream.stream_id;
+      nfrc->fr.stream.offset = fr->stream.offset;
+      nfrc->fr.stream.datacnt = fr->stream.datacnt;
       ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data,
                       fr->stream.datacnt);
 
@@ -312,7 +319,12 @@ static ngtcp2_ssize rtb_reclaim_frame(ng
         return rv;
       }
 
-      nfrc->fr = *fr;
+      nfrc->fr.stream.type = fr->stream.type;
+      nfrc->fr.stream.flags = 0;
+      nfrc->fr.stream.fin = 0;
+      nfrc->fr.stream.stream_id = 0;
+      nfrc->fr.stream.offset = fr->stream.offset;
+      nfrc->fr.stream.datacnt = fr->stream.datacnt;
       ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data,
                       fr->stream.datacnt);
 
@@ -413,7 +425,7 @@ static int conn_process_lost_datagram(ng
   int rv;
 
   for (frc = ent->frc; frc; frc = frc->next) {
-    switch (frc->fr.type) {
+    switch (frc->fr.hd.type) {
     case NGTCP2_FRAME_DATAGRAM:
     case NGTCP2_FRAME_DATAGRAM_LEN:
       assert(conn->callbacks.lost_datagram);
@@ -451,19 +463,28 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *r
   if (ent->flags &
       (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
     ++rtb->num_lost_ignore_pkts;
-  } else if (rtb->cc->on_pkt_lost) {
-    cc->on_pkt_lost(cc, cstat,
-                    ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen,
-                                       pktns->id, ent->ts, ent->rst.lost,
-                                       ent->rst.tx_in_flight,
-                                       ent->rst.is_app_limited),
-                    ts);
+  } else {
+    ++cstat->pkt_lost;
+    cstat->bytes_lost += ent->pktlen;
+
+    if (ent->hd.pkt_num >= rtb->cc_pkt_num) {
+      rtb->rst->lost += ent->pktlen;
+
+      if (rtb->cc->on_pkt_lost) {
+        cc->on_pkt_lost(cc, cstat,
+                        ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen,
+                                           pktns->id, ent->ts, ent->rst.lost,
+                                           ent->rst.tx_in_flight,
+                                           ent->rst.is_app_limited),
+                        ts);
+      }
+    }
   }
 
   if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) {
-    ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
-                    "pkn=%" PRId64 " has already been reclaimed on PTO",
-                    ent->hd.pkt_num);
+    ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
+                     "pkn=%" PRId64 " has already been reclaimed on PTO",
+                     ent->hd.pkt_num);
     assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED));
     assert(UINT64_MAX == ent->lost_ts);
   } else {
@@ -520,9 +541,10 @@ static void rtb_remove(ngtcp2_rtb *rtb,
   int rv;
   (void)rv;
 
+  rtb_on_remove(rtb, ent, cstat);
+
   rv = ngtcp2_ksl_remove_hint(&rtb->ents, it, it, &ent->hd.pkt_num);
   assert(0 == rv);
-  rtb_on_remove(rtb, ent, cstat);
 
   assert(ent->next == NULL);
 
@@ -591,7 +613,7 @@ static int process_acked_pkt(ngtcp2_rtb_
       frc->binder->flags |= NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK;
     }
 
-    switch (frc->fr.type) {
+    switch (frc->fr.hd.type) {
     case NGTCP2_FRAME_STREAM:
       strm = ngtcp2_conn_find_stream(conn, frc->fr.stream.stream_id);
       if (strm == NULL) {
@@ -704,6 +726,8 @@ static void rtb_on_pkt_acked(ngtcp2_rtb
   ngtcp2_cc *cc = rtb->cc;
   ngtcp2_cc_pkt pkt;
 
+  assert(ent->hd.pkt_num >= rtb->cc_pkt_num);
+
   ngtcp2_rst_update_rate_sample(rtb->rst, ent, ts);
 
   if (cc->on_pkt_acked) {
@@ -724,8 +748,7 @@ static void rtb_on_pkt_acked(ngtcp2_rtb
 static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
                             ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                             const ngtcp2_ack *fr, size_t ecn_acked,
-                            ngtcp2_tstamp largest_pkt_sent_ts,
-                            ngtcp2_tstamp ts) {
+                            const ngtcp2_cc_ack *cc_ack, ngtcp2_tstamp ts) {
   if (conn->tx.ecn.state == NGTCP2_ECN_STATE_FAILED) {
     return;
   }
@@ -752,9 +775,9 @@ static void conn_verify_ecn(ngtcp2_conn
   }
 
   if (fr->type == NGTCP2_FRAME_ACK_ECN) {
-    if (cc->congestion_event && largest_pkt_sent_ts != UINT64_MAX &&
+    if (cc->congestion_event && cc_ack->largest_pkt_sent_ts != UINT64_MAX &&
         fr->ecn.ce > pktns->acktr.ecn.ack.ce) {
-      cc->congestion_event(cc, cstat, largest_pkt_sent_ts, 0, ts);
+      cc->congestion_event(cc, cstat, cc_ack->largest_pkt_sent_ts, cc_ack, ts);
     }
 
     pktns->acktr.ecn.ack.ect0 = fr->ecn.ect0;
@@ -763,7 +786,7 @@ static void conn_verify_ecn(ngtcp2_conn
   }
 }
 
-static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost,
+static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_cc_ack *cc_ack,
                                ngtcp2_conn *conn, ngtcp2_pktns *pktns,
                                ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts);
 
@@ -777,24 +800,23 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_
   int rv;
   ngtcp2_ksl_it it;
   size_t num_acked = 0;
-  ngtcp2_tstamp largest_pkt_sent_ts = UINT64_MAX;
   int64_t pkt_num;
   ngtcp2_cc *cc = rtb->cc;
   ngtcp2_rtb_entry *acked_ent = NULL;
   int ack_eliciting_pkt_acked = 0;
   size_t ecn_acked = 0;
   int verify_ecn = 0;
-  ngtcp2_cc_ack cc_ack = {0};
+  ngtcp2_cc_ack cc_ack = {
+    .largest_pkt_sent_ts = UINT64_MAX,
+    .rtt = UINT64_MAX,
+  };
   size_t num_lost_pkts = rtb->num_lost_pkts - rtb->num_lost_ignore_pkts;
 
-  cc_ack.prior_bytes_in_flight = cstat->bytes_in_flight;
-  cc_ack.rtt = UINT64_MAX;
-
   if (conn && (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) &&
       (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR) &&
       largest_ack >= conn->pktns.crypto.tx.ckm->pkt_num) {
-    conn->flags &= (uint32_t) ~(NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED |
-                                NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR);
+    conn->flags &= (uint32_t)~(NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED |
+                               NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR);
     conn->crypto.key_update.confirmed_ts = ts;
 
     ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_CRY, "key update confirmed");
@@ -805,12 +827,17 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_
     verify_ecn = 1;
   }
 
+  ngtcp2_rst_reset_rate_sample(rtb->rst, cstat);
+
   /* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */
   it = ngtcp2_ksl_lower_bound(&rtb->ents, &largest_ack);
   if (ngtcp2_ksl_it_end(&it)) {
     if (conn && verify_ecn) {
-      conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked,
-                      largest_pkt_sent_ts, ts);
+      conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, &cc_ack, ts);
+    }
+
+    if (cc->on_ack_recv) {
+      cc->on_ack_recv(cc, cstat, &cc_ack, ts);
     }
 
     return 0;
@@ -834,8 +861,8 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_
       goto fail;
     }
 
-    if (largest_ack == pkt_num) {
-      largest_pkt_sent_ts = ent->ts;
+    if (rtb->largest_acked_tx_pkt_num == pkt_num) {
+      cc_ack.largest_pkt_sent_ts = ent->ts;
     }
 
     if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
@@ -843,7 +870,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_
     }
 
     rtb_remove(rtb, &it, &acked_ent, ent, cstat);
-    ++num_acked;
   }
 
   for (i = 0; i < fr->rangecnt; ++i) {
@@ -873,18 +899,14 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_
       }
 
       rtb_remove(rtb, &it, &acked_ent, ent, cstat);
-      ++num_acked;
     }
   }
 
-  if (largest_pkt_sent_ts != UINT64_MAX && ack_eliciting_pkt_acked) {
-    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) {
-      cc->new_rtt_sample(cc, cstat, ts);
-    }
+  if (cc_ack.largest_pkt_sent_ts != UINT64_MAX && ack_eliciting_pkt_acked) {
+    cc_ack.rtt = ngtcp2_max_uint64(pkt_ts - cc_ack.largest_pkt_sent_ts,
+                                   NGTCP2_NANOSECONDS);
+
+    ngtcp2_conn_update_rtt(conn, cc_ack.rtt, fr->ack_delay_unscaled, ts);
   }
 
   if (conn) {
@@ -904,23 +926,22 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_
 
         cc_ack.bytes_delivered += ent->pktlen;
         cc_ack.pkt_delivered = ent->rst.delivered;
+
+        rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
+
+        ++num_acked;
       }
 
-      rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
       acked_ent = ent->next;
       ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
                                     rtb->frc_objalloc, rtb->mem);
     }
-
-    if (verify_ecn) {
-      conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked,
-                      largest_pkt_sent_ts, ts);
-    }
   } else {
     /* For unit tests */
     for (ent = acked_ent; ent; ent = acked_ent) {
       rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
       acked_ent = ent->next;
+      ++num_acked;
       ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
                                     rtb->frc_objalloc, rtb->mem);
     }
@@ -935,17 +956,18 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_
     ngtcp2_rst_on_ack_recv(rtb->rst, cstat);
 
     if (conn) {
-      rv = rtb_detect_lost_pkt(rtb, &cc_ack.bytes_lost, conn, pktns, cstat, ts);
+      rv = rtb_detect_lost_pkt(rtb, &cc_ack, conn, pktns, cstat, ts);
       if (rv != 0) {
         return rv;
       }
     }
   }
 
-  rtb->rst->lost += cc_ack.bytes_lost;
+  if (conn && verify_ecn) {
+    conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, &cc_ack, ts);
+  }
 
-  cc_ack.largest_pkt_sent_ts = largest_pkt_sent_ts;
-  if (num_acked && cc->on_ack_recv) {
+  if (cc->on_ack_recv) {
     cc->on_ack_recv(cc, cstat, &cc_ack, ts);
   }
 
@@ -1011,7 +1033,11 @@ static int conn_all_ecn_pkt_lost(ngtcp2_
          pktns->tx.ecn.validation_pkt_sent == pktns->tx.ecn.validation_pkt_lost;
 }
 
-static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost,
+/*
+ * This function assigns the number of bytes lost to
+ * |cc_ack|->bytes_lost if any.
+ */
+static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_cc_ack *cc_ack,
                                ngtcp2_conn *conn, ngtcp2_pktns *pktns,
                                ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) {
   ngtcp2_rtb_entry *ent;
@@ -1129,8 +1155,10 @@ static int rtb_detect_lost_pkt(ngtcp2_rt
         break;
       }
 
+      cc_ack->bytes_lost = bytes_lost;
+
       if (cc->congestion_event) {
-        cc->congestion_event(cc, cstat, latest_ts, bytes_lost, ts);
+        cc->congestion_event(cc, cstat, latest_ts, cc_ack, ts);
       }
 
       loss_window = latest_ts - oldest_ts;
@@ -1143,10 +1171,10 @@ static int rtb_detect_lost_pkt(ngtcp2_rt
        */
       if (pktns->id == NGTCP2_PKTNS_ID_APPLICATION && loss_window &&
           loss_window >= congestion_period) {
-        ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
-                        "persistent congestion loss_window=%" PRIu64
-                        " congestion_period=%" PRIu64,
-                        loss_window, congestion_period);
+        ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
+                         "persistent congestion loss_window=%" PRIu64
+                         " congestion_period=%" PRIu64,
+                         loss_window, congestion_period);
 
         /* Reset min_rtt, srtt, and rttvar here.  Next new RTT
            sample will be used to recalculate these values. */
@@ -1166,18 +1194,18 @@ static int rtb_detect_lost_pkt(ngtcp2_rt
 
   ngtcp2_rtb_remove_excessive_lost_pkt(rtb, (size_t)pkt_thres);
 
-  if (ppkt_lost) {
-    *ppkt_lost = bytes_lost;
-  }
-
   return 0;
 }
 
 int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
                                ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat,
                                ngtcp2_tstamp ts) {
-  return rtb_detect_lost_pkt(rtb, /* ppkt_lost = */ NULL, conn, pktns, cstat,
-                             ts);
+  return rtb_detect_lost_pkt(rtb,
+                             &(ngtcp2_cc_ack){
+                               .largest_pkt_sent_ts = UINT64_MAX,
+                               .rtt = UINT64_MAX,
+                             },
+                             conn, pktns, cstat, ts);
 }
 
 void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) {
@@ -1193,8 +1221,8 @@ void ngtcp2_rtb_remove_excessive_lost_pk
 
     assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED);
 
-    ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
-                    "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
+    ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
+                     "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
 
     --rtb->num_lost_pkts;
 
@@ -1230,13 +1258,14 @@ void ngtcp2_rtb_remove_expired_lost_pkt(
     ngtcp2_ksl_it_prev(&it);
     ent = ngtcp2_ksl_it_get(&it);
 
-    if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED) ||
-        ts - ent->lost_ts < timeout) {
+    assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED);
+
+    if (ts - ent->lost_ts < timeout) {
       return;
     }
 
-    ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
-                    "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
+    ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
+                     "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
 
     --rtb->num_lost_pkts;
 
@@ -1280,7 +1309,7 @@ static int rtb_reclaim_frame_on_retry(ng
   int rv;
 
   for (; *pfrc;) {
-    switch ((*pfrc)->fr.type) {
+    switch ((*pfrc)->fr.hd.type) {
     case NGTCP2_FRAME_STREAM:
       frc = *pfrc;
 
@@ -1388,15 +1417,22 @@ int ngtcp2_rtb_reclaim_on_retry(ngtcp2_r
     assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE));
 
     if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) {
-      ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
-                      "pkn=%" PRId64 " has already been reclaimed on PTO",
-                      ent->hd.pkt_num);
+      ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
+                       "pkn=%" PRId64 " has already been reclaimed on PTO",
+                       ent->hd.pkt_num);
+
+      ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
+                                    rtb->frc_objalloc, rtb->mem);
+
       continue;
     }
 
     if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) &&
         (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_DATAGRAM) ||
          !conn->callbacks.lost_datagram)) {
+      ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
+                                    rtb->frc_objalloc, rtb->mem);
+
       continue;
     }
 
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rtb.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rtb.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_rtb.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_rtb.h	2026-05-15 15:49:15.167978500 +0200
@@ -48,41 +48,41 @@ typedef struct ngtcp2_conn_stat ngtcp2_c
 typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
 
 /* NGTCP2_RTB_ENTRY_FLAG_NONE indicates that no flag is set. */
-#define NGTCP2_RTB_ENTRY_FLAG_NONE 0x00u
+#define NGTCP2_RTB_ENTRY_FLAG_NONE 0x00U
 /* NGTCP2_RTB_ENTRY_FLAG_PROBE indicates that the entry includes a
    probe packet. */
-#define NGTCP2_RTB_ENTRY_FLAG_PROBE 0x01u
+#define NGTCP2_RTB_ENTRY_FLAG_PROBE 0x01U
 /* NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE indicates that the entry
    includes a frame which must be retransmitted until it is
    acknowledged.  In most cases, this flag is used along with
    NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING and
    NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING. */
-#define NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE 0x02u
+#define NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE 0x02U
 /* NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING indicates that the entry
    elicits acknowledgement. */
-#define NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING 0x04u
+#define NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING 0x04U
 /* NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED indicates that the packet has
    been reclaimed on PTO.  It is not marked lost yet and still
    consumes congestion window. */
-#define NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED 0x08u
+#define NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED 0x08U
 /* NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED indicates that the entry
    has been marked lost and, optionally, scheduled to retransmit. */
-#define NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED 0x10u
+#define NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED 0x10U
 /* NGTCP2_RTB_ENTRY_FLAG_ECN indicates that the entry is included in a
    UDP datagram with ECN marking. */
-#define NGTCP2_RTB_ENTRY_FLAG_ECN 0x20u
+#define NGTCP2_RTB_ENTRY_FLAG_ECN 0x20U
 /* NGTCP2_RTB_ENTRY_FLAG_DATAGRAM indicates that the entry includes
    DATAGRAM frame. */
-#define NGTCP2_RTB_ENTRY_FLAG_DATAGRAM 0x40u
+#define NGTCP2_RTB_ENTRY_FLAG_DATAGRAM 0x40U
 /* NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE indicates that the entry includes
    a PMTUD probe packet. */
-#define NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE 0x80u
+#define NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE 0x80U
 /* NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING indicates that the entry
    includes a packet which elicits PTO probe packets. */
-#define NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING 0x100u
+#define NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING 0x100U
 /* NGTCP2_RTB_ENTRY_FLAG_SKIP indicates that the entry has the skipped
    packet number. */
-#define NGTCP2_RTB_ENTRY_FLAG_SKIP 0x200u
+#define NGTCP2_RTB_ENTRY_FLAG_SKIP 0x200U
 
 typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry;
 
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_settings.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_settings.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_settings.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_settings.c	2026-05-15 15:49:15.167978500 +0200
@@ -37,6 +37,10 @@ void ngtcp2_settings_default_versioned(i
 
   switch (settings_version) {
   case NGTCP2_SETTINGS_VERSION:
+    settings->glitch_ratelim_burst = NGTCP2_DEFAULT_GLITCH_RATELIM_BURST;
+    settings->glitch_ratelim_rate = NGTCP2_DEFAULT_GLITCH_RATELIM_RATE;
+    /* fall through */
+  case NGTCP2_SETTINGS_V2:
   case NGTCP2_SETTINGS_V1:
     settings->cc_algo = NGTCP2_CC_ALGO_CUBIC;
     settings->initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT;
@@ -82,6 +86,9 @@ size_t ngtcp2_settingslen_version(int se
   switch (settings_version) {
   case NGTCP2_SETTINGS_VERSION:
     return sizeof(settings);
+  case NGTCP2_SETTINGS_V2:
+    return offsetof(ngtcp2_settings, pmtud_probeslen) +
+           sizeof(settings.pmtud_probeslen);
   case NGTCP2_SETTINGS_V1:
     return offsetof(ngtcp2_settings, initial_pkt_num) +
            sizeof(settings.initial_pkt_num);
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_settings.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_settings.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_settings.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_settings.h	2026-05-15 15:49:15.167978500 +0200
@@ -31,6 +31,13 @@
 
 #include <ngtcp2/ngtcp2.h>
 
+/* NGTCP2_DEFAULT_GLITCH_RATELIM_BURST is the maximum number of tokens
+   in glitch rate limiter.  It is also the initial value. */
+#define NGTCP2_DEFAULT_GLITCH_RATELIM_BURST 10000
+/* NGTCP2_DEFAULT_GLITCH_RATELIM_RATE is the rate of tokens generated
+   per second for glitch rate limiter. */
+#define NGTCP2_DEFAULT_GLITCH_RATELIM_RATE 330
+
 /*
  * ngtcp2_settings_convert_to_latest converts |src| of version
  * |settings_version| to the latest version NGTCP2_SETTINGS_VERSION.
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_str.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_str.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_str.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_str.c	2026-05-15 15:49:15.167978500 +0200
@@ -47,27 +47,32 @@ const void *ngtcp2_get_bytes(void *dest,
 
 uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len) {
   size_t i;
-  uint8_t *p = dest;
 
   for (i = 0; i < len; ++i) {
-    *p++ = (uint8_t)LOWER_XDIGITS[data[i] >> 4];
-    *p++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xf];
+    *dest++ = (uint8_t)LOWER_XDIGITS[data[i] >> 4];
+    *dest++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xF];
   }
 
+  return dest;
+}
+
+char *ngtcp2_encode_hex_cstr(char *dest, const uint8_t *data, size_t len) {
+  uint8_t *p = ngtcp2_encode_hex((uint8_t *)dest, data, len);
+
   *p = '\0';
 
   return dest;
 }
 
-char *ngtcp2_encode_printable_ascii(char *dest, const uint8_t *data,
-                                    size_t len) {
+char *ngtcp2_encode_printable_ascii_cstr(char *dest, const uint8_t *data,
+                                         size_t len) {
   size_t i;
   char *p = dest;
   uint8_t c;
 
   for (i = 0; i < len; ++i) {
     c = data[i];
-    if (0x20 <= c && c <= 0x7e) {
+    if (0x20 <= c && c <= 0x7E) {
       *p++ = (char)c;
     } else {
       *p++ = '.';
@@ -79,40 +84,15 @@ char *ngtcp2_encode_printable_ascii(char
   return dest;
 }
 
-/*
- * write_uint writes |n| to the buffer pointed by |p| in decimal
- * representation.  It returns |p| plus the number of bytes written.
- * The function assumes that the buffer has enough capacity to contain
- * a string.
- */
-static uint8_t *write_uint(uint8_t *p, uint64_t n) {
-  size_t nlen = 0;
-  uint64_t t;
-  uint8_t *res;
-
-  if (n == 0) {
-    *p++ = '0';
-    return p;
-  }
-  for (t = n; t; t /= 10, ++nlen)
-    ;
-  p += nlen;
-  res = p;
-  for (; n; n /= 10) {
-    *--p = (uint8_t)((n % 10) + '0');
-  }
-  return res;
-}
-
-uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const uint8_t *addr) {
+char *ngtcp2_encode_ipv4_cstr(char *dest, const uint8_t *addr) {
   size_t i;
-  uint8_t *p = dest;
+  char *p = dest;
 
-  p = write_uint(p, addr[0]);
+  p = (char *)ngtcp2_encode_uint((uint8_t *)p, addr[0]);
 
   for (i = 1; i < 4; ++i) {
     *p++ = '.';
-    p = write_uint(p, addr[i]);
+    p = (char *)ngtcp2_encode_uint((uint8_t *)p, addr[i]);
   }
 
   *p = '\0';
@@ -125,9 +105,9 @@ uint8_t *ngtcp2_encode_ipv4(uint8_t *des
  * length |len| to |dest| in hex string.  Any leading zeros are
  * suppressed.  It returns |dest| plus the number of bytes written.
  */
-static uint8_t *write_hex_zsup(uint8_t *dest, const uint8_t *data, size_t len) {
+static char *write_hex_zsup(char *dest, const uint8_t *data, size_t len) {
   size_t i;
-  uint8_t *p = dest;
+  char *p = dest;
   uint8_t d;
 
   for (i = 0; i < len; ++i) {
@@ -136,10 +116,10 @@ static uint8_t *write_hex_zsup(uint8_t *
       break;
     }
 
-    d &= 0xf;
+    d &= 0xF;
 
     if (d) {
-      *p++ = (uint8_t)LOWER_XDIGITS[d];
+      *p++ = LOWER_XDIGITS[d];
       ++i;
       break;
     }
@@ -152,19 +132,19 @@ static uint8_t *write_hex_zsup(uint8_t *
 
   for (; i < len; ++i) {
     d = data[i];
-    *p++ = (uint8_t)LOWER_XDIGITS[d >> 4];
-    *p++ = (uint8_t)LOWER_XDIGITS[d & 0xf];
+    *p++ = LOWER_XDIGITS[d >> 4];
+    *p++ = LOWER_XDIGITS[d & 0xF];
   }
 
   return p;
 }
 
-uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const uint8_t *addr) {
+char *ngtcp2_encode_ipv6_cstr(char *dest, const uint8_t *addr) {
   uint16_t blks[8];
   size_t i;
   size_t zlen, zoff;
   size_t max_zlen = 0, max_zoff = 8;
-  uint8_t *p = dest;
+  char *p = dest;
 
   for (i = 0; i < 16; i += sizeof(uint16_t)) {
     /* Copy in network byte order. */
@@ -231,3 +211,124 @@ int ngtcp2_cmemeq(const uint8_t *a, cons
 
   return rv == 0;
 }
+
+/* countl_zero counts the number of leading zeros in |x|.  It is
+   undefined if |x| is 0. */
+static int countl_zero(uint64_t x) {
+#ifdef __GNUC__
+  return __builtin_clzll(x);
+#else  /* !defined(__GNUC__) */
+  /* This is the same implementation of Go's LeadingZeros64 in
+     math/bits package. */
+  static const uint8_t len8tab[] = {
+    0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+  };
+  int n = 0;
+
+  if (x >= 1ULL << 32) {
+    x >>= 32;
+    n += 32;
+  }
+
+  if (x >= 1 << 16) {
+    x >>= 16;
+    n += 16;
+  }
+
+  if (x >= 1 << 8) {
+    x >>= 8;
+    n += 8;
+  }
+
+  return 64 - (n + len8tab[x]);
+#endif /* !defined(__GNUC__) */
+}
+
+/*
+ * count_digit returns the minimum number of digits to represent |x|
+ * in base 10.
+ *
+ * credit:
+ * https://lemire.me/blog/2025/01/07/counting-the-digits-of-64-bit-integers/
+ */
+static size_t count_digit(uint64_t x) {
+  static const uint64_t count_digit_tbl[] = {
+    9ULL,
+    99ULL,
+    999ULL,
+    9999ULL,
+    99999ULL,
+    999999ULL,
+    9999999ULL,
+    99999999ULL,
+    999999999ULL,
+    9999999999ULL,
+    99999999999ULL,
+    999999999999ULL,
+    9999999999999ULL,
+    99999999999999ULL,
+    999999999999999ULL,
+    9999999999999999ULL,
+    99999999999999999ULL,
+    999999999999999999ULL,
+    9999999999999999999ULL,
+  };
+  size_t y = (size_t)(19 * (63 - countl_zero(x | 1)) >> 6);
+
+  y += x > count_digit_tbl[y];
+
+  return y + 1;
+}
+
+uint8_t *ngtcp2_encode_uint(uint8_t *dest, uint64_t n) {
+  static const uint8_t uint_digits[] =
+    "00010203040506070809101112131415161718192021222324252627282930313233343536"
+    "37383940414243444546474849505152535455565758596061626364656667686970717273"
+    "7475767778798081828384858687888990919293949596979899";
+  uint8_t *p;
+  const uint8_t *tp;
+
+  if (n < 10) {
+    *dest++ = (uint8_t)('0' + n);
+    return dest;
+  }
+
+  if (n < 100) {
+    tp = &uint_digits[n * 2];
+    *dest++ = *tp++;
+    *dest++ = *tp;
+    return dest;
+  }
+
+  dest += count_digit(n);
+  p = dest;
+
+  for (; n >= 100; n /= 100) {
+    p -= 2;
+    tp = &uint_digits[(n % 100) * 2];
+    p[0] = *tp++;
+    p[1] = *tp;
+  }
+
+  if (n < 10) {
+    *--p = (uint8_t)('0' + n);
+    return dest;
+  }
+
+  p -= 2;
+  tp = &uint_digits[n * 2];
+  p[0] = *tp++;
+  p[1] = *tp;
+
+  return dest;
+}
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_str.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_str.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_str.h	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_str.h	2026-05-15 15:49:15.167978500 +0200
@@ -46,24 +46,31 @@ uint8_t *ngtcp2_setmem(uint8_t *dest, ui
 const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n);
 
 /*
- * ngtcp2_encode_hex encodes |data| of length |len| in hex string.  It
- * writes additional NULL bytes at the end of the buffer.  The buffer
- * pointed by |dest| must have at least |len| * 2 + 1 bytes space.
- * This function returns |dest|.
+ * ngtcp2_encode_hex encodes |data| of length |len| in hex string.
+ * The buffer pointed by |dest| must have at least |len| * 2 bytes
+ * space.  This function returns |dest| + |len| * 2.
  */
 uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len);
 
 /*
- * ngtcp2_encode_ipv4 encodes binary form IPv4 address stored in
+ * ngtcp2_encode_hex_cstr encodes |data| of length |len| in hex
+ * string.  It writes additional NULL bytes at the end of the buffer.
+ * The buffer pointed by |dest| must have at least |len| * 2 + 1 bytes
+ * space.  This function returns |dest|.
+ */
+char *ngtcp2_encode_hex_cstr(char *dest, const uint8_t *data, size_t len);
+
+/*
+ * ngtcp2_encode_ipv4_cstr encodes binary form IPv4 address stored in
  * |addr| to human readable text form in the buffer pointed by |dest|.
  * The capacity of buffer must have enough length to store a text form
  * plus a terminating NULL byte.  The resulting text form ends with
  * NULL byte.  The function returns |dest|.
  */
-uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const uint8_t *addr);
+char *ngtcp2_encode_ipv4_cstr(char *dest, const uint8_t *addr);
 
 /*
- * ngtcp2_encode_ipv6 encodes binary form IPv6 address stored in
+ * ngtcp2_encode_ipv6_cstr encodes binary form IPv6 address stored in
  * |addr| to human readable text form in the buffer pointed by |dest|.
  * The capacity of buffer must have enough length to store a text form
  * plus a terminating NULL byte.  The resulting text form ends with
@@ -72,7 +79,7 @@ uint8_t *ngtcp2_encode_ipv4(uint8_t *des
  * https://tools.ietf.org/html/rfc5952#section-4.  The function
  * returns |dest|.
  */
-uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const uint8_t *addr);
+char *ngtcp2_encode_ipv6_cstr(char *dest, const uint8_t *addr);
 
 /*
  * ngtcp2_encode_printable_ascii encodes |data| of length |len| in
@@ -81,8 +88,8 @@ uint8_t *ngtcp2_encode_ipv6(uint8_t *des
  * writes additional NULL bytes at the end of the buffer.  |dest| must
  * have at least |len| + 1 bytes.  This function returns |dest|.
  */
-char *ngtcp2_encode_printable_ascii(char *dest, const uint8_t *data,
-                                    size_t len);
+char *ngtcp2_encode_printable_ascii_cstr(char *dest, const uint8_t *data,
+                                         size_t len);
 
 /*
  * ngtcp2_cmemeq returns nonzero if the first |n| bytes of the buffers
@@ -91,4 +98,12 @@ char *ngtcp2_encode_printable_ascii(char
  */
 int ngtcp2_cmemeq(const uint8_t *a, const uint8_t *b, size_t n);
 
+/*
+ * ngtcp2_encode_uint encodes |n| as a decimal integer to the buffer
+ * pointed by |dest|.  This function assumes that the buffer contains
+ * the sufficient capacity to write the number.  This function returns
+ * the pointer to the buffer past the last byte written.
+ */
+uint8_t *ngtcp2_encode_uint(uint8_t *dest, uint64_t n);
+
 #endif /* !defined(NGTCP2_STR_H) */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_strm.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_strm.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_strm.c	2026-01-23 11:53:43.293757700 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_strm.c	2026-05-15 15:49:15.168978500 +0200
@@ -36,30 +36,27 @@ void ngtcp2_strm_init(ngtcp2_strm *strm,
                       uint64_t max_rx_offset, uint64_t max_tx_offset,
                       void *stream_user_data, ngtcp2_objalloc *frc_objalloc,
                       const ngtcp2_mem *mem) {
-  strm->pe.index = NGTCP2_PQ_BAD_INDEX;
-  strm->cycle = 0;
-  strm->frc_objalloc = frc_objalloc;
-  strm->tx.acked_offset = NULL;
-  strm->tx.cont_acked_offset = 0;
-  strm->tx.streamfrq = NULL;
-  strm->tx.offset = 0;
-  strm->tx.max_offset = max_tx_offset;
-  strm->tx.last_blocked_offset = UINT64_MAX;
-  strm->tx.last_max_stream_data_ts = UINT64_MAX;
-  strm->tx.loss_count = 0;
-  strm->tx.last_lost_pkt_num = -1;
-  strm->tx.stop_sending_app_error_code = 0;
-  strm->tx.reset_stream_app_error_code = 0;
-  strm->rx.rob = NULL;
-  strm->rx.cont_offset = 0;
-  strm->rx.last_offset = 0;
-  strm->rx.max_offset = strm->rx.unsent_max_offset = strm->rx.window =
-    max_rx_offset;
-  strm->mem = mem;
-  strm->stream_id = stream_id;
-  strm->stream_user_data = stream_user_data;
-  strm->flags = flags;
-  strm->app_error_code = 0;
+  *strm = (ngtcp2_strm){
+    .pe.index = NGTCP2_PQ_BAD_INDEX,
+    .frc_objalloc = frc_objalloc,
+    .tx =
+      {
+        .max_offset = max_tx_offset,
+        .last_blocked_offset = UINT64_MAX,
+        .last_max_stream_data_ts = UINT64_MAX,
+        .last_lost_pkt_num = -1,
+      },
+    .rx =
+      {
+        .max_offset = max_rx_offset,
+        .unsent_max_offset = max_rx_offset,
+        .window = max_rx_offset,
+      },
+    .mem = mem,
+    .stream_id = stream_id,
+    .stream_user_data = stream_user_data,
+    .flags = flags,
+  };
 }
 
 void ngtcp2_strm_free(ngtcp2_strm *strm) {
@@ -120,12 +117,13 @@ uint64_t ngtcp2_strm_rx_offset(const ngt
 /* strm_rob_heavily_fragmented returns nonzero if the number of gaps
    in |rob| exceeds the limit. */
 static int strm_rob_heavily_fragmented(const ngtcp2_rob *rob) {
-  return ngtcp2_ksl_len(&rob->gapksl) >= 5000;
+  return ngtcp2_ksl_len(&rob->gapksl) >= 4000;
 }
 
-int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
-                                size_t datalen, uint64_t offset) {
+ngtcp2_ssize ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
+                                         size_t datalen, uint64_t offset) {
   int rv;
+  ngtcp2_ssize nwrite;
 
   if (strm->rx.rob == NULL) {
     rv = strm_rob_init(strm);
@@ -138,11 +136,16 @@ int ngtcp2_strm_recv_reordering(ngtcp2_s
     }
   }
 
+  nwrite = ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
+  if (nwrite < 0) {
+    return nwrite;
+  }
+
   if (strm_rob_heavily_fragmented(strm->rx.rob)) {
     return NGTCP2_ERR_INTERNAL;
   }
 
-  return ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
+  return nwrite;
 }
 
 void ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) {
@@ -187,8 +190,8 @@ static int strm_streamfrq_init(ngtcp2_st
 int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) {
   int rv;
 
-  assert(frc->fr.type == NGTCP2_FRAME_STREAM ||
-         frc->fr.type == NGTCP2_FRAME_CRYPTO);
+  assert(frc->fr.hd.type == NGTCP2_FRAME_STREAM ||
+         frc->fr.hd.type == NGTCP2_FRAME_CRYPTO);
   assert(frc->next == NULL);
 
   if (strm->tx.streamfrq == NULL) {
@@ -196,6 +199,8 @@ int ngtcp2_strm_streamfrq_push(ngtcp2_st
     if (rv != 0) {
       return rv;
     }
+  } else if (ngtcp2_ksl_len(strm->tx.streamfrq) >= 8000) {
+    return NGTCP2_ERR_INTERNAL;
   }
 
   return ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &frc->fr.stream.offset,
@@ -300,8 +305,7 @@ static int strm_streamfrq_unacked_pop(ng
 
       fr->offset = offset + base_offset;
       fr->datacnt = end_idx - idx;
-      fr->data[0].base += base_offset;
-      fr->data[0].len -= (size_t)base_offset;
+      ngtcp2_vec_drop(&fr->data[0], (size_t)base_offset);
 
       *pfrc = frc;
 
@@ -327,8 +331,7 @@ static int strm_streamfrq_unacked_pop(ng
     nfr->stream_id = fr->stream_id;
     nfr->offset = end_offset + end_base_offset;
     nfr->datacnt = fr->datacnt - end_idx;
-    nfr->data[0].base += end_base_offset;
-    nfr->data[0].len -= (size_t)end_base_offset;
+    ngtcp2_vec_drop(&nfr->data[0], (size_t)end_base_offset);
 
     rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
     if (rv != 0) {
@@ -356,8 +359,7 @@ static int strm_streamfrq_unacked_pop(ng
       fr->data[fr->datacnt - 1].len = (size_t)end_base_offset;
     }
 
-    fr->data[0].base += base_offset;
-    fr->data[0].len -= (size_t)base_offset;
+    ngtcp2_vec_drop(&fr->data[0], (size_t)base_offset);
 
     *pfrc = frc;
 
@@ -370,13 +372,12 @@ static int strm_streamfrq_unacked_pop(ng
 int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
                               size_t left) {
   ngtcp2_stream *fr, *nfr;
-  ngtcp2_frame_chain *frc, *nfrc, *sfrc;
+  ngtcp2_frame_chain *frc, *nfrc;
   int rv;
   size_t nmerged;
   uint64_t datalen;
-  ngtcp2_vec a[NGTCP2_MAX_STREAM_DATACNT];
-  ngtcp2_vec b[NGTCP2_MAX_STREAM_DATACNT];
-  size_t acnt, bcnt;
+  ngtcp2_vec data[NGTCP2_MAX_STREAM_DATACNT];
+  size_t datacnt;
   uint64_t unacked_offset;
 
   if (strm->tx.streamfrq == NULL || ngtcp2_ksl_len(strm->tx.streamfrq) == 0) {
@@ -398,7 +399,11 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_str
   datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
 
   /* datalen could be zero if 0 length STREAM has been sent */
-  if (left == 0 && datalen) {
+  /* We might see more data in the queue, then left < datalen could be
+     true.  We only see the first one for now. */
+  if ((fr->type == NGTCP2_FRAME_STREAM &&
+       (left < datalen && left < NGTCP2_MIN_STREAM_DATALEN)) ||
+      (left == 0 && datalen)) {
     rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc);
     if (rv != 0) {
       assert(ngtcp2_err_is_fatal(rv));
@@ -412,17 +417,15 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_str
   }
 
   if (datalen > left) {
-    ngtcp2_vec_copy(a, fr->data, fr->datacnt);
-    acnt = fr->datacnt;
-
-    bcnt = 0;
-    ngtcp2_vec_split(b, &bcnt, a, &acnt, left, NGTCP2_MAX_STREAM_DATACNT);
+    datacnt = 0;
+    ngtcp2_vec_split(data, &datacnt, fr->data, &fr->datacnt, left,
+                     NGTCP2_MAX_STREAM_DATACNT);
 
-    assert(acnt > 0);
-    assert(bcnt > 0);
+    assert(fr->datacnt > 0);
+    assert(datacnt > 0);
 
     rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
-      &nfrc, bcnt, strm->frc_objalloc, strm->mem);
+      &nfrc, datacnt, strm->frc_objalloc, strm->mem);
     if (rv != 0) {
       assert(ngtcp2_err_is_fatal(rv));
       ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
@@ -435,8 +438,8 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_str
     nfr->fin = fr->fin;
     nfr->stream_id = fr->stream_id;
     nfr->offset = fr->offset + left;
-    nfr->datacnt = bcnt;
-    ngtcp2_vec_copy(nfr->data, b, bcnt);
+    nfr->datacnt = datacnt;
+    ngtcp2_vec_copy(nfr->data, data, datacnt);
 
     rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
     if (rv != 0) {
@@ -447,31 +450,17 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_str
       return rv;
     }
 
-    rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
-      &nfrc, acnt, strm->frc_objalloc, strm->mem);
-    if (rv != 0) {
-      assert(ngtcp2_err_is_fatal(rv));
-      ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
-      return rv;
-    }
-
-    nfr = &nfrc->fr.stream;
-    *nfr = *fr;
-    nfr->fin = 0;
-    nfr->datacnt = acnt;
-    ngtcp2_vec_copy(nfr->data, a, acnt);
-
-    ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
+    fr->fin = 0;
 
-    *pfrc = nfrc;
+    *pfrc = frc;
 
     return 0;
   }
 
   left -= (size_t)datalen;
 
-  ngtcp2_vec_copy(a, fr->data, fr->datacnt);
-  acnt = fr->datacnt;
+  ngtcp2_vec_copy(data, fr->data, fr->datacnt);
+  datacnt = fr->datacnt;
 
   for (; left && ngtcp2_ksl_len(strm->tx.streamfrq);) {
     unacked_offset = ngtcp2_strm_streamfrq_unacked_offset(strm);
@@ -498,9 +487,7 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_str
       break;
     }
 
-    bcnt = nfr->datacnt;
-
-    nmerged = ngtcp2_vec_merge(a, &acnt, nfr->data, &bcnt, left,
+    nmerged = ngtcp2_vec_merge(data, &datacnt, nfr->data, &nfr->datacnt, left,
                                NGTCP2_MAX_STREAM_DATACNT);
     if (nmerged == 0) {
       rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
@@ -518,54 +505,27 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_str
     datalen += nmerged;
     left -= nmerged;
 
-    if (bcnt == 0) {
+    if (nfr->datacnt == 0) {
       fr->fin = nfr->fin;
       ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
       continue;
     }
 
-    if (nfr->datacnt <= NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES ||
-        bcnt > NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES) {
-      nfr->offset += nmerged;
-      nfr->datacnt = bcnt;
-
-      rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
-      if (rv != 0) {
-        ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
-        ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
-        return rv;
-      }
-    } else {
-      rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
-        &sfrc, bcnt, strm->frc_objalloc, strm->mem);
-      if (rv != 0) {
-        ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
-        ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
-        return rv;
-      }
-
-      sfrc->fr.stream = nfrc->fr.stream;
-      sfrc->fr.stream.offset += nmerged;
-      sfrc->fr.stream.datacnt = bcnt;
-      ngtcp2_vec_copy(sfrc->fr.stream.data, nfrc->fr.stream.data, bcnt);
+    nfr->offset += nmerged;
 
+    rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
+    if (rv != 0) {
       ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
-
-      rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &sfrc->fr.stream.offset,
-                             sfrc);
-      if (rv != 0) {
-        ngtcp2_frame_chain_objalloc_del(sfrc, strm->frc_objalloc, strm->mem);
-        ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
-        return rv;
-      }
+      ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
+      return rv;
     }
 
     break;
   }
 
-  if (acnt == fr->datacnt) {
-    if (acnt > 0) {
-      fr->data[acnt - 1] = a[acnt - 1];
+  if (datacnt == fr->datacnt) {
+    if (datacnt > 0) {
+      fr->data[datacnt - 1] = data[datacnt - 1];
     }
 
     *pfrc = frc;
@@ -573,19 +533,23 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_str
     return 0;
   }
 
-  assert(acnt > fr->datacnt);
+  assert(datacnt > fr->datacnt);
 
   rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
-    &nfrc, acnt, strm->frc_objalloc, strm->mem);
+    &nfrc, datacnt, strm->frc_objalloc, strm->mem);
   if (rv != 0) {
     ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
     return rv;
   }
 
   nfr = &nfrc->fr.stream;
-  *nfr = *fr;
-  nfr->datacnt = acnt;
-  ngtcp2_vec_copy(nfr->data, a, acnt);
+  nfr->type = fr->type;
+  nfr->flags = fr->flags;
+  nfr->fin = fr->fin;
+  nfr->stream_id = fr->stream_id;
+  nfr->offset = fr->offset;
+  nfr->datacnt = datacnt;
+  ngtcp2_vec_copy(nfr->data, data, datacnt);
 
   ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
 
@@ -682,12 +646,11 @@ int ngtcp2_strm_is_all_tx_data_fin_acked
 
 ngtcp2_range ngtcp2_strm_get_unacked_range_after(const ngtcp2_strm *strm,
                                                  uint64_t offset) {
-  ngtcp2_range gap;
-
   if (strm->tx.acked_offset == NULL) {
-    gap.begin = strm->tx.cont_acked_offset;
-    gap.end = UINT64_MAX;
-    return gap;
+    return (ngtcp2_range){
+      .begin = strm->tx.cont_acked_offset,
+      .end = UINT64_MAX,
+    };
   }
 
   return ngtcp2_gaptr_get_first_gap_after(strm->tx.acked_offset, offset);
@@ -737,7 +700,16 @@ int ngtcp2_strm_ack_data(ngtcp2_strm *st
     }
   }
 
-  return ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
+  rv = ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
+  if (rv != 0) {
+    return rv;
+  }
+
+  if (ngtcp2_ksl_len(&strm->tx.acked_offset->gap) >= 4000) {
+    return NGTCP2_ERR_INTERNAL;
+  }
+
+  return 0;
 }
 
 void ngtcp2_strm_set_app_error_code(ngtcp2_strm *strm,
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_strm.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_strm.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_strm.h	2026-01-23 11:53:43.297758600 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_strm.h	2026-05-15 15:49:15.168978500 +0200
@@ -41,54 +41,54 @@
 typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
 
 /* NGTCP2_STRM_FLAG_NONE indicates that no flag is set. */
-#define NGTCP2_STRM_FLAG_NONE 0x00u
+#define NGTCP2_STRM_FLAG_NONE 0x00U
 /* NGTCP2_STRM_FLAG_SHUT_RD indicates that further reception of stream
    data is not allowed. */
-#define NGTCP2_STRM_FLAG_SHUT_RD 0x01u
+#define NGTCP2_STRM_FLAG_SHUT_RD 0x01U
 /* NGTCP2_STRM_FLAG_SHUT_WR indicates that further transmission of
    stream data is not allowed. */
-#define NGTCP2_STRM_FLAG_SHUT_WR 0x02u
+#define NGTCP2_STRM_FLAG_SHUT_WR 0x02U
 #define NGTCP2_STRM_FLAG_SHUT_RDWR                                             \
   (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_SHUT_WR)
 /* NGTCP2_STRM_FLAG_RESET_STREAM indicates that RESET_STREAM is sent
    from the local endpoint.  In this case, NGTCP2_STRM_FLAG_SHUT_WR is
    also set. */
-#define NGTCP2_STRM_FLAG_RESET_STREAM 0x04u
+#define NGTCP2_STRM_FLAG_RESET_STREAM 0x04U
 /* NGTCP2_STRM_FLAG_RESET_STREAM_RECVED indicates that RESET_STREAM is
    received from the remote endpoint.  In this case,
    NGTCP2_STRM_FLAG_SHUT_RD is also set. */
-#define NGTCP2_STRM_FLAG_RESET_STREAM_RECVED 0x08u
+#define NGTCP2_STRM_FLAG_RESET_STREAM_RECVED 0x08U
 /* NGTCP2_STRM_FLAG_STOP_SENDING indicates that STOP_SENDING is sent
    from the local endpoint. */
-#define NGTCP2_STRM_FLAG_STOP_SENDING 0x10u
+#define NGTCP2_STRM_FLAG_STOP_SENDING 0x10U
 /* NGTCP2_STRM_FLAG_RESET_STREAM_ACKED indicates that the outgoing
    RESET_STREAM is acknowledged by peer. */
-#define NGTCP2_STRM_FLAG_RESET_STREAM_ACKED 0x20u
+#define NGTCP2_STRM_FLAG_RESET_STREAM_ACKED 0x20U
 /* NGTCP2_STRM_FLAG_FIN_ACKED indicates that a STREAM with FIN bit set
    is acknowledged by a remote endpoint. */
-#define NGTCP2_STRM_FLAG_FIN_ACKED 0x40u
+#define NGTCP2_STRM_FLAG_FIN_ACKED 0x40U
 /* NGTCP2_STRM_FLAG_ANY_ACKED indicates that any portion of stream
    data, including 0 length segment, is acknowledged. */
-#define NGTCP2_STRM_FLAG_ANY_ACKED 0x80u
+#define NGTCP2_STRM_FLAG_ANY_ACKED 0x80U
 /* NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET indicates that app_error_code
    field is set.  This resolves the ambiguity that the initial
    app_error_code value 0 might be a proper application error code.
    In this case, without this flag, we are unable to distinguish
    assigned value from unassigned one.  */
-#define NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET 0x100u
+#define NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET 0x100U
 /* NGTCP2_STRM_FLAG_SEND_STOP_SENDING is set when STOP_SENDING frame
    should be sent. */
-#define NGTCP2_STRM_FLAG_SEND_STOP_SENDING 0x200u
+#define NGTCP2_STRM_FLAG_SEND_STOP_SENDING 0x200U
 /* NGTCP2_STRM_FLAG_SEND_RESET_STREAM is set when RESET_STREAM frame
    should be sent. */
-#define NGTCP2_STRM_FLAG_SEND_RESET_STREAM 0x400u
+#define NGTCP2_STRM_FLAG_SEND_RESET_STREAM 0x400U
 /* NGTCP2_STRM_FLAG_STOP_SENDING_RECVED indicates that STOP_SENDING is
    received from the remote endpoint.  In this case,
    NGTCP2_STRM_FLAG_SHUT_WR is also set. */
-#define NGTCP2_STRM_FLAG_STOP_SENDING_RECVED 0x800u
+#define NGTCP2_STRM_FLAG_STOP_SENDING_RECVED 0x800U
 /* NGTCP2_STRM_FLAG_ANY_SENT indicates that any STREAM frame,
    including empty one, has been sent. */
-#define NGTCP2_STRM_FLAG_ANY_SENT 0x1000u
+#define NGTCP2_STRM_FLAG_ANY_SENT 0x1000U
 
 typedef struct ngtcp2_strm ngtcp2_strm;
 
@@ -171,14 +171,14 @@ struct ngtcp2_strm {
       const ngtcp2_mem *mem;
       int64_t stream_id;
       void *stream_user_data;
-      /* flags is bit-wise OR of zero or more of NGTCP2_STRM_FLAG_*. */
-      uint32_t flags;
       /* app_error_code is an error code the local endpoint sent in
          RESET_STREAM or STOP_SENDING, or received from a remote endpoint
          in RESET_STREAM or STOP_SENDING.  First application error code is
          chosen and when set, NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET flag is
          set in flags field. */
       uint64_t app_error_code;
+      /* flags is bit-wise OR of zero or more of NGTCP2_STRM_FLAG_*. */
+      uint32_t flags;
     };
 
     ngtcp2_opl_entry oplent;
@@ -208,14 +208,14 @@ uint64_t ngtcp2_strm_rx_offset(const ngt
 /*
  * ngtcp2_strm_recv_reordering handles reordered data.
  *
- * It returns 0 if it succeeds, or one of the following negative error
- * codes:
+ * It returns the number of bytes newly buffered if it succeeds, or
+ * one of the following negative error codes:
  *
  * NGTCP2_ERR_NOMEM
  *     Out of memory
  */
-int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
-                                size_t datalen, uint64_t offset);
+ngtcp2_ssize ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
+                                         size_t datalen, uint64_t offset);
 
 /*
  * ngtcp2_strm_update_rx_offset tells that data up to |offset| bytes
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_transport_params.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_transport_params.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_transport_params.c	2026-01-23 11:53:43.297758600 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_transport_params.c	2026-05-15 15:49:15.168978500 +0200
@@ -150,8 +150,8 @@ ngtcp2_ssize ngtcp2_transport_params_enc
 
   if (params->stateless_reset_token_present) {
     len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) +
-           ngtcp2_put_uvarintlen(NGTCP2_STATELESS_RESET_TOKENLEN) +
-           NGTCP2_STATELESS_RESET_TOKENLEN;
+           ngtcp2_put_uvarintlen(sizeof(params->stateless_reset_token)) +
+           sizeof(params->stateless_reset_token);
   }
 
   if (params->preferred_addr_present) {
@@ -160,7 +160,7 @@ ngtcp2_ssize ngtcp2_transport_params_enc
     preferred_addrlen = 4 /* ipv4Address */ + 2 /* ipv4Port */ +
                         16 /* ipv6Address */ + 2 /* ipv6Port */
                         + 1 + params->preferred_addr.cid.datalen /* CID */ +
-                        NGTCP2_STATELESS_RESET_TOKENLEN;
+                        sizeof(params->preferred_addr.stateless_reset_token);
     len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) +
            ngtcp2_put_uvarintlen(preferred_addrlen) + preferred_addrlen;
   }
@@ -523,12 +523,12 @@ int ngtcp2_transport_params_decode_versi
   }
 
   /* Set default values */
-  memset(params, 0, sizeof(*params));
-  params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE;
-  params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT;
-  params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY;
-  params->active_connection_id_limit =
-    NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT;
+  *params = (ngtcp2_transport_params){
+    .max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE,
+    .ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT,
+    .max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY,
+    .active_connection_id_limit = NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT,
+  };
 
   p = end = data;
 
@@ -626,7 +626,8 @@ int ngtcp2_transport_params_decode_versi
       }
       len = 4 /* ipv4Address */ + 2 /* ipv4Port */ + 16 /* ipv6Address */ +
             2 /* ipv6Port */
-            + 1 /* cid length */ + NGTCP2_STATELESS_RESET_TOKENLEN;
+            + 1 /* cid length */ +
+            sizeof(params->preferred_addr.stateless_reset_token);
       if (valuelen < len) {
         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
       }
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_transport_params.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_transport_params.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_transport_params.h	2026-01-23 11:53:43.297758600 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_transport_params.h	2026-05-15 15:49:15.168978500 +0200
@@ -45,16 +45,16 @@ typedef uint64_t ngtcp2_transport_param_
 #define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI 0x07
 #define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI 0x08
 #define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI 0x09
-#define NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT 0x0a
-#define NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY 0x0b
-#define NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION 0x0c
-#define NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS 0x0d
-#define NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT 0x0e
-#define NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID 0x0f
+#define NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT 0x0A
+#define NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY 0x0B
+#define NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION 0x0C
+#define NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS 0x0D
+#define NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT 0x0E
+#define NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID 0x0F
 #define NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID 0x10
 /* https://datatracker.ietf.org/doc/html/rfc9221 */
 #define NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE 0x20
-#define NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT 0x2ab2
+#define NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT 0x2AB2
 /* https://datatracker.ietf.org/doc/html/rfc9368 */
 #define NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION 0x11
 
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_vec.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_vec.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_vec.c	2026-01-23 11:53:43.297758600 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_vec.c	2026-05-15 15:49:15.168978500 +0200
@@ -30,8 +30,11 @@
 #include "ngtcp2_str.h"
 
 ngtcp2_vec *ngtcp2_vec_init(ngtcp2_vec *vec, const uint8_t *base, size_t len) {
-  vec->base = (uint8_t *)base;
-  vec->len = len;
+  *vec = (ngtcp2_vec){
+    .base = (uint8_t *)base,
+    .len = len,
+  };
+
   return vec;
 }
 
@@ -102,8 +105,7 @@ ngtcp2_ssize ngtcp2_vec_split(ngtcp2_vec
       memcpy(dst, src + i, sizeof(ngtcp2_vec) * nmove);
     }
 
-    dst[0].len -= left;
-    dst[0].base += left;
+    ngtcp2_vec_drop(&dst[0], left);
     src[i].len = left;
 
     if (nmove == 0) {
@@ -136,8 +138,7 @@ size_t ngtcp2_vec_merge(ngtcp2_vec *dst,
       a->len = left;
       a->base = b->base;
 
-      b->len -= left;
-      b->base += left;
+      ngtcp2_vec_drop(b, left);
 
       return left;
     }
@@ -158,13 +159,14 @@ size_t ngtcp2_vec_merge(ngtcp2_vec *dst,
       } else if (*pdstcnt == maxcnt) {
         break;
       } else {
-        dst[*pdstcnt].len = left;
-        dst[*pdstcnt].base = b->base;
+        dst[*pdstcnt] = (ngtcp2_vec){
+          .base = b->base,
+          .len = left,
+        };
         ++*pdstcnt;
       }
 
-      b->len -= left;
-      b->base += left;
+      ngtcp2_vec_drop(b, left);
       left = 0;
 
       break;
@@ -199,8 +201,10 @@ size_t ngtcp2_vec_copy_at_most(ngtcp2_ve
     }
 
     if (src[i].len > left) {
-      dst[j].base = src[i].base;
-      dst[j].len = left;
+      dst[j] = (ngtcp2_vec){
+        .base = src[i].base,
+        .len = left,
+      };
 
       return j + 1;
     }
@@ -217,3 +221,14 @@ size_t ngtcp2_vec_copy_at_most(ngtcp2_ve
 void ngtcp2_vec_copy(ngtcp2_vec *dst, const ngtcp2_vec *src, size_t cnt) {
   memcpy(dst, src, sizeof(ngtcp2_vec) * cnt);
 }
+
+void ngtcp2_vec_split_at(ngtcp2_vec *dst, ngtcp2_vec *src, size_t offset) {
+  assert(offset < src->len);
+
+  *dst = (ngtcp2_vec){
+    .base = src->base + offset,
+    .len = src->len - offset,
+  };
+
+  src->len = offset;
+}
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_vec.h samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_vec.h
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_vec.h	2026-01-23 11:53:43.297758600 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_vec.h	2026-05-15 15:49:15.168978500 +0200
@@ -34,13 +34,6 @@
 #include "ngtcp2_mem.h"
 
 /*
- * ngtcp2_vec_lit is a convenient macro to fill the object pointed by
- * |DEST| with the literal string |LIT|.
- */
-#define ngtcp2_vec_lit(DEST, LIT)                                              \
-  ((DEST)->base = (uint8_t *)(LIT), (DEST)->len = sizeof(LIT) - 1, (DEST))
-
-/*
  * ngtcp2_vec_init initializes |vec| with the given parameters.  It
  * returns |vec|.
  */
@@ -103,4 +96,28 @@ size_t ngtcp2_vec_copy_at_most(ngtcp2_ve
  */
 void ngtcp2_vec_copy(ngtcp2_vec *dst, const ngtcp2_vec *src, size_t cnt);
 
+/*
+ * ngtcp2_vec_split_at splits |src| at the |offset|.  Caller must
+ * ensure that offset < src->len.  This function assigns the right
+ * part of vector into |dst|.
+ */
+void ngtcp2_vec_split_at(ngtcp2_vec *dst, ngtcp2_vec *src, size_t offset);
+
+/*
+ * ngtcp2_vec_end returns the one beyond the last offset of |v|.
+ */
+static inline uint8_t *ngtcp2_vec_end(const ngtcp2_vec *v) {
+  return v->base + v->len;
+}
+
+/*
+ * ngtcp2_vec_drop removes the first |n| bytes from |v| by adjusting
+ * its base and len fields.  This function assumes |v|->len > 0 &&
+ * |v|->len >= n.
+ */
+static inline void ngtcp2_vec_drop(ngtcp2_vec *v, size_t n) {
+  v->base += n;
+  v->len -= n;
+}
+
 #endif /* !defined(NGTCP2_VEC_H) */
diff -Npur samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_window_filter.c samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_window_filter.c
--- samba-4.23.7/third_party/ngtcp2/lib/ngtcp2_window_filter.c	2026-01-23 11:53:43.297758600 +0100
+++ samba-4.23.8/third_party/ngtcp2/lib/ngtcp2_window_filter.c	2026-05-15 15:49:15.168978500 +0200
@@ -39,7 +39,7 @@
 void ngtcp2_window_filter_init(ngtcp2_window_filter *wf,
                                uint64_t window_length) {
   wf->window_length = window_length;
-  memset(wf->estimates, 0xff, sizeof(wf->estimates));
+  memset(wf->estimates, 0xFF, sizeof(wf->estimates));
 }
 
 void ngtcp2_window_filter_update(ngtcp2_window_filter *wf, uint64_t new_sample,
diff -Npur samba-4.23.7/third_party/ngtcp2/wscript samba-4.23.8/third_party/ngtcp2/wscript
--- samba-4.23.7/third_party/ngtcp2/wscript	2026-01-23 11:53:43.297758600 +0100
+++ samba-4.23.8/third_party/ngtcp2/wscript	2026-05-15 15:49:15.169978600 +0200
@@ -72,9 +72,11 @@ def build(bld):
                       lib/ngtcp2_balloc.c
                       lib/ngtcp2_bbr.c
                       lib/ngtcp2_buf.c
+                      lib/ngtcp2_callbacks.c
                       lib/ngtcp2_cc.c
                       lib/ngtcp2_cid.c
                       lib/ngtcp2_conn.c
+                      lib/ngtcp2_conn_info.c
                       lib/ngtcp2_conv.c
                       lib/ngtcp2_crypto.c
                       lib/ngtcp2_dcidtr.c
@@ -89,6 +91,7 @@ def build(bld):
                       lib/ngtcp2_objalloc.c
                       lib/ngtcp2_opl.c
                       lib/ngtcp2_path.c
+                      lib/ngtcp2_pcg.c
                       lib/ngtcp2_pkt.c
                       lib/ngtcp2_pmtud.c
                       lib/ngtcp2_ppe.c
@@ -96,6 +99,7 @@ def build(bld):
                       lib/ngtcp2_pv.c
                       lib/ngtcp2_qlog.c
                       lib/ngtcp2_range.c
+                      lib/ngtcp2_ratelim.c
                       lib/ngtcp2_ringbuf.c
                       lib/ngtcp2_rob.c
                       lib/ngtcp2_rst.c
