Commit 2215089b authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

ipv6: tcp: handle ICMP messages on TCP_NEW_SYN_RECV request sockets

tcp_v6_err() can restrict lookups to ehash table, and not to listeners.

Note this patch creates the infrastructure, but this means that ICMP
messages for request sockets are ignored until complete conversion.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 26e37360
...@@ -324,18 +324,20 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -324,18 +324,20 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
{ {
const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
struct net *net = dev_net(skb->dev);
struct request_sock *fastopen;
struct ipv6_pinfo *np; struct ipv6_pinfo *np;
struct sock *sk;
int err;
struct tcp_sock *tp; struct tcp_sock *tp;
struct request_sock *fastopen;
__u32 seq, snd_una; __u32 seq, snd_una;
struct net *net = dev_net(skb->dev); struct sock *sk;
int err;
sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr, sk = __inet6_lookup_established(net, &tcp_hashinfo,
th->dest, &hdr->saddr, th->source, skb->dev->ifindex); &hdr->daddr, th->dest,
&hdr->saddr, ntohs(th->source),
skb->dev->ifindex);
if (sk == NULL) { if (!sk) {
ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev), ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
ICMP6_MIB_INERRORS); ICMP6_MIB_INERRORS);
return; return;
...@@ -345,6 +347,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -345,6 +347,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
inet_twsk_put(inet_twsk(sk)); inet_twsk_put(inet_twsk(sk));
return; return;
} }
seq = ntohl(th->seq);
if (sk->sk_state == TCP_NEW_SYN_RECV)
return tcp_req_err(sk, seq);
bh_lock_sock(sk); bh_lock_sock(sk);
if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG) if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG)
...@@ -359,7 +364,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -359,7 +364,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
} }
tp = tcp_sk(sk); tp = tcp_sk(sk);
seq = ntohl(th->seq);
/* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */
fastopen = tp->fastopen_rsk; fastopen = tp->fastopen_rsk;
snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una;
...@@ -403,33 +407,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -403,33 +407,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
/* Might be for an request_sock */ /* Might be for an request_sock */
switch (sk->sk_state) { switch (sk->sk_state) {
struct request_sock *req;
case TCP_LISTEN:
if (sock_owned_by_user(sk))
goto out;
/* Note : We use inet6_iif() here, not tcp_v6_iif() */
req = inet6_csk_search_req(sk, th->dest, &hdr->daddr,
&hdr->saddr, inet6_iif(skb));
if (!req)
goto out;
/* ICMPs are not backlogged, hence we cannot get
* an established socket here.
*/
WARN_ON(req->sk != NULL);
if (seq != tcp_rsk(req)->snt_isn) {
NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
reqsk_put(req);
goto out;
}
inet_csk_reqsk_queue_drop(sk, req);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
reqsk_put(req);
goto out;
case TCP_SYN_SENT: case TCP_SYN_SENT:
case TCP_SYN_RECV: case TCP_SYN_RECV:
/* Only in fast or simultaneous open. If a fast open socket is /* Only in fast or simultaneous open. If a fast open socket is
......
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