blob: 10d929abdf6aaafa12a5c19ac615fd3b72a903c8 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * net/core/ethtool.c - Ethtool ioctl handler
4 * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
5 *
6 * This file is where we call all the ethtool_ops commands to get
Matthew Wilcox61a44b92007-07-31 14:00:02 -07007 * the information ethtool needs.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
9
10#include <linux/module.h>
11#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080012#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/ethtool.h>
15#include <linux/netdevice.h>
Richard Cochranc8f3a8c2012-04-03 22:59:17 +000016#include <linux/net_tstamp.h>
17#include <linux/phy.h>
Jeff Garzikd17792e2010-03-04 08:21:53 +000018#include <linux/bitops.h>
chavey97f8aef2010-04-07 21:54:42 -070019#include <linux/uaccess.h>
Leon Romanovsky6a7e25c2020-01-27 09:20:28 +020020#include <linux/vermagic.h>
David S. Miller73da16c2010-09-21 16:12:11 -070021#include <linux/vmalloc.h>
Russell Kinge679c9c2018-03-28 15:44:16 -070022#include <linux/sfp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Ben Hutchings68f512f2011-04-02 00:35:15 +010024#include <linux/rtnetlink.h>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010025#include <linux/sched/signal.h>
Eric Dumazet960fb622014-11-16 06:23:05 -080026#include <linux/net.h>
Jakub Kicinskiddb6e992019-01-31 10:50:47 -080027#include <net/devlink.h>
Jakub Kicinski1661d342018-10-01 14:51:36 +020028#include <net/xdp_sock.h>
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +010029#include <net/flow_offload.h>
Michal Kubecek73286732019-12-27 15:56:03 +010030#include <linux/ethtool_netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
Michal Kubecekd44e1312019-12-11 10:58:29 +010032#include "common.h"
33
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +090034/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 * Some useful ethtool_ops methods that're device independent.
36 * If we find that all drivers want to do the same thing here,
37 * we can turn these into dev_() function calls.
38 */
39
40u32 ethtool_op_get_link(struct net_device *dev)
41{
42 return netif_carrier_ok(dev) ? 1 : 0;
43}
chavey97f8aef2010-04-07 21:54:42 -070044EXPORT_SYMBOL(ethtool_op_get_link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Richard Cochran02eacbd2012-04-03 22:59:22 +000046int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
47{
48 info->so_timestamping =
49 SOF_TIMESTAMPING_TX_SOFTWARE |
50 SOF_TIMESTAMPING_RX_SOFTWARE |
51 SOF_TIMESTAMPING_SOFTWARE;
52 info->phc_index = -1;
53 return 0;
54}
55EXPORT_SYMBOL(ethtool_op_get_ts_info);
56
Linus Torvalds1da177e2005-04-16 15:20:36 -070057/* Handlers for each ethtool command */
58
Michał Mirosław5455c692011-02-15 16:59:17 +000059static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
60{
61 struct ethtool_gfeatures cmd = {
62 .cmd = ETHTOOL_GFEATURES,
63 .size = ETHTOOL_DEV_FEATURE_WORDS,
64 };
Michał Mirosław475414f2011-11-15 15:29:55 +000065 struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
Michał Mirosław5455c692011-02-15 16:59:17 +000066 u32 __user *sizeaddr;
67 u32 copy_size;
Michał Mirosław475414f2011-11-15 15:29:55 +000068 int i;
69
70 /* in case feature bits run out again */
Michał Mirosław09da71b2011-11-16 14:32:03 +000071 BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > sizeof(netdev_features_t));
Michał Mirosław475414f2011-11-15 15:29:55 +000072
73 for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
Michał Mirosław09da71b2011-11-16 14:32:03 +000074 features[i].available = (u32)(dev->hw_features >> (32 * i));
75 features[i].requested = (u32)(dev->wanted_features >> (32 * i));
76 features[i].active = (u32)(dev->features >> (32 * i));
77 features[i].never_changed =
78 (u32)(NETIF_F_NEVER_CHANGE >> (32 * i));
Michał Mirosław475414f2011-11-15 15:29:55 +000079 }
Michał Mirosław5455c692011-02-15 16:59:17 +000080
81 sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size);
82 if (get_user(copy_size, sizeaddr))
83 return -EFAULT;
84
85 if (copy_size > ETHTOOL_DEV_FEATURE_WORDS)
86 copy_size = ETHTOOL_DEV_FEATURE_WORDS;
87
88 if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
89 return -EFAULT;
90 useraddr += sizeof(cmd);
91 if (copy_to_user(useraddr, features, copy_size * sizeof(*features)))
92 return -EFAULT;
93
94 return 0;
95}
96
97static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
98{
99 struct ethtool_sfeatures cmd;
100 struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
Michał Mirosław475414f2011-11-15 15:29:55 +0000101 netdev_features_t wanted = 0, valid = 0;
102 int i, ret = 0;
Michał Mirosław5455c692011-02-15 16:59:17 +0000103
104 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
105 return -EFAULT;
106 useraddr += sizeof(cmd);
107
108 if (cmd.size != ETHTOOL_DEV_FEATURE_WORDS)
109 return -EINVAL;
110
111 if (copy_from_user(features, useraddr, sizeof(features)))
112 return -EFAULT;
113
Michał Mirosław475414f2011-11-15 15:29:55 +0000114 for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
Michał Mirosław09da71b2011-11-16 14:32:03 +0000115 valid |= (netdev_features_t)features[i].valid << (32 * i);
116 wanted |= (netdev_features_t)features[i].requested << (32 * i);
Michał Mirosław475414f2011-11-15 15:29:55 +0000117 }
118
119 if (valid & ~NETIF_F_ETHTOOL_BITS)
Michał Mirosław5455c692011-02-15 16:59:17 +0000120 return -EINVAL;
121
Michał Mirosław475414f2011-11-15 15:29:55 +0000122 if (valid & ~dev->hw_features) {
123 valid &= dev->hw_features;
Michał Mirosław5455c692011-02-15 16:59:17 +0000124 ret |= ETHTOOL_F_UNSUPPORTED;
125 }
126
Michał Mirosław475414f2011-11-15 15:29:55 +0000127 dev->wanted_features &= ~valid;
128 dev->wanted_features |= wanted & valid;
Michał Mirosław6cb6a272011-04-02 22:48:47 -0700129 __netdev_update_features(dev);
Michał Mirosław5455c692011-02-15 16:59:17 +0000130
Michał Mirosław475414f2011-11-15 15:29:55 +0000131 if ((dev->wanted_features ^ dev->features) & valid)
Michał Mirosław5455c692011-02-15 16:59:17 +0000132 ret |= ETHTOOL_F_WISH;
133
134 return ret;
135}
136
Michał Mirosław340ae162011-02-15 16:59:16 +0000137static int __ethtool_get_sset_count(struct net_device *dev, int sset)
138{
139 const struct ethtool_ops *ops = dev->ethtool_ops;
140
Michał Mirosław5455c692011-02-15 16:59:17 +0000141 if (sset == ETH_SS_FEATURES)
142 return ARRAY_SIZE(netdev_features_strings);
143
Eyal Perry892311f2014-12-02 18:12:10 +0200144 if (sset == ETH_SS_RSS_HASH_FUNCS)
145 return ARRAY_SIZE(rss_hash_func_strings);
146
Hadar Hen Ziona4244b02015-06-11 10:28:16 +0300147 if (sset == ETH_SS_TUNABLES)
148 return ARRAY_SIZE(tunable_strings);
149
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +0100150 if (sset == ETH_SS_PHY_TUNABLES)
151 return ARRAY_SIZE(phy_tunable_strings);
152
Florian Fainelli99943382018-04-25 12:12:48 -0700153 if (sset == ETH_SS_PHY_STATS && dev->phydev &&
154 !ops->get_ethtool_phy_stats)
155 return phy_ethtool_get_sset_count(dev->phydev);
Andrew Lunnf3a40942015-12-30 16:28:25 +0100156
Michal Kubecek428c1222019-12-11 10:58:34 +0100157 if (sset == ETH_SS_LINK_MODES)
158 return __ETHTOOL_LINK_MODE_MASK_NBITS;
159
Jiri Pirkoc03a14e2013-01-07 09:02:08 +0000160 if (ops->get_sset_count && ops->get_strings)
Michał Mirosław340ae162011-02-15 16:59:16 +0000161 return ops->get_sset_count(dev, sset);
162 else
163 return -EOPNOTSUPP;
164}
165
166static void __ethtool_get_strings(struct net_device *dev,
167 u32 stringset, u8 *data)
168{
169 const struct ethtool_ops *ops = dev->ethtool_ops;
170
Michał Mirosław5455c692011-02-15 16:59:17 +0000171 if (stringset == ETH_SS_FEATURES)
172 memcpy(data, netdev_features_strings,
173 sizeof(netdev_features_strings));
Eyal Perry892311f2014-12-02 18:12:10 +0200174 else if (stringset == ETH_SS_RSS_HASH_FUNCS)
175 memcpy(data, rss_hash_func_strings,
176 sizeof(rss_hash_func_strings));
Hadar Hen Ziona4244b02015-06-11 10:28:16 +0300177 else if (stringset == ETH_SS_TUNABLES)
178 memcpy(data, tunable_strings, sizeof(tunable_strings));
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +0100179 else if (stringset == ETH_SS_PHY_TUNABLES)
180 memcpy(data, phy_tunable_strings, sizeof(phy_tunable_strings));
Florian Fainelli99943382018-04-25 12:12:48 -0700181 else if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
182 !ops->get_ethtool_phy_stats)
183 phy_ethtool_get_strings(dev->phydev, data);
Michal Kubecek428c1222019-12-11 10:58:34 +0100184 else if (stringset == ETH_SS_LINK_MODES)
185 memcpy(data, link_mode_names,
186 __ETHTOOL_LINK_MODE_MASK_NBITS * ETH_GSTRING_LEN);
Florian Fainelli99943382018-04-25 12:12:48 -0700187 else
Michał Mirosław5455c692011-02-15 16:59:17 +0000188 /* ops->get_strings is valid because checked earlier */
189 ops->get_strings(dev, stringset, data);
Michał Mirosław340ae162011-02-15 16:59:16 +0000190}
191
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000192static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd)
Michał Mirosław0a417702011-02-15 16:59:17 +0000193{
194 /* feature masks of legacy discrete ethtool ops */
195
196 switch (eth_cmd) {
197 case ETHTOOL_GTXCSUM:
198 case ETHTOOL_STXCSUM:
Vladyslav Tarasiuk9d648fb2020-03-24 13:57:08 +0200199 return NETIF_F_CSUM_MASK | NETIF_F_FCOE_CRC |
Michal Kubecekf70bb062020-03-12 21:07:43 +0100200 NETIF_F_SCTP_CRC;
Michał Mirosławe83d3602011-02-15 16:59:18 +0000201 case ETHTOOL_GRXCSUM:
202 case ETHTOOL_SRXCSUM:
203 return NETIF_F_RXCSUM;
Michał Mirosław0a417702011-02-15 16:59:17 +0000204 case ETHTOOL_GSG:
205 case ETHTOOL_SSG:
Michal Kubecekf70bb062020-03-12 21:07:43 +0100206 return NETIF_F_SG | NETIF_F_FRAGLIST;
Michał Mirosław0a417702011-02-15 16:59:17 +0000207 case ETHTOOL_GTSO:
208 case ETHTOOL_STSO:
209 return NETIF_F_ALL_TSO;
Michał Mirosław0a417702011-02-15 16:59:17 +0000210 case ETHTOOL_GGSO:
211 case ETHTOOL_SGSO:
212 return NETIF_F_GSO;
213 case ETHTOOL_GGRO:
214 case ETHTOOL_SGRO:
215 return NETIF_F_GRO;
216 default:
217 BUG();
218 }
219}
220
Michał Mirosław0a417702011-02-15 16:59:17 +0000221static int ethtool_get_one_feature(struct net_device *dev,
222 char __user *useraddr, u32 ethcmd)
223{
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000224 netdev_features_t mask = ethtool_get_feature_mask(ethcmd);
Michał Mirosław0a417702011-02-15 16:59:17 +0000225 struct ethtool_value edata = {
226 .cmd = ethcmd,
Michał Mirosław86794882011-02-15 16:59:17 +0000227 .data = !!(dev->features & mask),
Michał Mirosław0a417702011-02-15 16:59:17 +0000228 };
Michał Mirosław0a417702011-02-15 16:59:17 +0000229
Michał Mirosław0a417702011-02-15 16:59:17 +0000230 if (copy_to_user(useraddr, &edata, sizeof(edata)))
231 return -EFAULT;
232 return 0;
233}
234
Michał Mirosław0a417702011-02-15 16:59:17 +0000235static int ethtool_set_one_feature(struct net_device *dev,
236 void __user *useraddr, u32 ethcmd)
237{
238 struct ethtool_value edata;
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000239 netdev_features_t mask;
Michał Mirosław0a417702011-02-15 16:59:17 +0000240
241 if (copy_from_user(&edata, useraddr, sizeof(edata)))
242 return -EFAULT;
243
Michał Mirosław86794882011-02-15 16:59:17 +0000244 mask = ethtool_get_feature_mask(ethcmd);
245 mask &= dev->hw_features;
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000246 if (!mask)
Michał Mirosław0a417702011-02-15 16:59:17 +0000247 return -EOPNOTSUPP;
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000248
249 if (edata.data)
250 dev->wanted_features |= mask;
251 else
252 dev->wanted_features &= ~mask;
253
254 __netdev_update_features(dev);
255
256 return 0;
Michał Mirosław0a417702011-02-15 16:59:17 +0000257}
258
Michał Mirosław02b3a552011-11-15 15:29:55 +0000259#define ETH_ALL_FLAGS (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \
260 ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH)
Patrick McHardyf6469682013-04-19 02:04:27 +0000261#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_CTAG_RX | \
262 NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_NTUPLE | \
263 NETIF_F_RXHASH)
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000264
265static u32 __ethtool_get_flags(struct net_device *dev)
266{
Michał Mirosław02b3a552011-11-15 15:29:55 +0000267 u32 flags = 0;
268
Dragos Foianu8a731252013-07-13 14:43:00 +0100269 if (dev->features & NETIF_F_LRO)
270 flags |= ETH_FLAG_LRO;
271 if (dev->features & NETIF_F_HW_VLAN_CTAG_RX)
272 flags |= ETH_FLAG_RXVLAN;
273 if (dev->features & NETIF_F_HW_VLAN_CTAG_TX)
274 flags |= ETH_FLAG_TXVLAN;
275 if (dev->features & NETIF_F_NTUPLE)
276 flags |= ETH_FLAG_NTUPLE;
277 if (dev->features & NETIF_F_RXHASH)
278 flags |= ETH_FLAG_RXHASH;
Michał Mirosław02b3a552011-11-15 15:29:55 +0000279
280 return flags;
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000281}
282
283static int __ethtool_set_flags(struct net_device *dev, u32 data)
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000284{
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000285 netdev_features_t features = 0, changed;
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000286
Michał Mirosław02b3a552011-11-15 15:29:55 +0000287 if (data & ~ETH_ALL_FLAGS)
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000288 return -EINVAL;
289
Dragos Foianu8a731252013-07-13 14:43:00 +0100290 if (data & ETH_FLAG_LRO)
291 features |= NETIF_F_LRO;
292 if (data & ETH_FLAG_RXVLAN)
293 features |= NETIF_F_HW_VLAN_CTAG_RX;
294 if (data & ETH_FLAG_TXVLAN)
295 features |= NETIF_F_HW_VLAN_CTAG_TX;
296 if (data & ETH_FLAG_NTUPLE)
297 features |= NETIF_F_NTUPLE;
298 if (data & ETH_FLAG_RXHASH)
299 features |= NETIF_F_RXHASH;
Michał Mirosław02b3a552011-11-15 15:29:55 +0000300
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000301 /* allow changing only bits set in hw_features */
Michał Mirosław02b3a552011-11-15 15:29:55 +0000302 changed = (features ^ dev->features) & ETH_ALL_FEATURES;
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000303 if (changed & ~dev->hw_features)
304 return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;
305
306 dev->wanted_features =
Michał Mirosław02b3a552011-11-15 15:29:55 +0000307 (dev->wanted_features & ~changed) | (features & changed);
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000308
Michał Mirosław6cb6a272011-04-02 22:48:47 -0700309 __netdev_update_features(dev);
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000310
311 return 0;
312}
313
Alan Brady5a6cd6d2017-10-05 14:53:40 -0700314/* Given two link masks, AND them together and save the result in dst. */
315void ethtool_intersect_link_masks(struct ethtool_link_ksettings *dst,
316 struct ethtool_link_ksettings *src)
317{
318 unsigned int size = BITS_TO_LONGS(__ETHTOOL_LINK_MODE_MASK_NBITS);
319 unsigned int idx = 0;
320
321 for (; idx < size; idx++) {
322 dst->link_modes.supported[idx] &=
323 src->link_modes.supported[idx];
324 dst->link_modes.advertising[idx] &=
325 src->link_modes.advertising[idx];
326 }
327}
328EXPORT_SYMBOL(ethtool_intersect_link_masks);
329
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200330void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst,
331 u32 legacy_u32)
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800332{
333 bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS);
334 dst[0] = legacy_u32;
335}
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200336EXPORT_SYMBOL(ethtool_convert_legacy_u32_to_link_mode);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800337
338/* return false if src had higher bits set. lower bits always updated. */
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200339bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
340 const unsigned long *src)
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800341{
342 bool retval = true;
343
344 /* TODO: following test will soon always be true */
345 if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) {
346 __ETHTOOL_DECLARE_LINK_MODE_MASK(ext);
347
348 bitmap_zero(ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
349 bitmap_fill(ext, 32);
350 bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
351 if (bitmap_intersects(ext, src,
352 __ETHTOOL_LINK_MODE_MASK_NBITS)) {
353 /* src mask goes beyond bit 31 */
354 retval = false;
355 }
356 }
357 *legacy_u32 = src[0];
358 return retval;
359}
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200360EXPORT_SYMBOL(ethtool_convert_link_mode_to_legacy_u32);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800361
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800362/* return false if ksettings link modes had higher bits
363 * set. legacy_settings always updated (best effort)
364 */
365static bool
366convert_link_ksettings_to_legacy_settings(
367 struct ethtool_cmd *legacy_settings,
368 const struct ethtool_link_ksettings *link_ksettings)
369{
370 bool retval = true;
371
372 memset(legacy_settings, 0, sizeof(*legacy_settings));
373 /* this also clears the deprecated fields in legacy structure:
374 * __u8 transceiver;
375 * __u32 maxtxpkt;
376 * __u32 maxrxpkt;
377 */
378
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200379 retval &= ethtool_convert_link_mode_to_legacy_u32(
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800380 &legacy_settings->supported,
381 link_ksettings->link_modes.supported);
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200382 retval &= ethtool_convert_link_mode_to_legacy_u32(
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800383 &legacy_settings->advertising,
384 link_ksettings->link_modes.advertising);
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200385 retval &= ethtool_convert_link_mode_to_legacy_u32(
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800386 &legacy_settings->lp_advertising,
387 link_ksettings->link_modes.lp_advertising);
388 ethtool_cmd_speed_set(legacy_settings, link_ksettings->base.speed);
389 legacy_settings->duplex
390 = link_ksettings->base.duplex;
391 legacy_settings->port
392 = link_ksettings->base.port;
393 legacy_settings->phy_address
394 = link_ksettings->base.phy_address;
395 legacy_settings->autoneg
396 = link_ksettings->base.autoneg;
397 legacy_settings->mdio_support
398 = link_ksettings->base.mdio_support;
399 legacy_settings->eth_tp_mdix
400 = link_ksettings->base.eth_tp_mdix;
401 legacy_settings->eth_tp_mdix_ctrl
402 = link_ksettings->base.eth_tp_mdix_ctrl;
Florian Fainelli19cab882017-09-20 15:52:13 -0700403 legacy_settings->transceiver
404 = link_ksettings->base.transceiver;
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800405 return retval;
406}
407
408/* number of 32-bit words to store the user's link mode bitmaps */
409#define __ETHTOOL_LINK_MODE_MASK_NU32 \
410 DIV_ROUND_UP(__ETHTOOL_LINK_MODE_MASK_NBITS, 32)
411
412/* layout of the struct passed from/to userland */
413struct ethtool_link_usettings {
414 struct ethtool_link_settings base;
415 struct {
416 __u32 supported[__ETHTOOL_LINK_MODE_MASK_NU32];
417 __u32 advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
418 __u32 lp_advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
419 } link_modes;
420};
421
Michal Kubecek9b300492018-08-28 19:56:58 +0200422/* Internal kernel helper to query a device ethtool_link_settings. */
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800423int __ethtool_get_link_ksettings(struct net_device *dev,
424 struct ethtool_link_ksettings *link_ksettings)
425{
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800426 ASSERT_RTNL();
427
Michal Kubecek9b300492018-08-28 19:56:58 +0200428 if (!dev->ethtool_ops->get_link_ksettings)
David Decotigny3237fc62016-02-24 10:58:11 -0800429 return -EOPNOTSUPP;
430
Michal Kubecek9b300492018-08-28 19:56:58 +0200431 memset(link_ksettings, 0, sizeof(*link_ksettings));
432 return dev->ethtool_ops->get_link_ksettings(dev, link_ksettings);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800433}
434EXPORT_SYMBOL(__ethtool_get_link_ksettings);
435
436/* convert ethtool_link_usettings in user space to a kernel internal
437 * ethtool_link_ksettings. return 0 on success, errno on error.
438 */
439static int load_link_ksettings_from_user(struct ethtool_link_ksettings *to,
440 const void __user *from)
441{
442 struct ethtool_link_usettings link_usettings;
443
444 if (copy_from_user(&link_usettings, from, sizeof(link_usettings)))
445 return -EFAULT;
446
447 memcpy(&to->base, &link_usettings.base, sizeof(to->base));
Yury Norov3aa56882018-02-06 15:38:06 -0800448 bitmap_from_arr32(to->link_modes.supported,
449 link_usettings.link_modes.supported,
450 __ETHTOOL_LINK_MODE_MASK_NBITS);
451 bitmap_from_arr32(to->link_modes.advertising,
452 link_usettings.link_modes.advertising,
453 __ETHTOOL_LINK_MODE_MASK_NBITS);
454 bitmap_from_arr32(to->link_modes.lp_advertising,
455 link_usettings.link_modes.lp_advertising,
456 __ETHTOOL_LINK_MODE_MASK_NBITS);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800457
458 return 0;
459}
460
Cris Forno70ae1e12020-02-28 14:12:04 -0600461/* Check if the user is trying to change anything besides speed/duplex */
462bool ethtool_virtdev_validate_cmd(const struct ethtool_link_ksettings *cmd)
463{
464 struct ethtool_link_settings base2 = {};
465
466 base2.speed = cmd->base.speed;
467 base2.port = PORT_OTHER;
468 base2.duplex = cmd->base.duplex;
469 base2.cmd = cmd->base.cmd;
470 base2.link_mode_masks_nwords = cmd->base.link_mode_masks_nwords;
471
472 return !memcmp(&base2, &cmd->base, sizeof(base2)) &&
473 bitmap_empty(cmd->link_modes.supported,
474 __ETHTOOL_LINK_MODE_MASK_NBITS) &&
475 bitmap_empty(cmd->link_modes.lp_advertising,
476 __ETHTOOL_LINK_MODE_MASK_NBITS);
477}
478
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800479/* convert a kernel internal ethtool_link_ksettings to
480 * ethtool_link_usettings in user space. return 0 on success, errno on
481 * error.
482 */
483static int
484store_link_ksettings_for_user(void __user *to,
485 const struct ethtool_link_ksettings *from)
486{
487 struct ethtool_link_usettings link_usettings;
488
489 memcpy(&link_usettings.base, &from->base, sizeof(link_usettings));
Yury Norov3aa56882018-02-06 15:38:06 -0800490 bitmap_to_arr32(link_usettings.link_modes.supported,
491 from->link_modes.supported,
492 __ETHTOOL_LINK_MODE_MASK_NBITS);
493 bitmap_to_arr32(link_usettings.link_modes.advertising,
494 from->link_modes.advertising,
495 __ETHTOOL_LINK_MODE_MASK_NBITS);
496 bitmap_to_arr32(link_usettings.link_modes.lp_advertising,
497 from->link_modes.lp_advertising,
498 __ETHTOOL_LINK_MODE_MASK_NBITS);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800499
500 if (copy_to_user(to, &link_usettings, sizeof(link_usettings)))
501 return -EFAULT;
502
503 return 0;
504}
505
Michal Kubecek9b300492018-08-28 19:56:58 +0200506/* Query device for its ethtool_link_settings. */
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800507static int ethtool_get_link_ksettings(struct net_device *dev,
508 void __user *useraddr)
509{
510 int err = 0;
511 struct ethtool_link_ksettings link_ksettings;
512
513 ASSERT_RTNL();
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800514 if (!dev->ethtool_ops->get_link_ksettings)
515 return -EOPNOTSUPP;
516
517 /* handle bitmap nbits handshake */
518 if (copy_from_user(&link_ksettings.base, useraddr,
519 sizeof(link_ksettings.base)))
520 return -EFAULT;
521
522 if (__ETHTOOL_LINK_MODE_MASK_NU32
523 != link_ksettings.base.link_mode_masks_nwords) {
524 /* wrong link mode nbits requested */
525 memset(&link_ksettings, 0, sizeof(link_ksettings));
Ben Hutchings793cf872016-03-14 01:05:38 +0000526 link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS;
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800527 /* send back number of words required as negative val */
528 compiletime_assert(__ETHTOOL_LINK_MODE_MASK_NU32 <= S8_MAX,
529 "need too many bits for link modes!");
530 link_ksettings.base.link_mode_masks_nwords
531 = -((s8)__ETHTOOL_LINK_MODE_MASK_NU32);
532
533 /* copy the base fields back to user, not the link
534 * mode bitmaps
535 */
536 if (copy_to_user(useraddr, &link_ksettings.base,
537 sizeof(link_ksettings.base)))
538 return -EFAULT;
539
540 return 0;
541 }
542
543 /* handshake successful: user/kernel agree on
544 * link_mode_masks_nwords
545 */
546
547 memset(&link_ksettings, 0, sizeof(link_ksettings));
548 err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings);
549 if (err < 0)
550 return err;
551
552 /* make sure we tell the right values to user */
553 link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS;
554 link_ksettings.base.link_mode_masks_nwords
555 = __ETHTOOL_LINK_MODE_MASK_NU32;
556
557 return store_link_ksettings_for_user(useraddr, &link_ksettings);
558}
559
Michal Kubecek9b300492018-08-28 19:56:58 +0200560/* Update device ethtool_link_settings. */
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800561static int ethtool_set_link_ksettings(struct net_device *dev,
562 void __user *useraddr)
563{
564 int err;
565 struct ethtool_link_ksettings link_ksettings;
566
567 ASSERT_RTNL();
568
569 if (!dev->ethtool_ops->set_link_ksettings)
570 return -EOPNOTSUPP;
571
572 /* make sure nbits field has expected value */
573 if (copy_from_user(&link_ksettings.base, useraddr,
574 sizeof(link_ksettings.base)))
575 return -EFAULT;
576
577 if (__ETHTOOL_LINK_MODE_MASK_NU32
578 != link_ksettings.base.link_mode_masks_nwords)
579 return -EINVAL;
580
581 /* copy the whole structure, now that we know it has expected
582 * format
583 */
584 err = load_link_ksettings_from_user(&link_ksettings, useraddr);
585 if (err)
586 return err;
587
588 /* re-check nwords field, just in case */
589 if (__ETHTOOL_LINK_MODE_MASK_NU32
590 != link_ksettings.base.link_mode_masks_nwords)
591 return -EINVAL;
592
Michal Kubecek73286732019-12-27 15:56:03 +0100593 err = dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
Michal Kubecek1b1b1842019-12-27 15:56:18 +0100594 if (err >= 0) {
Michal Kubecek73286732019-12-27 15:56:03 +0100595 ethtool_notify(dev, ETHTOOL_MSG_LINKINFO_NTF, NULL);
Michal Kubecek1b1b1842019-12-27 15:56:18 +0100596 ethtool_notify(dev, ETHTOOL_MSG_LINKMODES_NTF, NULL);
597 }
Michal Kubecek73286732019-12-27 15:56:03 +0100598 return err;
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800599}
600
Cris Forno70ae1e12020-02-28 14:12:04 -0600601int ethtool_virtdev_set_link_ksettings(struct net_device *dev,
602 const struct ethtool_link_ksettings *cmd,
603 u32 *dev_speed, u8 *dev_duplex)
604{
605 u32 speed;
606 u8 duplex;
607
608 speed = cmd->base.speed;
609 duplex = cmd->base.duplex;
610 /* don't allow custom speed and duplex */
611 if (!ethtool_validate_speed(speed) ||
612 !ethtool_validate_duplex(duplex) ||
613 !ethtool_virtdev_validate_cmd(cmd))
614 return -EINVAL;
615 *dev_speed = speed;
616 *dev_duplex = duplex;
617
618 return 0;
619}
620EXPORT_SYMBOL(ethtool_virtdev_set_link_ksettings);
621
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800622/* Query device for its ethtool_cmd settings.
623 *
Michal Kubecek9b300492018-08-28 19:56:58 +0200624 * Backward compatibility note: for compatibility with legacy ethtool, this is
625 * now implemented via get_link_ksettings. When driver reports higher link mode
626 * bits, a kernel warning is logged once (with name of 1st driver/device) to
627 * recommend user to upgrade ethtool, but the command is successful (only the
628 * lower link mode bits reported back to user). Deprecated fields from
629 * ethtool_cmd (transceiver/maxrxpkt/maxtxpkt) are always set to zero.
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800630 */
Jiri Pirko4bc71cb2011-09-03 03:34:30 +0000631static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
632{
Michal Kubecek9b300492018-08-28 19:56:58 +0200633 struct ethtool_link_ksettings link_ksettings;
Jiri Pirko4bc71cb2011-09-03 03:34:30 +0000634 struct ethtool_cmd cmd;
Michal Kubecek9b300492018-08-28 19:56:58 +0200635 int err;
Jiri Pirko4bc71cb2011-09-03 03:34:30 +0000636
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800637 ASSERT_RTNL();
Michal Kubecek9b300492018-08-28 19:56:58 +0200638 if (!dev->ethtool_ops->get_link_ksettings)
639 return -EOPNOTSUPP;
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800640
Michal Kubecek9b300492018-08-28 19:56:58 +0200641 memset(&link_ksettings, 0, sizeof(link_ksettings));
642 err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings);
643 if (err < 0)
644 return err;
645 convert_link_ksettings_to_legacy_settings(&cmd, &link_ksettings);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800646
Michal Kubecek9b300492018-08-28 19:56:58 +0200647 /* send a sensible cmd tag back to user */
648 cmd.cmd = ETHTOOL_GSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
651 return -EFAULT;
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 return 0;
654}
655
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800656/* Update device link settings with given ethtool_cmd.
657 *
Michal Kubecek9b300492018-08-28 19:56:58 +0200658 * Backward compatibility note: for compatibility with legacy ethtool, this is
659 * now always implemented via set_link_settings. When user's request updates
660 * deprecated ethtool_cmd fields (transceiver/maxrxpkt/maxtxpkt), a kernel
661 * warning is logged once (with name of 1st driver/device) to recommend user to
662 * upgrade ethtool, and the request is rejected.
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800663 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
665{
Michal Kubecek9b300492018-08-28 19:56:58 +0200666 struct ethtool_link_ksettings link_ksettings;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 struct ethtool_cmd cmd;
Michal Kubecek73286732019-12-27 15:56:03 +0100668 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800670 ASSERT_RTNL();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
673 return -EFAULT;
Michal Kubecek9b300492018-08-28 19:56:58 +0200674 if (!dev->ethtool_ops->set_link_ksettings)
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800675 return -EOPNOTSUPP;
676
Michal Kubecek9b300492018-08-28 19:56:58 +0200677 if (!convert_legacy_settings_to_link_ksettings(&link_ksettings, &cmd))
678 return -EINVAL;
679 link_ksettings.base.link_mode_masks_nwords =
680 __ETHTOOL_LINK_MODE_MASK_NU32;
Michal Kubecek73286732019-12-27 15:56:03 +0100681 ret = dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
Michal Kubecek1b1b1842019-12-27 15:56:18 +0100682 if (ret >= 0) {
Michal Kubecek73286732019-12-27 15:56:03 +0100683 ethtool_notify(dev, ETHTOOL_MSG_LINKINFO_NTF, NULL);
Michal Kubecek1b1b1842019-12-27 15:56:18 +0100684 ethtool_notify(dev, ETHTOOL_MSG_LINKMODES_NTF, NULL);
685 }
Michal Kubecek73286732019-12-27 15:56:03 +0100686 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687}
688
chavey97f8aef2010-04-07 21:54:42 -0700689static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
690 void __user *useraddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691{
692 struct ethtool_drvinfo info;
Stephen Hemminger76fd8592006-09-08 11:16:13 -0700693 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 memset(&info, 0, sizeof(info));
696 info.cmd = ETHTOOL_GDRVINFO;
Leon Romanovsky6a7e25c2020-01-27 09:20:28 +0200697 strlcpy(info.version, UTS_RELEASE, sizeof(info.version));
Jiri Pirkoc03a14e2013-01-07 09:02:08 +0000698 if (ops->get_drvinfo) {
Ben Hutchings01414802010-08-17 02:31:15 -0700699 ops->get_drvinfo(dev, &info);
700 } else if (dev->dev.parent && dev->dev.parent->driver) {
701 strlcpy(info.bus_info, dev_name(dev->dev.parent),
702 sizeof(info.bus_info));
703 strlcpy(info.driver, dev->dev.parent->driver->name,
704 sizeof(info.driver));
705 } else {
706 return -EOPNOTSUPP;
707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Jeff Garzik723b2f52010-03-03 22:51:50 +0000709 /*
710 * this method of obtaining string set info is deprecated;
Jeff Garzikd17792e2010-03-04 08:21:53 +0000711 * Use ETHTOOL_GSSET_INFO instead.
Jeff Garzik723b2f52010-03-03 22:51:50 +0000712 */
Jiri Pirkoc03a14e2013-01-07 09:02:08 +0000713 if (ops->get_sset_count) {
Jeff Garzikff03d492007-08-15 16:01:08 -0700714 int rc;
715
716 rc = ops->get_sset_count(dev, ETH_SS_TEST);
717 if (rc >= 0)
718 info.testinfo_len = rc;
719 rc = ops->get_sset_count(dev, ETH_SS_STATS);
720 if (rc >= 0)
721 info.n_stats = rc;
Jeff Garzik339bf022007-08-15 16:01:32 -0700722 rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
723 if (rc >= 0)
724 info.n_priv_flags = rc;
Jeff Garzikff03d492007-08-15 16:01:08 -0700725 }
Yunsheng Linf9fc54d2018-12-26 19:51:46 +0800726 if (ops->get_regs_len) {
727 int ret = ops->get_regs_len(dev);
728
729 if (ret > 0)
730 info.regdump_len = ret;
731 }
732
Jiri Pirkoc03a14e2013-01-07 09:02:08 +0000733 if (ops->get_eeprom_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 info.eedump_len = ops->get_eeprom_len(dev);
735
Jakub Kicinskiddb6e992019-01-31 10:50:47 -0800736 if (!info.fw_version[0])
737 devlink_compat_running_version(dev, info.fw_version,
738 sizeof(info.fw_version));
Jakub Kicinskiddb6e992019-01-31 10:50:47 -0800739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 if (copy_to_user(useraddr, &info, sizeof(info)))
741 return -EFAULT;
742 return 0;
743}
744
Eric Dumazetf5c445e2010-03-08 12:17:04 -0800745static noinline_for_stack int ethtool_get_sset_info(struct net_device *dev,
chavey97f8aef2010-04-07 21:54:42 -0700746 void __user *useraddr)
Jeff Garzik723b2f52010-03-03 22:51:50 +0000747{
748 struct ethtool_sset_info info;
Jeff Garzik723b2f52010-03-03 22:51:50 +0000749 u64 sset_mask;
750 int i, idx = 0, n_bits = 0, ret, rc;
751 u32 *info_buf = NULL;
752
Jeff Garzik723b2f52010-03-03 22:51:50 +0000753 if (copy_from_user(&info, useraddr, sizeof(info)))
754 return -EFAULT;
755
756 /* store copy of mask, because we zero struct later on */
757 sset_mask = info.sset_mask;
758 if (!sset_mask)
759 return 0;
760
761 /* calculate size of return buffer */
Jeff Garzikd17792e2010-03-04 08:21:53 +0000762 n_bits = hweight64(sset_mask);
Jeff Garzik723b2f52010-03-03 22:51:50 +0000763
764 memset(&info, 0, sizeof(info));
765 info.cmd = ETHTOOL_GSSET_INFO;
766
Kees Cook6396bb22018-06-12 14:03:40 -0700767 info_buf = kcalloc(n_bits, sizeof(u32), GFP_USER);
Jeff Garzik723b2f52010-03-03 22:51:50 +0000768 if (!info_buf)
769 return -ENOMEM;
770
771 /*
772 * fill return buffer based on input bitmask and successful
773 * get_sset_count return
774 */
775 for (i = 0; i < 64; i++) {
776 if (!(sset_mask & (1ULL << i)))
777 continue;
778
Michał Mirosław340ae162011-02-15 16:59:16 +0000779 rc = __ethtool_get_sset_count(dev, i);
Jeff Garzik723b2f52010-03-03 22:51:50 +0000780 if (rc >= 0) {
781 info.sset_mask |= (1ULL << i);
782 info_buf[idx++] = rc;
783 }
784 }
785
786 ret = -EFAULT;
787 if (copy_to_user(useraddr, &info, sizeof(info)))
788 goto out;
789
790 useraddr += offsetof(struct ethtool_sset_info, data);
791 if (copy_to_user(useraddr, info_buf, idx * sizeof(u32)))
792 goto out;
793
794 ret = 0;
795
796out:
797 kfree(info_buf);
798 return ret;
799}
800
chavey97f8aef2010-04-07 21:54:42 -0700801static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
Ben Hutchingsbf988432010-06-28 08:45:58 +0000802 u32 cmd, void __user *useraddr)
Santwona Behera0853ad62008-07-02 03:47:41 -0700803{
Ben Hutchingsbf988432010-06-28 08:45:58 +0000804 struct ethtool_rxnfc info;
805 size_t info_size = sizeof(info);
Ben Hutchings55664f32012-01-03 12:04:51 +0000806 int rc;
Santwona Behera0853ad62008-07-02 03:47:41 -0700807
Santwona Behera59089d82009-02-20 00:58:13 -0800808 if (!dev->ethtool_ops->set_rxnfc)
Santwona Behera0853ad62008-07-02 03:47:41 -0700809 return -EOPNOTSUPP;
810
Ben Hutchingsbf988432010-06-28 08:45:58 +0000811 /* struct ethtool_rxnfc was originally defined for
812 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
813 * members. User-space might still be using that
814 * definition. */
815 if (cmd == ETHTOOL_SRXFH)
816 info_size = (offsetof(struct ethtool_rxnfc, data) +
817 sizeof(info.data));
818
819 if (copy_from_user(&info, useraddr, info_size))
Santwona Behera0853ad62008-07-02 03:47:41 -0700820 return -EFAULT;
821
Ben Hutchings55664f32012-01-03 12:04:51 +0000822 rc = dev->ethtool_ops->set_rxnfc(dev, &info);
823 if (rc)
824 return rc;
825
826 if (cmd == ETHTOOL_SRXCLSRLINS &&
827 copy_to_user(useraddr, &info, info_size))
828 return -EFAULT;
829
830 return 0;
Santwona Behera0853ad62008-07-02 03:47:41 -0700831}
832
chavey97f8aef2010-04-07 21:54:42 -0700833static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
Ben Hutchingsbf988432010-06-28 08:45:58 +0000834 u32 cmd, void __user *useraddr)
Santwona Behera0853ad62008-07-02 03:47:41 -0700835{
836 struct ethtool_rxnfc info;
Ben Hutchingsbf988432010-06-28 08:45:58 +0000837 size_t info_size = sizeof(info);
Santwona Behera59089d82009-02-20 00:58:13 -0800838 const struct ethtool_ops *ops = dev->ethtool_ops;
839 int ret;
840 void *rule_buf = NULL;
Santwona Behera0853ad62008-07-02 03:47:41 -0700841
Santwona Behera59089d82009-02-20 00:58:13 -0800842 if (!ops->get_rxnfc)
Santwona Behera0853ad62008-07-02 03:47:41 -0700843 return -EOPNOTSUPP;
844
Ben Hutchingsbf988432010-06-28 08:45:58 +0000845 /* struct ethtool_rxnfc was originally defined for
846 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
847 * members. User-space might still be using that
848 * definition. */
849 if (cmd == ETHTOOL_GRXFH)
850 info_size = (offsetof(struct ethtool_rxnfc, data) +
851 sizeof(info.data));
852
853 if (copy_from_user(&info, useraddr, info_size))
Santwona Behera0853ad62008-07-02 03:47:41 -0700854 return -EFAULT;
855
Edward Cree84a1d9c42018-03-08 15:45:03 +0000856 /* If FLOW_RSS was requested then user-space must be using the
857 * new definition, as FLOW_RSS is newer.
858 */
859 if (cmd == ETHTOOL_GRXFH && info.flow_type & FLOW_RSS) {
860 info_size = sizeof(info);
861 if (copy_from_user(&info, useraddr, info_size))
862 return -EFAULT;
Wenwen Wangd656fe42018-04-30 12:31:13 -0500863 /* Since malicious users may modify the original data,
864 * we need to check whether FLOW_RSS is still requested.
865 */
866 if (!(info.flow_type & FLOW_RSS))
867 return -EINVAL;
Edward Cree84a1d9c42018-03-08 15:45:03 +0000868 }
869
Wenwen Wang2bb32072018-10-09 08:15:38 -0500870 if (info.cmd != cmd)
871 return -EINVAL;
872
Santwona Behera59089d82009-02-20 00:58:13 -0800873 if (info.cmd == ETHTOOL_GRXCLSRLALL) {
874 if (info.rule_cnt > 0) {
Ben Hutchingsdb048b62010-06-28 08:44:07 +0000875 if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32))
Kees Cook6396bb22018-06-12 14:03:40 -0700876 rule_buf = kcalloc(info.rule_cnt, sizeof(u32),
Ben Hutchingsdb048b62010-06-28 08:44:07 +0000877 GFP_USER);
Santwona Behera59089d82009-02-20 00:58:13 -0800878 if (!rule_buf)
879 return -ENOMEM;
880 }
881 }
Santwona Behera0853ad62008-07-02 03:47:41 -0700882
Santwona Behera59089d82009-02-20 00:58:13 -0800883 ret = ops->get_rxnfc(dev, &info, rule_buf);
884 if (ret < 0)
885 goto err_out;
886
887 ret = -EFAULT;
Ben Hutchingsbf988432010-06-28 08:45:58 +0000888 if (copy_to_user(useraddr, &info, info_size))
Santwona Behera59089d82009-02-20 00:58:13 -0800889 goto err_out;
890
891 if (rule_buf) {
892 useraddr += offsetof(struct ethtool_rxnfc, rule_locs);
893 if (copy_to_user(useraddr, rule_buf,
894 info.rule_cnt * sizeof(u32)))
895 goto err_out;
896 }
897 ret = 0;
898
899err_out:
Wei Yongjunc9cacec2009-03-31 15:06:26 -0700900 kfree(rule_buf);
Santwona Behera59089d82009-02-20 00:58:13 -0800901
902 return ret;
Santwona Behera0853ad62008-07-02 03:47:41 -0700903}
904
Venkata Duvvuru3de0b592014-04-21 15:37:59 +0530905static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,
906 struct ethtool_rxnfc *rx_rings,
907 u32 size)
908{
Ben Hutchingsfb95cd82014-05-15 00:46:45 +0100909 int i;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +0530910
911 if (copy_from_user(indir, useraddr, size * sizeof(indir[0])))
Ben Hutchingsfb95cd82014-05-15 00:46:45 +0100912 return -EFAULT;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +0530913
914 /* Validate ring indices */
Ben Hutchingsfb95cd82014-05-15 00:46:45 +0100915 for (i = 0; i < size; i++)
916 if (indir[i] >= rx_rings->data)
917 return -EINVAL;
918
919 return 0;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +0530920}
921
Kim Jonesba905f52016-02-02 03:51:16 +0000922u8 netdev_rss_key[NETDEV_RSS_KEY_LEN] __read_mostly;
Eric Dumazet960fb622014-11-16 06:23:05 -0800923
924void netdev_rss_key_fill(void *buffer, size_t len)
925{
926 BUG_ON(len > sizeof(netdev_rss_key));
927 net_get_random_once(netdev_rss_key, sizeof(netdev_rss_key));
928 memcpy(buffer, netdev_rss_key, len);
929}
930EXPORT_SYMBOL(netdev_rss_key_fill);
931
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000932static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
933 void __user *useraddr)
934{
Ben Hutchings7850f632011-12-15 13:55:01 +0000935 u32 user_size, dev_size;
936 u32 *indir;
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000937 int ret;
938
Ben Hutchings7850f632011-12-15 13:55:01 +0000939 if (!dev->ethtool_ops->get_rxfh_indir_size ||
Ben Hutchingsfe62d002014-05-15 01:25:27 +0100940 !dev->ethtool_ops->get_rxfh)
Ben Hutchings7850f632011-12-15 13:55:01 +0000941 return -EOPNOTSUPP;
942 dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
943 if (dev_size == 0)
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000944 return -EOPNOTSUPP;
945
Ben Hutchings7850f632011-12-15 13:55:01 +0000946 if (copy_from_user(&user_size,
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000947 useraddr + offsetof(struct ethtool_rxfh_indir, size),
Ben Hutchings7850f632011-12-15 13:55:01 +0000948 sizeof(user_size)))
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000949 return -EFAULT;
950
Ben Hutchings7850f632011-12-15 13:55:01 +0000951 if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh_indir, size),
952 &dev_size, sizeof(dev_size)))
953 return -EFAULT;
954
955 /* If the user buffer size is 0, this is just a query for the
956 * device table size. Otherwise, if it's smaller than the
957 * device table size it's an error.
958 */
959 if (user_size < dev_size)
960 return user_size == 0 ? 0 : -EINVAL;
961
962 indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000963 if (!indir)
964 return -ENOMEM;
965
Eyal Perry892311f2014-12-02 18:12:10 +0200966 ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL);
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000967 if (ret)
968 goto out;
969
Ben Hutchings7850f632011-12-15 13:55:01 +0000970 if (copy_to_user(useraddr +
971 offsetof(struct ethtool_rxfh_indir, ring_index[0]),
972 indir, dev_size * sizeof(indir[0])))
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000973 ret = -EFAULT;
974
975out:
976 kfree(indir);
977 return ret;
978}
979
980static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
981 void __user *useraddr)
982{
Ben Hutchings7850f632011-12-15 13:55:01 +0000983 struct ethtool_rxnfc rx_rings;
984 u32 user_size, dev_size, i;
985 u32 *indir;
Jiri Pirkoc03a14e2013-01-07 09:02:08 +0000986 const struct ethtool_ops *ops = dev->ethtool_ops;
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000987 int ret;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +0530988 u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]);
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000989
Ben Hutchingsfe62d002014-05-15 01:25:27 +0100990 if (!ops->get_rxfh_indir_size || !ops->set_rxfh ||
Jiri Pirkoc03a14e2013-01-07 09:02:08 +0000991 !ops->get_rxnfc)
Ben Hutchings7850f632011-12-15 13:55:01 +0000992 return -EOPNOTSUPP;
Jiri Pirkoc03a14e2013-01-07 09:02:08 +0000993
994 dev_size = ops->get_rxfh_indir_size(dev);
Ben Hutchings7850f632011-12-15 13:55:01 +0000995 if (dev_size == 0)
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000996 return -EOPNOTSUPP;
997
Ben Hutchings7850f632011-12-15 13:55:01 +0000998 if (copy_from_user(&user_size,
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000999 useraddr + offsetof(struct ethtool_rxfh_indir, size),
Ben Hutchings7850f632011-12-15 13:55:01 +00001000 sizeof(user_size)))
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001001 return -EFAULT;
1002
Ben Hutchings278bc422011-12-15 13:56:49 +00001003 if (user_size != 0 && user_size != dev_size)
Ben Hutchings7850f632011-12-15 13:55:01 +00001004 return -EINVAL;
1005
1006 indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001007 if (!indir)
1008 return -ENOMEM;
1009
Ben Hutchings7850f632011-12-15 13:55:01 +00001010 rx_rings.cmd = ETHTOOL_GRXRINGS;
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001011 ret = ops->get_rxnfc(dev, &rx_rings, NULL);
Ben Hutchings7850f632011-12-15 13:55:01 +00001012 if (ret)
1013 goto out;
Ben Hutchings278bc422011-12-15 13:56:49 +00001014
1015 if (user_size == 0) {
1016 for (i = 0; i < dev_size; i++)
1017 indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
1018 } else {
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301019 ret = ethtool_copy_validate_indir(indir,
1020 useraddr + ringidx_offset,
1021 &rx_rings,
1022 dev_size);
1023 if (ret)
Ben Hutchings7850f632011-12-15 13:55:01 +00001024 goto out;
Ben Hutchings7850f632011-12-15 13:55:01 +00001025 }
1026
Eyal Perry892311f2014-12-02 18:12:10 +02001027 ret = ops->set_rxfh(dev, indir, NULL, ETH_RSS_HASH_NO_CHANGE);
Keller, Jacob Ed4ab4282016-02-08 16:05:03 -08001028 if (ret)
1029 goto out;
1030
1031 /* indicate whether rxfh was set to default */
1032 if (user_size == 0)
1033 dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
1034 else
1035 dev->priv_flags |= IFF_RXFH_CONFIGURED;
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001036
1037out:
1038 kfree(indir);
1039 return ret;
1040}
1041
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301042static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
1043 void __user *useraddr)
1044{
1045 int ret;
1046 const struct ethtool_ops *ops = dev->ethtool_ops;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001047 u32 user_indir_size, user_key_size;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301048 u32 dev_indir_size = 0, dev_key_size = 0;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001049 struct ethtool_rxfh rxfh;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301050 u32 total_size;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001051 u32 indir_bytes;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301052 u32 *indir = NULL;
Eyal Perry892311f2014-12-02 18:12:10 +02001053 u8 dev_hfunc = 0;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301054 u8 *hkey = NULL;
1055 u8 *rss_config;
1056
Eyal Perry892311f2014-12-02 18:12:10 +02001057 if (!ops->get_rxfh)
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301058 return -EOPNOTSUPP;
1059
1060 if (ops->get_rxfh_indir_size)
1061 dev_indir_size = ops->get_rxfh_indir_size(dev);
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301062 if (ops->get_rxfh_key_size)
1063 dev_key_size = ops->get_rxfh_key_size(dev);
1064
Ben Hutchingsf062a382014-05-15 16:28:07 +01001065 if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301066 return -EFAULT;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001067 user_indir_size = rxfh.indir_size;
1068 user_key_size = rxfh.key_size;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301069
Ben Hutchingsf062a382014-05-15 16:28:07 +01001070 /* Check that reserved fields are 0 for now */
Edward Cree84a1d9c42018-03-08 15:45:03 +00001071 if (rxfh.rsvd8[0] || rxfh.rsvd8[1] || rxfh.rsvd8[2] || rxfh.rsvd32)
Ben Hutchingsf062a382014-05-15 16:28:07 +01001072 return -EINVAL;
Edward Cree84a1d9c42018-03-08 15:45:03 +00001073 /* Most drivers don't handle rss_context, check it's 0 as well */
1074 if (rxfh.rss_context && !ops->get_rxfh_context)
1075 return -EOPNOTSUPP;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001076
1077 rxfh.indir_size = dev_indir_size;
1078 rxfh.key_size = dev_key_size;
1079 if (copy_to_user(useraddr, &rxfh, sizeof(rxfh)))
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301080 return -EFAULT;
1081
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301082 if ((user_indir_size && (user_indir_size != dev_indir_size)) ||
1083 (user_key_size && (user_key_size != dev_key_size)))
1084 return -EINVAL;
1085
1086 indir_bytes = user_indir_size * sizeof(indir[0]);
1087 total_size = indir_bytes + user_key_size;
1088 rss_config = kzalloc(total_size, GFP_USER);
1089 if (!rss_config)
1090 return -ENOMEM;
1091
1092 if (user_indir_size)
1093 indir = (u32 *)rss_config;
1094
1095 if (user_key_size)
1096 hkey = rss_config + indir_bytes;
1097
Edward Cree84a1d9c42018-03-08 15:45:03 +00001098 if (rxfh.rss_context)
1099 ret = dev->ethtool_ops->get_rxfh_context(dev, indir, hkey,
1100 &dev_hfunc,
1101 rxfh.rss_context);
1102 else
1103 ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc);
Eyal Perry892311f2014-12-02 18:12:10 +02001104 if (ret)
1105 goto out;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301106
Eyal Perry892311f2014-12-02 18:12:10 +02001107 if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, hfunc),
1108 &dev_hfunc, sizeof(rxfh.hfunc))) {
1109 ret = -EFAULT;
1110 } else if (copy_to_user(useraddr +
1111 offsetof(struct ethtool_rxfh, rss_config[0]),
1112 rss_config, total_size)) {
1113 ret = -EFAULT;
1114 }
1115out:
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301116 kfree(rss_config);
1117
1118 return ret;
1119}
1120
1121static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
1122 void __user *useraddr)
1123{
1124 int ret;
1125 const struct ethtool_ops *ops = dev->ethtool_ops;
1126 struct ethtool_rxnfc rx_rings;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001127 struct ethtool_rxfh rxfh;
1128 u32 dev_indir_size = 0, dev_key_size = 0, i;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301129 u32 *indir = NULL, indir_bytes = 0;
1130 u8 *hkey = NULL;
1131 u8 *rss_config;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301132 u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
Edward Cree84a1d9c42018-03-08 15:45:03 +00001133 bool delete = false;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301134
Eyal Perry892311f2014-12-02 18:12:10 +02001135 if (!ops->get_rxnfc || !ops->set_rxfh)
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301136 return -EOPNOTSUPP;
1137
1138 if (ops->get_rxfh_indir_size)
1139 dev_indir_size = ops->get_rxfh_indir_size(dev);
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301140 if (ops->get_rxfh_key_size)
Dan Carpenterd340c862015-02-20 13:54:05 +03001141 dev_key_size = ops->get_rxfh_key_size(dev);
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301142
Ben Hutchingsf062a382014-05-15 16:28:07 +01001143 if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301144 return -EFAULT;
1145
Ben Hutchingsf062a382014-05-15 16:28:07 +01001146 /* Check that reserved fields are 0 for now */
Edward Cree84a1d9c42018-03-08 15:45:03 +00001147 if (rxfh.rsvd8[0] || rxfh.rsvd8[1] || rxfh.rsvd8[2] || rxfh.rsvd32)
Ben Hutchingsf062a382014-05-15 16:28:07 +01001148 return -EINVAL;
Edward Cree84a1d9c42018-03-08 15:45:03 +00001149 /* Most drivers don't handle rss_context, check it's 0 as well */
1150 if (rxfh.rss_context && !ops->set_rxfh_context)
1151 return -EOPNOTSUPP;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001152
Eyal Perry892311f2014-12-02 18:12:10 +02001153 /* If either indir, hash key or function is valid, proceed further.
1154 * Must request at least one change: indir size, hash key or function.
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301155 */
Ben Hutchingsf062a382014-05-15 16:28:07 +01001156 if ((rxfh.indir_size &&
1157 rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE &&
1158 rxfh.indir_size != dev_indir_size) ||
1159 (rxfh.key_size && (rxfh.key_size != dev_key_size)) ||
1160 (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE &&
Eyal Perry892311f2014-12-02 18:12:10 +02001161 rxfh.key_size == 0 && rxfh.hfunc == ETH_RSS_HASH_NO_CHANGE))
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301162 return -EINVAL;
1163
Ben Hutchingsf062a382014-05-15 16:28:07 +01001164 if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301165 indir_bytes = dev_indir_size * sizeof(indir[0]);
1166
Ben Hutchingsf062a382014-05-15 16:28:07 +01001167 rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER);
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301168 if (!rss_config)
1169 return -ENOMEM;
1170
1171 rx_rings.cmd = ETHTOOL_GRXRINGS;
1172 ret = ops->get_rxnfc(dev, &rx_rings, NULL);
1173 if (ret)
1174 goto out;
1175
Edward Cree84a1d9c42018-03-08 15:45:03 +00001176 /* rxfh.indir_size == 0 means reset the indir table to default (master
1177 * context) or delete the context (other RSS contexts).
Ben Hutchingsf062a382014-05-15 16:28:07 +01001178 * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged.
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301179 */
Ben Hutchingsf062a382014-05-15 16:28:07 +01001180 if (rxfh.indir_size &&
1181 rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) {
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301182 indir = (u32 *)rss_config;
1183 ret = ethtool_copy_validate_indir(indir,
1184 useraddr + rss_cfg_offset,
1185 &rx_rings,
Ben Hutchingsf062a382014-05-15 16:28:07 +01001186 rxfh.indir_size);
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301187 if (ret)
1188 goto out;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001189 } else if (rxfh.indir_size == 0) {
Edward Cree84a1d9c42018-03-08 15:45:03 +00001190 if (rxfh.rss_context == 0) {
1191 indir = (u32 *)rss_config;
1192 for (i = 0; i < dev_indir_size; i++)
1193 indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
1194 } else {
1195 delete = true;
1196 }
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301197 }
1198
Ben Hutchingsf062a382014-05-15 16:28:07 +01001199 if (rxfh.key_size) {
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301200 hkey = rss_config + indir_bytes;
1201 if (copy_from_user(hkey,
1202 useraddr + rss_cfg_offset + indir_bytes,
Ben Hutchingsf062a382014-05-15 16:28:07 +01001203 rxfh.key_size)) {
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301204 ret = -EFAULT;
1205 goto out;
1206 }
1207 }
1208
Edward Cree84a1d9c42018-03-08 15:45:03 +00001209 if (rxfh.rss_context)
1210 ret = ops->set_rxfh_context(dev, indir, hkey, rxfh.hfunc,
1211 &rxfh.rss_context, delete);
1212 else
1213 ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc);
Keller, Jacob Ed4ab4282016-02-08 16:05:03 -08001214 if (ret)
1215 goto out;
1216
Edward Cree84a1d9c42018-03-08 15:45:03 +00001217 if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, rss_context),
1218 &rxfh.rss_context, sizeof(rxfh.rss_context)))
1219 ret = -EFAULT;
1220
1221 if (!rxfh.rss_context) {
1222 /* indicate whether rxfh was set to default */
1223 if (rxfh.indir_size == 0)
1224 dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
1225 else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
1226 dev->priv_flags |= IFF_RXFH_CONFIGURED;
1227 }
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301228
1229out:
1230 kfree(rss_config);
1231 return ret;
1232}
1233
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
1235{
1236 struct ethtool_regs regs;
Stephen Hemminger76fd8592006-09-08 11:16:13 -07001237 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 void *regbuf;
1239 int reglen, ret;
1240
1241 if (!ops->get_regs || !ops->get_regs_len)
1242 return -EOPNOTSUPP;
1243
1244 if (copy_from_user(&regs, useraddr, sizeof(regs)))
1245 return -EFAULT;
1246
1247 reglen = ops->get_regs_len(dev);
Yunsheng Linf9fc54d2018-12-26 19:51:46 +08001248 if (reglen <= 0)
1249 return reglen;
1250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 if (regs.len > reglen)
1252 regs.len = reglen;
1253
Dan Carpenteref76c772019-02-01 11:24:06 +03001254 regbuf = vzalloc(reglen);
1255 if (!regbuf)
1256 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
Vivien Didelot0ee4e762019-06-03 16:57:13 -04001258 if (regs.len < reglen)
1259 reglen = regs.len;
1260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 ops->get_regs(dev, &regs, regbuf);
1262
1263 ret = -EFAULT;
1264 if (copy_to_user(useraddr, &regs, sizeof(regs)))
1265 goto out;
1266 useraddr += offsetof(struct ethtool_regs, data);
Vivien Didelot0ee4e762019-06-03 16:57:13 -04001267 if (copy_to_user(useraddr, regbuf, reglen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 goto out;
1269 ret = 0;
1270
1271 out:
Ben Hutchingsa77f5db2010-09-20 08:42:17 +00001272 vfree(regbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 return ret;
1274}
1275
Ben Hutchingsd73d3a82009-10-05 10:59:58 +00001276static int ethtool_reset(struct net_device *dev, char __user *useraddr)
1277{
1278 struct ethtool_value reset;
1279 int ret;
1280
1281 if (!dev->ethtool_ops->reset)
1282 return -EOPNOTSUPP;
1283
1284 if (copy_from_user(&reset, useraddr, sizeof(reset)))
1285 return -EFAULT;
1286
1287 ret = dev->ethtool_ops->reset(dev, &reset.data);
1288 if (ret)
1289 return ret;
1290
1291 if (copy_to_user(useraddr, &reset, sizeof(reset)))
1292 return -EFAULT;
1293 return 0;
1294}
1295
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
1297{
zhanglin5ff223e2019-10-26 15:54:16 +08001298 struct ethtool_wolinfo wol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
1300 if (!dev->ethtool_ops->get_wol)
1301 return -EOPNOTSUPP;
1302
zhanglin5ff223e2019-10-26 15:54:16 +08001303 memset(&wol, 0, sizeof(struct ethtool_wolinfo));
1304 wol.cmd = ETHTOOL_GWOL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 dev->ethtool_ops->get_wol(dev, &wol);
1306
1307 if (copy_to_user(useraddr, &wol, sizeof(wol)))
1308 return -EFAULT;
1309 return 0;
1310}
1311
1312static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
1313{
1314 struct ethtool_wolinfo wol;
Heiner Kallweit61941142018-09-24 21:58:59 +02001315 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
1317 if (!dev->ethtool_ops->set_wol)
1318 return -EOPNOTSUPP;
1319
1320 if (copy_from_user(&wol, useraddr, sizeof(wol)))
1321 return -EFAULT;
1322
Heiner Kallweit61941142018-09-24 21:58:59 +02001323 ret = dev->ethtool_ops->set_wol(dev, &wol);
1324 if (ret)
1325 return ret;
1326
1327 dev->wol_enabled = !!wol.wolopts;
Michal Kubecek67bffa72020-01-26 23:11:19 +01001328 ethtool_notify(dev, ETHTOOL_MSG_WOL_NTF, NULL);
Heiner Kallweit61941142018-09-24 21:58:59 +02001329
1330 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331}
1332
Yuval Mintz80f12ec2012-06-06 17:13:06 +00001333static int ethtool_get_eee(struct net_device *dev, char __user *useraddr)
1334{
1335 struct ethtool_eee edata;
1336 int rc;
1337
1338 if (!dev->ethtool_ops->get_eee)
1339 return -EOPNOTSUPP;
1340
1341 memset(&edata, 0, sizeof(struct ethtool_eee));
1342 edata.cmd = ETHTOOL_GEEE;
1343 rc = dev->ethtool_ops->get_eee(dev, &edata);
1344
1345 if (rc)
1346 return rc;
1347
1348 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1349 return -EFAULT;
1350
1351 return 0;
1352}
1353
1354static int ethtool_set_eee(struct net_device *dev, char __user *useraddr)
1355{
1356 struct ethtool_eee edata;
1357
1358 if (!dev->ethtool_ops->set_eee)
1359 return -EOPNOTSUPP;
1360
1361 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1362 return -EFAULT;
1363
1364 return dev->ethtool_ops->set_eee(dev, &edata);
1365}
1366
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367static int ethtool_nway_reset(struct net_device *dev)
1368{
1369 if (!dev->ethtool_ops->nway_reset)
1370 return -EOPNOTSUPP;
1371
1372 return dev->ethtool_ops->nway_reset(dev);
1373}
1374
Ben Hutchingse596e6e2010-12-09 12:08:35 +00001375static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
1376{
1377 struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };
Michal Kubecek3d2b8472019-12-27 15:56:23 +01001378 int link = __ethtool_get_link(dev);
Ben Hutchingse596e6e2010-12-09 12:08:35 +00001379
Michal Kubecek3d2b8472019-12-27 15:56:23 +01001380 if (link < 0)
1381 return link;
Ben Hutchingse596e6e2010-12-09 12:08:35 +00001382
Michal Kubecek3d2b8472019-12-27 15:56:23 +01001383 edata.data = link;
Ben Hutchingse596e6e2010-12-09 12:08:35 +00001384 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1385 return -EFAULT;
1386 return 0;
1387}
1388
Ben Hutchings081d0942012-04-12 00:42:12 +00001389static int ethtool_get_any_eeprom(struct net_device *dev, void __user *useraddr,
1390 int (*getter)(struct net_device *,
1391 struct ethtool_eeprom *, u8 *),
1392 u32 total_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393{
1394 struct ethtool_eeprom eeprom;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001395 void __user *userbuf = useraddr + sizeof(eeprom);
1396 u32 bytes_remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 u8 *data;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001398 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
1401 return -EFAULT;
1402
1403 /* Check for wrap and zero */
1404 if (eeprom.offset + eeprom.len <= eeprom.offset)
1405 return -EINVAL;
1406
1407 /* Check for exceeding total eeprom len */
Ben Hutchings081d0942012-04-12 00:42:12 +00001408 if (eeprom.offset + eeprom.len > total_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 return -EINVAL;
1410
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001411 data = kmalloc(PAGE_SIZE, GFP_USER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 if (!data)
1413 return -ENOMEM;
1414
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001415 bytes_remaining = eeprom.len;
1416 while (bytes_remaining > 0) {
1417 eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
Ben Hutchings081d0942012-04-12 00:42:12 +00001419 ret = getter(dev, &eeprom, data);
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001420 if (ret)
1421 break;
1422 if (copy_to_user(userbuf, data, eeprom.len)) {
1423 ret = -EFAULT;
1424 break;
1425 }
1426 userbuf += eeprom.len;
1427 eeprom.offset += eeprom.len;
1428 bytes_remaining -= eeprom.len;
1429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
Mandeep Singh Bainesc5835df2008-04-24 20:55:56 -07001431 eeprom.len = userbuf - (useraddr + sizeof(eeprom));
1432 eeprom.offset -= eeprom.len;
1433 if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
1434 ret = -EFAULT;
1435
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 kfree(data);
1437 return ret;
1438}
1439
Ben Hutchings081d0942012-04-12 00:42:12 +00001440static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
1441{
1442 const struct ethtool_ops *ops = dev->ethtool_ops;
1443
Guenter Roecke0fb6fb2014-10-30 20:50:15 -07001444 if (!ops->get_eeprom || !ops->get_eeprom_len ||
1445 !ops->get_eeprom_len(dev))
Ben Hutchings081d0942012-04-12 00:42:12 +00001446 return -EOPNOTSUPP;
1447
1448 return ethtool_get_any_eeprom(dev, useraddr, ops->get_eeprom,
1449 ops->get_eeprom_len(dev));
1450}
1451
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
1453{
1454 struct ethtool_eeprom eeprom;
Stephen Hemminger76fd8592006-09-08 11:16:13 -07001455 const struct ethtool_ops *ops = dev->ethtool_ops;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001456 void __user *userbuf = useraddr + sizeof(eeprom);
1457 u32 bytes_remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 u8 *data;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001459 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
Guenter Roecke0fb6fb2014-10-30 20:50:15 -07001461 if (!ops->set_eeprom || !ops->get_eeprom_len ||
1462 !ops->get_eeprom_len(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 return -EOPNOTSUPP;
1464
1465 if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
1466 return -EFAULT;
1467
1468 /* Check for wrap and zero */
1469 if (eeprom.offset + eeprom.len <= eeprom.offset)
1470 return -EINVAL;
1471
1472 /* Check for exceeding total eeprom len */
1473 if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
1474 return -EINVAL;
1475
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001476 data = kmalloc(PAGE_SIZE, GFP_USER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 if (!data)
1478 return -ENOMEM;
1479
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001480 bytes_remaining = eeprom.len;
1481 while (bytes_remaining > 0) {
1482 eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001484 if (copy_from_user(data, userbuf, eeprom.len)) {
1485 ret = -EFAULT;
1486 break;
1487 }
1488 ret = ops->set_eeprom(dev, &eeprom, data);
1489 if (ret)
1490 break;
1491 userbuf += eeprom.len;
1492 eeprom.offset += eeprom.len;
1493 bytes_remaining -= eeprom.len;
1494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 kfree(data);
1497 return ret;
1498}
1499
chavey97f8aef2010-04-07 21:54:42 -07001500static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev,
1501 void __user *useraddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502{
Roland Dreier8e557422010-02-11 12:14:23 -08001503 struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505 if (!dev->ethtool_ops->get_coalesce)
1506 return -EOPNOTSUPP;
1507
1508 dev->ethtool_ops->get_coalesce(dev, &coalesce);
1509
1510 if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
1511 return -EFAULT;
1512 return 0;
1513}
1514
Jakub Kicinski95cddcb2020-03-04 21:15:31 -08001515static bool
1516ethtool_set_coalesce_supported(struct net_device *dev,
1517 struct ethtool_coalesce *coalesce)
1518{
1519 u32 supported_params = dev->ethtool_ops->supported_coalesce_params;
1520 u32 nonzero_params = 0;
1521
Jakub Kicinski95cddcb2020-03-04 21:15:31 -08001522 if (coalesce->rx_coalesce_usecs)
1523 nonzero_params |= ETHTOOL_COALESCE_RX_USECS;
1524 if (coalesce->rx_max_coalesced_frames)
1525 nonzero_params |= ETHTOOL_COALESCE_RX_MAX_FRAMES;
1526 if (coalesce->rx_coalesce_usecs_irq)
1527 nonzero_params |= ETHTOOL_COALESCE_RX_USECS_IRQ;
1528 if (coalesce->rx_max_coalesced_frames_irq)
1529 nonzero_params |= ETHTOOL_COALESCE_RX_MAX_FRAMES_IRQ;
1530 if (coalesce->tx_coalesce_usecs)
1531 nonzero_params |= ETHTOOL_COALESCE_TX_USECS;
1532 if (coalesce->tx_max_coalesced_frames)
1533 nonzero_params |= ETHTOOL_COALESCE_TX_MAX_FRAMES;
1534 if (coalesce->tx_coalesce_usecs_irq)
1535 nonzero_params |= ETHTOOL_COALESCE_TX_USECS_IRQ;
1536 if (coalesce->tx_max_coalesced_frames_irq)
1537 nonzero_params |= ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ;
1538 if (coalesce->stats_block_coalesce_usecs)
1539 nonzero_params |= ETHTOOL_COALESCE_STATS_BLOCK_USECS;
1540 if (coalesce->use_adaptive_rx_coalesce)
1541 nonzero_params |= ETHTOOL_COALESCE_USE_ADAPTIVE_RX;
1542 if (coalesce->use_adaptive_tx_coalesce)
1543 nonzero_params |= ETHTOOL_COALESCE_USE_ADAPTIVE_TX;
1544 if (coalesce->pkt_rate_low)
1545 nonzero_params |= ETHTOOL_COALESCE_PKT_RATE_LOW;
1546 if (coalesce->rx_coalesce_usecs_low)
1547 nonzero_params |= ETHTOOL_COALESCE_RX_USECS_LOW;
1548 if (coalesce->rx_max_coalesced_frames_low)
1549 nonzero_params |= ETHTOOL_COALESCE_RX_MAX_FRAMES_LOW;
1550 if (coalesce->tx_coalesce_usecs_low)
1551 nonzero_params |= ETHTOOL_COALESCE_TX_USECS_LOW;
1552 if (coalesce->tx_max_coalesced_frames_low)
1553 nonzero_params |= ETHTOOL_COALESCE_TX_MAX_FRAMES_LOW;
1554 if (coalesce->pkt_rate_high)
1555 nonzero_params |= ETHTOOL_COALESCE_PKT_RATE_HIGH;
1556 if (coalesce->rx_coalesce_usecs_high)
1557 nonzero_params |= ETHTOOL_COALESCE_RX_USECS_HIGH;
1558 if (coalesce->rx_max_coalesced_frames_high)
1559 nonzero_params |= ETHTOOL_COALESCE_RX_MAX_FRAMES_HIGH;
1560 if (coalesce->tx_coalesce_usecs_high)
1561 nonzero_params |= ETHTOOL_COALESCE_TX_USECS_HIGH;
1562 if (coalesce->tx_max_coalesced_frames_high)
1563 nonzero_params |= ETHTOOL_COALESCE_TX_MAX_FRAMES_HIGH;
1564 if (coalesce->rate_sample_interval)
1565 nonzero_params |= ETHTOOL_COALESCE_RATE_SAMPLE_INTERVAL;
1566
1567 return (supported_params & nonzero_params) == nonzero_params;
1568}
1569
chavey97f8aef2010-04-07 21:54:42 -07001570static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
1571 void __user *useraddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572{
1573 struct ethtool_coalesce coalesce;
1574
David S. Millerfa04ae52005-06-06 15:07:19 -07001575 if (!dev->ethtool_ops->set_coalesce)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 return -EOPNOTSUPP;
1577
1578 if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
1579 return -EFAULT;
1580
Jakub Kicinski95cddcb2020-03-04 21:15:31 -08001581 if (!ethtool_set_coalesce_supported(dev, &coalesce))
1582 return -EOPNOTSUPP;
1583
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 return dev->ethtool_ops->set_coalesce(dev, &coalesce);
1585}
1586
1587static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
1588{
Roland Dreier8e557422010-02-11 12:14:23 -08001589 struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
1591 if (!dev->ethtool_ops->get_ringparam)
1592 return -EOPNOTSUPP;
1593
1594 dev->ethtool_ops->get_ringparam(dev, &ringparam);
1595
1596 if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
1597 return -EFAULT;
1598 return 0;
1599}
1600
1601static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
1602{
Eugenia Emantayev37e2d992018-01-08 16:00:24 +02001603 struct ethtool_ringparam ringparam, max = { .cmd = ETHTOOL_GRINGPARAM };
Michal Kubecekbc9d1c92020-03-12 21:08:33 +01001604 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
Eugenia Emantayev37e2d992018-01-08 16:00:24 +02001606 if (!dev->ethtool_ops->set_ringparam || !dev->ethtool_ops->get_ringparam)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 return -EOPNOTSUPP;
1608
1609 if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
1610 return -EFAULT;
1611
Eugenia Emantayev37e2d992018-01-08 16:00:24 +02001612 dev->ethtool_ops->get_ringparam(dev, &max);
1613
1614 /* ensure new ring parameters are within the maximums */
1615 if (ringparam.rx_pending > max.rx_max_pending ||
1616 ringparam.rx_mini_pending > max.rx_mini_max_pending ||
1617 ringparam.rx_jumbo_pending > max.rx_jumbo_max_pending ||
1618 ringparam.tx_pending > max.tx_max_pending)
1619 return -EINVAL;
1620
Michal Kubecekbc9d1c92020-03-12 21:08:33 +01001621 ret = dev->ethtool_ops->set_ringparam(dev, &ringparam);
1622 if (!ret)
1623 ethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF, NULL);
1624 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625}
1626
amit salecha8b5933c2011-04-07 01:58:42 +00001627static noinline_for_stack int ethtool_get_channels(struct net_device *dev,
1628 void __user *useraddr)
1629{
1630 struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
1631
1632 if (!dev->ethtool_ops->get_channels)
1633 return -EOPNOTSUPP;
1634
1635 dev->ethtool_ops->get_channels(dev, &channels);
1636
1637 if (copy_to_user(useraddr, &channels, sizeof(channels)))
1638 return -EFAULT;
1639 return 0;
1640}
1641
1642static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
1643 void __user *useraddr)
1644{
Jakub Kicinskib8c8a2e2018-10-01 14:51:35 +02001645 struct ethtool_channels channels, curr = { .cmd = ETHTOOL_GCHANNELS };
Jakub Kicinski1661d342018-10-01 14:51:36 +02001646 u16 from_channel, to_channel;
Keller, Jacob Ed4ab4282016-02-08 16:05:03 -08001647 u32 max_rx_in_use = 0;
Jakub Kicinski1661d342018-10-01 14:51:36 +02001648 unsigned int i;
Michal Kubecek546379b2020-03-12 21:08:48 +01001649 int ret;
amit salecha8b5933c2011-04-07 01:58:42 +00001650
Keller, Jacob E8bf36862016-02-08 16:05:04 -08001651 if (!dev->ethtool_ops->set_channels || !dev->ethtool_ops->get_channels)
amit salecha8b5933c2011-04-07 01:58:42 +00001652 return -EOPNOTSUPP;
1653
1654 if (copy_from_user(&channels, useraddr, sizeof(channels)))
1655 return -EFAULT;
1656
Jakub Kicinskib8c8a2e2018-10-01 14:51:35 +02001657 dev->ethtool_ops->get_channels(dev, &curr);
Keller, Jacob E8bf36862016-02-08 16:05:04 -08001658
1659 /* ensure new counts are within the maximums */
Jakub Kicinskib8c8a2e2018-10-01 14:51:35 +02001660 if (channels.rx_count > curr.max_rx ||
1661 channels.tx_count > curr.max_tx ||
1662 channels.combined_count > curr.max_combined ||
1663 channels.other_count > curr.max_other)
Keller, Jacob E8bf36862016-02-08 16:05:04 -08001664 return -EINVAL;
1665
Keller, Jacob Ed4ab4282016-02-08 16:05:03 -08001666 /* ensure the new Rx count fits within the configured Rx flow
1667 * indirection table settings */
1668 if (netif_is_rxfh_configured(dev) &&
1669 !ethtool_get_max_rxfh_channel(dev, &max_rx_in_use) &&
1670 (channels.combined_count + channels.rx_count) <= max_rx_in_use)
1671 return -EINVAL;
1672
Jakub Kicinski1661d342018-10-01 14:51:36 +02001673 /* Disabling channels, query zero-copy AF_XDP sockets */
1674 from_channel = channels.combined_count +
1675 min(channels.rx_count, channels.tx_count);
1676 to_channel = curr.combined_count + max(curr.rx_count, curr.tx_count);
1677 for (i = from_channel; i < to_channel; i++)
1678 if (xdp_get_umem_from_qid(dev, i))
1679 return -EINVAL;
1680
Michal Kubecek546379b2020-03-12 21:08:48 +01001681 ret = dev->ethtool_ops->set_channels(dev, &channels);
1682 if (!ret)
1683 ethtool_notify(dev, ETHTOOL_MSG_CHANNELS_NTF, NULL);
1684 return ret;
amit salecha8b5933c2011-04-07 01:58:42 +00001685}
1686
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
1688{
Li RongQinge83887f2019-02-27 20:47:57 +08001689 struct ethtool_pauseparam pauseparam = { .cmd = ETHTOOL_GPAUSEPARAM };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691 if (!dev->ethtool_ops->get_pauseparam)
1692 return -EOPNOTSUPP;
1693
1694 dev->ethtool_ops->get_pauseparam(dev, &pauseparam);
1695
1696 if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
1697 return -EFAULT;
1698 return 0;
1699}
1700
1701static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
1702{
1703 struct ethtool_pauseparam pauseparam;
1704
Jeff Garzike1b90c42006-07-17 12:54:40 -04001705 if (!dev->ethtool_ops->set_pauseparam)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 return -EOPNOTSUPP;
1707
1708 if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
1709 return -EFAULT;
1710
1711 return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
1712}
1713
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
1715{
1716 struct ethtool_test test;
Stephen Hemminger76fd8592006-09-08 11:16:13 -07001717 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 u64 *data;
Jeff Garzikff03d492007-08-15 16:01:08 -07001719 int ret, test_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001721 if (!ops->self_test || !ops->get_sset_count)
Jeff Garzikff03d492007-08-15 16:01:08 -07001722 return -EOPNOTSUPP;
1723
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001724 test_len = ops->get_sset_count(dev, ETH_SS_TEST);
Jeff Garzikff03d492007-08-15 16:01:08 -07001725 if (test_len < 0)
1726 return test_len;
1727 WARN_ON(test_len == 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
1729 if (copy_from_user(&test, useraddr, sizeof(test)))
1730 return -EFAULT;
1731
Jeff Garzikff03d492007-08-15 16:01:08 -07001732 test.len = test_len;
Kees Cook6da2ec52018-06-12 13:55:00 -07001733 data = kmalloc_array(test_len, sizeof(u64), GFP_USER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 if (!data)
1735 return -ENOMEM;
1736
1737 ops->self_test(dev, &test, data);
1738
1739 ret = -EFAULT;
1740 if (copy_to_user(useraddr, &test, sizeof(test)))
1741 goto out;
1742 useraddr += sizeof(test);
1743 if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
1744 goto out;
1745 ret = 0;
1746
1747 out:
1748 kfree(data);
1749 return ret;
1750}
1751
1752static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
1753{
1754 struct ethtool_gstrings gstrings;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 u8 *data;
1756 int ret;
1757
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
1759 return -EFAULT;
1760
Michał Mirosław340ae162011-02-15 16:59:16 +00001761 ret = __ethtool_get_sset_count(dev, gstrings.string_set);
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001762 if (ret < 0)
1763 return ret;
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001764 if (ret > S32_MAX / ETH_GSTRING_LEN)
1765 return -ENOMEM;
1766 WARN_ON_ONCE(!ret);
Jeff Garzikff03d492007-08-15 16:01:08 -07001767
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001768 gstrings.len = ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769
Li RongQing3d883022019-03-29 09:18:02 +08001770 if (gstrings.len) {
1771 data = vzalloc(array_size(gstrings.len, ETH_GSTRING_LEN));
1772 if (!data)
1773 return -ENOMEM;
1774
1775 __ethtool_get_strings(dev, gstrings.string_set, data);
1776 } else {
1777 data = NULL;
1778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
1780 ret = -EFAULT;
1781 if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
1782 goto out;
1783 useraddr += sizeof(gstrings);
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001784 if (gstrings.len &&
1785 copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 goto out;
1787 ret = 0;
1788
Michał Mirosław340ae162011-02-15 16:59:16 +00001789out:
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001790 vfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 return ret;
1792}
1793
1794static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
1795{
1796 struct ethtool_value id;
Ben Hutchings68f512f2011-04-02 00:35:15 +01001797 static bool busy;
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001798 const struct ethtool_ops *ops = dev->ethtool_ops;
Ben Hutchings68f512f2011-04-02 00:35:15 +01001799 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001801 if (!ops->set_phys_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 return -EOPNOTSUPP;
1803
Ben Hutchings68f512f2011-04-02 00:35:15 +01001804 if (busy)
1805 return -EBUSY;
1806
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 if (copy_from_user(&id, useraddr, sizeof(id)))
1808 return -EFAULT;
1809
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001810 rc = ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE);
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001811 if (rc < 0)
Ben Hutchings68f512f2011-04-02 00:35:15 +01001812 return rc;
1813
1814 /* Drop the RTNL lock while waiting, but prevent reentry or
1815 * removal of the device.
1816 */
1817 busy = true;
1818 dev_hold(dev);
1819 rtnl_unlock();
1820
1821 if (rc == 0) {
1822 /* Driver will handle this itself */
1823 schedule_timeout_interruptible(
Allan, Bruce W143780c2011-04-11 13:01:59 +00001824 id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT);
Ben Hutchings68f512f2011-04-02 00:35:15 +01001825 } else {
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001826 /* Driver expects to be called at twice the frequency in rc */
1827 int n = rc * 2, i, interval = HZ / n;
Ben Hutchings68f512f2011-04-02 00:35:15 +01001828
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001829 /* Count down seconds */
1830 do {
1831 /* Count down iterations per second */
1832 i = n;
1833 do {
1834 rtnl_lock();
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001835 rc = ops->set_phys_id(dev,
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001836 (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
1837 rtnl_unlock();
1838 if (rc)
1839 break;
1840 schedule_timeout_interruptible(interval);
1841 } while (!signal_pending(current) && --i != 0);
Ben Hutchings68f512f2011-04-02 00:35:15 +01001842 } while (!signal_pending(current) &&
1843 (id.data == 0 || --id.data != 0));
1844 }
1845
1846 rtnl_lock();
1847 dev_put(dev);
1848 busy = false;
1849
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001850 (void) ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
Ben Hutchings68f512f2011-04-02 00:35:15 +01001851 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852}
1853
1854static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
1855{
1856 struct ethtool_stats stats;
Stephen Hemminger76fd8592006-09-08 11:16:13 -07001857 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 u64 *data;
Jeff Garzikff03d492007-08-15 16:01:08 -07001859 int ret, n_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001861 if (!ops->get_ethtool_stats || !ops->get_sset_count)
Jeff Garzikff03d492007-08-15 16:01:08 -07001862 return -EOPNOTSUPP;
1863
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001864 n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
Jeff Garzikff03d492007-08-15 16:01:08 -07001865 if (n_stats < 0)
1866 return n_stats;
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001867 if (n_stats > S32_MAX / sizeof(u64))
1868 return -ENOMEM;
1869 WARN_ON_ONCE(!n_stats);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 if (copy_from_user(&stats, useraddr, sizeof(stats)))
1871 return -EFAULT;
1872
Jeff Garzikff03d492007-08-15 16:01:08 -07001873 stats.n_stats = n_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
Li RongQing3d883022019-03-29 09:18:02 +08001875 if (n_stats) {
1876 data = vzalloc(array_size(n_stats, sizeof(u64)));
1877 if (!data)
1878 return -ENOMEM;
1879 ops->get_ethtool_stats(dev, &stats, data);
1880 } else {
1881 data = NULL;
1882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883
1884 ret = -EFAULT;
1885 if (copy_to_user(useraddr, &stats, sizeof(stats)))
1886 goto out;
1887 useraddr += sizeof(stats);
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001888 if (n_stats && copy_to_user(useraddr, data, n_stats * sizeof(u64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 goto out;
1890 ret = 0;
1891
1892 out:
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001893 vfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 return ret;
1895}
1896
Andrew Lunnf3a40942015-12-30 16:28:25 +01001897static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr)
1898{
Florian Fainelli99943382018-04-25 12:12:48 -07001899 const struct ethtool_ops *ops = dev->ethtool_ops;
Andrew Lunnf3a40942015-12-30 16:28:25 +01001900 struct phy_device *phydev = dev->phydev;
Florian Fainelli99943382018-04-25 12:12:48 -07001901 struct ethtool_stats stats;
Andrew Lunnf3a40942015-12-30 16:28:25 +01001902 u64 *data;
1903 int ret, n_stats;
1904
Florian Fainelli99943382018-04-25 12:12:48 -07001905 if (!phydev && (!ops->get_ethtool_phy_stats || !ops->get_sset_count))
Andrew Lunnf3a40942015-12-30 16:28:25 +01001906 return -EOPNOTSUPP;
1907
Florian Fainelli99943382018-04-25 12:12:48 -07001908 if (dev->phydev && !ops->get_ethtool_phy_stats)
1909 n_stats = phy_ethtool_get_sset_count(dev->phydev);
1910 else
1911 n_stats = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
Andrew Lunnf3a40942015-12-30 16:28:25 +01001912 if (n_stats < 0)
1913 return n_stats;
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001914 if (n_stats > S32_MAX / sizeof(u64))
1915 return -ENOMEM;
1916 WARN_ON_ONCE(!n_stats);
Andrew Lunnf3a40942015-12-30 16:28:25 +01001917
1918 if (copy_from_user(&stats, useraddr, sizeof(stats)))
1919 return -EFAULT;
1920
1921 stats.n_stats = n_stats;
Andrew Lunnf3a40942015-12-30 16:28:25 +01001922
Li RongQing3d883022019-03-29 09:18:02 +08001923 if (n_stats) {
1924 data = vzalloc(array_size(n_stats, sizeof(u64)));
1925 if (!data)
1926 return -ENOMEM;
1927
1928 if (dev->phydev && !ops->get_ethtool_phy_stats) {
1929 ret = phy_ethtool_get_stats(dev->phydev, &stats, data);
1930 if (ret < 0)
1931 goto out;
1932 } else {
1933 ops->get_ethtool_phy_stats(dev, &stats, data);
1934 }
Florian Fainelli99943382018-04-25 12:12:48 -07001935 } else {
Li RongQing3d883022019-03-29 09:18:02 +08001936 data = NULL;
Florian Fainelli99943382018-04-25 12:12:48 -07001937 }
Andrew Lunnf3a40942015-12-30 16:28:25 +01001938
1939 ret = -EFAULT;
1940 if (copy_to_user(useraddr, &stats, sizeof(stats)))
1941 goto out;
1942 useraddr += sizeof(stats);
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001943 if (n_stats && copy_to_user(useraddr, data, n_stats * sizeof(u64)))
Andrew Lunnf3a40942015-12-30 16:28:25 +01001944 goto out;
1945 ret = 0;
1946
1947 out:
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001948 vfree(data);
Andrew Lunnf3a40942015-12-30 16:28:25 +01001949 return ret;
1950}
1951
viro@ftp.linux.org.uk0bf0519d2005-09-05 03:26:18 +01001952static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
Jon Wetzela6f9a702005-08-20 17:15:54 -07001953{
1954 struct ethtool_perm_addr epaddr;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001955
Matthew Wilcox313674a2007-07-31 14:00:29 -07001956 if (copy_from_user(&epaddr, useraddr, sizeof(epaddr)))
Jon Wetzela6f9a702005-08-20 17:15:54 -07001957 return -EFAULT;
1958
Matthew Wilcox313674a2007-07-31 14:00:29 -07001959 if (epaddr.size < dev->addr_len)
1960 return -ETOOSMALL;
1961 epaddr.size = dev->addr_len;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001962
Jon Wetzela6f9a702005-08-20 17:15:54 -07001963 if (copy_to_user(useraddr, &epaddr, sizeof(epaddr)))
Matthew Wilcox313674a2007-07-31 14:00:29 -07001964 return -EFAULT;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001965 useraddr += sizeof(epaddr);
Matthew Wilcox313674a2007-07-31 14:00:29 -07001966 if (copy_to_user(useraddr, dev->perm_addr, epaddr.size))
1967 return -EFAULT;
1968 return 0;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001969}
1970
Jeff Garzik13c99b22007-08-15 16:01:56 -07001971static int ethtool_get_value(struct net_device *dev, char __user *useraddr,
1972 u32 cmd, u32 (*actor)(struct net_device *))
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001973{
Roland Dreier8e557422010-02-11 12:14:23 -08001974 struct ethtool_value edata = { .cmd = cmd };
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001975
Jeff Garzik13c99b22007-08-15 16:01:56 -07001976 if (!actor)
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001977 return -EOPNOTSUPP;
1978
Jeff Garzik13c99b22007-08-15 16:01:56 -07001979 edata.data = actor(dev);
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001980
1981 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1982 return -EFAULT;
1983 return 0;
1984}
1985
Jeff Garzik13c99b22007-08-15 16:01:56 -07001986static int ethtool_set_value_void(struct net_device *dev, char __user *useraddr,
1987 void (*actor)(struct net_device *, u32))
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001988{
1989 struct ethtool_value edata;
1990
Jeff Garzik13c99b22007-08-15 16:01:56 -07001991 if (!actor)
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001992 return -EOPNOTSUPP;
1993
1994 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1995 return -EFAULT;
1996
Jeff Garzik13c99b22007-08-15 16:01:56 -07001997 actor(dev, edata.data);
Jeff Garzik339bf022007-08-15 16:01:32 -07001998 return 0;
1999}
2000
Jeff Garzik13c99b22007-08-15 16:01:56 -07002001static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
2002 int (*actor)(struct net_device *, u32))
Jeff Garzik339bf022007-08-15 16:01:32 -07002003{
2004 struct ethtool_value edata;
2005
Jeff Garzik13c99b22007-08-15 16:01:56 -07002006 if (!actor)
Jeff Garzik339bf022007-08-15 16:01:32 -07002007 return -EOPNOTSUPP;
2008
2009 if (copy_from_user(&edata, useraddr, sizeof(edata)))
2010 return -EFAULT;
2011
Jeff Garzik13c99b22007-08-15 16:01:56 -07002012 return actor(dev, edata.data);
Jeff Garzik339bf022007-08-15 16:01:32 -07002013}
2014
chavey97f8aef2010-04-07 21:54:42 -07002015static noinline_for_stack int ethtool_flash_device(struct net_device *dev,
2016 char __user *useraddr)
Ajit Khaparde05c6a8d2009-09-02 17:02:55 +00002017{
2018 struct ethtool_flash efl;
2019
2020 if (copy_from_user(&efl, useraddr, sizeof(efl)))
2021 return -EFAULT;
Ben Hutchings786f5282012-02-01 09:32:25 +00002022 efl.data[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
2023
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08002024 if (!dev->ethtool_ops->flash_device)
2025 return devlink_compat_flash_update(dev, efl.data);
Jakub Kicinski4eceba12019-02-14 13:40:45 -08002026
Ajit Khaparde05c6a8d2009-09-02 17:02:55 +00002027 return dev->ethtool_ops->flash_device(dev, &efl);
2028}
2029
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002030static int ethtool_set_dump(struct net_device *dev,
2031 void __user *useraddr)
2032{
2033 struct ethtool_dump dump;
2034
2035 if (!dev->ethtool_ops->set_dump)
2036 return -EOPNOTSUPP;
2037
2038 if (copy_from_user(&dump, useraddr, sizeof(dump)))
2039 return -EFAULT;
2040
2041 return dev->ethtool_ops->set_dump(dev, &dump);
2042}
2043
2044static int ethtool_get_dump_flag(struct net_device *dev,
2045 void __user *useraddr)
2046{
2047 int ret;
2048 struct ethtool_dump dump;
2049 const struct ethtool_ops *ops = dev->ethtool_ops;
2050
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00002051 if (!ops->get_dump_flag)
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002052 return -EOPNOTSUPP;
2053
2054 if (copy_from_user(&dump, useraddr, sizeof(dump)))
2055 return -EFAULT;
2056
2057 ret = ops->get_dump_flag(dev, &dump);
2058 if (ret)
2059 return ret;
2060
2061 if (copy_to_user(useraddr, &dump, sizeof(dump)))
2062 return -EFAULT;
2063 return 0;
2064}
2065
2066static int ethtool_get_dump_data(struct net_device *dev,
2067 void __user *useraddr)
2068{
2069 int ret;
2070 __u32 len;
2071 struct ethtool_dump dump, tmp;
2072 const struct ethtool_ops *ops = dev->ethtool_ops;
2073 void *data = NULL;
2074
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00002075 if (!ops->get_dump_data || !ops->get_dump_flag)
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002076 return -EOPNOTSUPP;
2077
2078 if (copy_from_user(&dump, useraddr, sizeof(dump)))
2079 return -EFAULT;
2080
2081 memset(&tmp, 0, sizeof(tmp));
2082 tmp.cmd = ETHTOOL_GET_DUMP_FLAG;
2083 ret = ops->get_dump_flag(dev, &tmp);
2084 if (ret)
2085 return ret;
2086
Michal Schmidtc590b5e2013-07-01 17:23:30 +02002087 len = min(tmp.len, dump.len);
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002088 if (!len)
2089 return -EFAULT;
2090
Michal Schmidtc590b5e2013-07-01 17:23:30 +02002091 /* Don't ever let the driver think there's more space available
2092 * than it requested with .get_dump_flag().
2093 */
2094 dump.len = len;
2095
2096 /* Always allocate enough space to hold the whole thing so that the
2097 * driver does not need to check the length and bother with partial
2098 * dumping.
2099 */
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002100 data = vzalloc(tmp.len);
2101 if (!data)
2102 return -ENOMEM;
2103 ret = ops->get_dump_data(dev, &dump, data);
2104 if (ret)
2105 goto out;
2106
Michal Schmidtc590b5e2013-07-01 17:23:30 +02002107 /* There are two sane possibilities:
2108 * 1. The driver's .get_dump_data() does not touch dump.len.
2109 * 2. Or it may set dump.len to how much it really writes, which
2110 * should be tmp.len (or len if it can do a partial dump).
2111 * In any case respond to userspace with the actual length of data
2112 * it's receiving.
2113 */
2114 WARN_ON(dump.len != len && dump.len != tmp.len);
2115 dump.len = len;
2116
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002117 if (copy_to_user(useraddr, &dump, sizeof(dump))) {
2118 ret = -EFAULT;
2119 goto out;
2120 }
2121 useraddr += offsetof(struct ethtool_dump, data);
2122 if (copy_to_user(useraddr, data, len))
2123 ret = -EFAULT;
2124out:
2125 vfree(data);
2126 return ret;
2127}
2128
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002129static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr)
2130{
2131 int err = 0;
2132 struct ethtool_ts_info info;
2133 const struct ethtool_ops *ops = dev->ethtool_ops;
2134 struct phy_device *phydev = dev->phydev;
2135
2136 memset(&info, 0, sizeof(info));
2137 info.cmd = ETHTOOL_GET_TS_INFO;
2138
Richard Cochran7774ee22019-12-25 18:16:12 -08002139 if (phy_has_tsinfo(phydev)) {
2140 err = phy_ts_info(phydev, &info);
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00002141 } else if (ops->get_ts_info) {
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002142 err = ops->get_ts_info(dev, &info);
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002143 } else {
2144 info.so_timestamping =
2145 SOF_TIMESTAMPING_RX_SOFTWARE |
2146 SOF_TIMESTAMPING_SOFTWARE;
2147 info.phc_index = -1;
2148 }
2149
2150 if (err)
2151 return err;
2152
2153 if (copy_to_user(useraddr, &info, sizeof(info)))
2154 err = -EFAULT;
2155
2156 return err;
2157}
2158
Ed Swierk2f438362015-01-02 17:27:56 -08002159static int __ethtool_get_module_info(struct net_device *dev,
2160 struct ethtool_modinfo *modinfo)
2161{
2162 const struct ethtool_ops *ops = dev->ethtool_ops;
2163 struct phy_device *phydev = dev->phydev;
2164
Russell Kinge679c9c2018-03-28 15:44:16 -07002165 if (dev->sfp_bus)
2166 return sfp_get_module_info(dev->sfp_bus, modinfo);
2167
Ed Swierk2f438362015-01-02 17:27:56 -08002168 if (phydev && phydev->drv && phydev->drv->module_info)
2169 return phydev->drv->module_info(phydev, modinfo);
2170
2171 if (ops->get_module_info)
2172 return ops->get_module_info(dev, modinfo);
2173
2174 return -EOPNOTSUPP;
2175}
2176
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002177static int ethtool_get_module_info(struct net_device *dev,
2178 void __user *useraddr)
2179{
2180 int ret;
2181 struct ethtool_modinfo modinfo;
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002182
2183 if (copy_from_user(&modinfo, useraddr, sizeof(modinfo)))
2184 return -EFAULT;
2185
Ed Swierk2f438362015-01-02 17:27:56 -08002186 ret = __ethtool_get_module_info(dev, &modinfo);
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002187 if (ret)
2188 return ret;
2189
2190 if (copy_to_user(useraddr, &modinfo, sizeof(modinfo)))
2191 return -EFAULT;
2192
2193 return 0;
2194}
2195
Ed Swierk2f438362015-01-02 17:27:56 -08002196static int __ethtool_get_module_eeprom(struct net_device *dev,
2197 struct ethtool_eeprom *ee, u8 *data)
2198{
2199 const struct ethtool_ops *ops = dev->ethtool_ops;
2200 struct phy_device *phydev = dev->phydev;
2201
Russell Kinge679c9c2018-03-28 15:44:16 -07002202 if (dev->sfp_bus)
2203 return sfp_get_module_eeprom(dev->sfp_bus, ee, data);
2204
Ed Swierk2f438362015-01-02 17:27:56 -08002205 if (phydev && phydev->drv && phydev->drv->module_eeprom)
2206 return phydev->drv->module_eeprom(phydev, ee, data);
2207
2208 if (ops->get_module_eeprom)
2209 return ops->get_module_eeprom(dev, ee, data);
2210
2211 return -EOPNOTSUPP;
2212}
2213
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002214static int ethtool_get_module_eeprom(struct net_device *dev,
2215 void __user *useraddr)
2216{
2217 int ret;
2218 struct ethtool_modinfo modinfo;
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002219
Ed Swierk2f438362015-01-02 17:27:56 -08002220 ret = __ethtool_get_module_info(dev, &modinfo);
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002221 if (ret)
2222 return ret;
2223
Ed Swierk2f438362015-01-02 17:27:56 -08002224 return ethtool_get_any_eeprom(dev, useraddr,
2225 __ethtool_get_module_eeprom,
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002226 modinfo.eeprom_len);
2227}
2228
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302229static int ethtool_tunable_valid(const struct ethtool_tunable *tuna)
2230{
2231 switch (tuna->id) {
2232 case ETHTOOL_RX_COPYBREAK:
Eric Dumazet1255a502014-10-05 12:35:21 +03002233 case ETHTOOL_TX_COPYBREAK:
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302234 if (tuna->len != sizeof(u32) ||
2235 tuna->type_id != ETHTOOL_TUNABLE_U32)
2236 return -EINVAL;
2237 break;
Inbar Karmye1577c12017-11-20 16:14:30 +02002238 case ETHTOOL_PFC_PREVENTION_TOUT:
2239 if (tuna->len != sizeof(u16) ||
2240 tuna->type_id != ETHTOOL_TUNABLE_U16)
2241 return -EINVAL;
2242 break;
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302243 default:
2244 return -EINVAL;
2245 }
2246
2247 return 0;
2248}
2249
2250static int ethtool_get_tunable(struct net_device *dev, void __user *useraddr)
2251{
2252 int ret;
2253 struct ethtool_tunable tuna;
2254 const struct ethtool_ops *ops = dev->ethtool_ops;
2255 void *data;
2256
2257 if (!ops->get_tunable)
2258 return -EOPNOTSUPP;
2259 if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
2260 return -EFAULT;
2261 ret = ethtool_tunable_valid(&tuna);
2262 if (ret)
2263 return ret;
2264 data = kmalloc(tuna.len, GFP_USER);
2265 if (!data)
2266 return -ENOMEM;
2267 ret = ops->get_tunable(dev, &tuna, data);
2268 if (ret)
2269 goto out;
2270 useraddr += sizeof(tuna);
2271 ret = -EFAULT;
2272 if (copy_to_user(useraddr, data, tuna.len))
2273 goto out;
2274 ret = 0;
2275
2276out:
2277 kfree(data);
2278 return ret;
2279}
2280
2281static int ethtool_set_tunable(struct net_device *dev, void __user *useraddr)
2282{
2283 int ret;
2284 struct ethtool_tunable tuna;
2285 const struct ethtool_ops *ops = dev->ethtool_ops;
2286 void *data;
2287
2288 if (!ops->set_tunable)
2289 return -EOPNOTSUPP;
2290 if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
2291 return -EFAULT;
2292 ret = ethtool_tunable_valid(&tuna);
2293 if (ret)
2294 return ret;
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302295 useraddr += sizeof(tuna);
Al Viro30e7e3e2017-05-13 18:31:26 -04002296 data = memdup_user(useraddr, tuna.len);
2297 if (IS_ERR(data))
2298 return PTR_ERR(data);
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302299 ret = ops->set_tunable(dev, &tuna, data);
2300
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302301 kfree(data);
2302 return ret;
2303}
2304
Arnd Bergmann3499e872019-03-07 16:58:35 +01002305static noinline_for_stack int
2306ethtool_get_per_queue_coalesce(struct net_device *dev,
2307 void __user *useraddr,
2308 struct ethtool_per_queue_op *per_queue_opt)
Kan Liang421797b2016-02-19 09:24:02 -05002309{
2310 u32 bit;
2311 int ret;
2312 DECLARE_BITMAP(queue_mask, MAX_NUM_QUEUE);
2313
2314 if (!dev->ethtool_ops->get_per_queue_coalesce)
2315 return -EOPNOTSUPP;
2316
2317 useraddr += sizeof(*per_queue_opt);
2318
Yury Norov3aa56882018-02-06 15:38:06 -08002319 bitmap_from_arr32(queue_mask, per_queue_opt->queue_mask,
2320 MAX_NUM_QUEUE);
Kan Liang421797b2016-02-19 09:24:02 -05002321
2322 for_each_set_bit(bit, queue_mask, MAX_NUM_QUEUE) {
2323 struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
2324
2325 ret = dev->ethtool_ops->get_per_queue_coalesce(dev, bit, &coalesce);
2326 if (ret != 0)
2327 return ret;
2328 if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
2329 return -EFAULT;
2330 useraddr += sizeof(coalesce);
2331 }
2332
2333 return 0;
2334}
2335
Arnd Bergmann3499e872019-03-07 16:58:35 +01002336static noinline_for_stack int
2337ethtool_set_per_queue_coalesce(struct net_device *dev,
2338 void __user *useraddr,
2339 struct ethtool_per_queue_op *per_queue_opt)
Kan Liangf38d1382016-02-19 09:24:03 -05002340{
2341 u32 bit;
2342 int i, ret = 0;
2343 int n_queue;
2344 struct ethtool_coalesce *backup = NULL, *tmp = NULL;
2345 DECLARE_BITMAP(queue_mask, MAX_NUM_QUEUE);
2346
2347 if ((!dev->ethtool_ops->set_per_queue_coalesce) ||
2348 (!dev->ethtool_ops->get_per_queue_coalesce))
2349 return -EOPNOTSUPP;
2350
2351 useraddr += sizeof(*per_queue_opt);
2352
Yury Norov3aa56882018-02-06 15:38:06 -08002353 bitmap_from_arr32(queue_mask, per_queue_opt->queue_mask, MAX_NUM_QUEUE);
Kan Liangf38d1382016-02-19 09:24:03 -05002354 n_queue = bitmap_weight(queue_mask, MAX_NUM_QUEUE);
2355 tmp = backup = kmalloc_array(n_queue, sizeof(*backup), GFP_KERNEL);
2356 if (!backup)
2357 return -ENOMEM;
2358
2359 for_each_set_bit(bit, queue_mask, MAX_NUM_QUEUE) {
2360 struct ethtool_coalesce coalesce;
2361
2362 ret = dev->ethtool_ops->get_per_queue_coalesce(dev, bit, tmp);
2363 if (ret != 0)
2364 goto roll_back;
2365
2366 tmp++;
2367
2368 if (copy_from_user(&coalesce, useraddr, sizeof(coalesce))) {
2369 ret = -EFAULT;
2370 goto roll_back;
2371 }
2372
Jakub Kicinski95cddcb2020-03-04 21:15:31 -08002373 if (!ethtool_set_coalesce_supported(dev, &coalesce)) {
2374 ret = -EOPNOTSUPP;
2375 goto roll_back;
2376 }
2377
Kan Liangf38d1382016-02-19 09:24:03 -05002378 ret = dev->ethtool_ops->set_per_queue_coalesce(dev, bit, &coalesce);
2379 if (ret != 0)
2380 goto roll_back;
2381
2382 useraddr += sizeof(coalesce);
2383 }
2384
2385roll_back:
2386 if (ret != 0) {
2387 tmp = backup;
2388 for_each_set_bit(i, queue_mask, bit) {
2389 dev->ethtool_ops->set_per_queue_coalesce(dev, i, tmp);
2390 tmp++;
2391 }
2392 }
2393 kfree(backup);
2394
2395 return ret;
2396}
2397
Arnd Bergmann3499e872019-03-07 16:58:35 +01002398static int noinline_for_stack ethtool_set_per_queue(struct net_device *dev,
Wenwen Wang58f5bbe2018-10-08 10:49:35 -05002399 void __user *useraddr, u32 sub_cmd)
Kan Liangac2c7ad2016-02-19 09:24:01 -05002400{
2401 struct ethtool_per_queue_op per_queue_opt;
2402
2403 if (copy_from_user(&per_queue_opt, useraddr, sizeof(per_queue_opt)))
2404 return -EFAULT;
2405
Wenwen Wang58f5bbe2018-10-08 10:49:35 -05002406 if (per_queue_opt.sub_command != sub_cmd)
2407 return -EINVAL;
2408
Kan Liangac2c7ad2016-02-19 09:24:01 -05002409 switch (per_queue_opt.sub_command) {
Kan Liang421797b2016-02-19 09:24:02 -05002410 case ETHTOOL_GCOALESCE:
2411 return ethtool_get_per_queue_coalesce(dev, useraddr, &per_queue_opt);
Kan Liangf38d1382016-02-19 09:24:03 -05002412 case ETHTOOL_SCOALESCE:
2413 return ethtool_set_per_queue_coalesce(dev, useraddr, &per_queue_opt);
Kan Liangac2c7ad2016-02-19 09:24:01 -05002414 default:
2415 return -EOPNOTSUPP;
2416 };
2417}
2418
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002419static int ethtool_phy_tunable_valid(const struct ethtool_tunable *tuna)
2420{
2421 switch (tuna->id) {
Raju Lakkaraju65feddd2016-11-17 13:07:23 +01002422 case ETHTOOL_PHY_DOWNSHIFT:
Heiner Kallweit3aeb0802019-03-25 19:34:58 +01002423 case ETHTOOL_PHY_FAST_LINK_DOWN:
Raju Lakkaraju65feddd2016-11-17 13:07:23 +01002424 if (tuna->len != sizeof(u8) ||
2425 tuna->type_id != ETHTOOL_TUNABLE_U8)
2426 return -EINVAL;
2427 break;
Alexandru Ardelean9f2f13f2019-09-16 10:35:25 +03002428 case ETHTOOL_PHY_EDPD:
2429 if (tuna->len != sizeof(u16) ||
2430 tuna->type_id != ETHTOOL_TUNABLE_U16)
2431 return -EINVAL;
2432 break;
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002433 default:
2434 return -EINVAL;
2435 }
2436
2437 return 0;
2438}
2439
2440static int get_phy_tunable(struct net_device *dev, void __user *useraddr)
2441{
2442 int ret;
2443 struct ethtool_tunable tuna;
2444 struct phy_device *phydev = dev->phydev;
2445 void *data;
2446
2447 if (!(phydev && phydev->drv && phydev->drv->get_tunable))
2448 return -EOPNOTSUPP;
2449
2450 if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
2451 return -EFAULT;
2452 ret = ethtool_phy_tunable_valid(&tuna);
2453 if (ret)
2454 return ret;
2455 data = kmalloc(tuna.len, GFP_USER);
2456 if (!data)
2457 return -ENOMEM;
Florian Fainelli4b652462016-11-22 13:55:31 -08002458 mutex_lock(&phydev->lock);
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002459 ret = phydev->drv->get_tunable(phydev, &tuna, data);
Florian Fainelli4b652462016-11-22 13:55:31 -08002460 mutex_unlock(&phydev->lock);
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002461 if (ret)
2462 goto out;
2463 useraddr += sizeof(tuna);
2464 ret = -EFAULT;
2465 if (copy_to_user(useraddr, data, tuna.len))
2466 goto out;
2467 ret = 0;
2468
2469out:
2470 kfree(data);
2471 return ret;
2472}
2473
2474static int set_phy_tunable(struct net_device *dev, void __user *useraddr)
2475{
2476 int ret;
2477 struct ethtool_tunable tuna;
2478 struct phy_device *phydev = dev->phydev;
2479 void *data;
2480
2481 if (!(phydev && phydev->drv && phydev->drv->set_tunable))
2482 return -EOPNOTSUPP;
2483 if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
2484 return -EFAULT;
2485 ret = ethtool_phy_tunable_valid(&tuna);
2486 if (ret)
2487 return ret;
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002488 useraddr += sizeof(tuna);
Al Viro30e7e3e2017-05-13 18:31:26 -04002489 data = memdup_user(useraddr, tuna.len);
2490 if (IS_ERR(data))
2491 return PTR_ERR(data);
Florian Fainelli4b652462016-11-22 13:55:31 -08002492 mutex_lock(&phydev->lock);
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002493 ret = phydev->drv->set_tunable(phydev, &tuna, data);
Florian Fainelli4b652462016-11-22 13:55:31 -08002494 mutex_unlock(&phydev->lock);
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002495
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002496 kfree(data);
2497 return ret;
2498}
2499
Vidya Sagar Ravipati1a5f3da2017-07-27 16:47:26 -07002500static int ethtool_get_fecparam(struct net_device *dev, void __user *useraddr)
2501{
Li RongQinge83887f2019-02-27 20:47:57 +08002502 struct ethtool_fecparam fecparam = { .cmd = ETHTOOL_GFECPARAM };
Edward Creea6d50512018-02-28 19:15:58 +00002503 int rc;
Vidya Sagar Ravipati1a5f3da2017-07-27 16:47:26 -07002504
2505 if (!dev->ethtool_ops->get_fecparam)
2506 return -EOPNOTSUPP;
2507
Edward Creea6d50512018-02-28 19:15:58 +00002508 rc = dev->ethtool_ops->get_fecparam(dev, &fecparam);
2509 if (rc)
2510 return rc;
Vidya Sagar Ravipati1a5f3da2017-07-27 16:47:26 -07002511
2512 if (copy_to_user(useraddr, &fecparam, sizeof(fecparam)))
2513 return -EFAULT;
2514 return 0;
2515}
2516
2517static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr)
2518{
2519 struct ethtool_fecparam fecparam;
2520
2521 if (!dev->ethtool_ops->set_fecparam)
2522 return -EOPNOTSUPP;
2523
2524 if (copy_from_user(&fecparam, useraddr, sizeof(fecparam)))
2525 return -EFAULT;
2526
2527 return dev->ethtool_ops->set_fecparam(dev, &fecparam);
2528}
2529
Yan Burman600fed52013-06-03 02:03:34 +00002530/* The main entry point in this file. Called from net/core/dev_ioctl.c */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
Eric W. Biederman881d9662007-09-17 11:56:21 -07002532int dev_ethtool(struct net *net, struct ifreq *ifr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533{
Eric W. Biederman881d9662007-09-17 11:56:21 -07002534 struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 void __user *useraddr = ifr->ifr_data;
Kan Liangac2c7ad2016-02-19 09:24:01 -05002536 u32 ethcmd, sub_cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 int rc;
Bjørn Morkb29d3142013-05-01 23:06:42 +00002538 netdev_features_t old_features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 if (!dev || !netif_device_present(dev))
2541 return -ENODEV;
2542
chavey97f8aef2010-04-07 21:54:42 -07002543 if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 return -EFAULT;
2545
Kan Liangac2c7ad2016-02-19 09:24:01 -05002546 if (ethcmd == ETHTOOL_PERQUEUE) {
2547 if (copy_from_user(&sub_cmd, useraddr + sizeof(ethcmd), sizeof(sub_cmd)))
2548 return -EFAULT;
2549 } else {
2550 sub_cmd = ethcmd;
2551 }
Stephen Hemminger75f31232006-09-28 15:13:37 -07002552 /* Allow some commands to be done by anyone */
Kan Liangac2c7ad2016-02-19 09:24:01 -05002553 switch (sub_cmd) {
stephen hemminger0fdc1002010-08-23 10:24:18 +00002554 case ETHTOOL_GSET:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002555 case ETHTOOL_GDRVINFO:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002556 case ETHTOOL_GMSGLVL:
Ben Hutchings2da45db2012-06-12 13:05:41 +00002557 case ETHTOOL_GLINK:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002558 case ETHTOOL_GCOALESCE:
2559 case ETHTOOL_GRINGPARAM:
2560 case ETHTOOL_GPAUSEPARAM:
2561 case ETHTOOL_GRXCSUM:
2562 case ETHTOOL_GTXCSUM:
2563 case ETHTOOL_GSG:
Michał Mirosławf80400a2012-01-22 00:20:40 +00002564 case ETHTOOL_GSSET_INFO:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002565 case ETHTOOL_GSTRINGS:
Ben Hutchings2da45db2012-06-12 13:05:41 +00002566 case ETHTOOL_GSTATS:
Andrew Lunnf3a40942015-12-30 16:28:25 +01002567 case ETHTOOL_GPHYSTATS:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002568 case ETHTOOL_GTSO:
2569 case ETHTOOL_GPERMADDR:
Maciej Żenczykowski474ff262018-09-22 01:34:01 -07002570 case ETHTOOL_GUFO:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002571 case ETHTOOL_GGSO:
stephen hemminger1cab8192010-02-11 13:48:29 +00002572 case ETHTOOL_GGRO:
Jeff Garzik339bf022007-08-15 16:01:32 -07002573 case ETHTOOL_GFLAGS:
2574 case ETHTOOL_GPFLAGS:
Santwona Behera0853ad62008-07-02 03:47:41 -07002575 case ETHTOOL_GRXFH:
Santwona Behera59089d82009-02-20 00:58:13 -08002576 case ETHTOOL_GRXRINGS:
2577 case ETHTOOL_GRXCLSRLCNT:
2578 case ETHTOOL_GRXCLSRULE:
2579 case ETHTOOL_GRXCLSRLALL:
Ben Hutchings2da45db2012-06-12 13:05:41 +00002580 case ETHTOOL_GRXFHINDIR:
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05302581 case ETHTOOL_GRSSH:
Michał Mirosław5455c692011-02-15 16:59:17 +00002582 case ETHTOOL_GFEATURES:
Ben Hutchings2da45db2012-06-12 13:05:41 +00002583 case ETHTOOL_GCHANNELS:
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002584 case ETHTOOL_GET_TS_INFO:
Ben Hutchings2da45db2012-06-12 13:05:41 +00002585 case ETHTOOL_GEEE:
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302586 case ETHTOOL_GTUNABLE:
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002587 case ETHTOOL_PHY_GTUNABLE:
Miroslav Lichvar8006f6b2016-11-24 10:55:06 +01002588 case ETHTOOL_GLINKSETTINGS:
Vidya Sagar Ravipati1a5f3da2017-07-27 16:47:26 -07002589 case ETHTOOL_GFECPARAM:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002590 break;
2591 default:
Eric W. Biederman5e1fccc2012-11-16 03:03:04 +00002592 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Stephen Hemminger75f31232006-09-28 15:13:37 -07002593 return -EPERM;
2594 }
2595
chavey97f8aef2010-04-07 21:54:42 -07002596 if (dev->ethtool_ops->begin) {
2597 rc = dev->ethtool_ops->begin(dev);
2598 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 return rc;
chavey97f8aef2010-04-07 21:54:42 -07002600 }
Stephen Hemmingerd8a33ac2005-05-29 14:13:47 -07002601 old_features = dev->features;
2602
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 switch (ethcmd) {
2604 case ETHTOOL_GSET:
2605 rc = ethtool_get_settings(dev, useraddr);
2606 break;
2607 case ETHTOOL_SSET:
2608 rc = ethtool_set_settings(dev, useraddr);
2609 break;
2610 case ETHTOOL_GDRVINFO:
2611 rc = ethtool_get_drvinfo(dev, useraddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 break;
2613 case ETHTOOL_GREGS:
2614 rc = ethtool_get_regs(dev, useraddr);
2615 break;
2616 case ETHTOOL_GWOL:
2617 rc = ethtool_get_wol(dev, useraddr);
2618 break;
2619 case ETHTOOL_SWOL:
2620 rc = ethtool_set_wol(dev, useraddr);
2621 break;
2622 case ETHTOOL_GMSGLVL:
Jeff Garzik13c99b22007-08-15 16:01:56 -07002623 rc = ethtool_get_value(dev, useraddr, ethcmd,
2624 dev->ethtool_ops->get_msglevel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 break;
2626 case ETHTOOL_SMSGLVL:
Jeff Garzik13c99b22007-08-15 16:01:56 -07002627 rc = ethtool_set_value_void(dev, useraddr,
2628 dev->ethtool_ops->set_msglevel);
Michal Kubecek0bda7af2020-01-26 23:11:10 +01002629 if (!rc)
2630 ethtool_notify(dev, ETHTOOL_MSG_DEBUG_NTF, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 break;
Yuval Mintz80f12ec2012-06-06 17:13:06 +00002632 case ETHTOOL_GEEE:
2633 rc = ethtool_get_eee(dev, useraddr);
2634 break;
2635 case ETHTOOL_SEEE:
2636 rc = ethtool_set_eee(dev, useraddr);
2637 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 case ETHTOOL_NWAY_RST:
2639 rc = ethtool_nway_reset(dev);
2640 break;
2641 case ETHTOOL_GLINK:
Ben Hutchingse596e6e2010-12-09 12:08:35 +00002642 rc = ethtool_get_link(dev, useraddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 break;
2644 case ETHTOOL_GEEPROM:
2645 rc = ethtool_get_eeprom(dev, useraddr);
2646 break;
2647 case ETHTOOL_SEEPROM:
2648 rc = ethtool_set_eeprom(dev, useraddr);
2649 break;
2650 case ETHTOOL_GCOALESCE:
2651 rc = ethtool_get_coalesce(dev, useraddr);
2652 break;
2653 case ETHTOOL_SCOALESCE:
2654 rc = ethtool_set_coalesce(dev, useraddr);
2655 break;
2656 case ETHTOOL_GRINGPARAM:
2657 rc = ethtool_get_ringparam(dev, useraddr);
2658 break;
2659 case ETHTOOL_SRINGPARAM:
2660 rc = ethtool_set_ringparam(dev, useraddr);
2661 break;
2662 case ETHTOOL_GPAUSEPARAM:
2663 rc = ethtool_get_pauseparam(dev, useraddr);
2664 break;
2665 case ETHTOOL_SPAUSEPARAM:
2666 rc = ethtool_set_pauseparam(dev, useraddr);
2667 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 case ETHTOOL_TEST:
2669 rc = ethtool_self_test(dev, useraddr);
2670 break;
2671 case ETHTOOL_GSTRINGS:
2672 rc = ethtool_get_strings(dev, useraddr);
2673 break;
2674 case ETHTOOL_PHYS_ID:
2675 rc = ethtool_phys_id(dev, useraddr);
2676 break;
2677 case ETHTOOL_GSTATS:
2678 rc = ethtool_get_stats(dev, useraddr);
2679 break;
Jon Wetzela6f9a702005-08-20 17:15:54 -07002680 case ETHTOOL_GPERMADDR:
2681 rc = ethtool_get_perm_addr(dev, useraddr);
2682 break;
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07002683 case ETHTOOL_GFLAGS:
Jeff Garzik13c99b22007-08-15 16:01:56 -07002684 rc = ethtool_get_value(dev, useraddr, ethcmd,
Michał Mirosławbc5787c62011-11-15 15:29:55 +00002685 __ethtool_get_flags);
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07002686 break;
2687 case ETHTOOL_SFLAGS:
Michał Mirosławda8ac86c2011-02-15 16:59:18 +00002688 rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags);
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07002689 break;
Jeff Garzik339bf022007-08-15 16:01:32 -07002690 case ETHTOOL_GPFLAGS:
Jeff Garzik13c99b22007-08-15 16:01:56 -07002691 rc = ethtool_get_value(dev, useraddr, ethcmd,
2692 dev->ethtool_ops->get_priv_flags);
Michal Kubecek111dcba2020-03-12 21:08:18 +01002693 if (!rc)
2694 ethtool_notify(dev, ETHTOOL_MSG_PRIVFLAGS_NTF, NULL);
Jeff Garzik339bf022007-08-15 16:01:32 -07002695 break;
2696 case ETHTOOL_SPFLAGS:
Jeff Garzik13c99b22007-08-15 16:01:56 -07002697 rc = ethtool_set_value(dev, useraddr,
2698 dev->ethtool_ops->set_priv_flags);
Jeff Garzik339bf022007-08-15 16:01:32 -07002699 break;
Santwona Behera0853ad62008-07-02 03:47:41 -07002700 case ETHTOOL_GRXFH:
Santwona Behera59089d82009-02-20 00:58:13 -08002701 case ETHTOOL_GRXRINGS:
2702 case ETHTOOL_GRXCLSRLCNT:
2703 case ETHTOOL_GRXCLSRULE:
2704 case ETHTOOL_GRXCLSRLALL:
Ben Hutchingsbf988432010-06-28 08:45:58 +00002705 rc = ethtool_get_rxnfc(dev, ethcmd, useraddr);
Santwona Behera0853ad62008-07-02 03:47:41 -07002706 break;
2707 case ETHTOOL_SRXFH:
Santwona Behera59089d82009-02-20 00:58:13 -08002708 case ETHTOOL_SRXCLSRLDEL:
2709 case ETHTOOL_SRXCLSRLINS:
Ben Hutchingsbf988432010-06-28 08:45:58 +00002710 rc = ethtool_set_rxnfc(dev, ethcmd, useraddr);
Santwona Behera0853ad62008-07-02 03:47:41 -07002711 break;
Ajit Khaparde05c6a8d2009-09-02 17:02:55 +00002712 case ETHTOOL_FLASHDEV:
2713 rc = ethtool_flash_device(dev, useraddr);
2714 break;
Ben Hutchingsd73d3a82009-10-05 10:59:58 +00002715 case ETHTOOL_RESET:
2716 rc = ethtool_reset(dev, useraddr);
2717 break;
Jeff Garzik723b2f52010-03-03 22:51:50 +00002718 case ETHTOOL_GSSET_INFO:
2719 rc = ethtool_get_sset_info(dev, useraddr);
2720 break;
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00002721 case ETHTOOL_GRXFHINDIR:
2722 rc = ethtool_get_rxfh_indir(dev, useraddr);
2723 break;
2724 case ETHTOOL_SRXFHINDIR:
2725 rc = ethtool_set_rxfh_indir(dev, useraddr);
2726 break;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05302727 case ETHTOOL_GRSSH:
2728 rc = ethtool_get_rxfh(dev, useraddr);
2729 break;
2730 case ETHTOOL_SRSSH:
2731 rc = ethtool_set_rxfh(dev, useraddr);
2732 break;
Michał Mirosław5455c692011-02-15 16:59:17 +00002733 case ETHTOOL_GFEATURES:
2734 rc = ethtool_get_features(dev, useraddr);
2735 break;
2736 case ETHTOOL_SFEATURES:
2737 rc = ethtool_set_features(dev, useraddr);
2738 break;
Michał Mirosław0a417702011-02-15 16:59:17 +00002739 case ETHTOOL_GTXCSUM:
Michał Mirosławe83d3602011-02-15 16:59:18 +00002740 case ETHTOOL_GRXCSUM:
Michał Mirosław0a417702011-02-15 16:59:17 +00002741 case ETHTOOL_GSG:
2742 case ETHTOOL_GTSO:
Michał Mirosław0a417702011-02-15 16:59:17 +00002743 case ETHTOOL_GGSO:
2744 case ETHTOOL_GGRO:
2745 rc = ethtool_get_one_feature(dev, useraddr, ethcmd);
2746 break;
2747 case ETHTOOL_STXCSUM:
Michał Mirosławe83d3602011-02-15 16:59:18 +00002748 case ETHTOOL_SRXCSUM:
Michał Mirosław0a417702011-02-15 16:59:17 +00002749 case ETHTOOL_SSG:
2750 case ETHTOOL_STSO:
Michał Mirosław0a417702011-02-15 16:59:17 +00002751 case ETHTOOL_SGSO:
2752 case ETHTOOL_SGRO:
2753 rc = ethtool_set_one_feature(dev, useraddr, ethcmd);
2754 break;
amit salecha8b5933c2011-04-07 01:58:42 +00002755 case ETHTOOL_GCHANNELS:
2756 rc = ethtool_get_channels(dev, useraddr);
2757 break;
2758 case ETHTOOL_SCHANNELS:
2759 rc = ethtool_set_channels(dev, useraddr);
2760 break;
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002761 case ETHTOOL_SET_DUMP:
2762 rc = ethtool_set_dump(dev, useraddr);
2763 break;
2764 case ETHTOOL_GET_DUMP_FLAG:
2765 rc = ethtool_get_dump_flag(dev, useraddr);
2766 break;
2767 case ETHTOOL_GET_DUMP_DATA:
2768 rc = ethtool_get_dump_data(dev, useraddr);
2769 break;
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002770 case ETHTOOL_GET_TS_INFO:
2771 rc = ethtool_get_ts_info(dev, useraddr);
2772 break;
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002773 case ETHTOOL_GMODULEINFO:
2774 rc = ethtool_get_module_info(dev, useraddr);
2775 break;
2776 case ETHTOOL_GMODULEEEPROM:
2777 rc = ethtool_get_module_eeprom(dev, useraddr);
2778 break;
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302779 case ETHTOOL_GTUNABLE:
2780 rc = ethtool_get_tunable(dev, useraddr);
2781 break;
2782 case ETHTOOL_STUNABLE:
2783 rc = ethtool_set_tunable(dev, useraddr);
2784 break;
Andrew Lunnf3a40942015-12-30 16:28:25 +01002785 case ETHTOOL_GPHYSTATS:
2786 rc = ethtool_get_phy_stats(dev, useraddr);
2787 break;
Kan Liangac2c7ad2016-02-19 09:24:01 -05002788 case ETHTOOL_PERQUEUE:
Wenwen Wang58f5bbe2018-10-08 10:49:35 -05002789 rc = ethtool_set_per_queue(dev, useraddr, sub_cmd);
Kan Liangac2c7ad2016-02-19 09:24:01 -05002790 break;
David Decotigny3f1ac7a2016-02-24 10:57:59 -08002791 case ETHTOOL_GLINKSETTINGS:
2792 rc = ethtool_get_link_ksettings(dev, useraddr);
2793 break;
2794 case ETHTOOL_SLINKSETTINGS:
2795 rc = ethtool_set_link_ksettings(dev, useraddr);
2796 break;
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002797 case ETHTOOL_PHY_GTUNABLE:
2798 rc = get_phy_tunable(dev, useraddr);
2799 break;
2800 case ETHTOOL_PHY_STUNABLE:
2801 rc = set_phy_tunable(dev, useraddr);
2802 break;
Vidya Sagar Ravipati1a5f3da2017-07-27 16:47:26 -07002803 case ETHTOOL_GFECPARAM:
2804 rc = ethtool_get_fecparam(dev, useraddr);
2805 break;
2806 case ETHTOOL_SFECPARAM:
2807 rc = ethtool_set_fecparam(dev, useraddr);
2808 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 default:
Matthew Wilcox61a44b92007-07-31 14:00:02 -07002810 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002812
Stephen Hemmingere71a4782007-04-10 20:10:33 -07002813 if (dev->ethtool_ops->complete)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 dev->ethtool_ops->complete(dev);
Stephen Hemmingerd8a33ac2005-05-29 14:13:47 -07002815
2816 if (old_features != dev->features)
2817 netdev_features_change(dev);
2818
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820}
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01002821
2822struct ethtool_rx_flow_key {
2823 struct flow_dissector_key_basic basic;
2824 union {
2825 struct flow_dissector_key_ipv4_addrs ipv4;
2826 struct flow_dissector_key_ipv6_addrs ipv6;
2827 };
2828 struct flow_dissector_key_ports tp;
2829 struct flow_dissector_key_ip ip;
2830 struct flow_dissector_key_vlan vlan;
2831 struct flow_dissector_key_eth_addrs eth_addrs;
2832} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
2833
2834struct ethtool_rx_flow_match {
2835 struct flow_dissector dissector;
2836 struct ethtool_rx_flow_key key;
2837 struct ethtool_rx_flow_key mask;
2838};
2839
2840struct ethtool_rx_flow_rule *
2841ethtool_rx_flow_rule_create(const struct ethtool_rx_flow_spec_input *input)
2842{
2843 const struct ethtool_rx_flow_spec *fs = input->fs;
2844 static struct in6_addr zero_addr = {};
2845 struct ethtool_rx_flow_match *match;
2846 struct ethtool_rx_flow_rule *flow;
2847 struct flow_action_entry *act;
2848
2849 flow = kzalloc(sizeof(struct ethtool_rx_flow_rule) +
2850 sizeof(struct ethtool_rx_flow_match), GFP_KERNEL);
2851 if (!flow)
2852 return ERR_PTR(-ENOMEM);
2853
2854 /* ethtool_rx supports only one single action per rule. */
2855 flow->rule = flow_rule_alloc(1);
2856 if (!flow->rule) {
2857 kfree(flow);
2858 return ERR_PTR(-ENOMEM);
2859 }
2860
2861 match = (struct ethtool_rx_flow_match *)flow->priv;
2862 flow->rule->match.dissector = &match->dissector;
2863 flow->rule->match.mask = &match->mask;
2864 flow->rule->match.key = &match->key;
2865
2866 match->mask.basic.n_proto = htons(0xffff);
2867
2868 switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
Maxime Chevallier5b9469a2019-06-27 10:52:26 +02002869 case ETHER_FLOW: {
2870 const struct ethhdr *ether_spec, *ether_m_spec;
2871
2872 ether_spec = &fs->h_u.ether_spec;
2873 ether_m_spec = &fs->m_u.ether_spec;
2874
2875 if (!is_zero_ether_addr(ether_m_spec->h_source)) {
2876 ether_addr_copy(match->key.eth_addrs.src,
2877 ether_spec->h_source);
2878 ether_addr_copy(match->mask.eth_addrs.src,
2879 ether_m_spec->h_source);
2880 }
2881 if (!is_zero_ether_addr(ether_m_spec->h_dest)) {
2882 ether_addr_copy(match->key.eth_addrs.dst,
2883 ether_spec->h_dest);
2884 ether_addr_copy(match->mask.eth_addrs.dst,
2885 ether_m_spec->h_dest);
2886 }
2887 if (ether_m_spec->h_proto) {
2888 match->key.basic.n_proto = ether_spec->h_proto;
2889 match->mask.basic.n_proto = ether_m_spec->h_proto;
2890 }
2891 }
2892 break;
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01002893 case TCP_V4_FLOW:
2894 case UDP_V4_FLOW: {
2895 const struct ethtool_tcpip4_spec *v4_spec, *v4_m_spec;
2896
2897 match->key.basic.n_proto = htons(ETH_P_IP);
2898
2899 v4_spec = &fs->h_u.tcp_ip4_spec;
2900 v4_m_spec = &fs->m_u.tcp_ip4_spec;
2901
2902 if (v4_m_spec->ip4src) {
2903 match->key.ipv4.src = v4_spec->ip4src;
2904 match->mask.ipv4.src = v4_m_spec->ip4src;
2905 }
2906 if (v4_m_spec->ip4dst) {
2907 match->key.ipv4.dst = v4_spec->ip4dst;
2908 match->mask.ipv4.dst = v4_m_spec->ip4dst;
2909 }
2910 if (v4_m_spec->ip4src ||
2911 v4_m_spec->ip4dst) {
2912 match->dissector.used_keys |=
2913 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS);
2914 match->dissector.offset[FLOW_DISSECTOR_KEY_IPV4_ADDRS] =
2915 offsetof(struct ethtool_rx_flow_key, ipv4);
2916 }
2917 if (v4_m_spec->psrc) {
2918 match->key.tp.src = v4_spec->psrc;
2919 match->mask.tp.src = v4_m_spec->psrc;
2920 }
2921 if (v4_m_spec->pdst) {
2922 match->key.tp.dst = v4_spec->pdst;
2923 match->mask.tp.dst = v4_m_spec->pdst;
2924 }
2925 if (v4_m_spec->psrc ||
2926 v4_m_spec->pdst) {
2927 match->dissector.used_keys |=
2928 BIT(FLOW_DISSECTOR_KEY_PORTS);
2929 match->dissector.offset[FLOW_DISSECTOR_KEY_PORTS] =
2930 offsetof(struct ethtool_rx_flow_key, tp);
2931 }
2932 if (v4_m_spec->tos) {
2933 match->key.ip.tos = v4_spec->tos;
2934 match->mask.ip.tos = v4_m_spec->tos;
2935 match->dissector.used_keys |=
2936 BIT(FLOW_DISSECTOR_KEY_IP);
2937 match->dissector.offset[FLOW_DISSECTOR_KEY_IP] =
2938 offsetof(struct ethtool_rx_flow_key, ip);
2939 }
2940 }
2941 break;
2942 case TCP_V6_FLOW:
2943 case UDP_V6_FLOW: {
2944 const struct ethtool_tcpip6_spec *v6_spec, *v6_m_spec;
2945
2946 match->key.basic.n_proto = htons(ETH_P_IPV6);
2947
2948 v6_spec = &fs->h_u.tcp_ip6_spec;
2949 v6_m_spec = &fs->m_u.tcp_ip6_spec;
2950 if (memcmp(v6_m_spec->ip6src, &zero_addr, sizeof(zero_addr))) {
2951 memcpy(&match->key.ipv6.src, v6_spec->ip6src,
2952 sizeof(match->key.ipv6.src));
2953 memcpy(&match->mask.ipv6.src, v6_m_spec->ip6src,
2954 sizeof(match->mask.ipv6.src));
2955 }
2956 if (memcmp(v6_m_spec->ip6dst, &zero_addr, sizeof(zero_addr))) {
2957 memcpy(&match->key.ipv6.dst, v6_spec->ip6dst,
2958 sizeof(match->key.ipv6.dst));
2959 memcpy(&match->mask.ipv6.dst, v6_m_spec->ip6dst,
2960 sizeof(match->mask.ipv6.dst));
2961 }
2962 if (memcmp(v6_m_spec->ip6src, &zero_addr, sizeof(zero_addr)) ||
2963 memcmp(v6_m_spec->ip6src, &zero_addr, sizeof(zero_addr))) {
2964 match->dissector.used_keys |=
2965 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS);
2966 match->dissector.offset[FLOW_DISSECTOR_KEY_IPV6_ADDRS] =
2967 offsetof(struct ethtool_rx_flow_key, ipv6);
2968 }
2969 if (v6_m_spec->psrc) {
2970 match->key.tp.src = v6_spec->psrc;
2971 match->mask.tp.src = v6_m_spec->psrc;
2972 }
2973 if (v6_m_spec->pdst) {
2974 match->key.tp.dst = v6_spec->pdst;
2975 match->mask.tp.dst = v6_m_spec->pdst;
2976 }
2977 if (v6_m_spec->psrc ||
2978 v6_m_spec->pdst) {
2979 match->dissector.used_keys |=
2980 BIT(FLOW_DISSECTOR_KEY_PORTS);
2981 match->dissector.offset[FLOW_DISSECTOR_KEY_PORTS] =
2982 offsetof(struct ethtool_rx_flow_key, tp);
2983 }
2984 if (v6_m_spec->tclass) {
2985 match->key.ip.tos = v6_spec->tclass;
2986 match->mask.ip.tos = v6_m_spec->tclass;
2987 match->dissector.used_keys |=
2988 BIT(FLOW_DISSECTOR_KEY_IP);
2989 match->dissector.offset[FLOW_DISSECTOR_KEY_IP] =
2990 offsetof(struct ethtool_rx_flow_key, ip);
2991 }
2992 }
2993 break;
2994 default:
2995 ethtool_rx_flow_rule_destroy(flow);
2996 return ERR_PTR(-EINVAL);
2997 }
2998
2999 switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
3000 case TCP_V4_FLOW:
3001 case TCP_V6_FLOW:
3002 match->key.basic.ip_proto = IPPROTO_TCP;
3003 break;
3004 case UDP_V4_FLOW:
3005 case UDP_V6_FLOW:
3006 match->key.basic.ip_proto = IPPROTO_UDP;
3007 break;
3008 }
3009 match->mask.basic.ip_proto = 0xff;
3010
3011 match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
3012 match->dissector.offset[FLOW_DISSECTOR_KEY_BASIC] =
3013 offsetof(struct ethtool_rx_flow_key, basic);
3014
3015 if (fs->flow_type & FLOW_EXT) {
3016 const struct ethtool_flow_ext *ext_h_spec = &fs->h_ext;
3017 const struct ethtool_flow_ext *ext_m_spec = &fs->m_ext;
3018
Maxime Chevallierb73484b2019-05-30 16:08:40 +02003019 if (ext_m_spec->vlan_etype) {
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01003020 match->key.vlan.vlan_tpid = ext_h_spec->vlan_etype;
3021 match->mask.vlan.vlan_tpid = ext_m_spec->vlan_etype;
Maxime Chevallierb73484b2019-05-30 16:08:40 +02003022 }
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01003023
Maxime Chevallierb73484b2019-05-30 16:08:40 +02003024 if (ext_m_spec->vlan_tci) {
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01003025 match->key.vlan.vlan_id =
3026 ntohs(ext_h_spec->vlan_tci) & 0x0fff;
3027 match->mask.vlan.vlan_id =
3028 ntohs(ext_m_spec->vlan_tci) & 0x0fff;
3029
Maxime Chevallierf0d2ca12019-06-12 17:18:38 +02003030 match->key.vlan.vlan_dei =
3031 !!(ext_h_spec->vlan_tci & htons(0x1000));
3032 match->mask.vlan.vlan_dei =
3033 !!(ext_m_spec->vlan_tci & htons(0x1000));
3034
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01003035 match->key.vlan.vlan_priority =
3036 (ntohs(ext_h_spec->vlan_tci) & 0xe000) >> 13;
3037 match->mask.vlan.vlan_priority =
3038 (ntohs(ext_m_spec->vlan_tci) & 0xe000) >> 13;
Maxime Chevallierb73484b2019-05-30 16:08:40 +02003039 }
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01003040
Maxime Chevallierb73484b2019-05-30 16:08:40 +02003041 if (ext_m_spec->vlan_etype ||
3042 ext_m_spec->vlan_tci) {
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01003043 match->dissector.used_keys |=
3044 BIT(FLOW_DISSECTOR_KEY_VLAN);
3045 match->dissector.offset[FLOW_DISSECTOR_KEY_VLAN] =
3046 offsetof(struct ethtool_rx_flow_key, vlan);
3047 }
3048 }
3049 if (fs->flow_type & FLOW_MAC_EXT) {
3050 const struct ethtool_flow_ext *ext_h_spec = &fs->h_ext;
3051 const struct ethtool_flow_ext *ext_m_spec = &fs->m_ext;
3052
Nathan Chancellor8b34ec62019-02-07 21:46:53 -07003053 memcpy(match->key.eth_addrs.dst, ext_h_spec->h_dest,
3054 ETH_ALEN);
3055 memcpy(match->mask.eth_addrs.dst, ext_m_spec->h_dest,
3056 ETH_ALEN);
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01003057
Nathan Chancellor8b34ec62019-02-07 21:46:53 -07003058 match->dissector.used_keys |=
3059 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS);
3060 match->dissector.offset[FLOW_DISSECTOR_KEY_ETH_ADDRS] =
3061 offsetof(struct ethtool_rx_flow_key, eth_addrs);
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01003062 }
3063
3064 act = &flow->rule->action.entries[0];
3065 switch (fs->ring_cookie) {
3066 case RX_CLS_FLOW_DISC:
3067 act->id = FLOW_ACTION_DROP;
3068 break;
3069 case RX_CLS_FLOW_WAKE:
3070 act->id = FLOW_ACTION_WAKE;
3071 break;
3072 default:
3073 act->id = FLOW_ACTION_QUEUE;
3074 if (fs->flow_type & FLOW_RSS)
3075 act->queue.ctx = input->rss_ctx;
3076
3077 act->queue.vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
3078 act->queue.index = ethtool_get_flow_spec_ring(fs->ring_cookie);
3079 break;
3080 }
3081
3082 return flow;
3083}
3084EXPORT_SYMBOL(ethtool_rx_flow_rule_create);
3085
3086void ethtool_rx_flow_rule_destroy(struct ethtool_rx_flow_rule *flow)
3087{
3088 kfree(flow->rule);
3089 kfree(flow);
3090}
3091EXPORT_SYMBOL(ethtool_rx_flow_rule_destroy);