ethtool.c 68.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
/*
 * net/core/ethtool.c - Ethtool ioctl handler
 * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
 *
 * This file is where we call all the ethtool_ops commands to get
6
 * the information ethtool needs.
Linus Torvalds's avatar
Linus Torvalds committed
7
 *
8
9
10
11
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
Linus Torvalds's avatar
Linus Torvalds committed
12
13
14
15
 */

#include <linux/module.h>
#include <linux/types.h>
16
#include <linux/capability.h>
Linus Torvalds's avatar
Linus Torvalds committed
17
18
19
#include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
20
21
#include <linux/net_tstamp.h>
#include <linux/phy.h>
22
#include <linux/bitops.h>
23
#include <linux/uaccess.h>
24
#include <linux/vmalloc.h>
25
#include <linux/slab.h>
26
27
#include <linux/rtnetlink.h>
#include <linux/sched.h>
28
#include <linux/net.h>
Linus Torvalds's avatar
Linus Torvalds committed
29

30
/*
Linus Torvalds's avatar
Linus Torvalds committed
31
32
33
34
35
36
37
38
39
 * Some useful ethtool_ops methods that're device independent.
 * If we find that all drivers want to do the same thing here,
 * we can turn these into dev_() function calls.
 */

u32 ethtool_op_get_link(struct net_device *dev)
{
	return netif_carrier_ok(dev) ? 1 : 0;
}
40
EXPORT_SYMBOL(ethtool_op_get_link);
Linus Torvalds's avatar
Linus Torvalds committed
41

42
43
44
45
46
47
48
49
50
51
52
int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
{
	info->so_timestamping =
		SOF_TIMESTAMPING_TX_SOFTWARE |
		SOF_TIMESTAMPING_RX_SOFTWARE |
		SOF_TIMESTAMPING_SOFTWARE;
	info->phc_index = -1;
	return 0;
}
EXPORT_SYMBOL(ethtool_op_get_ts_info);

Linus Torvalds's avatar
Linus Torvalds committed
53
54
/* Handlers for each ethtool command */

55
#define ETHTOOL_DEV_FEATURE_WORDS	((NETDEV_FEATURE_COUNT + 31) / 32)
56

57
58
59
60
61
62
63
static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
	[NETIF_F_SG_BIT] =               "tx-scatter-gather",
	[NETIF_F_IP_CSUM_BIT] =          "tx-checksum-ipv4",
	[NETIF_F_HW_CSUM_BIT] =          "tx-checksum-ip-generic",
	[NETIF_F_IPV6_CSUM_BIT] =        "tx-checksum-ipv6",
	[NETIF_F_HIGHDMA_BIT] =          "highdma",
	[NETIF_F_FRAGLIST_BIT] =         "tx-scatter-gather-fraglist",
64
	[NETIF_F_HW_VLAN_CTAG_TX_BIT] =  "tx-vlan-hw-insert",
65

66
67
	[NETIF_F_HW_VLAN_CTAG_RX_BIT] =  "rx-vlan-hw-parse",
	[NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-filter",
68
69
70
	[NETIF_F_HW_VLAN_STAG_TX_BIT] =  "tx-vlan-stag-hw-insert",
	[NETIF_F_HW_VLAN_STAG_RX_BIT] =  "rx-vlan-stag-hw-parse",
	[NETIF_F_HW_VLAN_STAG_FILTER_BIT] = "rx-vlan-stag-filter",
71
72
73
74
75
76
77
78
79
80
81
	[NETIF_F_VLAN_CHALLENGED_BIT] =  "vlan-challenged",
	[NETIF_F_GSO_BIT] =              "tx-generic-segmentation",
	[NETIF_F_LLTX_BIT] =             "tx-lockless",
	[NETIF_F_NETNS_LOCAL_BIT] =      "netns-local",
	[NETIF_F_GRO_BIT] =              "rx-gro",
	[NETIF_F_LRO_BIT] =              "rx-lro",

	[NETIF_F_TSO_BIT] =              "tx-tcp-segmentation",
	[NETIF_F_UFO_BIT] =              "tx-udp-fragmentation",
	[NETIF_F_GSO_ROBUST_BIT] =       "tx-gso-robust",
	[NETIF_F_TSO_ECN_BIT] =          "tx-tcp-ecn-segmentation",
82
	[NETIF_F_TSO_MANGLEID_BIT] =	 "tx-tcp-mangleid-segmentation",
83
84
	[NETIF_F_TSO6_BIT] =             "tx-tcp6-segmentation",
	[NETIF_F_FSO_BIT] =              "tx-fcoe-segmentation",
85
	[NETIF_F_GSO_GRE_BIT] =		 "tx-gre-segmentation",
86
	[NETIF_F_GSO_GRE_CSUM_BIT] =	 "tx-gre-csum-segmentation",
87
88
	[NETIF_F_GSO_IPXIP4_BIT] =	 "tx-ipxip4-segmentation",
	[NETIF_F_GSO_IPXIP6_BIT] =	 "tx-ipxip6-segmentation",
89
	[NETIF_F_GSO_UDP_TUNNEL_BIT] =	 "tx-udp_tnl-segmentation",
90
	[NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT] = "tx-udp_tnl-csum-segmentation",
91
	[NETIF_F_GSO_PARTIAL_BIT] =	 "tx-gso-partial",
92
	[NETIF_F_GSO_SCTP_BIT] =	 "tx-sctp-segmentation",
93
94

	[NETIF_F_FCOE_CRC_BIT] =         "tx-checksum-fcoe-crc",
95
	[NETIF_F_SCTP_CRC_BIT] =        "tx-checksum-sctp",
96
97
98
99
100
101
	[NETIF_F_FCOE_MTU_BIT] =         "fcoe-mtu",
	[NETIF_F_NTUPLE_BIT] =           "rx-ntuple-filter",
	[NETIF_F_RXHASH_BIT] =           "rx-hashing",
	[NETIF_F_RXCSUM_BIT] =           "rx-checksum",
	[NETIF_F_NOCACHE_COPY_BIT] =     "tx-nocache-copy",
	[NETIF_F_LOOPBACK_BIT] =         "loopback",
Ben Greear's avatar
Ben Greear committed
102
	[NETIF_F_RXFCS_BIT] =            "rx-fcs",
Ben Greear's avatar
Ben Greear committed
103
	[NETIF_F_RXALL_BIT] =            "rx-all",
104
	[NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
Jiri Pirko's avatar
Jiri Pirko committed
105
	[NETIF_F_BUSY_POLL_BIT] =        "busy-poll",
106
	[NETIF_F_HW_TC_BIT] =		 "hw-tc-offload",
107
108
};

109
110
111
112
113
114
static const char
rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN] = {
	[ETH_RSS_HASH_TOP_BIT] =	"toeplitz",
	[ETH_RSS_HASH_XOR_BIT] =	"xor",
};

