diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 29 | 
1 files changed, 19 insertions, 10 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 24f1630b2afb..031cf72cd05c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5378,8 +5378,8 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,  {  	struct tcp_sock *tp = tcp_sk(sk);  	struct sk_buff *data = tp->syn_data ? tcp_write_queue_head(sk) : NULL; -	u16 mss = tp->rx_opt.mss_clamp; -	bool syn_drop; +	u16 mss = tp->rx_opt.mss_clamp, try_exp = 0; +	bool syn_drop = false;  	if (mss == tp->rx_opt.user_mss) {  		struct tcp_options_received opt; @@ -5391,16 +5391,25 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,  		mss = opt.mss_clamp;  	} -	if (!tp->syn_fastopen)  /* Ignore an unsolicited cookie */ +	if (!tp->syn_fastopen) { +		/* Ignore an unsolicited cookie */  		cookie->len = -1; +	} else if (tp->total_retrans) { +		/* SYN timed out and the SYN-ACK neither has a cookie nor +		 * acknowledges data. Presumably the remote received only +		 * the retransmitted (regular) SYNs: either the original +		 * SYN-data or the corresponding SYN-ACK was dropped. +		 */ +		syn_drop = (cookie->len < 0 && data); +	} else if (cookie->len < 0 && !tp->syn_data) { +		/* We requested a cookie but didn't get it. If we did not use +		 * the (old) exp opt format then try so next time (try_exp=1). +		 * Otherwise we go back to use the RFC7413 opt (try_exp=2). +		 */ +		try_exp = tp->syn_fastopen_exp ? 2 : 1; +	} -	/* The SYN-ACK neither has cookie nor acknowledges the data. Presumably -	 * the remote receives only the retransmitted (regular) SYNs: either -	 * the original SYN-data or the corresponding SYN-ACK is lost. -	 */ -	syn_drop = (cookie->len <= 0 && data && tp->total_retrans); - -	tcp_fastopen_cache_set(sk, mss, cookie, syn_drop); +	tcp_fastopen_cache_set(sk, mss, cookie, syn_drop, try_exp);  	if (data) { /* Retransmit unacked data in SYN */  		tcp_for_write_queue_from(data, sk) {  | 
