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