diff options
Diffstat (limited to 'net/ipv4/tcp_output.c')
| -rw-r--r-- | net/ipv4/tcp_output.c | 103 |
1 files changed, 86 insertions, 17 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 35dd983a8a99..2ac8beff4d77 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
| @@ -655,48 +655,77 @@ static unsigned tcp_synack_options(struct sock *sk, | |||
| 655 | struct request_sock *req, | 655 | struct request_sock *req, |
| 656 | unsigned mss, struct sk_buff *skb, | 656 | unsigned mss, struct sk_buff *skb, |
| 657 | struct tcp_out_options *opts, | 657 | struct tcp_out_options *opts, |
| 658 | struct tcp_md5sig_key **md5) { | 658 | struct tcp_md5sig_key **md5, |
| 659 | unsigned size = 0; | 659 | struct tcp_extend_values *xvp) |
| 660 | { | ||
| 660 | struct inet_request_sock *ireq = inet_rsk(req); | 661 | struct inet_request_sock *ireq = inet_rsk(req); |
| 661 | char doing_ts; | 662 | unsigned remaining = MAX_TCP_OPTION_SPACE; |
| 663 | u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ? | ||
| 664 | xvp->cookie_plus : | ||
| 665 | 0; | ||
| 666 | bool doing_ts = ireq->tstamp_ok; | ||
| 662 | 667 | ||
| 663 | #ifdef CONFIG_TCP_MD5SIG | 668 | #ifdef CONFIG_TCP_MD5SIG |
| 664 | *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); | 669 | *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); |
| 665 | if (*md5) { | 670 | if (*md5) { |
| 666 | opts->options |= OPTION_MD5; | 671 | opts->options |= OPTION_MD5; |
| 667 | size += TCPOLEN_MD5SIG_ALIGNED; | 672 | remaining -= TCPOLEN_MD5SIG_ALIGNED; |
| 673 | |||
| 674 | /* We can't fit any SACK blocks in a packet with MD5 + TS | ||
| 675 | * options. There was discussion about disabling SACK | ||
| 676 | * rather than TS in order to fit in better with old, | ||
| 677 | * buggy kernels, but that was deemed to be unnecessary. | ||
| 678 | */ | ||
| 679 | doing_ts &= !ireq->sack_ok; | ||
| 668 | } | 680 | } |
| 669 | #else | 681 | #else |
| 670 | *md5 = NULL; | 682 | *md5 = NULL; |
| 671 | #endif | 683 | #endif |
| 672 | 684 | ||
| 673 | /* we can't fit any SACK blocks in a packet with MD5 + TS | 685 | /* We always send an MSS option. */ |
| 674 | options. There was discussion about disabling SACK rather than TS in | ||
| 675 | order to fit in better with old, buggy kernels, but that was deemed | ||
| 676 | to be unnecessary. */ | ||
| 677 | doing_ts = ireq->tstamp_ok && !(*md5 && ireq->sack_ok); | ||
| 678 | |||
| 679 | opts->mss = mss; | 686 | opts->mss = mss; |
| 680 | size += TCPOLEN_MSS_ALIGNED; | 687 | remaining -= TCPOLEN_MSS_ALIGNED; |
| 681 | 688 | ||
| 682 | if (likely(ireq->wscale_ok)) { | 689 | if (likely(ireq->wscale_ok)) { |
| 683 | opts->ws = ireq->rcv_wscale; | 690 | opts->ws = ireq->rcv_wscale; |
| 684 | opts->options |= OPTION_WSCALE; | 691 | opts->options |= OPTION_WSCALE; |
| 685 | size += TCPOLEN_WSCALE_ALIGNED; | 692 | remaining -= TCPOLEN_WSCALE_ALIGNED; |
| 686 | } | 693 | } |
| 687 | if (likely(doing_ts)) { | 694 | if (likely(doing_ts)) { |
| 688 | opts->options |= OPTION_TS; | 695 | opts->options |= OPTION_TS; |
| 689 | opts->tsval = TCP_SKB_CB(skb)->when; | 696 | opts->tsval = TCP_SKB_CB(skb)->when; |
| 690 | opts->tsecr = req->ts_recent; | 697 | opts->tsecr = req->ts_recent; |
| 691 | size += TCPOLEN_TSTAMP_ALIGNED; | 698 | remaining -= TCPOLEN_TSTAMP_ALIGNED; |
| 692 | } | 699 | } |
| 693 | if (likely(ireq->sack_ok)) { | 700 | if (likely(ireq->sack_ok)) { |
| 694 | opts->options |= OPTION_SACK_ADVERTISE; | 701 | opts->options |= OPTION_SACK_ADVERTISE; |
| 695 | if (unlikely(!doing_ts)) | 702 | if (unlikely(!doing_ts)) |
| 696 | size += TCPOLEN_SACKPERM_ALIGNED; | 703 | remaining -= TCPOLEN_SACKPERM_ALIGNED; |
| 697 | } | 704 | } |
| 698 | 705 | ||
| 699 | return size; | 706 | /* Similar rationale to tcp_syn_options() applies here, too. |
| 707 | * If the <SYN> options fit, the same options should fit now! | ||
| 708 | */ | ||
| 709 | if (*md5 == NULL && | ||
| 710 | doing_ts && | ||
| 711 | cookie_plus > TCPOLEN_COOKIE_BASE) { | ||
| 712 | int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */ | ||
| 713 | |||
| 714 | if (0x2 & need) { | ||
| 715 | /* 32-bit multiple */ | ||
| 716 | need += 2; /* NOPs */ | ||
| 717 | } | ||
| 718 | if (need <= remaining) { | ||
| 719 | opts->options |= OPTION_COOKIE_EXTENSION; | ||
| 720 | opts->hash_size = cookie_plus - TCPOLEN_COOKIE_BASE; | ||
| 721 | remaining -= need; | ||
| 722 | } else { | ||
| 723 | /* There's no error return, so flag it. */ | ||
| 724 | xvp->cookie_out_never = 1; /* true */ | ||
| 725 | opts->hash_size = 0; | ||
| 726 | } | ||
| 727 | } | ||
| 728 | return MAX_TCP_OPTION_SPACE - remaining; | ||
| 700 | } | 729 | } |
| 701 | 730 | ||
| 702 | /* Compute TCP options for ESTABLISHED sockets. This is not the | 731 | /* Compute TCP options for ESTABLISHED sockets. This is not the |
| @@ -2365,6 +2394,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
| 2365 | struct request_values *rvp) | 2394 | struct request_values *rvp) |
| 2366 | { | 2395 | { |
| 2367 | struct tcp_out_options opts; | 2396 | struct tcp_out_options opts; |
| 2397 | struct tcp_extend_values *xvp = tcp_xv(rvp); | ||
| 2368 | struct inet_request_sock *ireq = inet_rsk(req); | 2398 | struct inet_request_sock *ireq = inet_rsk(req); |
| 2369 | struct tcp_sock *tp = tcp_sk(sk); | 2399 | struct tcp_sock *tp = tcp_sk(sk); |
| 2370 | struct tcphdr *th; | 2400 | struct tcphdr *th; |
| @@ -2408,8 +2438,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
| 2408 | #endif | 2438 | #endif |
| 2409 | TCP_SKB_CB(skb)->when = tcp_time_stamp; | 2439 | TCP_SKB_CB(skb)->when = tcp_time_stamp; |
| 2410 | tcp_header_size = tcp_synack_options(sk, req, mss, | 2440 | tcp_header_size = tcp_synack_options(sk, req, mss, |
| 2411 | skb, &opts, &md5) + | 2441 | skb, &opts, &md5, xvp) |
| 2412 | sizeof(struct tcphdr); | 2442 | + sizeof(*th); |
| 2413 | 2443 | ||
| 2414 | skb_push(skb, tcp_header_size); | 2444 | skb_push(skb, tcp_header_size); |
| 2415 | skb_reset_transport_header(skb); | 2445 | skb_reset_transport_header(skb); |
| @@ -2426,6 +2456,45 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
| 2426 | */ | 2456 | */ |
| 2427 | tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn, | 2457 | tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn, |
| 2428 | TCPCB_FLAG_SYN | TCPCB_FLAG_ACK); | 2458 | TCPCB_FLAG_SYN | TCPCB_FLAG_ACK); |
| 2459 | |||
| 2460 | if (OPTION_COOKIE_EXTENSION & opts.options) { | ||
| 2461 | const struct tcp_cookie_values *cvp = tp->cookie_values; | ||
| 2462 | |||
| 2463 | if (cvp != NULL && | ||
| 2464 | cvp->s_data_constant && | ||
| 2465 | cvp->s_data_desired > 0) { | ||
| 2466 | u8 *buf = skb_put(skb, cvp->s_data_desired); | ||
| 2467 | |||
| 2468 | /* copy data directly from the listening socket. */ | ||
| 2469 | memcpy(buf, cvp->s_data_payload, cvp->s_data_desired); | ||
| 2470 | TCP_SKB_CB(skb)->end_seq += cvp->s_data_desired; | ||
| 2471 | } | ||
| 2472 | |||
| 2473 | if (opts.hash_size > 0) { | ||
| 2474 | __u32 workspace[SHA_WORKSPACE_WORDS]; | ||
| 2475 | u32 *mess = &xvp->cookie_bakery[COOKIE_DIGEST_WORDS]; | ||
| 2476 | u32 *tail = &mess[COOKIE_MESSAGE_WORDS-1]; | ||
| 2477 | |||
| 2478 | /* Secret recipe depends on the Timestamp, (future) | ||
| 2479 | * Sequence and Acknowledgment Numbers, Initiator | ||
| 2480 | * Cookie, and others handled by IP variant caller. | ||
| 2481 | */ | ||
| 2482 | *tail-- ^= opts.tsval; | ||
| 2483 | *tail-- ^= tcp_rsk(req)->rcv_isn + 1; | ||
| 2484 | *tail-- ^= TCP_SKB_CB(skb)->seq + 1; | ||
| 2485 | |||
| 2486 | /* recommended */ | ||
| 2487 | *tail-- ^= ((th->dest << 16) | th->source); | ||
| 2488 | *tail-- ^= (u32)cvp; /* per sockopt */ | ||
| 2489 | |||
| 2490 | sha_transform((__u32 *)&xvp->cookie_bakery[0], | ||
| 2491 | (char *)mess, | ||
| 2492 | &workspace[0]); | ||
| 2493 | opts.hash_location = | ||
| 2494 | (__u8 *)&xvp->cookie_bakery[0]; | ||
| 2495 | } | ||
| 2496 | } | ||
| 2497 | |||
| 2429 | th->seq = htonl(TCP_SKB_CB(skb)->seq); | 2498 | th->seq = htonl(TCP_SKB_CB(skb)->seq); |
| 2430 | th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); | 2499 | th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); |
| 2431 | 2500 | ||
