lsquic_trans_params.c revision 02b6086d
1/* Copyright (c) 2017 - 2019 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 <stddef.h> 10#include <stdint.h> 11#include <string.h> 12 13#include <arpa/inet.h> 14#include <sys/socket.h> 15 16#include "lsquic_byteswap.h" 17#include "lsquic_int_types.h" 18#include "lsquic_types.h" 19#include "lsquic_version.h" 20#include "lsquic_sizes.h" 21#include "lsquic_trans_params.h" 22#include "lsquic_util.h" 23#include "lsquic_varint.h" 24 25#define LSQUIC_LOGGER_MODULE LSQLM_TRAPA 26#include "lsquic_logger.h" 27 28 29static const uint64_t def_vals[MAX_TPI + 1] = 30{ 31 [TPI_MAX_PACKET_SIZE] = TP_DEF_MAX_PACKET_SIZE, 32 [TPI_ACK_DELAY_EXPONENT] = TP_DEF_ACK_DELAY_EXP, 33 [TPI_INIT_MAX_STREAMS_UNI] = TP_DEF_INIT_MAX_STREAMS_UNI, 34 [TPI_INIT_MAX_STREAMS_BIDI] = TP_DEF_INIT_MAX_STREAMS_BIDI, 35 [TPI_INIT_MAX_DATA] = TP_DEF_INIT_MAX_DATA, 36 [TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL] = TP_DEF_INIT_MAX_STREAM_DATA_BIDI_LOCAL, 37 [TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE] = TP_DEF_INIT_MAX_STREAM_DATA_BIDI_REMOTE, 38 [TPI_INIT_MAX_STREAM_DATA_UNI] = TP_DEF_INIT_MAX_STREAM_DATA_UNI, 39 [TPI_IDLE_TIMEOUT] = TP_DEF_IDLE_TIMEOUT, 40 [TPI_MAX_ACK_DELAY] = TP_DEF_MAX_ACK_DELAY, 41 [TPI_ACTIVE_CONNECTION_ID_LIMIT] = TP_DEF_ACTIVE_CONNECTION_ID_LIMIT, 42}; 43 44 45static const uint64_t max_vals[MAX_TPI + 1] = 46{ 47 [TPI_MAX_PACKET_SIZE] = VINT_MAX_VALUE, 48 [TPI_ACK_DELAY_EXPONENT] = VINT_MAX_VALUE, 49 [TPI_INIT_MAX_STREAMS_UNI] = VINT_MAX_VALUE, 50 [TPI_INIT_MAX_STREAMS_BIDI] = VINT_MAX_VALUE, 51 [TPI_INIT_MAX_DATA] = VINT_MAX_VALUE, 52 [TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL] = VINT_MAX_VALUE, 53 [TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE] = VINT_MAX_VALUE, 54 [TPI_INIT_MAX_STREAM_DATA_UNI] = VINT_MAX_VALUE, 55 [TPI_IDLE_TIMEOUT] = VINT_MAX_VALUE, 56 [TPI_MAX_ACK_DELAY] = TP_MAX_MAX_ACK_DELAY, 57 [TPI_ACTIVE_CONNECTION_ID_LIMIT] = VINT_MAX_VALUE, 58}; 59 60 61#define TP_OFF(name_) ((uint64_t *) &((struct transport_params *) 0 \ 62 )->tp_numerics_u.s.name_ - (uint64_t *) &((struct transport_params *) \ 63 0)->tp_numerics_u.s) 64 65/* Map enum transport_params to index of tp_numerics_u.a; for numeric values only */ 66static const unsigned tpi2idx[MAX_TPI + 1] = 67{ 68 [TPI_MAX_PACKET_SIZE] = TP_OFF(max_packet_size), 69 [TPI_ACK_DELAY_EXPONENT] = TP_OFF(ack_delay_exponent), 70 [TPI_INIT_MAX_STREAMS_UNI] = TP_OFF(init_max_streams_uni), 71 [TPI_INIT_MAX_STREAMS_BIDI] = TP_OFF(init_max_streams_bidi), 72 [TPI_INIT_MAX_DATA] = TP_OFF(init_max_data), 73 [TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL] = TP_OFF(init_max_stream_data_bidi_local), 74 [TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE] = TP_OFF(init_max_stream_data_bidi_remote), 75 [TPI_INIT_MAX_STREAM_DATA_UNI] = TP_OFF(init_max_stream_data_uni), 76 [TPI_IDLE_TIMEOUT] = TP_OFF(idle_timeout), 77 [TPI_MAX_ACK_DELAY] = TP_OFF(max_ack_delay), 78 [TPI_ACTIVE_CONNECTION_ID_LIMIT] = TP_OFF(active_connection_id_limit), 79}; 80 81 82static size_t 83preferred_address_size (const struct transport_params *params) 84{ 85 return sizeof(params->tp_preferred_address.ipv4_addr) 86 + sizeof(params->tp_preferred_address.ipv4_port) 87 + sizeof(params->tp_preferred_address.ipv6_addr) 88 + sizeof(params->tp_preferred_address.ipv6_port) 89 + 1 + params->tp_preferred_address.cid.len 90 + sizeof(params->tp_preferred_address.srst) 91 ; 92} 93 94 95int 96lsquic_tp_encode (const struct transport_params *params, 97 unsigned char *const buf, size_t bufsz) 98{ 99 unsigned char *p; 100 size_t need = 2; 101 uint16_t u16; 102 enum transport_param_id tpi; 103 unsigned bits[MAX_TPI + 1]; 104 105 if (params->tp_flags & TRAPA_SERVER) 106 { 107 if (params->tp_flags & TRAPA_ORIGINAL_CID) 108 need += 4 + params->tp_original_cid.len; 109 if (params->tp_flags & TRAPA_RESET_TOKEN) 110 need += 4 + sizeof(params->tp_stateless_reset_token); 111 if (params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6)) 112 need += 4 + preferred_address_size(params); 113 } 114#if LSQUIC_TEST_QUANTUM_READINESS 115 else if (params->tp_flags & TRAPA_QUANTUM_READY) 116 need += 4 + QUANTUM_READY_SZ; 117#endif 118 119 for (tpi = 0; tpi <= MAX_TPI; ++tpi) 120 if ((NUMERIC_TRANS_PARAMS & (1 << tpi)) 121 && params->tp_numerics_u.a[tpi2idx[tpi]] != def_vals[tpi]) 122 { 123 if (params->tp_numerics_u.a[tpi2idx[tpi]] < max_vals[tpi]) 124 { 125 bits[tpi] = vint_val2bits(params->tp_numerics_u.a[tpi2idx[tpi]]); 126 need += 4 + (1 << bits[tpi]); 127 } 128 else 129 { 130 LSQ_DEBUG("numeric value is too large (%"PRIu64" vs maximum " 131 "of %"PRIu64, params->tp_numerics_u.a[tpi2idx[tpi]], 132 max_vals[tpi]); 133 return -1; 134 } 135 } 136 137 if (params->tp_disable_active_migration != TP_DEF_DISABLE_ACTIVE_MIGRATION) 138 need += 4 + 0; 139 140 if (params->tp_flags & TRAPA_QL_BITS) 141 need += 4 + 0; 142 143 if (need > bufsz || need > UINT16_MAX) 144 { 145 errno = ENOBUFS; 146 return -1; 147 } 148 149 p = buf; 150 151#define WRITE_TO_P(src, len) do { \ 152 memcpy(p, src, len); \ 153 p += len; \ 154} while (0) 155 156#if __BYTE_ORDER == __LITTLE_ENDIAN 157#define WRITE_UINT_TO_P(val, width) do { \ 158 u##width = bswap_##width(val); \ 159 WRITE_TO_P(&u##width, sizeof(u##width)); \ 160} while (0) 161#else 162#define WRITE_UINT_TO_P(val, width) do { \ 163 u##width = val; \ 164 WRITE_TO_P(&u##width, sizeof(u##width)); \ 165} while (0) 166#endif 167 168#define WRITE_PARAM_TO_P(tpidx, tpval, width) do { \ 169 WRITE_UINT_TO_P(tpidx, 16); \ 170 WRITE_UINT_TO_P(width / 8, 16); \ 171 if (width > 8) \ 172 WRITE_UINT_TO_P(tpval, width); \ 173 else if (width) \ 174 *p++ = tpval; \ 175} while (0) 176 177 WRITE_UINT_TO_P(need - 2 + buf - p, 16); 178 179 for (tpi = 0; tpi <= MAX_TPI; ++tpi) 180 if (NUMERIC_TRANS_PARAMS & (1 << tpi)) 181 { 182 if (params->tp_numerics_u.a[tpi2idx[tpi]] != def_vals[tpi]) 183 { 184 WRITE_UINT_TO_P(tpi, 16); 185 WRITE_UINT_TO_P(1 << bits[tpi], 16); 186 vint_write(p, params->tp_numerics_u.a[tpi2idx[tpi]], bits[tpi], 187 1 << bits[tpi]); 188 p += 1 << bits[tpi]; 189 } 190 } 191 else 192 switch (tpi) 193 { 194 case TPI_ORIGINAL_CONNECTION_ID: 195 if (params->tp_flags & TRAPA_ORIGINAL_CID) 196 { 197 WRITE_UINT_TO_P(TPI_ORIGINAL_CONNECTION_ID, 16); 198 WRITE_UINT_TO_P(params->tp_original_cid.len, 16); 199 WRITE_TO_P(params->tp_original_cid.idbuf, 200 params->tp_original_cid.len); 201 } 202 break; 203 case TPI_STATELESS_RESET_TOKEN: 204 if (params->tp_flags & TRAPA_RESET_TOKEN) 205 { 206 WRITE_UINT_TO_P(TPI_STATELESS_RESET_TOKEN, 16); 207 WRITE_UINT_TO_P(sizeof(params->tp_stateless_reset_token), 208 16); 209 WRITE_TO_P(params->tp_stateless_reset_token, 210 sizeof(params->tp_stateless_reset_token)); 211 } 212 break; 213 case TPI_PREFERRED_ADDRESS: 214 if (params->tp_flags 215 & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6)) 216 { 217 WRITE_UINT_TO_P(TPI_PREFERRED_ADDRESS, 16); 218 WRITE_UINT_TO_P(preferred_address_size(params), 16); 219 if (params->tp_flags & TRAPA_PREFADDR_IPv4) 220 { 221 WRITE_TO_P(¶ms->tp_preferred_address.ipv4_addr, 222 sizeof(params->tp_preferred_address.ipv4_addr)); 223 WRITE_UINT_TO_P(params->tp_preferred_address.ipv4_port, 224 16); 225 } 226 else 227 { 228 memset(p, 0, 6); 229 p += 6; 230 } 231 if (params->tp_flags & TRAPA_PREFADDR_IPv6) 232 { 233 WRITE_TO_P(¶ms->tp_preferred_address.ipv6_addr, 234 sizeof(params->tp_preferred_address.ipv6_addr)); 235 WRITE_UINT_TO_P(params->tp_preferred_address.ipv6_port, 236 16); 237 } 238 else 239 { 240 memset(p, 0, 18); 241 p += 18; 242 } 243 *p++ = params->tp_preferred_address.cid.len; 244 WRITE_TO_P(params->tp_preferred_address.cid.idbuf, 245 params->tp_preferred_address.cid.len); 246 WRITE_TO_P(params->tp_preferred_address.srst, 247 sizeof(params->tp_preferred_address.srst)); 248 } 249 break; 250 case TPI_DISABLE_ACTIVE_MIGRATION: 251 if (params->tp_disable_active_migration != TP_DEF_DISABLE_ACTIVE_MIGRATION) 252 { 253 WRITE_UINT_TO_P(TPI_DISABLE_ACTIVE_MIGRATION, 16); 254 WRITE_UINT_TO_P(0, 16); 255 } 256 break; 257 default: 258 assert(0); 259 return -1; 260 } 261 262 if (params->tp_flags & TRAPA_QL_BITS) 263 { 264 WRITE_UINT_TO_P(TPI_QL_BITS, 16); 265 WRITE_UINT_TO_P(0, 16); 266 } 267 268#if LSQUIC_TEST_QUANTUM_READINESS 269 if (params->tp_flags & TRAPA_QUANTUM_READY) 270 { 271 WRITE_UINT_TO_P(TPI_QUANTUM_READINESS, 16); 272 WRITE_UINT_TO_P(QUANTUM_READY_SZ, 16); 273 memset(p, 'Q', QUANTUM_READY_SZ); 274 p += QUANTUM_READY_SZ; 275 } 276#endif 277 278 assert(buf + need == p); 279 return (int) (p - buf); 280 281#undef WRITE_TO_P 282#undef WRITE_UINT_TO_P 283} 284 285 286int 287lsquic_tp_decode (const unsigned char *const buf, size_t bufsz, 288 int is_server, 289 struct transport_params *params) 290{ 291 const unsigned char *p, *end, *q; 292 uint16_t len, param_id, tlen; 293 unsigned set_of_ids; 294 int s; 295 296 p = buf; 297 end = buf + bufsz; 298 299 *params = TP_INITIALIZER(); 300 301 if (is_server) 302 params->tp_flags |= TRAPA_SERVER; 303 304 if (end - p < 2) 305 return -1; 306 READ_UINT(len, 16, p, 2); 307 p += 2; 308 if (len > end - p) 309 return -1; 310 end = p + len; 311 312#define EXPECT_LEN(expected_len) do { \ 313 if (expected_len != len) \ 314 return -1; \ 315} while (0) 316 317#define EXPECT_AT_LEAST(expected_len) do { \ 318 if ((expected_len) > (uintptr_t) (p + len - q)) \ 319 return -1; \ 320} while (0) 321 322 set_of_ids = 0; 323 while (p < end) 324 { 325 READ_UINT(param_id, 16, p, 2); 326 p += 2; 327 READ_UINT(len, 16, p, 2); 328 p += 2; 329 if (len > end - p) 330 return -1; 331 /* If we need to support parameter IDs 31 and up, we will need to 332 * change this code: 333 */ 334 if (param_id < sizeof(set_of_ids) * 8) 335 { 336 /* Only check duplicates for IDs <= 31: all standard parameters 337 * fit in a bitmask 32 bits wide. 338 */ 339 if (set_of_ids & (1 << param_id)) 340 return -1; 341 set_of_ids |= 1 << param_id; 342 } 343 else 344 goto gt32; 345 if (NUMERIC_TRANS_PARAMS & (1u << param_id)) 346 { 347 switch (len) 348 { 349 case 1: 350 case 2: 351 case 4: 352 case 8: 353 s = vint_read(p, p + len, 354 ¶ms->tp_numerics_u.a[tpi2idx[param_id]]); 355 if (s == len) 356 { 357 if (params->tp_numerics_u.a[tpi2idx[param_id]] 358 > max_vals[param_id]) 359 { 360 LSQ_DEBUG("numeric value of parameter 0x%X is too " 361 "large (%"PRIu64" vs maximum of %"PRIu64, 362 param_id, 363 params->tp_numerics_u.a[tpi2idx[param_id]], 364 max_vals[param_id]); 365 return -1; 366 } 367 p += s; 368 break; 369 } 370 else 371 { 372 LSQ_DEBUG("cannot read the value of numeric transport " 373 "param %u of length %u", param_id, len); 374 return -1; 375 } 376 default: 377 LSQ_DEBUG("invalid length=%u for numeric transport parameter", 378 len); 379 return -1; 380 } 381 } 382 else 383 { 384 gt32: switch (param_id) 385 { 386 case TPI_DISABLE_ACTIVE_MIGRATION: 387 EXPECT_LEN(0); 388 params->tp_disable_active_migration = 1; 389 break; 390 case TPI_STATELESS_RESET_TOKEN: 391 /* Client MUST not include reset token, 392 * see [draft-ietf-quic-transport-11], Section 6.4.1 393 */ 394 if (!is_server) 395 return -1; 396 EXPECT_LEN(sizeof(params->tp_stateless_reset_token)); 397 memcpy(params->tp_stateless_reset_token, p, 398 sizeof(params->tp_stateless_reset_token)); 399 params->tp_flags |= TRAPA_RESET_TOKEN; 400 break; 401 case TPI_ORIGINAL_CONNECTION_ID: 402 /* Client MUST not original connecti ID, 403 * see [draft-ietf-quic-transport-15], Section 6.6.1 404 */ 405 if (!is_server) 406 return -1; 407 if (len > MAX_CID_LEN) 408 return -1; 409 memcpy(params->tp_original_cid.idbuf, p, len); 410 params->tp_original_cid.len = len; 411 params->tp_flags |= TRAPA_ORIGINAL_CID; 412 break; 413 case TPI_PREFERRED_ADDRESS: 414 /* Client MUST not include preferred address, 415 * see [draft-ietf-quic-transport-12], Section 6.4.1 416 */ 417 if (!is_server) 418 return -1; 419 q = p; 420 EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_addr)); 421 memcpy(params->tp_preferred_address.ipv4_addr, q, 422 sizeof(params->tp_preferred_address.ipv4_addr)); 423 q += sizeof(params->tp_preferred_address.ipv4_addr); 424 EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_port)); 425 READ_UINT(params->tp_preferred_address.ipv4_port, 16, q, 2); 426 q += 2; 427 EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_addr)); 428 memcpy(params->tp_preferred_address.ipv6_addr, q, 429 sizeof(params->tp_preferred_address.ipv6_addr)); 430 q += sizeof(params->tp_preferred_address.ipv6_addr); 431 EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_port)); 432 READ_UINT(params->tp_preferred_address.ipv6_port, 16, q, 2); 433 q += 2; 434 EXPECT_AT_LEAST(1); 435 tlen = *q; 436 q += 1; 437 if (tlen < 4 || tlen > MAX_CID_LEN) 438 { 439 LSQ_DEBUG("preferred server address contains invalid " 440 "CID length of %"PRIu16" bytes", tlen); 441 return -1; 442 } 443 EXPECT_AT_LEAST(tlen); 444 memcpy(params->tp_preferred_address.cid.idbuf, q, tlen); 445 params->tp_preferred_address.cid.len = tlen; 446 q += tlen; 447 EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.srst)); 448 memcpy(params->tp_preferred_address.srst, q, 449 sizeof(params->tp_preferred_address.srst)); 450 q += sizeof(params->tp_preferred_address.srst); 451 if (q != p + len) 452 return -1; 453 if (params->tp_preferred_address.ipv4_port 454 && !lsquic_is_zero(params->tp_preferred_address.ipv4_addr, 455 sizeof(params->tp_preferred_address.ipv4_addr))) 456 params->tp_flags |= TRAPA_PREFADDR_IPv4; 457 if (params->tp_preferred_address.ipv6_port 458 && !lsquic_is_zero(params->tp_preferred_address.ipv6_addr, 459 sizeof(params->tp_preferred_address.ipv6_addr))) 460 params->tp_flags |= TRAPA_PREFADDR_IPv6; 461 break; 462 case TPI_QL_BITS: 463 EXPECT_LEN(0); 464 params->tp_flags |= TRAPA_QL_BITS; 465 break; 466 } 467 p += len; 468 } 469 } 470 471 if (p != end) 472 return -1; 473 474 return (int) (end - buf); 475#undef EXPECT_LEN 476} 477 478 479void 480lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz) 481{ 482 char *const end = buf + sz; 483 int nw; 484 char tok_str[sizeof(params->tp_stateless_reset_token) * 2 + 1]; 485 char addr_str[INET6_ADDRSTRLEN]; 486 487#define SEMICOLON "; " 488#define WRITE_ONE_PARAM(name, fmt) do { \ 489 nw = snprintf(buf, end - buf, #name ": " fmt SEMICOLON, params->tp_##name); \ 490 buf += nw; \ 491 if (buf >= end) \ 492 return; \ 493} while (0) 494 495 WRITE_ONE_PARAM(init_max_stream_data_bidi_local, "%"PRIu64); 496 WRITE_ONE_PARAM(init_max_stream_data_bidi_remote, "%"PRIu64); 497 WRITE_ONE_PARAM(init_max_stream_data_uni, "%"PRIu64); 498 WRITE_ONE_PARAM(init_max_data, "%"PRIu64); 499 WRITE_ONE_PARAM(idle_timeout, "%"PRIu64); 500 WRITE_ONE_PARAM(init_max_streams_bidi, "%"PRIu64); 501 WRITE_ONE_PARAM(init_max_streams_uni, "%"PRIu64); 502 WRITE_ONE_PARAM(max_packet_size, "%"PRIu64); 503 WRITE_ONE_PARAM(ack_delay_exponent, "%"PRIu64); 504 WRITE_ONE_PARAM(active_connection_id_limit, "%"PRIu64); 505 WRITE_ONE_PARAM(disable_active_migration, "%hhd"); 506#undef SEMICOLON 507#define SEMICOLON "" 508 WRITE_ONE_PARAM(max_ack_delay, "%"PRIu64); 509 if (params->tp_flags & TRAPA_RESET_TOKEN) 510 { 511 lsquic_hexstr(params->tp_stateless_reset_token, 512 sizeof(params->tp_stateless_reset_token), tok_str, sizeof(tok_str)); 513 nw = snprintf(buf, end - buf, "; stateless_reset_token: %s", tok_str); 514 buf += nw; 515 if (buf >= end) 516 return; 517 } 518 if (params->tp_flags & TRAPA_RESET_TOKEN) 519 { 520 char cidbuf_[MAX_CID_LEN * 2 + 1]; 521 nw = snprintf(buf, end - buf, "; original DCID (ODCID): %"CID_FMT, 522 CID_BITS(¶ms->tp_original_cid)); 523 buf += nw; 524 if (buf >= end) 525 return; 526 } 527 if (params->tp_flags & TRAPA_PREFADDR_IPv4) 528 { 529 if (inet_ntop(AF_INET, params->tp_preferred_address.ipv4_addr, 530 addr_str, sizeof(addr_str))) 531 { 532 nw = snprintf(buf, end - buf, "; IPv4 preferred address: %s:%u", 533 addr_str, params->tp_preferred_address.ipv4_port); 534 buf += nw; 535 if (buf >= end) 536 return; 537 } 538 } 539 if (params->tp_flags & TRAPA_PREFADDR_IPv6) 540 { 541 if (inet_ntop(AF_INET6, params->tp_preferred_address.ipv6_addr, 542 addr_str, sizeof(addr_str))) 543 { 544 nw = snprintf(buf, end - buf, "; IPv6 preferred address: %s:%u", 545 addr_str, params->tp_preferred_address.ipv6_port); 546 buf += nw; 547 if (buf >= end) 548 return; 549 } 550 } 551 if (params->tp_flags & TRAPA_QL_BITS) 552 { 553 nw = snprintf(buf, end - buf, "; QL loss bits"); 554 buf += nw; 555 if (buf >= end) 556 return; 557 } 558 559#undef SEMICOLON 560#undef WRITE_ONE_PARAM 561} 562