diff options
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/datagram.c | 1 | ||||
| -rw-r--r-- | net/core/dev.c | 28 | ||||
| -rw-r--r-- | net/core/dev_mcast.c | 5 | ||||
| -rw-r--r-- | net/core/drop_monitor.c | 1 | ||||
| -rw-r--r-- | net/core/dst.c | 1 | ||||
| -rw-r--r-- | net/core/ethtool.c | 104 | ||||
| -rw-r--r-- | net/core/fib_rules.c | 1 | ||||
| -rw-r--r-- | net/core/filter.c | 1 | ||||
| -rw-r--r-- | net/core/gen_estimator.c | 1 | ||||
| -rw-r--r-- | net/core/iovec.c | 1 | ||||
| -rw-r--r-- | net/core/link_watch.c | 1 | ||||
| -rw-r--r-- | net/core/neighbour.c | 3 | ||||
| -rw-r--r-- | net/core/net-sysfs.c | 1 | ||||
| -rw-r--r-- | net/core/net-traces.c | 1 | ||||
| -rw-r--r-- | net/core/netpoll.c | 12 | ||||
| -rw-r--r-- | net/core/rtnetlink.c | 164 | ||||
| -rw-r--r-- | net/core/scm.c | 1 | ||||
| -rw-r--r-- | net/core/sock.c | 19 | ||||
| -rw-r--r-- | net/core/sysctl_net_core.c | 1 | 
19 files changed, 246 insertions, 101 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c index 95c2e0840d0..2dccd4ee591 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -48,6 +48,7 @@  #include <linux/poll.h>  #include <linux/highmem.h>  #include <linux/spinlock.h> +#include <linux/slab.h>  #include <net/protocol.h>  #include <linux/skbuff.h> diff --git a/net/core/dev.c b/net/core/dev.c index bcc490cc945..264137fce3a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -80,6 +80,7 @@  #include <linux/types.h>  #include <linux/kernel.h>  #include <linux/hash.h> +#include <linux/slab.h>  #include <linux/sched.h>  #include <linux/mutex.h>  #include <linux/string.h> @@ -1450,7 +1451,7 @@ static inline void net_timestamp(struct sk_buff *skb)   *   * return values:   *	NET_RX_SUCCESS	(no congestion) - *	NET_RX_DROP     (packet was dropped) + *	NET_RX_DROP     (packet was dropped, but freed)   *   * dev_forward_skb can be used for injecting an skb from the   * start_xmit function of one device into the receive queue @@ -1464,12 +1465,11 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)  {  	skb_orphan(skb); -	if (!(dev->flags & IFF_UP)) -		return NET_RX_DROP; - -	if (skb->len > (dev->mtu + dev->hard_header_len)) +	if (!(dev->flags & IFF_UP) || +	    (skb->len > (dev->mtu + dev->hard_header_len))) { +		kfree_skb(skb);  		return NET_RX_DROP; - +	}  	skb_set_dev(skb, dev);  	skb->tstamp.tv64 = 0;  	skb->pkt_type = PACKET_HOST; @@ -1988,8 +1988,12 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,  			if (dev->real_num_tx_queues > 1)  				queue_index = skb_tx_hash(dev, skb); -			if (sk && sk->sk_dst_cache) -				sk_tx_queue_set(sk, queue_index); +			if (sk) { +				struct dst_entry *dst = rcu_dereference_bh(sk->sk_dst_cache); + +				if (dst && skb_dst(skb) == dst) +					sk_tx_queue_set(sk, queue_index); +			}  		}  	} @@ -2483,6 +2487,7 @@ int netif_receive_skb(struct sk_buff *skb)  {  	struct packet_type *ptype, *pt_prev;  	struct net_device *orig_dev; +	struct net_device *master;  	struct net_device *null_or_orig;  	struct net_device *null_or_bond;  	int ret = NET_RX_DROP; @@ -2503,11 +2508,12 @@ int netif_receive_skb(struct sk_buff *skb)  	null_or_orig = NULL;  	orig_dev = skb->dev; -	if (orig_dev->master) { -		if (skb_bond_should_drop(skb)) +	master = ACCESS_ONCE(orig_dev->master); +	if (master) { +		if (skb_bond_should_drop(skb, master))  			null_or_orig = orig_dev; /* deliver only exact match */  		else -			skb->dev = orig_dev->master; +			skb->dev = master;  	}  	__get_cpu_var(netdev_rx_stat).total++; diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index fd91569e239..3dc295beb48 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -97,8 +97,9 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)  	netif_addr_lock_bh(dev);  	if (alen != dev->addr_len) -		return -EINVAL; -	err = __dev_addr_add(&dev->mc_list, &dev->mc_count, addr, alen, glbl); +		err = -EINVAL; +	else +		err = __dev_addr_add(&dev->mc_list, &dev->mc_count, addr, alen, glbl);  	if (!err)  		__dev_set_rx_mode(dev);  	netif_addr_unlock_bh(dev); diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index f8c87497535..cf208d8042b 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -21,6 +21,7 @@  #include <linux/percpu.h>  #include <linux/timer.h>  #include <linux/bitops.h> +#include <linux/slab.h>  #include <net/genetlink.h>  #include <net/netevent.h> diff --git a/net/core/dst.c b/net/core/dst.c index cb1b3488b73..f307bc18f6a 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -12,6 +12,7 @@  #include <linux/workqueue.h>  #include <linux/mm.h>  #include <linux/module.h> +#include <linux/slab.h>  #include <linux/netdevice.h>  #include <linux/skbuff.h>  #include <linux/string.h> diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 0f2f82185ec..9d55c57f318 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -17,6 +17,8 @@  #include <linux/errno.h>  #include <linux/ethtool.h>  #include <linux/netdevice.h> +#include <linux/bitops.h> +#include <linux/slab.h>  #include <asm/uaccess.h>  /* @@ -199,10 +201,7 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)  	return dev->ethtool_ops->set_settings(dev, &cmd);  } -/* - * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() - */ -static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) +static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)  {  	struct ethtool_drvinfo info;  	const struct ethtool_ops *ops = dev->ethtool_ops; @@ -214,6 +213,10 @@ static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *use  	info.cmd = ETHTOOL_GDRVINFO;  	ops->get_drvinfo(dev, &info); +	/* +	 * this method of obtaining string set info is deprecated; +	 * Use ETHTOOL_GSSET_INFO instead. +	 */  	if (ops->get_sset_count) {  		int rc; @@ -237,10 +240,67 @@ static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *use  	return 0;  } -/* - * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() - */ -static noinline int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr) +static noinline_for_stack int ethtool_get_sset_info(struct net_device *dev, +                                          void __user *useraddr) +{ +	struct ethtool_sset_info info; +	const struct ethtool_ops *ops = dev->ethtool_ops; +	u64 sset_mask; +	int i, idx = 0, n_bits = 0, ret, rc; +	u32 *info_buf = NULL; + +	if (!ops->get_sset_count) +		return -EOPNOTSUPP; + +	if (copy_from_user(&info, useraddr, sizeof(info))) +		return -EFAULT; + +	/* store copy of mask, because we zero struct later on */ +	sset_mask = info.sset_mask; +	if (!sset_mask) +		return 0; + +	/* calculate size of return buffer */ +	n_bits = hweight64(sset_mask); + +	memset(&info, 0, sizeof(info)); +	info.cmd = ETHTOOL_GSSET_INFO; + +	info_buf = kzalloc(n_bits * sizeof(u32), GFP_USER); +	if (!info_buf) +		return -ENOMEM; + +	/* +	 * fill return buffer based on input bitmask and successful +	 * get_sset_count return +	 */ +	for (i = 0; i < 64; i++) { +		if (!(sset_mask & (1ULL << i))) +			continue; + +		rc = ops->get_sset_count(dev, i); +		if (rc >= 0) { +			info.sset_mask |= (1ULL << i); +			info_buf[idx++] = rc; +		} +	} + +	ret = -EFAULT; +	if (copy_to_user(useraddr, &info, sizeof(info))) +		goto out; + +	useraddr += offsetof(struct ethtool_sset_info, data); +	if (copy_to_user(useraddr, info_buf, idx * sizeof(u32))) +		goto out; + +	ret = 0; + +out: +	kfree(info_buf); +	return ret; +} + +static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)  {  	struct ethtool_rxnfc cmd; @@ -253,10 +313,7 @@ static noinline int ethtool_set_rxnfc(struct net_device *dev, void __user *usera  	return dev->ethtool_ops->set_rxnfc(dev, &cmd);  } -/* - * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() - */ -static noinline int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr) +static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)  {  	struct ethtool_rxnfc info;  	const struct ethtool_ops *ops = dev->ethtool_ops; @@ -328,10 +385,7 @@ static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,  	list->count++;  } -/* - * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() - */ -static noinline int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr) +static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr)  {  	struct ethtool_rx_ntuple cmd;  	const struct ethtool_ops *ops = dev->ethtool_ops; @@ -799,10 +853,7 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)  	return ret;  } -/* - * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() - */ -static noinline int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr) +static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr)  {  	struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE }; @@ -816,10 +867,7 @@ static noinline int ethtool_get_coalesce(struct net_device *dev, void __user *us  	return 0;  } -/* - * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() - */ -static noinline int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr) +static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)  {  	struct ethtool_coalesce coalesce; @@ -1229,10 +1277,7 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr,  	return actor(dev, edata.data);  } -/* - * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() - */ -static noinline int ethtool_flash_device(struct net_device *dev, char __user *useraddr) +static noinline_for_stack int ethtool_flash_device(struct net_device *dev, char __user *useraddr)  {  	struct ethtool_flash efl; @@ -1471,6 +1516,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)  	case ETHTOOL_GRXNTUPLE:  		rc = ethtool_get_rx_ntuple(dev, useraddr);  		break; +	case ETHTOOL_GSSET_INFO: +		rc = ethtool_get_sset_info(dev, useraddr); +		break;  	default:  		rc = -EOPNOTSUPP;  	} diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 9a24377146b..d2c3e7dc2e5 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -10,6 +10,7 @@  #include <linux/types.h>  #include <linux/kernel.h> +#include <linux/slab.h>  #include <linux/list.h>  #include <net/net_namespace.h>  #include <net/sock.h> diff --git a/net/core/filter.c b/net/core/filter.c index d38ef7fd50f..ff943bed21a 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -25,6 +25,7 @@  #include <linux/inet.h>  #include <linux/netdevice.h>  #include <linux/if_packet.h> +#include <linux/gfp.h>  #include <net/ip.h>  #include <net/protocol.h>  #include <net/netlink.h> diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 493775f4f2f..cf8e70392fe 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -32,6 +32,7 @@  #include <linux/rtnetlink.h>  #include <linux/init.h>  #include <linux/rbtree.h> +#include <linux/slab.h>  #include <net/sock.h>  #include <net/gen_stats.h> diff --git a/net/core/iovec.c b/net/core/iovec.c index 16ad45d4882..1e7f4e91a93 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -20,7 +20,6 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/mm.h> -#include <linux/slab.h>  #include <linux/net.h>  #include <linux/in6.h>  #include <asm/uaccess.h> diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 5910b555a54..bdbce2f5875 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -19,7 +19,6 @@  #include <linux/rtnetlink.h>  #include <linux/jiffies.h>  #include <linux/spinlock.h> -#include <linux/slab.h>  #include <linux/workqueue.h>  #include <linux/bitops.h>  #include <asm/types.h> diff --git a/net/core/neighbour.c b/net/core/neighbour.c index d102f6d9abd..bff37908bd5 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -15,6 +15,7 @@   *	Harald Welte		Add neighbour cache statistics like rtstat   */ +#include <linux/slab.h>  #include <linux/types.h>  #include <linux/kernel.h>  #include <linux/module.h> @@ -771,6 +772,8 @@ static __inline__ int neigh_max_probes(struct neighbour *n)  }  static void neigh_invalidate(struct neighbour *neigh) +	__releases(neigh->lock) +	__acquires(neigh->lock)  {  	struct sk_buff *skb; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 099c753c421..59cfc7d8fc4 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -13,6 +13,7 @@  #include <linux/kernel.h>  #include <linux/netdevice.h>  #include <linux/if_arp.h> +#include <linux/slab.h>  #include <net/sock.h>  #include <linux/rtnetlink.h>  #include <linux/wireless.h> diff --git a/net/core/net-traces.c b/net/core/net-traces.c index f1e982c508b..afa6380ed88 100644 --- a/net/core/net-traces.c +++ b/net/core/net-traces.c @@ -19,6 +19,7 @@  #include <linux/workqueue.h>  #include <linux/netlink.h>  #include <linux/net_dropmon.h> +#include <linux/slab.h>  #include <asm/unaligned.h>  #include <asm/bitops.h> diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 7aa69725376..a58f59b9759 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -22,6 +22,7 @@  #include <linux/delay.h>  #include <linux/rcupdate.h>  #include <linux/workqueue.h> +#include <linux/slab.h>  #include <net/tcp.h>  #include <net/udp.h>  #include <asm/unaligned.h> @@ -614,7 +615,7 @@ void netpoll_print_options(struct netpoll *np)  			 np->name, np->local_port);  	printk(KERN_INFO "%s: local IP %pI4\n",  			 np->name, &np->local_ip); -	printk(KERN_INFO "%s: interface %s\n", +	printk(KERN_INFO "%s: interface '%s'\n",  			 np->name, np->dev_name);  	printk(KERN_INFO "%s: remote port %d\n",  			 np->name, np->remote_port); @@ -661,6 +662,9 @@ int netpoll_parse_options(struct netpoll *np, char *opt)  		if ((delim = strchr(cur, '@')) == NULL)  			goto parse_failed;  		*delim = 0; +		if (*cur == ' ' || *cur == '\t') +			printk(KERN_INFO "%s: warning: whitespace" +					"is not allowed\n", np->name);  		np->remote_port = simple_strtol(cur, NULL, 10);  		cur = delim;  	} @@ -708,7 +712,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt)  	return 0;   parse_failed: -	printk(KERN_INFO "%s: couldn't parse config at %s!\n", +	printk(KERN_INFO "%s: couldn't parse config at '%s'!\n",  	       np->name, cur);  	return -1;  } @@ -735,7 +739,7 @@ int netpoll_setup(struct netpoll *np)  		npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);  		if (!npinfo) {  			err = -ENOMEM; -			goto release; +			goto put;  		}  		npinfo->rx_flags = 0; @@ -845,7 +849,7 @@ int netpoll_setup(struct netpoll *np)  		kfree(npinfo);  	} - +put:  	dev_put(ndev);  	return err;  } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4568120d853..31e85d327aa 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -602,12 +602,19 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,  	a->tx_compressed = b->tx_compressed;  }; +/* All VF info */  static inline int rtnl_vfinfo_size(const struct net_device *dev)  { -	if (dev->dev.parent && dev_is_pci(dev->dev.parent)) -		return dev_num_vf(dev->dev.parent) * -			sizeof(struct ifla_vf_info); -	else +	if (dev->dev.parent && dev_is_pci(dev->dev.parent)) { + +		int num_vfs = dev_num_vf(dev->dev.parent); +		size_t size = nlmsg_total_size(sizeof(struct nlattr)); +		size += nlmsg_total_size(num_vfs * sizeof(struct nlattr)); +		size += num_vfs * (sizeof(struct ifla_vf_mac) + +				  sizeof(struct ifla_vf_vlan) + +				  sizeof(struct ifla_vf_tx_rate)); +		return size; +	} else  		return 0;  } @@ -629,7 +636,7 @@ static inline size_t if_nlmsg_size(const struct net_device *dev)  	       + nla_total_size(1) /* IFLA_OPERSTATE */  	       + nla_total_size(1) /* IFLA_LINKMODE */  	       + nla_total_size(4) /* IFLA_NUM_VF */ -	       + nla_total_size(rtnl_vfinfo_size(dev)) /* IFLA_VFINFO */ +	       + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */  	       + rtnl_link_get_size(dev); /* IFLA_LINKINFO */  } @@ -700,14 +707,37 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,  	if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) {  		int i; -		struct ifla_vf_info ivi; -		NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)); -		for (i = 0; i < dev_num_vf(dev->dev.parent); i++) { +		struct nlattr *vfinfo, *vf; +		int num_vfs = dev_num_vf(dev->dev.parent); + +		NLA_PUT_U32(skb, IFLA_NUM_VF, num_vfs); +		vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); +		if (!vfinfo) +			goto nla_put_failure; +		for (i = 0; i < num_vfs; i++) { +			struct ifla_vf_info ivi; +			struct ifla_vf_mac vf_mac; +			struct ifla_vf_vlan vf_vlan; +			struct ifla_vf_tx_rate vf_tx_rate;  			if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi))  				break; -			NLA_PUT(skb, IFLA_VFINFO, sizeof(ivi), &ivi); +			vf_mac.vf = vf_vlan.vf = vf_tx_rate.vf = ivi.vf; +			memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac)); +			vf_vlan.vlan = ivi.vlan; +			vf_vlan.qos = ivi.qos; +			vf_tx_rate.rate = ivi.tx_rate; +			vf = nla_nest_start(skb, IFLA_VF_INFO); +			if (!vf) { +				nla_nest_cancel(skb, vfinfo); +				goto nla_put_failure; +			} +			NLA_PUT(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac); +			NLA_PUT(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan); +			NLA_PUT(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate), &vf_tx_rate); +			nla_nest_end(skb, vf);  		} +		nla_nest_end(skb, vfinfo);  	}  	if (dev->rtnl_link_ops) {  		if (rtnl_link_fill(skb, dev) < 0) @@ -769,12 +799,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {  	[IFLA_LINKINFO]		= { .type = NLA_NESTED },  	[IFLA_NET_NS_PID]	= { .type = NLA_U32 },  	[IFLA_IFALIAS]	        = { .type = NLA_STRING, .len = IFALIASZ-1 }, -	[IFLA_VF_MAC]		= { .type = NLA_BINARY, -				    .len = sizeof(struct ifla_vf_mac) }, -	[IFLA_VF_VLAN]		= { .type = NLA_BINARY, -				    .len = sizeof(struct ifla_vf_vlan) }, -	[IFLA_VF_TX_RATE]	= { .type = NLA_BINARY, -				    .len = sizeof(struct ifla_vf_tx_rate) }, +	[IFLA_VFINFO_LIST]	= {. type = NLA_NESTED },  };  EXPORT_SYMBOL(ifla_policy); @@ -783,6 +808,19 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {  	[IFLA_INFO_DATA]	= { .type = NLA_NESTED },  }; +static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = { +	[IFLA_VF_INFO]		= { .type = NLA_NESTED }, +}; + +static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { +	[IFLA_VF_MAC]		= { .type = NLA_BINARY, +				    .len = sizeof(struct ifla_vf_mac) }, +	[IFLA_VF_VLAN]		= { .type = NLA_BINARY, +				    .len = sizeof(struct ifla_vf_vlan) }, +	[IFLA_VF_TX_RATE]	= { .type = NLA_BINARY, +				    .len = sizeof(struct ifla_vf_tx_rate) }, +}; +  struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])  {  	struct net *net; @@ -812,6 +850,52 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])  	return 0;  } +static int do_setvfinfo(struct net_device *dev, struct nlattr *attr) +{ +	int rem, err = -EINVAL; +	struct nlattr *vf; +	const struct net_device_ops *ops = dev->netdev_ops; + +	nla_for_each_nested(vf, attr, rem) { +		switch (nla_type(vf)) { +		case IFLA_VF_MAC: { +			struct ifla_vf_mac *ivm; +			ivm = nla_data(vf); +			err = -EOPNOTSUPP; +			if (ops->ndo_set_vf_mac) +				err = ops->ndo_set_vf_mac(dev, ivm->vf, +							  ivm->mac); +			break; +		} +		case IFLA_VF_VLAN: { +			struct ifla_vf_vlan *ivv; +			ivv = nla_data(vf); +			err = -EOPNOTSUPP; +			if (ops->ndo_set_vf_vlan) +				err = ops->ndo_set_vf_vlan(dev, ivv->vf, +							   ivv->vlan, +							   ivv->qos); +			break; +		} +		case IFLA_VF_TX_RATE: { +			struct ifla_vf_tx_rate *ivt; +			ivt = nla_data(vf); +			err = -EOPNOTSUPP; +			if (ops->ndo_set_vf_tx_rate) +				err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, +							      ivt->rate); +			break; +		} +		default: +			err = -EINVAL; +			break; +		} +		if (err) +			break; +	} +	return err; +} +  static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,  		      struct nlattr **tb, char *ifname, int modified)  { @@ -942,40 +1026,17 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,  		write_unlock_bh(&dev_base_lock);  	} -	if (tb[IFLA_VF_MAC]) { -		struct ifla_vf_mac *ivm; -		ivm = nla_data(tb[IFLA_VF_MAC]); -		err = -EOPNOTSUPP; -		if (ops->ndo_set_vf_mac) -			err = ops->ndo_set_vf_mac(dev, ivm->vf, ivm->mac); -		if (err < 0) -			goto errout; -		modified = 1; -	} - -	if (tb[IFLA_VF_VLAN]) { -		struct ifla_vf_vlan *ivv; -		ivv = nla_data(tb[IFLA_VF_VLAN]); -		err = -EOPNOTSUPP; -		if (ops->ndo_set_vf_vlan) -			err = ops->ndo_set_vf_vlan(dev, ivv->vf, -						   ivv->vlan, -						   ivv->qos); -		if (err < 0) -			goto errout; -		modified = 1; -	} -	err = 0; - -	if (tb[IFLA_VF_TX_RATE]) { -		struct ifla_vf_tx_rate *ivt; -		ivt = nla_data(tb[IFLA_VF_TX_RATE]); -		err = -EOPNOTSUPP; -		if (ops->ndo_set_vf_tx_rate) -			err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, ivt->rate); -		if (err < 0) -			goto errout; -		modified = 1; +	if (tb[IFLA_VFINFO_LIST]) { +		struct nlattr *attr; +		int rem; +		nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) { +			if (nla_type(attr) != IFLA_VF_INFO) +				goto errout; +			err = do_setvfinfo(dev, attr); +			if (err < 0) +				goto errout; +			modified = 1; +		}  	}  	err = 0; @@ -1270,10 +1331,11 @@ replay:  			err = ops->newlink(net, dev, tb, data);  		else  			err = register_netdevice(dev); -		if (err < 0 && !IS_ERR(dev)) { + +		if (err < 0 && !IS_ERR(dev))  			free_netdev(dev); +		if (err < 0)  			goto out; -		}  		err = rtnl_configure_link(dev, ifm);  		if (err < 0) diff --git a/net/core/scm.c b/net/core/scm.c index 9b264634acf..b88f6f9d0b9 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -26,6 +26,7 @@  #include <linux/security.h>  #include <linux/pid.h>  #include <linux/nsproxy.h> +#include <linux/slab.h>  #include <asm/system.h>  #include <asm/uaccess.h> diff --git a/net/core/sock.c b/net/core/sock.c index fcd397a762f..c5812bbc2cc 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -340,8 +340,12 @@ int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested)  		rc = sk_backlog_rcv(sk, skb);  		mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_); -	} else -		sk_add_backlog(sk, skb); +	} else if (sk_add_backlog(sk, skb)) { +		bh_unlock_sock(sk); +		atomic_inc(&sk->sk_drops); +		goto discard_and_relse; +	} +  	bh_unlock_sock(sk);  out:  	sock_put(sk); @@ -1139,6 +1143,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)  		sock_lock_init(newsk);  		bh_lock_sock(newsk);  		newsk->sk_backlog.head	= newsk->sk_backlog.tail = NULL; +		newsk->sk_backlog.len = 0;  		atomic_set(&newsk->sk_rmem_alloc, 0);  		/* @@ -1542,6 +1547,12 @@ static void __release_sock(struct sock *sk)  		bh_lock_sock(sk);  	} while ((skb = sk->sk_backlog.head) != NULL); + +	/* +	 * Doing the zeroing here guarantee we can not loop forever +	 * while a wild producer attempts to flood us. +	 */ +	sk->sk_backlog.len = 0;  }  /** @@ -1874,6 +1885,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)  	sk->sk_allocation	=	GFP_KERNEL;  	sk->sk_rcvbuf		=	sysctl_rmem_default;  	sk->sk_sndbuf		=	sysctl_wmem_default; +	sk->sk_backlog.limit	=	sk->sk_rcvbuf << 1;  	sk->sk_state		=	TCP_CLOSE;  	sk_set_socket(sk, sock); @@ -2276,7 +2288,8 @@ out_free_request_sock_slab:  		prot->rsk_prot->slab = NULL;  	}  out_free_request_sock_slab_name: -	kfree(prot->rsk_prot->slab_name); +	if (prot->rsk_prot) +		kfree(prot->rsk_prot->slab_name);  out_free_sock_slab:  	kmem_cache_destroy(prot->slab);  	prot->slab = NULL; diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 06124872af5..b7b6b8208f7 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -12,6 +12,7 @@  #include <linux/netdevice.h>  #include <linux/ratelimit.h>  #include <linux/init.h> +#include <linux/slab.h>  #include <net/ip.h>  #include <net/sock.h>  |