Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Yuchung Cheng and committed by
David S. Miller
8e4178c1 783237e8

+35 -5
+35 -5
net/ipv4/tcp_input.c
··· 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 5677 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, 5650 5678 const struct tcphdr *th, unsigned int len) 5651 5679 { ··· 5681 5653 struct inet_connection_sock *icsk = inet_csk(sk); 5682 5654 struct tcp_sock *tp = tcp_sk(sk); 5683 5655 struct tcp_cookie_values *cvp = tp->cookie_values; 5656 + struct tcp_fastopen_cookie foc = { .len = -1 }; 5684 5657 int saved_clamp = tp->rx_opt.mss_clamp; 5685 5658 5686 - tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, NULL); 5659 + tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, &foc); 5687 5660 5688 5661 if (th->ack) { 5689 5662 /* rfc793: ··· 5694 5665 * If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send 5695 5666 * a reset (unless the RST bit is set, if so drop 5696 5667 * the segment and return)" 5697 - * 5698 - * We do not send data with SYN, so that RFC-correct 5699 - * test reduces to: 5700 5668 */ 5701 - if (TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt) 5669 + if (!after(TCP_SKB_CB(skb)->ack_seq, tp->snd_una) || 5670 + after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) 5702 5671 goto reset_and_undo; 5703 5672 5704 5673 if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr && ··· 5807 5780 smp_mb(); 5808 5781 5809 5782 tcp_finish_connect(sk, skb); 5783 + 5784 + if (tp->syn_fastopen && tcp_rcv_fastopen_synack(sk, skb, &foc)) 5785 + return -1; 5810 5786 5811 5787 if (sk->sk_write_pending || 5812 5788 icsk->icsk_accept_queue.rskq_defer_accept ||