diff options
author | Yuchung Cheng <ycheng@google.com> | 2012-07-19 02:43:08 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-19 14:02:03 -0400 |
commit | 8e4178c1c7b52f7c99f5fd22ef7af6b2bff409e3 (patch) | |
tree | 101ec972d397346ea603ee2a08b8320f1ed690eb | |
parent | 783237e8daf13481ee234997cbbbb823872ac388 (diff) |
net-tcp: Fast Open client - receiving SYN-ACK
On receiving the SYN-ACK after SYN-data, the client needs to
a) update the cached MSS and cookie (if included in SYN-ACK)
b) retransmit the data not yet acknowledged by the SYN-ACK in the final ACK of
the handshake.
Signed-off-by: Yuchung Cheng <ycheng@google.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/tcp_input.c | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a06bb8959e7e..38b6a811edfc 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -5646,6 +5646,34 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) | |||
5646 | } | 5646 | } |
5647 | } | 5647 | } |
5648 | 5648 | ||
5649 | static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, | ||
5650 | struct tcp_fastopen_cookie *cookie) | ||
5651 | { | ||
5652 | struct tcp_sock *tp = tcp_sk(sk); | ||
5653 | struct sk_buff *data = tcp_write_queue_head(sk); | ||
5654 | u16 mss = tp->rx_opt.mss_clamp; | ||
5655 | |||
5656 | if (mss == tp->rx_opt.user_mss) { | ||
5657 | struct tcp_options_received opt; | ||
5658 | const u8 *hash_location; | ||
5659 | |||
5660 | /* Get original SYNACK MSS value if user MSS sets mss_clamp */ | ||
5661 | tcp_clear_options(&opt); | ||
5662 | opt.user_mss = opt.mss_clamp = 0; | ||
5663 | tcp_parse_options(synack, &opt, &hash_location, 0, NULL); | ||
5664 | mss = opt.mss_clamp; | ||
5665 | } | ||
5666 | |||
5667 | tcp_fastopen_cache_set(sk, mss, cookie); | ||
5668 | |||
5669 | if (data) { /* Retransmit unacked data in SYN */ | ||
5670 | tcp_retransmit_skb(sk, data); | ||
5671 | tcp_rearm_rto(sk); | ||
5672 | return true; | ||
5673 | } | ||
5674 | return false; | ||
5675 | } | ||
5676 | |||
5649 | static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, | 5677 | static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, |
5650 | const struct tcphdr *th, unsigned int len) | 5678 | const struct tcphdr *th, unsigned int len) |
5651 | { | 5679 | { |
@@ -5653,9 +5681,10 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, | |||
5653 | struct inet_connection_sock *icsk = inet_csk(sk); | 5681 | struct inet_connection_sock *icsk = inet_csk(sk); |
5654 | struct tcp_sock *tp = tcp_sk(sk); | 5682 | struct tcp_sock *tp = tcp_sk(sk); |
5655 | struct tcp_cookie_values *cvp = tp->cookie_values; | 5683 | struct tcp_cookie_values *cvp = tp->cookie_values; |
5684 | struct tcp_fastopen_cookie foc = { .len = -1 }; | ||
5656 | int saved_clamp = tp->rx_opt.mss_clamp; | 5685 | int saved_clamp = tp->rx_opt.mss_clamp; |
5657 | 5686 | ||
5658 | tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, NULL); | 5687 | tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, &foc); |
5659 | 5688 | ||
5660 | if (th->ack) { | 5689 | if (th->ack) { |
5661 | /* rfc793: | 5690 | /* rfc793: |
@@ -5665,11 +5694,9 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, | |||
5665 | * If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send | 5694 | * If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send |
5666 | * a reset (unless the RST bit is set, if so drop | 5695 | * a reset (unless the RST bit is set, if so drop |
5667 | * the segment and return)" | 5696 | * the segment and return)" |
5668 | * | ||
5669 | * We do not send data with SYN, so that RFC-correct | ||
5670 | * test reduces to: | ||
5671 | */ | 5697 | */ |
5672 | if (TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt) | 5698 | if (!after(TCP_SKB_CB(skb)->ack_seq, tp->snd_una) || |
5699 | after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) | ||
5673 | goto reset_and_undo; | 5700 | goto reset_and_undo; |
5674 | 5701 | ||
5675 | if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr && | 5702 | if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr && |
@@ -5781,6 +5808,9 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, | |||
5781 | 5808 | ||
5782 | tcp_finish_connect(sk, skb); | 5809 | tcp_finish_connect(sk, skb); |
5783 | 5810 | ||
5811 | if (tp->syn_fastopen && tcp_rcv_fastopen_synack(sk, skb, &foc)) | ||
5812 | return -1; | ||
5813 | |||
5784 | if (sk->sk_write_pending || | 5814 | if (sk->sk_write_pending || |
5785 | icsk->icsk_accept_queue.rskq_defer_accept || | 5815 | icsk->icsk_accept_queue.rskq_defer_accept || |
5786 | icsk->icsk_ack.pingpong) { | 5816 | icsk->icsk_ack.pingpong) { |