Commit 9a1f02f3 authored by David S. Miller's avatar David S. Miller

Merge branch 'tcp-change-reaction-to-ICMP'

Eric Dumazet says:

====================
tcp: change reaction to ICMP messages

ICMP[v6] messages received for a socket in TCP_SYN_SENT currently abort
the connection attempt, in violation of standards.

This series changes our stack to adhere to RFC 6069 and RFC 1122
(4.2.3.9)

====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c6e9dba3 0a8de364
...@@ -482,6 +482,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) ...@@ -482,6 +482,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
const int code = icmp_hdr(skb)->code; const int code = icmp_hdr(skb)->code;
struct sock *sk; struct sock *sk;
struct request_sock *fastopen; struct request_sock *fastopen;
bool harderr = false;
u32 seq, snd_una; u32 seq, snd_una;
int err; int err;
struct net *net = dev_net(skb->dev); struct net *net = dev_net(skb->dev);
...@@ -555,6 +556,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) ...@@ -555,6 +556,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
goto out; goto out;
case ICMP_PARAMETERPROB: case ICMP_PARAMETERPROB:
err = EPROTO; err = EPROTO;
harderr = true;
break; break;
case ICMP_DEST_UNREACH: case ICMP_DEST_UNREACH:
if (code > NR_ICMP_UNREACH) if (code > NR_ICMP_UNREACH)
...@@ -579,6 +581,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) ...@@ -579,6 +581,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
} }
err = icmp_err_convert[code].errno; err = icmp_err_convert[code].errno;
harderr = icmp_err_convert[code].fatal;
/* check if this ICMP message allows revert of backoff. /* check if this ICMP message allows revert of backoff.
* (see RFC 6069) * (see RFC 6069)
*/ */
...@@ -604,6 +607,9 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) ...@@ -604,6 +607,9 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
ip_icmp_error(sk, skb, err, th->dest, info, (u8 *)th); ip_icmp_error(sk, skb, err, th->dest, info, (u8 *)th);
if (!harderr)
break;
if (!sock_owned_by_user(sk)) { if (!sock_owned_by_user(sk)) {
WRITE_ONCE(sk->sk_err, err); WRITE_ONCE(sk->sk_err, err);
......
...@@ -626,7 +626,6 @@ void tcp_retransmit_timer(struct sock *sk) ...@@ -626,7 +626,6 @@ void tcp_retransmit_timer(struct sock *sk)
* implemented ftp to mars will work nicely. We will have to fix * implemented ftp to mars will work nicely. We will have to fix
* the 120 second clamps though! * the 120 second clamps though!
*/ */
icsk->icsk_backoff++;
out_reset_timer: out_reset_timer:
/* If stream is thin, use linear timeouts. Since 'icsk_backoff' is /* If stream is thin, use linear timeouts. Since 'icsk_backoff' is
...@@ -647,11 +646,12 @@ void tcp_retransmit_timer(struct sock *sk) ...@@ -647,11 +646,12 @@ void tcp_retransmit_timer(struct sock *sk)
tcp_rto_min(sk), tcp_rto_min(sk),
TCP_RTO_MAX); TCP_RTO_MAX);
} else if (sk->sk_state != TCP_SYN_SENT || } else if (sk->sk_state != TCP_SYN_SENT ||
icsk->icsk_backoff > tp->total_rto >
READ_ONCE(net->ipv4.sysctl_tcp_syn_linear_timeouts)) { READ_ONCE(net->ipv4.sysctl_tcp_syn_linear_timeouts)) {
/* Use normal (exponential) backoff unless linear timeouts are /* Use normal (exponential) backoff unless linear timeouts are
* activated. * activated.
*/ */
icsk->icsk_backoff++;
icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
} }
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
......
...@@ -381,7 +381,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -381,7 +381,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
struct tcp_sock *tp; struct tcp_sock *tp;
__u32 seq, snd_una; __u32 seq, snd_una;
struct sock *sk; struct sock *sk;
bool fatal; bool harderr;
int err; int err;
sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
...@@ -402,9 +402,9 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -402,9 +402,9 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
return 0; return 0;
} }
seq = ntohl(th->seq); seq = ntohl(th->seq);
fatal = icmpv6_err_convert(type, code, &err); harderr = icmpv6_err_convert(type, code, &err);
if (sk->sk_state == TCP_NEW_SYN_RECV) { if (sk->sk_state == TCP_NEW_SYN_RECV) {
tcp_req_err(sk, seq, fatal); tcp_req_err(sk, seq, harderr);
return 0; return 0;
} }
...@@ -489,6 +489,9 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -489,6 +489,9 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
ipv6_icmp_error(sk, skb, err, th->dest, ntohl(info), (u8 *)th); ipv6_icmp_error(sk, skb, err, th->dest, ntohl(info), (u8 *)th);
if (!harderr)
break;
if (!sock_owned_by_user(sk)) { if (!sock_owned_by_user(sk)) {
WRITE_ONCE(sk->sk_err, err); WRITE_ONCE(sk->sk_err, err);
sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment