diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2011-12-15 08:55:01 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-16 13:52:47 -0500 |
commit | 7850f63f1620512631445b901ae11cd149e7375c (patch) | |
tree | d26a5f049dcf3634c4bf9e1b86915d201fab3836 /drivers | |
parent | 14596f7006297b67516e2b6a2b26bcb11fe08fb3 (diff) |
ethtool: Centralise validation of ETHTOOL_{G, S}RXFHINDIR parameters
Add a new ethtool operation (get_rxfh_indir_size) to get the
indirectional table size. Use this to validate the user buffer size
before calling get_rxfh_indir or set_rxfh_indir. Use get_rxnfc to get
the number of RX rings, and validate the contents of the new
indirection table before calling set_rxfh_indir. Remove this
validation from drivers.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Acked-by: Dimitris Michailidis <dm@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 39 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 27 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ethtool.c | 35 | ||||
-rw-r--r-- | drivers/net/vmxnet3/vmxnet3_ethtool.c | 35 |
4 files changed, 55 insertions, 81 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 90d44af85600..a688b9d975a2 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | |||
@@ -2302,18 +2302,20 @@ static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, | |||
2302 | } | 2302 | } |
2303 | } | 2303 | } |
2304 | 2304 | ||
2305 | static int bnx2x_get_rxfh_indir(struct net_device *dev, | 2305 | static u32 bnx2x_get_rxfh_indir_size(struct net_device *dev) |
2306 | struct ethtool_rxfh_indir *indir) | 2306 | { |
2307 | struct bnx2x *bp = netdev_priv(dev); | ||
2308 | |||
2309 | return (bp->multi_mode == ETH_RSS_MODE_DISABLED ? | ||
2310 | 0 : T_ETH_INDIRECTION_TABLE_SIZE); | ||
2311 | } | ||
2312 | |||
2313 | static int bnx2x_get_rxfh_indir(struct net_device *dev, u32 *indir) | ||
2307 | { | 2314 | { |
2308 | struct bnx2x *bp = netdev_priv(dev); | 2315 | struct bnx2x *bp = netdev_priv(dev); |
2309 | size_t copy_size = | ||
2310 | min_t(size_t, indir->size, T_ETH_INDIRECTION_TABLE_SIZE); | ||
2311 | u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; | 2316 | u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; |
2312 | size_t i; | 2317 | size_t i; |
2313 | 2318 | ||
2314 | if (bp->multi_mode == ETH_RSS_MODE_DISABLED) | ||
2315 | return -EOPNOTSUPP; | ||
2316 | |||
2317 | /* Get the current configuration of the RSS indirection table */ | 2319 | /* Get the current configuration of the RSS indirection table */ |
2318 | bnx2x_get_rss_ind_table(&bp->rss_conf_obj, ind_table); | 2320 | bnx2x_get_rss_ind_table(&bp->rss_conf_obj, ind_table); |
2319 | 2321 | ||
@@ -2326,33 +2328,19 @@ static int bnx2x_get_rxfh_indir(struct net_device *dev, | |||
2326 | * align the returned table to the Client ID of the leading RSS | 2328 | * align the returned table to the Client ID of the leading RSS |
2327 | * queue. | 2329 | * queue. |
2328 | */ | 2330 | */ |
2329 | for (i = 0; i < copy_size; i++) | 2331 | for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) |
2330 | indir->ring_index[i] = ind_table[i] - bp->fp->cl_id; | 2332 | indir[i] = ind_table[i] - bp->fp->cl_id; |
2331 | |||
2332 | indir->size = T_ETH_INDIRECTION_TABLE_SIZE; | ||
2333 | 2333 | ||
2334 | return 0; | 2334 | return 0; |
2335 | } | 2335 | } |
2336 | 2336 | ||
2337 | static int bnx2x_set_rxfh_indir(struct net_device *dev, | 2337 | static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir) |
2338 | const struct ethtool_rxfh_indir *indir) | ||
2339 | { | 2338 | { |
2340 | struct bnx2x *bp = netdev_priv(dev); | 2339 | struct bnx2x *bp = netdev_priv(dev); |
2341 | size_t i; | 2340 | size_t i; |
2342 | u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; | 2341 | u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; |
2343 | u32 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp); | ||
2344 | |||
2345 | if (bp->multi_mode == ETH_RSS_MODE_DISABLED) | ||
2346 | return -EOPNOTSUPP; | ||
2347 | |||
2348 | /* validate the size */ | ||
2349 | if (indir->size != T_ETH_INDIRECTION_TABLE_SIZE) | ||
2350 | return -EINVAL; | ||
2351 | 2342 | ||
2352 | for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { | 2343 | for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { |
2353 | /* validate the indices */ | ||
2354 | if (indir->ring_index[i] >= num_eth_queues) | ||
2355 | return -EINVAL; | ||
2356 | /* | 2344 | /* |
2357 | * The same as in bnx2x_get_rxfh_indir: we can't use a memcpy() | 2345 | * The same as in bnx2x_get_rxfh_indir: we can't use a memcpy() |
2358 | * as an internal storage of an indirection table is a u8 array | 2346 | * as an internal storage of an indirection table is a u8 array |
@@ -2362,7 +2350,7 @@ static int bnx2x_set_rxfh_indir(struct net_device *dev, | |||
2362 | * align the received table to the Client ID of the leading RSS | 2350 | * align the received table to the Client ID of the leading RSS |
2363 | * queue | 2351 | * queue |
2364 | */ | 2352 | */ |
2365 | ind_table[i] = indir->ring_index[i] + bp->fp->cl_id; | 2353 | ind_table[i] = indir[i] + bp->fp->cl_id; |
2366 | } | 2354 | } |
2367 | 2355 | ||
2368 | return bnx2x_config_rss_pf(bp, ind_table, false); | 2356 | return bnx2x_config_rss_pf(bp, ind_table, false); |
@@ -2395,6 +2383,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { | |||
2395 | .set_phys_id = bnx2x_set_phys_id, | 2383 | .set_phys_id = bnx2x_set_phys_id, |
2396 | .get_ethtool_stats = bnx2x_get_ethtool_stats, | 2384 | .get_ethtool_stats = bnx2x_get_ethtool_stats, |
2397 | .get_rxnfc = bnx2x_get_rxnfc, | 2385 | .get_rxnfc = bnx2x_get_rxnfc, |
2386 | .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, | ||
2398 | .get_rxfh_indir = bnx2x_get_rxfh_indir, | 2387 | .get_rxfh_indir = bnx2x_get_rxfh_indir, |
2399 | .set_rxfh_indir = bnx2x_set_rxfh_indir, | 2388 | .set_rxfh_indir = bnx2x_set_rxfh_indir, |
2400 | }; | 2389 | }; |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index a34e7ce7e214..8ffd55bdef3d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |||
@@ -1871,30 +1871,30 @@ static int cxgb_set_features(struct net_device *dev, netdev_features_t features) | |||
1871 | return err; | 1871 | return err; |
1872 | } | 1872 | } |
1873 | 1873 | ||
1874 | static int get_rss_table(struct net_device *dev, struct ethtool_rxfh_indir *p) | 1874 | static u32 get_rss_table_size(struct net_device *dev) |
1875 | { | 1875 | { |
1876 | const struct port_info *pi = netdev_priv(dev); | 1876 | const struct port_info *pi = netdev_priv(dev); |
1877 | unsigned int n = min_t(unsigned int, p->size, pi->rss_size); | ||
1878 | 1877 | ||
1879 | p->size = pi->rss_size; | 1878 | return pi->rss_size; |
1879 | } | ||
1880 | |||
1881 | static int get_rss_table(struct net_device *dev, u32 *p) | ||
1882 | { | ||
1883 | const struct port_info *pi = netdev_priv(dev); | ||
1884 | unsigned int n = pi->rss_size; | ||
1885 | |||
1880 | while (n--) | 1886 | while (n--) |
1881 | p->ring_index[n] = pi->rss[n]; | 1887 | p[n] = pi->rss[n]; |
1882 | return 0; | 1888 | return 0; |
1883 | } | 1889 | } |
1884 | 1890 | ||
1885 | static int set_rss_table(struct net_device *dev, | 1891 | static int set_rss_table(struct net_device *dev, const u32 *p) |
1886 | const struct ethtool_rxfh_indir *p) | ||
1887 | { | 1892 | { |
1888 | unsigned int i; | 1893 | unsigned int i; |
1889 | struct port_info *pi = netdev_priv(dev); | 1894 | struct port_info *pi = netdev_priv(dev); |
1890 | 1895 | ||
1891 | if (p->size != pi->rss_size) | 1896 | for (i = 0; i < pi->rss_size; i++) |
1892 | return -EINVAL; | 1897 | pi->rss[i] = p[i]; |
1893 | for (i = 0; i < p->size; i++) | ||
1894 | if (p->ring_index[i] >= pi->nqsets) | ||
1895 | return -EINVAL; | ||
1896 | for (i = 0; i < p->size; i++) | ||
1897 | pi->rss[i] = p->ring_index[i]; | ||
1898 | if (pi->adapter->flags & FULL_INIT_DONE) | 1898 | if (pi->adapter->flags & FULL_INIT_DONE) |
1899 | return write_rss(pi, pi->rss); | 1899 | return write_rss(pi, pi->rss); |
1900 | return 0; | 1900 | return 0; |
@@ -1989,6 +1989,7 @@ static struct ethtool_ops cxgb_ethtool_ops = { | |||
1989 | .get_wol = get_wol, | 1989 | .get_wol = get_wol, |
1990 | .set_wol = set_wol, | 1990 | .set_wol = set_wol, |
1991 | .get_rxnfc = get_rxnfc, | 1991 | .get_rxnfc = get_rxnfc, |
1992 | .get_rxfh_indir_size = get_rss_table_size, | ||
1992 | .get_rxfh_indir = get_rss_table, | 1993 | .get_rxfh_indir = get_rss_table, |
1993 | .set_rxfh_indir = set_rss_table, | 1994 | .set_rxfh_indir = set_rss_table, |
1994 | .flash_device = set_flash, | 1995 | .flash_device = set_flash, |
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index f3cd96dfa398..1be51b2bfa42 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c | |||
@@ -956,40 +956,28 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, | |||
956 | return rc < 0 ? rc : 0; | 956 | return rc < 0 ? rc : 0; |
957 | } | 957 | } |
958 | 958 | ||
959 | static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, | 959 | static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev) |
960 | struct ethtool_rxfh_indir *indir) | ||
961 | { | 960 | { |
962 | struct efx_nic *efx = netdev_priv(net_dev); | 961 | struct efx_nic *efx = netdev_priv(net_dev); |
963 | size_t copy_size = | ||
964 | min_t(size_t, indir->size, ARRAY_SIZE(efx->rx_indir_table)); | ||
965 | 962 | ||
966 | if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) | 963 | return (efx_nic_rev(efx) < EFX_REV_FALCON_B0 ? |
967 | return -EOPNOTSUPP; | 964 | 0 : ARRAY_SIZE(efx->rx_indir_table)); |
965 | } | ||
966 | |||
967 | static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir) | ||
968 | { | ||
969 | struct efx_nic *efx = netdev_priv(net_dev); | ||
968 | 970 | ||
969 | indir->size = ARRAY_SIZE(efx->rx_indir_table); | 971 | memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table)); |
970 | memcpy(indir->ring_index, efx->rx_indir_table, | ||
971 | copy_size * sizeof(indir->ring_index[0])); | ||
972 | return 0; | 972 | return 0; |
973 | } | 973 | } |
974 | 974 | ||
975 | static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, | 975 | static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, |
976 | const struct ethtool_rxfh_indir *indir) | 976 | const u32 *indir) |
977 | { | 977 | { |
978 | struct efx_nic *efx = netdev_priv(net_dev); | 978 | struct efx_nic *efx = netdev_priv(net_dev); |
979 | size_t i; | ||
980 | |||
981 | if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) | ||
982 | return -EOPNOTSUPP; | ||
983 | |||
984 | /* Validate size and indices */ | ||
985 | if (indir->size != ARRAY_SIZE(efx->rx_indir_table)) | ||
986 | return -EINVAL; | ||
987 | for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) | ||
988 | if (indir->ring_index[i] >= efx->n_rx_channels) | ||
989 | return -EINVAL; | ||
990 | 979 | ||
991 | memcpy(efx->rx_indir_table, indir->ring_index, | 980 | memcpy(efx->rx_indir_table, indir, sizeof(efx->rx_indir_table)); |
992 | sizeof(efx->rx_indir_table)); | ||
993 | efx_nic_push_rx_indir_table(efx); | 981 | efx_nic_push_rx_indir_table(efx); |
994 | return 0; | 982 | return 0; |
995 | } | 983 | } |
@@ -1020,6 +1008,7 @@ const struct ethtool_ops efx_ethtool_ops = { | |||
1020 | .reset = efx_ethtool_reset, | 1008 | .reset = efx_ethtool_reset, |
1021 | .get_rxnfc = efx_ethtool_get_rxnfc, | 1009 | .get_rxnfc = efx_ethtool_get_rxnfc, |
1022 | .set_rx_ntuple = efx_ethtool_set_rx_ntuple, | 1010 | .set_rx_ntuple = efx_ethtool_set_rx_ntuple, |
1011 | .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, | ||
1023 | .get_rxfh_indir = efx_ethtool_get_rxfh_indir, | 1012 | .get_rxfh_indir = efx_ethtool_get_rxfh_indir, |
1024 | .set_rxfh_indir = efx_ethtool_set_rxfh_indir, | 1013 | .set_rxfh_indir = efx_ethtool_set_rxfh_indir, |
1025 | }; | 1014 | }; |
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index b492ee1e5f17..a3eb75a62ea9 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c | |||
@@ -565,44 +565,38 @@ vmxnet3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info, | |||
565 | } | 565 | } |
566 | 566 | ||
567 | #ifdef VMXNET3_RSS | 567 | #ifdef VMXNET3_RSS |
568 | static u32 | ||
569 | vmxnet3_get_rss_indir_size(struct net_device *netdev) | ||
570 | { | ||
571 | struct vmxnet3_adapter *adapter = netdev_priv(netdev); | ||
572 | struct UPT1_RSSConf *rssConf = adapter->rss_conf; | ||
573 | |||
574 | return rssConf->indTableSize; | ||
575 | } | ||
576 | |||
568 | static int | 577 | static int |
569 | vmxnet3_get_rss_indir(struct net_device *netdev, | 578 | vmxnet3_get_rss_indir(struct net_device *netdev, u32 *p) |
570 | struct ethtool_rxfh_indir *p) | ||
571 | { | 579 | { |
572 | struct vmxnet3_adapter *adapter = netdev_priv(netdev); | 580 | struct vmxnet3_adapter *adapter = netdev_priv(netdev); |
573 | struct UPT1_RSSConf *rssConf = adapter->rss_conf; | 581 | struct UPT1_RSSConf *rssConf = adapter->rss_conf; |
574 | unsigned int n = min_t(unsigned int, p->size, rssConf->indTableSize); | 582 | unsigned int n = rssConf->indTableSize; |
575 | 583 | ||
576 | p->size = rssConf->indTableSize; | ||
577 | while (n--) | 584 | while (n--) |
578 | p->ring_index[n] = rssConf->indTable[n]; | 585 | p[n] = rssConf->indTable[n]; |
579 | return 0; | 586 | return 0; |
580 | 587 | ||
581 | } | 588 | } |
582 | 589 | ||
583 | static int | 590 | static int |
584 | vmxnet3_set_rss_indir(struct net_device *netdev, | 591 | vmxnet3_set_rss_indir(struct net_device *netdev, const u32 *p) |
585 | const struct ethtool_rxfh_indir *p) | ||
586 | { | 592 | { |
587 | unsigned int i; | 593 | unsigned int i; |
588 | unsigned long flags; | 594 | unsigned long flags; |
589 | struct vmxnet3_adapter *adapter = netdev_priv(netdev); | 595 | struct vmxnet3_adapter *adapter = netdev_priv(netdev); |
590 | struct UPT1_RSSConf *rssConf = adapter->rss_conf; | 596 | struct UPT1_RSSConf *rssConf = adapter->rss_conf; |
591 | 597 | ||
592 | if (p->size != rssConf->indTableSize) | ||
593 | return -EINVAL; | ||
594 | for (i = 0; i < rssConf->indTableSize; i++) { | ||
595 | /* | ||
596 | * Return with error code if any of the queue indices | ||
597 | * is out of range | ||
598 | */ | ||
599 | if (p->ring_index[i] < 0 || | ||
600 | p->ring_index[i] >= adapter->num_rx_queues) | ||
601 | return -EINVAL; | ||
602 | } | ||
603 | |||
604 | for (i = 0; i < rssConf->indTableSize; i++) | 598 | for (i = 0; i < rssConf->indTableSize; i++) |
605 | rssConf->indTable[i] = p->ring_index[i]; | 599 | rssConf->indTable[i] = p[i]; |
606 | 600 | ||
607 | spin_lock_irqsave(&adapter->cmd_lock, flags); | 601 | spin_lock_irqsave(&adapter->cmd_lock, flags); |
608 | VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, | 602 | VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, |
@@ -629,6 +623,7 @@ static struct ethtool_ops vmxnet3_ethtool_ops = { | |||
629 | .set_ringparam = vmxnet3_set_ringparam, | 623 | .set_ringparam = vmxnet3_set_ringparam, |
630 | .get_rxnfc = vmxnet3_get_rxnfc, | 624 | .get_rxnfc = vmxnet3_get_rxnfc, |
631 | #ifdef VMXNET3_RSS | 625 | #ifdef VMXNET3_RSS |
626 | .get_rxfh_indir_size = vmxnet3_get_rss_indir_size, | ||
632 | .get_rxfh_indir = vmxnet3_get_rss_indir, | 627 | .get_rxfh_indir = vmxnet3_get_rss_indir, |
633 | .set_rxfh_indir = vmxnet3_set_rss_indir, | 628 | .set_rxfh_indir = vmxnet3_set_rss_indir, |
634 | #endif | 629 | #endif |