diff options
-rw-r--r-- | include/net/inet_connection_sock.h | 1 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 4 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 3 | ||||
-rw-r--r-- | net/ipv4/inet_connection_sock.c | 16 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 6 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 3 |
6 files changed, 25 insertions, 8 deletions
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index ba1d3615acbb..183292722f6e 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h | |||
@@ -318,6 +318,7 @@ extern void inet_csk_reqsk_queue_prune(struct sock *parent, | |||
318 | const unsigned long max_rto); | 318 | const unsigned long max_rto); |
319 | 319 | ||
320 | extern void inet_csk_destroy_sock(struct sock *sk); | 320 | extern void inet_csk_destroy_sock(struct sock *sk); |
321 | extern void inet_csk_prepare_forced_close(struct sock *sk); | ||
321 | 322 | ||
322 | /* | 323 | /* |
323 | * LISTEN is a special case for poll.. | 324 | * LISTEN is a special case for poll.. |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 176ecdba4a22..4f9f5eb478f1 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -439,8 +439,8 @@ exit: | |||
439 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | 439 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); |
440 | return NULL; | 440 | return NULL; |
441 | put_and_exit: | 441 | put_and_exit: |
442 | bh_unlock_sock(newsk); | 442 | inet_csk_prepare_forced_close(newsk); |
443 | sock_put(newsk); | 443 | dccp_done(newsk); |
444 | goto exit; | 444 | goto exit; |
445 | } | 445 | } |
446 | 446 | ||
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 56840b249f3b..6e05981f271e 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -585,7 +585,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
585 | newinet->inet_rcv_saddr = LOOPBACK4_IPV6; | 585 | newinet->inet_rcv_saddr = LOOPBACK4_IPV6; |
586 | 586 | ||
587 | if (__inet_inherit_port(sk, newsk) < 0) { | 587 | if (__inet_inherit_port(sk, newsk) < 0) { |
588 | sock_put(newsk); | 588 | inet_csk_prepare_forced_close(newsk); |
589 | dccp_done(newsk); | ||
589 | goto out; | 590 | goto out; |
590 | } | 591 | } |
591 | __inet6_hash(newsk, NULL); | 592 | __inet6_hash(newsk, NULL); |
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 2026542d6836..d0670f00d524 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -710,6 +710,22 @@ void inet_csk_destroy_sock(struct sock *sk) | |||
710 | } | 710 | } |
711 | EXPORT_SYMBOL(inet_csk_destroy_sock); | 711 | EXPORT_SYMBOL(inet_csk_destroy_sock); |
712 | 712 | ||
713 | /* This function allows to force a closure of a socket after the call to | ||
714 | * tcp/dccp_create_openreq_child(). | ||
715 | */ | ||
716 | void inet_csk_prepare_forced_close(struct sock *sk) | ||
717 | { | ||
718 | /* sk_clone_lock locked the socket and set refcnt to 2 */ | ||
719 | bh_unlock_sock(sk); | ||
720 | sock_put(sk); | ||
721 | |||
722 | /* The below has to be done to allow calling inet_csk_destroy_sock */ | ||
723 | sock_set_flag(sk, SOCK_DEAD); | ||
724 | percpu_counter_inc(sk->sk_prot->orphan_count); | ||
725 | inet_sk(sk)->inet_num = 0; | ||
726 | } | ||
727 | EXPORT_SYMBOL(inet_csk_prepare_forced_close); | ||
728 | |||
713 | int inet_csk_listen_start(struct sock *sk, const int nr_table_entries) | 729 | int inet_csk_listen_start(struct sock *sk, const int nr_table_entries) |
714 | { | 730 | { |
715 | struct inet_sock *inet = inet_sk(sk); | 731 | struct inet_sock *inet = inet_sk(sk); |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1ed230716d51..54139fa514e6 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1767,10 +1767,8 @@ exit: | |||
1767 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | 1767 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); |
1768 | return NULL; | 1768 | return NULL; |
1769 | put_and_exit: | 1769 | put_and_exit: |
1770 | tcp_clear_xmit_timers(newsk); | 1770 | inet_csk_prepare_forced_close(newsk); |
1771 | tcp_cleanup_congestion_control(newsk); | 1771 | tcp_done(newsk); |
1772 | bh_unlock_sock(newsk); | ||
1773 | sock_put(newsk); | ||
1774 | goto exit; | 1772 | goto exit; |
1775 | } | 1773 | } |
1776 | EXPORT_SYMBOL(tcp_v4_syn_recv_sock); | 1774 | EXPORT_SYMBOL(tcp_v4_syn_recv_sock); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 6565cf55eb1e..93825dd3a7c0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -1288,7 +1288,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1288 | #endif | 1288 | #endif |
1289 | 1289 | ||
1290 | if (__inet_inherit_port(sk, newsk) < 0) { | 1290 | if (__inet_inherit_port(sk, newsk) < 0) { |
1291 | sock_put(newsk); | 1291 | inet_csk_prepare_forced_close(newsk); |
1292 | tcp_done(newsk); | ||
1292 | goto out; | 1293 | goto out; |
1293 | } | 1294 | } |
1294 | __inet6_hash(newsk, NULL); | 1295 | __inet6_hash(newsk, NULL); |