ethtool.c 35.9 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
#include <linux/bitops.h>
21
#include <linux/uaccess.h>
22
#include <linux/vmalloc.h>
23
#include <linux/slab.h>
24
25
#include <linux/rtnetlink.h>
#include <linux/sched.h>
Linus Torvalds's avatar
Linus Torvalds committed
26

27
/*
Linus Torvalds's avatar
Linus Torvalds committed
28
29
30
31
32
33
34
35
36
 * 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;
}
37
EXPORT_SYMBOL(ethtool_op_get_link);
Linus Torvalds's avatar
Linus Torvalds committed
38
39
40

/* Handlers for each ethtool command */

41
#define ETHTOOL_DEV_FEATURE_WORDS	((NETDEV_FEATURE_COUNT + 31) / 32)
42

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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",
	[NETIF_F_HW_VLAN_TX_BIT] =       "tx-vlan-hw-insert",

	[NETIF_F_HW_VLAN_RX_BIT] =       "rx-vlan-hw-parse",
	[NETIF_F_HW_VLAN_FILTER_BIT] =   "rx-vlan-filter",
	[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",
	[NETIF_F_TSO6_BIT] =             "tx-tcp6-segmentation",
	[NETIF_F_FSO_BIT] =              "tx-fcoe-segmentation",

	[NETIF_F_FCOE_CRC_BIT] =         "tx-checksum-fcoe-crc",
	[NETIF_F_SCTP_CSUM_BIT] =        "tx-checksum-sctp",
	[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",
};

78
79
80
81
82
83
static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_gfeatures cmd = {
		.cmd = ETHTOOL_GFEATURES,
		.size = ETHTOOL_DEV_FEATURE_WORDS,
	};
84
	struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
85
86
	u32 __user *sizeaddr;
	u32 copy_size;
87
88
89
	int i;

	/* in case feature bits run out again */
90
	BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > sizeof(netdev_features_t));
91
92

	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
93
94
95
96
97
		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));
98
	}
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

	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];
120
121
	netdev_features_t wanted = 0, valid = 0;
	int i, ret = 0;
122
123
124
125
126
127
128
129
130
131
132

	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;

133
	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
134
135
		valid |= (netdev_features_t)features[i].valid << (32 * i);
		wanted |= (netdev_features_t)features[i].requested << (32 * i);
136
137
138
	}

	if (valid & ~NETIF_F_ETHTOOL_BITS)
139
140
		return -EINVAL;

141
142
	if (valid & ~dev->hw_features) {
		valid &= dev->hw_features;
143
144
145
		ret |= ETHTOOL_F_UNSUPPORTED;
	}

146
147
	dev->wanted_features &= ~valid;
	dev->wanted_features |= wanted & valid;
148
	__netdev_update_features(dev);
149

150
	if ((dev->wanted_features ^ dev->features) & valid)
151
152
153
154
155
		ret |= ETHTOOL_F_WISH;

	return ret;
}

156
157
158
159
static int __ethtool_get_sset_count(struct net_device *dev, int sset)
{
	const struct ethtool_ops *ops = dev->ethtool_ops;

160
161
162
	if (sset == ETH_SS_FEATURES)
		return ARRAY_SIZE(netdev_features_strings);

163
164
165
166
167
168
169
170
171
172
173
	if (ops && ops->get_sset_count && ops->get_strings)
		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;

174
175
176
177
178
179
	if (stringset == ETH_SS_FEATURES)
		memcpy(data, netdev_features_strings,
			sizeof(netdev_features_strings));
	else
		/* ops->get_strings is valid because checked earlier */
		ops->get_strings(dev, stringset, data);
180
181
}

182
static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd)
183
184
185
186
187
188
189
{
	/* feature masks of legacy discrete ethtool ops */

	switch (eth_cmd) {
	case ETHTOOL_GTXCSUM:
	case ETHTOOL_STXCSUM:
		return NETIF_F_ALL_CSUM | NETIF_F_SCTP_CSUM;
190
191
192
	case ETHTOOL_GRXCSUM:
	case ETHTOOL_SRXCSUM:
		return NETIF_F_RXCSUM;
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
	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)
{
216
	netdev_features_t mask = ethtool_get_feature_mask(ethcmd);
217
218
	struct ethtool_value edata = {
		.cmd = ethcmd,
219
		.data = !!(dev->features & mask),
220
221
222
223
224
225
226
227
228
229
230
	};

	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;
231
	netdev_features_t mask;
232
233
234
235

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

236
237
	mask = ethtool_get_feature_mask(ethcmd);
	mask &= dev->hw_features;
238
239
	if (!mask)
		return -EOPNOTSUPP;
240

241
242
243
244
	if (edata.data)
		dev->wanted_features |= mask;
	else
		dev->wanted_features &= ~mask;
245

246
	__netdev_update_features(dev);
247

248
249
250
	return 0;
}

251
252
253
254
#define ETH_ALL_FLAGS    (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \
			  ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH)