115
116
117
118
119
120
121
static const char
tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
	[ETHTOOL_ID_UNSPEC]     = "Unspec",
	[ETHTOOL_RX_COPYBREAK]	= "rx-copybreak",
	[ETHTOOL_TX_COPYBREAK]	= "tx-copybreak",
};

122
123
124
125
126
127
static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_gfeatures cmd = {
		.cmd = ETHTOOL_GFEATURES,
		.size = ETHTOOL_DEV_FEATURE_WORDS,
	};
128
	struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
129
130
	u32 __user *sizeaddr;
	u32 copy_size;
131
132
133
	int i;

	/* in case feature bits run out again */
134
	BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > sizeof(netdev_features_t));
135
136

	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
137
138
139
140
141
		features[i].available = (u32)(dev->hw_features >> (32 * i));
		features[i].requested = (u32)(dev->wanted_features >> (32 * i));
		features[i].active = (u32)(dev->features >> (32 * i));
		features[i].never_changed =
			(u32)(NETIF_F_NEVER_CHANGE >> (32 * i));
142
	}
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

	sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size);
	if (get_user(copy_size, sizeaddr))
		return -EFAULT;

	if (copy_size > ETHTOOL_DEV_FEATURE_WORDS)
		copy_size = ETHTOOL_DEV_FEATURE_WORDS;

	if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
		return -EFAULT;
	useraddr += sizeof(cmd);
	if (copy_to_user(useraddr, features, copy_size * sizeof(*features)))
		return -EFAULT;

	return 0;
}

static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_sfeatures cmd;
	struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
164
165
	netdev_features_t wanted = 0, valid = 0;
	int i, ret = 0;
166
167
168
169
170
171
172
173
174
175
176

	if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
		return -EFAULT;
	useraddr += sizeof(cmd);

	if (cmd.size != ETHTOOL_DEV_FEATURE_WORDS)
		return -EINVAL;

	if (copy_from_user(features, useraddr, sizeof(features)))
		return -EFAULT;

177
	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
178
179
		valid |= (netdev_features_t)features[i].valid << (32 * i);
		wanted |= (netdev_features_t)features[i].requested << (32 * i);
180
181
182
	}

	if (valid & ~NETIF_F_ETHTOOL_BITS)
183
184
		return -EINVAL;

185
186
	if (valid & ~dev->hw_features) {
		valid &= dev->hw_features;
187
188
189
		ret |= ETHTOOL_F_UNSUPPORTED;
	}

190
191
	dev->wanted_features &= ~valid;
	dev->wanted_features |= wanted & valid;
192
	__netdev_update_features(dev);
193

194
	if ((dev->wanted_features ^ dev->features) & valid)
195
196
197
198
199
		ret |= ETHTOOL_F_WISH;

	return ret;
}

Andrew Lunn's avatar
Andrew Lunn committed
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
static int phy_get_sset_count(struct phy_device *phydev)
{
	int ret;

	if (phydev->drv->get_sset_count &&
	    phydev->drv->get_strings &&
	    phydev->drv->get_stats) {
		mutex_lock(&phydev->lock);
		ret = phydev->drv->get_sset_count(phydev);
		mutex_unlock(&phydev->lock);

		return ret;
	}

	return -EOPNOTSUPP;
}

217
218
219
220
static int __ethtool_get_sset_count(struct net_device *dev, int sset)
{
	const struct ethtool_ops *ops = dev->ethtool_ops;

221
222
223
	if (sset == ETH_SS_FEATURES)
		return ARRAY_SIZE(netdev_features_strings);

224
225
226
	if (sset == ETH_SS_RSS_HASH_FUNCS)
		return ARRAY_SIZE(rss_hash_func_strings);

227
228
229
	if (sset == ETH_SS_TUNABLES)
		return ARRAY_SIZE(tunable_strings);

Andrew Lunn's avatar
Andrew Lunn committed
230
231
232
233
234
235
236
	if (sset == ETH_SS_PHY_STATS) {
		if (dev->phydev)
			return phy_get_sset_count(dev->phydev);
		else
			return -EOPNOTSUPP;
	}

237
	if (ops->get_sset_count && ops->get_strings)
238
239
240
241
242
243
244
245
246
247
		return ops->get_sset_count(dev, sset);
	else
		return -EOPNOTSUPP;
}

static void __ethtool_get_strings(struct net_device *dev,
	u32 stringset, u8 *data)
{
	const struct ethtool_ops *ops = dev->ethtool_ops;

248
249
250
	if (stringset == ETH_SS_FEATURES)
		memcpy(data, netdev_features_strings,
			sizeof(netdev_features_strings));
251
252
253
	else if (stringset == ETH_SS_RSS_HASH_FUNCS)
		memcpy(data, rss_hash_func_strings,
		       sizeof(rss_hash_func_strings));
254
255
	else if (stringset == ETH_SS_TUNABLES)
		memcpy(data, tunable_strings, sizeof(tunable_strings));
Andrew Lunn's avatar
Andrew Lunn committed
256
257
258
259
260
261
262
263
264
265
266
	else if (stringset == ETH_SS_PHY_STATS) {
		struct phy_device *phydev = dev->phydev;

		if (phydev) {
			mutex_lock(&phydev->lock);
			phydev->drv->get_strings(phydev, data);
			mutex_unlock(&phydev->lock);
		} else {
			return;
		}
	} else
267
268
		/* ops->get_strings is valid because checked earlier */
		ops->get_strings(dev, stringset, data);
269
270
}

271
static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd)
272
273
274
275
276
277
{
	/* feature masks of legacy discrete ethtool ops */

	switch (eth_cmd) {
	case ETHTOOL_GTXCSUM:
	case ETHTOOL_STXCSUM:
278
		return NETIF_F_CSUM_MASK | NETIF_F_SCTP_CRC;
279
280
281
	case ETHTOOL_GRXCSUM:
	case ETHTOOL_SRXCSUM:
		return NETIF_F_RXCSUM;
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
	case ETHTOOL_GSG:
	case ETHTOOL_SSG:
		return NETIF_F_SG;
	case ETHTOOL_GTSO:
	case ETHTOOL_STSO:
		return NETIF_F_ALL_TSO;
	case ETHTOOL_GUFO:
	case ETHTOOL_SUFO:
		return NETIF_F_UFO;
	case ETHTOOL_GGSO:
	case ETHTOOL_SGSO:
		return NETIF_F_GSO;
	case ETHTOOL_GGRO:
	case ETHTOOL_SGRO:
		return NETIF_F_GRO;
	default:
		BUG();
	}
}

