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

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
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -482,6 +482,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
	const int code = icmp_hdr(skb)->code;
	struct sock *sk;
	struct request_sock *fastopen;
	bool harderr = false;
	u32 seq, snd_una;
	int err;
	struct net *net = dev_net(skb->dev);
@@ -555,6 +556,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
		goto out;
	case ICMP_PARAMETERPROB:
		err = EPROTO;
		harderr = true;
		break;
	case ICMP_DEST_UNREACH:
		if (code > NR_ICMP_UNREACH)
@@ -579,6 +581,7 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)
		}

		err = icmp_err_convert[code].errno;
		harderr = icmp_err_convert[code].fatal;
		/* check if this ICMP message allows revert of backoff.
		 * (see RFC 6069)
		 */
@@ -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);

		if (!harderr)
			break;

		if (!sock_owned_by_user(sk)) {
			WRITE_ONCE(sk->sk_err, err);

+2 −2
Original line number Diff line number Diff line
@@ -626,7 +626,6 @@ void tcp_retransmit_timer(struct sock *sk)
	 * implemented ftp to mars will work nicely. We will have to fix
	 * the 120 second clamps though!
	 */
	icsk->icsk_backoff++;

out_reset_timer:
	/* If stream is thin, use linear timeouts. Since 'icsk_backoff' is
@@ -647,11 +646,12 @@ void tcp_retransmit_timer(struct sock *sk)
				       tcp_rto_min(sk),
				       TCP_RTO_MAX);
	} else if (sk->sk_state != TCP_SYN_SENT ||
		   icsk->icsk_backoff >
		   tp->total_rto >
		   READ_ONCE(net->ipv4.sysctl_tcp_syn_linear_timeouts)) {
		/* Use normal (exponential) backoff unless linear timeouts are
		 * activated.
		 */
		icsk->icsk_backoff++;
		icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
	}
	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+6 −3
Original line number Diff line number Diff line
@@ -381,7 +381,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
	struct tcp_sock *tp;
	__u32 seq, snd_una;
	struct sock *sk;
	bool fatal;
	bool harderr;
	int err;

	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,
		return 0;
	}
	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) {
		tcp_req_err(sk, seq, fatal);
		tcp_req_err(sk, seq, harderr);
		return 0;
	}

@@ -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);

		if (!harderr)
			break;

		if (!sock_owned_by_user(sk)) {
			WRITE_ONCE(sk->sk_err, err);
			sk_error_report(sk);		/* Wake people up to see the error (see connect in sock.c) */