#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_RX | \
			  NETIF_F_HW_VLAN_TX | NETIF_F_NTUPLE | NETIF_F_RXHASH)
255
256
257

static u32 __ethtool_get_flags(struct net_device *dev)
{
258
259
260
261
262
263
264
265
266
	u32 flags = 0;

	if (dev->features & NETIF_F_LRO)	flags |= ETH_FLAG_LRO;
	if (dev->features & NETIF_F_HW_VLAN_RX)	flags |= ETH_FLAG_RXVLAN;
	if (dev->features & NETIF_F_HW_VLAN_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;

	return flags;
267
268
}

269
static int __ethtool_set_flags(struct net_device *dev, u32 data)
270
{
271
	netdev_features_t features = 0, changed;
272

273
	if (data & ~ETH_ALL_FLAGS)
274
275
		return -EINVAL;

276
277
278
279
280
281
	if (data & ETH_FLAG_LRO)	features |= NETIF_F_LRO;
	if (data & ETH_FLAG_RXVLAN)	features |= NETIF_F_HW_VLAN_RX;
	if (data & ETH_FLAG_TXVLAN)	features |= NETIF_F_HW_VLAN_TX;
	if (data & ETH_FLAG_NTUPLE)	features |= NETIF_F_NTUPLE;
	if (data & ETH_FLAG_RXHASH)	features |= NETIF_F_RXHASH;

282
	/* allow changing only bits set in hw_features */
283
	changed = (features ^ dev->features) & ETH_ALL_FEATURES;
284
285
286
287
	if (changed & ~dev->hw_features)
		return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;

	dev->wanted_features =
288
		(dev->wanted_features & ~changed) | (features & changed);
289

290
	__netdev_update_features(dev);
291
292
293
294

	return 0;
}

295
int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds's avatar
Linus Torvalds committed
296
{
297
	ASSERT_RTNL();
Linus Torvalds's avatar
Linus Torvalds committed
298

299
	if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
Linus Torvalds's avatar
Linus Torvalds committed
300
301
		return -EOPNOTSUPP;

302
303
304
305
306
307
308
309
310
311
312
313
	memset(cmd, 0, sizeof(struct ethtool_cmd));
	cmd->cmd = ETHTOOL_GSET;
	return dev->ethtool_ops->get_settings(dev, cmd);
}
EXPORT_SYMBOL(__ethtool_get_settings);

static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
{
	int err;
	struct ethtool_cmd cmd;

	err = __ethtool_get_settings(dev, &cmd);
Linus Torvalds's avatar
Linus Torvalds committed
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
	if (err < 0)
		return err;

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

static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_cmd cmd;

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

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

	return dev->ethtool_ops->set_settings(dev, &cmd);
}

335
336
static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
						  void __user *useraddr)
Linus Torvalds's avatar
Linus Torvalds committed
337
338
{
	struct ethtool_drvinfo info;
339
	const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds's avatar
Linus Torvalds committed
340
341
342

	memset(&info, 0, sizeof(info));
	info.cmd = ETHTOOL_GDRVINFO;
343
344
345
346
347
348
349
350
351
352
	if (ops && ops->get_drvinfo) {
		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
353

354
355
	/*
	 * this method of obtaining string set info is deprecated;
356
	 * Use ETHTOOL_GSSET_INFO instead.
357
	 */
358
	if (ops && ops->get_sset_count) {
359
360
361
362
363
364
365
366
		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;
367
368
369
		rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
		if (rc >= 0)
			info.n_priv_flags = rc;
370
	}
371
	if (ops && ops->get_regs_len)
Linus Torvalds's avatar
Linus Torvalds committed
372
		info.regdump_len = ops->get_regs_len(dev);
373
	if (ops && ops->get_eeprom_len)
Linus Torvalds's avatar
Linus Torvalds committed
374
375
376
377
378
379
380
		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
381
static noinline_for_stack int ethtool_get_sset_info(struct net_device *dev,
382
						    void __user *useraddr)
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
{
	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 */
398
	n_bits = hweight64(sset_mask);
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414

	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;

415
		rc = __ethtool_get_sset_count(dev, i);
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
		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;
}

437
static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
438
						u32 cmd, void __user *useraddr)
439
{
440
441
	struct ethtool_rxnfc info;
	size_t info_size = sizeof(info);
442
	int rc;
443

444
	if (!dev->ethtool_ops->set_rxnfc)
445
446
		return -EOPNOTSUPP;

447
448
449
450
451
452
453
454
455
	/* 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))
456
457
		return -EFAULT;

458
459
460
461
462
463
464
465
466
	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;
467
468
}

469
static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
470
						u32 cmd, void __user *useraddr)
471
472
{
	struct ethtool_rxnfc info;
473
	size_t info_size = sizeof(info);
474
475
476
	const struct ethtool_ops *ops = dev->ethtool_ops;
	int ret;
	void *rule_buf = NULL;
477

478
	if (!ops->get_rxnfc)
479
480
		return -EOPNOTSUPP;

481
482
483
484
485
486
487
488
489
	/* 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))
490
491
		return -EFAULT;

492
493
	if (info.cmd == ETHTOOL_GRXCLSRLALL) {
		if (info.rule_cnt > 0) {
494
			if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32))
495
				rule_buf = kzalloc(info.rule_cnt * sizeof(u32),
496
						   GFP_USER);
497
498
499
500
			if (!rule_buf)
				return -ENOMEM;
		}
	}
501

502
503
504
505
506
	ret = ops->get_rxnfc(dev, &info, rule_buf);
	if (ret < 0)
		goto err_out;

	ret = -EFAULT;
507
	if (copy_to_user(useraddr, &info, info_size))
508
509
510
511
512
513
514
515
516
517
518
		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:
519
	kfree(rule_buf);
520
521

	return ret;
522
523
}

524
525
526
static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
						     void __user *useraddr)
{
527
528
	u32 user_size, dev_size;
	u32 *indir;
529
530
	int ret;

531
532
533
534
535
	if (!dev->ethtool_ops->get_rxfh_indir_size ||
	    !dev->ethtool_ops->get_rxfh_indir)
		return -EOPNOTSUPP;
	dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
	if (dev_size == 0)
536
537
		return -EOPNOTSUPP;

538
	if (copy_from_user(&user_size,
539
			   useraddr + offsetof(struct ethtool_rxfh_indir, size),
540
			   sizeof(user_size)))
541
542
		return -EFAULT;

543
544
545
546
547
548
549
550
551
552
553
554
	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);
555
556
557
558
559
560
561
	if (!indir)
		return -ENOMEM;

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

562
563
564
	if (copy_to_user(useraddr +
			 offsetof(struct ethtool_rxfh_indir, ring_index[0]),
			 indir, dev_size * sizeof(indir[0])))
565
566
567
568
569
570
571
572
573
574
		ret = -EFAULT;

out:
	kfree(indir);
	return ret;
}

static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
						     void __user *useraddr)
{
575
576
577
	struct ethtool_rxnfc rx_rings;
	u32 user_size, dev_size, i;
	u32 *indir;
578
579
	int ret;

580
581
582
583
584
585
	if (!dev->ethtool_ops->get_rxfh_indir_size ||
	    !dev->ethtool_ops->set_rxfh_indir ||
	    !dev->ethtool_ops->get_rxnfc)
		return -EOPNOTSUPP;
	dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
	if (dev_size == 0)
586
587
		return -EOPNOTSUPP;

588
	if (copy_from_user(&user_size,
589
			   useraddr + offsetof(struct ethtool_rxfh_indir, size),
590
			   sizeof(user_size)))
591
592
		return -EFAULT;

593
	if (user_size != 0 && user_size != dev_size)
594
595
596
		return -EINVAL;

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

600
601
602
603
	rx_rings.cmd = ETHTOOL_GRXRINGS;
	ret = dev->ethtool_ops->get_rxnfc(dev, &rx_rings, NULL);
	if (ret)
		goto out;
604
605
606
607
608
609
610
611
612
613
614

	if (user_size == 0) {
		for (i = 0; i < dev_size; i++)
			indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
	} else {
		if (copy_from_user(indir,
				  useraddr +
				  offsetof(struct ethtool_rxfh_indir,
					   ring_index[0]),
				  dev_size * sizeof(indir[0]))) {
			ret = -EFAULT;
615
616
			goto out;
		}
617
618
619
620
621
622
623
624

		/* Validate ring indices */
		for (i = 0; i < dev_size; i++) {
			if (indir[i] >= rx_rings.data) {
				ret = -EINVAL;
				goto out;
			}
		}
625
626
	}

627
628
629
630
631
632
633
	ret = dev->ethtool_ops->set_rxfh_indir(dev, indir);

out:
	kfree(indir);
	return ret;
}