static int ethtool_get_one_feature(struct net_device *dev,
	char __user *useraddr, u32 ethcmd)
{
305
	netdev_features_t mask = ethtool_get_feature_mask(ethcmd);
306
307
	struct ethtool_value edata = {
		.cmd = ethcmd,
308
		.data = !!(dev->features & mask),
309
310
311
312
313
314
315
316
317
318
319
	};

	if (copy_to_user(useraddr, &edata, sizeof(edata)))
		return -EFAULT;
	return 0;
}

static int ethtool_set_one_feature(struct net_device *dev,
	void __user *useraddr, u32 ethcmd)
{
	struct ethtool_value edata;
320
	netdev_features_t mask;
321
322
323
324

	if (copy_from_user(&edata, useraddr, sizeof(edata)))
		return -EFAULT;

325
326
	mask = ethtool_get_feature_mask(ethcmd);
	mask &= dev->hw_features;
327
328
	if (!mask)
		return -EOPNOTSUPP;
329

330
331
332
333
	if (edata.data)
		dev->wanted_features |= mask;
	else
		dev->wanted_features &= ~mask;
334

335
	__netdev_update_features(dev);
336

337
338
339
	return 0;
}

340
341
#define ETH_ALL_FLAGS    (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \
			  ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH)
342
343
344
#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_CTAG_RX | \
			  NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_NTUPLE | \
			  NETIF_F_RXHASH)
345
346
347

static u32 __ethtool_get_flags(struct net_device *dev)
{
348
349
	u32 flags = 0;

350
351
352
353
354
355
356
357
358
359
	if (dev->features & NETIF_F_LRO)
		flags |= ETH_FLAG_LRO;
	if (dev->features & NETIF_F_HW_VLAN_CTAG_RX)
		flags |= ETH_FLAG_RXVLAN;
	if (dev->features & NETIF_F_HW_VLAN_CTAG_TX)
		flags |= ETH_FLAG_TXVLAN;
	if (dev->features & NETIF_F_NTUPLE)
		flags |= ETH_FLAG_NTUPLE;
	if (dev->features & NETIF_F_RXHASH)
		flags |= ETH_FLAG_RXHASH;
360
361

	return flags;
362
363
}

364
static int __ethtool_set_flags(struct net_device *dev, u32 data)
365
{
366
	netdev_features_t features = 0, changed;
367

368
	if (data & ~ETH_ALL_FLAGS)
369
370
		return -EINVAL;

371
372
373
374
375
376
377
378
379
380
	if (data & ETH_FLAG_LRO)
		features |= NETIF_F_LRO;
	if (data & ETH_FLAG_RXVLAN)
		features |= NETIF_F_HW_VLAN_CTAG_RX;
	if (data & ETH_FLAG_TXVLAN)
		features |= NETIF_F_HW_VLAN_CTAG_TX;
	if (data & ETH_FLAG_NTUPLE)
		features |= NETIF_F_NTUPLE;
	if (data & ETH_FLAG_RXHASH)
		features |= NETIF_F_RXHASH;
381

382
	/* allow changing only bits set in hw_features */
383
	changed = (features ^ dev->features) & ETH_ALL_FEATURES;
384
385
386
387
	if (changed & ~dev->hw_features)
		return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;

	dev->wanted_features =
388
		(dev->wanted_features & ~changed) | (features & changed);
389

390
	__netdev_update_features(dev);
391
392
393
394

	return 0;
}

395
396
void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst,
					     u32 legacy_u32)
397
398
399
400
{
	bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS);
	dst[0] = legacy_u32;
}
401
EXPORT_SYMBOL(ethtool_convert_legacy_u32_to_link_mode);
402
403

/* return false if src had higher bits set. lower bits always updated. */
404
405
bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
					     const unsigned long *src)
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
{
	bool retval = true;

	/* TODO: following test will soon always be true */
	if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) {
		__ETHTOOL_DECLARE_LINK_MODE_MASK(ext);

		bitmap_zero(ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
		bitmap_fill(ext, 32);
		bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
		if (bitmap_intersects(ext, src,
				      __ETHTOOL_LINK_MODE_MASK_NBITS)) {
			/* src mask goes beyond bit 31 */
			retval = false;
		}
	}
	*legacy_u32 = src[0];
	return retval;
}
425
EXPORT_SYMBOL(ethtool_convert_link_mode_to_legacy_u32);
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447

/* return false if legacy contained non-0 deprecated fields
 * transceiver/maxtxpkt/maxrxpkt. rest of ksettings always updated
 */
static bool
convert_legacy_settings_to_link_ksettings(
	struct ethtool_link_ksettings *link_ksettings,
	const struct ethtool_cmd *legacy_settings)
{
	bool retval = true;

	memset(link_ksettings, 0, sizeof(*link_ksettings));

	/* This is used to tell users that driver is still using these
	 * deprecated legacy fields, and they should not use
	 * %ETHTOOL_GLINKSETTINGS/%ETHTOOL_SLINKSETTINGS
	 */
	if (legacy_settings->transceiver ||
	    legacy_settings->maxtxpkt ||
	    legacy_settings->maxrxpkt)
		retval = false;

448
	ethtool_convert_legacy_u32_to_link_mode(
449
450
		link_ksettings->link_modes.supported,
		legacy_settings->supported);
451
	ethtool_convert_legacy_u32_to_link_mode(
452
453
		link_ksettings->link_modes.advertising,
		legacy_settings->advertising);
454
	ethtool_convert_legacy_u32_to_link_mode(
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
		link_ksettings->link_modes.lp_advertising,
		legacy_settings->lp_advertising);
	link_ksettings->base.speed
		= ethtool_cmd_speed(legacy_settings);
	link_ksettings->base.duplex
		= legacy_settings->duplex;
	link_ksettings->base.port
		= legacy_settings->port;
	link_ksettings->base.phy_address
		= legacy_settings->phy_address;
	link_ksettings->base.autoneg
		= legacy_settings->autoneg;
	link_ksettings->base.mdio_support
		= legacy_settings->mdio_support;
	link_ksettings->base.eth_tp_mdix
		= legacy_settings->eth_tp_mdix;
	link_ksettings->base.eth_tp_mdix_ctrl
		= legacy_settings->eth_tp_mdix_ctrl;
	return retval;
}

/* return false if ksettings link modes had higher bits
 * set. legacy_settings always updated (best effort)
 */
