src/event/quic/ngx_event_quic_transport.c - nginx-1.31.3 nginx/ @ 42f8df65b

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 = NGX_QUIC_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 (pkt->version == 0) {
  225.         /* version negotiation */
  226.         return NGX_ERROR;
  227.     }

  228.     if (!ngx_quic_supported_version(pkt->version)) {
  229.         return NGX_ABORT;
  230.     }

  231.     if (ngx_quic_parse_long_header_v1(pkt) != NGX_OK) {
  232.         return NGX_ERROR;
  233.     }

  234.     return NGX_OK;
  235. }


  236. static ngx_int_t
  237. ngx_quic_parse_short_header(ngx_quic_header_t *pkt, size_t dcid_len)
  238. {
  239.     u_char  *p, *end;

  240.     p = pkt->raw->pos;
  241.     end = pkt->data + pkt->len;

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

  244.     if (!(pkt->flags & NGX_QUIC_PKT_FIXED_BIT)) {
  245.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic fixed bit is not set");
  246.         return NGX_ERROR;
  247.     }

  248.     pkt->dcid.len = dcid_len;

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

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

  256.     return NGX_OK;
  257. }


  258. static ngx_int_t
  259. ngx_quic_parse_long_header(ngx_quic_header_t *pkt)
  260. {
  261.     u_char   *p, *end;
  262.     uint8_t   idlen;

  263.     p = pkt->raw->pos;
  264.     end = pkt->data + pkt->len;

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

  271.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
  272.                    "quic packet rx long flags:%xd version:%xD",
  273.                    pkt->flags, pkt->version);

  274.     if (!(pkt->flags & NGX_QUIC_PKT_FIXED_BIT)) {
  275.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic fixed bit is not set");
  276.         return NGX_ERROR;
  277.     }

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

  284.     if (idlen > NGX_QUIC_CID_LEN_MAX) {
  285.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  286.                       "quic packet dcid is too long");
  287.         return NGX_ERROR;
  288.     }

  289.     pkt->dcid.len = idlen;

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

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

  302.     if (idlen > NGX_QUIC_CID_LEN_MAX) {
  303.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  304.                       "quic packet scid is too long");
  305.         return NGX_ERROR;
  306.     }

  307.     pkt->scid.len = idlen;

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

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

  315.     return NGX_OK;
  316. }


  317. static ngx_int_t
  318. ngx_quic_supported_version(uint32_t version)
  319. {
  320.     ngx_uint_t  i;

  321.     for (i = 0; i < NGX_QUIC_NVERSIONS; i++) {
  322.         if (ngx_quic_versions[i] == version) {
  323.             return 1;
  324.         }
  325.     }

  326.     return 0;
  327. }


  328. static ngx_int_t
  329. ngx_quic_parse_long_header_v1(ngx_quic_header_t *pkt)
  330. {
  331.     u_char    *p, *end;
  332.     uint64_t   varint;

  333.     p = pkt->raw->pos;
  334.     end = pkt->raw->last;

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

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

  337.         if (pkt->len < NGX_QUIC_MIN_INITIAL_SIZE) {
  338.             ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  339.                           "quic UDP datagram is too small for initial packet");
  340.             return NGX_DECLINED;
  341.         }

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

  348.         pkt->token.len = varint;

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

  355.         pkt->level = NGX_QUIC_ENCRYPTION_INITIAL;

  356.     } else if (ngx_quic_pkt_zrtt(pkt->flags)) {
  357.         pkt->level = NGX_QUIC_ENCRYPTION_EARLY_DATA;

  358.     } else if (ngx_quic_pkt_hs(pkt->flags)) {
  359.         pkt->level = NGX_QUIC_ENCRYPTION_HANDSHAKE;

  360.     } else {
  361.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  362.                       "quic bad packet type");
  363.         return NGX_DECLINED;
  364.     }

  365.     p = ngx_quic_parse_int(p, end, &varint);
  366.     if (p == NULL) {
  367.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic bad packet length");
  368.         return NGX_ERROR;
  369.     }

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

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

  378.     pkt->raw->pos = p;
  379.     pkt->len = p + varint - pkt->data;

  380.     return NGX_OK;
  381. }


  382. ngx_int_t
  383. ngx_quic_get_packet_dcid(ngx_log_t *log, u_char *data, size_t n,
  384.     ngx_str_t *dcid)
  385. {
  386.     size_t  len, offset;

  387.     if (n == 0) {
  388.         goto failed;
  389.     }

  390.     if (ngx_quic_long_pkt(*data)) {
  391.         if (n < NGX_QUIC_LONG_DCID_LEN_OFFSET + 1) {
  392.             goto failed;
  393.         }

  394.         len = data[NGX_QUIC_LONG_DCID_LEN_OFFSET];
  395.         offset = NGX_QUIC_LONG_DCID_OFFSET;

  396.     } else {
  397.         len = NGX_QUIC_SERVER_CID_LEN;
  398.         offset = NGX_QUIC_SHORT_DCID_OFFSET;
  399.     }

  400.     if (n < len + offset) {
  401.         goto failed;
  402.     }

  403.     dcid->len = len;
  404.     dcid->data = &data[offset];

  405.     return NGX_OK;

  406. failed:

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

  408.     return NGX_ERROR;
  409. }


  410. size_t
  411. ngx_quic_create_version_negotiation(ngx_quic_header_t *pkt, u_char *out)
  412. {
  413.     u_char      *p, *start;
  414.     ngx_uint_t   i;

  415.     p = start = out;

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

  417.     /*
  418.      * The Version field of a Version Negotiation packet
  419.      * MUST be set to 0x00000000
  420.      */
  421.     p = ngx_quic_write_uint32(p, 0);

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

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

  426.     for (i = 0; i < NGX_QUIC_NVERSIONS; i++) {
  427.         p = ngx_quic_write_uint32(p, ngx_quic_versions[i]);
  428.     }

  429.     return p - start;
  430. }


  431. /* returns the amount of payload quic packet of "pkt_len" size may fit or 0 */
  432. size_t
  433. ngx_quic_payload_size(ngx_quic_header_t *pkt, size_t pkt_len)
  434. {
  435.     size_t  len;

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

  437.         len = 1 + pkt->dcid.len + pkt->num_len + NGX_QUIC_TAG_LEN;
  438.         if (len > pkt_len) {
  439.             return 0;
  440.         }

  441.         return pkt_len - len;
  442.     }

  443.     /* flags, version, dcid and scid with lengths and zero-length token */
  444.     len = 5 + 2 + pkt->dcid.len + pkt->scid.len
  445.           + (pkt->level == NGX_QUIC_ENCRYPTION_INITIAL ? 1 : 0);

  446.     if (len > pkt_len) {
  447.         return 0;
  448.     }

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

  452.     if (len > pkt_len) {
  453.         return 0;
  454.     }

  455.     return pkt_len - len;
  456. }


  457. size_t
  458. ngx_quic_create_header(ngx_quic_header_t *pkt, u_char *out, u_char **pnp)
  459. {
  460.     return ngx_quic_short_pkt(pkt->flags)
  461.            ? ngx_quic_create_short_header(pkt, out, pnp)
  462.            : ngx_quic_create_long_header(pkt, out, pnp);
  463. }


  464. static size_t
  465. ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
  466.     u_char **pnp)
  467. {
  468.     size_t   rem_len;
  469.     u_char  *p, *start;

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

  471.     if (out == NULL) {
  472.         return 5 + 2 + pkt->dcid.len + pkt->scid.len
  473.                + ngx_quic_varint_len(rem_len) + pkt->num_len
  474.                + (pkt->level == NGX_QUIC_ENCRYPTION_INITIAL ? 1 : 0);
  475.     }

  476.     p = start = out;

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

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

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

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

  483.     if (pkt->level == NGX_QUIC_ENCRYPTION_INITIAL) {
  484.         ngx_quic_build_int(&p, 0);
  485.     }

  486.     ngx_quic_build_int(&p, rem_len);

  487.     *pnp = p;

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

  502.     return p - start;
  503. }


  504. static size_t
  505. ngx_quic_create_short_header(ngx_quic_header_t *pkt, u_char *out,
  506.     u_char **pnp)
  507. {
  508.     u_char  *p, *start;

  509.     if (out == NULL) {
  510.         return 1 + pkt->dcid.len + pkt->num_len;
  511.     }

  512.     p = start = out;

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

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

  515.     *pnp = p;

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

  530.     return p - start;
  531. }


  532. size_t
  533. ngx_quic_create_retry_itag(ngx_quic_header_t *pkt, u_char *out,
  534.     u_char **start)
  535. {
  536.     u_char  *p;

  537.     p = out;

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

  540.     *start = p;

  541.     *p++ = 0xff;

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

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

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

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

  548.     return p - out;
  549. }


  550. ssize_t
  551. ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
  552.     ngx_quic_frame_t *f)
  553. {
  554.     u_char      *p;
  555.     uint64_t     varint;
  556.     ngx_buf_t   *b;
  557.     ngx_uint_t   i;

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

  559.     p = start;

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

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

  573.     f->type = varint;

  574.     if (ngx_quic_frame_allowed(pkt, f->type) != NGX_OK) {
  575.         pkt->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION;
  576.         return NGX_ERROR;
  577.     }

  578.     switch (f->type) {

  579.     case NGX_QUIC_FT_CRYPTO:

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

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

  588.         p = ngx_quic_read_bytes(p, end, f->u.crypto.length, &b->pos);
  589.         if (p == NULL) {
  590.             goto error;
  591.         }

  592.         b->last = p;

  593.         break;

  594.     case NGX_QUIC_FT_PADDING:

  595.         while (p < end && *p == NGX_QUIC_FT_PADDING) {
  596.             p++;
  597.         }

  598.         break;

  599.     case NGX_QUIC_FT_ACK:
  600.     case NGX_QUIC_FT_ACK_ECN:

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

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

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

  613.         p = ngx_quic_parse_int(p, end, &f->u.ack.first_range);
  614.         if (p == NULL) {
  615.             goto error;
  616.         }

  617.         b->pos = p;

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

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

  624.             p = ngx_quic_parse_int(p, end, &varint);
  625.             if (p == NULL) {
  626.                 goto error;
  627.             }
  628.         }

  629.         b->last = p;

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

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

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

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

  640.             p = ngx_quic_parse_int(p, end, &f->u.ack.ce);
  641.             if (p == NULL) {
  642.                 goto error;
  643.             }

  644.             ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
  645.                            "quic ACK ECN counters ect0:%uL ect1:%uL ce:%uL",
  646.                            f->u.ack.ect0, f->u.ack.ect1, f->u.ack.ce);
  647.         }

  648.         break;

  649.     case NGX_QUIC_FT_PING:
  650.         break;

  651.     case NGX_QUIC_FT_NEW_CONNECTION_ID:

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

  656.         p = ngx_quic_parse_int(p, end, &f->u.ncid.retire);
  657.         if (p == NULL) {
  658.             goto error;
  659.         }

  660.         if (f->u.ncid.retire > f->u.ncid.seqnum) {
  661.             goto error;
  662.         }

  663.         p = ngx_quic_read_uint8(p, end, &f->u.ncid.len);
  664.         if (p == NULL) {
  665.             goto error;
  666.         }

  667.         if (f->u.ncid.len < 1 || f->u.ncid.len > NGX_QUIC_CID_LEN_MAX) {
  668.             goto error;
  669.         }

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

  674.         p = ngx_quic_copy_bytes(p, end, NGX_QUIC_SR_TOKEN_LEN, f->u.ncid.srt);
  675.         if (p == NULL) {
  676.             goto error;
  677.         }

  678.         break;

  679.     case NGX_QUIC_FT_RETIRE_CONNECTION_ID:

  680.         p = ngx_quic_parse_int(p, end, &f->u.retire_cid.sequence_number);
  681.         if (p == NULL) {
  682.             goto error;
  683.         }

  684.         break;

  685.     case NGX_QUIC_FT_CONNECTION_CLOSE:
  686.     case NGX_QUIC_FT_CONNECTION_CLOSE_APP:

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

  691.         if (f->type == NGX_QUIC_FT_CONNECTION_CLOSE) {
  692.             p = ngx_quic_parse_int(p, end, &f->u.close.frame_type);
  693.             if (p == NULL) {
  694.                 goto error;
  695.             }
  696.         }

  697.         p = ngx_quic_parse_int(p, end, &varint);
  698.         if (p == NULL) {
  699.             goto error;
  700.         }

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

  702.         p = ngx_quic_read_bytes(p, end, f->u.close.reason.len,
  703.                                 &f->u.close.reason.data);
  704.         if (p == NULL) {
  705.             goto error;
  706.         }

  707.         break;

  708.     case NGX_QUIC_FT_STREAM:
  709.     case NGX_QUIC_FT_STREAM1:
  710.     case NGX_QUIC_FT_STREAM2:
  711.     case NGX_QUIC_FT_STREAM3:
  712.     case NGX_QUIC_FT_STREAM4:
  713.     case NGX_QUIC_FT_STREAM5:
  714.     case NGX_QUIC_FT_STREAM6:
  715.     case NGX_QUIC_FT_STREAM7:

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

  717.         p = ngx_quic_parse_int(p, end, &f->u.stream.stream_id);
  718.         if (p == NULL) {
  719.             goto error;
  720.         }

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

  723.             p = ngx_quic_parse_int(p, end, &f->u.stream.offset);
  724.             if (p == NULL) {
  725.                 goto error;
  726.             }

  727.         } else {
  728.             f->u.stream.off = 0;
  729.             f->u.stream.offset = 0;
  730.         }

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

  733.             p = ngx_quic_parse_int(p, end, &f->u.stream.length);
  734.             if (p == NULL) {
  735.                 goto error;
  736.             }

  737.         } else {
  738.             f->u.stream.len = 0;
  739.             f->u.stream.length = end - p; /* up to packet end */
  740.         }

  741.         p = ngx_quic_read_bytes(p, end, f->u.stream.length, &b->pos);
  742.         if (p == NULL) {
  743.             goto error;
  744.         }

  745.         b->last = p;

  746.         f->type = NGX_QUIC_FT_STREAM;
  747.         break;

  748.     case NGX_QUIC_FT_MAX_DATA:

  749.         p = ngx_quic_parse_int(p, end, &f->u.max_data.max_data);
  750.         if (p == NULL) {
  751.             goto error;
  752.         }

  753.         break;

  754.     case NGX_QUIC_FT_RESET_STREAM:

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

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

  763.         p = ngx_quic_parse_int(p, end, &f->u.reset_stream.final_size);
  764.         if (p == NULL) {
  765.             goto error;
  766.         }

  767.         break;

  768.     case NGX_QUIC_FT_STOP_SENDING:

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

  773.         p = ngx_quic_parse_int(p, end, &f->u.stop_sending.error_code);
  774.         if (p == NULL) {
  775.             goto error;
  776.         }

  777.         break;

  778.     case NGX_QUIC_FT_STREAMS_BLOCKED:
  779.     case NGX_QUIC_FT_STREAMS_BLOCKED2:

  780.         p = ngx_quic_parse_int(p, end, &f->u.streams_blocked.limit);
  781.         if (p == NULL) {
  782.             goto error;
  783.         }

  784.         if (f->u.streams_blocked.limit > 0x1000000000000000) {
  785.             goto error;
  786.         }

  787.         f->u.streams_blocked.bidi =
  788.                               (f->type == NGX_QUIC_FT_STREAMS_BLOCKED) ? 1 : 0;
  789.         break;

  790.     case NGX_QUIC_FT_MAX_STREAMS:
  791.     case NGX_QUIC_FT_MAX_STREAMS2:

  792.         p = ngx_quic_parse_int(p, end, &f->u.max_streams.limit);
  793.         if (p == NULL) {
  794.             goto error;
  795.         }

  796.         if (f->u.max_streams.limit > 0x1000000000000000) {
  797.             goto error;
  798.         }

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

  800.         break;

  801.     case NGX_QUIC_FT_MAX_STREAM_DATA:

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

  806.         p = ngx_quic_parse_int(p, end, &f->u.max_stream_data.limit);
  807.         if (p == NULL) {
  808.             goto error;
  809.         }

  810.         break;

  811.     case NGX_QUIC_FT_DATA_BLOCKED:

  812.         p = ngx_quic_parse_int(p, end, &f->u.data_blocked.limit);
  813.         if (p == NULL) {
  814.             goto error;
  815.         }

  816.         break;

  817.     case NGX_QUIC_FT_STREAM_DATA_BLOCKED:

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

  822.         p = ngx_quic_parse_int(p, end, &f->u.stream_data_blocked.limit);
  823.         if (p == NULL) {
  824.             goto error;
  825.         }

  826.         break;

  827.     case NGX_QUIC_FT_PATH_CHALLENGE:

  828.         p = ngx_quic_copy_bytes(p, end, 8, f->u.path_challenge.data);
  829.         if (p == NULL) {
  830.             goto error;
  831.         }

  832.         break;

  833.     case NGX_QUIC_FT_PATH_RESPONSE:

  834.         p = ngx_quic_copy_bytes(p, end, 8, f->u.path_response.data);
  835.         if (p == NULL) {
  836.             goto error;
  837.         }

  838.         break;

  839.     default:
  840.         ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  841.                       "quic unknown frame type 0x%xi", f->type);
  842.         return NGX_ERROR;
  843.     }

  844.     f->level = pkt->level;
  845. #if (NGX_DEBUG)
  846.     f->pnum = pkt->pn;
  847. #endif

  848.     return p - start;

  849. error:

  850.     pkt->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;

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

  853.     return NGX_ERROR;
  854. }


  855. static ngx_int_t
  856. ngx_quic_frame_allowed(ngx_quic_header_t *pkt, ngx_uint_t frame_type)
  857. {
  858.     uint8_t  ptype;

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

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

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

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

  902.         } else {
  903.             ptype = 2; /* zero-rtt */
  904.         }

  905.     } else {
  906.         ptype = 1; /* application data */
  907.     }

  908.     if (ptype & ngx_quic_frame_masks[frame_type]) {
  909.         return NGX_OK;
  910.     }

  911.     ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
  912.                   "quic frame type 0x%xi is not "
  913.                   "allowed in packet with flags 0x%xd",
  914.                   frame_type, pkt->flags);

  915.     return NGX_DECLINED;
  916. }


  917. ssize_t
  918. ngx_quic_parse_ack_range(ngx_log_t *log, u_char *start, u_char *end,
  919.     uint64_t *gap, uint64_t *range)
  920. {
  921.     u_char  *p;

  922.     p = start;

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

  929.     p = ngx_quic_parse_int(p, end, range);
  930.     if (p == NULL) {
  931.         ngx_log_error(NGX_LOG_INFO, log, 0,
  932.                       "quic failed to parse ack frame range");
  933.         return NGX_ERROR;
  934.     }

  935.     return p - start;
  936. }


  937. size_t
  938. ngx_quic_create_ack_range(u_char *p, uint64_t gap, uint64_t range)
  939. {
  940.     size_t   len;
  941.     u_char  *start;

  942.     if (p == NULL) {
  943.         len = ngx_quic_varint_len(gap);
  944.         len += ngx_quic_varint_len(range);
  945.         return len;
  946.     }

  947.     start = p;

  948.     ngx_quic_build_int(&p, gap);
  949.     ngx_quic_build_int(&p, range);

  950.     return p - start;
  951. }


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

  962.     switch (f->type) {
  963.     case NGX_QUIC_FT_PING:
  964.         return ngx_quic_create_ping(p);

  965.     case NGX_QUIC_FT_ACK:
  966.         f->need_ack = 0;
  967.         return ngx_quic_create_ack(p, &f->u.ack, f->data);

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

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

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

  974.     case NGX_QUIC_FT_HANDSHAKE_DONE:
  975.         return ngx_quic_create_hs_done(p);

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

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

  980.     case NGX_QUIC_FT_CONNECTION_CLOSE:
  981.     case NGX_QUIC_FT_CONNECTION_CLOSE_APP:
  982.         f->need_ack = 0;
  983.         return ngx_quic_create_close(p, f);

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

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

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

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

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

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

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

  998.     default:
  999.         /* BUG: unsupported frame type generated */
  1000.         return NGX_ERROR;
  1001.     }
  1002. }


  1003. static size_t
  1004. ngx_quic_create_ping(u_char *p)
  1005. {
  1006.     u_char  *start;

  1007.     if (p == NULL) {
  1008.         return ngx_quic_varint_len(NGX_QUIC_FT_PING);
  1009.     }

  1010.     start = p;

  1011.     ngx_quic_build_int(&p, NGX_QUIC_FT_PING);

  1012.     return p - start;
  1013. }


  1014. static size_t
  1015. ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack, ngx_chain_t *ranges)
  1016. {
  1017.     size_t      len;
  1018.     u_char     *start;
  1019.     ngx_buf_t  *b;

  1020.     if (p == NULL) {
  1021.         len = ngx_quic_varint_len(NGX_QUIC_FT_ACK);
  1022.         len += ngx_quic_varint_len(ack->largest);
  1023.         len += ngx_quic_varint_len(ack->delay);
  1024.         len += ngx_quic_varint_len(ack->range_count);
  1025.         len += ngx_quic_varint_len(ack->first_range);
  1026.         len += ack->ranges_length;

  1027.         return len;
  1028.     }

  1029.     start = p;

  1030.     ngx_quic_build_int(&p, NGX_QUIC_FT_ACK);
  1031.     ngx_quic_build_int(&p, ack->largest);
  1032.     ngx_quic_build_int(&p, ack->delay);
  1033.     ngx_quic_build_int(&p, ack->range_count);
  1034.     ngx_quic_build_int(&p, ack->first_range);

  1035.     while (ranges) {
  1036.         b = ranges->buf;
  1037.         p = ngx_cpymem(p, b->pos, b->last - b->pos);
  1038.         ranges = ranges->next;
  1039.     }

  1040.     return p - start;
  1041. }


  1042. static size_t
  1043. ngx_quic_create_reset_stream(u_char *p, ngx_quic_reset_stream_frame_t *rs)
  1044. {
  1045.     size_t   len;
  1046.     u_char  *start;

  1047.     if (p == NULL) {
  1048.         len = ngx_quic_varint_len(NGX_QUIC_FT_RESET_STREAM);
  1049.         len += ngx_quic_varint_len(rs->id);
  1050.         len += ngx_quic_varint_len(rs->error_code);
  1051.         len += ngx_quic_varint_len(rs->final_size);
  1052.         return len;
  1053.     }

  1054.     start = p;

  1055.     ngx_quic_build_int(&p, NGX_QUIC_FT_RESET_STREAM);
  1056.     ngx_quic_build_int(&p, rs->id);
  1057.     ngx_quic_build_int(&p, rs->error_code);
  1058.     ngx_quic_build_int(&p, rs->final_size);

  1059.     return p - start;
  1060. }


  1061. static size_t
  1062. ngx_quic_create_stop_sending(u_char *p, ngx_quic_stop_sending_frame_t *ss)
  1063. {
  1064.     size_t   len;
  1065.     u_char  *start;

  1066.     if (p == NULL) {
  1067.         len = ngx_quic_varint_len(NGX_QUIC_FT_STOP_SENDING);
  1068.         len += ngx_quic_varint_len(ss->id);
  1069.         len += ngx_quic_varint_len(ss->error_code);
  1070.         return len;
  1071.     }

  1072.     start = p;

  1073.     ngx_quic_build_int(&p, NGX_QUIC_FT_STOP_SENDING);
  1074.     ngx_quic_build_int(&p, ss->id);
  1075.     ngx_quic_build_int(&p, ss->error_code);

  1076.     return p - start;
  1077. }


  1078. static size_t
  1079. ngx_quic_create_crypto(u_char *p, ngx_quic_crypto_frame_t *crypto,
  1080.     ngx_chain_t *data)
  1081. {
  1082.     size_t      len;
  1083.     u_char     *start;
  1084.     ngx_buf_t  *b;

  1085.     if (p == NULL) {
  1086.         len = ngx_quic_varint_len(NGX_QUIC_FT_CRYPTO);
  1087.         len += ngx_quic_varint_len(crypto->offset);
  1088.         len += ngx_quic_varint_len(crypto->length);
  1089.         len += crypto->length;

  1090.         return len;
  1091.     }

  1092.     start = p;

  1093.     ngx_quic_build_int(&p, NGX_QUIC_FT_CRYPTO);
  1094.     ngx_quic_build_int(&p, crypto->offset);
  1095.     ngx_quic_build_int(&p, crypto->length);

  1096.     while (data) {
  1097.         b = data->buf;
  1098.         p = ngx_cpymem(p, b->pos, b->last - b->pos);
  1099.         data = data->next;
  1100.     }

  1101.     return p - start;
  1102. }


  1103. static size_t
  1104. ngx_quic_create_hs_done(u_char *p)
  1105. {
  1106.     u_char  *start;

  1107.     if (p == NULL) {
  1108.         return ngx_quic_varint_len(NGX_QUIC_FT_HANDSHAKE_DONE);
  1109.     }

  1110.     start = p;

  1111.     ngx_quic_build_int(&p, NGX_QUIC_FT_HANDSHAKE_DONE);

  1112.     return p - start;
  1113. }


  1114. static size_t
  1115. ngx_quic_create_new_token(u_char *p, ngx_quic_new_token_frame_t *token,
  1116.     ngx_chain_t *data)
  1117. {
  1118.     size_t      len;
  1119.     u_char     *start;
  1120.     ngx_buf_t  *b;

  1121.     if (p == NULL) {
  1122.         len = ngx_quic_varint_len(NGX_QUIC_FT_NEW_TOKEN);
  1123.         len += ngx_quic_varint_len(token->length);
  1124.         len += token->length;

  1125.         return len;
  1126.     }

  1127.     start = p;

  1128.     ngx_quic_build_int(&p, NGX_QUIC_FT_NEW_TOKEN);
  1129.     ngx_quic_build_int(&p, token->length);

  1130.     while (data) {
  1131.         b = data->buf;
  1132.         p = ngx_cpymem(p, b->pos, b->last - b->pos);
  1133.         data = data->next;
  1134.     }

  1135.     return p - start;
  1136. }


  1137. static size_t
  1138. ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf,
  1139.     ngx_chain_t *data)
  1140. {
  1141.     size_t      len;
  1142.     u_char     *start, type;
  1143.     ngx_buf_t  *b;

  1144.     type = NGX_QUIC_FT_STREAM;

  1145.     if (sf->off) {
  1146.         type |= NGX_QUIC_STREAM_FRAME_OFF;
  1147.     }

  1148.     if (sf->len) {
  1149.         type |= NGX_QUIC_STREAM_FRAME_LEN;
  1150.     }

  1151.     if (sf->fin) {
  1152.         type |= NGX_QUIC_STREAM_FRAME_FIN;
  1153.     }

  1154.     if (p == NULL) {
  1155.         len = ngx_quic_varint_len(type);
  1156.         len += ngx_quic_varint_len(sf->stream_id);

  1157.         if (sf->off) {
  1158.             len += ngx_quic_varint_len(sf->offset);
  1159.         }

  1160.         if (sf->len) {
  1161.             len += ngx_quic_varint_len(sf->length);
  1162.         }

  1163.         len += sf->length;

  1164.         return len;
  1165.     }

  1166.     start = p;

  1167.     ngx_quic_build_int(&p, type);
  1168.     ngx_quic_build_int(&p, sf->stream_id);

  1169.     if (sf->off) {
  1170.         ngx_quic_build_int(&p, sf->offset);
  1171.     }

  1172.     if (sf->len) {
  1173.         ngx_quic_build_int(&p, sf->length);
  1174.     }

  1175.     while (data) {
  1176.         b = data->buf;
  1177.         p = ngx_cpymem(p, b->pos, b->last - b->pos);
  1178.         data = data->next;
  1179.     }

  1180.     return p - start;
  1181. }


  1182. static size_t
  1183. ngx_quic_create_max_streams(u_char *p, ngx_quic_max_streams_frame_t *ms)
  1184. {
  1185.     size_t       len;
  1186.     u_char      *start;
  1187.     ngx_uint_t   type;

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

  1189.     if (p == NULL) {
  1190.         len = ngx_quic_varint_len(type);
  1191.         len += ngx_quic_varint_len(ms->limit);
  1192.         return len;
  1193.     }

  1194.     start = p;

  1195.     ngx_quic_build_int(&p, type);
  1196.     ngx_quic_build_int(&p, ms->limit);

  1197.     return p - start;
  1198. }


  1199. static ngx_int_t
  1200. ngx_quic_parse_transport_param(u_char *p, u_char *end, uint16_t id,
  1201.     ngx_quic_tp_t *dst)
  1202. {
  1203.     uint64_t   varint;
  1204.     ngx_str_t  str;

  1205.     varint = 0;
  1206.     ngx_str_null(&str);

  1207.     switch (id) {

  1208.     case NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION:
  1209.         /* zero-length option */
  1210.         if (end - p != 0) {
  1211.             return NGX_ERROR;
  1212.         }
  1213.         dst->disable_active_migration = 1;
  1214.         return NGX_OK;

  1215.     case NGX_QUIC_TP_MAX_IDLE_TIMEOUT:
  1216.     case NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
  1217.     case NGX_QUIC_TP_INITIAL_MAX_DATA:
  1218.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
  1219.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
  1220.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
  1221.     case NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
  1222.     case NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI:
  1223.     case NGX_QUIC_TP_ACK_DELAY_EXPONENT:
  1224.     case NGX_QUIC_TP_MAX_ACK_DELAY:
  1225.     case NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:

  1226.         p = ngx_quic_parse_int(p, end, &varint);
  1227.         if (p == NULL) {
  1228.             return NGX_ERROR;
  1229.         }
  1230.         break;

  1231.     case NGX_QUIC_TP_INITIAL_SCID:

  1232.         str.len = end - p;
  1233.         str.data = p;
  1234.         break;

  1235.     default:
  1236.         return NGX_DECLINED;
  1237.     }

  1238.     switch (id) {

  1239.     case NGX_QUIC_TP_MAX_IDLE_TIMEOUT:
  1240.         dst->max_idle_timeout = varint;
  1241.         break;

  1242.     case NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
  1243.         dst->max_udp_payload_size = varint;
  1244.         break;

  1245.     case NGX_QUIC_TP_INITIAL_MAX_DATA:
  1246.         dst->initial_max_data = varint;
  1247.         break;

  1248.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
  1249.         dst->initial_max_stream_data_bidi_local = varint;
  1250.         break;

  1251.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
  1252.         dst->initial_max_stream_data_bidi_remote = varint;
  1253.         break;

  1254.     case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
  1255.         dst->initial_max_stream_data_uni = varint;
  1256.         break;

  1257.     case NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
  1258.         dst->initial_max_streams_bidi = varint;
  1259.         break;

  1260.     case NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI:
  1261.         dst->initial_max_streams_uni = varint;
  1262.         break;

  1263.     case NGX_QUIC_TP_ACK_DELAY_EXPONENT:
  1264.         dst->ack_delay_exponent = varint;
  1265.         break;

  1266.     case NGX_QUIC_TP_MAX_ACK_DELAY:
  1267.         dst->max_ack_delay = varint;
  1268.         break;

  1269.     case NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
  1270.         dst->active_connection_id_limit = varint;
  1271.         break;

  1272.     case NGX_QUIC_TP_INITIAL_SCID:
  1273.         dst->initial_scid = str;
  1274.         break;

  1275.     default:
  1276.         return NGX_ERROR;
  1277.     }

  1278.     return NGX_OK;
  1279. }


  1280. ngx_int_t
  1281. ngx_quic_parse_transport_params(u_char *p, u_char *end, ngx_quic_tp_t *tp,
  1282.     ngx_log_t *log)
  1283. {
  1284.     uint64_t   id, len;
  1285.     ngx_int_t  rc;

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

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

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

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

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

  1318.         if (rc == NGX_ERROR) {
  1319.             ngx_log_error(NGX_LOG_INFO, log, 0,
  1320.                           "quic failed to parse"
  1321.                           " transport param id:0x%xL data", id);
  1322.             return NGX_ERROR;
  1323.         }

  1324.         if (rc == NGX_DECLINED) {
  1325.             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
  1326.                           "quic %s transport param id:0x%xL, skipped",
  1327.                           (id % 31 == 27) ? "reserved" : "unknown", id);
  1328.         }

  1329.         p += len;
  1330.     }

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

  1338.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, log, 0,
  1339.                    "quic transport parameters parsed ok");

  1340.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1341.                    "quic tp disable active migration: %ui",
  1342.                    tp->disable_active_migration);

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

  1345.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1346.                    "quic tp max_udp_payload_size:%ui",
  1347.                    tp->max_udp_payload_size);

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

  1350.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1351.                    "quic tp max_stream_data_bidi_local:%ui",
  1352.                    tp->initial_max_stream_data_bidi_local);

  1353.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1354.                    "quic tp max_stream_data_bidi_remote:%ui",
  1355.                    tp->initial_max_stream_data_bidi_remote);

  1356.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1357.                    "quic tp max_stream_data_uni:%ui",
  1358.                    tp->initial_max_stream_data_uni);

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

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

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

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

  1370.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
  1371.                    "quic tp active_connection_id_limit:%ui",
  1372.                    tp->active_connection_id_limit);

  1373.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
  1374.                    "quic tp initial source_connection_id len:%uz %xV",
  1375.                    tp->initial_scid.len, &tp->initial_scid);

  1376.     return NGX_OK;
  1377. }


  1378. static size_t
  1379. ngx_quic_create_max_stream_data(u_char *p, ngx_quic_max_stream_data_frame_t *ms)
  1380. {
  1381.     size_t   len;
  1382.     u_char  *start;

  1383.     if (p == NULL) {
  1384.         len = ngx_quic_varint_len(NGX_QUIC_FT_MAX_STREAM_DATA);
  1385.         len += ngx_quic_varint_len(ms->id);
  1386.         len += ngx_quic_varint_len(ms->limit);
  1387.         return len;
  1388.     }

  1389.     start = p;

  1390.     ngx_quic_build_int(&p, NGX_QUIC_FT_MAX_STREAM_DATA);
  1391.     ngx_quic_build_int(&p, ms->id);
  1392.     ngx_quic_build_int(&p, ms->limit);

  1393.     return p - start;
  1394. }


  1395. static size_t
  1396. ngx_quic_create_max_data(u_char *p, ngx_quic_max_data_frame_t *md)
  1397. {
  1398.     size_t   len;
  1399.     u_char  *start;

  1400.     if (p == NULL) {
  1401.         len = ngx_quic_varint_len(NGX_QUIC_FT_MAX_DATA);
  1402.         len += ngx_quic_varint_len(md->max_data);
  1403.         return len;
  1404.     }

  1405.     start = p;

  1406.     ngx_quic_build_int(&p, NGX_QUIC_FT_MAX_DATA);
  1407.     ngx_quic_build_int(&p, md->max_data);

  1408.     return p - start;
  1409. }


  1410. static size_t
  1411. ngx_quic_create_path_challenge(u_char *p, ngx_quic_path_challenge_frame_t *pc)
  1412. {
  1413.     size_t   len;
  1414.     u_char  *start;

  1415.     if (p == NULL) {
  1416.         len = ngx_quic_varint_len(NGX_QUIC_FT_PATH_CHALLENGE);
  1417.         len += sizeof(pc->data);
  1418.         return len;
  1419.     }

  1420.     start = p;

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

  1423.     return p - start;
  1424. }


  1425. static size_t
  1426. ngx_quic_create_path_response(u_char *p, ngx_quic_path_challenge_frame_t *pc)
  1427. {
  1428.     size_t   len;
  1429.     u_char  *start;

  1430.     if (p == NULL) {
  1431.         len = ngx_quic_varint_len(NGX_QUIC_FT_PATH_RESPONSE);
  1432.         len += sizeof(pc->data);
  1433.         return len;
  1434.     }

  1435.     start = p;

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

  1438.     return p - start;
  1439. }


  1440. static size_t
  1441. ngx_quic_create_new_connection_id(u_char *p, ngx_quic_new_conn_id_frame_t *ncid)
  1442. {
  1443.     size_t   len;
  1444.     u_char  *start;

  1445.     if (p == NULL) {
  1446.         len = ngx_quic_varint_len(NGX_QUIC_FT_NEW_CONNECTION_ID);
  1447.         len += ngx_quic_varint_len(ncid->seqnum);
  1448.         len += ngx_quic_varint_len(ncid->retire);
  1449.         len++;
  1450.         len += ncid->len;
  1451.         len += NGX_QUIC_SR_TOKEN_LEN;
  1452.         return len;
  1453.     }

  1454.     start = p;

  1455.     ngx_quic_build_int(&p, NGX_QUIC_FT_NEW_CONNECTION_ID);
  1456.     ngx_quic_build_int(&p, ncid->seqnum);
  1457.     ngx_quic_build_int(&p, ncid->retire);
  1458.     *p++ = ncid->len;
  1459.     p = ngx_cpymem(p, ncid->cid, ncid->len);
  1460.     p = ngx_cpymem(p, ncid->srt, NGX_QUIC_SR_TOKEN_LEN);

  1461.     return p - start;
  1462. }


  1463. static size_t
  1464. ngx_quic_create_retire_connection_id(u_char *p,
  1465.     ngx_quic_retire_cid_frame_t *rcid)
  1466. {
  1467.     size_t   len;
  1468.     u_char  *start;

  1469.     if (p == NULL) {
  1470.         len = ngx_quic_varint_len(NGX_QUIC_FT_RETIRE_CONNECTION_ID);
  1471.         len += ngx_quic_varint_len(rcid->sequence_number);
  1472.         return len;
  1473.     }

  1474.     start = p;

  1475.     ngx_quic_build_int(&p, NGX_QUIC_FT_RETIRE_CONNECTION_ID);
  1476.     ngx_quic_build_int(&p, rcid->sequence_number);

  1477.     return p - start;
  1478. }


  1479. ngx_int_t
  1480. ngx_quic_init_transport_params(ngx_quic_tp_t *tp, ngx_quic_conf_t *qcf)
  1481. {
  1482.     ngx_uint_t  nstreams;

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

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

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

  1496.     tp->max_udp_payload_size = NGX_QUIC_MAX_UDP_PAYLOAD_SIZE;

  1497.     nstreams = qcf->max_concurrent_streams_bidi
  1498.                + qcf->max_concurrent_streams_uni;

  1499.     tp->initial_max_data = nstreams * qcf->stream_buffer_size;
  1500.     tp->initial_max_stream_data_bidi_local = qcf->stream_buffer_size;
  1501.     tp->initial_max_stream_data_bidi_remote = qcf->stream_buffer_size;
  1502.     tp->initial_max_stream_data_uni = qcf->stream_buffer_size;

  1503.     tp->initial_max_streams_bidi = qcf->max_concurrent_streams_bidi;
  1504.     tp->initial_max_streams_uni = qcf->max_concurrent_streams_uni;

  1505.     tp->max_ack_delay = NGX_QUIC_DEFAULT_MAX_ACK_DELAY;
  1506.     tp->ack_delay_exponent = NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT;

  1507.     tp->active_connection_id_limit = qcf->active_connection_id_limit;
  1508.     tp->disable_active_migration = qcf->disable_active_migration;

  1509.     return NGX_OK;
  1510. }


  1511. ssize_t
  1512. ngx_quic_create_transport_params(u_char *pos, u_char *end, ngx_quic_tp_t *tp,
  1513.     size_t *clen)
  1514. {
  1515.     u_char  *p;
  1516.     size_t   len;

  1517. #define ngx_quic_tp_len(id, value)                                            \
  1518.     ngx_quic_varint_len(id)                                                   \
  1519.     + ngx_quic_varint_len(value)                                              \
  1520.     + ngx_quic_varint_len(ngx_quic_varint_len(value))

  1521. #define ngx_quic_tp_vint(id, value)                                           \
  1522.     do {                                                                      \
  1523.         ngx_quic_build_int(&p, id);                                           \
  1524.         ngx_quic_build_int(&p, ngx_quic_varint_len(value));                   \
  1525.         ngx_quic_build_int(&p, value);                                        \
  1526.     } while (0)

  1527. #define ngx_quic_tp_strlen(id, value)                                         \
  1528.     ngx_quic_varint_len(id)                                                   \
  1529.     + ngx_quic_varint_len(value.len)                                          \
  1530.     + value.len

  1531. #define ngx_quic_tp_str(id, value)                                            \
  1532.     do {                                                                      \
  1533.         ngx_quic_build_int(&p, id);                                           \
  1534.         ngx_quic_build_int(&p, value.len);                                    \
  1535.         p = ngx_cpymem(p, value.data, value.len);                             \
  1536.     } while (0)

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

  1538.     len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI,
  1539.                            tp->initial_max_streams_uni);

  1540.     len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
  1541.                            tp->initial_max_streams_bidi);

  1542.     len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
  1543.                            tp->initial_max_stream_data_bidi_local);

  1544.     len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
  1545.                            tp->initial_max_stream_data_bidi_remote);

  1546.     len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
  1547.                            tp->initial_max_stream_data_uni);

  1548.     len += ngx_quic_tp_len(NGX_QUIC_TP_MAX_IDLE_TIMEOUT,
  1549.                            tp->max_idle_timeout);

  1550.     len += ngx_quic_tp_len(NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE,
  1551.                            tp->max_udp_payload_size);

  1552.     if (tp->disable_active_migration) {
  1553.         len += ngx_quic_varint_len(NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION);
  1554.         len += ngx_quic_varint_len(0);
  1555.     }

  1556.     len += ngx_quic_tp_len(NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
  1557.                            tp->active_connection_id_limit);

  1558.     /* transport parameters listed above will be saved in 0-RTT context */
  1559.     if (clen) {
  1560.         *clen = len;
  1561.     }

  1562.     len += ngx_quic_tp_len(NGX_QUIC_TP_MAX_ACK_DELAY,
  1563.                            tp->max_ack_delay);

  1564.     len += ngx_quic_tp_len(NGX_QUIC_TP_ACK_DELAY_EXPONENT,
  1565.                            tp->ack_delay_exponent);

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

  1568.     if (tp->retry_scid.len) {
  1569.         len += ngx_quic_tp_strlen(NGX_QUIC_TP_RETRY_SCID, tp->retry_scid);
  1570.     }

  1571.     len += ngx_quic_varint_len(NGX_QUIC_TP_SR_TOKEN);
  1572.     len += ngx_quic_varint_len(NGX_QUIC_SR_TOKEN_LEN);
  1573.     len += NGX_QUIC_SR_TOKEN_LEN;

  1574.     if (pos == NULL) {
  1575.         return len;
  1576.     }

  1577.     p = pos;

  1578.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_DATA,
  1579.                      tp->initial_max_data);

  1580.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI,
  1581.                      tp->initial_max_streams_uni);

  1582.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
  1583.                      tp->initial_max_streams_bidi);

  1584.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
  1585.                      tp->initial_max_stream_data_bidi_local);

  1586.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
  1587.                      tp->initial_max_stream_data_bidi_remote);

  1588.     ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
  1589.                      tp->initial_max_stream_data_uni);

  1590.     ngx_quic_tp_vint(NGX_QUIC_TP_MAX_IDLE_TIMEOUT,
  1591.                      tp->max_idle_timeout);

  1592.     ngx_quic_tp_vint(NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE,
  1593.                      tp->max_udp_payload_size);

  1594.     if (tp->disable_active_migration) {
  1595.         ngx_quic_build_int(&p, NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION);
  1596.         ngx_quic_build_int(&p, 0);
  1597.     }

  1598.     ngx_quic_tp_vint(NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
  1599.                      tp->active_connection_id_limit);

  1600.     ngx_quic_tp_vint(NGX_QUIC_TP_MAX_ACK_DELAY,
  1601.                      tp->max_ack_delay);

  1602.     ngx_quic_tp_vint(NGX_QUIC_TP_ACK_DELAY_EXPONENT,
  1603.                      tp->ack_delay_exponent);

  1604.     ngx_quic_tp_str(NGX_QUIC_TP_ORIGINAL_DCID, tp->original_dcid);
  1605.     ngx_quic_tp_str(NGX_QUIC_TP_INITIAL_SCID, tp->initial_scid);

  1606.     if (tp->retry_scid.len) {
  1607.         ngx_quic_tp_str(NGX_QUIC_TP_RETRY_SCID, tp->retry_scid);
  1608.     }

  1609.     ngx_quic_build_int(&p, NGX_QUIC_TP_SR_TOKEN);
  1610.     ngx_quic_build_int(&p, NGX_QUIC_SR_TOKEN_LEN);
  1611.     p = ngx_cpymem(p, tp->sr_token, NGX_QUIC_SR_TOKEN_LEN);

  1612.     return p - pos;
  1613. }


  1614. static size_t
  1615. ngx_quic_create_close(u_char *p, ngx_quic_frame_t *f)
  1616. {
  1617.     size_t                   len;
  1618.     u_char                  *start;
  1619.     ngx_quic_close_frame_t  *cl;

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

  1621.     if (p == NULL) {
  1622.         len = ngx_quic_varint_len(f->type);
  1623.         len += ngx_quic_varint_len(cl->error_code);

  1624.         if (f->type != NGX_QUIC_FT_CONNECTION_CLOSE_APP) {
  1625.             len += ngx_quic_varint_len(cl->frame_type);
  1626.         }

  1627.         len += ngx_quic_varint_len(cl->reason.len);
  1628.         len += cl->reason.len;

  1629.         return len;
  1630.     }

  1631.     start = p;

  1632.     ngx_quic_build_int(&p, f->type);
  1633.     ngx_quic_build_int(&p, cl->error_code);

  1634.     if (f->type != NGX_QUIC_FT_CONNECTION_CLOSE_APP) {
  1635.         ngx_quic_build_int(&p, cl->frame_type);
  1636.     }

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

  1639.     return p - start;
  1640. }


  1641. void
  1642. ngx_quic_dcid_encode_key(u_char *dcid, uint64_t key)
  1643. {
  1644.     (void) ngx_quic_write_uint64(dcid, key);
  1645. }