Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8591a83c authored by Dmitry Shmidt's avatar Dmitry Shmidt
Browse files

Revert "net: socket ioctl to reset connections matching local address"

Use SOCK_DESTROY from now instead of SIOCKILLADDR

This reverts commit 38f0ec72.

Change-Id: I2dcd833b66c88a48de8978dce9d72ab78f9af549
parent 20de1c6b
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -1681,8 +1681,6 @@ static inline bool tcp_stream_memory_free(const struct sock *sk)
	return notsent_bytes < tcp_notsent_lowat(tp);
}

extern int tcp_nuke_addr(struct net *net, struct sockaddr *addr);

#ifdef CONFIG_PROC_FS
int tcp4_proc_init(void);
void tcp4_proc_exit(void);
+0 −1
Original line number Diff line number Diff line
@@ -65,7 +65,6 @@
#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 	*/
+0 −1
Original line number Diff line number Diff line
@@ -886,7 +886,6 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
	case SIOCSIFPFLAGS:
	case SIOCGIFPFLAGS:
	case SIOCSIFFLAGS:
	case SIOCKILLADDR:
		err = devinet_ioctl(net, cmd, (void __user *)arg);
		break;
	default:
+1 −7
Original line number Diff line number Diff line
@@ -59,7 +59,6 @@

#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>
@@ -965,7 +964,6 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
	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 = -EPERM;
		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
			goto out;
@@ -1017,8 +1015,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
	}

	ret = -EADDRNOTAVAIL;
	if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS
	    && cmd != SIOCKILLADDR)
	if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
		goto done;

	switch (cmd) {
@@ -1145,9 +1142,6 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
			inet_insert_ifa(ifa);
		}
		break;
	case SIOCKILLADDR:	/* Nuke all connections on this address */
		ret = tcp_nuke_addr(net, (struct sockaddr *) sin);
		break;
	}
done:
	rtnl_unlock();
+0 −105
Original line number Diff line number Diff line
@@ -276,9 +276,6 @@
#include <net/tcp.h>
#include <net/xfrm.h>
#include <net/ip.h>
#include <net/ip6_route.h>
#include <net/ipv6.h>
#include <net/transp_v6.h>
#include <net/sock.h>

#include <asm/uaccess.h>
@@ -3250,105 +3247,3 @@ void __init tcp_init(void)
	BUG_ON(tcp_register_congestion_control(&tcp_reno) != 0);
	tcp_tasklet_init();
}

static int tcp_is_local(struct net *net, __be32 addr) {
	struct rtable *rt;
	struct flowi4 fl4 = { .daddr = addr };
	rt = ip_route_output_key(net, &fl4);
	if (IS_ERR_OR_NULL(rt))
		return 0;
	return rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK);
}

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static int tcp_is_local6(struct net *net, struct in6_addr *addr) {
	struct rt6_info *rt6 = rt6_lookup(net, addr, addr, 0, 0);
	return rt6 && rt6->dst.dev && (rt6->dst.dev->flags & IFF_LOOPBACK);
}
#endif

/*
 * tcp_nuke_addr - destroy all sockets on the given local address
 * if local address is the unspecified address (0.0.0.0 or ::), destroy all
 * sockets with local addresses that are not configured.
 */
int tcp_nuke_addr(struct net *net, struct sockaddr *addr)
{
	int family = addr->sa_family;
	unsigned int bucket;

	struct in_addr *in;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	struct in6_addr *in6 = NULL;
#endif
	if (family == AF_INET) {
		in = &((struct sockaddr_in *)addr)->sin_addr;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	} else if (family == AF_INET6) {
		in6 = &((struct sockaddr_in6 *)addr)->sin6_addr;
#endif
	} else {
		return -EAFNOSUPPORT;
	}

	for (bucket = 0; bucket < tcp_hashinfo.ehash_mask; bucket++) {
		struct hlist_nulls_node *node;
		struct sock *sk;
		spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);

restart:
		spin_lock_bh(lock);
		sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
			struct inet_sock *inet = inet_sk(sk);

			if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
				continue;
			if (sock_flag(sk, SOCK_DEAD))
				continue;

			if (family == AF_INET) {
				__be32 s4 = inet->inet_rcv_saddr;
				if (s4 == LOOPBACK4_IPV6)
					continue;

				if (in->s_addr != s4 &&
				    !(in->s_addr == INADDR_ANY &&
				      !tcp_is_local(net, s4)))
					continue;
			}

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
			if (family == AF_INET6) {
				struct in6_addr *s6;

				s6 = &sk->sk_v6_rcv_saddr;
				if (ipv6_addr_type(s6) == IPV6_ADDR_MAPPED)
					continue;

				if (!ipv6_addr_equal(in6, s6) &&
				    !(ipv6_addr_equal(in6, &in6addr_any) &&
				      !tcp_is_local6(net, s6)))
				continue;
			}
#endif

			sock_hold(sk);
			spin_unlock_bh(lock);

			local_bh_disable();
			bh_lock_sock(sk);
			sk->sk_err = ETIMEDOUT;
			sk->sk_error_report(sk);

			tcp_done(sk);
			bh_unlock_sock(sk);
			local_bh_enable();
			sock_put(sk);

			goto restart;
		}
		spin_unlock_bh(lock);
	}

	return 0;
}
Loading