diff options
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.patch | 132 |
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 0000000..fdffc50 --- /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. */ + |