static bool
convert_link_ksettings_to_legacy_settings(
	struct ethtool_cmd *legacy_settings,
	const struct ethtool_link_ksettings *link_ksettings)
{
	bool retval = true;

	memset(legacy_settings, 0, sizeof(*legacy_settings));
	/* this also clears the deprecated fields in legacy structure:
	 * __u8		transceiver;
	 * __u32	maxtxpkt;
	 * __u32	maxrxpkt;
	 */

493
	retval &= ethtool_convert_link_mode_to_legacy_u32(
494
495
		&legacy_settings->supported,
		link_ksettings->link_modes.supported);
496
	retval &= ethtool_convert_link_mode_to_legacy_u32(
497
498
		&legacy_settings->advertising,
		link_ksettings->link_modes.advertising);
499
	retval &= ethtool_convert_link_mode_to_legacy_u32(
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
		&legacy_settings->lp_advertising,
		link_ksettings->link_modes.lp_advertising);
	ethtool_cmd_speed_set(legacy_settings, link_ksettings->base.speed);
	legacy_settings->duplex
		= link_ksettings->base.duplex;
	legacy_settings->port
		= link_ksettings->base.port;
	legacy_settings->phy_address
		= link_ksettings->base.phy_address;
	legacy_settings->autoneg
		= link_ksettings->base.autoneg;
	legacy_settings->mdio_support
		= link_ksettings->base.mdio_support;
	legacy_settings->eth_tp_mdix
		= link_ksettings->base.eth_tp_mdix;
	legacy_settings->eth_tp_mdix_ctrl
		= link_ksettings->base.eth_tp_mdix_ctrl;
	return retval;
}

/* number of 32-bit words to store the user's link mode bitmaps */
#define __ETHTOOL_LINK_MODE_MASK_NU32			\
	DIV_ROUND_UP(__ETHTOOL_LINK_MODE_MASK_NBITS, 32)

/* layout of the struct passed from/to userland */
struct ethtool_link_usettings {
	struct ethtool_link_settings base;
	struct {
		__u32 supported[__ETHTOOL_LINK_MODE_MASK_NU32];
		__u32 advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
		__u32 lp_advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
	} link_modes;
};

/* Internal kernel helper to query a device ethtool_link_settings.
 *
 * Backward compatibility note: for compatibility with legacy drivers
 * that implement only the ethtool_cmd API, this has to work with both
 * drivers implementing get_link_ksettings API and drivers
 * implementing get_settings API. When drivers implement get_settings
 * and report ethtool_cmd deprecated fields
 * (transceiver/maxrxpkt/maxtxpkt), these fields are silently ignored
 * because the resulting struct ethtool_link_settings does not report them.
 */
int __ethtool_get_link_ksettings(struct net_device *dev,
				 struct ethtool_link_ksettings *link_ksettings)
{
	int err;
	struct ethtool_cmd cmd;

	ASSERT_RTNL();

	if (dev->ethtool_ops->get_link_ksettings) {
		memset(link_ksettings, 0, sizeof(*link_ksettings));
		return dev->ethtool_ops->get_link_ksettings(dev,
							    link_ksettings);
	}

	/* driver doesn't support %ethtool_link_ksettings API. revert to
	 * legacy %ethtool_cmd API, unless it's not supported either.
	 * TODO: remove when ethtool_ops::get_settings disappears internally
	 */
562
563
564
565
566
567
	if (!dev->ethtool_ops->get_settings)
		return -EOPNOTSUPP;

	memset(&cmd, 0, sizeof(cmd));
	cmd.cmd = ETHTOOL_GSET;
	err = dev->ethtool_ops->get_settings(dev, &cmd);
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
	if (err < 0)
		return err;

	/* we ignore deprecated fields transceiver/maxrxpkt/maxtxpkt
	 */
	convert_legacy_settings_to_link_ksettings(link_ksettings, &cmd);
	return err;
}
EXPORT_SYMBOL(__ethtool_get_link_ksettings);

/* convert ethtool_link_usettings in user space to a kernel internal
 * ethtool_link_ksettings. return 0 on success, errno on error.
 */
static int load_link_ksettings_from_user(struct ethtool_link_ksettings *to,
					 const void __user *from)
{
	struct ethtool_link_usettings link_usettings;

	if (copy_from_user(&link_usettings, from, sizeof(link_usettings)))
		return -EFAULT;

	memcpy(&to->base, &link_usettings.base, sizeof(to->base));
	bitmap_from_u32array(to->link_modes.supported,
			     __ETHTOOL_LINK_MODE_MASK_NBITS,
			     link_usettings.link_modes.supported,
			     __ETHTOOL_LINK_MODE_MASK_NU32);
	bitmap_from_u32array(to->link_modes.advertising,
			     __ETHTOOL_LINK_MODE_MASK_NBITS,
			     link_usettings.link_modes.advertising,
			     __ETHTOOL_LINK_MODE_MASK_NU32);
	bitmap_from_u32array(to->link_modes.lp_advertising,
			     __ETHTOOL_LINK_MODE_MASK_NBITS,
			     link_usettings.link_modes.lp_advertising,
			     __ETHTOOL_LINK_MODE_MASK_NU32);

	return 0;
}

/* convert a kernel internal ethtool_link_ksettings to
 * ethtool_link_usettings in user space. return 0 on success, errno on
 * error.
 */
static int
store_link_ksettings_for_user(void __user *to,
			      const struct ethtool_link_ksettings *from)
{
	struct ethtool_link_usettings link_usettings;

	memcpy(&link_usettings.base, &from->base, sizeof(link_usettings));
	bitmap_to_u32array(link_usettings.link_modes.supported,
			   __ETHTOOL_LINK_MODE_MASK_NU32,
			   from->link_modes.supported,
			   __ETHTOOL_LINK_MODE_MASK_NBITS);
	bitmap_to_u32array(link_usettings.link_modes.advertising,
			   __ETHTOOL_LINK_MODE_MASK_NU32,
			   from->link_modes.advertising,
			   __ETHTOOL_LINK_MODE_MASK_NBITS);
	bitmap_to_u32array(link_usettings.link_modes.lp_advertising,
			   __ETHTOOL_LINK_MODE_MASK_NU32,
			   from->link_modes.lp_advertising,
			   __ETHTOOL_LINK_MODE_MASK_NBITS);

	if (copy_to_user(to, &link_usettings, sizeof(link_usettings)))
		return -EFAULT;

	return 0;
}

/* Query device for its ethtool_link_settings.
 *
 * Backward compatibility note: this function must fail when driver
 * does not implement ethtool::get_link_ksettings, even if legacy
 * ethtool_ops::get_settings is implemented. This tells new versions
 * of ethtool that they should use the legacy API %ETHTOOL_GSET for
 * this driver, so that they can correctly access the ethtool_cmd
 * deprecated fields (transceiver/maxrxpkt/maxtxpkt), until no driver
 * implements ethtool_ops::get_settings anymore.
 */
