diff options
| author | Takashi Iwai <tiwai@suse.de> | 2009-12-15 04:29:06 -0500 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2009-12-15 04:29:06 -0500 |
| commit | 709334c87dbdb44150ce436b3d13c814db0dcae9 (patch) | |
| tree | 5861a45f70c1f283720337abd864498f5afb3dbe /net/ipv4/tcp_output.c | |
| parent | 0d64b568fcd48b133721c1d322e7c51d85eb12df (diff) | |
| parent | f74890277a196949e4004fe2955e1d4fb3930f98 (diff) | |
Merge branch 'fixes' of git://git.alsa-project.org/alsa-kernel into for-linus
Diffstat (limited to 'net/ipv4/tcp_output.c')
| -rw-r--r-- | net/ipv4/tcp_output.c | 329 |
1 files changed, 272 insertions, 57 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index fcd278a7080e..93316a96d820 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
| @@ -59,6 +59,10 @@ int sysctl_tcp_base_mss __read_mostly = 512; | |||
| 59 | /* By default, RFC2861 behavior. */ | 59 | /* By default, RFC2861 behavior. */ |
| 60 | int sysctl_tcp_slow_start_after_idle __read_mostly = 1; | 60 | int sysctl_tcp_slow_start_after_idle __read_mostly = 1; |
| 61 | 61 | ||
| 62 | int sysctl_tcp_cookie_size __read_mostly = 0; /* TCP_COOKIE_MAX */ | ||
| 63 | EXPORT_SYMBOL_GPL(sysctl_tcp_cookie_size); | ||
| 64 | |||
| 65 | |||
| 62 | /* Account for new data that has been sent to the network. */ | 66 | /* Account for new data that has been sent to the network. */ |
| 63 | static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb) | 67 | static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb) |
| 64 | { | 68 | { |
| @@ -362,15 +366,45 @@ static inline int tcp_urg_mode(const struct tcp_sock *tp) | |||
| 362 | #define OPTION_TS (1 << 1) | 366 | #define OPTION_TS (1 << 1) |
| 363 | #define OPTION_MD5 (1 << 2) | 367 | #define OPTION_MD5 (1 << 2) |
| 364 | #define OPTION_WSCALE (1 << 3) | 368 | #define OPTION_WSCALE (1 << 3) |
| 369 | #define OPTION_COOKIE_EXTENSION (1 << 4) | ||
| 365 | 370 | ||
| 366 | struct tcp_out_options { | 371 | struct tcp_out_options { |
| 367 | u8 options; /* bit field of OPTION_* */ | 372 | u8 options; /* bit field of OPTION_* */ |
| 368 | u8 ws; /* window scale, 0 to disable */ | 373 | u8 ws; /* window scale, 0 to disable */ |
| 369 | u8 num_sack_blocks; /* number of SACK blocks to include */ | 374 | u8 num_sack_blocks; /* number of SACK blocks to include */ |
| 375 | u8 hash_size; /* bytes in hash_location */ | ||
| 370 | u16 mss; /* 0 to disable */ | 376 | u16 mss; /* 0 to disable */ |
| 371 | __u32 tsval, tsecr; /* need to include OPTION_TS */ | 377 | __u32 tsval, tsecr; /* need to include OPTION_TS */ |
| 378 | __u8 *hash_location; /* temporary pointer, overloaded */ | ||
| 372 | }; | 379 | }; |
| 373 | 380 | ||
| 381 | /* The sysctl int routines are generic, so check consistency here. | ||
| 382 | */ | ||
| 383 | static u8 tcp_cookie_size_check(u8 desired) | ||
| 384 | { | ||
| 385 | if (desired > 0) { | ||
| 386 | /* previously specified */ | ||
| 387 | return desired; | ||
| 388 | } | ||
| 389 | if (sysctl_tcp_cookie_size <= 0) { | ||
| 390 | /* no default specified */ | ||
| 391 | return 0; | ||
| 392 | } | ||
| 393 | if (sysctl_tcp_cookie_size <= TCP_COOKIE_MIN) { | ||
| 394 | /* value too small, specify minimum */ | ||
| 395 | return TCP_COOKIE_MIN; | ||
| 396 | } | ||
| 397 | if (sysctl_tcp_cookie_size >= TCP_COOKIE_MAX) { | ||
| 398 | /* value too large, specify maximum */ | ||
| 399 | return TCP_COOKIE_MAX; | ||
| 400 | } | ||
| 401 | if (0x1 & sysctl_tcp_cookie_size) { | ||
| 402 | /* 8-bit multiple, illegal, fix it */ | ||
| 403 | return (u8)(sysctl_tcp_cookie_size + 0x1); | ||
| 404 | } | ||
| 405 | return (u8)sysctl_tcp_cookie_size; | ||
| 406 | } | ||
| 407 | |||
| 374 | /* Write previously computed TCP options to the packet. | 408 | /* Write previously computed TCP options to the packet. |
| 375 | * | 409 | * |
| 376 | * Beware: Something in the Internet is very sensitive to the ordering of | 410 | * Beware: Something in the Internet is very sensitive to the ordering of |
| @@ -385,17 +419,34 @@ struct tcp_out_options { | |||
| 385 | * (but it may well be that other scenarios fail similarly). | 419 | * (but it may well be that other scenarios fail similarly). |
| 386 | */ | 420 | */ |
| 387 | static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, | 421 | static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, |
| 388 | const struct tcp_out_options *opts, | 422 | struct tcp_out_options *opts) |
| 389 | __u8 **md5_hash) { | 423 | { |
| 390 | if (unlikely(OPTION_MD5 & opts->options)) { | 424 | u8 options = opts->options; /* mungable copy */ |
| 391 | *ptr++ = htonl((TCPOPT_NOP << 24) | | 425 | |
| 392 | (TCPOPT_NOP << 16) | | 426 | /* Having both authentication and cookies for security is redundant, |
| 393 | (TCPOPT_MD5SIG << 8) | | 427 | * and there's certainly not enough room. Instead, the cookie-less |
| 394 | TCPOLEN_MD5SIG); | 428 | * extension variant is proposed. |
| 395 | *md5_hash = (__u8 *)ptr; | 429 | * |
| 430 | * Consider the pessimal case with authentication. The options | ||
| 431 | * could look like: | ||
| 432 | * COOKIE|MD5(20) + MSS(4) + SACK|TS(12) + WSCALE(4) == 40 | ||
| 433 | */ | ||
| 434 | if (unlikely(OPTION_MD5 & options)) { | ||
| 435 | if (unlikely(OPTION_COOKIE_EXTENSION & options)) { | ||
| 436 | *ptr++ = htonl((TCPOPT_COOKIE << 24) | | ||
| 437 | (TCPOLEN_COOKIE_BASE << 16) | | ||
| 438 | (TCPOPT_MD5SIG << 8) | | ||
| 439 | TCPOLEN_MD5SIG); | ||
| 440 | } else { | ||
| 441 | *ptr++ = htonl((TCPOPT_NOP << 24) | | ||
| 442 | (TCPOPT_NOP << 16) | | ||
| 443 | (TCPOPT_MD5SIG << 8) | | ||
| 444 | TCPOLEN_MD5SIG); | ||
| 445 | } | ||
| 446 | options &= ~OPTION_COOKIE_EXTENSION; | ||
| 447 | /* overload cookie hash location */ | ||
| 448 | opts->hash_location = (__u8 *)ptr; | ||
| 396 | ptr += 4; | 449 | ptr += 4; |
| 397 | } else { | ||
| 398 | *md5_hash = NULL; | ||
| 399 | } | 450 | } |
| 400 | 451 | ||
| 401 | if (unlikely(opts->mss)) { | 452 | if (unlikely(opts->mss)) { |
| @@ -404,12 +455,13 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, | |||
| 404 | opts->mss); | 455 | opts->mss); |
| 405 | } | 456 | } |
| 406 | 457 | ||
| 407 | if (likely(OPTION_TS & opts->options)) { | 458 | if (likely(OPTION_TS & options)) { |
| 408 | if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) { | 459 | if (unlikely(OPTION_SACK_ADVERTISE & options)) { |
| 409 | *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | | 460 | *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | |
| 410 | (TCPOLEN_SACK_PERM << 16) | | 461 | (TCPOLEN_SACK_PERM << 16) | |
| 411 | (TCPOPT_TIMESTAMP << 8) | | 462 | (TCPOPT_TIMESTAMP << 8) | |
| 412 | TCPOLEN_TIMESTAMP); | 463 | TCPOLEN_TIMESTAMP); |
| 464 | options &= ~OPTION_SACK_ADVERTISE; | ||
| 413 | } else { | 465 | } else { |
| 414 | *ptr++ = htonl((TCPOPT_NOP << 24) | | 466 | *ptr++ = htonl((TCPOPT_NOP << 24) | |
| 415 | (TCPOPT_NOP << 16) | | 467 | (TCPOPT_NOP << 16) | |
| @@ -420,15 +472,52 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, | |||
| 420 | *ptr++ = htonl(opts->tsecr); | 472 | *ptr++ = htonl(opts->tsecr); |
| 421 | } | 473 | } |
| 422 | 474 | ||
| 423 | if (unlikely(OPTION_SACK_ADVERTISE & opts->options && | 475 | /* Specification requires after timestamp, so do it now. |
| 424 | !(OPTION_TS & opts->options))) { | 476 | * |
| 477 | * Consider the pessimal case without authentication. The options | ||
| 478 | * could look like: | ||
| 479 | * MSS(4) + SACK|TS(12) + COOKIE(20) + WSCALE(4) == 40 | ||
| 480 | */ | ||
| 481 | if (unlikely(OPTION_COOKIE_EXTENSION & options)) { | ||
| 482 | __u8 *cookie_copy = opts->hash_location; | ||
| 483 | u8 cookie_size = opts->hash_size; | ||
| 484 | |||
| 485 | /* 8-bit multiple handled in tcp_cookie_size_check() above, | ||
| 486 | * and elsewhere. | ||
| 487 | */ | ||
| 488 | if (0x2 & cookie_size) { | ||
| 489 | __u8 *p = (__u8 *)ptr; | ||
| 490 | |||
| 491 | /* 16-bit multiple */ | ||
| 492 | *p++ = TCPOPT_COOKIE; | ||
| 493 | *p++ = TCPOLEN_COOKIE_BASE + cookie_size; | ||
| 494 | *p++ = *cookie_copy++; | ||
| 495 | *p++ = *cookie_copy++; | ||
| 496 | ptr++; | ||
| 497 | cookie_size -= 2; | ||
| 498 | } else { | ||
| 499 | /* 32-bit multiple */ | ||
| 500 | *ptr++ = htonl(((TCPOPT_NOP << 24) | | ||
| 501 | (TCPOPT_NOP << 16) | | ||
| 502 | (TCPOPT_COOKIE << 8) | | ||
| 503 | TCPOLEN_COOKIE_BASE) + | ||
| 504 | cookie_size); | ||
| 505 | } | ||
| 506 | |||
| 507 | if (cookie_size > 0) { | ||
| 508 | memcpy(ptr, cookie_copy, cookie_size); | ||
| 509 | ptr += (cookie_size / 4); | ||
| 510 | } | ||
| 511 | } | ||
| 512 | |||
| 513 | if (unlikely(OPTION_SACK_ADVERTISE & options)) { | ||
| 425 | *ptr++ = htonl((TCPOPT_NOP << 24) | | 514 | *ptr++ = htonl((TCPOPT_NOP << 24) | |
| 426 | (TCPOPT_NOP << 16) | | 515 | (TCPOPT_NOP << 16) | |
| 427 | (TCPOPT_SACK_PERM << 8) | | 516 | (TCPOPT_SACK_PERM << 8) | |
| 428 | TCPOLEN_SACK_PERM); | 517 | TCPOLEN_SACK_PERM); |
| 429 | } | 518 | } |
| 430 | 519 | ||
| 431 | if (unlikely(OPTION_WSCALE & opts->options)) { | 520 | if (unlikely(OPTION_WSCALE & options)) { |
| 432 | *ptr++ = htonl((TCPOPT_NOP << 24) | | 521 | *ptr++ = htonl((TCPOPT_NOP << 24) | |
| 433 | (TCPOPT_WINDOW << 16) | | 522 | (TCPOPT_WINDOW << 16) | |
| 434 | (TCPOLEN_WINDOW << 8) | | 523 | (TCPOLEN_WINDOW << 8) | |
| @@ -463,13 +552,18 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, | |||
| 463 | struct tcp_out_options *opts, | 552 | struct tcp_out_options *opts, |
| 464 | struct tcp_md5sig_key **md5) { | 553 | struct tcp_md5sig_key **md5) { |
| 465 | struct tcp_sock *tp = tcp_sk(sk); | 554 | struct tcp_sock *tp = tcp_sk(sk); |
| 466 | unsigned size = 0; | 555 | struct tcp_cookie_values *cvp = tp->cookie_values; |
| 556 | struct dst_entry *dst = __sk_dst_get(sk); | ||
| 557 | unsigned remaining = MAX_TCP_OPTION_SPACE; | ||
| 558 | u8 cookie_size = (!tp->rx_opt.cookie_out_never && cvp != NULL) ? | ||
| 559 | tcp_cookie_size_check(cvp->cookie_desired) : | ||
| 560 | 0; | ||
| 467 | 561 | ||
| 468 | #ifdef CONFIG_TCP_MD5SIG | 562 | #ifdef CONFIG_TCP_MD5SIG |
| 469 | *md5 = tp->af_specific->md5_lookup(sk, sk); | 563 | *md5 = tp->af_specific->md5_lookup(sk, sk); |
| 470 | if (*md5) { | 564 | if (*md5) { |
| 471 | opts->options |= OPTION_MD5; | 565 | opts->options |= OPTION_MD5; |
| 472 | size += TCPOLEN_MD5SIG_ALIGNED; | 566 | remaining -= TCPOLEN_MD5SIG_ALIGNED; |
| 473 | } | 567 | } |
| 474 | #else | 568 | #else |
| 475 | *md5 = NULL; | 569 | *md5 = NULL; |
| @@ -485,26 +579,76 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, | |||
| 485 | * SACKs don't matter, we never delay an ACK when we have any of those | 579 | * SACKs don't matter, we never delay an ACK when we have any of those |
| 486 | * going out. */ | 580 | * going out. */ |
| 487 | opts->mss = tcp_advertise_mss(sk); | 581 | opts->mss = tcp_advertise_mss(sk); |
| 488 | size += TCPOLEN_MSS_ALIGNED; | 582 | remaining -= TCPOLEN_MSS_ALIGNED; |
| 489 | 583 | ||
| 490 | if (likely(sysctl_tcp_timestamps && *md5 == NULL)) { | 584 | if (likely(sysctl_tcp_timestamps && |
| 585 | !dst_feature(dst, RTAX_FEATURE_NO_TSTAMP) && | ||
| 586 | *md5 == NULL)) { | ||
| 491 | opts->options |= OPTION_TS; | 587 | opts->options |= OPTION_TS; |
| 492 | opts->tsval = TCP_SKB_CB(skb)->when; | 588 | opts->tsval = TCP_SKB_CB(skb)->when; |
| 493 | opts->tsecr = tp->rx_opt.ts_recent; | 589 | opts->tsecr = tp->rx_opt.ts_recent; |
| 494 | size += TCPOLEN_TSTAMP_ALIGNED; | 590 | remaining -= TCPOLEN_TSTAMP_ALIGNED; |
| 495 | } | 591 | } |
| 496 | if (likely(sysctl_tcp_window_scaling)) { | 592 | if (likely(sysctl_tcp_window_scaling && |
| 593 | !dst_feature(dst, RTAX_FEATURE_NO_WSCALE))) { | ||
| 497 | opts->ws = tp->rx_opt.rcv_wscale; | 594 | opts->ws = tp->rx_opt.rcv_wscale; |
| 498 | opts->options |= OPTION_WSCALE; | 595 | opts->options |= OPTION_WSCALE; |
| 499 | size += TCPOLEN_WSCALE_ALIGNED; | 596 | remaining -= TCPOLEN_WSCALE_ALIGNED; |
| 500 | } | 597 | } |
| 501 | if (likely(sysctl_tcp_sack)) { | 598 | if (likely(sysctl_tcp_sack && |
| 599 | !dst_feature(dst, RTAX_FEATURE_NO_SACK))) { | ||
| 502 | opts->options |= OPTION_SACK_ADVERTISE; | 600 | opts->options |= OPTION_SACK_ADVERTISE; |
| 503 | if (unlikely(!(OPTION_TS & opts->options))) | 601 | if (unlikely(!(OPTION_TS & opts->options))) |
| 504 | size += TCPOLEN_SACKPERM_ALIGNED; | 602 | remaining -= TCPOLEN_SACKPERM_ALIGNED; |
| 505 | } | 603 | } |
| 506 | 604 | ||
| 507 | return size; | 605 | /* Note that timestamps are required by the specification. |
| 606 | * | ||
| 607 | * Odd numbers of bytes are prohibited by the specification, ensuring | ||
| 608 | * that the cookie is 16-bit aligned, and the resulting cookie pair is | ||
| 609 | * 32-bit aligned. | ||
| 610 | */ | ||
| 611 | if (*md5 == NULL && | ||
| 612 | (OPTION_TS & opts->options) && | ||
| 613 | cookie_size > 0) { | ||
| 614 | int need = TCPOLEN_COOKIE_BASE + cookie_size; | ||
| 615 | |||
| 616 | if (0x2 & need) { | ||
| 617 | /* 32-bit multiple */ | ||
| 618 | need += 2; /* NOPs */ | ||
| 619 | |||
| 620 | if (need > remaining) { | ||
| 621 | /* try shrinking cookie to fit */ | ||
| 622 | cookie_size -= 2; | ||
| 623 | need -= 4; | ||
| 624 | } | ||
| 625 | } | ||
| 626 | while (need > remaining && TCP_COOKIE_MIN <= cookie_size) { | ||
| 627 | cookie_size -= 4; | ||
| 628 | need -= 4; | ||
| 629 | } | ||
| 630 | if (TCP_COOKIE_MIN <= cookie_size) { | ||
| 631 | opts->options |= OPTION_COOKIE_EXTENSION; | ||
| 632 | opts->hash_location = (__u8 *)&cvp->cookie_pair[0]; | ||
| 633 | opts->hash_size = cookie_size; | ||
| 634 | |||
| 635 | /* Remember for future incarnations. */ | ||
| 636 | cvp->cookie_desired = cookie_size; | ||
| 637 | |||
| 638 | if (cvp->cookie_desired != cvp->cookie_pair_size) { | ||
| 639 | /* Currently use random bytes as a nonce, | ||
| 640 | * assuming these are completely unpredictable | ||
| 641 | * by hostile users of the same system. | ||
| 642 | */ | ||
| 643 | get_random_bytes(&cvp->cookie_pair[0], | ||
| 644 | cookie_size); | ||
| 645 | cvp->cookie_pair_size = cookie_size; | ||
| 646 | } | ||
| 647 | |||
| 648 | remaining -= need; | ||
| 649 | } | ||
| 650 | } | ||
| 651 | return MAX_TCP_OPTION_SPACE - remaining; | ||
| 508 | } | 652 | } |
| 509 | 653 | ||
| 510 | /* Set up TCP options for SYN-ACKs. */ | 654 | /* Set up TCP options for SYN-ACKs. */ |
| @@ -512,48 +656,77 @@ static unsigned tcp_synack_options(struct sock *sk, | |||
| 512 | struct request_sock *req, | 656 | struct request_sock *req, |
| 513 | unsigned mss, struct sk_buff *skb, | 657 | unsigned mss, struct sk_buff *skb, |
| 514 | struct tcp_out_options *opts, | 658 | struct tcp_out_options *opts, |
| 515 | struct tcp_md5sig_key **md5) { | 659 | struct tcp_md5sig_key **md5, |
| 516 | unsigned size = 0; | 660 | struct tcp_extend_values *xvp) |
| 661 | { | ||
| 517 | struct inet_request_sock *ireq = inet_rsk(req); | 662 | struct inet_request_sock *ireq = inet_rsk(req); |
| 518 | char doing_ts; | 663 | unsigned remaining = MAX_TCP_OPTION_SPACE; |
| 664 | u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ? | ||
| 665 | xvp->cookie_plus : | ||
| 666 | 0; | ||
| 667 | bool doing_ts = ireq->tstamp_ok; | ||
| 519 | 668 | ||
| 520 | #ifdef CONFIG_TCP_MD5SIG | 669 | #ifdef CONFIG_TCP_MD5SIG |
| 521 | *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); | 670 | *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); |
| 522 | if (*md5) { | 671 | if (*md5) { |
| 523 | opts->options |= OPTION_MD5; | 672 | opts->options |= OPTION_MD5; |
| 524 | size += TCPOLEN_MD5SIG_ALIGNED; | 673 | remaining -= TCPOLEN_MD5SIG_ALIGNED; |
| 674 | |||
| 675 | /* We can't fit any SACK blocks in a packet with MD5 + TS | ||
| 676 | * options. There was discussion about disabling SACK | ||
| 677 | * rather than TS in order to fit in better with old, | ||
| 678 | * buggy kernels, but that was deemed to be unnecessary. | ||
| 679 | */ | ||
| 680 | doing_ts &= !ireq->sack_ok; | ||
| 525 | } | 681 | } |
| 526 | #else | 682 | #else |
| 527 | *md5 = NULL; | 683 | *md5 = NULL; |
| 528 | #endif | 684 | #endif |
| 529 | 685 | ||
| 530 | /* we can't fit any SACK blocks in a packet with MD5 + TS | 686 | /* We always send an MSS option. */ |
| 531 | options. There was discussion about disabling SACK rather than TS in | ||
| 532 | order to fit in better with old, buggy kernels, but that was deemed | ||
| 533 | to be unnecessary. */ | ||
| 534 | doing_ts = ireq->tstamp_ok && !(*md5 && ireq->sack_ok); | ||
| 535 | |||
| 536 | opts->mss = mss; | 687 | opts->mss = mss; |
| 537 | size += TCPOLEN_MSS_ALIGNED; | 688 | remaining -= TCPOLEN_MSS_ALIGNED; |
| 538 | 689 | ||
| 539 | if (likely(ireq->wscale_ok)) { | 690 | if (likely(ireq->wscale_ok)) { |
| 540 | opts->ws = ireq->rcv_wscale; | 691 | opts->ws = ireq->rcv_wscale; |
| 541 | opts->options |= OPTION_WSCALE; | 692 | opts->options |= OPTION_WSCALE; |
| 542 | size += TCPOLEN_WSCALE_ALIGNED; | 693 | remaining -= TCPOLEN_WSCALE_ALIGNED; |
| 543 | } | 694 | } |
| 544 | if (likely(doing_ts)) { | 695 | if (likely(doing_ts)) { |
| 545 | opts->options |= OPTION_TS; | 696 | opts->options |= OPTION_TS; |
| 546 | opts->tsval = TCP_SKB_CB(skb)->when; | 697 | opts->tsval = TCP_SKB_CB(skb)->when; |
| 547 | opts->tsecr = req->ts_recent; | 698 | opts->tsecr = req->ts_recent; |
| 548 | size += TCPOLEN_TSTAMP_ALIGNED; | 699 | remaining -= TCPOLEN_TSTAMP_ALIGNED; |
| 549 | } | 700 | } |
| 550 | if (likely(ireq->sack_ok)) { | 701 | if (likely(ireq->sack_ok)) { |
| 551 | opts->options |= OPTION_SACK_ADVERTISE; | 702 | opts->options |= OPTION_SACK_ADVERTISE; |
| 552 | if (unlikely(!doing_ts)) | 703 | if (unlikely(!doing_ts)) |
| 553 | size += TCPOLEN_SACKPERM_ALIGNED; | 704 | remaining -= TCPOLEN_SACKPERM_ALIGNED; |
| 554 | } | 705 | } |
| 555 | 706 | ||
| 556 | return size; | 707 | /* Similar rationale to tcp_syn_options() applies here, too. |
| 708 | * If the <SYN> options fit, the same options should fit now! | ||
| 709 | */ | ||
| 710 | if (*md5 == NULL && | ||
| 711 | doing_ts && | ||
| 712 | cookie_plus > TCPOLEN_COOKIE_BASE) { | ||
| 713 | int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */ | ||
| 714 | |||
| 715 | if (0x2 & need) { | ||
| 716 | /* 32-bit multiple */ | ||
| 717 | need += 2; /* NOPs */ | ||
| 718 | } | ||
| 719 | if (need <= remaining) { | ||
| 720 | opts->options |= OPTION_COOKIE_EXTENSION; | ||
| 721 | opts->hash_size = cookie_plus - TCPOLEN_COOKIE_BASE; | ||
| 722 | remaining -= need; | ||
| 723 | } else { | ||
| 724 | /* There's no error return, so flag it. */ | ||
| 725 | xvp->cookie_out_never = 1; /* true */ | ||
| 726 | opts->hash_size = 0; | ||
| 727 | } | ||
| 728 | } | ||
| 729 | return MAX_TCP_OPTION_SPACE - remaining; | ||
| 557 | } | 730 | } |
| 558 | 731 | ||
| 559 | /* Compute TCP options for ESTABLISHED sockets. This is not the | 732 | /* Compute TCP options for ESTABLISHED sockets. This is not the |
| @@ -619,7 +792,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
| 619 | struct tcp_out_options opts; | 792 | struct tcp_out_options opts; |
| 620 | unsigned tcp_options_size, tcp_header_size; | 793 | unsigned tcp_options_size, tcp_header_size; |
| 621 | struct tcp_md5sig_key *md5; | 794 | struct tcp_md5sig_key *md5; |
| 622 | __u8 *md5_hash_location; | ||
| 623 | struct tcphdr *th; | 795 | struct tcphdr *th; |
| 624 | int err; | 796 | int err; |
| 625 | 797 | ||
| @@ -661,8 +833,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
| 661 | 833 | ||
| 662 | /* Build TCP header and checksum it. */ | 834 | /* Build TCP header and checksum it. */ |
| 663 | th = tcp_hdr(skb); | 835 | th = tcp_hdr(skb); |
| 664 | th->source = inet->sport; | 836 | th->source = inet->inet_sport; |
| 665 | th->dest = inet->dport; | 837 | th->dest = inet->inet_dport; |
| 666 | th->seq = htonl(tcb->seq); | 838 | th->seq = htonl(tcb->seq); |
| 667 | th->ack_seq = htonl(tp->rcv_nxt); | 839 | th->ack_seq = htonl(tp->rcv_nxt); |
| 668 | *(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) | | 840 | *(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) | |
| @@ -690,7 +862,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
| 690 | } | 862 | } |
| 691 | } | 863 | } |
| 692 | 864 | ||
| 693 | tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location); | 865 | tcp_options_write((__be32 *)(th + 1), tp, &opts); |
| 694 | if (likely((tcb->flags & TCPCB_FLAG_SYN) == 0)) | 866 | if (likely((tcb->flags & TCPCB_FLAG_SYN) == 0)) |
| 695 | TCP_ECN_send(sk, skb, tcp_header_size); | 867 | TCP_ECN_send(sk, skb, tcp_header_size); |
| 696 | 868 | ||
| @@ -698,7 +870,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
| 698 | /* Calculate the MD5 hash, as we have all we need now */ | 870 | /* Calculate the MD5 hash, as we have all we need now */ |
| 699 | if (md5) { | 871 | if (md5) { |
| 700 | sk->sk_route_caps &= ~NETIF_F_GSO_MASK; | 872 | sk->sk_route_caps &= ~NETIF_F_GSO_MASK; |
| 701 | tp->af_specific->calc_md5_hash(md5_hash_location, | 873 | tp->af_specific->calc_md5_hash(opts.hash_location, |
| 702 | md5, sk, NULL, skb); | 874 | md5, sk, NULL, skb); |
| 703 | } | 875 | } |
| 704 | #endif | 876 | #endif |
| @@ -1918,8 +2090,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) | |||
| 1918 | * case, when window is shrunk to zero. In this case | 2090 | * case, when window is shrunk to zero. In this case |
| 1919 | * our retransmit serves as a zero window probe. | 2091 | * our retransmit serves as a zero window probe. |
| 1920 | */ | 2092 | */ |
| 1921 | if (!before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp)) | 2093 | if (!before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp)) && |
| 1922 | && TCP_SKB_CB(skb)->seq != tp->snd_una) | 2094 | TCP_SKB_CB(skb)->seq != tp->snd_una) |
| 1923 | return -EAGAIN; | 2095 | return -EAGAIN; |
| 1924 | 2096 | ||
| 1925 | if (skb->len > cur_mss) { | 2097 | if (skb->len > cur_mss) { |
| @@ -2219,16 +2391,17 @@ int tcp_send_synack(struct sock *sk) | |||
| 2219 | 2391 | ||
| 2220 | /* Prepare a SYN-ACK. */ | 2392 | /* Prepare a SYN-ACK. */ |
| 2221 | struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | 2393 | struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, |
| 2222 | struct request_sock *req) | 2394 | struct request_sock *req, |
| 2395 | struct request_values *rvp) | ||
| 2223 | { | 2396 | { |
| 2397 | struct tcp_out_options opts; | ||
| 2398 | struct tcp_extend_values *xvp = tcp_xv(rvp); | ||
| 2224 | struct inet_request_sock *ireq = inet_rsk(req); | 2399 | struct inet_request_sock *ireq = inet_rsk(req); |
| 2225 | struct tcp_sock *tp = tcp_sk(sk); | 2400 | struct tcp_sock *tp = tcp_sk(sk); |
| 2226 | struct tcphdr *th; | 2401 | struct tcphdr *th; |
| 2227 | int tcp_header_size; | ||
| 2228 | struct tcp_out_options opts; | ||
| 2229 | struct sk_buff *skb; | 2402 | struct sk_buff *skb; |
| 2230 | struct tcp_md5sig_key *md5; | 2403 | struct tcp_md5sig_key *md5; |
| 2231 | __u8 *md5_hash_location; | 2404 | int tcp_header_size; |
| 2232 | int mss; | 2405 | int mss; |
| 2233 | 2406 | ||
| 2234 | skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); | 2407 | skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); |
| @@ -2266,8 +2439,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
| 2266 | #endif | 2439 | #endif |
| 2267 | TCP_SKB_CB(skb)->when = tcp_time_stamp; | 2440 | TCP_SKB_CB(skb)->when = tcp_time_stamp; |
| 2268 | tcp_header_size = tcp_synack_options(sk, req, mss, | 2441 | tcp_header_size = tcp_synack_options(sk, req, mss, |
| 2269 | skb, &opts, &md5) + | 2442 | skb, &opts, &md5, xvp) |
| 2270 | sizeof(struct tcphdr); | 2443 | + sizeof(*th); |
| 2271 | 2444 | ||
| 2272 | skb_push(skb, tcp_header_size); | 2445 | skb_push(skb, tcp_header_size); |
| 2273 | skb_reset_transport_header(skb); | 2446 | skb_reset_transport_header(skb); |
| @@ -2284,19 +2457,58 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
| 2284 | */ | 2457 | */ |
| 2285 | tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn, | 2458 | tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn, |
| 2286 | TCPCB_FLAG_SYN | TCPCB_FLAG_ACK); | 2459 | TCPCB_FLAG_SYN | TCPCB_FLAG_ACK); |
| 2460 | |||
| 2461 | if (OPTION_COOKIE_EXTENSION & opts.options) { | ||
| 2462 | const struct tcp_cookie_values *cvp = tp->cookie_values; | ||
| 2463 | |||
| 2464 | if (cvp != NULL && | ||
| 2465 | cvp->s_data_constant && | ||
| 2466 | cvp->s_data_desired > 0) { | ||
| 2467 | u8 *buf = skb_put(skb, cvp->s_data_desired); | ||
| 2468 | |||
| 2469 | /* copy data directly from the listening socket. */ | ||
| 2470 | memcpy(buf, cvp->s_data_payload, cvp->s_data_desired); | ||
| 2471 | TCP_SKB_CB(skb)->end_seq += cvp->s_data_desired; | ||
| 2472 | } | ||
| 2473 | |||
| 2474 | if (opts.hash_size > 0) { | ||
| 2475 | __u32 workspace[SHA_WORKSPACE_WORDS]; | ||
| 2476 | u32 *mess = &xvp->cookie_bakery[COOKIE_DIGEST_WORDS]; | ||
| 2477 | u32 *tail = &mess[COOKIE_MESSAGE_WORDS-1]; | ||
| 2478 | |||
| 2479 | /* Secret recipe depends on the Timestamp, (future) | ||
| 2480 | * Sequence and Acknowledgment Numbers, Initiator | ||
| 2481 | * Cookie, and others handled by IP variant caller. | ||
| 2482 | */ | ||
| 2483 | *tail-- ^= opts.tsval; | ||
| 2484 | *tail-- ^= tcp_rsk(req)->rcv_isn + 1; | ||
| 2485 | *tail-- ^= TCP_SKB_CB(skb)->seq + 1; | ||
| 2486 | |||
| 2487 | /* recommended */ | ||
| 2488 | *tail-- ^= ((th->dest << 16) | th->source); | ||
| 2489 | *tail-- ^= (u32)(unsigned long)cvp; /* per sockopt */ | ||
| 2490 | |||
| 2491 | sha_transform((__u32 *)&xvp->cookie_bakery[0], | ||
| 2492 | (char *)mess, | ||
| 2493 | &workspace[0]); | ||
| 2494 | opts.hash_location = | ||
| 2495 | (__u8 *)&xvp->cookie_bakery[0]; | ||
| 2496 | } | ||
| 2497 | } | ||
| 2498 | |||
| 2287 | th->seq = htonl(TCP_SKB_CB(skb)->seq); | 2499 | th->seq = htonl(TCP_SKB_CB(skb)->seq); |
| 2288 | th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); | 2500 | th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); |
| 2289 | 2501 | ||
| 2290 | /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ | 2502 | /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ |
| 2291 | th->window = htons(min(req->rcv_wnd, 65535U)); | 2503 | th->window = htons(min(req->rcv_wnd, 65535U)); |
| 2292 | tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location); | 2504 | tcp_options_write((__be32 *)(th + 1), tp, &opts); |
| 2293 | th->doff = (tcp_header_size >> 2); | 2505 | th->doff = (tcp_header_size >> 2); |
| 2294 | TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); | 2506 | TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); |
| 2295 | 2507 | ||
| 2296 | #ifdef CONFIG_TCP_MD5SIG | 2508 | #ifdef CONFIG_TCP_MD5SIG |
| 2297 | /* Okay, we have all we need - do the md5 hash if needed */ | 2509 | /* Okay, we have all we need - do the md5 hash if needed */ |
| 2298 | if (md5) { | 2510 | if (md5) { |
| 2299 | tcp_rsk(req)->af_specific->calc_md5_hash(md5_hash_location, | 2511 | tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location, |
| 2300 | md5, NULL, req, skb); | 2512 | md5, NULL, req, skb); |
| 2301 | } | 2513 | } |
| 2302 | #endif | 2514 | #endif |
| @@ -2315,7 +2527,9 @@ static void tcp_connect_init(struct sock *sk) | |||
| 2315 | * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. | 2527 | * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. |
| 2316 | */ | 2528 | */ |
| 2317 | tp->tcp_header_len = sizeof(struct tcphdr) + | 2529 | tp->tcp_header_len = sizeof(struct tcphdr) + |
| 2318 | (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); | 2530 | (sysctl_tcp_timestamps && |
| 2531 | (!dst_feature(dst, RTAX_FEATURE_NO_TSTAMP) ? | ||
| 2532 | TCPOLEN_TSTAMP_ALIGNED : 0)); | ||
| 2319 | 2533 | ||
| 2320 | #ifdef CONFIG_TCP_MD5SIG | 2534 | #ifdef CONFIG_TCP_MD5SIG |
| 2321 | if (tp->af_specific->md5_lookup(sk, sk) != NULL) | 2535 | if (tp->af_specific->md5_lookup(sk, sk) != NULL) |
| @@ -2341,7 +2555,8 @@ static void tcp_connect_init(struct sock *sk) | |||
| 2341 | tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), | 2555 | tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), |
| 2342 | &tp->rcv_wnd, | 2556 | &tp->rcv_wnd, |
| 2343 | &tp->window_clamp, | 2557 | &tp->window_clamp, |
| 2344 | sysctl_tcp_window_scaling, | 2558 | (sysctl_tcp_window_scaling && |
| 2559 | !dst_feature(dst, RTAX_FEATURE_NO_WSCALE)), | ||
| 2345 | &rcv_wscale); | 2560 | &rcv_wscale); |
| 2346 | 2561 | ||
| 2347 | tp->rx_opt.rcv_wscale = rcv_wscale; | 2562 | tp->rx_opt.rcv_wscale = rcv_wscale; |
