diff options
author | Michał Mirosław <mirq-linux@rere.qmqm.pl> | 2011-02-15 16:59:18 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-02-17 14:16:34 -0800 |
commit | da8ac86c4a56a14bf8deea7d2f92d0a453c67f91 (patch) | |
tree | 9ccb11cb01f7917240efe014cae22f5ff3ce9d43 /net | |
parent | 86794881c29a7ea6271644b49ad81518cabda96b (diff) | |
download | linux-stable-da8ac86c4a56a14bf8deea7d2f92d0a453c67f91.tar.gz linux-stable-da8ac86c4a56a14bf8deea7d2f92d0a453c67f91.tar.bz2 linux-stable-da8ac86c4a56a14bf8deea7d2f92d0a453c67f91.zip |
net: use ndo_fix_features for ethtool_ops->set_flags
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/ethtool.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 65999974f743..65b3d50a6df2 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -427,6 +427,34 @@ static int ethtool_set_one_feature(struct net_device *dev, } } +static int __ethtool_set_flags(struct net_device *dev, u32 data) +{ + u32 changed; + + if (data & ~flags_dup_features) + return -EINVAL; + + /* legacy set_flags() op */ + if (dev->ethtool_ops->set_flags) { + if (unlikely(dev->hw_features & flags_dup_features)) + netdev_warn(dev, + "driver BUG: mixed hw_features and set_flags()\n"); + return dev->ethtool_ops->set_flags(dev, data); + } + + /* allow changing only bits set in hw_features */ + changed = (data ^ dev->wanted_features) & flags_dup_features; + if (changed & ~dev->hw_features) + return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP; + + dev->wanted_features = + (dev->wanted_features & ~changed) | data; + + netdev_update_features(dev); + + return 0; +} + static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) { struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; @@ -1768,8 +1796,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) ethtool_op_get_flags)); break; case ETHTOOL_SFLAGS: - rc = ethtool_set_value(dev, useraddr, - dev->ethtool_ops->set_flags); + rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags); break; case ETHTOOL_GPFLAGS: rc = ethtool_get_value(dev, useraddr, ethcmd, |