static int ethtool_get_link_ksettings(struct net_device *dev,
				      void __user *useraddr)
{
	int err = 0;
	struct ethtool_link_ksettings link_ksettings;

	ASSERT_RTNL();

	if (!dev->ethtool_ops->get_link_ksettings)
		return -EOPNOTSUPP;

	/* handle bitmap nbits handshake */
	if (copy_from_user(&link_ksettings.base, useraddr,
			   sizeof(link_ksettings.base)))
		return -EFAULT;

	if (__ETHTOOL_LINK_MODE_MASK_NU32
	    != link_ksettings.base.link_mode_masks_nwords) {
		/* wrong link mode nbits requested */
		memset(&link_ksettings, 0, sizeof(link_ksettings));
666
		link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS;
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
		/* send back number of words required as negative val */
		compiletime_assert(__ETHTOOL_LINK_MODE_MASK_NU32 <= S8_MAX,
				   "need too many bits for link modes!");
		link_ksettings.base.link_mode_masks_nwords
			= -((s8)__ETHTOOL_LINK_MODE_MASK_NU32);

		/* copy the base fields back to user, not the link
		 * mode bitmaps
		 */
		if (copy_to_user(useraddr, &link_ksettings.base,
				 sizeof(link_ksettings.base)))
			return -EFAULT;

		return 0;
	}

	/* handshake successful: user/kernel agree on
	 * link_mode_masks_nwords
	 */

	memset(&link_ksettings, 0, sizeof(link_ksettings));
	err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings);
	if (err < 0)
		return err;

	/* make sure we tell the right values to user */
	link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS;
	link_ksettings.base.link_mode_masks_nwords
		= __ETHTOOL_LINK_MODE_MASK_NU32;

	return store_link_ksettings_for_user(useraddr, &link_ksettings);
}

/* Update device ethtool_link_settings.
 *
 * Backward compatibility note: this function must fail when driver
 * does not implement ethtool::set_link_ksettings, even if legacy
 * ethtool_ops::set_settings is implemented. This tells new versions
 * of ethtool that they should use the legacy API %ETHTOOL_SSET for
 * this driver, so that they can correctly update the ethtool_cmd
 * deprecated fields (transceiver/maxrxpkt/maxtxpkt), until no driver
 * implements ethtool_ops::get_settings anymore.
 */
static int ethtool_set_link_ksettings(struct net_device *dev,
				      void __user *useraddr)
{
	int err;
	struct ethtool_link_ksettings link_ksettings;

	ASSERT_RTNL();

	if (!dev->ethtool_ops->set_link_ksettings)
		return -EOPNOTSUPP;

	/* make sure nbits field has expected value */
	if (copy_from_user(&link_ksettings.base, useraddr,
			   sizeof(link_ksettings.base)))
		return -EFAULT;

	if (__ETHTOOL_LINK_MODE_MASK_NU32
	    != link_ksettings.base.link_mode_masks_nwords)
		return -EINVAL;

	/* copy the whole structure, now that we know it has expected
	 * format
	 */
	err = load_link_ksettings_from_user(&link_ksettings, useraddr);
	if (err)
		return err;

	/* re-check nwords field, just in case */
	if (__ETHTOOL_LINK_MODE_MASK_NU32
	    != link_ksettings.base.link_mode_masks_nwords)
		return -EINVAL;

	return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
}

static void
warn_incomplete_ethtool_legacy_settings_conversion(const char *details)
{
	char name[sizeof(current->comm)];

	pr_info_once("warning: `%s' uses legacy ethtool link settings API, %s\n",
		     get_task_comm(name, current), details);
}

/* Query device for its ethtool_cmd settings.
 *
 * Backward compatibility note: for compatibility with legacy ethtool,
 * this has to work with both drivers implementing get_link_ksettings
 * API and drivers implementing get_settings API. When drivers
 * implement get_link_ksettings and report higher link mode bits, a
 * kernel warning is logged once (with name of 1st driver/device) to
 * recommend user to upgrade ethtool, but the command is successful
 * (only the lower link mode bits reported back to user).
 */
764
765
766
767
static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_cmd cmd;

768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
	ASSERT_RTNL();

	if (dev->ethtool_ops->get_link_ksettings) {
		/* First, use link_ksettings API if it is supported */
		int err;
		struct ethtool_link_ksettings link_ksettings;

		memset(&link_ksettings, 0, sizeof(link_ksettings));
		err = dev->ethtool_ops->get_link_ksettings(dev,
							   &link_ksettings);
		if (err < 0)
			return err;
		if (!convert_link_ksettings_to_legacy_settings(&cmd,
							       &link_ksettings))
			warn_incomplete_ethtool_legacy_settings_conversion(
				"link modes are only partially reported");

		/* send a sensible cmd tag back to user */
		cmd.cmd = ETHTOOL_GSET;
	} else {
		/* driver doesn't support %ethtool_link_ksettings
		 * API. revert to legacy %ethtool_cmd API, unless it's
		 * not supported either.
		 */
792
793
794
795
796
797
798
799
		int err;

		if (!dev->ethtool_ops->get_settings)
			return -EOPNOTSUPP;

		memset(&cmd, 0, sizeof(cmd));
		cmd.cmd = ETHTOOL_GSET;
		err = dev->ethtool_ops->get_settings(dev, &cmd);
800
801
802
		if (err < 0)
			return err;
	}
Linus Torvalds's avatar
Linus Torvalds committed
803
804
805

	if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
		return -EFAULT;
806

Linus Torvalds's avatar
Linus Torvalds committed
807
808
809
	return 0;
}

810
811
812
813
814
815
816
817
818
819
/* Update device link settings with given ethtool_cmd.
 *
 * Backward compatibility note: for compatibility with legacy ethtool,
 * this has to work with both drivers implementing set_link_ksettings
 * API and drivers implementing set_settings API. When drivers
 * implement set_link_ksettings and user's request updates deprecated
 * ethtool_cmd fields (transceiver/maxrxpkt/maxtxpkt), a kernel
 * warning is logged once (with name of 1st driver/device) to
 * recommend user to upgrade ethtool, and the request is rejected.
 */
Linus Torvalds's avatar
Linus Torvalds committed
820
821
822
823
static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_cmd cmd;

824
	ASSERT_RTNL();
Linus Torvalds's avatar
Linus Torvalds committed
825
826
827
828

	if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
		return -EFAULT;

829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
	/* first, try new %ethtool_link_ksettings API. */
	if (dev->ethtool_ops->set_link_ksettings) {
		struct ethtool_link_ksettings link_ksettings;

		if (!convert_legacy_settings_to_link_ksettings(&link_ksettings,
							       &cmd))
			return -EINVAL;

		link_ksettings.base.cmd = ETHTOOL_SLINKSETTINGS;
		link_ksettings.base.link_mode_masks_nwords
			= __ETHTOOL_LINK_MODE_MASK_NU32;
		return dev->ethtool_ops->set_link_ksettings(dev,
							    &link_ksettings);
	}

	/* legacy %ethtool_cmd API */

	/* TODO: return -EOPNOTSUPP when ethtool_ops::get_settings
	 * disappears internally
	 */

	if (!dev->ethtool_ops->set_settings)
		return -EOPNOTSUPP;