Linus Torvalds's avatar
Linus Torvalds committed
634
635
636
static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
{
	struct ethtool_regs regs;
637
	const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds's avatar
Linus Torvalds committed
638
639
640
641
642
643
644
645
646
647
648
649
650
	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;

651
	regbuf = vzalloc(reglen);
652
	if (reglen && !regbuf)
Linus Torvalds's avatar
Linus Torvalds committed
653
654
655
656
657
658
659
660
		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);
661
	if (regbuf && copy_to_user(useraddr, regbuf, regs.len))
Linus Torvalds's avatar
Linus Torvalds committed
662
663
664
665
		goto out;
	ret = 0;

 out:
666
	vfree(regbuf);
Linus Torvalds's avatar
Linus Torvalds committed
667
668
669
	return ret;
}

Ben Hutchings's avatar
Ben Hutchings committed
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
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
690
691
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
{
692
	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
Linus Torvalds's avatar
Linus Torvalds committed
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

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

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

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

static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
{
	struct ethtool_wolinfo wol;

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

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

	return dev->ethtool_ops->set_wol(dev, &wol);
}

static int ethtool_nway_reset(struct net_device *dev)
{
	if (!dev->ethtool_ops->nway_reset)
		return -EOPNOTSUPP;

	return dev->ethtool_ops->nway_reset(dev);
}

725
726
727
728
729
730
731
732
733
734
735
736
737
738
static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
{
	struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };

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

	edata.data = netif_running(dev) && dev->ethtool_ops->get_link(dev);

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

Linus Torvalds's avatar
Linus Torvalds committed
739
740
741
static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_eeprom eeprom;
742
	const struct ethtool_ops *ops = dev->ethtool_ops;
743
744
	void __user *userbuf = useraddr + sizeof(eeprom);
	u32 bytes_remaining;
Linus Torvalds's avatar
Linus Torvalds committed
745
	u8 *data;
746
	int ret = 0;
Linus Torvalds's avatar
Linus Torvalds committed
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761

	if (!ops->get_eeprom || !ops->get_eeprom_len)
		return -EOPNOTSUPP;

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

	/* Check for wrap and zero */
	if (eeprom.offset + eeprom.len <= eeprom.offset)
		return -EINVAL;

	/* Check for exceeding total eeprom len */
	if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
		return -EINVAL;

762
	data = kmalloc(PAGE_SIZE, GFP_USER);
Linus Torvalds's avatar
Linus Torvalds committed
763
764
765
	if (!data)
		return -ENOMEM;

766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
	bytes_remaining = eeprom.len;
	while (bytes_remaining > 0) {
		eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);

		ret = ops->get_eeprom(dev, &eeprom, data);
		if (ret)
			break;
		if (copy_to_user(userbuf, data, eeprom.len)) {
			ret = -EFAULT;
			break;
		}
		userbuf += eeprom.len;
		eeprom.offset += eeprom.len;
		bytes_remaining -= eeprom.len;
	}
Linus Torvalds's avatar
Linus Torvalds committed
781

782
783
784
785
786
	eeprom.len = userbuf - (useraddr + sizeof(eeprom));
	eeprom.offset -= eeprom.len;
	if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
		ret = -EFAULT;

Linus Torvalds's avatar
Linus Torvalds committed
787
788
789
790
791
792
793
	kfree(data);
	return ret;
}

static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_eeprom eeprom;
794
	const struct ethtool_ops *ops = dev->ethtool_ops;
795
796
	void __user *userbuf = useraddr + sizeof(eeprom);
	u32 bytes_remaining;
Linus Torvalds's avatar
Linus Torvalds committed
797
	u8 *data;
798
	int ret = 0;
Linus Torvalds's avatar
Linus Torvalds committed
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813

	if (!ops->set_eeprom || !ops->get_eeprom_len)
		return -EOPNOTSUPP;

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

	/* Check for wrap and zero */
	if (eeprom.offset + eeprom.len <= eeprom.offset)
		return -EINVAL;

	/* Check for exceeding total eeprom len */
	if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
		return -EINVAL;

