aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2010-06-29 22:44:32 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-30 17:09:35 -0400
commit1437ce3983bcbc0447a0dedcd644c14fe833d266 (patch)
tree073ba0dc60127b08b65fbcca4d0d7c15318c08f8
parentb3003be36a3c9215cd17182349981581de269048 (diff)
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: 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>
-rw-r--r--drivers/net/cxgb4/cxgb4_main.c9
-rw-r--r--drivers/net/enic/enic_main.c1
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c5
-rw-r--r--drivers/net/mv643xx_eth.c7
-rw-r--r--drivers/net/myri10ge/myri10ge.c10
-rw-r--r--drivers/net/niu.c9
-rw-r--r--drivers/net/sfc/ethtool.c5
-rw-r--r--drivers/net/sky2.c16
-rw-r--r--include/linux/ethtool.h2
-rw-r--r--net/core/ethtool.c28
10 files changed, 32 insertions, 60 deletions
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 65281674de91..55a720e4abdc 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -1799,14 +1799,7 @@ static int set_tso(struct net_device *dev, u32 value)
1799 1799
1800static int set_flags(struct net_device *dev, u32 flags) 1800static int set_flags(struct net_device *dev, u32 flags)
1801{ 1801{
1802 if (flags & ~ETH_FLAG_RXHASH) 1802 return ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH);
1803 return -EOPNOTSUPP;
1804
1805 if (flags & ETH_FLAG_RXHASH)
1806 dev->features |= NETIF_F_RXHASH;
1807 else
1808 dev->features &= ~NETIF_F_RXHASH;
1809 return 0;
1810} 1803}
1811 1804
1812static struct ethtool_ops cxgb_ethtool_ops = { 1805static struct ethtool_ops cxgb_ethtool_ops = {
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 6c6795b90fa6..77a7f87d498e 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -365,7 +365,6 @@ static const struct ethtool_ops enic_ethtool_ops = {
365 .get_coalesce = enic_get_coalesce, 365 .get_coalesce = enic_get_coalesce,
366 .set_coalesce = enic_set_coalesce, 366 .set_coalesce = enic_set_coalesce,
367 .get_flags = ethtool_op_get_flags, 367 .get_flags = ethtool_op_get_flags,
368 .set_flags = ethtool_op_set_flags,
369}; 368};
370 369
371static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) 370static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 873b45efca40..7d2e5ea2deba 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -2205,8 +2205,11 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
2205{ 2205{
2206 struct ixgbe_adapter *adapter = netdev_priv(netdev); 2206 struct ixgbe_adapter *adapter = netdev_priv(netdev);
2207 bool need_reset = false; 2207 bool need_reset = false;
2208 int rc;
2208 2209
2209 ethtool_op_set_flags(netdev, data); 2210 rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO | ETH_FLAG_NTUPLE);
2211 if (rc)
2212 return rc;
2210 2213
2211 /* if state changes we need to update adapter->flags and reset */ 2214 /* if state changes we need to update adapter->flags and reset */
2212 if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) { 2215 if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) {
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index e345ec8cb473..82b720f29c75 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1636,6 +1636,11 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev,
1636 } 1636 }
1637} 1637}
1638 1638
1639static int mv643xx_eth_set_flags(struct net_device *dev, u32 data)
1640{
1641 return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO);
1642}
1643
1639static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset) 1644static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset)
1640{ 1645{
1641 if (sset == ETH_SS_STATS) 1646 if (sset == ETH_SS_STATS)
@@ -1661,7 +1666,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = {
1661 .get_strings = mv643xx_eth_get_strings, 1666 .get_strings = mv643xx_eth_get_strings,
1662 .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, 1667 .get_ethtool_stats = mv643xx_eth_get_ethtool_stats,
1663 .get_flags = ethtool_op_get_flags, 1668 .get_flags = ethtool_op_get_flags,
1664 .set_flags = ethtool_op_set_flags, 1669 .set_flags = mv643xx_eth_set_flags,
1665 .get_sset_count = mv643xx_eth_get_sset_count, 1670 .get_sset_count = mv643xx_eth_get_sset_count,
1666}; 1671};
1667 1672
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index e0b47cc8a86e..d771d1650d60 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1730,8 +1730,7 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
1730 if (csum_enabled) 1730 if (csum_enabled)
1731 mgp->csum_flag = MXGEFW_FLAGS_CKSUM; 1731 mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
1732 else { 1732 else {
1733 u32 flags = ethtool_op_get_flags(netdev); 1733 netdev->features &= ~NETIF_F_LRO;
1734 err = ethtool_op_set_flags(netdev, (flags & ~ETH_FLAG_LRO));
1735 mgp->csum_flag = 0; 1734 mgp->csum_flag = 0;
1736 1735
1737 } 1736 }
@@ -1900,6 +1899,11 @@ static u32 myri10ge_get_msglevel(struct net_device *netdev)
1900 return mgp->msg_enable; 1899 return mgp->msg_enable;
1901} 1900}
1902 1901
1902static int myri10ge_set_flags(struct net_device *netdev, u32 value)
1903{
1904 return ethtool_op_set_flags(netdev, value, ETH_FLAG_LRO);
1905}
1906
1903static const struct ethtool_ops myri10ge_ethtool_ops = { 1907static const struct ethtool_ops myri10ge_ethtool_ops = {
1904 .get_settings = myri10ge_get_settings, 1908 .get_settings = myri10ge_get_settings,
1905 .get_drvinfo = myri10ge_get_drvinfo, 1909 .get_drvinfo = myri10ge_get_drvinfo,
@@ -1920,7 +1924,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
1920 .set_msglevel = myri10ge_set_msglevel, 1924 .set_msglevel = myri10ge_set_msglevel,
1921 .get_msglevel = myri10ge_get_msglevel, 1925 .get_msglevel = myri10ge_get_msglevel,
1922 .get_flags = ethtool_op_get_flags, 1926 .get_flags = ethtool_op_get_flags,
1923 .set_flags = ethtool_op_set_flags 1927 .set_flags = myri10ge_set_flags
1924}; 1928};
1925 1929
1926static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) 1930static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 63e8e3893bd6..3d523cb7975a 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -7920,14 +7920,7 @@ static int niu_phys_id(struct net_device *dev, u32 data)
7920 7920
7921static int niu_set_flags(struct net_device *dev, u32 data) 7921static int niu_set_flags(struct net_device *dev, u32 data)
7922{ 7922{
7923 if (data & (ETH_FLAG_LRO | ETH_FLAG_NTUPLE)) 7923 return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH);
7924 return -EOPNOTSUPP;
7925
7926 if (data & ETH_FLAG_RXHASH)
7927 dev->features |= NETIF_F_RXHASH;
7928 else
7929 dev->features &= ~NETIF_F_RXHASH;
7930 return 0;
7931} 7924}
7932 7925
7933static const struct ethtool_ops niu_ethtool_ops = { 7926static const struct ethtool_ops niu_ethtool_ops = {
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 7693cfbf9cf4..23372bf5cd59 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -551,10 +551,7 @@ static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data)
551 struct efx_nic *efx = netdev_priv(net_dev); 551 struct efx_nic *efx = netdev_priv(net_dev);
552 u32 supported = efx->type->offload_features & ETH_FLAG_RXHASH; 552 u32 supported = efx->type->offload_features & ETH_FLAG_RXHASH;
553 553
554 if (data & ~supported) 554 return ethtool_op_set_flags(net_dev, data, supported);
555 return -EOPNOTSUPP;
556
557 return ethtool_op_set_flags(net_dev, data);
558} 555}
559 556
560static void efx_ethtool_self_test(struct net_device *net_dev, 557static void efx_ethtool_self_test(struct net_device *net_dev,
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 7985165e84fc..c762c6ac055b 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -4188,17 +4188,13 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
4188static int sky2_set_flags(struct net_device *dev, u32 data) 4188static int sky2_set_flags(struct net_device *dev, u32 data)
4189{ 4189{
4190 struct sky2_port *sky2 = netdev_priv(dev); 4190 struct sky2_port *sky2 = netdev_priv(dev);
4191 u32 supported =
4192 (sky2->hw->flags & SKY2_HW_RSS_BROKEN) ? 0 : ETH_FLAG_RXHASH;
4193 int rc;
4191 4194
4192 if (data & ~ETH_FLAG_RXHASH) 4195 rc = ethtool_op_set_flags(dev, data, supported);
4193 return -EOPNOTSUPP; 4196 if (rc)
4194 4197 return rc;
4195 if (data & ETH_FLAG_RXHASH) {
4196 if (sky2->hw->flags & SKY2_HW_RSS_BROKEN)
4197 return -EINVAL;
4198
4199 dev->features |= NETIF_F_RXHASH;
4200 } else
4201 dev->features &= ~NETIF_F_RXHASH;
4202 4198
4203 rx_set_rss(dev); 4199 rx_set_rss(dev);
4204 4200
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 2c8af093d8b3..084ddb3c8032 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -457,7 +457,7 @@ int ethtool_op_set_tso(struct net_device *dev, u32 data);
457u32 ethtool_op_get_ufo(struct net_device *dev); 457u32 ethtool_op_get_ufo(struct net_device *dev);
458int ethtool_op_set_ufo(struct net_device *dev, u32 data); 458int ethtool_op_set_ufo(struct net_device *dev, u32 data);
459u32 ethtool_op_get_flags(struct net_device *dev); 459u32 ethtool_op_get_flags(struct net_device *dev);
460int ethtool_op_set_flags(struct net_device *dev, u32 data); 460int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported);
461void ethtool_ntuple_flush(struct net_device *dev); 461void ethtool_ntuple_flush(struct net_device *dev);
462 462
463/** 463/**
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index a0f4964033d2..5d42fae520d9 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -144,31 +144,13 @@ u32 ethtool_op_get_flags(struct net_device *dev)
144} 144}
145EXPORT_SYMBOL(ethtool_op_get_flags); 145EXPORT_SYMBOL(ethtool_op_get_flags);
146 146
147int ethtool_op_set_flags(struct net_device *dev, u32 data) 147int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
148{ 148{
149 const struct ethtool_ops *ops = dev->ethtool_ops; 149 if (data & ~supported)
150 unsigned long features = dev->features; 150 return -EINVAL;
151
152 if (data & ETH_FLAG_LRO)
153 features |= NETIF_F_LRO;
154 else
155 features &= ~NETIF_F_LRO;
156
157 if (data & ETH_FLAG_NTUPLE) {
158 if (!ops->set_rx_ntuple)
159 return -EOPNOTSUPP;
160 features |= NETIF_F_NTUPLE;
161 } else {
162 /* safe to clear regardless */
163 features &= ~NETIF_F_NTUPLE;
164 }
165
166 if (data & ETH_FLAG_RXHASH)
167 features |= NETIF_F_RXHASH;
168 else
169 features &= ~NETIF_F_RXHASH;
170 151
171 dev->features = features; 152 dev->features = ((dev->features & ~flags_dup_features) |
153 (data & flags_dup_features));
172 return 0; 154 return 0;
173} 155}
174EXPORT_SYMBOL(ethtool_op_set_flags); 156EXPORT_SYMBOL(ethtool_op_set_flags);