1 From 2df5996350da51bcdee798c00ae1f2415fd9ad20 Mon Sep 17 00:00:00 2001
2 From: Robert Love <rlove@google.com>
3 Date: Mon, 12 May 2008 17:08:29 -0400
4 Subject: [PATCH 081/134] net: socket ioctl to reset connections matching local address
6 Introduce a new socket ioctl, SIOCKILLADDR, that nukes all sockets
7 bound to the same local address. This is useful in situations with
8 dynamic IPs, to kill stuck connections.
10 Signed-off-by: Brian Swetland <swetland@google.com>
12 net: fix tcp_v4_nuke_addr
14 Signed-off-by: Dima Zavin <dima@android.com>
16 include/linux/sockios.h | 1 +
17 include/net/tcp.h | 2 ++
18 net/ipv4/af_inet.c | 1 +
19 net/ipv4/devinet.c | 9 ++++++++-
20 net/ipv4/tcp_ipv4.c | 31 +++++++++++++++++++++++++++++++
21 5 files changed, 43 insertions(+), 1 deletions(-)
23 --- a/include/linux/sockios.h
24 +++ b/include/linux/sockios.h
26 #define SIOCDIFADDR 0x8936 /* delete PA address */
27 #define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */
28 #define SIOCGIFCOUNT 0x8938 /* get number of devices */
29 +#define SIOCKILLADDR 0x8939 /* kill sockets with this local addr */
31 #define SIOCGIFBR 0x8940 /* Bridging support */
32 #define SIOCSIFBR 0x8941 /* Set bridging options */
33 --- a/include/net/tcp.h
34 +++ b/include/net/tcp.h
35 @@ -1381,6 +1381,8 @@ extern struct sk_buff **tcp4_gro_receive
36 extern int tcp_gro_complete(struct sk_buff *skb);
37 extern int tcp4_gro_complete(struct sk_buff *skb);
39 +extern void tcp_v4_nuke_addr(__u32 saddr);
42 extern int tcp4_proc_init(void);
43 extern void tcp4_proc_exit(void);
44 --- a/net/ipv4/af_inet.c
45 +++ b/net/ipv4/af_inet.c
46 @@ -825,6 +825,7 @@ int inet_ioctl(struct socket *sock, unsi
51 err = devinet_ioctl(net, cmd, (void __user *)arg);
54 --- a/net/ipv4/devinet.c
55 +++ b/net/ipv4/devinet.c
61 #include <net/route.h>
62 #include <net/ip_fib.h>
63 #include <net/rtnetlink.h>
64 @@ -631,6 +632,7 @@ int devinet_ioctl(struct net *net, unsig
65 case SIOCSIFBRDADDR: /* Set the broadcast address */
66 case SIOCSIFDSTADDR: /* Set the destination address */
67 case SIOCSIFNETMASK: /* Set the netmask for the interface */
68 + case SIOCKILLADDR: /* Nuke all sockets on this address */
70 if (!capable(CAP_NET_ADMIN))
72 @@ -680,7 +682,8 @@ int devinet_ioctl(struct net *net, unsig
76 - if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
77 + if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS
78 + && cmd != SIOCKILLADDR)
82 @@ -804,6 +807,10 @@ int devinet_ioctl(struct net *net, unsig
86 + case SIOCKILLADDR: /* Nuke all connections on this address */
88 + tcp_v4_nuke_addr(sin->sin_addr.s_addr);
93 --- a/net/ipv4/tcp_ipv4.c
94 +++ b/net/ipv4/tcp_ipv4.c
95 @@ -1845,6 +1845,37 @@ void tcp_v4_destroy_sock(struct sock *sk
97 EXPORT_SYMBOL(tcp_v4_destroy_sock);
100 + * tcp_v4_nuke_addr - destroy all sockets on the given local address
102 +void tcp_v4_nuke_addr(__u32 saddr)
104 + unsigned int bucket;
106 + for (bucket = 0; bucket < tcp_hashinfo.ehash_size; bucket++) {
107 + struct hlist_nulls_node *node;
109 + spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);
111 + spin_lock_bh(lock);
112 + sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
113 + struct inet_sock *inet = inet_sk(sk);
115 + if (inet->rcv_saddr != saddr)
117 + if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
119 + if (sock_flag(sk, SOCK_DEAD))
122 + sk->sk_err = ETIMEDOUT;
123 + sk->sk_error_report(sk);
126 + spin_unlock_bh(lock);
130 #ifdef CONFIG_PROC_FS
131 /* Proc filesystem TCP sock list dumping. */