lsquic_trans_params.c revision feca77f5
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_trans_params.c
4 */
5
6#include <assert.h>
7#include <errno.h>
8#include <inttypes.h>
9#include <limits.h>
10#include <stddef.h>
11#include <stdint.h>
12#include <string.h>
13
14#include <arpa/inet.h>
15#include <sys/socket.h>
16
17#include "lsquic_byteswap.h"
18#include "lsquic_int_types.h"
19#include "lsquic_types.h"
20#include "lsquic_version.h"
21#include "lsquic_sizes.h"
22#include "lsquic_trans_params.h"
23#include "lsquic_util.h"
24#include "lsquic_varint.h"
25
26#define LSQUIC_LOGGER_MODULE LSQLM_TRAPA
27#include "lsquic_logger.h"
28
29
30static enum transport_param_id
31tpi_val_2_enum (uint64_t tpi_val)
32{
33    switch (tpi_val)
34    {
35    case 0:         return TPI_ORIGINAL_CONNECTION_ID;
36    case 1:         return TPI_MAX_IDLE_TIMEOUT;
37    case 2:         return TPI_STATELESS_RESET_TOKEN;
38    case 3:         return TPI_MAX_PACKET_SIZE;
39    case 4:         return TPI_INIT_MAX_DATA;
40    case 5:         return TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL;
41    case 6:         return TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE;
42    case 7:         return TPI_INIT_MAX_STREAM_DATA_UNI;
43    case 8:         return TPI_INIT_MAX_STREAMS_BIDI;
44    case 9:         return TPI_INIT_MAX_STREAMS_UNI;
45    case 10:        return TPI_ACK_DELAY_EXPONENT;
46    case 11:        return TPI_MAX_ACK_DELAY;
47    case 12:        return TPI_DISABLE_ACTIVE_MIGRATION;
48    case 13:        return TPI_PREFERRED_ADDRESS;
49    case 14:        return TPI_ACTIVE_CONNECTION_ID_LIMIT;
50#if LSQUIC_TEST_QUANTUM_READINESS
51    case 0xC37:     return TPI_QUANTUM_READINESS;
52#endif
53    case 0x1057:    return TPI_LOSS_BITS;
54    case 0xDE1A:    return TPI_MIN_ACK_DELAY;
55    default:        return INT_MAX;
56    }
57}
58
59
60static const unsigned short enum_2_tpi_val[LAST_TPI + 1] =
61{
62    [TPI_ORIGINAL_CONNECTION_ID]            =  0x0,
63    [TPI_MAX_IDLE_TIMEOUT]                  =  0x1,
64    [TPI_STATELESS_RESET_TOKEN]             =  0x2,
65    [TPI_MAX_PACKET_SIZE]                   =  0x3,
66    [TPI_INIT_MAX_DATA]                     =  0x4,
67    [TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL]   =  0x5,
68    [TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE]  =  0x6,
69    [TPI_INIT_MAX_STREAM_DATA_UNI]          =  0x7,
70    [TPI_INIT_MAX_STREAMS_BIDI]             =  0x8,
71    [TPI_INIT_MAX_STREAMS_UNI]              =  0x9,
72    [TPI_ACK_DELAY_EXPONENT]                =  0xA,
73    [TPI_MAX_ACK_DELAY]                     =  0xB,
74    [TPI_DISABLE_ACTIVE_MIGRATION]          =  0xC,
75    [TPI_PREFERRED_ADDRESS]                 =  0xD,
76    [TPI_ACTIVE_CONNECTION_ID_LIMIT]        =  0xE,
77#if LSQUIC_TEST_QUANTUM_READINESS
78    [TPI_QUANTUM_READINESS]                 =  0xC37,
79#endif
80    [TPI_LOSS_BITS]                         =  0x1057,
81    [TPI_MIN_ACK_DELAY]                     =  0xDE1A,
82};
83
84
85static const char * const tpi2str[LAST_TPI + 1] =
86{
87    [TPI_ORIGINAL_CONNECTION_ID]            =  "original_connection_id",
88    [TPI_MAX_IDLE_TIMEOUT]                  =  "max_idle_timeout",
89    [TPI_STATELESS_RESET_TOKEN]             =  "stateless_reset_token",
90    [TPI_MAX_PACKET_SIZE]                   =  "max_packet_size",
91    [TPI_INIT_MAX_DATA]                     =  "init_max_data",
92    [TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL]   =  "init_max_stream_data_bidi_local",
93    [TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE]  =  "init_max_stream_data_bidi_remote",
94    [TPI_INIT_MAX_STREAM_DATA_UNI]          =  "init_max_stream_data_uni",
95    [TPI_INIT_MAX_STREAMS_BIDI]             =  "init_max_streams_bidi",
96    [TPI_INIT_MAX_STREAMS_UNI]              =  "init_max_streams_uni",
97    [TPI_ACK_DELAY_EXPONENT]                =  "ack_delay_exponent",
98    [TPI_MAX_ACK_DELAY]                     =  "max_ack_delay",
99    [TPI_DISABLE_ACTIVE_MIGRATION]          =  "disable_active_migration",
100    [TPI_PREFERRED_ADDRESS]                 =  "preferred_address",
101    [TPI_ACTIVE_CONNECTION_ID_LIMIT]        =  "active_connection_id_limit",
102#if LSQUIC_TEST_QUANTUM_READINESS
103    [TPI_QUANTUM_READINESS]                 =  "quantum_readiness",
104#endif
105    [TPI_LOSS_BITS]                         =  "loss_bits",
106    [TPI_MIN_ACK_DELAY]                     =  "min_ack_delay",
107};
108
109
110static const uint64_t def_vals[MAX_NUM_WITH_DEF_TPI + 1] =
111{
112    [TPI_MAX_PACKET_SIZE]                   =  TP_DEF_MAX_PACKET_SIZE,
113    [TPI_ACK_DELAY_EXPONENT]                =  TP_DEF_ACK_DELAY_EXP,
114    [TPI_INIT_MAX_STREAMS_UNI]              =  TP_DEF_INIT_MAX_STREAMS_UNI,
115    [TPI_INIT_MAX_STREAMS_BIDI]             =  TP_DEF_INIT_MAX_STREAMS_BIDI,
116    [TPI_INIT_MAX_DATA]                     =  TP_DEF_INIT_MAX_DATA,
117    [TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL]   =  TP_DEF_INIT_MAX_STREAM_DATA_BIDI_LOCAL,
118    [TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE]  =  TP_DEF_INIT_MAX_STREAM_DATA_BIDI_REMOTE,
119    [TPI_INIT_MAX_STREAM_DATA_UNI]          =  TP_DEF_INIT_MAX_STREAM_DATA_UNI,
120    [TPI_MAX_IDLE_TIMEOUT]                  =  TP_DEF_MAX_IDLE_TIMEOUT,
121    [TPI_MAX_ACK_DELAY]                     =  TP_DEF_MAX_ACK_DELAY,
122    [TPI_ACTIVE_CONNECTION_ID_LIMIT]        =  TP_DEF_ACTIVE_CONNECTION_ID_LIMIT,
123};
124
125
126static const uint64_t max_vals[MAX_NUMERIC_TPI + 1] =
127{
128    [TPI_MAX_PACKET_SIZE]                   =  VINT_MAX_VALUE,
129    [TPI_ACK_DELAY_EXPONENT]                =  VINT_MAX_VALUE,
130    [TPI_INIT_MAX_STREAMS_UNI]              =  VINT_MAX_VALUE,
131    [TPI_INIT_MAX_STREAMS_BIDI]             =  VINT_MAX_VALUE,
132    [TPI_INIT_MAX_DATA]                     =  VINT_MAX_VALUE,
133    [TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL]   =  VINT_MAX_VALUE,
134    [TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE]  =  VINT_MAX_VALUE,
135    [TPI_INIT_MAX_STREAM_DATA_UNI]          =  VINT_MAX_VALUE,
136    [TPI_MAX_IDLE_TIMEOUT]                  =  VINT_MAX_VALUE,
137    [TPI_MAX_ACK_DELAY]                     =  TP_MAX_MAX_ACK_DELAY,
138    [TPI_ACTIVE_CONNECTION_ID_LIMIT]        =  VINT_MAX_VALUE,
139    [TPI_LOSS_BITS]                         =  1,
140    [TPI_MIN_ACK_DELAY]                     =  (1u << 24) - 1u,
141};
142
143
144static const uint64_t min_vals[MAX_NUMERIC_TPI + 1] =
145{
146    [TPI_MIN_ACK_DELAY]                     =  1,
147};
148
149
150static size_t
151preferred_address_size (const struct transport_params *params)
152{
153    return sizeof(params->tp_preferred_address.ipv4_addr)
154         + sizeof(params->tp_preferred_address.ipv4_port)
155         + sizeof(params->tp_preferred_address.ipv6_addr)
156         + sizeof(params->tp_preferred_address.ipv6_port)
157         + 1 + params->tp_preferred_address.cid.len
158         + sizeof(params->tp_preferred_address.srst)
159         ;
160}
161
162
163int
164lsquic_tp_has_pref_ipv4 (const struct transport_params *params)
165{
166    return (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
167        && params->tp_preferred_address.ipv4_port
168        && !lsquic_is_zero(params->tp_preferred_address.ipv4_addr,
169                    sizeof(params->tp_preferred_address.ipv4_addr));
170}
171
172
173int
174lsquic_tp_has_pref_ipv6 (const struct transport_params *params)
175{
176    return (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
177        && params->tp_preferred_address.ipv6_port
178        && !lsquic_is_zero(params->tp_preferred_address.ipv6_addr,
179                    sizeof(params->tp_preferred_address.ipv6_addr));
180}
181
182
183int
184lsquic_tp_encode (const struct transport_params *params, int is_server,
185                  unsigned char *const buf, size_t bufsz)
186{
187    unsigned char *p;
188    size_t need = 2;
189    uint16_t u16;
190    enum transport_param_id tpi;
191    unsigned set;
192    unsigned bits[MAX_NUMERIC_TPI + 1];
193
194    set = params->tp_set;   /* Will turn bits off for default values */
195
196    if (is_server)
197    {
198        if (set & (1 << TPI_ORIGINAL_CONNECTION_ID))
199            need += 4 + params->tp_original_cid.len;
200        if (set & (1 << TPI_STATELESS_RESET_TOKEN))
201            need += 4 + sizeof(params->tp_stateless_reset_token);
202        if (set & (1 << TPI_PREFERRED_ADDRESS))
203            need += 4 + preferred_address_size(params);
204    }
205#if LSQUIC_TEST_QUANTUM_READINESS
206    else if (set & (1 << TPI_QUANTUM_READINESS))
207        need += 4 + QUANTUM_READY_SZ;
208#endif
209
210    for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
211        if (set & (1 << tpi))
212        {
213            if (tpi > MAX_NUM_WITH_DEF_TPI
214                        || params->tp_numerics[tpi] != def_vals[tpi])
215            {
216                if (params->tp_numerics[tpi] >= min_vals[tpi]
217                                && params->tp_numerics[tpi] <= max_vals[tpi])
218                {
219                    bits[tpi] = vint_val2bits(params->tp_numerics[tpi]);
220                    need += 4 + (1 << bits[tpi]);
221                }
222                else if (params->tp_numerics[tpi] > max_vals[tpi])
223                {
224                    LSQ_DEBUG("numeric value of %s is too large (%"PRIu64" vs "
225                        "maximum of %"PRIu64")", tpi2str[tpi],
226                        params->tp_numerics[tpi], max_vals[tpi]);
227                    return -1;
228                }
229                else
230                {
231                    LSQ_DEBUG("numeric value of %s is too small (%"PRIu64" vs "
232                        "minimum " "of %"PRIu64")",
233                        tpi2str[tpi], params->tp_numerics[tpi], min_vals[tpi]);
234                    return -1;
235                }
236            }
237            else
238                set &= ~(1 << tpi);     /* Don't write default value */
239        }
240
241    for (; tpi <= MAX_EMPTY_TPI; ++tpi)
242        if (set & (1 << tpi))
243            need += 4 + 0;
244
245    if (need > bufsz || need > UINT16_MAX)
246    {
247        errno = ENOBUFS;
248        return -1;
249    }
250
251    p = buf;
252
253#define WRITE_TO_P(src, len) do {                                       \
254    memcpy(p, src, len);                                                \
255    p += len;                                                           \
256} while (0)
257
258#if __BYTE_ORDER == __LITTLE_ENDIAN
259#define WRITE_UINT_TO_P(val, width) do {                                \
260    u##width = bswap_##width(val);                                      \
261    WRITE_TO_P(&u##width, sizeof(u##width));                            \
262} while (0)
263#else
264#define WRITE_UINT_TO_P(val, width) do {                                \
265    u##width = val;                                                     \
266    WRITE_TO_P(&u##width, sizeof(u##width));                            \
267} while (0)
268#endif
269
270#define WRITE_PARAM_TO_P(tpidx, tpval, width) do {                      \
271    WRITE_UINT_TO_P(tpidx, 16);                                         \
272    WRITE_UINT_TO_P(width / 8, 16);                                     \
273    if (width > 8)                                                      \
274        WRITE_UINT_TO_P(tpval, width);                                  \
275    else if (width)                                                     \
276        *p++ = tpval;                                                   \
277} while (0)
278
279    WRITE_UINT_TO_P(need - 2 + buf - p, 16);
280
281    for (tpi = 0; tpi <= LAST_TPI; ++tpi)
282        if (set & (1 << tpi))
283        {
284            WRITE_UINT_TO_P(enum_2_tpi_val[tpi], 16);
285            switch (tpi)
286            {
287            case TPI_MAX_IDLE_TIMEOUT:
288            case TPI_MAX_PACKET_SIZE:
289            case TPI_INIT_MAX_DATA:
290            case TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL:
291            case TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE:
292            case TPI_INIT_MAX_STREAM_DATA_UNI:
293            case TPI_INIT_MAX_STREAMS_BIDI:
294            case TPI_INIT_MAX_STREAMS_UNI:
295            case TPI_ACK_DELAY_EXPONENT:
296            case TPI_MAX_ACK_DELAY:
297            case TPI_ACTIVE_CONNECTION_ID_LIMIT:
298            case TPI_LOSS_BITS:
299            case TPI_MIN_ACK_DELAY:
300                WRITE_UINT_TO_P(1 << bits[tpi], 16);
301                vint_write(p, params->tp_numerics[tpi], bits[tpi],
302                                                                1 << bits[tpi]);
303                p += 1 << bits[tpi];
304                break;
305            case TPI_ORIGINAL_CONNECTION_ID:
306                WRITE_UINT_TO_P(params->tp_original_cid.len, 16);
307                WRITE_TO_P(params->tp_original_cid.idbuf,
308                                            params->tp_original_cid.len);
309                break;
310            case TPI_STATELESS_RESET_TOKEN:
311                WRITE_UINT_TO_P(sizeof(params->tp_stateless_reset_token), 16);
312                WRITE_TO_P(params->tp_stateless_reset_token,
313                                sizeof(params->tp_stateless_reset_token));
314                break;
315            case TPI_PREFERRED_ADDRESS:
316                WRITE_UINT_TO_P(preferred_address_size(params), 16);
317                WRITE_TO_P(&params->tp_preferred_address.ipv4_addr,
318                        sizeof(params->tp_preferred_address.ipv4_addr));
319                WRITE_UINT_TO_P(params->tp_preferred_address.ipv4_port, 16);
320                WRITE_TO_P(&params->tp_preferred_address.ipv6_addr,
321                        sizeof(params->tp_preferred_address.ipv6_addr));
322                WRITE_UINT_TO_P(params->tp_preferred_address.ipv6_port, 16);
323                *p++ = params->tp_preferred_address.cid.len;
324                WRITE_TO_P(params->tp_preferred_address.cid.idbuf,
325                                    params->tp_preferred_address.cid.len);
326                WRITE_TO_P(params->tp_preferred_address.srst,
327                                sizeof(params->tp_preferred_address.srst));
328                break;
329            case TPI_DISABLE_ACTIVE_MIGRATION:
330                WRITE_UINT_TO_P(0, 16);
331                break;
332#if LSQUIC_TEST_QUANTUM_READINESS
333            case TPI_QUANTUM_READINESS:
334                WRITE_UINT_TO_P(QUANTUM_READY_SZ, 16);
335                memset(p, 'Q', QUANTUM_READY_SZ);
336                p += QUANTUM_READY_SZ;
337                break;
338#endif
339            }
340        }
341
342    assert(buf + need == p);
343    return (int) (p - buf);
344
345#undef WRITE_TO_P
346#undef WRITE_UINT_TO_P
347}
348
349
350int
351lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
352                  int is_server,
353                  struct transport_params *params)
354{
355    const unsigned char *p, *end, *q;
356    uint16_t len, param_id, tlen;
357    enum transport_param_id tpi;
358    unsigned set_of_ids;
359    int s;
360
361    p = buf;
362    end = buf + bufsz;
363
364    *params = TP_INITIALIZER();
365
366    if (end - p < 2)
367        return -1;
368    READ_UINT(len, 16, p, 2);
369    p += 2;
370    if (len > end - p)
371        return -1;
372    end = p + len;
373
374#define EXPECT_LEN(expected_len) do {                               \
375    if (expected_len != len)                                        \
376        return -1;                                                  \
377} while (0)
378
379#define EXPECT_AT_LEAST(expected_len) do {                          \
380    if ((expected_len) > (uintptr_t) (p + len - q))                 \
381        return -1;                                                  \
382} while (0)
383
384    set_of_ids = 0;
385    while (p + 4 <= end)
386    {
387        READ_UINT(param_id, 16, p, 2);
388        p += 2;
389        READ_UINT(len, 16, p, 2);
390        p += 2;
391        if (len > end - p)
392            return -1;
393        tpi = tpi_val_2_enum(param_id);
394        if (tpi <= LAST_TPI)
395        {
396            if (set_of_ids & (1 << tpi))
397                return -1;
398            set_of_ids |= 1 << tpi;
399        }
400        switch (tpi)
401        {
402        case TPI_MAX_IDLE_TIMEOUT:
403        case TPI_MAX_PACKET_SIZE:
404        case TPI_INIT_MAX_DATA:
405        case TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL:
406        case TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE:
407        case TPI_INIT_MAX_STREAM_DATA_UNI:
408        case TPI_INIT_MAX_STREAMS_BIDI:
409        case TPI_INIT_MAX_STREAMS_UNI:
410        case TPI_ACK_DELAY_EXPONENT:
411        case TPI_MAX_ACK_DELAY:
412        case TPI_ACTIVE_CONNECTION_ID_LIMIT:
413        case TPI_LOSS_BITS:
414        case TPI_MIN_ACK_DELAY:
415            switch (len)
416            {
417            case 1:
418            case 2:
419            case 4:
420            case 8:
421                s = vint_read(p, p + len, &params->tp_numerics[tpi]);
422                if (s == len)
423                {
424                    if (params->tp_numerics[tpi] > max_vals[tpi])
425                    {
426                        LSQ_DEBUG("numeric value of %s is too large "
427                            "(%"PRIu64" vs maximum of %"PRIu64, tpi2str[tpi],
428                            params->tp_numerics[tpi], max_vals[tpi]);
429                        return -1;
430                    }
431                    else if (params->tp_numerics[tpi] < min_vals[tpi])
432                    {
433                        LSQ_DEBUG("numeric value of %s is too small "
434                            "(%"PRIu64" vs minimum of %"PRIu64, tpi2str[tpi],
435                            params->tp_numerics[tpi], min_vals[tpi]);
436                        return -1;
437                    }
438                    break;
439                }
440                else
441                {
442                    LSQ_DEBUG("cannot read the value of numeric transport "
443                                        "param %u of length %u", param_id, len);
444                    return -1;
445                }
446            default:
447                LSQ_DEBUG("invalid length=%u for numeric transport "
448                                            "parameter 0x%X", len, param_id);
449                return -1;
450            }
451            break;
452        case TPI_DISABLE_ACTIVE_MIGRATION:
453            EXPECT_LEN(0);
454            break;
455        case TPI_STATELESS_RESET_TOKEN:
456            /* Client MUST not include reset token,
457             * see [draft-ietf-quic-transport-11], Section 6.4.1
458             */
459            if (!is_server)
460                return -1;
461            EXPECT_LEN(sizeof(params->tp_stateless_reset_token));
462            memcpy(params->tp_stateless_reset_token, p,
463                                sizeof(params->tp_stateless_reset_token));
464            break;
465        case TPI_ORIGINAL_CONNECTION_ID:
466            /* Client MUST not original connecti ID,
467             * see [draft-ietf-quic-transport-15], Section 6.6.1
468             */
469            if (!is_server)
470                return -1;
471            if (len > MAX_CID_LEN)
472                return -1;
473            memcpy(params->tp_original_cid.idbuf, p, len);
474            params->tp_original_cid.len = len;
475            break;
476        case TPI_PREFERRED_ADDRESS:
477            /* Client MUST not include preferred address,
478             * see [draft-ietf-quic-transport-12], Section 6.4.1
479             */
480            if (!is_server)
481                return -1;
482            q = p;
483            EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_addr));
484            memcpy(params->tp_preferred_address.ipv4_addr, q,
485                        sizeof(params->tp_preferred_address.ipv4_addr));
486            q += sizeof(params->tp_preferred_address.ipv4_addr);
487            EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_port));
488            READ_UINT(params->tp_preferred_address.ipv4_port, 16, q, 2);
489            q += 2;
490            EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_addr));
491            memcpy(params->tp_preferred_address.ipv6_addr, q,
492                        sizeof(params->tp_preferred_address.ipv6_addr));
493            q += sizeof(params->tp_preferred_address.ipv6_addr);
494            EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_port));
495            READ_UINT(params->tp_preferred_address.ipv6_port, 16, q, 2);
496            q += 2;
497            EXPECT_AT_LEAST(1);
498            tlen = *q;
499            q += 1;
500            if (tlen < 4 || tlen > MAX_CID_LEN)
501            {
502                LSQ_DEBUG("preferred server address contains invalid "
503                    "CID length of %"PRIu16" bytes", tlen);
504                return -1;
505            }
506            EXPECT_AT_LEAST(tlen);
507            memcpy(params->tp_preferred_address.cid.idbuf, q, tlen);
508            params->tp_preferred_address.cid.len = tlen;
509            q += tlen;
510            EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.srst));
511            memcpy(params->tp_preferred_address.srst, q,
512                            sizeof(params->tp_preferred_address.srst));
513            q += sizeof(params->tp_preferred_address.srst);
514            if (q != p + len)
515                return -1;
516            break;
517        default:
518            /* Do nothing: skip this transport parameter */
519            break;
520        }
521        p += len;
522        if (tpi <= LAST_TPI)
523        {
524            params->tp_set |= 1 << tpi;
525            params->tp_decoded |= 1 << tpi;
526        }
527    }
528
529    if (p != end)
530        return -1;
531
532    if ((params->tp_set & (1 << TPI_MIN_ACK_DELAY))
533            && params->tp_numerics[TPI_MIN_ACK_DELAY]
534                            > params->tp_numerics[TPI_MAX_ACK_DELAY] * 1000)
535    {
536        LSQ_DEBUG("min_ack_delay (%"PRIu64" usec) is larger than "
537            "max_ack_delay (%"PRIu64" ms)",
538            params->tp_numerics[TPI_MIN_ACK_DELAY],
539            params->tp_numerics[TPI_MAX_ACK_DELAY]);
540        return -1;
541    }
542
543    return (int) (end - buf);
544#undef EXPECT_LEN
545}
546
547
548void
549lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
550{
551    char *const end = buf + sz;
552    int nw;
553    enum transport_param_id tpi;
554    char tok_str[sizeof(params->tp_stateless_reset_token) * 2 + 1];
555    char addr_str[INET6_ADDRSTRLEN];
556
557    for (tpi = 0; tpi <= MAX_NUMERIC_TPI; ++tpi)
558        if (params->tp_set & (1 << tpi))
559        {
560            nw = snprintf(buf, end - buf, "%.*s%s: %"PRIu64,
561                (buf + sz > end) << 1, "; ", tpi2str[tpi],
562                params->tp_numerics[tpi]);
563            buf += nw;
564            if (buf >= end)
565                return;
566        }
567    for (; tpi <= MAX_EMPTY_TPI; ++tpi)
568        if (params->tp_set & (1 << TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL))
569        {
570            nw = snprintf(buf, end - buf, "%.*s%s",
571                                    (buf + sz > end) << 1, "; ", tpi2str[tpi]);
572            buf += nw;
573            if (buf >= end)
574                return;
575        }
576#if LSQUIC_TEST_QUANTUM_READINESS
577    if (params->tp_set & (1 << TPI_QUANTUM_READINESS))
578    {
579        nw = snprintf(buf, end - buf, "%.*s%s",
580                (buf + sz > end) << 1, "; ", tpi2str[TPI_QUANTUM_READINESS]);
581        buf += nw;
582        if (buf >= end)
583            return;
584    }
585#endif
586    if (params->tp_set & (1 << TPI_STATELESS_RESET_TOKEN))
587    {
588        lsquic_hexstr(params->tp_stateless_reset_token,
589            sizeof(params->tp_stateless_reset_token), tok_str, sizeof(tok_str));
590        nw = snprintf(buf, end - buf, "; stateless_reset_token: %s", tok_str);
591        buf += nw;
592        if (buf >= end)
593            return;
594    }
595    if (params->tp_set & (1 << TPI_ORIGINAL_CONNECTION_ID))
596    {
597        char cidbuf_[MAX_CID_LEN * 2 + 1];
598        nw = snprintf(buf, end - buf, "; original DCID (ODCID): %"CID_FMT,
599                                        CID_BITS(&params->tp_original_cid));
600        buf += nw;
601        if (buf >= end)
602            return;
603    }
604    if (lsquic_tp_has_pref_ipv4(params))
605    {
606        if (inet_ntop(AF_INET, params->tp_preferred_address.ipv4_addr,
607                                                addr_str, sizeof(addr_str)))
608        {
609            nw = snprintf(buf, end - buf, "; IPv4 preferred address: %s:%u",
610                            addr_str, params->tp_preferred_address.ipv4_port);
611            buf += nw;
612            if (buf >= end)
613                return;
614        }
615    }
616    if (lsquic_tp_has_pref_ipv6(params))
617    {
618        if (inet_ntop(AF_INET6, params->tp_preferred_address.ipv6_addr,
619                                                addr_str, sizeof(addr_str)))
620        {
621            nw = snprintf(buf, end - buf, "; IPv6 preferred address: %s:%u",
622                            addr_str, params->tp_preferred_address.ipv6_port);
623            buf += nw;
624            if (buf >= end)
625                return;
626        }
627    }
628}
629