814
	data = kmalloc(PAGE_SIZE, GFP_USER);
Linus Torvalds's avatar
Linus Torvalds committed
815
816
817
	if (!data)
		return -ENOMEM;

818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
	bytes_remaining = eeprom.len;
	while (bytes_remaining > 0) {
		eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);

		if (copy_from_user(data, userbuf, eeprom.len)) {
			ret = -EFAULT;
			break;
		}
		ret = ops->set_eeprom(dev, &eeprom, data);
		if (ret)
			break;
		userbuf += eeprom.len;
		eeprom.offset += eeprom.len;
		bytes_remaining -= eeprom.len;
	}
Linus Torvalds's avatar
Linus Torvalds committed
833
834
835
836
837

	kfree(data);
	return ret;
}

838
839
static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev,
						   void __user *useraddr)
Linus Torvalds's avatar
Linus Torvalds committed
840
{
841
	struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
Linus Torvalds's avatar
Linus Torvalds committed
842
843
844
845
846
847
848
849
850
851
852

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

	dev->ethtool_ops->get_coalesce(dev, &coalesce);

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

853
854
static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
						   void __user *useraddr)
Linus Torvalds's avatar
Linus Torvalds committed
855
856
857
{
	struct ethtool_coalesce coalesce;

858
	if (!dev->ethtool_ops->set_coalesce)
Linus Torvalds's avatar
Linus Torvalds committed
859
860
861
862
863
864
865
866
867
868
		return -EOPNOTSUPP;

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

	return dev->ethtool_ops->set_coalesce(dev, &coalesce);
}

static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
{
869
	struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM };
Linus Torvalds's avatar
Linus Torvalds committed
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893

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

	dev->ethtool_ops->get_ringparam(dev, &ringparam);

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

static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_ringparam ringparam;

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

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

	return dev->ethtool_ops->set_ringparam(dev, &ringparam);
}

894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
static noinline_for_stack int ethtool_get_channels(struct net_device *dev,
						   void __user *useraddr)
{
	struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };

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

	dev->ethtool_ops->get_channels(dev, &channels);

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

static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
						   void __user *useraddr)
{
	struct ethtool_channels channels;

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

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

	return dev->ethtool_ops->set_channels(dev, &channels);
}

Linus Torvalds's avatar
Linus Torvalds committed
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };

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

	dev->ethtool_ops->get_pauseparam(dev, &pauseparam);

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

static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_pauseparam pauseparam;

941
	if (!dev->ethtool_ops->set_pauseparam)
Linus Torvalds's avatar
Linus Torvalds committed
942
943
944
945
946
947
948
949
950
951
952
		return -EOPNOTSUPP;

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

	return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
}

static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
{
	struct ethtool_test test;
953
	const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds's avatar
Linus Torvalds committed
954
	u64 *data;
955
	int ret, test_len;
Linus Torvalds's avatar
Linus Torvalds committed
956

957
	if (!ops->self_test || !ops->get_sset_count)
Linus Torvalds's avatar
Linus Torvalds committed
958
959
		return -EOPNOTSUPP;

960
	test_len = ops->get_sset_count(dev, ETH_SS_TEST);
961
962
963
964
	if (test_len < 0)
		return test_len;
	WARN_ON(test_len == 0);

Linus Torvalds's avatar
Linus Torvalds committed
965
966
967
	if (copy_from_user(&test, useraddr, sizeof(test)))
		return -EFAULT;

968
969
	test.len = test_len;
	data = kmalloc(test_len * sizeof(u64), GFP_USER);
Linus Torvalds's avatar
Linus Torvalds committed
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
	if (!data)
		return -ENOMEM;

	ops->self_test(dev, &test, data);

	ret = -EFAULT;
	if (copy_to_user(useraddr, &test, sizeof(test)))
		goto out;
	useraddr += sizeof(test);
	if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
		goto out;
	ret = 0;

 out:
	kfree(data);
	return ret;
}

static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_gstrings gstrings;
	u8 *data;
	int ret;

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

997
	ret = __ethtool_get_sset_count(dev, gstrings.string_set);
998
999
1000
1001
	if (ret < 0)
		return ret;

	gstrings.len = ret;
Linus Torvalds's avatar
Linus Torvalds committed
1002
1003
1004
1005
1006

	data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
	if (!data)
		return -ENOMEM;

1007
	__ethtool_get_strings(dev, gstrings.string_set, data);
