diff options
| author | Linus Walleij <linus.walleij@linaro.org> | 2013-10-08 13:27:11 +0200 | 
|---|---|---|
| committer | Linus Walleij <linus.walleij@linaro.org> | 2013-10-08 13:27:11 +0200 | 
| commit | bfabb59433fc18ff78d2818e10e212d0f85d56ae (patch) | |
| tree | dd7cbead179c09c62627a84c16c802d99095ba6e /net/core | |
| parent | 6a08a92ec45782e5543addf5f8785e2560a078f6 (diff) | |
| parent | d0e639c9e06d44e713170031fe05fb60ebe680af (diff) | |
Merge tag 'v3.12-rc4' into devel
Linux 3.12-rc4
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/dev.c | 49 | ||||
| -rw-r--r-- | net/core/flow_dissector.c | 4 | ||||
| -rw-r--r-- | net/core/netpoll.c | 11 | ||||
| -rw-r--r-- | net/core/secure_seq.c | 27 | 
4 files changed, 79 insertions, 12 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 5c713f2239c..65f829cfd92 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5247,10 +5247,12 @@ static int dev_new_index(struct net *net)  /* Delayed registration/unregisteration */  static LIST_HEAD(net_todo_list); +static DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);  static void net_set_todo(struct net_device *dev)  {  	list_add_tail(&dev->todo_list, &net_todo_list); +	dev_net(dev)->dev_unreg_count++;  }  static void rollback_registered_many(struct list_head *head) @@ -5918,6 +5920,12 @@ void netdev_run_todo(void)  		if (dev->destructor)  			dev->destructor(dev); +		/* Report a network device has been unregistered */ +		rtnl_lock(); +		dev_net(dev)->dev_unreg_count--; +		__rtnl_unlock(); +		wake_up(&netdev_unregistering_wq); +  		/* Free network device */  		kobject_put(&dev->dev.kobj);  	} @@ -6603,6 +6611,34 @@ static void __net_exit default_device_exit(struct net *net)  	rtnl_unlock();  } +static void __net_exit rtnl_lock_unregistering(struct list_head *net_list) +{ +	/* Return with the rtnl_lock held when there are no network +	 * devices unregistering in any network namespace in net_list. +	 */ +	struct net *net; +	bool unregistering; +	DEFINE_WAIT(wait); + +	for (;;) { +		prepare_to_wait(&netdev_unregistering_wq, &wait, +				TASK_UNINTERRUPTIBLE); +		unregistering = false; +		rtnl_lock(); +		list_for_each_entry(net, net_list, exit_list) { +			if (net->dev_unreg_count > 0) { +				unregistering = true; +				break; +			} +		} +		if (!unregistering) +			break; +		__rtnl_unlock(); +		schedule(); +	} +	finish_wait(&netdev_unregistering_wq, &wait); +} +  static void __net_exit default_device_exit_batch(struct list_head *net_list)  {  	/* At exit all network devices most be removed from a network @@ -6614,7 +6650,18 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)  	struct net *net;  	LIST_HEAD(dev_kill_list); -	rtnl_lock(); +	/* To prevent network device cleanup code from dereferencing +	 * loopback devices or network devices that have been freed +	 * wait here for all pending unregistrations to complete, +	 * before unregistring the loopback device and allowing the +	 * network namespace be freed. +	 * +	 * The netdev todo list containing all network devices +	 * unregistrations that happen in default_device_exit_batch +	 * will run in the rtnl_unlock() at the end of +	 * default_device_exit_batch. +	 */ +	rtnl_lock_unregistering(net_list);  	list_for_each_entry(net, net_list, exit_list) {  		for_each_netdev_reverse(net, dev) {  			if (dev->rtnl_link_ops) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 1929af87b26..8d7d0dd72db 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -154,8 +154,8 @@ ipv6:  	if (poff >= 0) {  		__be32 *ports, _ports; -		nhoff += poff; -		ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports); +		ports = skb_header_pointer(skb, nhoff + poff, +					   sizeof(_ports), &_ports);  		if (ports)  			flow->ports = *ports;  	} diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 2c637e9a0b2..fc75c9e461b 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -550,7 +550,7 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo  		return;  	proto = ntohs(eth_hdr(skb)->h_proto); -	if (proto == ETH_P_IP) { +	if (proto == ETH_P_ARP) {  		struct arphdr *arp;  		unsigned char *arp_ptr;  		/* No arp on this interface */ @@ -1284,15 +1284,14 @@ EXPORT_SYMBOL_GPL(__netpoll_free_async);  void netpoll_cleanup(struct netpoll *np)  { -	if (!np->dev) -		return; -  	rtnl_lock(); +	if (!np->dev) +		goto out;  	__netpoll_cleanup(np); -	rtnl_unlock(); -  	dev_put(np->dev);  	np->dev = NULL; +out: +	rtnl_unlock();  }  EXPORT_SYMBOL(netpoll_cleanup); diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index 6a2f13cee86..3f1ec1586ae 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c @@ -10,11 +10,24 @@  #include <net/secure_seq.h> -static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; +#define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4) -void net_secret_init(void) +static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned; + +static void net_secret_init(void)  { -	get_random_bytes(net_secret, sizeof(net_secret)); +	u32 tmp; +	int i; + +	if (likely(net_secret[0])) +		return; + +	for (i = NET_SECRET_SIZE; i > 0;) { +		do { +			get_random_bytes(&tmp, sizeof(tmp)); +		} while (!tmp); +		cmpxchg(&net_secret[--i], 0, tmp); +	}  }  #ifdef CONFIG_INET @@ -42,6 +55,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,  	u32 hash[MD5_DIGEST_WORDS];  	u32 i; +	net_secret_init();  	memcpy(hash, saddr, 16);  	for (i = 0; i < 4; i++)  		secret[i] = net_secret[i] + (__force u32)daddr[i]; @@ -63,6 +77,7 @@ u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,  	u32 hash[MD5_DIGEST_WORDS];  	u32 i; +	net_secret_init();  	memcpy(hash, saddr, 16);  	for (i = 0; i < 4; i++)  		secret[i] = net_secret[i] + (__force u32) daddr[i]; @@ -82,6 +97,7 @@ __u32 secure_ip_id(__be32 daddr)  {  	u32 hash[MD5_DIGEST_WORDS]; +	net_secret_init();  	hash[0] = (__force __u32) daddr;  	hash[1] = net_secret[13];  	hash[2] = net_secret[14]; @@ -96,6 +112,7 @@ __u32 secure_ipv6_id(const __be32 daddr[4])  {  	__u32 hash[4]; +	net_secret_init();  	memcpy(hash, daddr, 16);  	md5_transform(hash, net_secret); @@ -107,6 +124,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,  {  	u32 hash[MD5_DIGEST_WORDS]; +	net_secret_init();  	hash[0] = (__force u32)saddr;  	hash[1] = (__force u32)daddr;  	hash[2] = ((__force u16)sport << 16) + (__force u16)dport; @@ -121,6 +139,7 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)  {  	u32 hash[MD5_DIGEST_WORDS]; +	net_secret_init();  	hash[0] = (__force u32)saddr;  	hash[1] = (__force u32)daddr;  	hash[2] = (__force u32)dport ^ net_secret[14]; @@ -140,6 +159,7 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,  	u32 hash[MD5_DIGEST_WORDS];  	u64 seq; +	net_secret_init();  	hash[0] = (__force u32)saddr;  	hash[1] = (__force u32)daddr;  	hash[2] = ((__force u16)sport << 16) + (__force u16)dport; @@ -164,6 +184,7 @@ u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,  	u64 seq;  	u32 i; +	net_secret_init();  	memcpy(hash, saddr, 16);  	for (i = 0; i < 4; i++)  		secret[i] = net_secret[i] + daddr[i];  | 
