ps3: R.I.P.
[openwrt.git] / target / linux / goldfish / patches-2.6.30 / 0081-net-socket-ioctl-to-reset-connections-matching-loca.patch
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
5
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.
9
10 Signed-off-by: Brian Swetland <swetland@google.com>
11
12 net: fix tcp_v4_nuke_addr
13
14 Signed-off-by: Dima Zavin <dima@android.com>
15 ---
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(-)
22
23 --- a/include/linux/sockios.h
24 +++ b/include/linux/sockios.h
25 @@ -65,6 +65,7 @@
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 */
30  
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);
38  
39 +extern void tcp_v4_nuke_addr(__u32 saddr);
40 +
41  #ifdef CONFIG_PROC_FS
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
47                 case SIOCSIFPFLAGS:
48                 case SIOCGIFPFLAGS:
49                 case SIOCSIFFLAGS:
50 +               case SIOCKILLADDR:
51                         err = devinet_ioctl(net, cmd, (void __user *)arg);
52                         break;
53                 default:
54 --- a/net/ipv4/devinet.c
55 +++ b/net/ipv4/devinet.c
56 @@ -57,6 +57,7 @@
57  
58  #include <net/arp.h>
59  #include <net/ip.h>
60 +#include <net/tcp.h>
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 */
69                 ret = -EACCES;
70                 if (!capable(CAP_NET_ADMIN))
71                         goto out;
72 @@ -680,7 +682,8 @@ int devinet_ioctl(struct net *net, unsig
73         }
74  
75         ret = -EADDRNOTAVAIL;
76 -       if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
77 +       if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS
78 +           && cmd != SIOCKILLADDR)
79                 goto done;
80  
81         switch (cmd) {
82 @@ -804,6 +807,10 @@ int devinet_ioctl(struct net *net, unsig
83                         inet_insert_ifa(ifa);
84                 }
85                 break;
86 +       case SIOCKILLADDR:      /* Nuke all connections on this address */
87 +               ret = 0;
88 +               tcp_v4_nuke_addr(sin->sin_addr.s_addr);
89 +               break;
90         }
91  done:
92         rtnl_unlock();
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
96  
97  EXPORT_SYMBOL(tcp_v4_destroy_sock);
98  
99 +/*
100 + * tcp_v4_nuke_addr - destroy all sockets on the given local address
101 + */
102 +void tcp_v4_nuke_addr(__u32 saddr)
103 +{
104 +       unsigned int bucket;
105 +
106 +       for (bucket = 0; bucket < tcp_hashinfo.ehash_size; bucket++) {
107 +               struct hlist_nulls_node *node;
108 +               struct sock *sk;
109 +               spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);
110 +
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);
114 +
115 +                       if (inet->rcv_saddr != saddr)
116 +                               continue;
117 +                       if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
118 +                               continue;
119 +                       if (sock_flag(sk, SOCK_DEAD))
120 +                               continue;
121 +
122 +                       sk->sk_err = ETIMEDOUT;
123 +                       sk->sk_error_report(sk);
124 +                       tcp_done(sk);
125 +               }
126 +               spin_unlock_bh(lock);
127 +       }
128 +}
129 +
130  #ifdef CONFIG_PROC_FS
131  /* Proc filesystem TCP sock list dumping. */
132