Linus Torvalds's avatar
Linus Torvalds committed
853
854
855
	return dev->ethtool_ops->set_settings(dev, &cmd);
}

856
857
static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
						  void __user *useraddr)
Linus Torvalds's avatar
Linus Torvalds committed
858
859
{
	struct ethtool_drvinfo info;
860
	const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds's avatar
Linus Torvalds committed
861
862
863

	memset(&info, 0, sizeof(info));
	info.cmd = ETHTOOL_GDRVINFO;
864
	if (ops->get_drvinfo) {
865
866
867
868
869
870
871
872
873
		ops->get_drvinfo(dev, &info);
	} else if (dev->dev.parent && dev->dev.parent->driver) {
		strlcpy(info.bus_info, dev_name(dev->dev.parent),
			sizeof(info.bus_info));
		strlcpy(info.driver, dev->dev.parent->driver->name,
			sizeof(info.driver));
	} else {
		return -EOPNOTSUPP;
	}
Linus Torvalds's avatar
Linus Torvalds committed
874

875
876
	/*
	 * this method of obtaining string set info is deprecated;
877
	 * Use ETHTOOL_GSSET_INFO instead.
878
	 */
879
	if (ops->get_sset_count) {
880
881
882
883
884
885
886
887
		int rc;

		rc = ops->get_sset_count(dev, ETH_SS_TEST);
		if (rc >= 0)
			info.testinfo_len = rc;
		rc = ops->get_sset_count(dev, ETH_SS_STATS);
		if (rc >= 0)
			info.n_stats = rc;
888
889
890
		rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
		if (rc >= 0)
			info.n_priv_flags = rc;
891
	}
892
	if (ops->get_regs_len)
Linus Torvalds's avatar
Linus Torvalds committed
893
		info.regdump_len = ops->get_regs_len(dev);
894
	if (ops->get_eeprom_len)
Linus Torvalds's avatar
Linus Torvalds committed
895
896
897
898
899
900
901
		info.eedump_len = ops->get_eeprom_len(dev);

	if (copy_to_user(useraddr, &info, sizeof(info)))
		return -EFAULT;
	return 0;
}

Eric Dumazet's avatar
Eric Dumazet committed
902
static noinline_for_stack int ethtool_get_sset_info(struct net_device *dev,
903
						    void __user *useraddr)
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
{
	struct ethtool_sset_info info;
	u64 sset_mask;
	int i, idx = 0, n_bits = 0, ret, rc;
	u32 *info_buf = NULL;

	if (copy_from_user(&info, useraddr, sizeof(info)))
		return -EFAULT;

	/* store copy of mask, because we zero struct later on */
	sset_mask = info.sset_mask;
	if (!sset_mask)
		return 0;

	/* calculate size of return buffer */
919
	n_bits = hweight64(sset_mask);
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935

	memset(&info, 0, sizeof(info));
	info.cmd = ETHTOOL_GSSET_INFO;

	info_buf = kzalloc(n_bits * sizeof(u32), GFP_USER);
	if (!info_buf)
		return -ENOMEM;

	/*
	 * fill return buffer based on input bitmask and successful
	 * get_sset_count return
	 */
	for (i = 0; i < 64; i++) {
		if (!(sset_mask & (1ULL << i)))
			continue;

936
		rc = __ethtool_get_sset_count(dev, i);
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
		if (rc >= 0) {
			info.sset_mask |= (1ULL << i);
			info_buf[idx++] = rc;
		}
	}

	ret = -EFAULT;
	if (copy_to_user(useraddr, &info, sizeof(info)))
		goto out;

	useraddr += offsetof(struct ethtool_sset_info, data);
	if (copy_to_user(useraddr, info_buf, idx * sizeof(u32)))
		goto out;

	ret = 0;

out:
	kfree(info_buf);
	return ret;
}

958
static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
959
						u32 cmd, void __user *useraddr)
960
{
961
962
	struct ethtool_rxnfc info;
	size_t info_size = sizeof(info);
963
	int rc;
964

965
	if (!dev->ethtool_ops->set_rxnfc)
966
967
		return -EOPNOTSUPP;

968
969
970
971
972
973
974
975
976
	/* struct ethtool_rxnfc was originally defined for
	 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
	 * members.  User-space might still be using that
	 * definition. */
	if (cmd == ETHTOOL_SRXFH)
		info_size = (offsetof(struct ethtool_rxnfc, data) +
			     sizeof(info.data));

	if (copy_from_user(&info, useraddr, info_size))
977
978
		return -EFAULT;

979
980
981
982
983
984
985
986
987
	rc = dev->ethtool_ops->set_rxnfc(dev, &info);
	if (rc)
		return rc;

	if (cmd == ETHTOOL_SRXCLSRLINS &&
	    copy_to_user(useraddr, &info, info_size))
		return -EFAULT;

	return 0;
988
989
}

990
static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
991
						u32 cmd, void __user *useraddr)
992
993
{
	struct ethtool_rxnfc info;
994
	size_t info_size = sizeof(info);
995
996
997
	const struct ethtool_ops *ops = dev->ethtool_ops;
	int ret;
	void *rule_buf = NULL;
998

999
	if (!ops->get_rxnfc)
1000
1001
		return -EOPNOTSUPP;

1002
1003
1004
1005
1006
1007
1008
1009
1010
	/* struct ethtool_rxnfc was originally defined for
	 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
	 * members.  User-space might still be using that
	 * definition. */
	if (cmd == ETHTOOL_GRXFH)
		info_size = (offsetof(struct ethtool_rxnfc, data) +
			     sizeof(info.data));

	if (copy_from_user(&info, useraddr, info_size))
1011
1012
		return -EFAULT;

1013
1014
	if (info.cmd == ETHTOOL_GRXCLSRLALL) {
		if (info.rule_cnt > 0) {
1015
			if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32))
1016
				rule_buf = kzalloc(info.rule_cnt * sizeof(u32),
1017
						   GFP_USER);
1018
1019
1020
1021
			if (!rule_buf)
				return -ENOMEM;
		}
	}
1022

1023
1024
1025
1026
1027
	ret = ops->get_rxnfc(dev, &info, rule_buf);
	if (ret < 0)
		goto err_out;

	ret = -EFAULT;
1028
	if (copy_to_user(useraddr, &info, info_size))
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
		goto err_out;

	if (rule_buf) {
		useraddr += offsetof(struct ethtool_rxnfc, rule_locs);
		if (copy_to_user(useraddr, rule_buf,
				 info.rule_cnt * sizeof(u32)))
			goto err_out;
	}
	ret = 0;

