ethtool: Change ethtool_op_set_flags to validate flags
authorBen Hutchings <bhutchings@solarflare.com>
Wed, 30 Jun 2010 02:44:32 +0000 (02:44 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 30 Jun 2010 21:09:35 +0000 (14:09 -0700)
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: Ben Hutchings <bhutchings@solarflare.com>
Reviewed-by: Stanislaw Gruszka <sgruszka@redhat.com>
Acked-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/cxgb4/cxgb4_main.c
drivers/net/enic/enic_main.c
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/mv643xx_eth.c
drivers/net/myri10ge/myri10ge.c
drivers/net/niu.c
drivers/net/sfc/ethtool.c
drivers/net/sky2.c
include/linux/ethtool.h
net/core/ethtool.c

index 65281674de914b3b013608b4c12a0baa34b368a4..55a720e4abdc63301e707b3cbd218b7a7e2c9cec 100644 (file)
@@ -1799,14 +1799,7 @@ static int set_tso(struct net_device *dev, u32 value)
 
 static int set_flags(struct net_device *dev, u32 flags)
 {
-       if (flags & ~ETH_FLAG_RXHASH)
-               return -EOPNOTSUPP;
-
-       if (flags & ETH_FLAG_RXHASH)
-               dev->features |= NETIF_F_RXHASH;
-       else
-               dev->features &= ~NETIF_F_RXHASH;
-       return 0;
+       return ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH);
 }
 
 static struct ethtool_ops cxgb_ethtool_ops = {
index 6c6795b90fa6bb99d18aa6072c9450d21f576817..77a7f87d498e5800fe8e9708d54b34a2e43c6bc0 100644 (file)
@@ -365,7 +365,6 @@ static const struct ethtool_ops enic_ethtool_ops = {
        .get_coalesce = enic_get_coalesce,
        .set_coalesce = enic_set_coalesce,
        .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)
index 873b45efca40f7847e2d317091e0d583a1614fe5..7d2e5ea2deba0bf2e0567076772f740d08a4365e 100644 (file)
@@ -2205,8 +2205,11 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        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 (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) {
index e345ec8cb473cda0d3454d5f2711b08c55fe8bdf..82b720f29c7520bea23f25a37ea4cc0109cff849 100644 (file)
@@ -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)
 {
        if (sset == ETH_SS_STATS)
@@ -1661,7 +1666,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = {
        .get_strings            = mv643xx_eth_get_strings,
        .get_ethtool_stats      = mv643xx_eth_get_ethtool_stats,
        .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,
 };
 
index e0b47cc8a86e7600da43d0cb4915d7e58feb06b4..d771d1650d600c49b308b0106abbc5e6b45eab69 100644 (file)
@@ -1730,8 +1730,7 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
        if (csum_enabled)
                mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
        else {
-               u32 flags = ethtool_op_get_flags(netdev);
-               err = ethtool_op_set_flags(netdev, (flags & ~ETH_FLAG_LRO));
+               netdev->features &= ~NETIF_F_LRO;
                mgp->csum_flag = 0;
 
        }
@@ -1900,6 +1899,11 @@ static u32 myri10ge_get_msglevel(struct net_device *netdev)
        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 = {
        .get_settings = myri10ge_get_settings,
        .get_drvinfo = myri10ge_get_drvinfo,
@@ -1920,7 +1924,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
        .set_msglevel = myri10ge_set_msglevel,
        .get_msglevel = myri10ge_get_msglevel,
        .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)
index 63e8e3893bd6cb9d05ad674a036c1b3f49e82aad..3d523cb7975ac8bb4e847bff1a0521513fc9860d 100644 (file)
@@ -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)
 {
-       if (data & (ETH_FLAG_LRO | ETH_FLAG_NTUPLE))
-               return -EOPNOTSUPP;
-
-       if (data & ETH_FLAG_RXHASH)
-               dev->features |= NETIF_F_RXHASH;
-       else
-               dev->features &= ~NETIF_F_RXHASH;
-       return 0;
+       return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH);
 }
 
 static const struct ethtool_ops niu_ethtool_ops = {
index 7693cfbf9cf4cdca98a62879d18980613ce3778a..23372bf5cd59e33e9bb624c486e446faeeb3ae4c 100644 (file)
@@ -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);
        u32 supported = efx->type->offload_features & ETH_FLAG_RXHASH;
 
-       if (data & ~supported)
-               return -EOPNOTSUPP;
-
-       return ethtool_op_set_flags(net_dev, data);
+       return ethtool_op_set_flags(net_dev, data, supported);
 }
 
 static void efx_ethtool_self_test(struct net_device *net_dev,
index 7985165e84fc4ed6ca6ce5fceb8e60d54dca0b5d..c762c6ac055b119870977e644fdca2d80642a6ae 100644 (file)
@@ -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)
 {
        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)
-               return -EOPNOTSUPP;
-
-       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;
+       rc = ethtool_op_set_flags(dev, data, supported);
+       if (rc)
+               return rc;
 
        rx_set_rss(dev);
 
index 2c8af093d8b3f0cafc5a43d6286b8f7a9426423b..084ddb3c8032bbd7f7b2788f53f0b7ad34d813de 100644 (file)
@@ -457,7 +457,7 @@ int ethtool_op_set_tso(struct net_device *dev, u32 data);
 u32 ethtool_op_get_ufo(struct net_device *dev);
 int ethtool_op_set_ufo(struct net_device *dev, u32 data);
 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);
 
 /**
index a0f4964033d289b8d1b4959d4d1196ccc094bdff..5d42fae520d95b23b3d20d0770d8a1ad5b826ca0 100644 (file)
@@ -144,31 +144,13 @@ u32 ethtool_op_get_flags(struct net_device *dev)
 }
 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;
-       unsigned long features = dev->features;
-
-       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;
+       if (data & ~supported)
+               return -EINVAL;
 
-       dev->features = features;
+       dev->features = ((dev->features & ~flags_dup_features) |
+                        (data & flags_dup_features));
        return 0;
 }
 EXPORT_SYMBOL(ethtool_op_set_flags);