diff options
Diffstat (limited to 'net/ipv4/tcp_timer.c')
| -rw-r--r-- | net/ipv4/tcp_timer.c | 39 | 
1 files changed, 38 insertions, 1 deletions
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index b774a03bd1d..fc04711e80c 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -305,6 +305,35 @@ static void tcp_probe_timer(struct sock *sk)  }  /* + *	Timer for Fast Open socket to retransmit SYNACK. Note that the + *	sk here is the child socket, not the parent (listener) socket. + */ +static void tcp_fastopen_synack_timer(struct sock *sk) +{ +	struct inet_connection_sock *icsk = inet_csk(sk); +	int max_retries = icsk->icsk_syn_retries ? : +	    sysctl_tcp_synack_retries + 1; /* add one more retry for fastopen */ +	struct request_sock *req; + +	req = tcp_sk(sk)->fastopen_rsk; +	req->rsk_ops->syn_ack_timeout(sk, req); + +	if (req->retrans >= max_retries) { +		tcp_write_err(sk); +		return; +	} +	/* XXX (TFO) - Unlike regular SYN-ACK retransmit, we ignore error +	 * returned from rtx_syn_ack() to make it more persistent like +	 * regular retransmit because if the child socket has been accepted +	 * it's not good to give up too easily. +	 */ +	req->rsk_ops->rtx_syn_ack(sk, req, NULL); +	req->retrans++; +	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, +			  TCP_TIMEOUT_INIT << req->retrans, TCP_RTO_MAX); +} + +/*   *	The TCP retransmit timer.   */ @@ -317,7 +346,15 @@ void tcp_retransmit_timer(struct sock *sk)  		tcp_resume_early_retransmit(sk);  		return;  	} - +	if (tp->fastopen_rsk) { +		BUG_ON(sk->sk_state != TCP_SYN_RECV && +		    sk->sk_state != TCP_FIN_WAIT1); +		tcp_fastopen_synack_timer(sk); +		/* Before we receive ACK to our SYN-ACK don't retransmit +		 * anything else (e.g., data or FIN segments). +		 */ +		return; +	}  	if (!tp->packets_out)  		goto out;  |