err_out:
1040
	kfree(rule_buf);
1041
1042

	return ret;
1043
1044
}

1045
1046
1047
1048
static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,
					struct ethtool_rxnfc *rx_rings,
					u32 size)
{
1049
	int i;
1050
1051

	if (copy_from_user(indir, useraddr, size * sizeof(indir[0])))
1052
		return -EFAULT;
1053
1054

	/* Validate ring indices */
1055
1056
1057
1058
1059
	for (i = 0; i < size; i++)
		if (indir[i] >= rx_rings->data)
			return -EINVAL;

	return 0;
1060
1061
}

1062
u8 netdev_rss_key[NETDEV_RSS_KEY_LEN] __read_mostly;
1063
1064
1065
1066
1067
1068
1069
1070
1071

void netdev_rss_key_fill(void *buffer, size_t len)
{
	BUG_ON(len > sizeof(netdev_rss_key));
	net_get_random_once(netdev_rss_key, sizeof(netdev_rss_key));
	memcpy(buffer, netdev_rss_key, len);
}
EXPORT_SYMBOL(netdev_rss_key_fill);

1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
static int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max)
{
	u32 dev_size, current_max = 0;
	u32 *indir;
	int ret;

	if (!dev->ethtool_ops->get_rxfh_indir_size ||
	    !dev->ethtool_ops->get_rxfh)
		return -EOPNOTSUPP;
	dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
	if (dev_size == 0)
		return -EOPNOTSUPP;

	indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
	if (!indir)
		return -ENOMEM;

	ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL);
	if (ret)
		goto out;

	while (dev_size--)
		current_max = max(current_max, indir[dev_size]);

	*max = current_max;

out:
	kfree(indir);
	return ret;
}

1103
1104
1105
static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
						     void __user *useraddr)
{
1106
1107
	u32 user_size, dev_size;
	u32 *indir;
1108
1109
	int ret;

1110
	if (!dev->ethtool_ops->get_rxfh_indir_size ||
1111
	    !dev->ethtool_ops->get_rxfh)
1112
1113
1114
		return -EOPNOTSUPP;
	dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
	if (dev_size == 0)
1115
1116
		return -EOPNOTSUPP;

1117
	if (copy_from_user(&user_size,
1118
			   useraddr + offsetof(struct ethtool_rxfh_indir, size),
1119
			   sizeof(user_size)))
1120
1121
		return -EFAULT;

1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
	if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh_indir, size),
			 &dev_size, sizeof(dev_size)))
		return -EFAULT;

	/* If the user buffer size is 0, this is just a query for the
	 * device table size.  Otherwise, if it's smaller than the
	 * device table size it's an error.
	 */
	if (user_size < dev_size)
		return user_size == 0 ? 0 : -EINVAL;

	indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
1134
1135
1136
	if (!indir)
		return -ENOMEM;

1137
	ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL);
1138
1139
1140
	if (ret)
		goto out;

1141
1142
1143
	if (copy_to_user(useraddr +
			 offsetof(struct ethtool_rxfh_indir, ring_index[0]),
			 indir, dev_size * sizeof(indir[0])))
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
		ret = -EFAULT;

out:
	kfree(indir);
	return ret;
}

static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
						     void __user *useraddr)
{
1154
1155
1156
	struct ethtool_rxnfc rx_rings;
	u32 user_size, dev_size, i;
	u32 *indir;
1157
	const struct ethtool_ops *ops = dev->ethtool_ops;
1158
	int ret;
1159
	u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]);
1160

1161
	if (!ops->get_rxfh_indir_size || !ops->set_rxfh ||
1162
	    !ops->get_rxnfc)
1163
		return -EOPNOTSUPP;
1164
1165

	dev_size = ops->get_rxfh_indir_size(dev);
1166
	if (dev_size == 0)
1167
1168
		return -EOPNOTSUPP;

1169
	if (copy_from_user(&user_size,
1170
			   useraddr + offsetof(struct ethtool_rxfh_indir, size),
1171
			   sizeof(user_size)))
1172
1173
		return -EFAULT;

1174
	if (user_size != 0 && user_size != dev_size)
1175
1176
1177
		return -EINVAL;

	indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
1178
1179
1180
	if (!indir)
		return -ENOMEM;

1181
	rx_rings.cmd = ETHTOOL_GRXRINGS;
1182
	ret = ops->get_rxnfc(dev, &rx_rings, NULL);
1183
1184
	if (ret)
		goto out;
1185
1186
1187
1188
1189

	if (user_size == 0) {
		for (i = 0; i < dev_size; i++)
			indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
	} else {
1190
1191
1192
1193
1194
1195
1196
1197
		ret = ethtool_copy_validate_indir(indir,
						  useraddr + ringidx_offset,
						  &rx_rings,
						  dev_size);
		if (ret)
			goto out;
	}

1198
	ret = ops->set_rxfh(dev, indir, NULL, ETH_RSS_HASH_NO_CHANGE);
1199
1200
1201
1202
1203
1204
1205
1206
	if (ret)
		goto out;

	/* indicate whether rxfh was set to default */
	if (user_size == 0)
		dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
	else
		dev->priv_flags |= IFF_RXFH_CONFIGURED;
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217

out:
	kfree(indir);
	return ret;
}

static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
					       void __user *useraddr)
{
	int ret;
	const struct ethtool_ops *ops = dev->ethtool_ops;
1218
	u32 user_indir_size, user_key_size;
1219
	u32 dev_indir_size = 0, dev_key_size = 0;
1220
	struct ethtool_rxfh rxfh;
1221
	u32 total_size;
1222
	u32 indir_bytes;
1223
	u32 *indir = NULL;
1224
	u8 dev_hfunc = 0;
1225
1226
1227
	u8 *hkey = NULL;
	u8 *rss_config;

1228
	if (!ops->get_rxfh)
1229
1230
1231
1232
1233
1234
1235
		return -EOPNOTSUPP;

	if (ops->get_rxfh_indir_size)
		dev_indir_size = ops->get_rxfh_indir_size(dev);
	if (ops->get_rxfh_key_size)
		dev_key_size = ops->get_rxfh_key_size(dev);

1236
	if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
1237
		return -EFAULT;
1238
1239
	user_indir_size = rxfh.indir_size;
	user_key_size = rxfh.key_size;
1240

1241
	/* Check that reserved fields are 0 for now */
1242
1243
	if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] ||
	    rxfh.rsvd8[2] || rxfh.rsvd32)
