Add ngtcp2_max_remote_stream_id callback
diff --git a/examples/client.cc b/examples/client.cc
index 1fc3732..6b55190 100644
--- a/examples/client.cc
+++ b/examples/client.cc
@@ -931,6 +931,8 @@
       path_validation,
       ::select_preferred_address,
       nullptr, // stream_reset
+      nullptr, // max_remote_stream_id_bidi,
+      nullptr, // max_remote_stream_id_uni,
   };
 
   auto dis = std::uniform_int_distribution<uint8_t>(
diff --git a/examples/server.cc b/examples/server.cc
index d73ccd8..b3998f0 100644
--- a/examples/server.cc
+++ b/examples/server.cc
@@ -1066,6 +1066,8 @@
       path_validation,
       nullptr, // select_preferred_addr
       nullptr, // stream_reset
+      nullptr, // max_remote_stream_id_bidi,
+      nullptr, // max_remote_stream_id_uni,
   };
 
   ngtcp2_settings settings;
diff --git a/lib/includes/ngtcp2/ngtcp2.h b/lib/includes/ngtcp2/ngtcp2.h
index 06a94f5..c364577 100644
--- a/lib/includes/ngtcp2/ngtcp2.h
+++ b/lib/includes/ngtcp2/ngtcp2.h
@@ -1451,6 +1451,22 @@
                                             const ngtcp2_preferred_addr *paddr,
                                             void *user_data);
 
+/**
+ * @functypedef
+ *
+ * :type:`ngtcp2_max_remote_stream_id` is a callback function which is
+ * invoked when the maximum stream ID which remote endpoint can open
+ * is extended.  |max_stream_id| is the maximum stream ID which remote
+ * endpoint can initiate.
+ *
+ * The callback function must return 0 if it succeeds.  Returning
+ * :enum:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
+ * immediately.
+ */
+typedef int (*ngtcp2_max_remote_stream_id)(ngtcp2_conn *conn,
+                                           int64_t max_stream_id,
+                                           void *user_data);
+
 typedef struct {
   ngtcp2_client_initial client_initial;
   ngtcp2_recv_client_initial recv_client_initial;
@@ -1503,6 +1519,8 @@
   ngtcp2_path_validation path_validation;
   ngtcp2_select_preferred_addr select_preferred_addr;
   ngtcp2_stream_reset stream_reset;
+  ngtcp2_max_remote_stream_id max_remote_stream_id_bidi;
+  ngtcp2_max_remote_stream_id max_remote_stream_id_uni;
 } ngtcp2_conn_callbacks;
 
 /*
diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c
index f7f5a4a..2b348d1 100644
--- a/lib/ngtcp2_conn.c
+++ b/lib/ngtcp2_conn.c
@@ -266,6 +266,40 @@
   return 0;
 }
 
+static int conn_call_max_remote_stream_id_bidi(ngtcp2_conn *conn,
+                                               int64_t max_stream_id) {
+  int rv;
+
+  if (!conn->callbacks.max_remote_stream_id_bidi) {
+    return 0;
+  }
+
+  rv = conn->callbacks.max_remote_stream_id_bidi(conn, max_stream_id,
+                                                 conn->user_data);
+  if (rv != 0) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
+static int conn_call_max_remote_stream_id_uni(ngtcp2_conn *conn,
+                                              int64_t max_stream_id) {
+  int rv;
+
+  if (!conn->callbacks.max_remote_stream_id_uni) {
+    return 0;
+  }
+
+  rv = conn->callbacks.max_remote_stream_id_uni(conn, max_stream_id,
+                                                conn->user_data);
+  if (rv != 0) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
 /*
  * bw_reset resets |bw| to the initial state.
  */
@@ -2229,6 +2263,13 @@
   if (rv != NGTCP2_ERR_NOBUF && *pfrc == NULL &&
       conn->remote.bidi.unsent_max_stream_id >
           conn->remote.bidi.max_stream_id) {
+    rv = conn_call_max_remote_stream_id_bidi(
+        conn, conn->remote.bidi.unsent_max_stream_id);
+    if (rv != 0) {
+      assert(ngtcp2_err_is_fatal(rv));
+      return rv;
+    }
+
     rv = ngtcp2_frame_chain_new(&nfrc, conn->mem);
     if (rv != 0) {
       assert(ngtcp2_err_is_fatal(rv));
@@ -2254,6 +2295,13 @@
   if (rv != NGTCP2_ERR_NOBUF && *pfrc == NULL) {
     if (conn->remote.uni.unsent_max_stream_id >
         conn->remote.uni.max_stream_id) {
+      rv = conn_call_max_remote_stream_id_uni(
+          conn, conn->remote.uni.unsent_max_stream_id);
+      if (rv != 0) {
+        assert(ngtcp2_err_is_fatal(rv));
+        return rv;
+      }
+
       rv = ngtcp2_frame_chain_new(&nfrc, conn->mem);
       if (rv != 0) {
         assert(ngtcp2_err_is_fatal(rv));