diff options
| author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-03-30 14:04:53 +1100 | 
|---|---|---|
| committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-03-30 14:04:53 +1100 | 
| commit | 9ff9a26b786c35ee8d2a66222924a807ec851a9f (patch) | |
| tree | db432a17bccca1ca2c16907f0ee83ac449ed4012 /net/core/ethtool.c | |
| parent | 0a3108beea9143225119d5e7c72a8e2c64f3eb7d (diff) | |
| parent | 0d34fb8e93ceba7b6dad0062dbb4a0813bacd75b (diff) | |
Merge commit 'origin/master' into next
Manual merge of:
	arch/powerpc/include/asm/elf.h
	drivers/i2c/busses/i2c-mpc.c
Diffstat (limited to 'net/core/ethtool.c')
| -rw-r--r-- | net/core/ethtool.c | 58 | 
1 files changed, 48 insertions, 10 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 947710a36ce..244ca56dffa 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -209,34 +209,62 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)  	return 0;  } -static int ethtool_set_rxhash(struct net_device *dev, void __user *useraddr) +static int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)  {  	struct ethtool_rxnfc cmd; -	if (!dev->ethtool_ops->set_rxhash) +	if (!dev->ethtool_ops->set_rxnfc)  		return -EOPNOTSUPP;  	if (copy_from_user(&cmd, useraddr, sizeof(cmd)))  		return -EFAULT; -	return dev->ethtool_ops->set_rxhash(dev, &cmd); +	return dev->ethtool_ops->set_rxnfc(dev, &cmd);  } -static int ethtool_get_rxhash(struct net_device *dev, void __user *useraddr) +static int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)  {  	struct ethtool_rxnfc info; +	const struct ethtool_ops *ops = dev->ethtool_ops; +	int ret; +	void *rule_buf = NULL; -	if (!dev->ethtool_ops->get_rxhash) +	if (!ops->get_rxnfc)  		return -EOPNOTSUPP;  	if (copy_from_user(&info, useraddr, sizeof(info)))  		return -EFAULT; -	dev->ethtool_ops->get_rxhash(dev, &info); +	if (info.cmd == ETHTOOL_GRXCLSRLALL) { +		if (info.rule_cnt > 0) { +			rule_buf = kmalloc(info.rule_cnt * sizeof(u32), +					   GFP_USER); +			if (!rule_buf) +				return -ENOMEM; +		} +	} +	ret = ops->get_rxnfc(dev, &info, rule_buf); +	if (ret < 0) +		goto err_out; + +	ret = -EFAULT;  	if (copy_to_user(useraddr, &info, sizeof(info))) -		return -EFAULT; -	return 0; +		goto err_out; + +	if (rule_buf) { +		useraddr += offsetof(struct ethtool_rxnfc, rule_locs); +		if (copy_to_user(useraddr, rule_buf, +				 info.rule_cnt * sizeof(u32))) +			goto err_out; +	} +	ret = 0; + +err_out: +	if (rule_buf) +		kfree(rule_buf); + +	return ret;  }  static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) @@ -901,6 +929,10 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)  	case ETHTOOL_GFLAGS:  	case ETHTOOL_GPFLAGS:  	case ETHTOOL_GRXFH: +	case ETHTOOL_GRXRINGS: +	case ETHTOOL_GRXCLSRLCNT: +	case ETHTOOL_GRXCLSRULE: +	case ETHTOOL_GRXCLSRLALL:  		break;  	default:  		if (!capable(CAP_NET_ADMIN)) @@ -1052,10 +1084,16 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)  				       dev->ethtool_ops->set_priv_flags);  		break;  	case ETHTOOL_GRXFH: -		rc = ethtool_get_rxhash(dev, useraddr); +	case ETHTOOL_GRXRINGS: +	case ETHTOOL_GRXCLSRLCNT: +	case ETHTOOL_GRXCLSRULE: +	case ETHTOOL_GRXCLSRLALL: +		rc = ethtool_get_rxnfc(dev, useraddr);  		break;  	case ETHTOOL_SRXFH: -		rc = ethtool_set_rxhash(dev, useraddr); +	case ETHTOOL_SRXCLSRLDEL: +	case ETHTOOL_SRXCLSRLINS: +		rc = ethtool_set_rxnfc(dev, useraddr);  		break;  	case ETHTOOL_GGRO:  		rc = ethtool_get_gro(dev, useraddr);  | 
