diff options
author | Yuchung Cheng <ycheng@google.com> | 2014-05-11 23:22:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-05-13 17:53:03 -0400 |
commit | 0a672f74131dd682087dfd5f45bf61f95804772e (patch) | |
tree | 4e3781451c7828a66c8d49771bcb4c5f26818709 /net/ipv4/tcp_ipv4.c | |
parent | 843f4a55e336e6d0c7bb92e7f9621535bc8d5fcd (diff) |
tcp: improve fastopen icmp handling
If a fast open socket is already accepted by the user, it should
be treated like a connected socket to record the ICMP error in
sk_softerr, so the user can fetch it. Do that in both tcp_v4_err
and tcp_v6_err.
Also refactor the sequence window check to improve readability
(e.g., there were two local variables named 'req').
Signed-off-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: Daniel Lee <longinus00@gmail.com>
Signed-off-by: Jerry Chu <hkchu@google.com>
Acked-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 35 |
1 files changed, 14 insertions, 21 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1665f0f84233..a2780e5334c9 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -336,8 +336,8 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) | |||
336 | const int code = icmp_hdr(icmp_skb)->code; | 336 | const int code = icmp_hdr(icmp_skb)->code; |
337 | struct sock *sk; | 337 | struct sock *sk; |
338 | struct sk_buff *skb; | 338 | struct sk_buff *skb; |
339 | struct request_sock *req; | 339 | struct request_sock *fastopen; |
340 | __u32 seq; | 340 | __u32 seq, snd_una; |
341 | __u32 remaining; | 341 | __u32 remaining; |
342 | int err; | 342 | int err; |
343 | struct net *net = dev_net(icmp_skb->dev); | 343 | struct net *net = dev_net(icmp_skb->dev); |
@@ -378,12 +378,12 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) | |||
378 | 378 | ||
379 | icsk = inet_csk(sk); | 379 | icsk = inet_csk(sk); |
380 | tp = tcp_sk(sk); | 380 | tp = tcp_sk(sk); |
381 | req = tp->fastopen_rsk; | ||
382 | seq = ntohl(th->seq); | 381 | seq = ntohl(th->seq); |
382 | /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ | ||
383 | fastopen = tp->fastopen_rsk; | ||
384 | snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; | ||
383 | if (sk->sk_state != TCP_LISTEN && | 385 | if (sk->sk_state != TCP_LISTEN && |
384 | !between(seq, tp->snd_una, tp->snd_nxt) && | 386 | !between(seq, snd_una, tp->snd_nxt)) { |
385 | (req == NULL || seq != tcp_rsk(req)->snt_isn)) { | ||
386 | /* For a Fast Open socket, allow seq to be snt_isn. */ | ||
387 | NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); | 387 | NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); |
388 | goto out; | 388 | goto out; |
389 | } | 389 | } |
@@ -426,11 +426,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) | |||
426 | if (code != ICMP_NET_UNREACH && code != ICMP_HOST_UNREACH) | 426 | if (code != ICMP_NET_UNREACH && code != ICMP_HOST_UNREACH) |
427 | break; | 427 | break; |
428 | if (seq != tp->snd_una || !icsk->icsk_retransmits || | 428 | if (seq != tp->snd_una || !icsk->icsk_retransmits || |
429 | !icsk->icsk_backoff) | 429 | !icsk->icsk_backoff || fastopen) |
430 | break; | 430 | break; |
431 | 431 | ||
432 | /* XXX (TFO) - revisit the following logic for TFO */ | ||
433 | |||
434 | if (sock_owned_by_user(sk)) | 432 | if (sock_owned_by_user(sk)) |
435 | break; | 433 | break; |
436 | 434 | ||
@@ -462,14 +460,6 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) | |||
462 | goto out; | 460 | goto out; |
463 | } | 461 | } |
464 | 462 | ||
465 | /* XXX (TFO) - if it's a TFO socket and has been accepted, rather | ||
466 | * than following the TCP_SYN_RECV case and closing the socket, | ||
467 | * we ignore the ICMP error and keep trying like a fully established | ||
468 | * socket. Is this the right thing to do? | ||
469 | */ | ||
470 | if (req && req->sk == NULL) | ||
471 | goto out; | ||
472 | |||
473 | switch (sk->sk_state) { | 463 | switch (sk->sk_state) { |
474 | struct request_sock *req, **prev; | 464 | struct request_sock *req, **prev; |
475 | case TCP_LISTEN: | 465 | case TCP_LISTEN: |
@@ -502,10 +492,13 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) | |||
502 | goto out; | 492 | goto out; |
503 | 493 | ||
504 | case TCP_SYN_SENT: | 494 | case TCP_SYN_SENT: |
505 | case TCP_SYN_RECV: /* Cannot happen. | 495 | case TCP_SYN_RECV: |
506 | It can f.e. if SYNs crossed, | 496 | /* Only in fast or simultaneous open. If a fast open socket is |
507 | or Fast Open. | 497 | * is already accepted it is treated as a connected one below. |
508 | */ | 498 | */ |
499 | if (fastopen && fastopen->sk == NULL) | ||
500 | break; | ||
501 | |||
509 | if (!sock_owned_by_user(sk)) { | 502 | if (!sock_owned_by_user(sk)) { |
510 | sk->sk_err = err; | 503 | sk->sk_err = err; |
511 | 504 | ||