Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'ethtool-rssh-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/net-next

Ben Hutchings says:

====================
Pull request: Fixes for new ethtool RSS commands

This addresses several problems I previously identified with the new
ETHTOOL_{G,S}RSSH commands:

1. Missing validation of reserved parameters
2. Vague documentation
3. Use of unnamed magic number
4. No consolidation with existing driver operations

I don't currently have access to suitable network hardware, but have
tested these changes with a dummy driver that can support various
combinations of operations and sizes, together with (a) Debian's ethtool
3.13 (b) ethtool 3.14 with the submitted patch to use ETHTOOL_{G,S}RSSH
and minor adjustment for fixes 1 and 3.

v2: Update RSS operations in vmxnet3 too
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+122 -131
+8 -7
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
··· 3316 3316 return T_ETH_INDIRECTION_TABLE_SIZE; 3317 3317 } 3318 3318 3319 - static int bnx2x_get_rxfh_indir(struct net_device *dev, u32 *indir) 3319 + static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key) 3320 3320 { 3321 3321 struct bnx2x *bp = netdev_priv(dev); 3322 3322 u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; ··· 3340 3340 return 0; 3341 3341 } 3342 3342 3343 - static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir) 3343 + static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir, 3344 + const u8 *key) 3344 3345 { 3345 3346 struct bnx2x *bp = netdev_priv(dev); 3346 3347 size_t i; 3347 3348 3348 3349 for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { 3349 3350 /* 3350 - * The same as in bnx2x_get_rxfh_indir: we can't use a memcpy() 3351 + * The same as in bnx2x_get_rxfh: we can't use a memcpy() 3351 3352 * as an internal storage of an indirection table is a u8 array 3352 3353 * while indir->ring_index points to an array of u32. 3353 3354 * ··· 3472 3471 .get_rxnfc = bnx2x_get_rxnfc, 3473 3472 .set_rxnfc = bnx2x_set_rxnfc, 3474 3473 .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, 3475 - .get_rxfh_indir = bnx2x_get_rxfh_indir, 3476 - .set_rxfh_indir = bnx2x_set_rxfh_indir, 3474 + .get_rxfh = bnx2x_get_rxfh, 3475 + .set_rxfh = bnx2x_set_rxfh, 3477 3476 .get_channels = bnx2x_get_channels, 3478 3477 .set_channels = bnx2x_set_channels, 3479 3478 .get_module_info = bnx2x_get_module_info, ··· 3499 3498 .get_rxnfc = bnx2x_get_rxnfc, 3500 3499 .set_rxnfc = bnx2x_set_rxnfc, 3501 3500 .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, 3502 - .get_rxfh_indir = bnx2x_get_rxfh_indir, 3503 - .set_rxfh_indir = bnx2x_set_rxfh_indir, 3501 + .get_rxfh = bnx2x_get_rxfh, 3502 + .set_rxfh = bnx2x_set_rxfh, 3504 3503 .get_channels = bnx2x_get_channels, 3505 3504 .set_channels = bnx2x_set_channels, 3506 3505 };
+4 -4
drivers/net/ethernet/broadcom/tg3.c
··· 12532 12532 return size; 12533 12533 } 12534 12534 12535 - static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir) 12535 + static int tg3_get_rxfh(struct net_device *dev, u32 *indir, u8 *key) 12536 12536 { 12537 12537 struct tg3 *tp = netdev_priv(dev); 12538 12538 int i; ··· 12543 12543 return 0; 12544 12544 } 12545 12545 12546 - static int tg3_set_rxfh_indir(struct net_device *dev, const u32 *indir) 12546 + static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key) 12547 12547 { 12548 12548 struct tg3 *tp = netdev_priv(dev); 12549 12549 size_t i; ··· 14075 14075 .get_sset_count = tg3_get_sset_count, 14076 14076 .get_rxnfc = tg3_get_rxnfc, 14077 14077 .get_rxfh_indir_size = tg3_get_rxfh_indir_size, 14078 - .get_rxfh_indir = tg3_get_rxfh_indir, 14079 - .set_rxfh_indir = tg3_set_rxfh_indir, 14078 + .get_rxfh = tg3_get_rxfh, 14079 + .set_rxfh = tg3_set_rxfh, 14080 14080 .get_channels = tg3_get_channels, 14081 14081 .set_channels = tg3_set_channels, 14082 14082 .get_ts_info = tg3_get_ts_info,
+4 -4
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
··· 2739 2739 return pi->rss_size; 2740 2740 } 2741 2741 2742 - static int get_rss_table(struct net_device *dev, u32 *p) 2742 + static int get_rss_table(struct net_device *dev, u32 *p, u8 *key) 2743 2743 { 2744 2744 const struct port_info *pi = netdev_priv(dev); 2745 2745 unsigned int n = pi->rss_size; ··· 2749 2749 return 0; 2750 2750 } 2751 2751 2752 - static int set_rss_table(struct net_device *dev, const u32 *p) 2752 + static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key) 2753 2753 { 2754 2754 unsigned int i; 2755 2755 struct port_info *pi = netdev_priv(dev); ··· 2851 2851 .set_wol = set_wol, 2852 2852 .get_rxnfc = get_rxnfc, 2853 2853 .get_rxfh_indir_size = get_rss_table_size, 2854 - .get_rxfh_indir = get_rss_table, 2855 - .set_rxfh_indir = set_rss_table, 2854 + .get_rxfh = get_rss_table, 2855 + .set_rxfh = set_rss_table, 2856 2856 .flash_device = set_flash, 2857 2857 }; 2858 2858
+1 -1
drivers/net/ethernet/emulex/benet/be_cmds.c
··· 2065 2065 } 2066 2066 2067 2067 int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, 2068 - u32 rss_hash_opts, u16 table_size, u8 *rss_hkey) 2068 + u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey) 2069 2069 { 2070 2070 struct be_mcc_wrb *wrb; 2071 2071 struct be_cmd_req_rss_config *req;
+1 -1
drivers/net/ethernet/emulex/benet/be_cmds.h
··· 2082 2082 u32 *function_mode, u32 *function_caps, u16 *asic_rev); 2083 2083 int be_cmd_reset_function(struct be_adapter *adapter); 2084 2084 int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, 2085 - u32 rss_hash_opts, u16 table_size, u8 *rss_hkey); 2085 + u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey); 2086 2086 int be_process_mcc(struct be_adapter *adapter); 2087 2087 int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon, 2088 2088 u8 status, u8 state);
+2 -1
drivers/net/ethernet/emulex/benet/be_ethtool.c
··· 1117 1117 return 0; 1118 1118 } 1119 1119 1120 - static int be_set_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey) 1120 + static int be_set_rxfh(struct net_device *netdev, const u32 *indir, 1121 + const u8 *hkey) 1121 1122 { 1122 1123 int rc = 0, i, j; 1123 1124 struct be_adapter *adapter = netdev_priv(netdev);
+9 -6
drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
··· 624 624 } 625 625 626 626 /** 627 - * i40evf_get_rxfh_indir - get the rx flow hash indirection table 627 + * i40evf_get_rxfh - get the rx flow hash indirection table 628 628 * @netdev: network interface device structure 629 629 * @indir: indirection table 630 + * @key: hash key (will be %NULL until get_rxfh_key_size is implemented) 630 631 * 631 632 * Reads the indirection table directly from the hardware. Always returns 0. 632 633 **/ 633 - static int i40evf_get_rxfh_indir(struct net_device *netdev, u32 *indir) 634 + static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key) 634 635 { 635 636 struct i40evf_adapter *adapter = netdev_priv(netdev); 636 637 struct i40e_hw *hw = &adapter->hw; ··· 649 648 } 650 649 651 650 /** 652 - * i40evf_set_rxfh_indir - set the rx flow hash indirection table 651 + * i40evf_set_rxfh - set the rx flow hash indirection table 653 652 * @netdev: network interface device structure 654 653 * @indir: indirection table 654 + * @key: hash key (will be %NULL until get_rxfh_key_size is implemented) 655 655 * 656 656 * Returns -EINVAL if the table specifies an inavlid queue id, otherwise 657 657 * returns 0 after programming the table. 658 658 **/ 659 - static int i40evf_set_rxfh_indir(struct net_device *netdev, const u32 *indir) 659 + static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir, 660 + const u8 *key) 660 661 { 661 662 struct i40evf_adapter *adapter = netdev_priv(netdev); 662 663 struct i40e_hw *hw = &adapter->hw; ··· 692 689 .get_rxnfc = i40evf_get_rxnfc, 693 690 .set_rxnfc = i40evf_set_rxnfc, 694 691 .get_rxfh_indir_size = i40evf_get_rxfh_indir_size, 695 - .get_rxfh_indir = i40evf_get_rxfh_indir, 696 - .set_rxfh_indir = i40evf_set_rxfh_indir, 692 + .get_rxfh = i40evf_get_rxfh, 693 + .set_rxfh = i40evf_set_rxfh, 697 694 .get_channels = i40evf_get_channels, 698 695 }; 699 696
+5 -4
drivers/net/ethernet/intel/igb/igb_ethtool.c
··· 2830 2830 return IGB_RETA_SIZE; 2831 2831 } 2832 2832 2833 - static int igb_get_rxfh_indir(struct net_device *netdev, u32 *indir) 2833 + static int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key) 2834 2834 { 2835 2835 struct igb_adapter *adapter = netdev_priv(netdev); 2836 2836 int i; ··· 2876 2876 } 2877 2877 } 2878 2878 2879 - static int igb_set_rxfh_indir(struct net_device *netdev, const u32 *indir) 2879 + static int igb_set_rxfh(struct net_device *netdev, const u32 *indir, 2880 + const u8 *key) 2880 2881 { 2881 2882 struct igb_adapter *adapter = netdev_priv(netdev); 2882 2883 struct e1000_hw *hw = &adapter->hw; ··· 3026 3025 .get_module_info = igb_get_module_info, 3027 3026 .get_module_eeprom = igb_get_module_eeprom, 3028 3027 .get_rxfh_indir_size = igb_get_rxfh_indir_size, 3029 - .get_rxfh_indir = igb_get_rxfh_indir, 3030 - .set_rxfh_indir = igb_set_rxfh_indir, 3028 + .get_rxfh = igb_get_rxfh, 3029 + .set_rxfh = igb_set_rxfh, 3031 3030 .get_channels = igb_get_channels, 3032 3031 .set_channels = igb_set_channels, 3033 3032 .begin = igb_ethtool_begin,
+5 -5
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
··· 564 564 return priv->rx_ring_num; 565 565 } 566 566 567 - static int mlx4_en_get_rxfh_indir(struct net_device *dev, u32 *ring_index) 567 + static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key) 568 568 { 569 569 struct mlx4_en_priv *priv = netdev_priv(dev); 570 570 struct mlx4_en_rss_map *rss_map = &priv->rss_map; ··· 582 582 return err; 583 583 } 584 584 585 - static int mlx4_en_set_rxfh_indir(struct net_device *dev, 586 - const u32 *ring_index) 585 + static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index, 586 + const u8 *key) 587 587 { 588 588 struct mlx4_en_priv *priv = netdev_priv(dev); 589 589 struct mlx4_en_dev *mdev = priv->mdev; ··· 1224 1224 .get_rxnfc = mlx4_en_get_rxnfc, 1225 1225 .set_rxnfc = mlx4_en_set_rxnfc, 1226 1226 .get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size, 1227 - .get_rxfh_indir = mlx4_en_get_rxfh_indir, 1228 - .set_rxfh_indir = mlx4_en_set_rxfh_indir, 1227 + .get_rxfh = mlx4_en_get_rxfh, 1228 + .set_rxfh = mlx4_en_set_rxfh, 1229 1229 .get_channels = mlx4_en_get_channels, 1230 1230 .set_channels = mlx4_en_set_channels, 1231 1231 .get_ts_info = mlx4_en_get_ts_info,
+5 -5
drivers/net/ethernet/sfc/ethtool.c
··· 1033 1033 0 : ARRAY_SIZE(efx->rx_indir_table)); 1034 1034 } 1035 1035 1036 - static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir) 1036 + static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key) 1037 1037 { 1038 1038 struct efx_nic *efx = netdev_priv(net_dev); 1039 1039 ··· 1041 1041 return 0; 1042 1042 } 1043 1043 1044 - static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, 1045 - const u32 *indir) 1044 + static int efx_ethtool_set_rxfh(struct net_device *net_dev, 1045 + const u32 *indir, const u8 *key) 1046 1046 { 1047 1047 struct efx_nic *efx = netdev_priv(net_dev); 1048 1048 ··· 1125 1125 .get_rxnfc = efx_ethtool_get_rxnfc, 1126 1126 .set_rxnfc = efx_ethtool_set_rxnfc, 1127 1127 .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, 1128 - .get_rxfh_indir = efx_ethtool_get_rxfh_indir, 1129 - .set_rxfh_indir = efx_ethtool_set_rxfh_indir, 1128 + .get_rxfh = efx_ethtool_get_rxfh, 1129 + .set_rxfh = efx_ethtool_set_rxfh, 1130 1130 .get_ts_info = efx_ethtool_get_ts_info, 1131 1131 .get_module_info = efx_ethtool_get_module_info, 1132 1132 .get_module_eeprom = efx_ethtool_get_module_eeprom,
+4 -4
drivers/net/vmxnet3/vmxnet3_ethtool.c
··· 579 579 } 580 580 581 581 static int 582 - vmxnet3_get_rss_indir(struct net_device *netdev, u32 *p) 582 + vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key) 583 583 { 584 584 struct vmxnet3_adapter *adapter = netdev_priv(netdev); 585 585 struct UPT1_RSSConf *rssConf = adapter->rss_conf; ··· 592 592 } 593 593 594 594 static int 595 - vmxnet3_set_rss_indir(struct net_device *netdev, const u32 *p) 595 + vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key) 596 596 { 597 597 unsigned int i; 598 598 unsigned long flags; ··· 628 628 .get_rxnfc = vmxnet3_get_rxnfc, 629 629 #ifdef VMXNET3_RSS 630 630 .get_rxfh_indir_size = vmxnet3_get_rss_indir_size, 631 - .get_rxfh_indir = vmxnet3_get_rss_indir, 632 - .set_rxfh_indir = vmxnet3_set_rss_indir, 631 + .get_rxfh = vmxnet3_get_rss, 632 + .set_rxfh = vmxnet3_set_rss, 633 633 #endif 634 634 }; 635 635
+10 -14
include/linux/ethtool.h
··· 158 158 * Returns zero if not supported for this specific device. 159 159 * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table. 160 160 * Returns zero if not supported for this specific device. 161 - * @get_rxfh_indir: Get the contents of the RX flow hash indirection table. 162 - * Will not be called if @get_rxfh_indir_size returns zero. 163 161 * @get_rxfh: Get the contents of the RX flow hash indirection table and hash 164 162 * key. 165 - * Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size 166 - * returns zero. 163 + * Will only be called if one or both of @get_rxfh_indir_size and 164 + * @get_rxfh_key_size are implemented and return non-zero. 167 165 * Returns a negative error code or zero. 168 - * @set_rxfh_indir: Set the contents of the RX flow hash indirection table. 169 - * Will not be called if @get_rxfh_indir_size returns zero. 170 - * @set_rxfh: Set the contents of the RX flow hash indirection table and 171 - * hash key. 172 - * Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size 173 - * returns zero. 166 + * @set_rxfh: Set the contents of the RX flow hash indirection table and/or 167 + * hash key. In case only the indirection table or hash key is to be 168 + * changed, the other argument will be %NULL. 169 + * Will only be called if one or both of @get_rxfh_indir_size and 170 + * @get_rxfh_key_size are implemented and return non-zero. 174 171 * Returns a negative error code or zero. 175 172 * @get_channels: Get number of channels. 176 173 * @set_channels: Set number of channels. Returns a negative error code or ··· 241 244 int (*reset)(struct net_device *, u32 *); 242 245 u32 (*get_rxfh_key_size)(struct net_device *); 243 246 u32 (*get_rxfh_indir_size)(struct net_device *); 244 - int (*get_rxfh)(struct net_device *, u32 *, u8 *); 245 - int (*set_rxfh)(struct net_device *, u32 *, u8 *); 246 - int (*get_rxfh_indir)(struct net_device *, u32 *); 247 - int (*set_rxfh_indir)(struct net_device *, const u32 *); 247 + int (*get_rxfh)(struct net_device *, u32 *indir, u8 *key); 248 + int (*set_rxfh)(struct net_device *, const u32 *indir, 249 + const u8 *key); 248 250 void (*get_channels)(struct net_device *, struct ethtool_channels *); 249 251 int (*set_channels)(struct net_device *, struct ethtool_channels *); 250 252 int (*get_dump_flag)(struct net_device *, struct ethtool_dump *);
+14 -11
include/uapi/linux/ethtool.h
··· 850 850 * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key. 851 851 * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH 852 852 * @rss_context: RSS context identifier. 853 - * @indir_size: On entry, the array size of the user buffer, which may be zero. 854 - * On return from %ETHTOOL_GRSSH, the array size of the hardware 855 - * indirection table. 856 - * @key_size: On entry, the array size of the user buffer in bytes, 857 - * which may be zero. 858 - * On return from %ETHTOOL_GRSSH, the size of the RSS hash key. 853 + * @indir_size: On entry, the array size of the user buffer for the 854 + * indirection table, which may be zero, or (for %ETHTOOL_SRSSH), 855 + * %ETH_RXFH_INDIR_NO_CHANGE. On return from %ETHTOOL_GRSSH, 856 + * the array size of the hardware indirection table. 857 + * @key_size: On entry, the array size of the user buffer for the hash key, 858 + * which may be zero. On return from %ETHTOOL_GRSSH, the size of the 859 + * hardware hash key. 859 860 * @rsvd: Reserved for future extensions. 860 861 * @rss_config: RX ring/queue index for each hash value i.e., indirection table 861 - * of size @indir_size followed by hash key of size @key_size. 862 + * of @indir_size __u32 elements, followed by hash key of @key_size 863 + * bytes. 862 864 * 863 865 * For %ETHTOOL_GRSSH, a @indir_size and key_size of zero means that only the 864 - * size should be returned. For %ETHTOOL_SRSSH, a @indir_size of 0xDEADBEEF 865 - * means that indir table setting is not requested and a @indir_size of zero 866 - * means the indir table should be reset to default values. This last feature 867 - * is not supported by the original implementations. 866 + * size should be returned. For %ETHTOOL_SRSSH, an @indir_size of 867 + * %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested 868 + * and a @indir_size of zero means the indir table should be reset to default 869 + * values. 868 870 */ 869 871 struct ethtool_rxfh { 870 872 __u32 cmd; ··· 876 874 __u32 rsvd[2]; 877 875 __u32 rss_config[0]; 878 876 }; 877 + #define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff 879 878 880 879 /** 881 880 * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter
+50 -64
net/core/ethtool.c
··· 561 561 struct ethtool_rxnfc *rx_rings, 562 562 u32 size) 563 563 { 564 - int ret = 0, i; 564 + int i; 565 565 566 566 if (copy_from_user(indir, useraddr, size * sizeof(indir[0]))) 567 - ret = -EFAULT; 567 + return -EFAULT; 568 568 569 569 /* Validate ring indices */ 570 - for (i = 0; i < size; i++) { 571 - if (indir[i] >= rx_rings->data) { 572 - ret = -EINVAL; 573 - break; 574 - } 575 - } 576 - return ret; 570 + for (i = 0; i < size; i++) 571 + if (indir[i] >= rx_rings->data) 572 + return -EINVAL; 573 + 574 + return 0; 577 575 } 578 576 579 577 static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, ··· 582 584 int ret; 583 585 584 586 if (!dev->ethtool_ops->get_rxfh_indir_size || 585 - !dev->ethtool_ops->get_rxfh_indir) 587 + !dev->ethtool_ops->get_rxfh) 586 588 return -EOPNOTSUPP; 587 589 dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev); 588 590 if (dev_size == 0) ··· 608 610 if (!indir) 609 611 return -ENOMEM; 610 612 611 - ret = dev->ethtool_ops->get_rxfh_indir(dev, indir); 613 + ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL); 612 614 if (ret) 613 615 goto out; 614 616 ··· 632 634 int ret; 633 635 u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]); 634 636 635 - if (!ops->get_rxfh_indir_size || !ops->set_rxfh_indir || 637 + if (!ops->get_rxfh_indir_size || !ops->set_rxfh || 636 638 !ops->get_rxnfc) 637 639 return -EOPNOTSUPP; 638 640 ··· 669 671 goto out; 670 672 } 671 673 672 - ret = ops->set_rxfh_indir(dev, indir); 674 + ret = ops->set_rxfh(dev, indir, NULL); 673 675 674 676 out: 675 677 kfree(indir); ··· 681 683 { 682 684 int ret; 683 685 const struct ethtool_ops *ops = dev->ethtool_ops; 684 - u32 user_indir_size = 0, user_key_size = 0; 686 + u32 user_indir_size, user_key_size; 685 687 u32 dev_indir_size = 0, dev_key_size = 0; 688 + struct ethtool_rxfh rxfh; 686 689 u32 total_size; 687 - u32 indir_offset, indir_bytes; 688 - u32 key_offset; 690 + u32 indir_bytes; 689 691 u32 *indir = NULL; 690 692 u8 *hkey = NULL; 691 693 u8 *rss_config; ··· 697 699 698 700 if (ops->get_rxfh_indir_size) 699 701 dev_indir_size = ops->get_rxfh_indir_size(dev); 700 - 701 - indir_offset = offsetof(struct ethtool_rxfh, indir_size); 702 - 703 - if (copy_from_user(&user_indir_size, 704 - useraddr + indir_offset, 705 - sizeof(user_indir_size))) 706 - return -EFAULT; 707 - 708 - if (copy_to_user(useraddr + indir_offset, 709 - &dev_indir_size, sizeof(dev_indir_size))) 710 - return -EFAULT; 711 - 712 702 if (ops->get_rxfh_key_size) 713 703 dev_key_size = ops->get_rxfh_key_size(dev); 714 704 715 705 if ((dev_key_size + dev_indir_size) == 0) 716 706 return -EOPNOTSUPP; 717 707 718 - key_offset = offsetof(struct ethtool_rxfh, key_size); 719 - 720 - if (copy_from_user(&user_key_size, 721 - useraddr + key_offset, 722 - sizeof(user_key_size))) 708 + if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) 723 709 return -EFAULT; 710 + user_indir_size = rxfh.indir_size; 711 + user_key_size = rxfh.key_size; 724 712 725 - if (copy_to_user(useraddr + key_offset, 726 - &dev_key_size, sizeof(dev_key_size))) 713 + /* Check that reserved fields are 0 for now */ 714 + if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1]) 715 + return -EINVAL; 716 + 717 + rxfh.indir_size = dev_indir_size; 718 + rxfh.key_size = dev_key_size; 719 + if (copy_to_user(useraddr, &rxfh, sizeof(rxfh))) 727 720 return -EFAULT; 728 721 729 722 /* If the user buffer size is 0, this is just a query for the ··· 759 770 int ret; 760 771 const struct ethtool_ops *ops = dev->ethtool_ops; 761 772 struct ethtool_rxnfc rx_rings; 762 - u32 user_indir_size = 0, dev_indir_size = 0, i; 763 - u32 user_key_size = 0, dev_key_size = 0; 773 + struct ethtool_rxfh rxfh; 774 + u32 dev_indir_size = 0, dev_key_size = 0, i; 764 775 u32 *indir = NULL, indir_bytes = 0; 765 776 u8 *hkey = NULL; 766 777 u8 *rss_config; 767 - u32 indir_offset, key_offset; 768 778 u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); 769 779 770 780 if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) || ··· 772 784 773 785 if (ops->get_rxfh_indir_size) 774 786 dev_indir_size = ops->get_rxfh_indir_size(dev); 775 - 776 - indir_offset = offsetof(struct ethtool_rxfh, indir_size); 777 - if (copy_from_user(&user_indir_size, 778 - useraddr + indir_offset, 779 - sizeof(user_indir_size))) 780 - return -EFAULT; 781 - 782 787 if (ops->get_rxfh_key_size) 783 788 dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev); 784 - 785 789 if ((dev_key_size + dev_indir_size) == 0) 786 790 return -EOPNOTSUPP; 787 791 788 - key_offset = offsetof(struct ethtool_rxfh, key_size); 789 - if (copy_from_user(&user_key_size, 790 - useraddr + key_offset, 791 - sizeof(user_key_size))) 792 + if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) 792 793 return -EFAULT; 793 794 794 - /* If either indir or hash key is valid, proceed further. 795 - */ 796 - if ((user_indir_size && ((user_indir_size != 0xDEADBEEF) && 797 - user_indir_size != dev_indir_size)) || 798 - (user_key_size && (user_key_size != dev_key_size))) 795 + /* Check that reserved fields are 0 for now */ 796 + if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1]) 799 797 return -EINVAL; 800 798 801 - if (user_indir_size != 0xDEADBEEF) 799 + /* If either indir or hash key is valid, proceed further. 800 + * It is not valid to request that both be unchanged. 801 + */ 802 + if ((rxfh.indir_size && 803 + rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE && 804 + rxfh.indir_size != dev_indir_size) || 805 + (rxfh.key_size && (rxfh.key_size != dev_key_size)) || 806 + (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE && 807 + rxfh.key_size == 0)) 808 + return -EINVAL; 809 + 810 + if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) 802 811 indir_bytes = dev_indir_size * sizeof(indir[0]); 803 812 804 - rss_config = kzalloc(indir_bytes + user_key_size, GFP_USER); 813 + rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER); 805 814 if (!rss_config) 806 815 return -ENOMEM; 807 816 ··· 807 822 if (ret) 808 823 goto out; 809 824 810 - /* user_indir_size == 0 means reset the indir table to default. 811 - * user_indir_size == 0xDEADBEEF means indir setting is not requested. 825 + /* rxfh.indir_size == 0 means reset the indir table to default. 826 + * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged. 812 827 */ 813 - if (user_indir_size && user_indir_size != 0xDEADBEEF) { 828 + if (rxfh.indir_size && 829 + rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) { 814 830 indir = (u32 *)rss_config; 815 831 ret = ethtool_copy_validate_indir(indir, 816 832 useraddr + rss_cfg_offset, 817 833 &rx_rings, 818 - user_indir_size); 834 + rxfh.indir_size); 819 835 if (ret) 820 836 goto out; 821 - } else if (user_indir_size == 0) { 837 + } else if (rxfh.indir_size == 0) { 822 838 indir = (u32 *)rss_config; 823 839 for (i = 0; i < dev_indir_size; i++) 824 840 indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); 825 841 } 826 842 827 - if (user_key_size) { 843 + if (rxfh.key_size) { 828 844 hkey = rss_config + indir_bytes; 829 845 if (copy_from_user(hkey, 830 846 useraddr + rss_cfg_offset + indir_bytes, 831 - user_key_size)) { 847 + rxfh.key_size)) { 832 848 ret = -EFAULT; 833 849 goto out; 834 850 }