src/event/quic/ngx_event_quic_transport.c - nginx source code

Global variables defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Nginx, Inc.
  3. */


  4. #include <ngx_config.h>
  5. #include <ngx_core.h>
  6. #include <ngx_event.h>
  7. #include <ngx_event_quic_connection.h>


  8. #define NGX_QUIC_LONG_DCID_LEN_OFFSET  5
  9. #define NGX_QUIC_LONG_DCID_OFFSET      6
  10. #define NGX_QUIC_SHORT_DCID_OFFSET     1

  11. #define NGX_QUIC_STREAM_FRAME_FIN      0x01
  12. #define NGX_QUIC_STREAM_FRAME_LEN      0x02
  13. #define NGX_QUIC_STREAM_FRAME_OFF      0x04


  14. #if (NGX_HAVE_NONALIGNED)

  15. #define ngx_quic_parse_uint16(p)  ntohs(*(uint16_t *) (p))
  16. #define ngx_quic_parse_uint32(p)  ntohl(*(uint32_t *) (p))

  17. #define ngx_quic_write_uint16  ngx_quic_write_uint16_aligned
  18. #define ngx_quic_write_uint32  ngx_quic_write_uint32_aligned

  19. #else

  20. #define ngx_quic_parse_uint16(p)  ((p)[0] << 8 | (p)[1])
  21. #define ngx_quic_parse_uint32(p)                                              \
  22.     ((uint32_t) (p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3])

  23. #define ngx_quic_write_uint16(p, s)                                           \
  24.     ((p)[0] = (u_char) ((s) >> 8),                                            \
  25.      (p)[1] = (u_char)  (s),                                                  \
  26.      (p) + sizeof(uint16_t))

  27. #define ngx_quic_write_uint32(p, s)                                           \
  28.     ((p)[0] = (u_char) ((s) >> 24),                                           \
  29.      (p)[1] = (u_char) ((s) >> 16),                                           \
  30.      (p)[2] = (u_char) ((s) >> 8),                                            \
  31.      (p)[3] = (u_char)  (s),                                                  \
  32.      (p) + sizeof(uint32_t))

  33. #endif

  34. #define ngx_quic_write_uint64(p, s)                                           \
  35.     ((p)[0] = (u_char) ((s) >> 56),                                           \
  36.      (p)[1] = (u_char) ((s) >> 48),                                           \
  37.      (p)[2] = (u_char) ((s) >> 40),                                           \
  38.      (p)[3] = (u_char) ((s) >> 32),                                           \
  39.      (p)[4] = (u_char) ((s) >> 24),                                           \
  40.      (p)[5] = (u_char) ((s) >> 16),                                           \
  41.      (p)[6] = (u_char) ((s) >> 8),                                            \
  42.      (p)[7] = (u_char)  (s),                                                  \
  43.      (p) + sizeof(uint64_t))

  44. #define ngx_quic_write_uint24(p, s)                                           \
  45.     ((p)[0] = (u_char) ((s) >> 16),                                           \
  46.      (p)[1] = (u_char) ((s) >> 8),                                            \
  47.      (p)[2] = (u_char)  (s),                                                  \
  48.      (p) + 3)

  49. #define ngx_quic_write_uint16_aligned(p, s)                                   \
  50.     (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t))

  51. #define ngx_quic_write_uint32_aligned(p, s)                                   \
  52.     (*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t))

  53. #define ngx_quic_build_int_set(p, value, len, bits)                           \
  54.     (*(p)++ = ((value >> ((len) * 8)) & 0xff) | ((bits) << 6))


  55. static u_char *ngx_quic_parse_int(u_char *pos, u_char *end, uint64_t *out);
  56. static ngx_uint_t ngx_quic_varint_len(uint64_t value);
  57. static void ngx_quic_build_int(u_char **pos, uint64_t value);

  58. static u_char *ngx_quic_read_uint8(u_char *pos, u_char *end, uint8_t *value);
  59. static u_char *ngx_quic_read_uint32(u_char *pos, u_char *end, uint32_t *value);
  60. static u_char *ngx_quic_read_bytes(u_char *pos, u_char *end, size_t len,
  61.     u_char **out);
  62. static u_char *ngx_quic_copy_bytes(u_char *pos, u_char *end, size_t len,
  63.     u_char *dst);

  64. static ngx_int_t ngx_quic_parse_short_header(ngx_quic_header_t *pkt,
  65.     size_t dcid_len);
  66. static ngx_int_t ngx_quic_parse_long_header(ngx_quic_header_t *pkt);
  67. static ngx_int_t ngx_quic_supported_version(uint32_t version);
  68. static ngx_int_t ngx_quic_parse_long_header_v1(ngx_quic_header_t *pkt);

  69. static size_t ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
  70.     u_char **pnp);
  71. static size_t ngx_quic_create_short_header(ngx_quic_header_t *pkt, u_char *out,
  72.     u_char **pnp);

  73. static ngx_int_t ngx_quic_frame_allowed(ngx_quic_header_t *pkt,
  74.     ngx_uint_t frame_type);
  75. static size_t ngx_quic_create_ping(u_char *p);
  76. static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack,
  77.     ngx_chain_t *ranges);
  78. static size_t ngx_quic_create_reset_stream(u_char *p,
  79.     ngx_quic_reset_stream_frame_t *rs);
  80. static size_t ngx_quic_create_stop_sending(u_char *p,
  81.     ngx_quic_stop_sending_frame_t *ss);
  82. static size_t ngx_quic_create_crypto(u_char *p,
  83.     ngx_quic_crypto_frame_t *crypto, ngx_chain_t *data);
  84. static size_t ngx_quic_create_hs_done(u_char *p);
  85. static size_t ngx_quic_create_new_token(u_char *p,
  86.     ngx_quic_new_token_frame_t *token, ngx_chain_t *data);
  87. static size_t ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf,
  88.     ngx_chain_t *data);
  89. static size_t ngx_quic_create_max_streams(u_char *p,
  90.     ngx_quic_max_streams_frame_t *ms);
  91. static size_t ngx_quic_create_max_stream_data(u_char *p,
  92.     ngx_quic_max_stream_data_frame_t *ms);
  93. static size_t ngx_quic_create_max_data(u_char *p,
  94.     ngx_quic_max_data_frame_t *md);
  95. static size_t ngx_quic_create_path_challenge(u_char *p,
  96.     ngx_quic_path_challenge_frame_t *pc);
  97. static size_t ngx_quic_create_path_response(u_char *p,
  98.     ngx_quic_path_challenge_frame_t *pc);
  99. static size_t ngx_quic_create_new_connection_id(u_char *p,
  100.     ngx_quic_new_conn_id_frame_t *rcid);
  101. static size_t ngx_quic_create_retire_connection_id(u_char *p,
  102.     ngx_quic_retire_cid_frame_t *rcid);
  103. static size_t ngx_quic_create_close(u_char *p, ngx_quic_frame_t *f);

  104. static ngx_int_t ngx_quic_parse_transport_param(u_char *p, u_char *end,
  105.     uint16_t id, ngx_quic_tp_t *dst);


  106. uint32_t  ngx_quic_versions[] = {
  107.     /* QUICv1 */
  108.     0x00000001,
  109. };

  110. #define NGX_QUIC_NVERSIONS \
  111.     (sizeof(ngx_quic_versions) / sizeof(ngx_quic_versions[0]))


  112. static ngx_inline u_char *
  113. ngx_quic_parse_int(u_char *pos, u_char *end, uint64_t *out)
  114. {
  115.     u_char      *p;
  116.     uint64_t     value;
  117.     ngx_uint_t   len;

  118.     if (pos >= end) {
  119.         return NULL;
  120.     }

  121.     p = pos;
  122.     len = 1 << (*p >> 6);

  123.     value = *p++ & 0x3f;

  124.     if ((size_t)(end - p) < (len - 1)) {
  125.         return NULL;
  126.     }

  127.     while (--len) {
  128.         value = (value << 8) + *p++;
  129.     }

  130.     *out = value;

  131.     return p;
  132. }


  133. static ngx_inline u_char *
  134. ngx_quic_read_uint8(u_char *pos, u_char *end, uint8_t *value)
  135. {
  136.     if ((size_t)(end - pos) < 1) {
  137.         return NULL;
  138.     }

  139.     *value = *pos;

  140.     return pos + 1;
  141. }


  142. static ngx_inline u_char *
  143. ngx_quic_read_uint32(u_char *pos, u_char *end, uint32_t *value)
  144. {
  145.     if ((size_t)(end - pos) < sizeof(uint32_t)) {
  146.         return NULL;
  147.     }

  148.     *value = ngx_quic_parse_uint32(pos);

  149.     return pos + sizeof(uint32_t);
  150. }


  151. static ngx_inline u_char *
  152. ngx_quic_read_bytes(u_char *pos, u_char *end, size_t len, u_char **out)
  153. {
  154.     if ((size_t)(end - pos) < len) {
  155.         return NULL;
  156.     }

  157.     *out = pos;

  158.     return pos + len;
  159. }


  160. static u_char *
  161. ngx_quic_copy_bytes(u_char *pos, u_char *end, size_t len, u_char *dst)
  162. {
  163.     if ((size_t)(end - pos) < len) {
  164.         return NULL;
  165.     }

  166.     ngx_memcpy(dst, pos, len);

  167.     return pos + len;
  168. }


  169. static ngx_inline ngx_uint_t
  170. ngx_quic_varint_len(uint64_t value)
  171. {
  172.     if (value < (1 << 6)) {
  173.         return 1;
  174.     }

  175.     if (value < (1 << 14)) {
  176.         return 2;
  177.     }

  178.     if (value < (1 << 30)) {
  179.         return 4;
  180.     }

  181.     return 8;
  182. }


  183. static ngx_inline void
  184. ngx_quic_build_int(u_char **pos, uint64_t value)
  185. {
  186.     u_char  *p;

  187.     p = *pos;

  188.     if (value < (1 << 6)) {
  189.         ngx_quic_build_int_set(p, value, 0, 0);

  190.     } else if (value < (1 << 14)) {
  191.         ngx_quic_build_int_set(p, value, 1, 1);
  192.         ngx_quic_build_int_set(p, value, 0, 0);

  193.     } else if (value < (1 << 30)) {
  194.         ngx_quic_build_int_set(p, value, 3, 2);
  195.         ngx_quic_build_int_set(p, value, 2, 0);
  196.         ngx_quic_build_int_set(p, value, 1, 0);
  197.         ngx_quic_build_int_set(p, value, 0, 0);

  198.     } else {
  199.         ngx_quic_build_int_set(p, value, 7, 3);
  200.         ngx_quic_build_int_set(p, value, 6, 0);
  201.         ngx_quic_build_int_set(p, value, 5, 0);
  202.         ngx_quic_build_int_set(p, value, 4, 0);
  203.         ngx_quic_build_int_set(p, value, 3, 0);
  204.         ngx_quic_build_int_set(p, value, 2, 0);
  205.         ngx_quic_build_int_set(p, value, 1, 0);
  206.         ngx_quic_build_int_set(p, value, 0, 0);
  207.     }

  208.     *pos = p;
  209. }


  210. ngx_int_t
  211. ngx_quic_parse_packet(ngx_quic_header_t *pkt)
  212. {
  213.     if (!ngx_quic_long_pkt(pkt->flags)) {
  214.         pkt->level = ssl_encryption_application;

  215.         if (ngx_quic_parse_short_header(pkt, NGX_QUIC_SERVER_CID_LEN) != NGX_OK)
  216.         {
  217.             return NGX_ERROR;
  218.         }

  219.         return NGX_OK;
  220.     }

  221.     if (ngx_quic_parse_long_header(pkt) != NGX_OK) {
  222.         return NGX_ERROR;
  223.     }

  224.     if (!ngx_quic_supported_version(pkt->version)) {
  225.         return NGX_ABORT;
  226.     }

  227.     if (ngx_quic_parse_long_header_v1(pkt) != NGX_OK) {
  228.         return NGX_ERROR;
  229.     }

  230.     return NGX_OK;
  231. }


  232. static ngx_int_t
  233. ngx_quic_parse_short_header(ngx_quic_header_t *pkt, size_t dcid_len)
  234. {
  235.     u_char  *p, *end;

  236.     p = pkt->raw->pos;
  237.     end = pkt->data + pkt->len;

  238.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
  239.                    "quic packet rx short flags:%xd", pkt->flags);

  240.     if (!(pkt->flags & NGX_QUIC_PKT_FIXED_BIT)) {
  241.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic fixed bit is not set");
  242.         return NGX_ERROR;
  243.     }

  244.     pkt->dcid.len = dcid_len;

  245.     p = ngx_quic_read_bytes(p, end, dcid_len, &pkt->dcid.data);
  246.     if (p == NULL) {
  247.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  248.                       "quic packet is too small to read dcid");
  249.         return NGX_ERROR;
  250.     }

  251.     pkt->raw->pos = p;

  252.     return NGX_OK;
  253. }


  254. static ngx_int_t
  255. ngx_quic_parse_long_header(ngx_quic_header_t *pkt)
  256. {
  257.     u_char   *p, *end;
  258.     uint8_t   idlen;

  259.     p = pkt->raw->pos;
  260.     end = pkt->data + pkt->len;

  261.     p = ngx_quic_read_uint32(p, end, &pkt->version);
  262.     if (p == NULL) {
  263.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  264.                       "quic packet is too small to read version");
  265.         return NGX_ERROR;
  266.     }

  267.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
  268.                    "quic packet rx long flags:%xd version:%xD",
  269.                    pkt->flags, pkt->version);

  270.     if (!(pkt->flags & NGX_QUIC_PKT_FIXED_BIT)) {
  271.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic fixed bit is not set");
  272.         return NGX_ERROR;
  273.     }

  274.     p = ngx_quic_read_uint8(p, end, &idlen);
  275.     if (p == NULL) {
  276.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  277.                       "quic packet is too small to read dcid len");
  278.         return NGX_ERROR;
  279.     }

  280.     if (idlen > NGX_QUIC_CID_LEN_MAX) {
  281.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  282.                       "quic packet dcid is too long");
  283.         return NGX_ERROR;
  284.     }

  285.     pkt->dcid.len = idlen;

  286.     p = ngx_quic_read_bytes(p, end, idlen, &pkt->dcid.data);
  287.     if (p == NULL) {
  288.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  289.                       "quic packet is too small to read dcid");
  290.         return NGX_ERROR;
  291.     }

  292.     p = ngx_quic_read_uint8(p, end, &idlen);
  293.     if (p == NULL) {
  294.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  295.                       "quic packet is too small to read scid len");
  296.         return NGX_ERROR;
  297.     }

  298.     if (idlen > NGX_QUIC_CID_LEN_MAX) {
  299.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  300.                       "quic packet scid is too long");
  301.         return NGX_ERROR;
  302.     }

  303.     pkt->scid.len = idlen;

  304.     p = ngx_quic_read_bytes(p, end, idlen, &pkt->scid.data);
  305.     if (p == NULL) {
  306.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  307.                       "quic packet is too small to read scid");
  308.         return NGX_ERROR;
  309.     }

  310.     pkt->raw->pos = p;

  311.     return NGX_OK;
  312. }


  313. static ngx_int_t
  314. ngx_quic_supported_version(uint32_t version)
  315. {
  316.     ngx_uint_t  i;

  317.     for (i = 0; i < NGX_QUIC_NVERSIONS; i++) {
  318.         if (ngx_quic_versions[i] == version) {
  319.             return 1;
  320.         }
  321.     }

  322.     return 0;
  323. }


  324. static ngx_int_t
  325. ngx_quic_parse_long_header_v1(ngx_quic_header_t *pkt)
  326. {
  327.     u_char    *p, *end;
  328.     uint64_t   varint;

  329.     p = pkt->raw->pos;
  330.     end = pkt->raw->last;

  331.     pkt->log->action = "parsing quic long header";

  332.     if (ngx_quic_pkt_in(pkt->flags)) {

  333.         if (pkt->len < NGX_QUIC_MIN_INITIAL_SIZE) {
  334.             ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  335.                           "quic UDP datagram is too small for initial packet");
  336.             return NGX_DECLINED;
  337.         }

  338.         p = ngx_quic_parse_int(p, end, &varint);
  339.         if (p == NULL) {
  340.             ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  341.                           "quic failed to parse token length");
  342.             return NGX_ERROR;
  343.         }

  344.         pkt->token.len = varint;

  345.         p = ngx_quic_read_bytes(p, end, pkt->token.len, &pkt->token.data);
  346.         if (p == NULL) {
  347.             ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  348.                           "quic packet too small to read token data");
  349.             return NGX_ERROR;
  350.         }

  351.         pkt->level = ssl_encryption_initial;

  352.     } else if (ngx_quic_pkt_zrtt(pkt->flags)) {
  353.         pkt->level = ssl_encryption_early_data;

  354.     } else if (ngx_quic_pkt_hs(pkt->flags)) {
  355.         pkt->level = ssl_encryption_handshake;

  356.     } else {
  357.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  358.                       "quic bad packet type");
  359.         return NGX_DECLINED;
  360.     }

  361.     p = ngx_quic_parse_int(p, end, &varint);
  362.     if (p == NULL) {
  363.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic bad packet length");
  364.         return NGX_ERROR;
  365.     }

  366.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
  367.                    "quic packet rx %s len:%uL",
  368.                    ngx_quic_level_name(pkt->level), varint);

  369.     if (varint > (uint64_t) ((pkt->data + pkt->len) - p)) {
  370.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic truncated %s packet",
  371.                       ngx_quic_level_name(pkt->level));
  372.         return NGX_ERROR;
  373.     }

  374.     pkt->raw->pos = p;
  375.     pkt->len = p + varint - pkt->data;

  376.     return NGX_OK;
  377. }


  378. ngx_int_t
  379. ngx_quic_get_packet_dcid(ngx_log_t *log, u_char *data, size_t n,
  380.     ngx_str_t *dcid)
  381. {
  382.     size_t  len, offset;

  383.     if (n == 0) {
  384.         goto failed;
  385.     }

  386.     if (ngx_quic_long_pkt(*data)) {
  387.         if (n < NGX_QUIC_LONG_DCID_LEN_OFFSET + 1) {
  388.             goto failed;
  389.         }

  390.         len = data[NGX_QUIC_LONG_DCID_LEN_OFFSET];
  391.         offset = NGX_QUIC_LONG_DCID_OFFSET;

  392.     } else {
  393.         len = NGX_QUIC_SERVER_CID_LEN;
  394.         offset = NGX_QUIC_SHORT_DCID_OFFSET;
  395.     }

  396.     if (n < len + offset) {
  397.         goto failed;
  398.     }

  399.     dcid->len = len;
  400.     dcid->data = &data[offset];

  401.     return NGX_OK;

  402. failed:

  403.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, log, 0, "quic malformed packet");

  404.     return NGX_ERROR;
  405. }


  406. size_t
  407. ngx_quic_create_version_negotiation(ngx_quic_header_t *pkt, u_char *out)
  408. {
  409.     u_char      *p, *start;
  410.     ngx_uint_t   i;

  411.     p = start = out;

  412.     *p++ = pkt->flags;

  413.     /*
  414.      * The Version field of a Version Negotiation packet
  415.      * MUST be set to 0x00000000
  416.      */
  417.     p = ngx_quic_write_uint32(p, 0);

  418.     *p++ = pkt->dcid.len;
  419.     p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len);

  420.     *p++ = pkt->scid.len;
  421.     p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len);

  422.     for (i = 0; i < NGX_QUIC_NVERSIONS; i++) {
  423.         p = ngx_quic_write_uint32(p, ngx_quic_versions[i]);
  424.     }

  425.     return p - start;
  426. }


  427. /* returns the amount of payload quic packet of "pkt_len" size may fit or 0 */
  428. size_t
  429. ngx_quic_payload_size(ngx_quic_header_t *pkt, size_t pkt_len)
  430. {
  431.     size_t  len;

  432.     if (ngx_quic_short_pkt(pkt->flags)) {

  433.         len = 1 + pkt->dcid.len + pkt->num_len + NGX_QUIC_TAG_LEN;
  434.         if (len > pkt_len) {
  435.             return 0;
  436.         }

  437.         return pkt_len - len;
  438.     }

  439.     /* flags, version, dcid and scid with lengths and zero-length token */
  440.     len = 5 + 2 + pkt->dcid.len + pkt->scid.len
  441.           + (pkt->level == ssl_encryption_initial ? 1 : 0);

  442.     if (len > pkt_len) {
  443.         return 0;
  444.     }

  445.     /* (pkt_len - len) is 'remainder' packet length (see RFC 9000, 17.2) */
  446.     len += ngx_quic_varint_len(pkt_len - len)
  447.            + pkt->num_len + NGX_QUIC_TAG_LEN;

  448.     if (len > pkt_len) {
  449.         return 0;
  450.     }

  451.     return pkt_len - len;
  452. }


  453. size_t
  454. ngx_quic_create_header(ngx_quic_header_t *pkt, u_char *out, u_char **pnp)
  455. {
  456.     return ngx_quic_short_pkt(pkt->flags)
  457.            ? ngx_quic_create_short_header(pkt, out, pnp)
  458.            : ngx_quic_create_long_header(pkt, out, pnp);
  459. }


  460. static size_t
  461. ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
  462.     u_char **pnp)
  463. {
  464.     size_t   rem_len;
  465.     u_char  *p, *start;

  466.     rem_len = pkt->num_len + pkt->payload.len + NGX_QUIC_TAG_LEN;

  467.     if (out == NULL) {
  468.         return 5 + 2 + pkt->dcid.len + pkt->scid.len
  469.                + ngx_quic_varint_len(rem_len) + pkt->num_len
  470.                + (pkt->level == ssl_encryption_initial ? 1 : 0);
  471.     }

  472.     p = start = out;

  473.     *p++ = pkt->flags;

  474.     p = ngx_quic_write_uint32(p, pkt->version);

  475.     *p++ = pkt->dcid.len;
  476.     p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len);

  477.     *p++ = pkt->scid.len;
  478.     p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len);

  479.     if (pkt->level == ssl_encryption_initial) {
  480.         ngx_quic_build_int(&p, 0);
  481.     }

  482.     ngx_quic_build_int(&p, rem_len);

  483.     *pnp = p;

  484.     switch (pkt->num_len) {
  485.     case 1:
  486.         *p++ = pkt->trunc;
  487.         break;
  488.     case 2:
  489.         p = ngx_quic_write_uint16(p, pkt->trunc);
  490.         break;
  491.     case 3:
  492.         p = ngx_quic_write_uint24(p, pkt->trunc);
  493.         break;
  494.     case 4:
  495.         p = ngx_quic_write_uint32(p, pkt->trunc);
  496.         break;
  497.     }

  498.     return p - start;
  499. }


  500. static size_t
  501. ngx_quic_create_short_header(ngx_quic_header_t *pkt, u_char *out,
  502.     u_char **pnp)
  503. {
  504.     u_char  *p, *start;

  505.     if (out == NULL) {
  506.         return 1 + pkt->dcid.len + pkt->num_len;
  507.     }

  508.     p = start = out;

  509.     *p++ = pkt->flags;

  510.     p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len);

  511.     *pnp = p;

  512.     switch (pkt->num_len) {
  513.     case 1:
  514.         *p++ = pkt->trunc;
  515.         break;
  516.     case 2:
  517.         p = ngx_quic_write_uint16(p, pkt->trunc);
  518.         break;
  519.     case 3:
  520.         p = ngx_quic_write_uint24(p, pkt->trunc);
  521.         break;
  522.     case 4:
  523.         p = ngx_quic_write_uint32(p, pkt->trunc);
  524.         break;
  525.     }

  526.     return p - start;
  527. }


  528. size_t
  529. ngx_quic_create_retry_itag(ngx_quic_header_t *pkt, u_char *out,
  530.     u_char **start)
  531. {
  532.     u_char  *p;

  533.     p = out;

  534.     *p++ = pkt->odcid.len;
  535.     p = ngx_cpymem(p, pkt->odcid.data, pkt->odcid.len);

  536.     *start = p;

  537.     *p++ = 0xff;

  538.     p = ngx_quic_write_uint32(p, pkt->version);

  539.     *p++ = pkt->dcid.len;
  540.     p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len);

  541.     *p++ = pkt->scid.len;
  542.     p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len);

  543.     p = ngx_cpymem(p, pkt->token.data, pkt->token.len);

  544.     return p - out;
  545. }


  546. ssize_t
  547. ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
  548.     ngx_quic_frame_t *f)
  549. {
  550.     u_char      *p;
  551.     uint64_t     varint;
  552.     ngx_buf_t   *b;
  553.     ngx_uint_t   i;

  554.     b = f->data->buf;

  555.     p = start;

  556.     p = ngx_quic_parse_int(p, end, &varint);
  557.     if (p == NULL) {
  558.         pkt->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
  559.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  560.                       "quic failed to obtain quic frame type");
  561.         return NGX_ERROR;
  562.     }

  563.     if (varint > NGX_QUIC_FT_LAST) {
  564.         pkt->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
  565.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  566.                       "quic unknown frame type 0x%xL", varint);
  567.         return NGX_ERROR;
  568.     }

  569.     f->type = varint;

  570.     if (ngx_quic_frame_allowed(pkt, f->type) != NGX_OK) {
  571.         pkt->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION;
  572.         return NGX_ERROR;
  573.     }

  574.     switch (f->type) {

  575.     case NGX_QUIC_FT_CRYPTO:

  576.         p = ngx_quic_parse_int(p, end, &f->u.crypto.offset);
  577.         if (p == NULL) {
  578.             goto error;
  579.         }

  580.         p = ngx_quic_parse_int(p, end, &f->u.crypto.length);
  581.         if (p == NULL) {
  582.             goto error;
  583.         }

  584.         p = ngx_quic_read_bytes(p, end, f->u.crypto.length, &b->pos);
  585.         if (p == NULL) {
  586.             goto error;
  587.         }

  588.         b->last = p;

  589.         break;

  590.     case NGX_QUIC_FT_PADDING:

  591.         while (p < end && *p == NGX_QUIC_FT_PADDING) {
  592.             p++;
  593.         }

  594.         break;

  595.     case NGX_QUIC_FT_ACK:
  596.     case NGX_QUIC_FT_ACK_ECN:

  597.         p = ngx_quic_parse_int(p, end, &f->u.ack.largest);
  598.         if (p == NULL) {
  599.             goto error;
  600.         }

  601.         p = ngx_quic_parse_int(p, end, &f->u.ack.delay);
  602.         if (p == NULL) {
  603.             goto error;
  604.         }

  605.         p = ngx_quic_parse_int(p, end, &f->u.ack.range_count);
  606.         if (p == NULL) {
  607.             goto error;
  608.         }

  609.         p = ngx_quic_parse_int(p, end, &f->u.ack.first_range);
  610.         if (p == NULL) {
  611.             goto error;
  612.         }

  613.         b->pos = p;

  614.         /* process all ranges to get bounds, values are ignored */
  615.         for (i = 0; i < f->u.ack.range_count; i++) {

  616.             p = ngx_quic_parse_int(p, end, &varint);
  617.             if (p == NULL) {
  618.                 goto error;
  619.             }

  620.             p = ngx_quic_parse_int(p, end, &varint);
  621.             if (p == NULL) {
  622.                 goto error;
  623.             }
  624.         }

  625.         b->last = p;

  626.         f->u.ack.ranges_length = b->last - b->pos;

  627.         if (f->type == NGX_QUIC_FT_ACK_ECN) {

  628.             p = ngx_quic_parse_int(p, end, &f->u.ack.ect0);
  629.             if (p == NULL) {
  630.                 goto error;
  631.             }

  632.             p = ngx_quic_parse_int(p, end, &f->u.ack.ect1);
  633.             if (p == NULL) {
  634.                 goto error;
  635.             }

  636.             p = ngx_quic_parse_int(p, end, &f->u.ack.ce);
  637.             if (p == NULL) {
  638.                 goto error;
  639.             }

  640.             ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
  641.                            "quic ACK ECN counters ect0:%uL ect1:%uL ce:%uL",
  642.                            f->u.ack.ect0, f->u.ack.ect1, f->u.ack.ce);
  643.         }

  644.         break;

  645.     case NGX_QUIC_FT_PING:
  646.         break;

  647.     case NGX_QUIC_FT_NEW_CONNECTION_ID:

  648.         p = ngx_quic_parse_int(p, end, &f->u.ncid.seqnum);
  649.         if (p == NULL) {
  650.             goto error;
  651.         }

  652.         p = ngx_quic_parse_int(p, end, &f->u.ncid.retire);
  653.         if (p == NULL) {
  654.             goto error;
  655.         }

  656.         if (f->u.ncid.retire > f->u.ncid.seqnum) {
  657.             goto error;
  658.         }

  659.         p = ngx_quic_read_uint8(p, end, &f->u.ncid.len);
  660.         if (p == NULL) {
  661.             goto error;
  662.         }

  663.         if (f->u.ncid.len < 1 || f->u.ncid.len > NGX_QUIC_CID_LEN_MAX) {
  664.             goto error;
  665.         }

  666.         p = ngx_quic_copy_bytes(p, end, f->u.ncid.len, f->u.ncid.cid);
  667.         if (p == NULL) {
  668.             goto error;
  669.         }

  670.         p = ngx_quic_copy_bytes(p, end, NGX_QUIC_SR_TOKEN_LEN, f->u.ncid.srt);
  671.         if (p == NULL) {
  672.             goto error;
  673.         }

  674.         break;

  675.     case NGX_QUIC_FT_RETIRE_CONNECTION_ID:

  676.         p = ngx_quic_parse_int(p, end, &f->u.retire_cid.sequence_number);
  677.         if (p == NULL) {
  678.             goto error;
  679.         }

  680.         break;

  681.     case NGX_QUIC_FT_CONNECTION_CLOSE:
  682.     case NGX_QUIC_FT_CONNECTION_CLOSE_APP:

  683.         p = ngx_quic_parse_int(p, end, &f->u.close.error_code);
  684.         if (p == NULL) {
  685.             goto error;
  686.         }

  687.         if (f->type == NGX_QUIC_FT_CONNECTION_CLOSE) {
  688.             p = ngx_quic_parse_int(p, end, &f->u.close.frame_type);
  689.             if (p == NULL) {
  690.                 goto error;
  691.             }
  692.         }

  693.         p = ngx_quic_parse_int(p, end, &varint);
  694.         if (p == NULL) {
  695.             goto error;
  696.         }

  697.         f->u.close.reason.len = varint;

  698.         p = ngx_quic_read_bytes(p, end, f->u.close.reason.len,
  699.                                 &f->u.close.reason.data);
  700.         if (p == NULL) {
  701.             goto error;
  702.         }

  703.         break;

  704.     case NGX_QUIC_FT_STREAM:
  705.     case NGX_QUIC_FT_STREAM1:
  706.     case NGX_QUIC_FT_STREAM2:
  707.     case NGX_QUIC_FT_STREAM3:
  708.     case NGX_QUIC_FT_STREAM4:
  709.     case NGX_QUIC_FT_STREAM5:
  710.     case NGX_QUIC_FT_STREAM6:
  711.     case NGX_QUIC_FT_STREAM7:

  712.         f->u.stream.fin = (f->type & NGX_QUIC_STREAM_FRAME_FIN) ? 1 : 0;

  713.         p = ngx_quic_parse_int(p, end, &f->u.stream.stream_id);
  714.         if (p == NULL) {
  715.             goto error;
  716.         }

  717.         if (f->type & NGX_QUIC_STREAM_FRAME_OFF) {
  718.             f->u.stream.off = 1;

  719.             p = ngx_quic_parse_int(p, end, &f->u.stream.offset);
  720.             if (p == NULL) {
  721.                 goto error;
  722.             }

  723.         } else {
  724.             f->u.stream.off = 0;
  725.             f->u.stream.offset = 0;
  726.         }

  727.         if (f->type & NGX_QUIC_STREAM_FRAME_LEN) {
  728.             f->u.stream.len = 1;

  729.             p = ngx_quic_parse_int(p, end, &f->u.stream.length);
  730.             if (p == NULL) {
  731.                 goto error;
  732.             }

  733.         } else {
  734.             f->u.stream.len = 0;
  735.             f->u.stream.length = end - p; /* up to packet end */
  736.         }

  737.         p = ngx_quic_read_bytes(p, end, f->u.stream.length, &b->pos);
  738.         if (p == NULL) {
  739.             goto error;
  740.         }

  741.         b->last = p;

  742.         f->type = NGX_QUIC_FT_STREAM;
  743.         break;

  744.     case NGX_QUIC_FT_MAX_DATA:

  745.         p = ngx_quic_parse_int(p, end, &f->u.max_data.max_data);
  746.         if (p == NULL) {
  747.             goto error;
  748.         }

  749.         break;

  750.     case NGX_QUIC_FT_RESET_STREAM:

  751.         p = ngx_quic_parse_int(p, end, &f->u.reset_stream.id);
  752.         if (p == NULL) {
  753.             goto error;
  754.         }

  755.         p = ngx_quic_parse_int(p, end, &f->u.reset_stream.error_code);
  756.         if (p == NULL) {
  757.             goto error;
  758.         }

  759.         p = ngx_quic_parse_int(p, end, &f->u.reset_stream.final_size);
  760.         if (p == NULL) {
  761.             goto error;
  762.         }

  763.         break;

  764.     case NGX_QUIC_FT_STOP_SENDING:

  765.         p = ngx_quic_parse_int(p, end, &f->u.stop_sending.id);
  766.         if (p == NULL) {
  767.             goto error;
  768.         }

  769.         p = ngx_quic_parse_int(p, end, &f->u.stop_sending.error_code);
  770.         if (p == NULL) {
  771.             goto error;
  772.         }

  773.         break;

  774.     case NGX_QUIC_FT_STREAMS_BLOCKED:
  775.     case NGX_QUIC_FT_STREAMS_BLOCKED2:

  776.         p = ngx_quic_parse_int(p, end, &f->u.streams_blocked.limit);
  777.         if (p == NULL) {
  778.             goto error;
  779.         }

  780.         if (f->u.streams_blocked.limit > 0x1000000000000000) {
  781.             goto error;
  782.         }

  783.         f->u.streams_blocked.bidi =
  784.                               (f->type == NGX_QUIC_FT_STREAMS_BLOCKED) ? 1 : 0;
  785.         break;

  786.     case NGX_QUIC_FT_MAX_STREAMS:
  787.     case NGX_QUIC_FT_MAX_STREAMS2:

  788.         p = ngx_quic_parse_int(p, end, &f->u.max_streams.limit);
  789.         if (p == NULL) {
  790.             goto error;
  791.         }

  792.         if (f->u.max_streams.limit > 0x1000000000000000) {
  793.             goto error;
  794.         }

  795.         f->u.max_streams.bidi = (f->type == NGX_QUIC_FT_MAX_STREAMS) ? 1 : 0;

  796.         break;

  797.     case NGX_QUIC_FT_MAX_STREAM_DATA:

  798.         p = ngx_quic_parse_int(p, end, &f->u.max_stream_data.id);
  799.         if (p == NULL) {
  800.             goto error;
  801.         }

  802.         p = ngx_quic_parse_int(p, end, &f->u.max_stream_data.limit);
  803.         if (p == NULL) {
  804.             goto error;
  805.         }

  806.         break;

  807.     case NGX_QUIC_FT_DATA_BLOCKED:

  808.         p = ngx_quic_parse_int(p, end, &f->u.data_blocked.limit);
  809.         if (p == NULL) {
  810.             goto error;
  811.         }

  812.         break;

  813.     case NGX_QUIC_FT_STREAM_DATA_BLOCKED:

  814.         p = ngx_quic_parse_int(p, end, &f->u.stream_data_blocked.id);
  815.         if (p == NULL) {
  816.             goto error;
  817.         }

  818.         p = ngx_quic_parse_int(p, end, &f->u.stream_data_blocked.limit);
  819.         if (p == NULL) {
  820.             goto error;
  821.         }

  822.         break;

  823.     case NGX_QUIC_FT_PATH_CHALLENGE:

  824.         p = ngx_quic_copy_bytes(p, end, 8, f->u.path_challenge.data);
  825.         if (p == NULL) {
  826.             goto error;
  827.         }

  828.         break;

  829.     case NGX_QUIC_FT_PATH_RESPONSE:

  830.         p = ngx_quic_copy_bytes(p, end, 8, f->u.path_response.data);
  831.         if (p == NULL) {
  832.             goto error;
  833.         }

  834.         break;

  835.     default:
  836.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  837.                       "quic unknown frame type 0x%xi", f->type);
  838.         return NGX_ERROR;
  839.     }

  840.     f->level = pkt->level;
  841. #if (NGX_DEBUG)
  842.     f->pnum = pkt->pn;
  843. #endif

  844.     return p - start;

  845. error:

  846.     pkt->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;

  847.     ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  848.                   "quic failed to parse frame type:0x%xi", f->type);

  849.     return NGX_ERROR;
  850. }


  851. static ngx_int_t
  852. ngx_quic_frame_allowed(ngx_quic_header_t *pkt, ngx_uint_t frame_type)
  853. {
  854.     uint8_t  ptype;

  855.     /*
  856.      * RFC 9000, 12.4. Frames and Frame Types: Table 3
  857.      *
  858.      * Frame permissions per packet: 4 bits: IH01
  859.      */
  860.     static uint8_t ngx_quic_frame_masks[] = {
  861.          /* PADDING  */              0xF,
  862.          /* PING */                  0xF,
  863.          /* ACK */                   0xD,
  864.          /* ACK_ECN */               0xD,
  865.          /* RESET_STREAM */          0x3,
  866.          /* STOP_SENDING */          0x3,
  867.          /* CRYPTO */                0xD,
  868.          /* NEW_TOKEN */             0x0, /* only sent by server */
  869.          /* STREAM */                0x3,
  870.          /* STREAM1 */               0x3,
  871.          /* STREAM2 */               0x3,
  872.          /* STREAM3 */               0x3,
  873.          /* STREAM4 */               0x3,
  874.          /* STREAM5 */               0x3,
  875.          /* STREAM6 */               0x3,
  876.          /* STREAM7 */               0x3,
  877.          /* MAX_DATA */              0x3,
  878.          /* MAX_STREAM_DATA */       0x3,
  879.          /* MAX_STREAMS */           0x3,
  880.          /* MAX_STREAMS2 */          0x3,
  881.          /* DATA_BLOCKED */          0x3,
  882.          /* STREAM_DATA_BLOCKED */   0x3,
  883.          /* STREAMS_BLOCKED */       0x3,
  884.          /* STREAMS_BLOCKED2 */      0x3,
  885.          /* NEW_CONNECTION_ID */     0x3,
  886.          /* RETIRE_CONNECTION_ID */  0x3,
  887.          /* PATH_CHALLENGE */        0x3,
  888.          /* PATH_RESPONSE */         0x1,
  889.          /* CONNECTION_CLOSE */      0xF,
  890.          /* CONNECTION_CLOSE2 */     0x3,
  891.          /* HANDSHAKE_DONE */        0x0, /* only sent by server */
  892.     };

  893.     if (ngx_quic_long_pkt(pkt->flags)) {

  894.         if (ngx_quic_pkt_in(pkt->flags)) {
  895.             ptype = 8; /* initial */

  896.         } else if (ngx_quic_pkt_hs(pkt->flags)) {
  897.             ptype = 4; /* handshake */

  898.         } else {
  899.             ptype = 2; /* zero-rtt */
  900.         }

  901.     } else {
  902.         ptype = 1; /* application data */
  903.     }

  904.     if (ptype & ngx_quic_frame_masks[frame_type]) {
  905.         return NGX_OK;
  906.     }

  907.     ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  908.                   "quic frame type 0x%xi is not "
  909.                   "allowed in packet with flags 0x%xd",
  910.                   frame_type, pkt->flags);

  911.     return NGX_DECLINED;
  912. }


  913. ssize_t
  914. ngx_quic_parse_ack_range(ngx_log_t *log, u_char *start, u_char *end,
  915.     uint64_t *gap, uint64_t *range)
  916. {
  917.     u_char  *p;

  918.     p = start;

  919.     p = ngx_quic_parse_int(p, end, gap);
  920.     if (p == NULL) {
  921.         ngx_log_error(NGX_LOG_INFO, log, 0,
  922.                       "quic failed to parse ack frame gap");
  923.         return NGX_ERROR;
  924.     }

  925.     p = ngx_quic_parse_int(p, end, range);
  926.     if (p == NULL) {
  927.         ngx_log_error(NGX_LOG_INFO, log, 0,
  928.                       "quic failed to parse ack frame range");
  929.         return NGX_ERROR;
  930.     }

  931.     return p - start;
  932. }


  933. size_t
  934. ngx_quic_create_ack_range(u_char *p, uint64_t gap, uint64_t range)
  935. {
  936.     size_t   len;
  937.     u_char  *start;

  938.     if (p == NULL) {
  939.         len = ngx_quic_varint_len(gap);
  940.         len += ngx_quic_varint_len(range);
  941.         return len;
  942.     }

  943.     start = p;

  944.     ngx_quic_build_int(&p, gap);
  945.     ngx_quic_build_int(&p, range);

  946.     return p - start;
  947. }


  948. ssize_t
  949. ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f)
  950. {
  951.     /*
  952.      *  RFC 9002, 2.  Conventions and Definitions
  953.      *
  954.      *  Ack-eliciting frames:  All frames other than ACK, PADDING, and
  955.      *  CONNECTION_CLOSE are considered ack-eliciting.
  956.      */
  957.     f->need_ack = 1;

  958.     switch (f->type) {
  959.     case NGX_QUIC_FT_PING:
  960.         return ngx_quic_create_ping(p);

  961.     case NGX_QUIC_FT_ACK:
  962.         f->need_ack = 0;
  963.         return ngx_quic_create_ack(p, &f->u.ack, f->data);

  964.     case NGX_QUIC_FT_RESET_STREAM:
  965.         return ngx_quic_create_reset_stream(p, &f->u.reset_stream);

  966.     case NGX_QUIC_FT_STOP_SENDING:
  967.         return ngx_quic_create_stop_sending(p, &f->u.stop_sending);

  968.     case NGX_QUIC_FT_CRYPTO:
  969.         return ngx_quic_create_crypto(p, &f->u.crypto, f->data);

  970.     case NGX_QUIC_FT_HANDSHAKE_DONE:
  971.         return ngx_quic_create_hs_done(p);

  972.     case NGX_QUIC_FT_NEW_TOKEN:
  973.         return ngx_quic_create_new_token(p, &f->u.token, f->data);

  974.     case NGX_QUIC_FT_STREAM:
  975.         return ngx_quic_create_stream(p, &f->u.stream, f->data);

  976.     case NGX_QUIC_FT_CONNECTION_CLOSE:
  977.     case NGX_QUIC_FT_CONNECTION_CLOSE_APP:
  978.         f->need_ack = 0;
  979.         return ngx_quic_create_close(p, f);

  980.     case NGX_QUIC_FT_MAX_STREAMS:
  981.         return ngx_quic_create_max_streams(p, &f->u.max_streams);

  982.     case NGX_QUIC_FT_MAX_STREAM_DATA:
  983.         return ngx_quic_create_max_stream_data(p, &f->u.max_stream_data);

  984.     case NGX_QUIC_FT_MAX_DATA:
  985.         return ngx_quic_create_max_data(p, &f->u.max_data);

  986.     case NGX_QUIC_FT_PATH_CHALLENGE:
  987.         return ngx_quic_create_path_challenge(p, &f->u.path_challenge);

  988.     case NGX_QUIC_FT_PATH_RESPONSE:
  989.         return ngx_quic_create_path_response(p, &f->u.path_response);

  990.     case NGX_QUIC_FT_NEW_CONNECTION_ID:
  991.         return ngx_quic_create_new_connection_id(p, &f->u.ncid);

  992.     case NGX_QUIC_FT_RETIRE_CONNECTION_ID:
  993.         return ngx_quic_create_retire_connection_id(p, &f->u.retire_cid);

  994.     default:
  995.         /* BUG: unsupported frame type generated */
  996.         return NGX_ERROR;
  997.     }
  998. }


  999. static size_t
  1000. ngx_quic_create_ping(u_char *p)
  1001. {
  1002.     u_char  *start;

  1003.     if (p == NULL) {
  1004.         return ngx_quic_varint_len(NGX_QUIC_FT_PING);
  1005.     }

  1006.     start = p;

  1007.     ngx_quic_build_int(&p, NGX_QUIC_FT_PING);

  1008.     return p - start;
  1009. }


  1010. static size_t
  1011. ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack, ngx_chain_t *ranges)
  1012. {
  1013.     size_t      len;
  1014.     u_char     *start;
  1015.     ngx_buf_t  *b;

  1016.     if (p == NULL) {
  1017.         len = ngx_quic_varint_len(NGX_QUIC_FT_ACK);
  1018.         len += ngx_quic_varint_len(ack->largest);
  1019.         len += ngx_quic_varint_len(ack->delay);
  1020.         len += ngx_quic_varint_len(ack->range_count);
  1021.         len += ngx_quic_varint_len(ack->first_range);
  1022.         len += ack->ranges_length;

  1023.         return len;
  1024.     }

  1025.     start = p;

  1026.     ngx_quic_build_int(&p, NGX_QUIC_FT_ACK);
  1027.     ngx_quic_build_int(&p, ack->largest);
  1028.     ngx_quic_build_int(&p, ack->delay);
  1029.     ngx_quic_build_int(&p, ack->range_count);
  1030.     ngx_quic_build_int(&p, ack->first_range);

  1031.     while (ranges) {
  1032.         b = ranges->buf;
  1033.         p = ngx_cpymem(p, b->pos, b->last - b->pos);
  1034.         ranges = ranges->next;
  1035.     }

  1036.     return p - start;
  1037. }


  1038. static size_t
  1039. ngx_quic_create_reset_stream(u_char *p, ngx_quic_reset_stream_frame_t *rs)
  1040. {
  1041.     size_t   len;
  1042.     u_char  *start;

  1043.     if (p == NULL) {
  1044.         len = ngx_quic_varint_len(NGX_QUIC_FT_RESET_STREAM);
  1045.         len += ngx_quic_varint_len(rs->id);
  1046.         len += ngx_quic_varint_len(rs->error_code);
  1047.         len += ngx_quic_varint_len(rs->final_size);
  1048.         return len;
  1049.     }

  1050.     start = p;

  1051.     ngx_quic_build_int(&p, NGX_QUIC_FT_RESET_STREAM);
  1052.     ngx_quic_build_int(&p, rs->id);
  1053.     ngx_quic_build_int(&p, rs->error_code);
  1054.     ngx_quic_build_int(&p, rs->final_size);

  1055.     return p - start;
  1056. }


  1057. static size_t
  1058. ngx_quic_create_stop_sending(u_char *p, ngx_quic_stop_sending_frame_t *ss)
  1059. {
  1060.     size_t   len;
  1061.     u_char  *start;

  1062.     if (p == NULL) {
  1063.         len = ngx_quic_varint_len(NGX_QUIC_FT_STOP_SENDING);
  1064.         len += ngx_quic_varint_len(ss->id);
  1065.         len += ngx_quic_varint_len(ss->error_code);
  1066.         return len;
  1067.     }

  1068.     start = p;

  1069.     ngx_quic_build_int(&p, NGX_QUIC_FT_STOP_SENDING);
  1070.     ngx_quic_build_int(&p, ss->id);
  1071.     ngx_quic_build_int(&p, ss->error_code);

  1072.     return p - start;
  1073. }


  1074. static size_t
  1075. ngx_quic_create_crypto(u_char *p, ngx_quic_crypto_frame_t *crypto,
  1076.     ngx_chain_t *data)
  1077. {
  1078.     size_t      len;
  1079.     u_char     *start;
  1080.     ngx_buf_t  *b;

  1081.     if (p == NULL) {
  1082.         len = ngx_quic_varint_len(NGX_QUIC_FT_CRYPTO);
  1083.         len += ngx_quic_varint_len(crypto->offset);
  1084.         len += ngx_quic_varint_len(crypto->length);
  1085.         len += crypto->length;

  1086.         return len;
  1087.     }

  1088.     start = p;

  1089.     ngx_quic_build_int(&p, NGX_QUIC_FT_CRYPTO);
  1090.     ngx_quic_build_int(&p, crypto->offset);
  1091.     ngx_quic_build_int(&p, crypto->length);

  1092.     while (data) {
  1093.         b = data->buf;
  1094.         p = ngx_cpymem(p, b->pos, b->last - b->pos);
  1095.         data = data->next;
  1096.     }

  1097.     return p - start;
  1098. }


  1099. static size_t
  1100. ngx_quic_create_hs_done(u_char *p)
  1101. {
  1102.     u_char  *start;

  1103.     if (p == NULL) {
  1104.         return ngx_quic_varint_len(NGX_QUIC_FT_HANDSHAKE_DONE);
  1105.     }

  1106.     start = p;

  1107.     ngx_quic_build_int(&p, NGX_QUIC_FT_HANDSHAKE_DONE);

  1108.     return p - start;
  1109. }


  1110. static size_t
  1111. ngx_quic_create_new_token(u_char *p, ngx_quic_new_token_frame_t *token,
  1112.     ngx_chain_t *data)
  1113. {
  1114.     size_t      len;
  1115.     u_char     *start;
  1116.     ngx_buf_t  *b;

  1117.     if (p == NULL) {
  1118.         len = ngx_quic_varint_len(NGX_QUIC_FT_NEW_TOKEN);
  1119.         len += ngx_quic_varint_len(token->length);
  1120.         len += token->length;

  1121.         return len;
  1122.     }

  1123.     start = p;

  1124.     ngx_quic_build_int(&p, NGX_QUIC_FT_NEW_TOKEN);
  1125.     ngx_quic_build_int(&p, token->length);

  1126.     while (data) {
  1127.         b = data->buf;
  1128.         p = ngx_cpymem(p, b->pos, b->last - b->pos);
  1129.         data = data->next;
  1130.     }

  1131.     return p - start;
  1132. }


  1133. static size_t
  1134. ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf,
  1135.     ngx_chain_t *data)
  1136. {
  1137.     size_t      len;
  1138.     u_char     *start, type;
  1139.     ngx_buf_t  *b;

  1140.     type = NGX_QUIC_FT_STREAM;

  1141.     if (sf->off) {
  1142.         type |= NGX_QUIC_STREAM_FRAME_OFF;
  1143.     }

  1144.     if (sf->len) {
  1145.         type |= NGX_QUIC_STREAM_FRAME_LEN;
  1146.     }

  1147.     if (sf->fin) {
  1148.         type |= NGX_QUIC_STREAM_FRAME_FIN;
  1149.     }

  1150.     if (p == NULL) {
  1151.         len = ngx_quic_varint_len(type);
  1152.         len += ngx_quic_varint_len(sf->stream_id);

  1153.         if (sf->off) {
  1154.             len += ngx_quic_varint_len(sf->offset);
  1155.         }

  1156.         if (sf->len) {
  1157.             len += ngx_quic_varint_len(sf->length);
  1158.         }

  1159.         len += sf->length;

  1160.         return len;
  1161.     }

  1162.     start = p;

  1163.     ngx_quic_build_int(&p, type);
  1164.     ngx_quic_build_int(&p, sf->stream_id);

  1165.     if (sf->off) {
  1166.         ngx_quic_build_int(&p, sf->offset);
  1167.     }

  1168.     if (sf->len) {
  1169.         ngx_quic_build_int(&p, sf->length);
  1170.     }

  1171.     while (data) {
  1172.         b = data->buf;
  1173.         p = ngx_cpymem(p, b->pos, b->last - b->pos);
  1174.         data = data->next;
  1175.     }

  1176.     return p - start;
  1177. }


  1178. static size_t
  1179. ngx_quic_create_max_streams(u_char *p, ngx_quic_max_streams_frame_t *ms)
  1180. {
  1181.     size_t       len;
  1182.     u_char      *start;
  1183.     ngx_uint_t   type;

  1184.     type = ms->bidi ? NGX_QUIC_FT_MAX_STREAMS : NGX_QUIC_FT_MAX_STREAMS2;

  1185.     if (p == NULL) {
  1186.         len = ngx_quic_varint_len(type);
  1187.         len += ngx_quic_varint_len(ms->limit);
  1188.         return len;
  1189.     }

  1190.     start = p;

  1191.     ngx_quic_build_int(&p, type);
  1192.     ngx_quic_build_int(&p, ms->limit);

  1193.     return p - start;
  1194. }


  1195. static ngx_int_t
  1196. ngx_quic_parse_transport_param(u_char *p, u_char *end, uint16_t id,
  1197.     ngx_quic_tp_t *dst)
  1198. {
  1199.     uint64_t   varint;
  1200.     ngx_str_t  str;

  1201.     varint = 0;
  1202.     ngx_str_null(&str);

  1203.     switch (id) {

  1204.     case NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION:
  1205.         /* zero-length option */
  1206.         if (end - p != 0) {
  1207.             return NGX_ERROR;
  1208.         }
  1209.         dst->disable_active_migration = 1;
  1210.         return NGX_OK;

  1211.     case NGX_QUIC_TP_MAX_IDLE_TIMEOUT:
  1212.     case NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
  1213.     case NGX_QUIC_TP_INITIAL_MAX_DATA:
  1214.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
  1215.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
  1216.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
  1217.     case NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
  1218.     case NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI:
  1219.     case NGX_QUIC_TP_ACK_DELAY_EXPONENT:
  1220.     case NGX_QUIC_TP_MAX_ACK_DELAY:
  1221.     case NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:

  1222.         p = ngx_quic_parse_int(p, end, &varint);
  1223.         if (p == NULL) {
  1224.             return NGX_ERROR;
  1225.         }
  1226.         break;

  1227.     case NGX_QUIC_TP_INITIAL_SCID:

  1228.         str.len = end - p;
  1229.         str.data = p;
  1230.         break;

  1231.     default:
  1232.         return NGX_DECLINED;
  1233.     }

  1234.     switch (id) {

  1235.     case NGX_QUIC_TP_MAX_IDLE_TIMEOUT:
  1236.         dst->max_idle_timeout = varint;
  1237.         break;

  1238.     case NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
  1239.         dst->max_udp_payload_size = varint;
  1240.         break;

  1241.     case NGX_QUIC_TP_INITIAL_MAX_DATA:
  1242.         dst->initial_max_data = varint;
  1243.         break;

  1244.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
  1245.         dst->initial_max_stream_data_bidi_local = varint;
  1246.         break;

  1247.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
  1248.         dst->initial_max_stream_data_bidi_remote = varint;
  1249.         break;

  1250.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
  1251.         dst->initial_max_stream_data_uni = varint;
  1252.         break;

  1253.     case NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
  1254.         dst->initial_max_streams_bidi = varint;
  1255.         break;

  1256.     case NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI:
  1257.         dst->initial_max_streams_uni = varint;
  1258.         break;

  1259.     case NGX_QUIC_TP_ACK_DELAY_EXPONENT:
  1260.         dst->ack_delay_exponent = varint;
  1261.         break;

  1262.     case NGX_QUIC_TP_MAX_ACK_DELAY:
  1263.         dst->max_ack_delay = varint;
  1264.         break;

  1265.     case NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
  1266.         dst->active_connection_id_limit = varint;
  1267.         break;

  1268.     case NGX_QUIC_TP_INITIAL_SCID:
  1269.         dst->initial_scid = str;
  1270.         break;

  1271.     default:
  1272.         return NGX_ERROR;
  1273.     }

  1274.     return NGX_OK;
  1275. }


  1276. ngx_int_t
  1277. ngx_quic_parse_transport_params(u_char *p, u_char *end, ngx_quic_tp_t *tp,
  1278.     ngx_log_t *log)
  1279. {
  1280.     uint64_t   id, len;
  1281.     ngx_int_t  rc;

  1282.     while (p < end) {
  1283.         p = ngx_quic_parse_int(p, end, &id);
  1284.         if (p == NULL) {
  1285.             ngx_log_error(NGX_LOG_INFO, log, 0,
  1286.                           "quic failed to parse transport param id");
  1287.             return NGX_ERROR;
  1288.         }

  1289.         switch (id) {
  1290.         case NGX_QUIC_TP_ORIGINAL_DCID:
  1291.         case NGX_QUIC_TP_PREFERRED_ADDRESS:
  1292.         case NGX_QUIC_TP_RETRY_SCID:
  1293.         case NGX_QUIC_TP_SR_TOKEN:
  1294.             ngx_log_error(NGX_LOG_INFO, log, 0,
  1295.                           "quic client sent forbidden transport param"
  1296.                           " id:0x%xL", id);
  1297.             return NGX_ERROR;
  1298.         }

  1299.         p = ngx_quic_parse_int(p, end, &len);
  1300.         if (p == NULL) {
  1301.             ngx_log_error(NGX_LOG_INFO, log, 0,
  1302.                           "quic failed to parse"
  1303.                           " transport param id:0x%xL length", id);
  1304.             return NGX_ERROR;
  1305.         }

  1306.         if ((size_t) (end - p) < len) {
  1307.             ngx_log_error(NGX_LOG_INFO, log, 0,
  1308.                           "quic failed to parse"
  1309.                           " transport param id:0x%xL, data length %uL too long",
  1310.                           id, len);
  1311.             return NGX_ERROR;
  1312.         }

  1313.         rc = ngx_quic_parse_transport_param(p, p + len, id, tp);

  1314.         if (rc == NGX_ERROR) {
  1315.             ngx_log_error(NGX_LOG_INFO, log, 0,
  1316.                           "quic failed to parse"
  1317.                           " transport param id:0x%xL data", id);
  1318.             return NGX_ERROR;
  1319.         }

  1320.         if (rc == NGX_DECLINED) {
  1321.             ngx_log_error(NGX_LOG_INFO, log, 0,
  1322.                           "quic %s transport param id:0x%xL, skipped",
  1323.                           (id % 31 == 27) ? "reserved" : "unknown", id);
  1324.         }

  1325.         p += len;
  1326.     }

  1327.     if (p != end) {
  1328.         ngx_log_error(NGX_LOG_INFO, log, 0,
  1329.                       "quic trailing garbage in"
  1330.                       " transport parameters: bytes:%ui",
  1331.                       end - p);
  1332.         return NGX_ERROR;
  1333.     }

  1334.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, log, 0,
  1335.                    "quic transport parameters parsed ok");

  1336.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1337.                    "quic tp disable active migration: %ui",
  1338.                    tp->disable_active_migration);

  1339.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "quic tp idle_timeout:%ui",
  1340.                    tp->max_idle_timeout);

  1341.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1342.                    "quic tp max_udp_payload_size:%ui",
  1343.                    tp->max_udp_payload_size);

  1344.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "quic tp max_data:%ui",
  1345.                    tp->initial_max_data);

  1346.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1347.                    "quic tp max_stream_data_bidi_local:%ui",
  1348.                    tp->initial_max_stream_data_bidi_local);

  1349.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1350.                    "quic tp max_stream_data_bidi_remote:%ui",
  1351.                    tp->initial_max_stream_data_bidi_remote);

  1352.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1353.                    "quic tp max_stream_data_uni:%ui",
  1354.                    tp->initial_max_stream_data_uni);

  1355.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1356.                    "quic tp initial_max_streams_bidi:%ui",
  1357.                    tp->initial_max_streams_bidi);

  1358.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1359.                    "quic tp initial_max_streams_uni:%ui",
  1360.                    tp->initial_max_streams_uni);

  1361.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1362.                    "quic tp ack_delay_exponent:%ui",
  1363.                    tp->ack_delay_exponent);

  1364.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "quic tp max_ack_delay:%ui",
  1365.                    tp->max_ack_delay);

  1366.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1367.                    "quic tp active_connection_id_limit:%ui",
  1368.                    tp->active_connection_id_limit);

  1369.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
  1370.                    "quic tp initial source_connection_id len:%uz %xV",
  1371.                    tp->initial_scid.len, &tp->initial_scid);

  1372.     return NGX_OK;
  1373. }


  1374. static size_t
  1375. ngx_quic_create_max_stream_data(u_char *p, ngx_quic_max_stream_data_frame_t *ms)
  1376. {
  1377.     size_t   len;
  1378.     u_char  *start;

  1379.     if (p == NULL) {
  1380.         len = ngx_quic_varint_len(NGX_QUIC_FT_MAX_STREAM_DATA);
  1381.         len += ngx_quic_varint_len(ms->id);
  1382.         len += ngx_quic_varint_len(ms->limit);
  1383.         return len;
  1384.     }

  1385.     start = p;

  1386.     ngx_quic_build_int(&p, NGX_QUIC_FT_MAX_STREAM_DATA);
  1387.     ngx_quic_build_int(&p, ms->id);
  1388.     ngx_quic_build_int(&p, ms->limit);

  1389.     return p - start;
  1390. }


  1391. static size_t
  1392. ngx_quic_create_max_data(u_char *p, ngx_quic_max_data_frame_t *md)
  1393. {
  1394.     size_t   len;
  1395.     u_char  *start;

  1396.     if (p == NULL) {
  1397.         len = ngx_quic_varint_len(NGX_QUIC_FT_MAX_DATA);
  1398.         len += ngx_quic_varint_len(md->max_data);
  1399.         return len;
  1400.     }

  1401.     start = p;

  1402.     ngx_quic_build_int(&p, NGX_QUIC_FT_MAX_DATA);
  1403.     ngx_quic_build_int(&p, md->max_data);

  1404.     return p - start;
  1405. }


  1406. static size_t
  1407. ngx_quic_create_path_challenge(u_char *p, ngx_quic_path_challenge_frame_t *pc)
  1408. {
  1409.     size_t   len;
  1410.     u_char  *start;

  1411.     if (p == NULL) {
  1412.         len = ngx_quic_varint_len(NGX_QUIC_FT_PATH_CHALLENGE);
  1413.         len += sizeof(pc->data);
  1414.         return len;
  1415.     }

  1416.     start = p;

  1417.     ngx_quic_build_int(&p, NGX_QUIC_FT_PATH_CHALLENGE);
  1418.     p = ngx_cpymem(p, &pc->data, sizeof(pc->data));

  1419.     return p - start;
  1420. }


  1421. static size_t
  1422. ngx_quic_create_path_response(u_char *p, ngx_quic_path_challenge_frame_t *pc)
  1423. {
  1424.     size_t   len;
  1425.     u_char  *start;

  1426.     if (p == NULL) {
  1427.         len = ngx_quic_varint_len(NGX_QUIC_FT_PATH_RESPONSE);
  1428.         len += sizeof(pc->data);
  1429.         return len;
  1430.     }

  1431.     start = p;

  1432.     ngx_quic_build_int(&p, NGX_QUIC_FT_PATH_RESPONSE);
  1433.     p = ngx_cpymem(p, &pc->data, sizeof(pc->data));

  1434.     return p - start;
  1435. }


  1436. static size_t
  1437. ngx_quic_create_new_connection_id(u_char *p, ngx_quic_new_conn_id_frame_t *ncid)
  1438. {
  1439.     size_t   len;
  1440.     u_char  *start;

  1441.     if (p == NULL) {
  1442.         len = ngx_quic_varint_len(NGX_QUIC_FT_NEW_CONNECTION_ID);
  1443.         len += ngx_quic_varint_len(ncid->seqnum);
  1444.         len += ngx_quic_varint_len(ncid->retire);
  1445.         len++;
  1446.         len += ncid->len;
  1447.         len += NGX_QUIC_SR_TOKEN_LEN;
  1448.         return len;
  1449.     }

  1450.     start = p;

  1451.     ngx_quic_build_int(&p, NGX_QUIC_FT_NEW_CONNECTION_ID);
  1452.     ngx_quic_build_int(&p, ncid->seqnum);
  1453.     ngx_quic_build_int(&p, ncid->retire);
  1454.     *p++ = ncid->len;
  1455.     p = ngx_cpymem(p, ncid->cid, ncid->len);
  1456.     p = ngx_cpymem(p, ncid->srt, NGX_QUIC_SR_TOKEN_LEN);

  1457.     return p - start;
  1458. }


  1459. static size_t
  1460. ngx_quic_create_retire_connection_id(u_char *p,
  1461.     ngx_quic_retire_cid_frame_t *rcid)
  1462. {
  1463.     size_t   len;
  1464.     u_char  *start;

  1465.     if (p == NULL) {
  1466.         len = ngx_quic_varint_len(NGX_QUIC_FT_RETIRE_CONNECTION_ID);
  1467.         len += ngx_quic_varint_len(rcid->sequence_number);
  1468.         return len;
  1469.     }

  1470.     start = p;

  1471.     ngx_quic_build_int(&p, NGX_QUIC_FT_RETIRE_CONNECTION_ID);
  1472.     ngx_quic_build_int(&p, rcid->sequence_number);

  1473.     return p - start;
  1474. }


  1475. ngx_int_t
  1476. ngx_quic_init_transport_params(ngx_quic_tp_t *tp, ngx_quic_conf_t *qcf)
  1477. {
  1478.     ngx_uint_t  nstreams;

  1479.     ngx_memzero(tp, sizeof(ngx_quic_tp_t));

  1480.     /*
  1481.      * set by ngx_memzero():
  1482.      *
  1483.      *     tp->disable_active_migration = 0;
  1484.      *     tp->original_dcid = { 0, NULL };
  1485.      *     tp->initial_scid = { 0, NULL };
  1486.      *     tp->retry_scid = { 0, NULL };
  1487.      *     tp->sr_token = { 0 }
  1488.      *     tp->sr_enabled = 0
  1489.      *     tp->preferred_address = NULL
  1490.      */

  1491.     tp->max_idle_timeout = qcf->idle_timeout;

  1492.     tp->max_udp_payload_size = NGX_QUIC_MAX_UDP_PAYLOAD_SIZE;

  1493.     nstreams = qcf->max_concurrent_streams_bidi
  1494.                + qcf->max_concurrent_streams_uni;

  1495.     tp->initial_max_data = nstreams * qcf->stream_buffer_size;
  1496.     tp->initial_max_stream_data_bidi_local = qcf->stream_buffer_size;
  1497.     tp->initial_max_stream_data_bidi_remote = qcf->stream_buffer_size;
  1498.     tp->initial_max_stream_data_uni = qcf->stream_buffer_size;

  1499.     tp->initial_max_streams_bidi = qcf->max_concurrent_streams_bidi;
  1500.     tp->initial_max_streams_uni = qcf->max_concurrent_streams_uni;

  1501.     tp->max_ack_delay = NGX_QUIC_DEFAULT_MAX_ACK_DELAY;
  1502.     tp->ack_delay_exponent = NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT;

  1503.     tp->active_connection_id_limit = qcf->active_connection_id_limit;
  1504.     tp->disable_active_migration = qcf->disable_active_migration;

  1505.     return NGX_OK;
  1506. }


  1507. ssize_t
  1508. ngx_quic_create_transport_params(u_char *pos, u_char *end, ngx_quic_tp_t *tp,
  1509.     size_t *clen)
  1510. {
  1511.     u_char  *p;
  1512.     size_t   len;

  1513. #define ngx_quic_tp_len(id, value)                                            \
  1514.     ngx_quic_varint_len(id)                                                   \
  1515.     + ngx_quic_varint_len(value)                                              \
  1516.     + ngx_quic_varint_len(ngx_quic_varint_len(value))

  1517. #define ngx_quic_tp_vint(id, value)                                           \
  1518.     do {                                                                      \
  1519.         ngx_quic_build_int(&p, id);                                           \
  1520.         ngx_quic_build_int(&p, ngx_quic_varint_len(value));                   \
  1521.         ngx_quic_build_int(&p, value);                                        \
  1522.     } while (0)

  1523. #define ngx_quic_tp_strlen(id, value)                                         \
  1524.     ngx_quic_varint_len(id)                                                   \
  1525.     + ngx_quic_varint_len(value.len)                                          \
  1526.     + value.len

  1527. #define ngx_quic_tp_str(id, value)                                            \
  1528.     do {                                                                      \
  1529.         ngx_quic_build_int(&p, id);                                           \
  1530.         ngx_quic_build_int(&p, value.len);                                    \
  1531.         p = ngx_cpymem(p, value.data, value.len);                             \
  1532.     } while (0)

  1533.     len = ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_DATA, tp->initial_max_data);

  1534.     len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI,
  1535.                            tp->initial_max_streams_uni);

  1536.     len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
  1537.                            tp->initial_max_streams_bidi);

  1538.     len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
  1539.                            tp->initial_max_stream_data_bidi_local);

  1540.     len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
  1541.                            tp->initial_max_stream_data_bidi_remote);

  1542.     len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
  1543.                            tp->initial_max_stream_data_uni);

  1544.     len += ngx_quic_tp_len(NGX_QUIC_TP_MAX_IDLE_TIMEOUT,
  1545.                            tp->max_idle_timeout);

  1546.     len += ngx_quic_tp_len(NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE,
  1547.                            tp->max_udp_payload_size);

  1548.     if (tp->disable_active_migration) {
  1549.         len += ngx_quic_varint_len(NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION);
  1550.         len += ngx_quic_varint_len(0);
  1551.     }

  1552.     len += ngx_quic_tp_len(NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
  1553.                            tp->active_connection_id_limit);

  1554.     /* transport parameters listed above will be saved in 0-RTT context */
  1555.     if (clen) {
  1556.         *clen = len;
  1557.     }

  1558.     len += ngx_quic_tp_len(NGX_QUIC_TP_MAX_ACK_DELAY,
  1559.                            tp->max_ack_delay);

  1560.     len += ngx_quic_tp_len(NGX_QUIC_TP_ACK_DELAY_EXPONENT,
  1561.                            tp->ack_delay_exponent);

  1562.     len += ngx_quic_tp_strlen(NGX_QUIC_TP_ORIGINAL_DCID, tp->original_dcid);
  1563.     len += ngx_quic_tp_strlen(NGX_QUIC_TP_INITIAL_SCID, tp->initial_scid);

  1564.     if (tp->retry_scid.len) {
  1565.         len += ngx_quic_tp_strlen(NGX_QUIC_TP_RETRY_SCID, tp->retry_scid);
  1566.     }

  1567.     len += ngx_quic_varint_len(NGX_QUIC_TP_SR_TOKEN);
  1568.     len += ngx_quic_varint_len(NGX_QUIC_SR_TOKEN_LEN);
  1569.     len += NGX_QUIC_SR_TOKEN_LEN;

  1570.     if (pos == NULL) {
  1571.         return len;
  1572.     }

  1573.     p = pos;

  1574.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_DATA,
  1575.                      tp->initial_max_data);

  1576.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI,
  1577.                      tp->initial_max_streams_uni);

  1578.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
  1579.                      tp->initial_max_streams_bidi);

  1580.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
  1581.                      tp->initial_max_stream_data_bidi_local);

  1582.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
  1583.                      tp->initial_max_stream_data_bidi_remote);

  1584.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
  1585.                      tp->initial_max_stream_data_uni);

  1586.     ngx_quic_tp_vint(NGX_QUIC_TP_MAX_IDLE_TIMEOUT,
  1587.                      tp->max_idle_timeout);

  1588.     ngx_quic_tp_vint(NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE,
  1589.                      tp->max_udp_payload_size);

  1590.     if (tp->disable_active_migration) {
  1591.         ngx_quic_build_int(&p, NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION);
  1592.         ngx_quic_build_int(&p, 0);
  1593.     }

  1594.     ngx_quic_tp_vint(NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
  1595.                      tp->active_connection_id_limit);

  1596.     ngx_quic_tp_vint(NGX_QUIC_TP_MAX_ACK_DELAY,
  1597.                      tp->max_ack_delay);

  1598.     ngx_quic_tp_vint(NGX_QUIC_TP_ACK_DELAY_EXPONENT,
  1599.                      tp->ack_delay_exponent);

  1600.     ngx_quic_tp_str(NGX_QUIC_TP_ORIGINAL_DCID, tp->original_dcid);
  1601.     ngx_quic_tp_str(NGX_QUIC_TP_INITIAL_SCID, tp->initial_scid);

  1602.     if (tp->retry_scid.len) {
  1603.         ngx_quic_tp_str(NGX_QUIC_TP_RETRY_SCID, tp->retry_scid);
  1604.     }

  1605.     ngx_quic_build_int(&p, NGX_QUIC_TP_SR_TOKEN);
  1606.     ngx_quic_build_int(&p, NGX_QUIC_SR_TOKEN_LEN);
  1607.     p = ngx_cpymem(p, tp->sr_token, NGX_QUIC_SR_TOKEN_LEN);

  1608.     return p - pos;
  1609. }


  1610. static size_t
  1611. ngx_quic_create_close(u_char *p, ngx_quic_frame_t *f)
  1612. {
  1613.     size_t                   len;
  1614.     u_char                  *start;
  1615.     ngx_quic_close_frame_t  *cl;

  1616.     cl = &f->u.close;

  1617.     if (p == NULL) {
  1618.         len = ngx_quic_varint_len(f->type);
  1619.         len += ngx_quic_varint_len(cl->error_code);

  1620.         if (f->type != NGX_QUIC_FT_CONNECTION_CLOSE_APP) {
  1621.             len += ngx_quic_varint_len(cl->frame_type);
  1622.         }

  1623.         len += ngx_quic_varint_len(cl->reason.len);
  1624.         len += cl->reason.len;

  1625.         return len;
  1626.     }

  1627.     start = p;

  1628.     ngx_quic_build_int(&p, f->type);
  1629.     ngx_quic_build_int(&p, cl->error_code);

  1630.     if (f->type != NGX_QUIC_FT_CONNECTION_CLOSE_APP) {
  1631.         ngx_quic_build_int(&p, cl->frame_type);
  1632.     }

  1633.     ngx_quic_build_int(&p, cl->reason.len);
  1634.     p = ngx_cpymem(p, cl->reason.data, cl->reason.len);

  1635.     return p - start;
  1636. }


  1637. void
  1638. ngx_quic_dcid_encode_key(u_char *dcid, uint64_t key)
  1639. {
  1640.     (void) ngx_quic_write_uint64(dcid, key);
  1641. }