Linus Torvalds's avatar
Linus Torvalds committed
1008
1009
1010
1011
1012
1013
1014
1015
1016

	ret = -EFAULT;
	if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
		goto out;
	useraddr += sizeof(gstrings);
	if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
		goto out;
	ret = 0;

1017
out:
Linus Torvalds's avatar
Linus Torvalds committed
1018
1019
1020
1021
1022
1023
1024
	kfree(data);
	return ret;
}

static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_value id;
1025
1026
	static bool busy;
	int rc;
Linus Torvalds's avatar
Linus Torvalds committed
1027

1028
	if (!dev->ethtool_ops->set_phys_id)
Linus Torvalds's avatar
Linus Torvalds committed
1029
1030
		return -EOPNOTSUPP;

1031
1032
1033
	if (busy)
		return -EBUSY;

Linus Torvalds's avatar
Linus Torvalds committed
1034
1035
1036
	if (copy_from_user(&id, useraddr, sizeof(id)))
		return -EFAULT;

1037
	rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE);
1038
	if (rc < 0)
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
		return rc;

	/* Drop the RTNL lock while waiting, but prevent reentry or
	 * removal of the device.
	 */
	busy = true;
	dev_hold(dev);
	rtnl_unlock();

	if (rc == 0) {
		/* Driver will handle this itself */
		schedule_timeout_interruptible(
1051
			id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT);
1052
	} else {
1053
1054
1055
1056
		/* Driver expects to be called at twice the frequency in rc */
		int n = rc * 2, i, interval = HZ / n;

		/* Count down seconds */
1057
		do {
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
			/* Count down iterations per second */
			i = n;
			do {
				rtnl_lock();
				rc = dev->ethtool_ops->set_phys_id(dev,
				    (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
				rtnl_unlock();
				if (rc)
					break;
				schedule_timeout_interruptible(interval);
			} while (!signal_pending(current) && --i != 0);
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
		} while (!signal_pending(current) &&
			 (id.data == 0 || --id.data != 0));
	}

	rtnl_lock();
	dev_put(dev);
	busy = false;

	(void)dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
	return rc;
Linus Torvalds's avatar
Linus Torvalds committed
1079
1080
1081
1082
1083
}

static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_stats stats;
1084
	const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds's avatar
Linus Torvalds committed
1085
	u64 *data;
1086
	int ret, n_stats;
Linus Torvalds's avatar
Linus Torvalds committed
1087

1088
	if (!ops->get_ethtool_stats || !ops->get_sset_count)
Linus Torvalds's avatar
Linus Torvalds committed
1089
1090
		return -EOPNOTSUPP;

1091
	n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
1092
1093
1094
1095
	if (n_stats < 0)
		return n_stats;
	WARN_ON(n_stats == 0);

Linus Torvalds's avatar
Linus Torvalds committed
1096
1097
1098
	if (copy_from_user(&stats, useraddr, sizeof(stats)))
		return -EFAULT;

1099
1100
	stats.n_stats = n_stats;
	data = kmalloc(n_stats * sizeof(u64), GFP_USER);
Linus Torvalds's avatar
Linus Torvalds committed
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
	if (!data)
		return -ENOMEM;

	ops->get_ethtool_stats(dev, &stats, data);

	ret = -EFAULT;
	if (copy_to_user(useraddr, &stats, sizeof(stats)))
		goto out;
	useraddr += sizeof(stats);
	if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
		goto out;
	ret = 0;

 out:
	kfree(data);
	return ret;
}

1119
static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
1120
1121
1122
{
	struct ethtool_perm_addr epaddr;

1123
	if (copy_from_user(&epaddr, useraddr, sizeof(epaddr)))
1124
1125
		return -EFAULT;

1126
1127
1128
	if (epaddr.size < dev->addr_len)
		return -ETOOSMALL;
	epaddr.size = dev->addr_len;
1129
1130

	if (copy_to_user(useraddr, &epaddr, sizeof(epaddr)))
1131
		return -EFAULT;
1132
	useraddr += sizeof(epaddr);
1133
1134
1135
	if (copy_to_user(useraddr, dev->perm_addr, epaddr.size))
		return -EFAULT;
	return 0;
1136
1137
}

1138
1139
static int ethtool_get_value(struct net_device *dev, char __user *useraddr,
			     u32 cmd, u32 (*actor)(struct net_device *))
