blob: aed2c2cf1623f57a101a0849b731b4ddc585325e [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>
David S. Miller73da16c2010-09-21 16:12:11 -070020#include <linux/vmalloc.h>
Russell Kinge679c9c2018-03-28 15:44:16 -070021#include <linux/sfp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Ben Hutchings68f512f2011-04-02 00:35:15 +010023#include <linux/rtnetlink.h>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010024#include <linux/sched/signal.h>
Eric Dumazet960fb622014-11-16 06:23:05 -080025#include <linux/net.h>
Jakub Kicinskiddb6e992019-01-31 10:50:47 -080026#include <net/devlink.h>
Jakub Kicinski1661d342018-10-01 14:51:36 +020027#include <net/xdp_sock.h>
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +010028#include <net/flow_offload.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Michal Kubecekd44e1312019-12-11 10:58:29 +010030#include "common.h"
31
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +090032/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 * Some useful ethtool_ops methods that're device independent.
34 * If we find that all drivers want to do the same thing here,
35 * we can turn these into dev_() function calls.
36 */
37
38u32 ethtool_op_get_link(struct net_device *dev)
39{
40 return netif_carrier_ok(dev) ? 1 : 0;
41}
chavey97f8aef2010-04-07 21:54:42 -070042EXPORT_SYMBOL(ethtool_op_get_link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Richard Cochran02eacbd2012-04-03 22:59:22 +000044int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
45{
46 info->so_timestamping =
47 SOF_TIMESTAMPING_TX_SOFTWARE |
48 SOF_TIMESTAMPING_RX_SOFTWARE |
49 SOF_TIMESTAMPING_SOFTWARE;
50 info->phc_index = -1;
51 return 0;
52}
53EXPORT_SYMBOL(ethtool_op_get_ts_info);
54
Linus Torvalds1da177e2005-04-16 15:20:36 -070055/* Handlers for each ethtool command */
56
Michał Mirosław475414f2011-11-15 15:29:55 +000057#define ETHTOOL_DEV_FEATURE_WORDS ((NETDEV_FEATURE_COUNT + 31) / 32)
Michał Mirosław5455c692011-02-15 16:59:17 +000058
59static 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:
Tom Herberta1882222015-12-14 11:19:43 -0800199 return NETIF_F_CSUM_MASK | NETIF_F_SCTP_CRC;
Michał Mirosławe83d3602011-02-15 16:59:18 +0000200 case ETHTOOL_GRXCSUM:
201 case ETHTOOL_SRXCSUM:
202 return NETIF_F_RXCSUM;
Michał Mirosław0a417702011-02-15 16:59:17 +0000203 case ETHTOOL_GSG:
204 case ETHTOOL_SSG:
205 return NETIF_F_SG;
206 case ETHTOOL_GTSO:
207 case ETHTOOL_STSO:
208 return NETIF_F_ALL_TSO;
Michał Mirosław0a417702011-02-15 16:59:17 +0000209 case ETHTOOL_GGSO:
210 case ETHTOOL_SGSO:
211 return NETIF_F_GSO;
212 case ETHTOOL_GGRO:
213 case ETHTOOL_SGRO:
214 return NETIF_F_GRO;
215 default:
216 BUG();
217 }
218}
219
Michał Mirosław0a417702011-02-15 16:59:17 +0000220static int ethtool_get_one_feature(struct net_device *dev,
221 char __user *useraddr, u32 ethcmd)
222{
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000223 netdev_features_t mask = ethtool_get_feature_mask(ethcmd);
Michał Mirosław0a417702011-02-15 16:59:17 +0000224 struct ethtool_value edata = {
225 .cmd = ethcmd,
Michał Mirosław86794882011-02-15 16:59:17 +0000226 .data = !!(dev->features & mask),
Michał Mirosław0a417702011-02-15 16:59:17 +0000227 };
Michał Mirosław0a417702011-02-15 16:59:17 +0000228
Michał Mirosław0a417702011-02-15 16:59:17 +0000229 if (copy_to_user(useraddr, &edata, sizeof(edata)))
230 return -EFAULT;
231 return 0;
232}
233
Michał Mirosław0a417702011-02-15 16:59:17 +0000234static int ethtool_set_one_feature(struct net_device *dev,
235 void __user *useraddr, u32 ethcmd)
236{
237 struct ethtool_value edata;
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000238 netdev_features_t mask;
Michał Mirosław0a417702011-02-15 16:59:17 +0000239
240 if (copy_from_user(&edata, useraddr, sizeof(edata)))
241 return -EFAULT;
242
Michał Mirosław86794882011-02-15 16:59:17 +0000243 mask = ethtool_get_feature_mask(ethcmd);
244 mask &= dev->hw_features;
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000245 if (!mask)
Michał Mirosław0a417702011-02-15 16:59:17 +0000246 return -EOPNOTSUPP;
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000247
248 if (edata.data)
249 dev->wanted_features |= mask;
250 else
251 dev->wanted_features &= ~mask;
252
253 __netdev_update_features(dev);
254
255 return 0;
Michał Mirosław0a417702011-02-15 16:59:17 +0000256}
257
Michał Mirosław02b3a552011-11-15 15:29:55 +0000258#define ETH_ALL_FLAGS (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \
259 ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH)
Patrick McHardyf6469682013-04-19 02:04:27 +0000260#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_CTAG_RX | \
261 NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_NTUPLE | \
262 NETIF_F_RXHASH)
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000263
264static u32 __ethtool_get_flags(struct net_device *dev)
265{
Michał Mirosław02b3a552011-11-15 15:29:55 +0000266 u32 flags = 0;
267
Dragos Foianu8a731252013-07-13 14:43:00 +0100268 if (dev->features & NETIF_F_LRO)
269 flags |= ETH_FLAG_LRO;
270 if (dev->features & NETIF_F_HW_VLAN_CTAG_RX)
271 flags |= ETH_FLAG_RXVLAN;
272 if (dev->features & NETIF_F_HW_VLAN_CTAG_TX)
273 flags |= ETH_FLAG_TXVLAN;
274 if (dev->features & NETIF_F_NTUPLE)
275 flags |= ETH_FLAG_NTUPLE;
276 if (dev->features & NETIF_F_RXHASH)
277 flags |= ETH_FLAG_RXHASH;
Michał Mirosław02b3a552011-11-15 15:29:55 +0000278
279 return flags;
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000280}
281
282static int __ethtool_set_flags(struct net_device *dev, u32 data)
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000283{
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000284 netdev_features_t features = 0, changed;
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000285
Michał Mirosław02b3a552011-11-15 15:29:55 +0000286 if (data & ~ETH_ALL_FLAGS)
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000287 return -EINVAL;
288
Dragos Foianu8a731252013-07-13 14:43:00 +0100289 if (data & ETH_FLAG_LRO)
290 features |= NETIF_F_LRO;
291 if (data & ETH_FLAG_RXVLAN)
292 features |= NETIF_F_HW_VLAN_CTAG_RX;
293 if (data & ETH_FLAG_TXVLAN)
294 features |= NETIF_F_HW_VLAN_CTAG_TX;
295 if (data & ETH_FLAG_NTUPLE)
296 features |= NETIF_F_NTUPLE;
297 if (data & ETH_FLAG_RXHASH)
298 features |= NETIF_F_RXHASH;
Michał Mirosław02b3a552011-11-15 15:29:55 +0000299
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000300 /* allow changing only bits set in hw_features */
Michał Mirosław02b3a552011-11-15 15:29:55 +0000301 changed = (features ^ dev->features) & ETH_ALL_FEATURES;
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000302 if (changed & ~dev->hw_features)
303 return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;
304
305 dev->wanted_features =
Michał Mirosław02b3a552011-11-15 15:29:55 +0000306 (dev->wanted_features & ~changed) | (features & changed);
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000307
Michał Mirosław6cb6a272011-04-02 22:48:47 -0700308 __netdev_update_features(dev);
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000309
310 return 0;
311}
312
Alan Brady5a6cd6d2017-10-05 14:53:40 -0700313/* Given two link masks, AND them together and save the result in dst. */
314void ethtool_intersect_link_masks(struct ethtool_link_ksettings *dst,
315 struct ethtool_link_ksettings *src)
316{
317 unsigned int size = BITS_TO_LONGS(__ETHTOOL_LINK_MODE_MASK_NBITS);
318 unsigned int idx = 0;
319
320 for (; idx < size; idx++) {
321 dst->link_modes.supported[idx] &=
322 src->link_modes.supported[idx];
323 dst->link_modes.advertising[idx] &=
324 src->link_modes.advertising[idx];
325 }
326}
327EXPORT_SYMBOL(ethtool_intersect_link_masks);
328
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200329void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst,
330 u32 legacy_u32)
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800331{
332 bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS);
333 dst[0] = legacy_u32;
334}
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200335EXPORT_SYMBOL(ethtool_convert_legacy_u32_to_link_mode);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800336
337/* return false if src had higher bits set. lower bits always updated. */
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200338bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
339 const unsigned long *src)
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800340{
341 bool retval = true;
342
343 /* TODO: following test will soon always be true */
344 if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) {
345 __ETHTOOL_DECLARE_LINK_MODE_MASK(ext);
346
347 bitmap_zero(ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
348 bitmap_fill(ext, 32);
349 bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
350 if (bitmap_intersects(ext, src,
351 __ETHTOOL_LINK_MODE_MASK_NBITS)) {
352 /* src mask goes beyond bit 31 */
353 retval = false;
354 }
355 }
356 *legacy_u32 = src[0];
357 return retval;
358}
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200359EXPORT_SYMBOL(ethtool_convert_link_mode_to_legacy_u32);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800360
361/* return false if legacy contained non-0 deprecated fields
Niklas Söderlund95491e32017-10-20 01:32:08 +0200362 * maxtxpkt/maxrxpkt. rest of ksettings always updated
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800363 */
364static bool
365convert_legacy_settings_to_link_ksettings(
366 struct ethtool_link_ksettings *link_ksettings,
367 const struct ethtool_cmd *legacy_settings)
368{
369 bool retval = true;
370
371 memset(link_ksettings, 0, sizeof(*link_ksettings));
372
373 /* This is used to tell users that driver is still using these
374 * deprecated legacy fields, and they should not use
375 * %ETHTOOL_GLINKSETTINGS/%ETHTOOL_SLINKSETTINGS
376 */
Niklas Söderlund95491e32017-10-20 01:32:08 +0200377 if (legacy_settings->maxtxpkt ||
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800378 legacy_settings->maxrxpkt)
379 retval = false;
380
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200381 ethtool_convert_legacy_u32_to_link_mode(
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800382 link_ksettings->link_modes.supported,
383 legacy_settings->supported);
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200384 ethtool_convert_legacy_u32_to_link_mode(
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800385 link_ksettings->link_modes.advertising,
386 legacy_settings->advertising);
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200387 ethtool_convert_legacy_u32_to_link_mode(
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800388 link_ksettings->link_modes.lp_advertising,
389 legacy_settings->lp_advertising);
390 link_ksettings->base.speed
391 = ethtool_cmd_speed(legacy_settings);
392 link_ksettings->base.duplex
393 = legacy_settings->duplex;
394 link_ksettings->base.port
395 = legacy_settings->port;
396 link_ksettings->base.phy_address
397 = legacy_settings->phy_address;
398 link_ksettings->base.autoneg
399 = legacy_settings->autoneg;
400 link_ksettings->base.mdio_support
401 = legacy_settings->mdio_support;
402 link_ksettings->base.eth_tp_mdix
403 = legacy_settings->eth_tp_mdix;
404 link_ksettings->base.eth_tp_mdix_ctrl
405 = legacy_settings->eth_tp_mdix_ctrl;
406 return retval;
407}
408
409/* return false if ksettings link modes had higher bits
410 * set. legacy_settings always updated (best effort)
411 */
412static bool
413convert_link_ksettings_to_legacy_settings(
414 struct ethtool_cmd *legacy_settings,
415 const struct ethtool_link_ksettings *link_ksettings)
416{
417 bool retval = true;
418
419 memset(legacy_settings, 0, sizeof(*legacy_settings));
420 /* this also clears the deprecated fields in legacy structure:
421 * __u8 transceiver;
422 * __u32 maxtxpkt;
423 * __u32 maxrxpkt;
424 */
425
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200426 retval &= ethtool_convert_link_mode_to_legacy_u32(
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800427 &legacy_settings->supported,
428 link_ksettings->link_modes.supported);
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200429 retval &= ethtool_convert_link_mode_to_legacy_u32(
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800430 &legacy_settings->advertising,
431 link_ksettings->link_modes.advertising);
Philippe Reynes6d62b4d2016-04-15 00:34:59 +0200432 retval &= ethtool_convert_link_mode_to_legacy_u32(
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800433 &legacy_settings->lp_advertising,
434 link_ksettings->link_modes.lp_advertising);
435 ethtool_cmd_speed_set(legacy_settings, link_ksettings->base.speed);
436 legacy_settings->duplex
437 = link_ksettings->base.duplex;
438 legacy_settings->port
439 = link_ksettings->base.port;
440 legacy_settings->phy_address
441 = link_ksettings->base.phy_address;
442 legacy_settings->autoneg
443 = link_ksettings->base.autoneg;
444 legacy_settings->mdio_support
445 = link_ksettings->base.mdio_support;
446 legacy_settings->eth_tp_mdix
447 = link_ksettings->base.eth_tp_mdix;
448 legacy_settings->eth_tp_mdix_ctrl
449 = link_ksettings->base.eth_tp_mdix_ctrl;
Florian Fainelli19cab882017-09-20 15:52:13 -0700450 legacy_settings->transceiver
451 = link_ksettings->base.transceiver;
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800452 return retval;
453}
454
455/* number of 32-bit words to store the user's link mode bitmaps */
456#define __ETHTOOL_LINK_MODE_MASK_NU32 \
457 DIV_ROUND_UP(__ETHTOOL_LINK_MODE_MASK_NBITS, 32)
458
459/* layout of the struct passed from/to userland */
460struct ethtool_link_usettings {
461 struct ethtool_link_settings base;
462 struct {
463 __u32 supported[__ETHTOOL_LINK_MODE_MASK_NU32];
464 __u32 advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
465 __u32 lp_advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
466 } link_modes;
467};
468
Michal Kubecek9b300492018-08-28 19:56:58 +0200469/* Internal kernel helper to query a device ethtool_link_settings. */
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800470int __ethtool_get_link_ksettings(struct net_device *dev,
471 struct ethtool_link_ksettings *link_ksettings)
472{
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800473 ASSERT_RTNL();
474
Michal Kubecek9b300492018-08-28 19:56:58 +0200475 if (!dev->ethtool_ops->get_link_ksettings)
David Decotigny3237fc62016-02-24 10:58:11 -0800476 return -EOPNOTSUPP;
477
Michal Kubecek9b300492018-08-28 19:56:58 +0200478 memset(link_ksettings, 0, sizeof(*link_ksettings));
479 return dev->ethtool_ops->get_link_ksettings(dev, link_ksettings);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800480}
481EXPORT_SYMBOL(__ethtool_get_link_ksettings);
482
483/* convert ethtool_link_usettings in user space to a kernel internal
484 * ethtool_link_ksettings. return 0 on success, errno on error.
485 */
486static int load_link_ksettings_from_user(struct ethtool_link_ksettings *to,
487 const void __user *from)
488{
489 struct ethtool_link_usettings link_usettings;
490
491 if (copy_from_user(&link_usettings, from, sizeof(link_usettings)))
492 return -EFAULT;
493
494 memcpy(&to->base, &link_usettings.base, sizeof(to->base));
Yury Norov3aa56882018-02-06 15:38:06 -0800495 bitmap_from_arr32(to->link_modes.supported,
496 link_usettings.link_modes.supported,
497 __ETHTOOL_LINK_MODE_MASK_NBITS);
498 bitmap_from_arr32(to->link_modes.advertising,
499 link_usettings.link_modes.advertising,
500 __ETHTOOL_LINK_MODE_MASK_NBITS);
501 bitmap_from_arr32(to->link_modes.lp_advertising,
502 link_usettings.link_modes.lp_advertising,
503 __ETHTOOL_LINK_MODE_MASK_NBITS);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800504
505 return 0;
506}
507
508/* convert a kernel internal ethtool_link_ksettings to
509 * ethtool_link_usettings in user space. return 0 on success, errno on
510 * error.
511 */
512static int
513store_link_ksettings_for_user(void __user *to,
514 const struct ethtool_link_ksettings *from)
515{
516 struct ethtool_link_usettings link_usettings;
517
518 memcpy(&link_usettings.base, &from->base, sizeof(link_usettings));
Yury Norov3aa56882018-02-06 15:38:06 -0800519 bitmap_to_arr32(link_usettings.link_modes.supported,
520 from->link_modes.supported,
521 __ETHTOOL_LINK_MODE_MASK_NBITS);
522 bitmap_to_arr32(link_usettings.link_modes.advertising,
523 from->link_modes.advertising,
524 __ETHTOOL_LINK_MODE_MASK_NBITS);
525 bitmap_to_arr32(link_usettings.link_modes.lp_advertising,
526 from->link_modes.lp_advertising,
527 __ETHTOOL_LINK_MODE_MASK_NBITS);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800528
529 if (copy_to_user(to, &link_usettings, sizeof(link_usettings)))
530 return -EFAULT;
531
532 return 0;
533}
534
Michal Kubecek9b300492018-08-28 19:56:58 +0200535/* Query device for its ethtool_link_settings. */
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800536static int ethtool_get_link_ksettings(struct net_device *dev,
537 void __user *useraddr)
538{
539 int err = 0;
540 struct ethtool_link_ksettings link_ksettings;
541
542 ASSERT_RTNL();
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800543 if (!dev->ethtool_ops->get_link_ksettings)
544 return -EOPNOTSUPP;
545
546 /* handle bitmap nbits handshake */
547 if (copy_from_user(&link_ksettings.base, useraddr,
548 sizeof(link_ksettings.base)))
549 return -EFAULT;
550
551 if (__ETHTOOL_LINK_MODE_MASK_NU32
552 != link_ksettings.base.link_mode_masks_nwords) {
553 /* wrong link mode nbits requested */
554 memset(&link_ksettings, 0, sizeof(link_ksettings));
Ben Hutchings793cf872016-03-14 01:05:38 +0000555 link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS;
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800556 /* send back number of words required as negative val */
557 compiletime_assert(__ETHTOOL_LINK_MODE_MASK_NU32 <= S8_MAX,
558 "need too many bits for link modes!");
559 link_ksettings.base.link_mode_masks_nwords
560 = -((s8)__ETHTOOL_LINK_MODE_MASK_NU32);
561
562 /* copy the base fields back to user, not the link
563 * mode bitmaps
564 */
565 if (copy_to_user(useraddr, &link_ksettings.base,
566 sizeof(link_ksettings.base)))
567 return -EFAULT;
568
569 return 0;
570 }
571
572 /* handshake successful: user/kernel agree on
573 * link_mode_masks_nwords
574 */
575
576 memset(&link_ksettings, 0, sizeof(link_ksettings));
577 err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings);
578 if (err < 0)
579 return err;
580
581 /* make sure we tell the right values to user */
582 link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS;
583 link_ksettings.base.link_mode_masks_nwords
584 = __ETHTOOL_LINK_MODE_MASK_NU32;
585
586 return store_link_ksettings_for_user(useraddr, &link_ksettings);
587}
588
Michal Kubecek9b300492018-08-28 19:56:58 +0200589/* Update device ethtool_link_settings. */
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800590static int ethtool_set_link_ksettings(struct net_device *dev,
591 void __user *useraddr)
592{
593 int err;
594 struct ethtool_link_ksettings link_ksettings;
595
596 ASSERT_RTNL();
597
598 if (!dev->ethtool_ops->set_link_ksettings)
599 return -EOPNOTSUPP;
600
601 /* make sure nbits field has expected value */
602 if (copy_from_user(&link_ksettings.base, useraddr,
603 sizeof(link_ksettings.base)))
604 return -EFAULT;
605
606 if (__ETHTOOL_LINK_MODE_MASK_NU32
607 != link_ksettings.base.link_mode_masks_nwords)
608 return -EINVAL;
609
610 /* copy the whole structure, now that we know it has expected
611 * format
612 */
613 err = load_link_ksettings_from_user(&link_ksettings, useraddr);
614 if (err)
615 return err;
616
617 /* re-check nwords field, just in case */
618 if (__ETHTOOL_LINK_MODE_MASK_NU32
619 != link_ksettings.base.link_mode_masks_nwords)
620 return -EINVAL;
621
622 return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
623}
624
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800625/* Query device for its ethtool_cmd settings.
626 *
Michal Kubecek9b300492018-08-28 19:56:58 +0200627 * Backward compatibility note: for compatibility with legacy ethtool, this is
628 * now implemented via get_link_ksettings. When driver reports higher link mode
629 * bits, a kernel warning is logged once (with name of 1st driver/device) to
630 * recommend user to upgrade ethtool, but the command is successful (only the
631 * lower link mode bits reported back to user). Deprecated fields from
632 * ethtool_cmd (transceiver/maxrxpkt/maxtxpkt) are always set to zero.
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800633 */
Jiri Pirko4bc71cb2011-09-03 03:34:30 +0000634static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
635{
Michal Kubecek9b300492018-08-28 19:56:58 +0200636 struct ethtool_link_ksettings link_ksettings;
Jiri Pirko4bc71cb2011-09-03 03:34:30 +0000637 struct ethtool_cmd cmd;
Michal Kubecek9b300492018-08-28 19:56:58 +0200638 int err;
Jiri Pirko4bc71cb2011-09-03 03:34:30 +0000639
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800640 ASSERT_RTNL();
Michal Kubecek9b300492018-08-28 19:56:58 +0200641 if (!dev->ethtool_ops->get_link_ksettings)
642 return -EOPNOTSUPP;
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800643
Michal Kubecek9b300492018-08-28 19:56:58 +0200644 memset(&link_ksettings, 0, sizeof(link_ksettings));
645 err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings);
646 if (err < 0)
647 return err;
648 convert_link_ksettings_to_legacy_settings(&cmd, &link_ksettings);
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800649
Michal Kubecek9b300492018-08-28 19:56:58 +0200650 /* send a sensible cmd tag back to user */
651 cmd.cmd = ETHTOOL_GSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
654 return -EFAULT;
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 return 0;
657}
658
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800659/* Update device link settings with given ethtool_cmd.
660 *
Michal Kubecek9b300492018-08-28 19:56:58 +0200661 * Backward compatibility note: for compatibility with legacy ethtool, this is
662 * now always implemented via set_link_settings. When user's request updates
663 * deprecated ethtool_cmd fields (transceiver/maxrxpkt/maxtxpkt), a kernel
664 * warning is logged once (with name of 1st driver/device) to recommend user to
665 * upgrade ethtool, and the request is rejected.
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800666 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
668{
Michal Kubecek9b300492018-08-28 19:56:58 +0200669 struct ethtool_link_ksettings link_ksettings;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 struct ethtool_cmd cmd;
671
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800672 ASSERT_RTNL();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
675 return -EFAULT;
Michal Kubecek9b300492018-08-28 19:56:58 +0200676 if (!dev->ethtool_ops->set_link_ksettings)
David Decotigny3f1ac7a2016-02-24 10:57:59 -0800677 return -EOPNOTSUPP;
678
Michal Kubecek9b300492018-08-28 19:56:58 +0200679 if (!convert_legacy_settings_to_link_ksettings(&link_ksettings, &cmd))
680 return -EINVAL;
681 link_ksettings.base.link_mode_masks_nwords =
682 __ETHTOOL_LINK_MODE_MASK_NU32;
683 return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684}
685
chavey97f8aef2010-04-07 21:54:42 -0700686static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
687 void __user *useraddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
689 struct ethtool_drvinfo info;
Stephen Hemminger76fd8592006-09-08 11:16:13 -0700690 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 memset(&info, 0, sizeof(info));
693 info.cmd = ETHTOOL_GDRVINFO;
Jiri Pirkoc03a14e2013-01-07 09:02:08 +0000694 if (ops->get_drvinfo) {
Ben Hutchings01414802010-08-17 02:31:15 -0700695 ops->get_drvinfo(dev, &info);
696 } else if (dev->dev.parent && dev->dev.parent->driver) {
697 strlcpy(info.bus_info, dev_name(dev->dev.parent),
698 sizeof(info.bus_info));
699 strlcpy(info.driver, dev->dev.parent->driver->name,
700 sizeof(info.driver));
701 } else {
702 return -EOPNOTSUPP;
703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Jeff Garzik723b2f52010-03-03 22:51:50 +0000705 /*
706 * this method of obtaining string set info is deprecated;
Jeff Garzikd17792e2010-03-04 08:21:53 +0000707 * Use ETHTOOL_GSSET_INFO instead.
Jeff Garzik723b2f52010-03-03 22:51:50 +0000708 */
Jiri Pirkoc03a14e2013-01-07 09:02:08 +0000709 if (ops->get_sset_count) {
Jeff Garzikff03d492007-08-15 16:01:08 -0700710 int rc;
711
712 rc = ops->get_sset_count(dev, ETH_SS_TEST);
713 if (rc >= 0)
714 info.testinfo_len = rc;
715 rc = ops->get_sset_count(dev, ETH_SS_STATS);
716 if (rc >= 0)
717 info.n_stats = rc;
Jeff Garzik339bf022007-08-15 16:01:32 -0700718 rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
719 if (rc >= 0)
720 info.n_priv_flags = rc;
Jeff Garzikff03d492007-08-15 16:01:08 -0700721 }
Yunsheng Linf9fc54d2018-12-26 19:51:46 +0800722 if (ops->get_regs_len) {
723 int ret = ops->get_regs_len(dev);
724
725 if (ret > 0)
726 info.regdump_len = ret;
727 }
728
Jiri Pirkoc03a14e2013-01-07 09:02:08 +0000729 if (ops->get_eeprom_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 info.eedump_len = ops->get_eeprom_len(dev);
731
Jakub Kicinskiddb6e992019-01-31 10:50:47 -0800732 if (!info.fw_version[0])
733 devlink_compat_running_version(dev, info.fw_version,
734 sizeof(info.fw_version));
Jakub Kicinskiddb6e992019-01-31 10:50:47 -0800735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 if (copy_to_user(useraddr, &info, sizeof(info)))
737 return -EFAULT;
738 return 0;
739}
740
Eric Dumazetf5c445e2010-03-08 12:17:04 -0800741static noinline_for_stack int ethtool_get_sset_info(struct net_device *dev,
chavey97f8aef2010-04-07 21:54:42 -0700742 void __user *useraddr)
Jeff Garzik723b2f52010-03-03 22:51:50 +0000743{
744 struct ethtool_sset_info info;
Jeff Garzik723b2f52010-03-03 22:51:50 +0000745 u64 sset_mask;
746 int i, idx = 0, n_bits = 0, ret, rc;
747 u32 *info_buf = NULL;
748
Jeff Garzik723b2f52010-03-03 22:51:50 +0000749 if (copy_from_user(&info, useraddr, sizeof(info)))
750 return -EFAULT;
751
752 /* store copy of mask, because we zero struct later on */
753 sset_mask = info.sset_mask;
754 if (!sset_mask)
755 return 0;
756
757 /* calculate size of return buffer */
Jeff Garzikd17792e2010-03-04 08:21:53 +0000758 n_bits = hweight64(sset_mask);
Jeff Garzik723b2f52010-03-03 22:51:50 +0000759
760 memset(&info, 0, sizeof(info));
761 info.cmd = ETHTOOL_GSSET_INFO;
762
Kees Cook6396bb22018-06-12 14:03:40 -0700763 info_buf = kcalloc(n_bits, sizeof(u32), GFP_USER);
Jeff Garzik723b2f52010-03-03 22:51:50 +0000764 if (!info_buf)
765 return -ENOMEM;
766
767 /*
768 * fill return buffer based on input bitmask and successful
769 * get_sset_count return
770 */
771 for (i = 0; i < 64; i++) {
772 if (!(sset_mask & (1ULL << i)))
773 continue;
774
Michał Mirosław340ae162011-02-15 16:59:16 +0000775 rc = __ethtool_get_sset_count(dev, i);
Jeff Garzik723b2f52010-03-03 22:51:50 +0000776 if (rc >= 0) {
777 info.sset_mask |= (1ULL << i);
778 info_buf[idx++] = rc;
779 }
780 }
781
782 ret = -EFAULT;
783 if (copy_to_user(useraddr, &info, sizeof(info)))
784 goto out;
785
786 useraddr += offsetof(struct ethtool_sset_info, data);
787 if (copy_to_user(useraddr, info_buf, idx * sizeof(u32)))
788 goto out;
789
790 ret = 0;
791
792out:
793 kfree(info_buf);
794 return ret;
795}
796
chavey97f8aef2010-04-07 21:54:42 -0700797static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
Ben Hutchingsbf988432010-06-28 08:45:58 +0000798 u32 cmd, void __user *useraddr)
Santwona Behera0853ad62008-07-02 03:47:41 -0700799{
Ben Hutchingsbf988432010-06-28 08:45:58 +0000800 struct ethtool_rxnfc info;
801 size_t info_size = sizeof(info);
Ben Hutchings55664f32012-01-03 12:04:51 +0000802 int rc;
Santwona Behera0853ad62008-07-02 03:47:41 -0700803
Santwona Behera59089d82009-02-20 00:58:13 -0800804 if (!dev->ethtool_ops->set_rxnfc)
Santwona Behera0853ad62008-07-02 03:47:41 -0700805 return -EOPNOTSUPP;
806
Ben Hutchingsbf988432010-06-28 08:45:58 +0000807 /* struct ethtool_rxnfc was originally defined for
808 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
809 * members. User-space might still be using that
810 * definition. */
811 if (cmd == ETHTOOL_SRXFH)
812 info_size = (offsetof(struct ethtool_rxnfc, data) +
813 sizeof(info.data));
814
815 if (copy_from_user(&info, useraddr, info_size))
Santwona Behera0853ad62008-07-02 03:47:41 -0700816 return -EFAULT;
817
Ben Hutchings55664f32012-01-03 12:04:51 +0000818 rc = dev->ethtool_ops->set_rxnfc(dev, &info);
819 if (rc)
820 return rc;
821
822 if (cmd == ETHTOOL_SRXCLSRLINS &&
823 copy_to_user(useraddr, &info, info_size))
824 return -EFAULT;
825
826 return 0;
Santwona Behera0853ad62008-07-02 03:47:41 -0700827}
828
chavey97f8aef2010-04-07 21:54:42 -0700829static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
Ben Hutchingsbf988432010-06-28 08:45:58 +0000830 u32 cmd, void __user *useraddr)
Santwona Behera0853ad62008-07-02 03:47:41 -0700831{
832 struct ethtool_rxnfc info;
Ben Hutchingsbf988432010-06-28 08:45:58 +0000833 size_t info_size = sizeof(info);
Santwona Behera59089d82009-02-20 00:58:13 -0800834 const struct ethtool_ops *ops = dev->ethtool_ops;
835 int ret;
836 void *rule_buf = NULL;
Santwona Behera0853ad62008-07-02 03:47:41 -0700837
Santwona Behera59089d82009-02-20 00:58:13 -0800838 if (!ops->get_rxnfc)
Santwona Behera0853ad62008-07-02 03:47:41 -0700839 return -EOPNOTSUPP;
840
Ben Hutchingsbf988432010-06-28 08:45:58 +0000841 /* struct ethtool_rxnfc was originally defined for
842 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
843 * members. User-space might still be using that
844 * definition. */
845 if (cmd == ETHTOOL_GRXFH)
846 info_size = (offsetof(struct ethtool_rxnfc, data) +
847 sizeof(info.data));
848
849 if (copy_from_user(&info, useraddr, info_size))
Santwona Behera0853ad62008-07-02 03:47:41 -0700850 return -EFAULT;
851
Edward Cree84a1d9c42018-03-08 15:45:03 +0000852 /* If FLOW_RSS was requested then user-space must be using the
853 * new definition, as FLOW_RSS is newer.
854 */
855 if (cmd == ETHTOOL_GRXFH && info.flow_type & FLOW_RSS) {
856 info_size = sizeof(info);
857 if (copy_from_user(&info, useraddr, info_size))
858 return -EFAULT;
Wenwen Wangd656fe42018-04-30 12:31:13 -0500859 /* Since malicious users may modify the original data,
860 * we need to check whether FLOW_RSS is still requested.
861 */
862 if (!(info.flow_type & FLOW_RSS))
863 return -EINVAL;
Edward Cree84a1d9c42018-03-08 15:45:03 +0000864 }
865
Wenwen Wang2bb32072018-10-09 08:15:38 -0500866 if (info.cmd != cmd)
867 return -EINVAL;
868
Santwona Behera59089d82009-02-20 00:58:13 -0800869 if (info.cmd == ETHTOOL_GRXCLSRLALL) {
870 if (info.rule_cnt > 0) {
Ben Hutchingsdb048b62010-06-28 08:44:07 +0000871 if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32))
Kees Cook6396bb22018-06-12 14:03:40 -0700872 rule_buf = kcalloc(info.rule_cnt, sizeof(u32),
Ben Hutchingsdb048b62010-06-28 08:44:07 +0000873 GFP_USER);
Santwona Behera59089d82009-02-20 00:58:13 -0800874 if (!rule_buf)
875 return -ENOMEM;
876 }
877 }
Santwona Behera0853ad62008-07-02 03:47:41 -0700878
Santwona Behera59089d82009-02-20 00:58:13 -0800879 ret = ops->get_rxnfc(dev, &info, rule_buf);
880 if (ret < 0)
881 goto err_out;
882
883 ret = -EFAULT;
Ben Hutchingsbf988432010-06-28 08:45:58 +0000884 if (copy_to_user(useraddr, &info, info_size))
Santwona Behera59089d82009-02-20 00:58:13 -0800885 goto err_out;
886
887 if (rule_buf) {
888 useraddr += offsetof(struct ethtool_rxnfc, rule_locs);
889 if (copy_to_user(useraddr, rule_buf,
890 info.rule_cnt * sizeof(u32)))
891 goto err_out;
892 }
893 ret = 0;
894
895err_out:
Wei Yongjunc9cacec2009-03-31 15:06:26 -0700896 kfree(rule_buf);
Santwona Behera59089d82009-02-20 00:58:13 -0800897
898 return ret;
Santwona Behera0853ad62008-07-02 03:47:41 -0700899}
900
Venkata Duvvuru3de0b592014-04-21 15:37:59 +0530901static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,
902 struct ethtool_rxnfc *rx_rings,
903 u32 size)
904{
Ben Hutchingsfb95cd82014-05-15 00:46:45 +0100905 int i;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +0530906
907 if (copy_from_user(indir, useraddr, size * sizeof(indir[0])))
Ben Hutchingsfb95cd82014-05-15 00:46:45 +0100908 return -EFAULT;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +0530909
910 /* Validate ring indices */
Ben Hutchingsfb95cd82014-05-15 00:46:45 +0100911 for (i = 0; i < size; i++)
912 if (indir[i] >= rx_rings->data)
913 return -EINVAL;
914
915 return 0;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +0530916}
917
Kim Jonesba905f52016-02-02 03:51:16 +0000918u8 netdev_rss_key[NETDEV_RSS_KEY_LEN] __read_mostly;
Eric Dumazet960fb622014-11-16 06:23:05 -0800919
920void netdev_rss_key_fill(void *buffer, size_t len)
921{
922 BUG_ON(len > sizeof(netdev_rss_key));
923 net_get_random_once(netdev_rss_key, sizeof(netdev_rss_key));
924 memcpy(buffer, netdev_rss_key, len);
925}
926EXPORT_SYMBOL(netdev_rss_key_fill);
927
Keller, Jacob Ed4ab4282016-02-08 16:05:03 -0800928static int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max)
929{
930 u32 dev_size, current_max = 0;
931 u32 *indir;
932 int ret;
933
934 if (!dev->ethtool_ops->get_rxfh_indir_size ||
935 !dev->ethtool_ops->get_rxfh)
936 return -EOPNOTSUPP;
937 dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
938 if (dev_size == 0)
939 return -EOPNOTSUPP;
940
941 indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
942 if (!indir)
943 return -ENOMEM;
944
945 ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL);
946 if (ret)
947 goto out;
948
949 while (dev_size--)
950 current_max = max(current_max, indir[dev_size]);
951
952 *max = current_max;
953
954out:
955 kfree(indir);
956 return ret;
957}
958
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000959static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
960 void __user *useraddr)
961{
Ben Hutchings7850f632011-12-15 13:55:01 +0000962 u32 user_size, dev_size;
963 u32 *indir;
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000964 int ret;
965
Ben Hutchings7850f632011-12-15 13:55:01 +0000966 if (!dev->ethtool_ops->get_rxfh_indir_size ||
Ben Hutchingsfe62d002014-05-15 01:25:27 +0100967 !dev->ethtool_ops->get_rxfh)
Ben Hutchings7850f632011-12-15 13:55:01 +0000968 return -EOPNOTSUPP;
969 dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
970 if (dev_size == 0)
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000971 return -EOPNOTSUPP;
972
Ben Hutchings7850f632011-12-15 13:55:01 +0000973 if (copy_from_user(&user_size,
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000974 useraddr + offsetof(struct ethtool_rxfh_indir, size),
Ben Hutchings7850f632011-12-15 13:55:01 +0000975 sizeof(user_size)))
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000976 return -EFAULT;
977
Ben Hutchings7850f632011-12-15 13:55:01 +0000978 if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh_indir, size),
979 &dev_size, sizeof(dev_size)))
980 return -EFAULT;
981
982 /* If the user buffer size is 0, this is just a query for the
983 * device table size. Otherwise, if it's smaller than the
984 * device table size it's an error.
985 */
986 if (user_size < dev_size)
987 return user_size == 0 ? 0 : -EINVAL;
988
989 indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000990 if (!indir)
991 return -ENOMEM;
992
Eyal Perry892311f2014-12-02 18:12:10 +0200993 ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL);
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000994 if (ret)
995 goto out;
996
Ben Hutchings7850f632011-12-15 13:55:01 +0000997 if (copy_to_user(useraddr +
998 offsetof(struct ethtool_rxfh_indir, ring_index[0]),
999 indir, dev_size * sizeof(indir[0])))
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001000 ret = -EFAULT;
1001
1002out:
1003 kfree(indir);
1004 return ret;
1005}
1006
1007static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
1008 void __user *useraddr)
1009{
Ben Hutchings7850f632011-12-15 13:55:01 +00001010 struct ethtool_rxnfc rx_rings;
1011 u32 user_size, dev_size, i;
1012 u32 *indir;
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001013 const struct ethtool_ops *ops = dev->ethtool_ops;
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001014 int ret;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301015 u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]);
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001016
Ben Hutchingsfe62d002014-05-15 01:25:27 +01001017 if (!ops->get_rxfh_indir_size || !ops->set_rxfh ||
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001018 !ops->get_rxnfc)
Ben Hutchings7850f632011-12-15 13:55:01 +00001019 return -EOPNOTSUPP;
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001020
1021 dev_size = ops->get_rxfh_indir_size(dev);
Ben Hutchings7850f632011-12-15 13:55:01 +00001022 if (dev_size == 0)
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001023 return -EOPNOTSUPP;
1024
Ben Hutchings7850f632011-12-15 13:55:01 +00001025 if (copy_from_user(&user_size,
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001026 useraddr + offsetof(struct ethtool_rxfh_indir, size),
Ben Hutchings7850f632011-12-15 13:55:01 +00001027 sizeof(user_size)))
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001028 return -EFAULT;
1029
Ben Hutchings278bc422011-12-15 13:56:49 +00001030 if (user_size != 0 && user_size != dev_size)
Ben Hutchings7850f632011-12-15 13:55:01 +00001031 return -EINVAL;
1032
1033 indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001034 if (!indir)
1035 return -ENOMEM;
1036
Ben Hutchings7850f632011-12-15 13:55:01 +00001037 rx_rings.cmd = ETHTOOL_GRXRINGS;
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001038 ret = ops->get_rxnfc(dev, &rx_rings, NULL);
Ben Hutchings7850f632011-12-15 13:55:01 +00001039 if (ret)
1040 goto out;
Ben Hutchings278bc422011-12-15 13:56:49 +00001041
1042 if (user_size == 0) {
1043 for (i = 0; i < dev_size; i++)
1044 indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
1045 } else {
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301046 ret = ethtool_copy_validate_indir(indir,
1047 useraddr + ringidx_offset,
1048 &rx_rings,
1049 dev_size);
1050 if (ret)
Ben Hutchings7850f632011-12-15 13:55:01 +00001051 goto out;
Ben Hutchings7850f632011-12-15 13:55:01 +00001052 }
1053
Eyal Perry892311f2014-12-02 18:12:10 +02001054 ret = ops->set_rxfh(dev, indir, NULL, ETH_RSS_HASH_NO_CHANGE);
Keller, Jacob Ed4ab4282016-02-08 16:05:03 -08001055 if (ret)
1056 goto out;
1057
1058 /* indicate whether rxfh was set to default */
1059 if (user_size == 0)
1060 dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
1061 else
1062 dev->priv_flags |= IFF_RXFH_CONFIGURED;
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001063
1064out:
1065 kfree(indir);
1066 return ret;
1067}
1068
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301069static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
1070 void __user *useraddr)
1071{
1072 int ret;
1073 const struct ethtool_ops *ops = dev->ethtool_ops;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001074 u32 user_indir_size, user_key_size;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301075 u32 dev_indir_size = 0, dev_key_size = 0;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001076 struct ethtool_rxfh rxfh;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301077 u32 total_size;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001078 u32 indir_bytes;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301079 u32 *indir = NULL;
Eyal Perry892311f2014-12-02 18:12:10 +02001080 u8 dev_hfunc = 0;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301081 u8 *hkey = NULL;
1082 u8 *rss_config;
1083
Eyal Perry892311f2014-12-02 18:12:10 +02001084 if (!ops->get_rxfh)
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301085 return -EOPNOTSUPP;
1086
1087 if (ops->get_rxfh_indir_size)
1088 dev_indir_size = ops->get_rxfh_indir_size(dev);
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301089 if (ops->get_rxfh_key_size)
1090 dev_key_size = ops->get_rxfh_key_size(dev);
1091
Ben Hutchingsf062a382014-05-15 16:28:07 +01001092 if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301093 return -EFAULT;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001094 user_indir_size = rxfh.indir_size;
1095 user_key_size = rxfh.key_size;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301096
Ben Hutchingsf062a382014-05-15 16:28:07 +01001097 /* Check that reserved fields are 0 for now */
Edward Cree84a1d9c42018-03-08 15:45:03 +00001098 if (rxfh.rsvd8[0] || rxfh.rsvd8[1] || rxfh.rsvd8[2] || rxfh.rsvd32)
Ben Hutchingsf062a382014-05-15 16:28:07 +01001099 return -EINVAL;
Edward Cree84a1d9c42018-03-08 15:45:03 +00001100 /* Most drivers don't handle rss_context, check it's 0 as well */
1101 if (rxfh.rss_context && !ops->get_rxfh_context)
1102 return -EOPNOTSUPP;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001103
1104 rxfh.indir_size = dev_indir_size;
1105 rxfh.key_size = dev_key_size;
1106 if (copy_to_user(useraddr, &rxfh, sizeof(rxfh)))
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301107 return -EFAULT;
1108
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301109 if ((user_indir_size && (user_indir_size != dev_indir_size)) ||
1110 (user_key_size && (user_key_size != dev_key_size)))
1111 return -EINVAL;
1112
1113 indir_bytes = user_indir_size * sizeof(indir[0]);
1114 total_size = indir_bytes + user_key_size;
1115 rss_config = kzalloc(total_size, GFP_USER);
1116 if (!rss_config)
1117 return -ENOMEM;
1118
1119 if (user_indir_size)
1120 indir = (u32 *)rss_config;
1121
1122 if (user_key_size)
1123 hkey = rss_config + indir_bytes;
1124
Edward Cree84a1d9c42018-03-08 15:45:03 +00001125 if (rxfh.rss_context)
1126 ret = dev->ethtool_ops->get_rxfh_context(dev, indir, hkey,
1127 &dev_hfunc,
1128 rxfh.rss_context);
1129 else
1130 ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc);
Eyal Perry892311f2014-12-02 18:12:10 +02001131 if (ret)
1132 goto out;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301133
Eyal Perry892311f2014-12-02 18:12:10 +02001134 if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, hfunc),
1135 &dev_hfunc, sizeof(rxfh.hfunc))) {
1136 ret = -EFAULT;
1137 } else if (copy_to_user(useraddr +
1138 offsetof(struct ethtool_rxfh, rss_config[0]),
1139 rss_config, total_size)) {
1140 ret = -EFAULT;
1141 }
1142out:
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301143 kfree(rss_config);
1144
1145 return ret;
1146}
1147
1148static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
1149 void __user *useraddr)
1150{
1151 int ret;
1152 const struct ethtool_ops *ops = dev->ethtool_ops;
1153 struct ethtool_rxnfc rx_rings;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001154 struct ethtool_rxfh rxfh;
1155 u32 dev_indir_size = 0, dev_key_size = 0, i;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301156 u32 *indir = NULL, indir_bytes = 0;
1157 u8 *hkey = NULL;
1158 u8 *rss_config;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301159 u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
Edward Cree84a1d9c42018-03-08 15:45:03 +00001160 bool delete = false;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301161
Eyal Perry892311f2014-12-02 18:12:10 +02001162 if (!ops->get_rxnfc || !ops->set_rxfh)
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301163 return -EOPNOTSUPP;
1164
1165 if (ops->get_rxfh_indir_size)
1166 dev_indir_size = ops->get_rxfh_indir_size(dev);
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301167 if (ops->get_rxfh_key_size)
Dan Carpenterd340c862015-02-20 13:54:05 +03001168 dev_key_size = ops->get_rxfh_key_size(dev);
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301169
Ben Hutchingsf062a382014-05-15 16:28:07 +01001170 if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301171 return -EFAULT;
1172
Ben Hutchingsf062a382014-05-15 16:28:07 +01001173 /* Check that reserved fields are 0 for now */
Edward Cree84a1d9c42018-03-08 15:45:03 +00001174 if (rxfh.rsvd8[0] || rxfh.rsvd8[1] || rxfh.rsvd8[2] || rxfh.rsvd32)
Ben Hutchingsf062a382014-05-15 16:28:07 +01001175 return -EINVAL;
Edward Cree84a1d9c42018-03-08 15:45:03 +00001176 /* Most drivers don't handle rss_context, check it's 0 as well */
1177 if (rxfh.rss_context && !ops->set_rxfh_context)
1178 return -EOPNOTSUPP;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001179
Eyal Perry892311f2014-12-02 18:12:10 +02001180 /* If either indir, hash key or function is valid, proceed further.
1181 * Must request at least one change: indir size, hash key or function.
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301182 */
Ben Hutchingsf062a382014-05-15 16:28:07 +01001183 if ((rxfh.indir_size &&
1184 rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE &&
1185 rxfh.indir_size != dev_indir_size) ||
1186 (rxfh.key_size && (rxfh.key_size != dev_key_size)) ||
1187 (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE &&
Eyal Perry892311f2014-12-02 18:12:10 +02001188 rxfh.key_size == 0 && rxfh.hfunc == ETH_RSS_HASH_NO_CHANGE))
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301189 return -EINVAL;
1190
Ben Hutchingsf062a382014-05-15 16:28:07 +01001191 if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301192 indir_bytes = dev_indir_size * sizeof(indir[0]);
1193
Ben Hutchingsf062a382014-05-15 16:28:07 +01001194 rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER);
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301195 if (!rss_config)
1196 return -ENOMEM;
1197
1198 rx_rings.cmd = ETHTOOL_GRXRINGS;
1199 ret = ops->get_rxnfc(dev, &rx_rings, NULL);
1200 if (ret)
1201 goto out;
1202
Edward Cree84a1d9c42018-03-08 15:45:03 +00001203 /* rxfh.indir_size == 0 means reset the indir table to default (master
1204 * context) or delete the context (other RSS contexts).
Ben Hutchingsf062a382014-05-15 16:28:07 +01001205 * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged.
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301206 */
Ben Hutchingsf062a382014-05-15 16:28:07 +01001207 if (rxfh.indir_size &&
1208 rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) {
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301209 indir = (u32 *)rss_config;
1210 ret = ethtool_copy_validate_indir(indir,
1211 useraddr + rss_cfg_offset,
1212 &rx_rings,
Ben Hutchingsf062a382014-05-15 16:28:07 +01001213 rxfh.indir_size);
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301214 if (ret)
1215 goto out;
Ben Hutchingsf062a382014-05-15 16:28:07 +01001216 } else if (rxfh.indir_size == 0) {
Edward Cree84a1d9c42018-03-08 15:45:03 +00001217 if (rxfh.rss_context == 0) {
1218 indir = (u32 *)rss_config;
1219 for (i = 0; i < dev_indir_size; i++)
1220 indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
1221 } else {
1222 delete = true;
1223 }
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301224 }
1225
Ben Hutchingsf062a382014-05-15 16:28:07 +01001226 if (rxfh.key_size) {
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301227 hkey = rss_config + indir_bytes;
1228 if (copy_from_user(hkey,
1229 useraddr + rss_cfg_offset + indir_bytes,
Ben Hutchingsf062a382014-05-15 16:28:07 +01001230 rxfh.key_size)) {
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301231 ret = -EFAULT;
1232 goto out;
1233 }
1234 }
1235
Edward Cree84a1d9c42018-03-08 15:45:03 +00001236 if (rxfh.rss_context)
1237 ret = ops->set_rxfh_context(dev, indir, hkey, rxfh.hfunc,
1238 &rxfh.rss_context, delete);
1239 else
1240 ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc);
Keller, Jacob Ed4ab4282016-02-08 16:05:03 -08001241 if (ret)
1242 goto out;
1243
Edward Cree84a1d9c42018-03-08 15:45:03 +00001244 if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, rss_context),
1245 &rxfh.rss_context, sizeof(rxfh.rss_context)))
1246 ret = -EFAULT;
1247
1248 if (!rxfh.rss_context) {
1249 /* indicate whether rxfh was set to default */
1250 if (rxfh.indir_size == 0)
1251 dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
1252 else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
1253 dev->priv_flags |= IFF_RXFH_CONFIGURED;
1254 }
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05301255
1256out:
1257 kfree(rss_config);
1258 return ret;
1259}
1260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
1262{
1263 struct ethtool_regs regs;
Stephen Hemminger76fd8592006-09-08 11:16:13 -07001264 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 void *regbuf;
1266 int reglen, ret;
1267
1268 if (!ops->get_regs || !ops->get_regs_len)
1269 return -EOPNOTSUPP;
1270
1271 if (copy_from_user(&regs, useraddr, sizeof(regs)))
1272 return -EFAULT;
1273
1274 reglen = ops->get_regs_len(dev);
Yunsheng Linf9fc54d2018-12-26 19:51:46 +08001275 if (reglen <= 0)
1276 return reglen;
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 if (regs.len > reglen)
1279 regs.len = reglen;
1280
Dan Carpenteref76c772019-02-01 11:24:06 +03001281 regbuf = vzalloc(reglen);
1282 if (!regbuf)
1283 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
Vivien Didelot0ee4e762019-06-03 16:57:13 -04001285 if (regs.len < reglen)
1286 reglen = regs.len;
1287
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 ops->get_regs(dev, &regs, regbuf);
1289
1290 ret = -EFAULT;
1291 if (copy_to_user(useraddr, &regs, sizeof(regs)))
1292 goto out;
1293 useraddr += offsetof(struct ethtool_regs, data);
Vivien Didelot0ee4e762019-06-03 16:57:13 -04001294 if (copy_to_user(useraddr, regbuf, reglen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 goto out;
1296 ret = 0;
1297
1298 out:
Ben Hutchingsa77f5db2010-09-20 08:42:17 +00001299 vfree(regbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 return ret;
1301}
1302
Ben Hutchingsd73d3a82009-10-05 10:59:58 +00001303static int ethtool_reset(struct net_device *dev, char __user *useraddr)
1304{
1305 struct ethtool_value reset;
1306 int ret;
1307
1308 if (!dev->ethtool_ops->reset)
1309 return -EOPNOTSUPP;
1310
1311 if (copy_from_user(&reset, useraddr, sizeof(reset)))
1312 return -EFAULT;
1313
1314 ret = dev->ethtool_ops->reset(dev, &reset.data);
1315 if (ret)
1316 return ret;
1317
1318 if (copy_to_user(useraddr, &reset, sizeof(reset)))
1319 return -EFAULT;
1320 return 0;
1321}
1322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
1324{
zhanglin5ff223e2019-10-26 15:54:16 +08001325 struct ethtool_wolinfo wol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
1327 if (!dev->ethtool_ops->get_wol)
1328 return -EOPNOTSUPP;
1329
zhanglin5ff223e2019-10-26 15:54:16 +08001330 memset(&wol, 0, sizeof(struct ethtool_wolinfo));
1331 wol.cmd = ETHTOOL_GWOL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 dev->ethtool_ops->get_wol(dev, &wol);
1333
1334 if (copy_to_user(useraddr, &wol, sizeof(wol)))
1335 return -EFAULT;
1336 return 0;
1337}
1338
1339static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
1340{
1341 struct ethtool_wolinfo wol;
Heiner Kallweit61941142018-09-24 21:58:59 +02001342 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
1344 if (!dev->ethtool_ops->set_wol)
1345 return -EOPNOTSUPP;
1346
1347 if (copy_from_user(&wol, useraddr, sizeof(wol)))
1348 return -EFAULT;
1349
Heiner Kallweit61941142018-09-24 21:58:59 +02001350 ret = dev->ethtool_ops->set_wol(dev, &wol);
1351 if (ret)
1352 return ret;
1353
1354 dev->wol_enabled = !!wol.wolopts;
1355
1356 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357}
1358
Yuval Mintz80f12ec2012-06-06 17:13:06 +00001359static int ethtool_get_eee(struct net_device *dev, char __user *useraddr)
1360{
1361 struct ethtool_eee edata;
1362 int rc;
1363
1364 if (!dev->ethtool_ops->get_eee)
1365 return -EOPNOTSUPP;
1366
1367 memset(&edata, 0, sizeof(struct ethtool_eee));
1368 edata.cmd = ETHTOOL_GEEE;
1369 rc = dev->ethtool_ops->get_eee(dev, &edata);
1370
1371 if (rc)
1372 return rc;
1373
1374 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1375 return -EFAULT;
1376
1377 return 0;
1378}
1379
1380static int ethtool_set_eee(struct net_device *dev, char __user *useraddr)
1381{
1382 struct ethtool_eee edata;
1383
1384 if (!dev->ethtool_ops->set_eee)
1385 return -EOPNOTSUPP;
1386
1387 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1388 return -EFAULT;
1389
1390 return dev->ethtool_ops->set_eee(dev, &edata);
1391}
1392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393static int ethtool_nway_reset(struct net_device *dev)
1394{
1395 if (!dev->ethtool_ops->nway_reset)
1396 return -EOPNOTSUPP;
1397
1398 return dev->ethtool_ops->nway_reset(dev);
1399}
1400
Ben Hutchingse596e6e2010-12-09 12:08:35 +00001401static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
1402{
1403 struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };
1404
1405 if (!dev->ethtool_ops->get_link)
1406 return -EOPNOTSUPP;
1407
1408 edata.data = netif_running(dev) && dev->ethtool_ops->get_link(dev);
1409
1410 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1411 return -EFAULT;
1412 return 0;
1413}
1414
Ben Hutchings081d0942012-04-12 00:42:12 +00001415static int ethtool_get_any_eeprom(struct net_device *dev, void __user *useraddr,
1416 int (*getter)(struct net_device *,
1417 struct ethtool_eeprom *, u8 *),
1418 u32 total_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419{
1420 struct ethtool_eeprom eeprom;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001421 void __user *userbuf = useraddr + sizeof(eeprom);
1422 u32 bytes_remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 u8 *data;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001424 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
1427 return -EFAULT;
1428
1429 /* Check for wrap and zero */
1430 if (eeprom.offset + eeprom.len <= eeprom.offset)
1431 return -EINVAL;
1432
1433 /* Check for exceeding total eeprom len */
Ben Hutchings081d0942012-04-12 00:42:12 +00001434 if (eeprom.offset + eeprom.len > total_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 return -EINVAL;
1436
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001437 data = kmalloc(PAGE_SIZE, GFP_USER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 if (!data)
1439 return -ENOMEM;
1440
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001441 bytes_remaining = eeprom.len;
1442 while (bytes_remaining > 0) {
1443 eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Ben Hutchings081d0942012-04-12 00:42:12 +00001445 ret = getter(dev, &eeprom, data);
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001446 if (ret)
1447 break;
1448 if (copy_to_user(userbuf, data, eeprom.len)) {
1449 ret = -EFAULT;
1450 break;
1451 }
1452 userbuf += eeprom.len;
1453 eeprom.offset += eeprom.len;
1454 bytes_remaining -= eeprom.len;
1455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
Mandeep Singh Bainesc5835df2008-04-24 20:55:56 -07001457 eeprom.len = userbuf - (useraddr + sizeof(eeprom));
1458 eeprom.offset -= eeprom.len;
1459 if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
1460 ret = -EFAULT;
1461
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 kfree(data);
1463 return ret;
1464}
1465
Ben Hutchings081d0942012-04-12 00:42:12 +00001466static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
1467{
1468 const struct ethtool_ops *ops = dev->ethtool_ops;
1469
Guenter Roecke0fb6fb2014-10-30 20:50:15 -07001470 if (!ops->get_eeprom || !ops->get_eeprom_len ||
1471 !ops->get_eeprom_len(dev))
Ben Hutchings081d0942012-04-12 00:42:12 +00001472 return -EOPNOTSUPP;
1473
1474 return ethtool_get_any_eeprom(dev, useraddr, ops->get_eeprom,
1475 ops->get_eeprom_len(dev));
1476}
1477
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
1479{
1480 struct ethtool_eeprom eeprom;
Stephen Hemminger76fd8592006-09-08 11:16:13 -07001481 const struct ethtool_ops *ops = dev->ethtool_ops;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001482 void __user *userbuf = useraddr + sizeof(eeprom);
1483 u32 bytes_remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 u8 *data;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001485 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
Guenter Roecke0fb6fb2014-10-30 20:50:15 -07001487 if (!ops->set_eeprom || !ops->get_eeprom_len ||
1488 !ops->get_eeprom_len(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 return -EOPNOTSUPP;
1490
1491 if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
1492 return -EFAULT;
1493
1494 /* Check for wrap and zero */
1495 if (eeprom.offset + eeprom.len <= eeprom.offset)
1496 return -EINVAL;
1497
1498 /* Check for exceeding total eeprom len */
1499 if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
1500 return -EINVAL;
1501
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001502 data = kmalloc(PAGE_SIZE, GFP_USER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 if (!data)
1504 return -ENOMEM;
1505
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001506 bytes_remaining = eeprom.len;
1507 while (bytes_remaining > 0) {
1508 eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -07001510 if (copy_from_user(data, userbuf, eeprom.len)) {
1511 ret = -EFAULT;
1512 break;
1513 }
1514 ret = ops->set_eeprom(dev, &eeprom, data);
1515 if (ret)
1516 break;
1517 userbuf += eeprom.len;
1518 eeprom.offset += eeprom.len;
1519 bytes_remaining -= eeprom.len;
1520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 kfree(data);
1523 return ret;
1524}
1525
chavey97f8aef2010-04-07 21:54:42 -07001526static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev,
1527 void __user *useraddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528{
Roland Dreier8e557422010-02-11 12:14:23 -08001529 struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
1531 if (!dev->ethtool_ops->get_coalesce)
1532 return -EOPNOTSUPP;
1533
1534 dev->ethtool_ops->get_coalesce(dev, &coalesce);
1535
1536 if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
1537 return -EFAULT;
1538 return 0;
1539}
1540
chavey97f8aef2010-04-07 21:54:42 -07001541static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
1542 void __user *useraddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543{
1544 struct ethtool_coalesce coalesce;
1545
David S. Millerfa04ae52005-06-06 15:07:19 -07001546 if (!dev->ethtool_ops->set_coalesce)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 return -EOPNOTSUPP;
1548
1549 if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
1550 return -EFAULT;
1551
1552 return dev->ethtool_ops->set_coalesce(dev, &coalesce);
1553}
1554
1555static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
1556{
Roland Dreier8e557422010-02-11 12:14:23 -08001557 struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
1559 if (!dev->ethtool_ops->get_ringparam)
1560 return -EOPNOTSUPP;
1561
1562 dev->ethtool_ops->get_ringparam(dev, &ringparam);
1563
1564 if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
1565 return -EFAULT;
1566 return 0;
1567}
1568
1569static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
1570{
Eugenia Emantayev37e2d992018-01-08 16:00:24 +02001571 struct ethtool_ringparam ringparam, max = { .cmd = ETHTOOL_GRINGPARAM };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Eugenia Emantayev37e2d992018-01-08 16:00:24 +02001573 if (!dev->ethtool_ops->set_ringparam || !dev->ethtool_ops->get_ringparam)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 return -EOPNOTSUPP;
1575
1576 if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
1577 return -EFAULT;
1578
Eugenia Emantayev37e2d992018-01-08 16:00:24 +02001579 dev->ethtool_ops->get_ringparam(dev, &max);
1580
1581 /* ensure new ring parameters are within the maximums */
1582 if (ringparam.rx_pending > max.rx_max_pending ||
1583 ringparam.rx_mini_pending > max.rx_mini_max_pending ||
1584 ringparam.rx_jumbo_pending > max.rx_jumbo_max_pending ||
1585 ringparam.tx_pending > max.tx_max_pending)
1586 return -EINVAL;
1587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 return dev->ethtool_ops->set_ringparam(dev, &ringparam);
1589}
1590
amit salecha8b5933c2011-04-07 01:58:42 +00001591static noinline_for_stack int ethtool_get_channels(struct net_device *dev,
1592 void __user *useraddr)
1593{
1594 struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
1595
1596 if (!dev->ethtool_ops->get_channels)
1597 return -EOPNOTSUPP;
1598
1599 dev->ethtool_ops->get_channels(dev, &channels);
1600
1601 if (copy_to_user(useraddr, &channels, sizeof(channels)))
1602 return -EFAULT;
1603 return 0;
1604}
1605
1606static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
1607 void __user *useraddr)
1608{
Jakub Kicinskib8c8a2e2018-10-01 14:51:35 +02001609 struct ethtool_channels channels, curr = { .cmd = ETHTOOL_GCHANNELS };
Jakub Kicinski1661d342018-10-01 14:51:36 +02001610 u16 from_channel, to_channel;
Keller, Jacob Ed4ab4282016-02-08 16:05:03 -08001611 u32 max_rx_in_use = 0;
Jakub Kicinski1661d342018-10-01 14:51:36 +02001612 unsigned int i;
amit salecha8b5933c2011-04-07 01:58:42 +00001613
Keller, Jacob E8bf36862016-02-08 16:05:04 -08001614 if (!dev->ethtool_ops->set_channels || !dev->ethtool_ops->get_channels)
amit salecha8b5933c2011-04-07 01:58:42 +00001615 return -EOPNOTSUPP;
1616
1617 if (copy_from_user(&channels, useraddr, sizeof(channels)))
1618 return -EFAULT;
1619
Jakub Kicinskib8c8a2e2018-10-01 14:51:35 +02001620 dev->ethtool_ops->get_channels(dev, &curr);
Keller, Jacob E8bf36862016-02-08 16:05:04 -08001621
1622 /* ensure new counts are within the maximums */
Jakub Kicinskib8c8a2e2018-10-01 14:51:35 +02001623 if (channels.rx_count > curr.max_rx ||
1624 channels.tx_count > curr.max_tx ||
1625 channels.combined_count > curr.max_combined ||
1626 channels.other_count > curr.max_other)
Keller, Jacob E8bf36862016-02-08 16:05:04 -08001627 return -EINVAL;
1628
Keller, Jacob Ed4ab4282016-02-08 16:05:03 -08001629 /* ensure the new Rx count fits within the configured Rx flow
1630 * indirection table settings */
1631 if (netif_is_rxfh_configured(dev) &&
1632 !ethtool_get_max_rxfh_channel(dev, &max_rx_in_use) &&
1633 (channels.combined_count + channels.rx_count) <= max_rx_in_use)
1634 return -EINVAL;
1635
Jakub Kicinski1661d342018-10-01 14:51:36 +02001636 /* Disabling channels, query zero-copy AF_XDP sockets */
1637 from_channel = channels.combined_count +
1638 min(channels.rx_count, channels.tx_count);
1639 to_channel = curr.combined_count + max(curr.rx_count, curr.tx_count);
1640 for (i = from_channel; i < to_channel; i++)
1641 if (xdp_get_umem_from_qid(dev, i))
1642 return -EINVAL;
1643
amit salecha8b5933c2011-04-07 01:58:42 +00001644 return dev->ethtool_ops->set_channels(dev, &channels);
1645}
1646
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
1648{
Li RongQinge83887f2019-02-27 20:47:57 +08001649 struct ethtool_pauseparam pauseparam = { .cmd = ETHTOOL_GPAUSEPARAM };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
1651 if (!dev->ethtool_ops->get_pauseparam)
1652 return -EOPNOTSUPP;
1653
1654 dev->ethtool_ops->get_pauseparam(dev, &pauseparam);
1655
1656 if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
1657 return -EFAULT;
1658 return 0;
1659}
1660
1661static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
1662{
1663 struct ethtool_pauseparam pauseparam;
1664
Jeff Garzike1b90c42006-07-17 12:54:40 -04001665 if (!dev->ethtool_ops->set_pauseparam)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 return -EOPNOTSUPP;
1667
1668 if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
1669 return -EFAULT;
1670
1671 return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
1672}
1673
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
1675{
1676 struct ethtool_test test;
Stephen Hemminger76fd8592006-09-08 11:16:13 -07001677 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 u64 *data;
Jeff Garzikff03d492007-08-15 16:01:08 -07001679 int ret, test_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001681 if (!ops->self_test || !ops->get_sset_count)
Jeff Garzikff03d492007-08-15 16:01:08 -07001682 return -EOPNOTSUPP;
1683
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001684 test_len = ops->get_sset_count(dev, ETH_SS_TEST);
Jeff Garzikff03d492007-08-15 16:01:08 -07001685 if (test_len < 0)
1686 return test_len;
1687 WARN_ON(test_len == 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
1689 if (copy_from_user(&test, useraddr, sizeof(test)))
1690 return -EFAULT;
1691
Jeff Garzikff03d492007-08-15 16:01:08 -07001692 test.len = test_len;
Kees Cook6da2ec52018-06-12 13:55:00 -07001693 data = kmalloc_array(test_len, sizeof(u64), GFP_USER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 if (!data)
1695 return -ENOMEM;
1696
1697 ops->self_test(dev, &test, data);
1698
1699 ret = -EFAULT;
1700 if (copy_to_user(useraddr, &test, sizeof(test)))
1701 goto out;
1702 useraddr += sizeof(test);
1703 if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
1704 goto out;
1705 ret = 0;
1706
1707 out:
1708 kfree(data);
1709 return ret;
1710}
1711
1712static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
1713{
1714 struct ethtool_gstrings gstrings;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 u8 *data;
1716 int ret;
1717
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
1719 return -EFAULT;
1720
Michał Mirosław340ae162011-02-15 16:59:16 +00001721 ret = __ethtool_get_sset_count(dev, gstrings.string_set);
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001722 if (ret < 0)
1723 return ret;
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001724 if (ret > S32_MAX / ETH_GSTRING_LEN)
1725 return -ENOMEM;
1726 WARN_ON_ONCE(!ret);
Jeff Garzikff03d492007-08-15 16:01:08 -07001727
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001728 gstrings.len = ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Li RongQing3d883022019-03-29 09:18:02 +08001730 if (gstrings.len) {
1731 data = vzalloc(array_size(gstrings.len, ETH_GSTRING_LEN));
1732 if (!data)
1733 return -ENOMEM;
1734
1735 __ethtool_get_strings(dev, gstrings.string_set, data);
1736 } else {
1737 data = NULL;
1738 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
1740 ret = -EFAULT;
1741 if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
1742 goto out;
1743 useraddr += sizeof(gstrings);
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001744 if (gstrings.len &&
1745 copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 goto out;
1747 ret = 0;
1748
Michał Mirosław340ae162011-02-15 16:59:16 +00001749out:
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001750 vfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 return ret;
1752}
1753
1754static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
1755{
1756 struct ethtool_value id;
Ben Hutchings68f512f2011-04-02 00:35:15 +01001757 static bool busy;
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001758 const struct ethtool_ops *ops = dev->ethtool_ops;
Ben Hutchings68f512f2011-04-02 00:35:15 +01001759 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001761 if (!ops->set_phys_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 return -EOPNOTSUPP;
1763
Ben Hutchings68f512f2011-04-02 00:35:15 +01001764 if (busy)
1765 return -EBUSY;
1766
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 if (copy_from_user(&id, useraddr, sizeof(id)))
1768 return -EFAULT;
1769
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001770 rc = ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE);
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001771 if (rc < 0)
Ben Hutchings68f512f2011-04-02 00:35:15 +01001772 return rc;
1773
1774 /* Drop the RTNL lock while waiting, but prevent reentry or
1775 * removal of the device.
1776 */
1777 busy = true;
1778 dev_hold(dev);
1779 rtnl_unlock();
1780
1781 if (rc == 0) {
1782 /* Driver will handle this itself */
1783 schedule_timeout_interruptible(
Allan, Bruce W143780c2011-04-11 13:01:59 +00001784 id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT);
Ben Hutchings68f512f2011-04-02 00:35:15 +01001785 } else {
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001786 /* Driver expects to be called at twice the frequency in rc */
1787 int n = rc * 2, i, interval = HZ / n;
Ben Hutchings68f512f2011-04-02 00:35:15 +01001788
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001789 /* Count down seconds */
1790 do {
1791 /* Count down iterations per second */
1792 i = n;
1793 do {
1794 rtnl_lock();
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001795 rc = ops->set_phys_id(dev,
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001796 (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
1797 rtnl_unlock();
1798 if (rc)
1799 break;
1800 schedule_timeout_interruptible(interval);
1801 } while (!signal_pending(current) && --i != 0);
Ben Hutchings68f512f2011-04-02 00:35:15 +01001802 } while (!signal_pending(current) &&
1803 (id.data == 0 || --id.data != 0));
1804 }
1805
1806 rtnl_lock();
1807 dev_put(dev);
1808 busy = false;
1809
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00001810 (void) ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
Ben Hutchings68f512f2011-04-02 00:35:15 +01001811 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812}
1813
1814static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
1815{
1816 struct ethtool_stats stats;
Stephen Hemminger76fd8592006-09-08 11:16:13 -07001817 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 u64 *data;
Jeff Garzikff03d492007-08-15 16:01:08 -07001819 int ret, n_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001821 if (!ops->get_ethtool_stats || !ops->get_sset_count)
Jeff Garzikff03d492007-08-15 16:01:08 -07001822 return -EOPNOTSUPP;
1823
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001824 n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
Jeff Garzikff03d492007-08-15 16:01:08 -07001825 if (n_stats < 0)
1826 return n_stats;
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001827 if (n_stats > S32_MAX / sizeof(u64))
1828 return -ENOMEM;
1829 WARN_ON_ONCE(!n_stats);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 if (copy_from_user(&stats, useraddr, sizeof(stats)))
1831 return -EFAULT;
1832
Jeff Garzikff03d492007-08-15 16:01:08 -07001833 stats.n_stats = n_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
Li RongQing3d883022019-03-29 09:18:02 +08001835 if (n_stats) {
1836 data = vzalloc(array_size(n_stats, sizeof(u64)));
1837 if (!data)
1838 return -ENOMEM;
1839 ops->get_ethtool_stats(dev, &stats, data);
1840 } else {
1841 data = NULL;
1842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844 ret = -EFAULT;
1845 if (copy_to_user(useraddr, &stats, sizeof(stats)))
1846 goto out;
1847 useraddr += sizeof(stats);
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001848 if (n_stats && copy_to_user(useraddr, data, n_stats * sizeof(u64)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 goto out;
1850 ret = 0;
1851
1852 out:
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001853 vfree(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 return ret;
1855}
1856
Andrew Lunnf3a40942015-12-30 16:28:25 +01001857static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr)
1858{
Florian Fainelli99943382018-04-25 12:12:48 -07001859 const struct ethtool_ops *ops = dev->ethtool_ops;
Andrew Lunnf3a40942015-12-30 16:28:25 +01001860 struct phy_device *phydev = dev->phydev;
Florian Fainelli99943382018-04-25 12:12:48 -07001861 struct ethtool_stats stats;
Andrew Lunnf3a40942015-12-30 16:28:25 +01001862 u64 *data;
1863 int ret, n_stats;
1864
Florian Fainelli99943382018-04-25 12:12:48 -07001865 if (!phydev && (!ops->get_ethtool_phy_stats || !ops->get_sset_count))
Andrew Lunnf3a40942015-12-30 16:28:25 +01001866 return -EOPNOTSUPP;
1867
Florian Fainelli99943382018-04-25 12:12:48 -07001868 if (dev->phydev && !ops->get_ethtool_phy_stats)
1869 n_stats = phy_ethtool_get_sset_count(dev->phydev);
1870 else
1871 n_stats = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
Andrew Lunnf3a40942015-12-30 16:28:25 +01001872 if (n_stats < 0)
1873 return n_stats;
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001874 if (n_stats > S32_MAX / sizeof(u64))
1875 return -ENOMEM;
1876 WARN_ON_ONCE(!n_stats);
Andrew Lunnf3a40942015-12-30 16:28:25 +01001877
1878 if (copy_from_user(&stats, useraddr, sizeof(stats)))
1879 return -EFAULT;
1880
1881 stats.n_stats = n_stats;
Andrew Lunnf3a40942015-12-30 16:28:25 +01001882
Li RongQing3d883022019-03-29 09:18:02 +08001883 if (n_stats) {
1884 data = vzalloc(array_size(n_stats, sizeof(u64)));
1885 if (!data)
1886 return -ENOMEM;
1887
1888 if (dev->phydev && !ops->get_ethtool_phy_stats) {
1889 ret = phy_ethtool_get_stats(dev->phydev, &stats, data);
1890 if (ret < 0)
1891 goto out;
1892 } else {
1893 ops->get_ethtool_phy_stats(dev, &stats, data);
1894 }
Florian Fainelli99943382018-04-25 12:12:48 -07001895 } else {
Li RongQing3d883022019-03-29 09:18:02 +08001896 data = NULL;
Florian Fainelli99943382018-04-25 12:12:48 -07001897 }
Andrew Lunnf3a40942015-12-30 16:28:25 +01001898
1899 ret = -EFAULT;
1900 if (copy_to_user(useraddr, &stats, sizeof(stats)))
1901 goto out;
1902 useraddr += sizeof(stats);
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001903 if (n_stats && copy_to_user(useraddr, data, n_stats * sizeof(u64)))
Andrew Lunnf3a40942015-12-30 16:28:25 +01001904 goto out;
1905 ret = 0;
1906
1907 out:
Alexei Starovoitov4d1ceea2017-01-30 18:25:18 -08001908 vfree(data);
Andrew Lunnf3a40942015-12-30 16:28:25 +01001909 return ret;
1910}
1911
viro@ftp.linux.org.uk0bf0519d2005-09-05 03:26:18 +01001912static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
Jon Wetzela6f9a702005-08-20 17:15:54 -07001913{
1914 struct ethtool_perm_addr epaddr;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001915
Matthew Wilcox313674a2007-07-31 14:00:29 -07001916 if (copy_from_user(&epaddr, useraddr, sizeof(epaddr)))
Jon Wetzela6f9a702005-08-20 17:15:54 -07001917 return -EFAULT;
1918
Matthew Wilcox313674a2007-07-31 14:00:29 -07001919 if (epaddr.size < dev->addr_len)
1920 return -ETOOSMALL;
1921 epaddr.size = dev->addr_len;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001922
Jon Wetzela6f9a702005-08-20 17:15:54 -07001923 if (copy_to_user(useraddr, &epaddr, sizeof(epaddr)))
Matthew Wilcox313674a2007-07-31 14:00:29 -07001924 return -EFAULT;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001925 useraddr += sizeof(epaddr);
Matthew Wilcox313674a2007-07-31 14:00:29 -07001926 if (copy_to_user(useraddr, dev->perm_addr, epaddr.size))
1927 return -EFAULT;
1928 return 0;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001929}
1930
Jeff Garzik13c99b22007-08-15 16:01:56 -07001931static int ethtool_get_value(struct net_device *dev, char __user *useraddr,
1932 u32 cmd, u32 (*actor)(struct net_device *))
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001933{
Roland Dreier8e557422010-02-11 12:14:23 -08001934 struct ethtool_value edata = { .cmd = cmd };
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001935
Jeff Garzik13c99b22007-08-15 16:01:56 -07001936 if (!actor)
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001937 return -EOPNOTSUPP;
1938
Jeff Garzik13c99b22007-08-15 16:01:56 -07001939 edata.data = actor(dev);
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001940
1941 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1942 return -EFAULT;
1943 return 0;
1944}
1945
Jeff Garzik13c99b22007-08-15 16:01:56 -07001946static int ethtool_set_value_void(struct net_device *dev, char __user *useraddr,
1947 void (*actor)(struct net_device *, u32))
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001948{
1949 struct ethtool_value edata;
1950
Jeff Garzik13c99b22007-08-15 16:01:56 -07001951 if (!actor)
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001952 return -EOPNOTSUPP;
1953
1954 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1955 return -EFAULT;
1956
Jeff Garzik13c99b22007-08-15 16:01:56 -07001957 actor(dev, edata.data);
Jeff Garzik339bf022007-08-15 16:01:32 -07001958 return 0;
1959}
1960
Jeff Garzik13c99b22007-08-15 16:01:56 -07001961static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
1962 int (*actor)(struct net_device *, u32))
Jeff Garzik339bf022007-08-15 16:01:32 -07001963{
1964 struct ethtool_value edata;
1965
Jeff Garzik13c99b22007-08-15 16:01:56 -07001966 if (!actor)
Jeff Garzik339bf022007-08-15 16:01:32 -07001967 return -EOPNOTSUPP;
1968
1969 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1970 return -EFAULT;
1971
Jeff Garzik13c99b22007-08-15 16:01:56 -07001972 return actor(dev, edata.data);
Jeff Garzik339bf022007-08-15 16:01:32 -07001973}
1974
chavey97f8aef2010-04-07 21:54:42 -07001975static noinline_for_stack int ethtool_flash_device(struct net_device *dev,
1976 char __user *useraddr)
Ajit Khaparde05c6a8d2009-09-02 17:02:55 +00001977{
1978 struct ethtool_flash efl;
1979
1980 if (copy_from_user(&efl, useraddr, sizeof(efl)))
1981 return -EFAULT;
Ben Hutchings786f5282012-02-01 09:32:25 +00001982 efl.data[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
1983
Jakub Kicinski1b45ff62019-02-25 19:34:06 -08001984 if (!dev->ethtool_ops->flash_device)
1985 return devlink_compat_flash_update(dev, efl.data);
Jakub Kicinski4eceba12019-02-14 13:40:45 -08001986
Ajit Khaparde05c6a8d2009-09-02 17:02:55 +00001987 return dev->ethtool_ops->flash_device(dev, &efl);
1988}
1989
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00001990static int ethtool_set_dump(struct net_device *dev,
1991 void __user *useraddr)
1992{
1993 struct ethtool_dump dump;
1994
1995 if (!dev->ethtool_ops->set_dump)
1996 return -EOPNOTSUPP;
1997
1998 if (copy_from_user(&dump, useraddr, sizeof(dump)))
1999 return -EFAULT;
2000
2001 return dev->ethtool_ops->set_dump(dev, &dump);
2002}
2003
2004static int ethtool_get_dump_flag(struct net_device *dev,
2005 void __user *useraddr)
2006{
2007 int ret;
2008 struct ethtool_dump dump;
2009 const struct ethtool_ops *ops = dev->ethtool_ops;
2010
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00002011 if (!ops->get_dump_flag)
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002012 return -EOPNOTSUPP;
2013
2014 if (copy_from_user(&dump, useraddr, sizeof(dump)))
2015 return -EFAULT;
2016
2017 ret = ops->get_dump_flag(dev, &dump);
2018 if (ret)
2019 return ret;
2020
2021 if (copy_to_user(useraddr, &dump, sizeof(dump)))
2022 return -EFAULT;
2023 return 0;
2024}
2025
2026static int ethtool_get_dump_data(struct net_device *dev,
2027 void __user *useraddr)
2028{
2029 int ret;
2030 __u32 len;
2031 struct ethtool_dump dump, tmp;
2032 const struct ethtool_ops *ops = dev->ethtool_ops;
2033 void *data = NULL;
2034
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00002035 if (!ops->get_dump_data || !ops->get_dump_flag)
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002036 return -EOPNOTSUPP;
2037
2038 if (copy_from_user(&dump, useraddr, sizeof(dump)))
2039 return -EFAULT;
2040
2041 memset(&tmp, 0, sizeof(tmp));
2042 tmp.cmd = ETHTOOL_GET_DUMP_FLAG;
2043 ret = ops->get_dump_flag(dev, &tmp);
2044 if (ret)
2045 return ret;
2046
Michal Schmidtc590b5e2013-07-01 17:23:30 +02002047 len = min(tmp.len, dump.len);
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002048 if (!len)
2049 return -EFAULT;
2050
Michal Schmidtc590b5e2013-07-01 17:23:30 +02002051 /* Don't ever let the driver think there's more space available
2052 * than it requested with .get_dump_flag().
2053 */
2054 dump.len = len;
2055
2056 /* Always allocate enough space to hold the whole thing so that the
2057 * driver does not need to check the length and bother with partial
2058 * dumping.
2059 */
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002060 data = vzalloc(tmp.len);
2061 if (!data)
2062 return -ENOMEM;
2063 ret = ops->get_dump_data(dev, &dump, data);
2064 if (ret)
2065 goto out;
2066
Michal Schmidtc590b5e2013-07-01 17:23:30 +02002067 /* There are two sane possibilities:
2068 * 1. The driver's .get_dump_data() does not touch dump.len.
2069 * 2. Or it may set dump.len to how much it really writes, which
2070 * should be tmp.len (or len if it can do a partial dump).
2071 * In any case respond to userspace with the actual length of data
2072 * it's receiving.
2073 */
2074 WARN_ON(dump.len != len && dump.len != tmp.len);
2075 dump.len = len;
2076
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002077 if (copy_to_user(useraddr, &dump, sizeof(dump))) {
2078 ret = -EFAULT;
2079 goto out;
2080 }
2081 useraddr += offsetof(struct ethtool_dump, data);
2082 if (copy_to_user(useraddr, data, len))
2083 ret = -EFAULT;
2084out:
2085 vfree(data);
2086 return ret;
2087}
2088
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002089static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr)
2090{
2091 int err = 0;
2092 struct ethtool_ts_info info;
2093 const struct ethtool_ops *ops = dev->ethtool_ops;
2094 struct phy_device *phydev = dev->phydev;
2095
2096 memset(&info, 0, sizeof(info));
2097 info.cmd = ETHTOOL_GET_TS_INFO;
2098
2099 if (phydev && phydev->drv && phydev->drv->ts_info) {
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002100 err = phydev->drv->ts_info(phydev, &info);
Jiri Pirkoc03a14e2013-01-07 09:02:08 +00002101 } else if (ops->get_ts_info) {
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002102 err = ops->get_ts_info(dev, &info);
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002103 } else {
2104 info.so_timestamping =
2105 SOF_TIMESTAMPING_RX_SOFTWARE |
2106 SOF_TIMESTAMPING_SOFTWARE;
2107 info.phc_index = -1;
2108 }
2109
2110 if (err)
2111 return err;
2112
2113 if (copy_to_user(useraddr, &info, sizeof(info)))
2114 err = -EFAULT;
2115
2116 return err;
2117}
2118
Ed Swierk2f438362015-01-02 17:27:56 -08002119static int __ethtool_get_module_info(struct net_device *dev,
2120 struct ethtool_modinfo *modinfo)
2121{
2122 const struct ethtool_ops *ops = dev->ethtool_ops;
2123 struct phy_device *phydev = dev->phydev;
2124
Russell Kinge679c9c2018-03-28 15:44:16 -07002125 if (dev->sfp_bus)
2126 return sfp_get_module_info(dev->sfp_bus, modinfo);
2127
Ed Swierk2f438362015-01-02 17:27:56 -08002128 if (phydev && phydev->drv && phydev->drv->module_info)
2129 return phydev->drv->module_info(phydev, modinfo);
2130
2131 if (ops->get_module_info)
2132 return ops->get_module_info(dev, modinfo);
2133
2134 return -EOPNOTSUPP;
2135}
2136
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002137static int ethtool_get_module_info(struct net_device *dev,
2138 void __user *useraddr)
2139{
2140 int ret;
2141 struct ethtool_modinfo modinfo;
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002142
2143 if (copy_from_user(&modinfo, useraddr, sizeof(modinfo)))
2144 return -EFAULT;
2145
Ed Swierk2f438362015-01-02 17:27:56 -08002146 ret = __ethtool_get_module_info(dev, &modinfo);
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002147 if (ret)
2148 return ret;
2149
2150 if (copy_to_user(useraddr, &modinfo, sizeof(modinfo)))
2151 return -EFAULT;
2152
2153 return 0;
2154}
2155
Ed Swierk2f438362015-01-02 17:27:56 -08002156static int __ethtool_get_module_eeprom(struct net_device *dev,
2157 struct ethtool_eeprom *ee, u8 *data)
2158{
2159 const struct ethtool_ops *ops = dev->ethtool_ops;
2160 struct phy_device *phydev = dev->phydev;
2161
Russell Kinge679c9c2018-03-28 15:44:16 -07002162 if (dev->sfp_bus)
2163 return sfp_get_module_eeprom(dev->sfp_bus, ee, data);
2164
Ed Swierk2f438362015-01-02 17:27:56 -08002165 if (phydev && phydev->drv && phydev->drv->module_eeprom)
2166 return phydev->drv->module_eeprom(phydev, ee, data);
2167
2168 if (ops->get_module_eeprom)
2169 return ops->get_module_eeprom(dev, ee, data);
2170
2171 return -EOPNOTSUPP;
2172}
2173
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002174static int ethtool_get_module_eeprom(struct net_device *dev,
2175 void __user *useraddr)
2176{
2177 int ret;
2178 struct ethtool_modinfo modinfo;
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002179
Ed Swierk2f438362015-01-02 17:27:56 -08002180 ret = __ethtool_get_module_info(dev, &modinfo);
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002181 if (ret)
2182 return ret;
2183
Ed Swierk2f438362015-01-02 17:27:56 -08002184 return ethtool_get_any_eeprom(dev, useraddr,
2185 __ethtool_get_module_eeprom,
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002186 modinfo.eeprom_len);
2187}
2188
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302189static int ethtool_tunable_valid(const struct ethtool_tunable *tuna)
2190{
2191 switch (tuna->id) {
2192 case ETHTOOL_RX_COPYBREAK:
Eric Dumazet1255a502014-10-05 12:35:21 +03002193 case ETHTOOL_TX_COPYBREAK:
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302194 if (tuna->len != sizeof(u32) ||
2195 tuna->type_id != ETHTOOL_TUNABLE_U32)
2196 return -EINVAL;
2197 break;
Inbar Karmye1577c12017-11-20 16:14:30 +02002198 case ETHTOOL_PFC_PREVENTION_TOUT:
2199 if (tuna->len != sizeof(u16) ||
2200 tuna->type_id != ETHTOOL_TUNABLE_U16)
2201 return -EINVAL;
2202 break;
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302203 default:
2204 return -EINVAL;
2205 }
2206
2207 return 0;
2208}
2209
2210static int ethtool_get_tunable(struct net_device *dev, void __user *useraddr)
2211{
2212 int ret;
2213 struct ethtool_tunable tuna;
2214 const struct ethtool_ops *ops = dev->ethtool_ops;
2215 void *data;
2216
2217 if (!ops->get_tunable)
2218 return -EOPNOTSUPP;
2219 if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
2220 return -EFAULT;
2221 ret = ethtool_tunable_valid(&tuna);
2222 if (ret)
2223 return ret;
2224 data = kmalloc(tuna.len, GFP_USER);
2225 if (!data)
2226 return -ENOMEM;
2227 ret = ops->get_tunable(dev, &tuna, data);
2228 if (ret)
2229 goto out;
2230 useraddr += sizeof(tuna);
2231 ret = -EFAULT;
2232 if (copy_to_user(useraddr, data, tuna.len))
2233 goto out;
2234 ret = 0;
2235
2236out:
2237 kfree(data);
2238 return ret;
2239}
2240
2241static int ethtool_set_tunable(struct net_device *dev, void __user *useraddr)
2242{
2243 int ret;
2244 struct ethtool_tunable tuna;
2245 const struct ethtool_ops *ops = dev->ethtool_ops;
2246 void *data;
2247
2248 if (!ops->set_tunable)
2249 return -EOPNOTSUPP;
2250 if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
2251 return -EFAULT;
2252 ret = ethtool_tunable_valid(&tuna);
2253 if (ret)
2254 return ret;
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302255 useraddr += sizeof(tuna);
Al Viro30e7e3e2017-05-13 18:31:26 -04002256 data = memdup_user(useraddr, tuna.len);
2257 if (IS_ERR(data))
2258 return PTR_ERR(data);
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302259 ret = ops->set_tunable(dev, &tuna, data);
2260
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302261 kfree(data);
2262 return ret;
2263}
2264
Arnd Bergmann3499e872019-03-07 16:58:35 +01002265static noinline_for_stack int
2266ethtool_get_per_queue_coalesce(struct net_device *dev,
2267 void __user *useraddr,
2268 struct ethtool_per_queue_op *per_queue_opt)
Kan Liang421797b2016-02-19 09:24:02 -05002269{
2270 u32 bit;
2271 int ret;
2272 DECLARE_BITMAP(queue_mask, MAX_NUM_QUEUE);
2273
2274 if (!dev->ethtool_ops->get_per_queue_coalesce)
2275 return -EOPNOTSUPP;
2276
2277 useraddr += sizeof(*per_queue_opt);
2278
Yury Norov3aa56882018-02-06 15:38:06 -08002279 bitmap_from_arr32(queue_mask, per_queue_opt->queue_mask,
2280 MAX_NUM_QUEUE);
Kan Liang421797b2016-02-19 09:24:02 -05002281
2282 for_each_set_bit(bit, queue_mask, MAX_NUM_QUEUE) {
2283 struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
2284
2285 ret = dev->ethtool_ops->get_per_queue_coalesce(dev, bit, &coalesce);
2286 if (ret != 0)
2287 return ret;
2288 if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
2289 return -EFAULT;
2290 useraddr += sizeof(coalesce);
2291 }
2292
2293 return 0;
2294}
2295
Arnd Bergmann3499e872019-03-07 16:58:35 +01002296static noinline_for_stack int
2297ethtool_set_per_queue_coalesce(struct net_device *dev,
2298 void __user *useraddr,
2299 struct ethtool_per_queue_op *per_queue_opt)
Kan Liangf38d1382016-02-19 09:24:03 -05002300{
2301 u32 bit;
2302 int i, ret = 0;
2303 int n_queue;
2304 struct ethtool_coalesce *backup = NULL, *tmp = NULL;
2305 DECLARE_BITMAP(queue_mask, MAX_NUM_QUEUE);
2306
2307 if ((!dev->ethtool_ops->set_per_queue_coalesce) ||
2308 (!dev->ethtool_ops->get_per_queue_coalesce))
2309 return -EOPNOTSUPP;
2310
2311 useraddr += sizeof(*per_queue_opt);
2312
Yury Norov3aa56882018-02-06 15:38:06 -08002313 bitmap_from_arr32(queue_mask, per_queue_opt->queue_mask, MAX_NUM_QUEUE);
Kan Liangf38d1382016-02-19 09:24:03 -05002314 n_queue = bitmap_weight(queue_mask, MAX_NUM_QUEUE);
2315 tmp = backup = kmalloc_array(n_queue, sizeof(*backup), GFP_KERNEL);
2316 if (!backup)
2317 return -ENOMEM;
2318
2319 for_each_set_bit(bit, queue_mask, MAX_NUM_QUEUE) {
2320 struct ethtool_coalesce coalesce;
2321
2322 ret = dev->ethtool_ops->get_per_queue_coalesce(dev, bit, tmp);
2323 if (ret != 0)
2324 goto roll_back;
2325
2326 tmp++;
2327
2328 if (copy_from_user(&coalesce, useraddr, sizeof(coalesce))) {
2329 ret = -EFAULT;
2330 goto roll_back;
2331 }
2332
2333 ret = dev->ethtool_ops->set_per_queue_coalesce(dev, bit, &coalesce);
2334 if (ret != 0)
2335 goto roll_back;
2336
2337 useraddr += sizeof(coalesce);
2338 }
2339
2340roll_back:
2341 if (ret != 0) {
2342 tmp = backup;
2343 for_each_set_bit(i, queue_mask, bit) {
2344 dev->ethtool_ops->set_per_queue_coalesce(dev, i, tmp);
2345 tmp++;
2346 }
2347 }
2348 kfree(backup);
2349
2350 return ret;
2351}
2352
Arnd Bergmann3499e872019-03-07 16:58:35 +01002353static int noinline_for_stack ethtool_set_per_queue(struct net_device *dev,
Wenwen Wang58f5bbe2018-10-08 10:49:35 -05002354 void __user *useraddr, u32 sub_cmd)
Kan Liangac2c7ad2016-02-19 09:24:01 -05002355{
2356 struct ethtool_per_queue_op per_queue_opt;
2357
2358 if (copy_from_user(&per_queue_opt, useraddr, sizeof(per_queue_opt)))
2359 return -EFAULT;
2360
Wenwen Wang58f5bbe2018-10-08 10:49:35 -05002361 if (per_queue_opt.sub_command != sub_cmd)
2362 return -EINVAL;
2363
Kan Liangac2c7ad2016-02-19 09:24:01 -05002364 switch (per_queue_opt.sub_command) {
Kan Liang421797b2016-02-19 09:24:02 -05002365 case ETHTOOL_GCOALESCE:
2366 return ethtool_get_per_queue_coalesce(dev, useraddr, &per_queue_opt);
Kan Liangf38d1382016-02-19 09:24:03 -05002367 case ETHTOOL_SCOALESCE:
2368 return ethtool_set_per_queue_coalesce(dev, useraddr, &per_queue_opt);
Kan Liangac2c7ad2016-02-19 09:24:01 -05002369 default:
2370 return -EOPNOTSUPP;
2371 };
2372}
2373
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002374static int ethtool_phy_tunable_valid(const struct ethtool_tunable *tuna)
2375{
2376 switch (tuna->id) {
Raju Lakkaraju65feddd2016-11-17 13:07:23 +01002377 case ETHTOOL_PHY_DOWNSHIFT:
Heiner Kallweit3aeb0802019-03-25 19:34:58 +01002378 case ETHTOOL_PHY_FAST_LINK_DOWN:
Raju Lakkaraju65feddd2016-11-17 13:07:23 +01002379 if (tuna->len != sizeof(u8) ||
2380 tuna->type_id != ETHTOOL_TUNABLE_U8)
2381 return -EINVAL;
2382 break;
Alexandru Ardelean9f2f13f2019-09-16 10:35:25 +03002383 case ETHTOOL_PHY_EDPD:
2384 if (tuna->len != sizeof(u16) ||
2385 tuna->type_id != ETHTOOL_TUNABLE_U16)
2386 return -EINVAL;
2387 break;
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002388 default:
2389 return -EINVAL;
2390 }
2391
2392 return 0;
2393}
2394
2395static int get_phy_tunable(struct net_device *dev, void __user *useraddr)
2396{
2397 int ret;
2398 struct ethtool_tunable tuna;
2399 struct phy_device *phydev = dev->phydev;
2400 void *data;
2401
2402 if (!(phydev && phydev->drv && phydev->drv->get_tunable))
2403 return -EOPNOTSUPP;
2404
2405 if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
2406 return -EFAULT;
2407 ret = ethtool_phy_tunable_valid(&tuna);
2408 if (ret)
2409 return ret;
2410 data = kmalloc(tuna.len, GFP_USER);
2411 if (!data)
2412 return -ENOMEM;
Florian Fainelli4b652462016-11-22 13:55:31 -08002413 mutex_lock(&phydev->lock);
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002414 ret = phydev->drv->get_tunable(phydev, &tuna, data);
Florian Fainelli4b652462016-11-22 13:55:31 -08002415 mutex_unlock(&phydev->lock);
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002416 if (ret)
2417 goto out;
2418 useraddr += sizeof(tuna);
2419 ret = -EFAULT;
2420 if (copy_to_user(useraddr, data, tuna.len))
2421 goto out;
2422 ret = 0;
2423
2424out:
2425 kfree(data);
2426 return ret;
2427}
2428
2429static int set_phy_tunable(struct net_device *dev, void __user *useraddr)
2430{
2431 int ret;
2432 struct ethtool_tunable tuna;
2433 struct phy_device *phydev = dev->phydev;
2434 void *data;
2435
2436 if (!(phydev && phydev->drv && phydev->drv->set_tunable))
2437 return -EOPNOTSUPP;
2438 if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
2439 return -EFAULT;
2440 ret = ethtool_phy_tunable_valid(&tuna);
2441 if (ret)
2442 return ret;
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002443 useraddr += sizeof(tuna);
Al Viro30e7e3e2017-05-13 18:31:26 -04002444 data = memdup_user(useraddr, tuna.len);
2445 if (IS_ERR(data))
2446 return PTR_ERR(data);
Florian Fainelli4b652462016-11-22 13:55:31 -08002447 mutex_lock(&phydev->lock);
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002448 ret = phydev->drv->set_tunable(phydev, &tuna, data);
Florian Fainelli4b652462016-11-22 13:55:31 -08002449 mutex_unlock(&phydev->lock);
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002450
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002451 kfree(data);
2452 return ret;
2453}
2454
Vidya Sagar Ravipati1a5f3da2017-07-27 16:47:26 -07002455static int ethtool_get_fecparam(struct net_device *dev, void __user *useraddr)
2456{
Li RongQinge83887f2019-02-27 20:47:57 +08002457 struct ethtool_fecparam fecparam = { .cmd = ETHTOOL_GFECPARAM };
Edward Creea6d50512018-02-28 19:15:58 +00002458 int rc;
Vidya Sagar Ravipati1a5f3da2017-07-27 16:47:26 -07002459
2460 if (!dev->ethtool_ops->get_fecparam)
2461 return -EOPNOTSUPP;
2462
Edward Creea6d50512018-02-28 19:15:58 +00002463 rc = dev->ethtool_ops->get_fecparam(dev, &fecparam);
2464 if (rc)
2465 return rc;
Vidya Sagar Ravipati1a5f3da2017-07-27 16:47:26 -07002466
2467 if (copy_to_user(useraddr, &fecparam, sizeof(fecparam)))
2468 return -EFAULT;
2469 return 0;
2470}
2471
2472static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr)
2473{
2474 struct ethtool_fecparam fecparam;
2475
2476 if (!dev->ethtool_ops->set_fecparam)
2477 return -EOPNOTSUPP;
2478
2479 if (copy_from_user(&fecparam, useraddr, sizeof(fecparam)))
2480 return -EFAULT;
2481
2482 return dev->ethtool_ops->set_fecparam(dev, &fecparam);
2483}
2484
Yan Burman600fed52013-06-03 02:03:34 +00002485/* The main entry point in this file. Called from net/core/dev_ioctl.c */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
Eric W. Biederman881d9662007-09-17 11:56:21 -07002487int dev_ethtool(struct net *net, struct ifreq *ifr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488{
Eric W. Biederman881d9662007-09-17 11:56:21 -07002489 struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 void __user *useraddr = ifr->ifr_data;
Kan Liangac2c7ad2016-02-19 09:24:01 -05002491 u32 ethcmd, sub_cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 int rc;
Bjørn Morkb29d3142013-05-01 23:06:42 +00002493 netdev_features_t old_features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 if (!dev || !netif_device_present(dev))
2496 return -ENODEV;
2497
chavey97f8aef2010-04-07 21:54:42 -07002498 if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 return -EFAULT;
2500
Kan Liangac2c7ad2016-02-19 09:24:01 -05002501 if (ethcmd == ETHTOOL_PERQUEUE) {
2502 if (copy_from_user(&sub_cmd, useraddr + sizeof(ethcmd), sizeof(sub_cmd)))
2503 return -EFAULT;
2504 } else {
2505 sub_cmd = ethcmd;
2506 }
Stephen Hemminger75f31232006-09-28 15:13:37 -07002507 /* Allow some commands to be done by anyone */
Kan Liangac2c7ad2016-02-19 09:24:01 -05002508 switch (sub_cmd) {
stephen hemminger0fdc1002010-08-23 10:24:18 +00002509 case ETHTOOL_GSET:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002510 case ETHTOOL_GDRVINFO:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002511 case ETHTOOL_GMSGLVL:
Ben Hutchings2da45db2012-06-12 13:05:41 +00002512 case ETHTOOL_GLINK:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002513 case ETHTOOL_GCOALESCE:
2514 case ETHTOOL_GRINGPARAM:
2515 case ETHTOOL_GPAUSEPARAM:
2516 case ETHTOOL_GRXCSUM:
2517 case ETHTOOL_GTXCSUM:
2518 case ETHTOOL_GSG:
Michał Mirosławf80400a2012-01-22 00:20:40 +00002519 case ETHTOOL_GSSET_INFO:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002520 case ETHTOOL_GSTRINGS:
Ben Hutchings2da45db2012-06-12 13:05:41 +00002521 case ETHTOOL_GSTATS:
Andrew Lunnf3a40942015-12-30 16:28:25 +01002522 case ETHTOOL_GPHYSTATS:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002523 case ETHTOOL_GTSO:
2524 case ETHTOOL_GPERMADDR:
Maciej Żenczykowski474ff262018-09-22 01:34:01 -07002525 case ETHTOOL_GUFO:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002526 case ETHTOOL_GGSO:
stephen hemminger1cab8192010-02-11 13:48:29 +00002527 case ETHTOOL_GGRO:
Jeff Garzik339bf022007-08-15 16:01:32 -07002528 case ETHTOOL_GFLAGS:
2529 case ETHTOOL_GPFLAGS:
Santwona Behera0853ad62008-07-02 03:47:41 -07002530 case ETHTOOL_GRXFH:
Santwona Behera59089d82009-02-20 00:58:13 -08002531 case ETHTOOL_GRXRINGS:
2532 case ETHTOOL_GRXCLSRLCNT:
2533 case ETHTOOL_GRXCLSRULE:
2534 case ETHTOOL_GRXCLSRLALL:
Ben Hutchings2da45db2012-06-12 13:05:41 +00002535 case ETHTOOL_GRXFHINDIR:
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05302536 case ETHTOOL_GRSSH:
Michał Mirosław5455c692011-02-15 16:59:17 +00002537 case ETHTOOL_GFEATURES:
Ben Hutchings2da45db2012-06-12 13:05:41 +00002538 case ETHTOOL_GCHANNELS:
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002539 case ETHTOOL_GET_TS_INFO:
Ben Hutchings2da45db2012-06-12 13:05:41 +00002540 case ETHTOOL_GEEE:
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302541 case ETHTOOL_GTUNABLE:
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002542 case ETHTOOL_PHY_GTUNABLE:
Miroslav Lichvar8006f6b2016-11-24 10:55:06 +01002543 case ETHTOOL_GLINKSETTINGS:
Vidya Sagar Ravipati1a5f3da2017-07-27 16:47:26 -07002544 case ETHTOOL_GFECPARAM:
Stephen Hemminger75f31232006-09-28 15:13:37 -07002545 break;
2546 default:
Eric W. Biederman5e1fccc2012-11-16 03:03:04 +00002547 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Stephen Hemminger75f31232006-09-28 15:13:37 -07002548 return -EPERM;
2549 }
2550
chavey97f8aef2010-04-07 21:54:42 -07002551 if (dev->ethtool_ops->begin) {
2552 rc = dev->ethtool_ops->begin(dev);
2553 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 return rc;
chavey97f8aef2010-04-07 21:54:42 -07002555 }
Stephen Hemmingerd8a33ac2005-05-29 14:13:47 -07002556 old_features = dev->features;
2557
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 switch (ethcmd) {
2559 case ETHTOOL_GSET:
2560 rc = ethtool_get_settings(dev, useraddr);
2561 break;
2562 case ETHTOOL_SSET:
2563 rc = ethtool_set_settings(dev, useraddr);
2564 break;
2565 case ETHTOOL_GDRVINFO:
2566 rc = ethtool_get_drvinfo(dev, useraddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 break;
2568 case ETHTOOL_GREGS:
2569 rc = ethtool_get_regs(dev, useraddr);
2570 break;
2571 case ETHTOOL_GWOL:
2572 rc = ethtool_get_wol(dev, useraddr);
2573 break;
2574 case ETHTOOL_SWOL:
2575 rc = ethtool_set_wol(dev, useraddr);
2576 break;
2577 case ETHTOOL_GMSGLVL:
Jeff Garzik13c99b22007-08-15 16:01:56 -07002578 rc = ethtool_get_value(dev, useraddr, ethcmd,
2579 dev->ethtool_ops->get_msglevel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 break;
2581 case ETHTOOL_SMSGLVL:
Jeff Garzik13c99b22007-08-15 16:01:56 -07002582 rc = ethtool_set_value_void(dev, useraddr,
2583 dev->ethtool_ops->set_msglevel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 break;
Yuval Mintz80f12ec2012-06-06 17:13:06 +00002585 case ETHTOOL_GEEE:
2586 rc = ethtool_get_eee(dev, useraddr);
2587 break;
2588 case ETHTOOL_SEEE:
2589 rc = ethtool_set_eee(dev, useraddr);
2590 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 case ETHTOOL_NWAY_RST:
2592 rc = ethtool_nway_reset(dev);
2593 break;
2594 case ETHTOOL_GLINK:
Ben Hutchingse596e6e2010-12-09 12:08:35 +00002595 rc = ethtool_get_link(dev, useraddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 break;
2597 case ETHTOOL_GEEPROM:
2598 rc = ethtool_get_eeprom(dev, useraddr);
2599 break;
2600 case ETHTOOL_SEEPROM:
2601 rc = ethtool_set_eeprom(dev, useraddr);
2602 break;
2603 case ETHTOOL_GCOALESCE:
2604 rc = ethtool_get_coalesce(dev, useraddr);
2605 break;
2606 case ETHTOOL_SCOALESCE:
2607 rc = ethtool_set_coalesce(dev, useraddr);
2608 break;
2609 case ETHTOOL_GRINGPARAM:
2610 rc = ethtool_get_ringparam(dev, useraddr);
2611 break;
2612 case ETHTOOL_SRINGPARAM:
2613 rc = ethtool_set_ringparam(dev, useraddr);
2614 break;
2615 case ETHTOOL_GPAUSEPARAM:
2616 rc = ethtool_get_pauseparam(dev, useraddr);
2617 break;
2618 case ETHTOOL_SPAUSEPARAM:
2619 rc = ethtool_set_pauseparam(dev, useraddr);
2620 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 case ETHTOOL_TEST:
2622 rc = ethtool_self_test(dev, useraddr);
2623 break;
2624 case ETHTOOL_GSTRINGS:
2625 rc = ethtool_get_strings(dev, useraddr);
2626 break;
2627 case ETHTOOL_PHYS_ID:
2628 rc = ethtool_phys_id(dev, useraddr);
2629 break;
2630 case ETHTOOL_GSTATS:
2631 rc = ethtool_get_stats(dev, useraddr);
2632 break;
Jon Wetzela6f9a702005-08-20 17:15:54 -07002633 case ETHTOOL_GPERMADDR:
2634 rc = ethtool_get_perm_addr(dev, useraddr);
2635 break;
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07002636 case ETHTOOL_GFLAGS:
Jeff Garzik13c99b22007-08-15 16:01:56 -07002637 rc = ethtool_get_value(dev, useraddr, ethcmd,
Michał Mirosławbc5787c62011-11-15 15:29:55 +00002638 __ethtool_get_flags);
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07002639 break;
2640 case ETHTOOL_SFLAGS:
Michał Mirosławda8ac86c2011-02-15 16:59:18 +00002641 rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags);
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07002642 break;
Jeff Garzik339bf022007-08-15 16:01:32 -07002643 case ETHTOOL_GPFLAGS:
Jeff Garzik13c99b22007-08-15 16:01:56 -07002644 rc = ethtool_get_value(dev, useraddr, ethcmd,
2645 dev->ethtool_ops->get_priv_flags);
Jeff Garzik339bf022007-08-15 16:01:32 -07002646 break;
2647 case ETHTOOL_SPFLAGS:
Jeff Garzik13c99b22007-08-15 16:01:56 -07002648 rc = ethtool_set_value(dev, useraddr,
2649 dev->ethtool_ops->set_priv_flags);
Jeff Garzik339bf022007-08-15 16:01:32 -07002650 break;
Santwona Behera0853ad62008-07-02 03:47:41 -07002651 case ETHTOOL_GRXFH:
Santwona Behera59089d82009-02-20 00:58:13 -08002652 case ETHTOOL_GRXRINGS:
2653 case ETHTOOL_GRXCLSRLCNT:
2654 case ETHTOOL_GRXCLSRULE:
2655 case ETHTOOL_GRXCLSRLALL:
Ben Hutchingsbf988432010-06-28 08:45:58 +00002656 rc = ethtool_get_rxnfc(dev, ethcmd, useraddr);
Santwona Behera0853ad62008-07-02 03:47:41 -07002657 break;
2658 case ETHTOOL_SRXFH:
Santwona Behera59089d82009-02-20 00:58:13 -08002659 case ETHTOOL_SRXCLSRLDEL:
2660 case ETHTOOL_SRXCLSRLINS:
Ben Hutchingsbf988432010-06-28 08:45:58 +00002661 rc = ethtool_set_rxnfc(dev, ethcmd, useraddr);
Santwona Behera0853ad62008-07-02 03:47:41 -07002662 break;
Ajit Khaparde05c6a8d2009-09-02 17:02:55 +00002663 case ETHTOOL_FLASHDEV:
2664 rc = ethtool_flash_device(dev, useraddr);
2665 break;
Ben Hutchingsd73d3a82009-10-05 10:59:58 +00002666 case ETHTOOL_RESET:
2667 rc = ethtool_reset(dev, useraddr);
2668 break;
Jeff Garzik723b2f52010-03-03 22:51:50 +00002669 case ETHTOOL_GSSET_INFO:
2670 rc = ethtool_get_sset_info(dev, useraddr);
2671 break;
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00002672 case ETHTOOL_GRXFHINDIR:
2673 rc = ethtool_get_rxfh_indir(dev, useraddr);
2674 break;
2675 case ETHTOOL_SRXFHINDIR:
2676 rc = ethtool_set_rxfh_indir(dev, useraddr);
2677 break;
Venkata Duvvuru3de0b592014-04-21 15:37:59 +05302678 case ETHTOOL_GRSSH:
2679 rc = ethtool_get_rxfh(dev, useraddr);
2680 break;
2681 case ETHTOOL_SRSSH:
2682 rc = ethtool_set_rxfh(dev, useraddr);
2683 break;
Michał Mirosław5455c692011-02-15 16:59:17 +00002684 case ETHTOOL_GFEATURES:
2685 rc = ethtool_get_features(dev, useraddr);
2686 break;
2687 case ETHTOOL_SFEATURES:
2688 rc = ethtool_set_features(dev, useraddr);
2689 break;
Michał Mirosław0a417702011-02-15 16:59:17 +00002690 case ETHTOOL_GTXCSUM:
Michał Mirosławe83d3602011-02-15 16:59:18 +00002691 case ETHTOOL_GRXCSUM:
Michał Mirosław0a417702011-02-15 16:59:17 +00002692 case ETHTOOL_GSG:
2693 case ETHTOOL_GTSO:
Michał Mirosław0a417702011-02-15 16:59:17 +00002694 case ETHTOOL_GGSO:
2695 case ETHTOOL_GGRO:
2696 rc = ethtool_get_one_feature(dev, useraddr, ethcmd);
2697 break;
2698 case ETHTOOL_STXCSUM:
Michał Mirosławe83d3602011-02-15 16:59:18 +00002699 case ETHTOOL_SRXCSUM:
Michał Mirosław0a417702011-02-15 16:59:17 +00002700 case ETHTOOL_SSG:
2701 case ETHTOOL_STSO:
Michał Mirosław0a417702011-02-15 16:59:17 +00002702 case ETHTOOL_SGSO:
2703 case ETHTOOL_SGRO:
2704 rc = ethtool_set_one_feature(dev, useraddr, ethcmd);
2705 break;
amit salecha8b5933c2011-04-07 01:58:42 +00002706 case ETHTOOL_GCHANNELS:
2707 rc = ethtool_get_channels(dev, useraddr);
2708 break;
2709 case ETHTOOL_SCHANNELS:
2710 rc = ethtool_set_channels(dev, useraddr);
2711 break;
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00002712 case ETHTOOL_SET_DUMP:
2713 rc = ethtool_set_dump(dev, useraddr);
2714 break;
2715 case ETHTOOL_GET_DUMP_FLAG:
2716 rc = ethtool_get_dump_flag(dev, useraddr);
2717 break;
2718 case ETHTOOL_GET_DUMP_DATA:
2719 rc = ethtool_get_dump_data(dev, useraddr);
2720 break;
Richard Cochranc8f3a8c2012-04-03 22:59:17 +00002721 case ETHTOOL_GET_TS_INFO:
2722 rc = ethtool_get_ts_info(dev, useraddr);
2723 break;
Stuart Hodgson41c3cb62012-04-19 09:44:42 +01002724 case ETHTOOL_GMODULEINFO:
2725 rc = ethtool_get_module_info(dev, useraddr);
2726 break;
2727 case ETHTOOL_GMODULEEEPROM:
2728 rc = ethtool_get_module_eeprom(dev, useraddr);
2729 break;
Govindarajulu Varadarajanf0db9b02014-09-03 03:17:20 +05302730 case ETHTOOL_GTUNABLE:
2731 rc = ethtool_get_tunable(dev, useraddr);
2732 break;
2733 case ETHTOOL_STUNABLE:
2734 rc = ethtool_set_tunable(dev, useraddr);
2735 break;
Andrew Lunnf3a40942015-12-30 16:28:25 +01002736 case ETHTOOL_GPHYSTATS:
2737 rc = ethtool_get_phy_stats(dev, useraddr);
2738 break;
Kan Liangac2c7ad2016-02-19 09:24:01 -05002739 case ETHTOOL_PERQUEUE:
Wenwen Wang58f5bbe2018-10-08 10:49:35 -05002740 rc = ethtool_set_per_queue(dev, useraddr, sub_cmd);
Kan Liangac2c7ad2016-02-19 09:24:01 -05002741 break;
David Decotigny3f1ac7a2016-02-24 10:57:59 -08002742 case ETHTOOL_GLINKSETTINGS:
2743 rc = ethtool_get_link_ksettings(dev, useraddr);
2744 break;
2745 case ETHTOOL_SLINKSETTINGS:
2746 rc = ethtool_set_link_ksettings(dev, useraddr);
2747 break;
Raju Lakkaraju968ad9d2016-11-17 13:07:21 +01002748 case ETHTOOL_PHY_GTUNABLE:
2749 rc = get_phy_tunable(dev, useraddr);
2750 break;
2751 case ETHTOOL_PHY_STUNABLE:
2752 rc = set_phy_tunable(dev, useraddr);
2753 break;
Vidya Sagar Ravipati1a5f3da2017-07-27 16:47:26 -07002754 case ETHTOOL_GFECPARAM:
2755 rc = ethtool_get_fecparam(dev, useraddr);
2756 break;
2757 case ETHTOOL_SFECPARAM:
2758 rc = ethtool_set_fecparam(dev, useraddr);
2759 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 default:
Matthew Wilcox61a44b92007-07-31 14:00:02 -07002761 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002763
Stephen Hemmingere71a4782007-04-10 20:10:33 -07002764 if (dev->ethtool_ops->complete)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 dev->ethtool_ops->complete(dev);
Stephen Hemmingerd8a33ac2005-05-29 14:13:47 -07002766
2767 if (old_features != dev->features)
2768 netdev_features_change(dev);
2769
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771}
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01002772
2773struct ethtool_rx_flow_key {
2774 struct flow_dissector_key_basic basic;
2775 union {
2776 struct flow_dissector_key_ipv4_addrs ipv4;
2777 struct flow_dissector_key_ipv6_addrs ipv6;
2778 };
2779 struct flow_dissector_key_ports tp;
2780 struct flow_dissector_key_ip ip;
2781 struct flow_dissector_key_vlan vlan;
2782 struct flow_dissector_key_eth_addrs eth_addrs;
2783} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
2784
2785struct ethtool_rx_flow_match {
2786 struct flow_dissector dissector;
2787 struct ethtool_rx_flow_key key;
2788 struct ethtool_rx_flow_key mask;
2789};
2790
2791struct ethtool_rx_flow_rule *
2792ethtool_rx_flow_rule_create(const struct ethtool_rx_flow_spec_input *input)
2793{
2794 const struct ethtool_rx_flow_spec *fs = input->fs;
2795 static struct in6_addr zero_addr = {};
2796 struct ethtool_rx_flow_match *match;
2797 struct ethtool_rx_flow_rule *flow;
2798 struct flow_action_entry *act;
2799
2800 flow = kzalloc(sizeof(struct ethtool_rx_flow_rule) +
2801 sizeof(struct ethtool_rx_flow_match), GFP_KERNEL);
2802 if (!flow)
2803 return ERR_PTR(-ENOMEM);
2804
2805 /* ethtool_rx supports only one single action per rule. */
2806 flow->rule = flow_rule_alloc(1);
2807 if (!flow->rule) {
2808 kfree(flow);
2809 return ERR_PTR(-ENOMEM);
2810 }
2811
2812 match = (struct ethtool_rx_flow_match *)flow->priv;
2813 flow->rule->match.dissector = &match->dissector;
2814 flow->rule->match.mask = &match->mask;
2815 flow->rule->match.key = &match->key;
2816
2817 match->mask.basic.n_proto = htons(0xffff);
2818
2819 switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
Maxime Chevallier5b9469a2019-06-27 10:52:26 +02002820 case ETHER_FLOW: {
2821 const struct ethhdr *ether_spec, *ether_m_spec;
2822
2823 ether_spec = &fs->h_u.ether_spec;
2824 ether_m_spec = &fs->m_u.ether_spec;
2825
2826 if (!is_zero_ether_addr(ether_m_spec->h_source)) {
2827 ether_addr_copy(match->key.eth_addrs.src,
2828 ether_spec->h_source);
2829 ether_addr_copy(match->mask.eth_addrs.src,
2830 ether_m_spec->h_source);
2831 }
2832 if (!is_zero_ether_addr(ether_m_spec->h_dest)) {
2833 ether_addr_copy(match->key.eth_addrs.dst,
2834 ether_spec->h_dest);
2835 ether_addr_copy(match->mask.eth_addrs.dst,
2836 ether_m_spec->h_dest);
2837 }
2838 if (ether_m_spec->h_proto) {
2839 match->key.basic.n_proto = ether_spec->h_proto;
2840 match->mask.basic.n_proto = ether_m_spec->h_proto;
2841 }
2842 }
2843 break;
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01002844 case TCP_V4_FLOW:
2845 case UDP_V4_FLOW: {
2846 const struct ethtool_tcpip4_spec *v4_spec, *v4_m_spec;
2847
2848 match->key.basic.n_proto = htons(ETH_P_IP);
2849
2850 v4_spec = &fs->h_u.tcp_ip4_spec;
2851 v4_m_spec = &fs->m_u.tcp_ip4_spec;
2852
2853 if (v4_m_spec->ip4src) {
2854 match->key.ipv4.src = v4_spec->ip4src;
2855 match->mask.ipv4.src = v4_m_spec->ip4src;
2856 }
2857 if (v4_m_spec->ip4dst) {
2858 match->key.ipv4.dst = v4_spec->ip4dst;
2859 match->mask.ipv4.dst = v4_m_spec->ip4dst;
2860 }
2861 if (v4_m_spec->ip4src ||
2862 v4_m_spec->ip4dst) {
2863 match->dissector.used_keys |=
2864 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS);
2865 match->dissector.offset[FLOW_DISSECTOR_KEY_IPV4_ADDRS] =
2866 offsetof(struct ethtool_rx_flow_key, ipv4);
2867 }
2868 if (v4_m_spec->psrc) {
2869 match->key.tp.src = v4_spec->psrc;
2870 match->mask.tp.src = v4_m_spec->psrc;
2871 }
2872 if (v4_m_spec->pdst) {
2873 match->key.tp.dst = v4_spec->pdst;
2874 match->mask.tp.dst = v4_m_spec->pdst;
2875 }
2876 if (v4_m_spec->psrc ||
2877 v4_m_spec->pdst) {
2878 match->dissector.used_keys |=
2879 BIT(FLOW_DISSECTOR_KEY_PORTS);
2880 match->dissector.offset[FLOW_DISSECTOR_KEY_PORTS] =
2881 offsetof(struct ethtool_rx_flow_key, tp);
2882 }
2883 if (v4_m_spec->tos) {
2884 match->key.ip.tos = v4_spec->tos;
2885 match->mask.ip.tos = v4_m_spec->tos;
2886 match->dissector.used_keys |=
2887 BIT(FLOW_DISSECTOR_KEY_IP);
2888 match->dissector.offset[FLOW_DISSECTOR_KEY_IP] =
2889 offsetof(struct ethtool_rx_flow_key, ip);
2890 }
2891 }
2892 break;
2893 case TCP_V6_FLOW:
2894 case UDP_V6_FLOW: {
2895 const struct ethtool_tcpip6_spec *v6_spec, *v6_m_spec;
2896
2897 match->key.basic.n_proto = htons(ETH_P_IPV6);
2898
2899 v6_spec = &fs->h_u.tcp_ip6_spec;
2900 v6_m_spec = &fs->m_u.tcp_ip6_spec;
2901 if (memcmp(v6_m_spec->ip6src, &zero_addr, sizeof(zero_addr))) {
2902 memcpy(&match->key.ipv6.src, v6_spec->ip6src,
2903 sizeof(match->key.ipv6.src));
2904 memcpy(&match->mask.ipv6.src, v6_m_spec->ip6src,
2905 sizeof(match->mask.ipv6.src));
2906 }
2907 if (memcmp(v6_m_spec->ip6dst, &zero_addr, sizeof(zero_addr))) {
2908 memcpy(&match->key.ipv6.dst, v6_spec->ip6dst,
2909 sizeof(match->key.ipv6.dst));
2910 memcpy(&match->mask.ipv6.dst, v6_m_spec->ip6dst,
2911 sizeof(match->mask.ipv6.dst));
2912 }
2913 if (memcmp(v6_m_spec->ip6src, &zero_addr, sizeof(zero_addr)) ||
2914 memcmp(v6_m_spec->ip6src, &zero_addr, sizeof(zero_addr))) {
2915 match->dissector.used_keys |=
2916 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS);
2917 match->dissector.offset[FLOW_DISSECTOR_KEY_IPV6_ADDRS] =
2918 offsetof(struct ethtool_rx_flow_key, ipv6);
2919 }
2920 if (v6_m_spec->psrc) {
2921 match->key.tp.src = v6_spec->psrc;
2922 match->mask.tp.src = v6_m_spec->psrc;
2923 }
2924 if (v6_m_spec->pdst) {
2925 match->key.tp.dst = v6_spec->pdst;
2926 match->mask.tp.dst = v6_m_spec->pdst;
2927 }
2928 if (v6_m_spec->psrc ||
2929 v6_m_spec->pdst) {
2930 match->dissector.used_keys |=
2931 BIT(FLOW_DISSECTOR_KEY_PORTS);
2932 match->dissector.offset[FLOW_DISSECTOR_KEY_PORTS] =
2933 offsetof(struct ethtool_rx_flow_key, tp);
2934 }
2935 if (v6_m_spec->tclass) {
2936 match->key.ip.tos = v6_spec->tclass;
2937 match->mask.ip.tos = v6_m_spec->tclass;
2938 match->dissector.used_keys |=
2939 BIT(FLOW_DISSECTOR_KEY_IP);
2940 match->dissector.offset[FLOW_DISSECTOR_KEY_IP] =
2941 offsetof(struct ethtool_rx_flow_key, ip);
2942 }
2943 }
2944 break;
2945 default:
2946 ethtool_rx_flow_rule_destroy(flow);
2947 return ERR_PTR(-EINVAL);
2948 }
2949
2950 switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
2951 case TCP_V4_FLOW:
2952 case TCP_V6_FLOW:
2953 match->key.basic.ip_proto = IPPROTO_TCP;
2954 break;
2955 case UDP_V4_FLOW:
2956 case UDP_V6_FLOW:
2957 match->key.basic.ip_proto = IPPROTO_UDP;
2958 break;
2959 }
2960 match->mask.basic.ip_proto = 0xff;
2961
2962 match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
2963 match->dissector.offset[FLOW_DISSECTOR_KEY_BASIC] =
2964 offsetof(struct ethtool_rx_flow_key, basic);
2965
2966 if (fs->flow_type & FLOW_EXT) {
2967 const struct ethtool_flow_ext *ext_h_spec = &fs->h_ext;
2968 const struct ethtool_flow_ext *ext_m_spec = &fs->m_ext;
2969
Maxime Chevallierb73484b2019-05-30 16:08:40 +02002970 if (ext_m_spec->vlan_etype) {
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01002971 match->key.vlan.vlan_tpid = ext_h_spec->vlan_etype;
2972 match->mask.vlan.vlan_tpid = ext_m_spec->vlan_etype;
Maxime Chevallierb73484b2019-05-30 16:08:40 +02002973 }
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01002974
Maxime Chevallierb73484b2019-05-30 16:08:40 +02002975 if (ext_m_spec->vlan_tci) {
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01002976 match->key.vlan.vlan_id =
2977 ntohs(ext_h_spec->vlan_tci) & 0x0fff;
2978 match->mask.vlan.vlan_id =
2979 ntohs(ext_m_spec->vlan_tci) & 0x0fff;
2980
Maxime Chevallierf0d2ca12019-06-12 17:18:38 +02002981 match->key.vlan.vlan_dei =
2982 !!(ext_h_spec->vlan_tci & htons(0x1000));
2983 match->mask.vlan.vlan_dei =
2984 !!(ext_m_spec->vlan_tci & htons(0x1000));
2985
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01002986 match->key.vlan.vlan_priority =
2987 (ntohs(ext_h_spec->vlan_tci) & 0xe000) >> 13;
2988 match->mask.vlan.vlan_priority =
2989 (ntohs(ext_m_spec->vlan_tci) & 0xe000) >> 13;
Maxime Chevallierb73484b2019-05-30 16:08:40 +02002990 }
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01002991
Maxime Chevallierb73484b2019-05-30 16:08:40 +02002992 if (ext_m_spec->vlan_etype ||
2993 ext_m_spec->vlan_tci) {
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01002994 match->dissector.used_keys |=
2995 BIT(FLOW_DISSECTOR_KEY_VLAN);
2996 match->dissector.offset[FLOW_DISSECTOR_KEY_VLAN] =
2997 offsetof(struct ethtool_rx_flow_key, vlan);
2998 }
2999 }
3000 if (fs->flow_type & FLOW_MAC_EXT) {
3001 const struct ethtool_flow_ext *ext_h_spec = &fs->h_ext;
3002 const struct ethtool_flow_ext *ext_m_spec = &fs->m_ext;
3003
Nathan Chancellor8b34ec62019-02-07 21:46:53 -07003004 memcpy(match->key.eth_addrs.dst, ext_h_spec->h_dest,
3005 ETH_ALEN);
3006 memcpy(match->mask.eth_addrs.dst, ext_m_spec->h_dest,
3007 ETH_ALEN);
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01003008
Nathan Chancellor8b34ec62019-02-07 21:46:53 -07003009 match->dissector.used_keys |=
3010 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS);
3011 match->dissector.offset[FLOW_DISSECTOR_KEY_ETH_ADDRS] =
3012 offsetof(struct ethtool_rx_flow_key, eth_addrs);
Pablo Neira Ayusoeca42052019-02-02 12:50:51 +01003013 }
3014
3015 act = &flow->rule->action.entries[0];
3016 switch (fs->ring_cookie) {
3017 case RX_CLS_FLOW_DISC:
3018 act->id = FLOW_ACTION_DROP;
3019 break;
3020 case RX_CLS_FLOW_WAKE:
3021 act->id = FLOW_ACTION_WAKE;
3022 break;
3023 default:
3024 act->id = FLOW_ACTION_QUEUE;
3025 if (fs->flow_type & FLOW_RSS)
3026 act->queue.ctx = input->rss_ctx;
3027
3028 act->queue.vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
3029 act->queue.index = ethtool_get_flow_spec_ring(fs->ring_cookie);
3030 break;
3031 }
3032
3033 return flow;
3034}
3035EXPORT_SYMBOL(ethtool_rx_flow_rule_create);
3036
3037void ethtool_rx_flow_rule_destroy(struct ethtool_rx_flow_rule *flow)
3038{
3039 kfree(flow->rule);
3040 kfree(flow);
3041}
3042EXPORT_SYMBOL(ethtool_rx_flow_rule_destroy);