aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/goldfish/patches-2.6.30/0081-net-socket-ioctl-to-reset-connections-matching-loca.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/goldfish/patches-2.6.30/0081-net-socket-ioctl-to-reset-connections-matching-loca.patch')
-rw-r--r--target/linux/goldfish/patches-2.6.30/0081-net-socket-ioctl-to-reset-connections-matching-loca.patch132
1 files changed, 132 insertions, 0 deletions
diff --git a/target/linux/goldfish/patches-2.6.30/0081-net-socket-ioctl-to-reset-connections-matching-loca.patch b/target/linux/goldfish/patches-2.6.30/0081-net-socket-ioctl-to-reset-connections-matching-loca.patch
new file mode 100644
index 0000000000..fdffc507a0
--- /dev/null
+++ b/target/linux/goldfish/patches-2.6.30/0081-net-socket-ioctl-to-reset-connections-matching-loca.patch
@@ -0,0 +1,132 @@
+From 2df5996350da51bcdee798c00ae1f2415fd9ad20 Mon Sep 17 00:00:00 2001
+From: Robert Love <rlove@google.com>
+Date: Mon, 12 May 2008 17:08:29 -0400
+Subject: [PATCH 081/134] net: socket ioctl to reset connections matching local address
+
+Introduce a new socket ioctl, SIOCKILLADDR, that nukes all sockets
+bound to the same local address. This is useful in situations with
+dynamic IPs, to kill stuck connections.
+
+Signed-off-by: Brian Swetland <swetland@google.com>
+
+net: fix tcp_v4_nuke_addr
+
+Signed-off-by: Dima Zavin <dima@android.com>
+---
+ include/linux/sockios.h | 1 +
+ include/net/tcp.h | 2 ++
+ net/ipv4/af_inet.c | 1 +
+ net/ipv4/devinet.c | 9 ++++++++-
+ net/ipv4/tcp_ipv4.c | 31 +++++++++++++++++++++++++++++++
+ 5 files changed, 43 insertions(+), 1 deletions(-)
+
+--- a/include/linux/sockios.h
++++ b/include/linux/sockios.h
+@@ -65,6 +65,7 @@
+ #define SIOCDIFADDR 0x8936 /* delete PA address */
+ #define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */
+ #define SIOCGIFCOUNT 0x8938 /* get number of devices */
++#define SIOCKILLADDR 0x8939 /* kill sockets with this local addr */
+
+ #define SIOCGIFBR 0x8940 /* Bridging support */
+ #define SIOCSIFBR 0x8941 /* Set bridging options */
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -1381,6 +1381,8 @@ extern struct sk_buff **tcp4_gro_receive
+ extern int tcp_gro_complete(struct sk_buff *skb);
+ extern int tcp4_gro_complete(struct sk_buff *skb);
+
++extern void tcp_v4_nuke_addr(__u32 saddr);
++
+ #ifdef CONFIG_PROC_FS
+ extern int tcp4_proc_init(void);
+ extern void tcp4_proc_exit(void);
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -825,6 +825,7 @@ int inet_ioctl(struct socket *sock, unsi
+ case SIOCSIFPFLAGS:
+ case SIOCGIFPFLAGS:
+ case SIOCSIFFLAGS:
++ case SIOCKILLADDR:
+ err = devinet_ioctl(net, cmd, (void __user *)arg);
+ break;
+ default:
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -57,6 +57,7 @@
+
+ #include <net/arp.h>
+ #include <net/ip.h>
++#include <net/tcp.h>
+ #include <net/route.h>
+ #include <net/ip_fib.h>
+ #include <net/rtnetlink.h>
+@@ -631,6 +632,7 @@ int devinet_ioctl(struct net *net, unsig
+ case SIOCSIFBRDADDR: /* Set the broadcast address */
+ case SIOCSIFDSTADDR: /* Set the destination address */
+ case SIOCSIFNETMASK: /* Set the netmask for the interface */
++ case SIOCKILLADDR: /* Nuke all sockets on this address */
+ ret = -EACCES;
+ if (!capable(CAP_NET_ADMIN))
+ goto out;
+@@ -680,7 +682,8 @@ int devinet_ioctl(struct net *net, unsig
+ }
+
+ ret = -EADDRNOTAVAIL;
+- if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
++ if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS
++ && cmd != SIOCKILLADDR)
+ goto done;
+
+ switch (cmd) {
+@@ -804,6 +807,10 @@ int devinet_ioctl(struct net *net, unsig
+ inet_insert_ifa(ifa);
+ }
+ break;
++ case SIOCKILLADDR: /* Nuke all connections on this address */
++ ret = 0;
++ tcp_v4_nuke_addr(sin->sin_addr.s_addr);
++ break;
+ }
+ done:
+ rtnl_unlock();
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -1845,6 +1845,37 @@ void tcp_v4_destroy_sock(struct sock *sk
+
+ EXPORT_SYMBOL(tcp_v4_destroy_sock);
+
++/*
++ * tcp_v4_nuke_addr - destroy all sockets on the given local address
++ */
++void tcp_v4_nuke_addr(__u32 saddr)
++{
++ unsigned int bucket;
++
++ for (bucket = 0; bucket < tcp_hashinfo.ehash_size; bucket++) {
++ struct hlist_nulls_node *node;
++ struct sock *sk;
++ spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);
++
++ spin_lock_bh(lock);
++ sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
++ struct inet_sock *inet = inet_sk(sk);
++
++ if (inet->rcv_saddr != saddr)
++ continue;
++ if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
++ continue;
++ if (sock_flag(sk, SOCK_DEAD))
++ continue;
++
++ sk->sk_err = ETIMEDOUT;
++ sk->sk_error_report(sk);
++ tcp_done(sk);
++ }
++ spin_unlock_bh(lock);
++ }
++}
++
+ #ifdef CONFIG_PROC_FS
+ /* Proc filesystem TCP sock list dumping. */
+