1140
{
1141
	struct ethtool_value edata = { .cmd = cmd };
1142

1143
	if (!actor)
1144
1145
		return -EOPNOTSUPP;

1146
	edata.data = actor(dev);
1147
1148
1149
1150
1151
1152

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

1153
1154
static int ethtool_set_value_void(struct net_device *dev, char __user *useraddr,
			     void (*actor)(struct net_device *, u32))
1155
1156
1157
{
	struct ethtool_value edata;

1158
	if (!actor)
1159
1160
1161
1162
1163
		return -EOPNOTSUPP;

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

1164
	actor(dev, edata.data);
1165
1166
1167
	return 0;
}

1168
1169
static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
			     int (*actor)(struct net_device *, u32))
1170
1171
1172
{
	struct ethtool_value edata;

1173
	if (!actor)
1174
1175
1176
1177
1178
		return -EOPNOTSUPP;

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

1179
	return actor(dev, edata.data);
1180
1181
}

1182
1183
static noinline_for_stack int ethtool_flash_device(struct net_device *dev,
						   char __user *useraddr)
1184
1185
1186
1187
1188
1189
1190
1191
1192
{
	struct ethtool_flash efl;

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

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

1193
1194
	efl.data[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;

1195
1196
1197
	return dev->ethtool_ops->flash_device(dev, &efl);
}

1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
static int ethtool_set_dump(struct net_device *dev,
			void __user *useraddr)
{
	struct ethtool_dump dump;

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

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

	return dev->ethtool_ops->set_dump(dev, &dump);
}

static int ethtool_get_dump_flag(struct net_device *dev,
				void __user *useraddr)
{
	int ret;
	struct ethtool_dump dump;
	const struct ethtool_ops *ops = dev->ethtool_ops;

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

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

	ret = ops->get_dump_flag(dev, &dump);
	if (ret)
		return ret;

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

static int ethtool_get_dump_data(struct net_device *dev,
				void __user *useraddr)
{
	int ret;
	__u32 len;
	struct ethtool_dump dump, tmp;
	const struct ethtool_ops *ops = dev->ethtool_ops;
	void *data = NULL;

	if (!dev->ethtool_ops->get_dump_data ||
		!dev->ethtool_ops->get_dump_flag)
		return -EOPNOTSUPP;

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

	memset(&tmp, 0, sizeof(tmp));
	tmp.cmd = ETHTOOL_GET_DUMP_FLAG;
	ret = ops->get_dump_flag(dev, &tmp);
	if (ret)
		return ret;

	len = (tmp.len > dump.len) ? dump.len : tmp.len;
	if (!len)
		return -EFAULT;

	data = vzalloc(tmp.len);
	if (!data)
		return -ENOMEM;
	ret = ops->get_dump_data(dev, &dump, data);
	if (ret)
		goto out;

	if (copy_to_user(useraddr, &dump, sizeof(dump))) {
		ret = -EFAULT;
		goto out;
	}
	useraddr += offsetof(struct ethtool_dump, data);
	if (copy_to_user(useraddr, data, len))
		ret = -EFAULT;
out:
	vfree(data);
	return ret;
}

Linus Torvalds's avatar
Linus Torvalds committed
1279
1280
/* The main entry point in this file.  Called from net/core/dev.c */

1281
int dev_ethtool(struct net *net, struct ifreq *ifr)
Linus Torvalds's avatar
Linus Torvalds committed
1282
{
1283
	struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
Linus Torvalds's avatar
Linus Torvalds committed
1284
1285
1286
	void __user *useraddr = ifr->ifr_data;
	u32 ethcmd;
	int rc;
1287
	u32 old_features;
Linus Torvalds's avatar
Linus Torvalds committed
1288
1289
1290
1291

	if (!dev || !netif_device_present(dev))
		return -ENODEV;

1292
	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
Linus Torvalds's avatar
Linus Torvalds committed
1293
1294
		return -EFAULT;

1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
	if (!dev->ethtool_ops) {
		/* ETHTOOL_GDRVINFO does not require any driver support.
		 * It is also unprivileged and does not change anything,
		 * so we can take a shortcut to it. */
		if (ethcmd == ETHTOOL_GDRVINFO)
			return ethtool_get_drvinfo(dev, useraddr);
		else
			return -EOPNOTSUPP;
	}

1305
	/* Allow some commands to be done by anyone */
1306
	switch (ethcmd) {
1307
	case ETHTOOL_GSET:
1308
1309
1310
1311
1312
1313
1314
1315
	case ETHTOOL_GDRVINFO:
	case ETHTOOL_GMSGLVL:
	case ETHTOOL_GCOALESCE:
	case ETHTOOL_GRINGPARAM:
	case ETHTOOL_GPAUSEPARAM:
	case ETHTOOL_GRXCSUM:
	case ETHTOOL_GTXCSUM:
	case ETHTOOL_GSG:
1316
	case ETHTOOL_GSSET_INFO:
1317
1318
1319
1320
1321
	case ETHTOOL_GSTRINGS:
	case ETHTOOL_GTSO:
	case ETHTOOL_GPERMADDR:
	case ETHTOOL_GUFO:
	case ETHTOOL_GGSO:
1322
	case ETHTOOL_GGRO:
1323
1324
	case ETHTOOL_GFLAGS:
	case ETHTOOL_GPFLAGS:
1325
	case ETHTOOL_GRXFH:
1326
1327
1328
1329
	case ETHTOOL_GRXRINGS:
	case ETHTOOL_GRXCLSRLCNT:
	case ETHTOOL_GRXCLSRULE:
	case ETHTOOL_GRXCLSRLALL:
1330
	case ETHTOOL_GFEATURES:
1331
1332
1333
1334
1335
1336
		break;
	default:
		if (!capable(CAP_NET_ADMIN))
			return -EPERM;
	}

1337
1338
1339
	if (dev->ethtool_ops->begin) {
		rc = dev->ethtool_ops->begin(dev);
		if (rc  < 0)
Linus Torvalds's avatar
Linus Torvalds committed
1340
			return rc;
1341
	}
1342
1343
	old_features = dev->features;

Linus Torvalds's avatar
Linus Torvalds committed
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
	switch (ethcmd) {
	case ETHTOOL_GSET:
		rc = ethtool_get_settings(dev, useraddr);
		break;
	case ETHTOOL_SSET:
		rc = ethtool_set_settings(dev, useraddr);
		break;
	case ETHTOOL_GDRVINFO:
		rc = ethtool_get_drvinfo(dev, useraddr);
		break;
	case ETHTOOL_GREGS:
		rc = ethtool_get_regs(dev, useraddr);
		break;
	case ETHTOOL_GWOL:
		rc = ethtool_get_wol(dev, useraddr);
		break;
	case ETHTOOL_SWOL:
		rc = ethtool_set_wol(dev, useraddr);
		break;
	case ETHTOOL_GMSGLVL:
1364
1365
		rc = ethtool_get_value(dev, useraddr, ethcmd,
				       dev->ethtool_ops->get_msglevel);
Linus Torvalds's avatar
Linus Torvalds committed
1366
1367
		break;
	case ETHTOOL_SMSGLVL:
1368
1369
		rc = ethtool_set_value_void(dev, useraddr,
				       dev->ethtool_ops->set_msglevel);
Linus Torvalds's avatar
Linus Torvalds committed
1370
1371
1372
1373
1374
		break;
	case ETHTOOL_NWAY_RST:
		rc = ethtool_nway_reset(dev);
		break;
	case ETHTOOL_GLINK:
1375
		rc = ethtool_get_link(dev, useraddr);
Linus Torvalds's avatar
Linus Torvalds committed
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
		break;
	case ETHTOOL_GEEPROM:
		rc = ethtool_get_eeprom(dev, useraddr);
		break;
	case ETHTOOL_SEEPROM:
		rc = ethtool_set_eeprom(dev, useraddr);
		break;
	case ETHTOOL_GCOALESCE:
		rc = ethtool_get_coalesce(dev, useraddr);
		break;
	case ETHTOOL_SCOALESCE:
		rc = ethtool_set_coalesce(dev, useraddr);
		break;
	case ETHTOOL_GRINGPARAM:
		rc = ethtool_get_ringparam(dev, useraddr);
		break;
	case ETHTOOL_SRINGPARAM:
		rc = ethtool_set_ringparam(dev, useraddr);
		break;
	case ETHTOOL_GPAUSEPARAM:
		rc = ethtool_get_pauseparam(dev, useraddr);
		break;
	case ETHTOOL_SPAUSEPARAM:
		rc = ethtool_set_pauseparam(dev, useraddr);
		break;
	case ETHTOOL_TEST:
		rc = ethtool_self_test(dev, useraddr);
		break;
	case ETHTOOL_GSTRINGS:
		rc = ethtool_get_strings(dev, useraddr);
		break;
	case ETHTOOL_PHYS_ID:
		rc