|
@@ -138,10 +138,10 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
|
|
|
* retransmissions with an initial RTO of TCP_RTO_MIN.
|
|
|
*/
|
|
|
static bool retransmits_timed_out(struct sock *sk,
|
|
|
- unsigned int boundary)
|
|
|
+ unsigned int boundary,
|
|
|
+ unsigned int timeout)
|
|
|
{
|
|
|
- unsigned int timeout, linear_backoff_thresh;
|
|
|
- unsigned int start_ts;
|
|
|
+ unsigned int linear_backoff_thresh, start_ts;
|
|
|
|
|
|
if (!inet_csk(sk)->icsk_retransmits)
|
|
|
return false;
|
|
@@ -151,14 +151,15 @@ static bool retransmits_timed_out(struct sock *sk,
|
|
|
else
|
|
|
start_ts = tcp_sk(sk)->retrans_stamp;
|
|
|
|
|
|
- linear_backoff_thresh = ilog2(TCP_RTO_MAX/TCP_RTO_MIN);
|
|
|
-
|
|
|
- if (boundary <= linear_backoff_thresh)
|
|
|
- timeout = ((2 << boundary) - 1) * TCP_RTO_MIN;
|
|
|
- else
|
|
|
- timeout = ((2 << linear_backoff_thresh) - 1) * TCP_RTO_MIN +
|
|
|
- (boundary - linear_backoff_thresh) * TCP_RTO_MAX;
|
|
|
+ if (likely(timeout == 0)) {
|
|
|
+ linear_backoff_thresh = ilog2(TCP_RTO_MAX/TCP_RTO_MIN);
|
|
|
|
|
|
+ if (boundary <= linear_backoff_thresh)
|
|
|
+ timeout = ((2 << boundary) - 1) * TCP_RTO_MIN;
|
|
|
+ else
|
|
|
+ timeout = ((2 << linear_backoff_thresh) - 1) * TCP_RTO_MIN +
|
|
|
+ (boundary - linear_backoff_thresh) * TCP_RTO_MAX;
|
|
|
+ }
|
|
|
return (tcp_time_stamp - start_ts) >= timeout;
|
|
|
}
|
|
|
|
|
@@ -174,7 +175,7 @@ static int tcp_write_timeout(struct sock *sk)
|
|
|
dst_negative_advice(sk);
|
|
|
retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
|
|
|
} else {
|
|
|
- if (retransmits_timed_out(sk, sysctl_tcp_retries1)) {
|
|
|
+ if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0)) {
|
|
|
/* Black hole detection */
|
|
|
tcp_mtu_probing(icsk, sk);
|
|
|
|
|
@@ -187,14 +188,16 @@ static int tcp_write_timeout(struct sock *sk)
|
|
|
|
|
|
retry_until = tcp_orphan_retries(sk, alive);
|
|
|
do_reset = alive ||
|
|
|
- !retransmits_timed_out(sk, retry_until);
|
|
|
+ !retransmits_timed_out(sk, retry_until, 0);
|
|
|
|
|
|
if (tcp_out_of_resources(sk, do_reset))
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (retransmits_timed_out(sk, retry_until)) {
|
|
|
+ if (retransmits_timed_out(sk, retry_until,
|
|
|
+ (1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV) ? 0 :
|
|
|
+ icsk->icsk_user_timeout)) {
|
|
|
/* Has it gone just too far? */
|
|
|
tcp_write_err(sk);
|
|
|
return 1;
|
|
@@ -436,7 +439,7 @@ out_reset_timer:
|
|
|
icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
|
|
|
}
|
|
|
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
|
|
|
- if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1))
|
|
|
+ if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1, 0))
|
|
|
__sk_dst_reset(sk);
|
|
|
|
|
|
out:;
|
|
@@ -556,7 +559,14 @@ static void tcp_keepalive_timer (unsigned long data)
|
|
|
elapsed = keepalive_time_elapsed(tp);
|
|
|
|
|
|
if (elapsed >= keepalive_time_when(tp)) {
|
|
|
- if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
|
|
|
+ /* If the TCP_USER_TIMEOUT option is enabled, use that
|
|
|
+ * to determine when to timeout instead.
|
|
|
+ */
|
|
|
+ if ((icsk->icsk_user_timeout != 0 &&
|
|
|
+ elapsed >= icsk->icsk_user_timeout &&
|
|
|
+ icsk->icsk_probes_out > 0) ||
|
|
|
+ (icsk->icsk_user_timeout == 0 &&
|
|
|
+ icsk->icsk_probes_out >= keepalive_probes(tp))) {
|
|
|
tcp_send_active_reset(sk, GFP_ATOMIC);
|
|
|
tcp_write_err(sk);
|
|
|
goto out;
|