diff options
| author | Patrick McManus <mcmanus@ducksong.com> | 2008-03-21 19:33:01 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-03-21 19:33:01 -0400 |
| commit | ec3c0982a2dd1e671bad8e9d26c28dcba0039d87 (patch) | |
| tree | 11a3cd7c530e4225a4c3d4c3f3cc54eb7d2e0e4f /net/ipv4/tcp_input.c | |
| parent | e4c78840284f3f51b1896cf3936d60a6033c4d2c (diff) | |
[TCP]: TCP_DEFER_ACCEPT updates - process as established
Change TCP_DEFER_ACCEPT implementation so that it transitions a
connection to ESTABLISHED after handshake is complete instead of
leaving it in SYN-RECV until some data arrvies. Place connection in
accept queue when first data packet arrives from slow path.
Benefits:
- established connection is now reset if it never makes it
to the accept queue
- diagnostic state of established matches with the packet traces
showing completed handshake
- TCP_DEFER_ACCEPT timeouts are expressed in seconds and can now be
enforced with reasonable accuracy instead of rounding up to next
exponential back-off of syn-ack retry.
Signed-off-by: Patrick McManus <mcmanus@ducksong.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 9cf446427cc2..6e46b4c0f28c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
| @@ -4451,6 +4451,49 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th) | |||
| 4451 | } | 4451 | } |
| 4452 | } | 4452 | } |
| 4453 | 4453 | ||
| 4454 | static int tcp_defer_accept_check(struct sock *sk) | ||
| 4455 | { | ||
| 4456 | struct tcp_sock *tp = tcp_sk(sk); | ||
| 4457 | |||
| 4458 | if (tp->defer_tcp_accept.request) { | ||
| 4459 | int queued_data = tp->rcv_nxt - tp->copied_seq; | ||
| 4460 | int hasfin = !skb_queue_empty(&sk->sk_receive_queue) ? | ||
| 4461 | tcp_hdr((struct sk_buff *) | ||
| 4462 | sk->sk_receive_queue.prev)->fin : 0; | ||
| 4463 | |||
| 4464 | if (queued_data && hasfin) | ||
| 4465 | queued_data--; | ||
| 4466 | |||
| 4467 | if (queued_data && | ||
| 4468 | tp->defer_tcp_accept.listen_sk->sk_state == TCP_LISTEN) { | ||
| 4469 | if (sock_flag(sk, SOCK_KEEPOPEN)) { | ||
| 4470 | inet_csk_reset_keepalive_timer(sk, | ||
| 4471 | keepalive_time_when(tp)); | ||
| 4472 | } else { | ||
| 4473 | inet_csk_delete_keepalive_timer(sk); | ||
| 4474 | } | ||
| 4475 | |||
| 4476 | inet_csk_reqsk_queue_add( | ||
| 4477 | tp->defer_tcp_accept.listen_sk, | ||
| 4478 | tp->defer_tcp_accept.request, | ||
| 4479 | sk); | ||
| 4480 | |||
| 4481 | tp->defer_tcp_accept.listen_sk->sk_data_ready( | ||
| 4482 | tp->defer_tcp_accept.listen_sk, 0); | ||
| 4483 | |||
| 4484 | sock_put(tp->defer_tcp_accept.listen_sk); | ||
| 4485 | sock_put(sk); | ||
| 4486 | tp->defer_tcp_accept.listen_sk = NULL; | ||
| 4487 | tp->defer_tcp_accept.request = NULL; | ||
| 4488 | } else if (hasfin || | ||
| 4489 | tp->defer_tcp_accept.listen_sk->sk_state != TCP_LISTEN) { | ||
| 4490 | tcp_reset(sk); | ||
| 4491 | return -1; | ||
| 4492 | } | ||
| 4493 | } | ||
| 4494 | return 0; | ||
| 4495 | } | ||
| 4496 | |||
| 4454 | static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) | 4497 | static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) |
| 4455 | { | 4498 | { |
| 4456 | struct tcp_sock *tp = tcp_sk(sk); | 4499 | struct tcp_sock *tp = tcp_sk(sk); |
| @@ -4811,6 +4854,9 @@ step5: | |||
| 4811 | 4854 | ||
| 4812 | tcp_data_snd_check(sk); | 4855 | tcp_data_snd_check(sk); |
| 4813 | tcp_ack_snd_check(sk); | 4856 | tcp_ack_snd_check(sk); |
| 4857 | |||
| 4858 | if (tcp_defer_accept_check(sk)) | ||
| 4859 | return -1; | ||
| 4814 | return 0; | 4860 | return 0; |
| 4815 | 4861 | ||
| 4816 | csum_error: | 4862 | csum_error: |