1244
1245
1246
1247
1248
		return -EINVAL;

	rxfh.indir_size = dev_indir_size;
	rxfh.key_size = dev_key_size;
	if (copy_to_user(useraddr, &rxfh, sizeof(rxfh)))
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
		return -EFAULT;

	if ((user_indir_size && (user_indir_size != dev_indir_size)) ||
	    (user_key_size && (user_key_size != dev_key_size)))
		return -EINVAL;

	indir_bytes = user_indir_size * sizeof(indir[0]);
	total_size = indir_bytes + user_key_size;
	rss_config = kzalloc(total_size, GFP_USER);
	if (!rss_config)
		return -ENOMEM;

	if (user_indir_size)
		indir = (u32 *)rss_config;

	if (user_key_size)
		hkey = rss_config + indir_bytes;

1267
1268
1269
	ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc);
	if (ret)
		goto out;
1270

1271
1272
1273
1274
1275
1276
1277
1278
1279
	if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, hfunc),
			 &dev_hfunc, sizeof(rxfh.hfunc))) {
		ret = -EFAULT;
	} else if (copy_to_user(useraddr +
			      offsetof(struct ethtool_rxfh, rss_config[0]),
			      rss_config, total_size)) {
		ret = -EFAULT;
	}
out:
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
	kfree(rss_config);

	return ret;
}

static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
					       void __user *useraddr)
{
	int ret;
	const struct ethtool_ops *ops = dev->ethtool_ops;
	struct ethtool_rxnfc rx_rings;
1291
1292
	struct ethtool_rxfh rxfh;
	u32 dev_indir_size = 0, dev_key_size = 0, i;
1293
1294
1295
1296
1297
	u32 *indir = NULL, indir_bytes = 0;
	u8 *hkey = NULL;
	u8 *rss_config;
	u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);

1298
	if (!ops->get_rxnfc || !ops->set_rxfh)
1299
1300
1301
1302
1303
		return -EOPNOTSUPP;

	if (ops->get_rxfh_indir_size)
		dev_indir_size = ops->get_rxfh_indir_size(dev);
	if (ops->get_rxfh_key_size)
1304
		dev_key_size = ops->get_rxfh_key_size(dev);
1305

1306
	if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
1307
1308
		return -EFAULT;

1309
	/* Check that reserved fields are 0 for now */
1310
1311
	if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] ||
	    rxfh.rsvd8[2] || rxfh.rsvd32)
1312
1313
		return -EINVAL;

1314
1315
	/* If either indir, hash key or function is valid, proceed further.
	 * Must request at least one change: indir size, hash key or function.
1316
	 */
1317
1318
1319
1320
1321
	if ((rxfh.indir_size &&
	     rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE &&
	     rxfh.indir_size != dev_indir_size) ||
	    (rxfh.key_size && (rxfh.key_size != dev_key_size)) ||
	    (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE &&
1322
	     rxfh.key_size == 0 && rxfh.hfunc == ETH_RSS_HASH_NO_CHANGE))
1323
1324
		return -EINVAL;

1325
	if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
1326
1327
		indir_bytes = dev_indir_size * sizeof(indir[0]);

1328
	rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER);
1329
1330
1331
1332
1333
1334
1335
1336
	if (!rss_config)
		return -ENOMEM;

	rx_rings.cmd = ETHTOOL_GRXRINGS;
	ret = ops->get_rxnfc(dev, &rx_rings, NULL);
	if (ret)
		goto out;

1337
1338
	/* rxfh.indir_size == 0 means reset the indir table to default.
	 * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged.
1339
	 */
1340
1341
	if (rxfh.indir_size &&
	    rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) {
1342
1343
1344
1345
		indir = (u32 *)rss_config;
		ret = ethtool_copy_validate_indir(indir,
						  useraddr + rss_cfg_offset,
						  &rx_rings,
1346
						  rxfh.indir_size);
1347
		if (ret)
1348
			goto out;
1349
	} else if (rxfh.indir_size == 0) {
1350
1351
1352
1353
		indir = (u32 *)rss_config;
		for (i = 0; i < dev_indir_size; i++)
			indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
	}
1354

1355
	if (rxfh.key_size) {
1356
1357
1358
		hkey = rss_config + indir_bytes;
		if (copy_from_user(hkey,
				   useraddr + rss_cfg_offset + indir_bytes,
1359
				   rxfh.key_size)) {
1360
1361
			ret = -EFAULT;
			goto out;
1362
		}
1363
1364
	}

1365
	ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc);
1366
1367
1368
1369
1370
1371
1372
1373
	if (ret)
		goto out;

	/* indicate whether rxfh was set to default */
	if (rxfh.indir_size == 0)
		dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
	else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
		dev->priv_flags |= IFF_RXFH_CONFIGURED;
1374
1375

out:
1376
	kfree(rss_config);
1377
1378
1379
	return ret;
}

Linus Torvalds's avatar
Linus Torvalds committed
1380
1381
1382
static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
{
	struct ethtool_regs regs;
1383
	const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds's avatar
Linus Torvalds committed
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
	void *regbuf;
	int reglen, ret;

	if (!ops->get_regs || !ops->get_regs_len)
		return -EOPNOTSUPP;

	if (copy_from_user(&regs, useraddr, sizeof(regs)))
		return -EFAULT;

	reglen = ops->get_regs_len(dev);
	if (regs.len > reglen)
		regs.len = reglen;

1397
	regbuf = vzalloc(reglen);
1398
	if (reglen && !regbuf)
Linus Torvalds's avatar
Linus Torvalds committed
1399
1400
1401
1402
1403
1404
1405
1406
		return -ENOMEM;

	ops->get_regs(dev, &regs, regbuf);

	ret = -EFAULT;
	if (copy_to_user(useraddr, &regs, sizeof(regs)))
		goto out;
	useraddr += offsetof(struct ethtool_regs, data);
1407
	if (regbuf && copy_to_user(useraddr, regbuf, regs.len))
Linus Torvalds's avatar
Linus Torvalds committed
1408
1409
1410
1411
		goto out;
	ret = 0;

 out:
1412
	vfree(regbuf);
Linus Torvalds's avatar
Linus Torvalds committed
1413
1414
1415
	return ret;
}

Ben Hutchings's avatar
Ben Hutchings committed
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
static int ethtool_reset(struct net_device *dev, char __user *useraddr)
{
	struct ethtool_value reset;
	int ret;

	if (!dev->ethtool_ops->reset)
		return -EOPNOTSUPP;

	if (copy_from_user(&reset, useraddr, sizeof(reset)))
		return -EFAULT;

	ret = dev->ethtool_ops->reset(dev, &reset.data);
	if (ret)
		return ret;

	if (copy_to_user(useraddr, &reset, sizeof(reset)))
		return -EFAULT;
	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
1436
1437
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
{
1438
	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
Linus Torvalds's avatar
Linus Torvalds committed
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462

	if (!dev->ethtool_ops->get_wol)
		return -EOPNOTSUPP;

	dev->ethtool_ops->get_wol(dev, &wol);

	if (