Commit 1437ce39 authored by Ben Hutchings's avatar Ben Hutchings Committed by David S. Miller

ethtool: Change ethtool_op_set_flags to validate flags

ethtool_op_set_flags() does not check for unsupported flags, and has
no way of doing so.  This means it is not suitable for use as a
default implementation of ethtool_ops::set_flags.

Add a 'supported' parameter specifying the flags that the driver and
hardware support, validate the requested flags against this, and
change all current callers to pass this parameter.

Change some other trivial implementations of ethtool_ops::set_flags to
call ethtool_op_set_flags().
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Reviewed-by: default avatarStanislaw Gruszka <sgruszka@redhat.com>
Acked-by: default avatarJeff Garzik <jgarzik@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b3003be3
...@@ -1799,14 +1799,7 @@ static int set_tso(struct net_device *dev, u32 value) ...@@ -1799,14 +1799,7 @@ static int set_tso(struct net_device *dev, u32 value)
static int set_flags(struct net_device *dev, u32 flags) static int set_flags(struct net_device *dev, u32 flags)
{ {
if (flags & ~ETH_FLAG_RXHASH) return ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH);
return -EOPNOTSUPP;
if (flags & ETH_FLAG_RXHASH)
dev->features |= NETIF_F_RXHASH;
else
dev->features &= ~NETIF_F_RXHASH;
return 0;
} }
static struct ethtool_ops cxgb_ethtool_ops = { static struct ethtool_ops cxgb_ethtool_ops = {
......
...@@ -365,7 +365,6 @@ static const struct ethtool_ops enic_ethtool_ops = { ...@@ -365,7 +365,6 @@ static const struct ethtool_ops enic_ethtool_ops = {
.get_coalesce = enic_get_coalesce, .get_coalesce = enic_get_coalesce,
.set_coalesce = enic_set_coalesce, .set_coalesce = enic_set_coalesce,
.get_flags = ethtool_op_get_flags, .get_flags = ethtool_op_get_flags,
.set_flags = ethtool_op_set_flags,
}; };
static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
......
...@@ -2205,8 +2205,11 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data) ...@@ -2205,8 +2205,11 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
{ {
struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_adapter *adapter = netdev_priv(netdev);
bool need_reset = false; bool need_reset = false;
int rc;
ethtool_op_set_flags(netdev, data); rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO | ETH_FLAG_NTUPLE);
if (rc)
return rc;
/* if state changes we need to update adapter->flags and reset */ /* if state changes we need to update adapter->flags and reset */
if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) { if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) {
......
...@@ -1636,6 +1636,11 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev, ...@@ -1636,6 +1636,11 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev,
} }
} }
static int mv643xx_eth_set_flags(struct net_device *dev, u32 data)
{
return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO);
}
static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset) static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset)
{ {
if (sset == ETH_SS_STATS) if (sset == ETH_SS_STATS)
...@@ -1661,7 +1666,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { ...@@ -1661,7 +1666,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = {
.get_strings = mv643xx_eth_get_strings, .get_strings = mv643xx_eth_get_strings,
.get_ethtool_stats = mv643xx_eth_get_ethtool_stats, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats,
.get_flags = ethtool_op_get_flags, .get_flags = ethtool_op_get_flags,
.set_flags = ethtool_op_set_flags, .set_flags = mv643xx_eth_set_flags,
.get_sset_count = mv643xx_eth_get_sset_count, .get_sset_count = mv643xx_eth_get_sset_count,
}; };
......
...@@ -1730,8 +1730,7 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled) ...@@ -1730,8 +1730,7 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
if (csum_enabled) if (csum_enabled)
mgp->csum_flag = MXGEFW_FLAGS_CKSUM; mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
else { else {
u32 flags = ethtool_op_get_flags(netdev); netdev->features &= ~NETIF_F_LRO;
err = ethtool_op_set_flags(netdev, (flags & ~ETH_FLAG_LRO));
mgp->csum_flag = 0; mgp->csum_flag = 0;
} }
...@@ -1900,6 +1899,11 @@ static u32 myri10ge_get_msglevel(struct net_device *netdev) ...@@ -1900,6 +1899,11 @@ static u32 myri10ge_get_msglevel(struct net_device *netdev)
return mgp->msg_enable; return mgp->msg_enable;
} }
static int myri10ge_set_flags(struct net_device *netdev, u32 value)
{
return ethtool_op_set_flags(netdev, value, ETH_FLAG_LRO);
}
static const struct ethtool_ops myri10ge_ethtool_ops = { static const struct ethtool_ops myri10ge_ethtool_ops = {
.get_settings = myri10ge_get_settings, .get_settings = myri10ge_get_settings,
.get_drvinfo = myri10ge_get_drvinfo, .get_drvinfo = myri10ge_get_drvinfo,
...@@ -1920,7 +1924,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { ...@@ -1920,7 +1924,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
.set_msglevel = myri10ge_set_msglevel, .set_msglevel = myri10ge_set_msglevel,
.get_msglevel = myri10ge_get_msglevel, .get_msglevel = myri10ge_get_msglevel,
.get_flags = ethtool_op_get_flags, .get_flags = ethtool_op_get_flags,
.set_flags = ethtool_op_set_flags .set_flags = myri10ge_set_flags
}; };
static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
......
...@@ -7920,14 +7920,7 @@ static int niu_phys_id(struct net_device *dev, u32 data) ...@@ -7920,14 +7920,7 @@ static int niu_phys_id(struct net_device *dev, u32 data)
static int niu_set_flags(struct net_device *dev, u32 data) static int niu_set_flags(struct net_device *dev, u32 data)
{ {
if (data & (ETH_FLAG_LRO | ETH_FLAG_NTUPLE)) return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH);
return -EOPNOTSUPP;
if (data & ETH_FLAG_RXHASH)
dev->features |= NETIF_F_RXHASH;
else
dev->features &= ~NETIF_F_RXHASH;
return 0;
} }
static const struct ethtool_ops niu_ethtool_ops = { static const struct ethtool_ops niu_ethtool_ops = {
......
...@@ -551,10 +551,7 @@ static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data) ...@@ -551,10 +551,7 @@ static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data)
struct efx_nic *efx = netdev_priv(net_dev); struct efx_nic *efx = netdev_priv(net_dev);
u32 supported = efx->type->offload_features & ETH_FLAG_RXHASH; u32 supported = efx->type->offload_features & ETH_FLAG_RXHASH;
if (data & ~supported) return ethtool_op_set_flags(net_dev, data, supported);
return -EOPNOTSUPP;
return ethtool_op_set_flags(net_dev, data);
} }
static void efx_ethtool_self_test(struct net_device *net_dev, static void efx_ethtool_self_test(struct net_device *net_dev,
......
...@@ -4188,17 +4188,13 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom ...@@ -4188,17 +4188,13 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
static int sky2_set_flags(struct net_device *dev, u32 data) static int sky2_set_flags(struct net_device *dev, u32 data)
{ {
struct sky2_port *sky2 = netdev_priv(dev); struct sky2_port *sky2 = netdev_priv(dev);
u32 supported =
(sky2->hw->flags & SKY2_HW_RSS_BROKEN) ? 0 : ETH_FLAG_RXHASH;
int rc;
if (data & ~ETH_FLAG_RXHASH) rc = ethtool_op_set_flags(dev, data, supported);
return -EOPNOTSUPP; if (rc)
return rc;
if (data & ETH_FLAG_RXHASH) {
if (sky2->hw->flags & SKY2_HW_RSS_BROKEN)
return -EINVAL;
dev->features |= NETIF_F_RXHASH;
} else
dev->features &= ~NETIF_F_RXHASH;
rx_set_rss(dev); rx_set_rss(dev);
......
...@@ -457,7 +457,7 @@ int ethtool_op_set_tso(struct net_device *dev, u32 data); ...@@ -457,7 +457,7 @@ int ethtool_op_set_tso(struct net_device *dev, u32 data);
u32 ethtool_op_get_ufo(struct net_device *dev); u32 ethtool_op_get_ufo(struct net_device *dev);
int ethtool_op_set_ufo(struct net_device *dev, u32 data); int ethtool_op_set_ufo(struct net_device *dev, u32 data);
u32 ethtool_op_get_flags(struct net_device *dev); u32 ethtool_op_get_flags(struct net_device *dev);
int ethtool_op_set_flags(struct net_device *dev, u32 data); int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported);
void ethtool_ntuple_flush(struct net_device *dev); void ethtool_ntuple_flush(struct net_device *dev);
/** /**
......
...@@ -144,31 +144,13 @@ u32 ethtool_op_get_flags(struct net_device *dev) ...@@ -144,31 +144,13 @@ u32 ethtool_op_get_flags(struct net_device *dev)
} }
EXPORT_SYMBOL(ethtool_op_get_flags); EXPORT_SYMBOL(ethtool_op_get_flags);
int ethtool_op_set_flags(struct net_device *dev, u32 data) int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
{ {
const struct ethtool_ops *ops = dev->ethtool_ops; if (data & ~supported)
unsigned long features = dev->features; return -EINVAL;
if (data & ETH_FLAG_LRO)
features |= NETIF_F_LRO;
else
features &= ~NETIF_F_LRO;
if (data & ETH_FLAG_NTUPLE) {
if (!ops->set_rx_ntuple)
return -EOPNOTSUPP;
features |= NETIF_F_NTUPLE;
} else {
/* safe to clear regardless */
features &= ~NETIF_F_NTUPLE;
}
if (data & ETH_FLAG_RXHASH)
features |= NETIF_F_RXHASH;
else
features &= ~NETIF_F_RXHASH;
dev->features = features; dev->features = ((dev->features & ~flags_dup_features) |
(data & flags_dup_features));
return 0; return 0;
} }
EXPORT_SYMBOL(ethtool_op_set_flags); EXPORT_SYMBOL(ethtool_op_set_flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment