aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/tcp_ipv6.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2015-03-22 13:22:23 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-23 16:52:26 -0400
commit2215089b224412bfb28c5ae823b2a5d4e28a49d7 (patch)
tree40d60e356592fcb2160b4f7fbb69e8dc995b42d2 /net/ipv6/tcp_ipv6.c
parent26e3736090e1037ac929787df21c05497479b77f (diff)
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: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r--net/ipv6/tcp_ipv6.c47
1 files changed, 12 insertions, 35 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 6e3f90db038c..4a4e6d30c448 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -324,18 +324,20 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
324{ 324{
325 const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; 325 const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
326 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); 326 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
327 struct net *net = dev_net(skb->dev);
328 struct request_sock *fastopen;
327 struct ipv6_pinfo *np; 329 struct ipv6_pinfo *np;
328 struct sock *sk;
329 int err;
330 struct tcp_sock *tp; 330 struct tcp_sock *tp;
331 struct request_sock *fastopen;
332 __u32 seq, snd_una; 331 __u32 seq, snd_una;
333 struct net *net = dev_net(skb->dev); 332 struct sock *sk;
333 int err;
334 334
335 sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr, 335 sk = __inet6_lookup_established(net, &tcp_hashinfo,
336 th->dest, &hdr->saddr, th->source, skb->dev->ifindex); 336 &hdr->daddr, th->dest,
337 &hdr->saddr, ntohs(th->source),
338 skb->dev->ifindex);
337 339
338 if (sk == NULL) { 340 if (!sk) {
339 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev), 341 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
340 ICMP6_MIB_INERRORS); 342 ICMP6_MIB_INERRORS);
341 return; 343 return;
@@ -345,6 +347,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
345 inet_twsk_put(inet_twsk(sk)); 347 inet_twsk_put(inet_twsk(sk));
346 return; 348 return;
347 } 349 }
350 seq = ntohl(th->seq);
351 if (sk->sk_state == TCP_NEW_SYN_RECV)
352 return tcp_req_err(sk, seq);
348 353
349 bh_lock_sock(sk); 354 bh_lock_sock(sk);
350 if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG) 355 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 } 364 }
360 365
361 tp = tcp_sk(sk); 366 tp = tcp_sk(sk);
362 seq = ntohl(th->seq);
363 /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ 367 /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */
364 fastopen = tp->fastopen_rsk; 368 fastopen = tp->fastopen_rsk;
365 snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; 369 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 407
404 /* Might be for an request_sock */ 408 /* Might be for an request_sock */
405 switch (sk->sk_state) { 409 switch (sk->sk_state) {
406 struct request_sock *req;
407 case TCP_LISTEN:
408 if (sock_owned_by_user(sk))
409 goto out;
410
411 /* Note : We use inet6_iif() here, not tcp_v6_iif() */
412 req = inet6_csk_search_req(sk, th->dest, &hdr->daddr,
413 &hdr->saddr, inet6_iif(skb));
414 if (!req)
415 goto out;
416
417 /* ICMPs are not backlogged, hence we cannot get
418 * an established socket here.
419 */
420 WARN_ON(req->sk != NULL);
421
422 if (seq != tcp_rsk(req)->snt_isn) {
423 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
424 reqsk_put(req);
425 goto out;
426 }
427
428 inet_csk_reqsk_queue_drop(sk, req);
429 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
430 reqsk_put(req);
431 goto out;
432
433 case TCP_SYN_SENT: 410 case TCP_SYN_SENT:
434 case TCP_SYN_RECV: 411 case TCP_SYN_RECV:
435 /* Only in fast or simultaneous open. If a fast open socket is 412 /* Only in fast or simultaneous open. If a fast open socket is