net/sunrpc: Convert (void)snprintf to snprintf
[deliverable/linux.git] / net / core / ethtool.c
CommitLineData
1da177e4
LT
1/*
2 * net/core/ethtool.c - Ethtool ioctl handler
3 * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
4 *
5 * This file is where we call all the ethtool_ops commands to get
61a44b9c 6 * the information ethtool needs.
1da177e4 7 *
61a44b9c
MW
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
1da177e4
LT
12 */
13
14#include <linux/module.h>
15#include <linux/types.h>
4fc268d2 16#include <linux/capability.h>
1da177e4
LT
17#include <linux/errno.h>
18#include <linux/ethtool.h>
19#include <linux/netdevice.h>
d17792eb 20#include <linux/bitops.h>
1da177e4
LT
21#include <asm/uaccess.h>
22
4ec93edb 23/*
1da177e4
LT
24 * Some useful ethtool_ops methods that're device independent.
25 * If we find that all drivers want to do the same thing here,
26 * we can turn these into dev_() function calls.
27 */
28
29u32 ethtool_op_get_link(struct net_device *dev)
30{
31 return netif_carrier_ok(dev) ? 1 : 0;
32}
33
1896e61f
SS
34u32 ethtool_op_get_rx_csum(struct net_device *dev)
35{
36 return (dev->features & NETIF_F_ALL_CSUM) != 0;
37}
8a729fce 38EXPORT_SYMBOL(ethtool_op_get_rx_csum);
1896e61f 39
1da177e4
LT
40u32 ethtool_op_get_tx_csum(struct net_device *dev)
41{
8648b305 42 return (dev->features & NETIF_F_ALL_CSUM) != 0;
1da177e4 43}
8a729fce 44EXPORT_SYMBOL(ethtool_op_get_tx_csum);
1da177e4
LT
45
46int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
47{
48 if (data)
49 dev->features |= NETIF_F_IP_CSUM;
50 else
51 dev->features &= ~NETIF_F_IP_CSUM;
52
53 return 0;
54}
55
69f6a0fa
JM
56int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data)
57{
58 if (data)
59 dev->features |= NETIF_F_HW_CSUM;
60 else
61 dev->features &= ~NETIF_F_HW_CSUM;
62
63 return 0;
64}
6460d948
MC
65
66int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
67{
68 if (data)
69 dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
70 else
71 dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
72
73 return 0;
74}
75
1da177e4
LT
76u32 ethtool_op_get_sg(struct net_device *dev)
77{
78 return (dev->features & NETIF_F_SG) != 0;
79}
80
81int ethtool_op_set_sg(struct net_device *dev, u32 data)
82{
83 if (data)
84 dev->features |= NETIF_F_SG;
85 else
86 dev->features &= ~NETIF_F_SG;
87
88 return 0;
89}
90
91u32 ethtool_op_get_tso(struct net_device *dev)
92{
93 return (dev->features & NETIF_F_TSO) != 0;
94}
95
96int ethtool_op_set_tso(struct net_device *dev, u32 data)
97{
98 if (data)
99 dev->features |= NETIF_F_TSO;
100 else
101 dev->features &= ~NETIF_F_TSO;
102
103 return 0;
104}
105
e89e9cf5
AR
106u32 ethtool_op_get_ufo(struct net_device *dev)
107{
108 return (dev->features & NETIF_F_UFO) != 0;
109}
110
111int ethtool_op_set_ufo(struct net_device *dev, u32 data)
112{
113 if (data)
114 dev->features |= NETIF_F_UFO;
115 else
116 dev->features &= ~NETIF_F_UFO;
117 return 0;
118}
119
3ae7c0b2
JG
120/* the following list of flags are the same as their associated
121 * NETIF_F_xxx values in include/linux/netdevice.h
122 */
123static const u32 flags_dup_features =
15682bc4 124 (ETH_FLAG_LRO | ETH_FLAG_NTUPLE);
3ae7c0b2
JG
125
126u32 ethtool_op_get_flags(struct net_device *dev)
127{
128 /* in the future, this function will probably contain additional
129 * handling for flags which are not so easily handled
130 * by a simple masking operation
131 */
132
133 return dev->features & flags_dup_features;
134}
135
136int ethtool_op_set_flags(struct net_device *dev, u32 data)
137{
0d643e1f 138 const struct ethtool_ops *ops = dev->ethtool_ops;
9675478b 139 unsigned long features = dev->features;
0d643e1f 140
3ae7c0b2 141 if (data & ETH_FLAG_LRO)
9675478b 142 features |= NETIF_F_LRO;
3ae7c0b2 143 else
9675478b 144 features &= ~NETIF_F_LRO;
3ae7c0b2 145
0d643e1f
PW
146 if (data & ETH_FLAG_NTUPLE) {
147 if (!ops->set_rx_ntuple)
148 return -EOPNOTSUPP;
9675478b 149 features |= NETIF_F_NTUPLE;
0d643e1f
PW
150 } else {
151 /* safe to clear regardless */
9675478b 152 features &= ~NETIF_F_NTUPLE;
0d643e1f 153 }
15682bc4 154
9675478b 155 dev->features = features;
3ae7c0b2
JG
156 return 0;
157}
158
15682bc4
PWJ
159void ethtool_ntuple_flush(struct net_device *dev)
160{
161 struct ethtool_rx_ntuple_flow_spec_container *fsc, *f;
162
163 list_for_each_entry_safe(fsc, f, &dev->ethtool_ntuple_list.list, list) {
164 list_del(&fsc->list);
165 kfree(fsc);
166 }
167 dev->ethtool_ntuple_list.count = 0;
168}
169EXPORT_SYMBOL(ethtool_ntuple_flush);
170
1da177e4
LT
171/* Handlers for each ethtool command */
172
173static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
174{
8e557421 175 struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
1da177e4
LT
176 int err;
177
178 if (!dev->ethtool_ops->get_settings)
179 return -EOPNOTSUPP;
180
181 err = dev->ethtool_ops->get_settings(dev, &cmd);
182 if (err < 0)
183 return err;
184
185 if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
186 return -EFAULT;
187 return 0;
188}
189
190static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
191{
192 struct ethtool_cmd cmd;
193
194 if (!dev->ethtool_ops->set_settings)
195 return -EOPNOTSUPP;
196
197 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
198 return -EFAULT;
199
200 return dev->ethtool_ops->set_settings(dev, &cmd);
201}
202
339c6e99
ED
203/*
204 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
205 */
206static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
1da177e4
LT
207{
208 struct ethtool_drvinfo info;
76fd8593 209 const struct ethtool_ops *ops = dev->ethtool_ops;
1da177e4
LT
210
211 if (!ops->get_drvinfo)
212 return -EOPNOTSUPP;
213
214 memset(&info, 0, sizeof(info));
215 info.cmd = ETHTOOL_GDRVINFO;
216 ops->get_drvinfo(dev, &info);
217
723b2f57
JG
218 /*
219 * this method of obtaining string set info is deprecated;
d17792eb 220 * Use ETHTOOL_GSSET_INFO instead.
723b2f57 221 */
ff03d49f
JG
222 if (ops->get_sset_count) {
223 int rc;
224
225 rc = ops->get_sset_count(dev, ETH_SS_TEST);
226 if (rc >= 0)
227 info.testinfo_len = rc;
228 rc = ops->get_sset_count(dev, ETH_SS_STATS);
229 if (rc >= 0)
230 info.n_stats = rc;
339bf024
JG
231 rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
232 if (rc >= 0)
233 info.n_priv_flags = rc;
ff03d49f 234 }
1da177e4
LT
235 if (ops->get_regs_len)
236 info.regdump_len = ops->get_regs_len(dev);
237 if (ops->get_eeprom_len)
238 info.eedump_len = ops->get_eeprom_len(dev);
239
240 if (copy_to_user(useraddr, &info, sizeof(info)))
241 return -EFAULT;
242 return 0;
243}
244
723b2f57
JG
245/*
246 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
247 */
248static noinline int ethtool_get_sset_info(struct net_device *dev,
249 void __user *useraddr)
250{
251 struct ethtool_sset_info info;
252 const struct ethtool_ops *ops = dev->ethtool_ops;
253 u64 sset_mask;
254 int i, idx = 0, n_bits = 0, ret, rc;
255 u32 *info_buf = NULL;
256
257 if (!ops->get_sset_count)
258 return -EOPNOTSUPP;
259
260 if (copy_from_user(&info, useraddr, sizeof(info)))
261 return -EFAULT;
262
263 /* store copy of mask, because we zero struct later on */
264 sset_mask = info.sset_mask;
265 if (!sset_mask)
266 return 0;
267
268 /* calculate size of return buffer */
d17792eb 269 n_bits = hweight64(sset_mask);
723b2f57
JG
270
271 memset(&info, 0, sizeof(info));
272 info.cmd = ETHTOOL_GSSET_INFO;
273
274 info_buf = kzalloc(n_bits * sizeof(u32), GFP_USER);
275 if (!info_buf)
276 return -ENOMEM;
277
278 /*
279 * fill return buffer based on input bitmask and successful
280 * get_sset_count return
281 */
282 for (i = 0; i < 64; i++) {
283 if (!(sset_mask & (1ULL << i)))
284 continue;
285
286 rc = ops->get_sset_count(dev, i);
287 if (rc >= 0) {
288 info.sset_mask |= (1ULL << i);
289 info_buf[idx++] = rc;
290 }
291 }
292
293 ret = -EFAULT;
294 if (copy_to_user(useraddr, &info, sizeof(info)))
295 goto out;
296
297 useraddr += offsetof(struct ethtool_sset_info, data);
298 if (copy_to_user(useraddr, info_buf, idx * sizeof(u32)))
299 goto out;
300
301 ret = 0;
302
303out:
304 kfree(info_buf);
305 return ret;
306}
307
339c6e99
ED
308/*
309 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
310 */
311static noinline int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)
0853ad66
SB
312{
313 struct ethtool_rxnfc cmd;
314
59089d8d 315 if (!dev->ethtool_ops->set_rxnfc)
0853ad66
SB
316 return -EOPNOTSUPP;
317
318 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
319 return -EFAULT;
320
59089d8d 321 return dev->ethtool_ops->set_rxnfc(dev, &cmd);
0853ad66
SB
322}
323
339c6e99
ED
324/*
325 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
326 */
327static noinline int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)
0853ad66
SB
328{
329 struct ethtool_rxnfc info;
59089d8d
SB
330 const struct ethtool_ops *ops = dev->ethtool_ops;
331 int ret;
332 void *rule_buf = NULL;
0853ad66 333
59089d8d 334 if (!ops->get_rxnfc)
0853ad66
SB
335 return -EOPNOTSUPP;
336
337 if (copy_from_user(&info, useraddr, sizeof(info)))
338 return -EFAULT;
339
59089d8d
SB
340 if (info.cmd == ETHTOOL_GRXCLSRLALL) {
341 if (info.rule_cnt > 0) {
342 rule_buf = kmalloc(info.rule_cnt * sizeof(u32),
343 GFP_USER);
344 if (!rule_buf)
345 return -ENOMEM;
346 }
347 }
0853ad66 348
59089d8d
SB
349 ret = ops->get_rxnfc(dev, &info, rule_buf);
350 if (ret < 0)
351 goto err_out;
352
353 ret = -EFAULT;
0853ad66 354 if (copy_to_user(useraddr, &info, sizeof(info)))
59089d8d
SB
355 goto err_out;
356
357 if (rule_buf) {
358 useraddr += offsetof(struct ethtool_rxnfc, rule_locs);
359 if (copy_to_user(useraddr, rule_buf,
360 info.rule_cnt * sizeof(u32)))
361 goto err_out;
362 }
363 ret = 0;
364
365err_out:
c9caceca 366 kfree(rule_buf);
59089d8d
SB
367
368 return ret;
0853ad66
SB
369}
370
e8589118
PW
371static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
372 struct ethtool_rx_ntuple_flow_spec *spec,
373 struct ethtool_rx_ntuple_flow_spec_container *fsc)
15682bc4 374{
15682bc4
PWJ
375
376 /* don't add filters forever */
e8589118
PW
377 if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) {
378 /* free the container */
379 kfree(fsc);
380 return;
381 }
15682bc4
PWJ
382
383 /* Copy the whole filter over */
384 fsc->fs.flow_type = spec->flow_type;
385 memcpy(&fsc->fs.h_u, &spec->h_u, sizeof(spec->h_u));
386 memcpy(&fsc->fs.m_u, &spec->m_u, sizeof(spec->m_u));
387
388 fsc->fs.vlan_tag = spec->vlan_tag;
389 fsc->fs.vlan_tag_mask = spec->vlan_tag_mask;
390 fsc->fs.data = spec->data;
391 fsc->fs.data_mask = spec->data_mask;
392 fsc->fs.action = spec->action;
393
394 /* add to the list */
395 list_add_tail_rcu(&fsc->list, &list->list);
396 list->count++;
15682bc4
PWJ
397}
398
339c6e99
ED
399/*
400 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
401 */
402static noinline int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr)
15682bc4
PWJ
403{
404 struct ethtool_rx_ntuple cmd;
405 const struct ethtool_ops *ops = dev->ethtool_ops;
e8589118 406 struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL;
15682bc4
PWJ
407 int ret;
408
15682bc4
PWJ
409 if (!(dev->features & NETIF_F_NTUPLE))
410 return -EINVAL;
411
412 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
413 return -EFAULT;
414
15682bc4
PWJ
415 /*
416 * Cache filter in dev struct for GET operation only if
417 * the underlying driver doesn't have its own GET operation, and
e8589118
PW
418 * only if the filter was added successfully. First make sure we
419 * can allocate the filter, then continue if successful.
15682bc4 420 */
e8589118
PW
421 if (!ops->get_rx_ntuple) {
422 fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC);
423 if (!fsc)
15682bc4 424 return -ENOMEM;
e8589118
PW
425 }
426
427 ret = ops->set_rx_ntuple(dev, &cmd);
428 if (ret) {
429 kfree(fsc);
430 return ret;
431 }
432
433 if (!ops->get_rx_ntuple)
434 __rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs, fsc);
15682bc4
PWJ
435
436 return ret;
437}
438
439static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr)
440{
441 struct ethtool_gstrings gstrings;
442 const struct ethtool_ops *ops = dev->ethtool_ops;
443 struct ethtool_rx_ntuple_flow_spec_container *fsc;
444 u8 *data;
445 char *p;
446 int ret, i, num_strings = 0;
447
448 if (!ops->get_sset_count)
449 return -EOPNOTSUPP;
450
451 if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
452 return -EFAULT;
453
454 ret = ops->get_sset_count(dev, gstrings.string_set);
455 if (ret < 0)
456 return ret;
457
458 gstrings.len = ret;
459
460 data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
461 if (!data)
462 return -ENOMEM;
463
464 if (ops->get_rx_ntuple) {
465 /* driver-specific filter grab */
466 ret = ops->get_rx_ntuple(dev, gstrings.string_set, data);
467 goto copy;
468 }
469
470 /* default ethtool filter grab */
471 i = 0;
472 p = (char *)data;
473 list_for_each_entry(fsc, &dev->ethtool_ntuple_list.list, list) {
474 sprintf(p, "Filter %d:\n", i);
475 p += ETH_GSTRING_LEN;
476 num_strings++;
477
478 switch (fsc->fs.flow_type) {
479 case TCP_V4_FLOW:
480 sprintf(p, "\tFlow Type: TCP\n");
481 p += ETH_GSTRING_LEN;
482 num_strings++;
483 break;
484 case UDP_V4_FLOW:
485 sprintf(p, "\tFlow Type: UDP\n");
486 p += ETH_GSTRING_LEN;
487 num_strings++;
488 break;
489 case SCTP_V4_FLOW:
490 sprintf(p, "\tFlow Type: SCTP\n");
491 p += ETH_GSTRING_LEN;
492 num_strings++;
493 break;
494 case AH_ESP_V4_FLOW:
495 sprintf(p, "\tFlow Type: AH ESP\n");
496 p += ETH_GSTRING_LEN;
497 num_strings++;
498 break;
499 case ESP_V4_FLOW:
500 sprintf(p, "\tFlow Type: ESP\n");
501 p += ETH_GSTRING_LEN;
502 num_strings++;
503 break;
504 case IP_USER_FLOW:
505 sprintf(p, "\tFlow Type: Raw IP\n");
506 p += ETH_GSTRING_LEN;
507 num_strings++;
508 break;
509 case IPV4_FLOW:
510 sprintf(p, "\tFlow Type: IPv4\n");
511 p += ETH_GSTRING_LEN;
512 num_strings++;
513 break;
514 default:
515 sprintf(p, "\tFlow Type: Unknown\n");
516 p += ETH_GSTRING_LEN;
517 num_strings++;
518 goto unknown_filter;
519 };
520
521 /* now the rest of the filters */
522 switch (fsc->fs.flow_type) {
523 case TCP_V4_FLOW:
524 case UDP_V4_FLOW:
525 case SCTP_V4_FLOW:
526 sprintf(p, "\tSrc IP addr: 0x%x\n",
527 fsc->fs.h_u.tcp_ip4_spec.ip4src);
528 p += ETH_GSTRING_LEN;
529 num_strings++;
530 sprintf(p, "\tSrc IP mask: 0x%x\n",
531 fsc->fs.m_u.tcp_ip4_spec.ip4src);
532 p += ETH_GSTRING_LEN;
533 num_strings++;
534 sprintf(p, "\tDest IP addr: 0x%x\n",
535 fsc->fs.h_u.tcp_ip4_spec.ip4dst);
536 p += ETH_GSTRING_LEN;
537 num_strings++;
538 sprintf(p, "\tDest IP mask: 0x%x\n",
539 fsc->fs.m_u.tcp_ip4_spec.ip4dst);
540 p += ETH_GSTRING_LEN;
541 num_strings++;
542 sprintf(p, "\tSrc Port: %d, mask: 0x%x\n",
543 fsc->fs.h_u.tcp_ip4_spec.psrc,
544 fsc->fs.m_u.tcp_ip4_spec.psrc);
545 p += ETH_GSTRING_LEN;
546 num_strings++;
547 sprintf(p, "\tDest Port: %d, mask: 0x%x\n",
548 fsc->fs.h_u.tcp_ip4_spec.pdst,
549 fsc->fs.m_u.tcp_ip4_spec.pdst);
550 p += ETH_GSTRING_LEN;
551 num_strings++;
552 sprintf(p, "\tTOS: %d, mask: 0x%x\n",
553 fsc->fs.h_u.tcp_ip4_spec.tos,
554 fsc->fs.m_u.tcp_ip4_spec.tos);
555 p += ETH_GSTRING_LEN;
556 num_strings++;
557 break;
558 case AH_ESP_V4_FLOW:
559 case ESP_V4_FLOW:
560 sprintf(p, "\tSrc IP addr: 0x%x\n",
561 fsc->fs.h_u.ah_ip4_spec.ip4src);
562 p += ETH_GSTRING_LEN;
563 num_strings++;
564 sprintf(p, "\tSrc IP mask: 0x%x\n",
565 fsc->fs.m_u.ah_ip4_spec.ip4src);
566 p += ETH_GSTRING_LEN;
567 num_strings++;
568 sprintf(p, "\tDest IP addr: 0x%x\n",
569 fsc->fs.h_u.ah_ip4_spec.ip4dst);
570 p += ETH_GSTRING_LEN;
571 num_strings++;
572 sprintf(p, "\tDest IP mask: 0x%x\n",
573 fsc->fs.m_u.ah_ip4_spec.ip4dst);
574 p += ETH_GSTRING_LEN;
575 num_strings++;
576 sprintf(p, "\tSPI: %d, mask: 0x%x\n",
577 fsc->fs.h_u.ah_ip4_spec.spi,
578 fsc->fs.m_u.ah_ip4_spec.spi);
579 p += ETH_GSTRING_LEN;
580 num_strings++;
581 sprintf(p, "\tTOS: %d, mask: 0x%x\n",
582 fsc->fs.h_u.ah_ip4_spec.tos,
583 fsc->fs.m_u.ah_ip4_spec.tos);
584 p += ETH_GSTRING_LEN;
585 num_strings++;
586 break;
587 case IP_USER_FLOW:
588 sprintf(p, "\tSrc IP addr: 0x%x\n",
589 fsc->fs.h_u.raw_ip4_spec.ip4src);
590 p += ETH_GSTRING_LEN;
591 num_strings++;
592 sprintf(p, "\tSrc IP mask: 0x%x\n",
593 fsc->fs.m_u.raw_ip4_spec.ip4src);
594 p += ETH_GSTRING_LEN;
595 num_strings++;
596 sprintf(p, "\tDest IP addr: 0x%x\n",
597 fsc->fs.h_u.raw_ip4_spec.ip4dst);
598 p += ETH_GSTRING_LEN;
599 num_strings++;
600 sprintf(p, "\tDest IP mask: 0x%x\n",
601 fsc->fs.m_u.raw_ip4_spec.ip4dst);
602 p += ETH_GSTRING_LEN;
603 num_strings++;
604 break;
605 case IPV4_FLOW:
606 sprintf(p, "\tSrc IP addr: 0x%x\n",
607 fsc->fs.h_u.usr_ip4_spec.ip4src);
608 p += ETH_GSTRING_LEN;
609 num_strings++;
610 sprintf(p, "\tSrc IP mask: 0x%x\n",
611 fsc->fs.m_u.usr_ip4_spec.ip4src);
612 p += ETH_GSTRING_LEN;
613 num_strings++;
614 sprintf(p, "\tDest IP addr: 0x%x\n",
615 fsc->fs.h_u.usr_ip4_spec.ip4dst);
616 p += ETH_GSTRING_LEN;
617 num_strings++;
618 sprintf(p, "\tDest IP mask: 0x%x\n",
619 fsc->fs.m_u.usr_ip4_spec.ip4dst);
620 p += ETH_GSTRING_LEN;
621 num_strings++;
622 sprintf(p, "\tL4 bytes: 0x%x, mask: 0x%x\n",
623 fsc->fs.h_u.usr_ip4_spec.l4_4_bytes,
624 fsc->fs.m_u.usr_ip4_spec.l4_4_bytes);
625 p += ETH_GSTRING_LEN;
626 num_strings++;
627 sprintf(p, "\tTOS: %d, mask: 0x%x\n",
628 fsc->fs.h_u.usr_ip4_spec.tos,
629 fsc->fs.m_u.usr_ip4_spec.tos);
630 p += ETH_GSTRING_LEN;
631 num_strings++;
632 sprintf(p, "\tIP Version: %d, mask: 0x%x\n",
633 fsc->fs.h_u.usr_ip4_spec.ip_ver,
634 fsc->fs.m_u.usr_ip4_spec.ip_ver);
635 p += ETH_GSTRING_LEN;
636 num_strings++;
637 sprintf(p, "\tProtocol: %d, mask: 0x%x\n",
638 fsc->fs.h_u.usr_ip4_spec.proto,
639 fsc->fs.m_u.usr_ip4_spec.proto);
640 p += ETH_GSTRING_LEN;
641 num_strings++;
642 break;
643 };
644 sprintf(p, "\tVLAN: %d, mask: 0x%x\n",
645 fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask);
646 p += ETH_GSTRING_LEN;
647 num_strings++;
648 sprintf(p, "\tUser-defined: 0x%Lx\n", fsc->fs.data);
649 p += ETH_GSTRING_LEN;
650 num_strings++;
651 sprintf(p, "\tUser-defined mask: 0x%Lx\n", fsc->fs.data_mask);
652 p += ETH_GSTRING_LEN;
653 num_strings++;
654 if (fsc->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
655 sprintf(p, "\tAction: Drop\n");
656 else
657 sprintf(p, "\tAction: Direct to queue %d\n",
658 fsc->fs.action);
659 p += ETH_GSTRING_LEN;
660 num_strings++;
661unknown_filter:
662 i++;
663 }
664copy:
665 /* indicate to userspace how many strings we actually have */
666 gstrings.len = num_strings;
667 ret = -EFAULT;
668 if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
669 goto out;
670 useraddr += sizeof(gstrings);
671 if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
672 goto out;
673 ret = 0;
674
675out:
676 kfree(data);
677 return ret;
678}
679
1da177e4
LT
680static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
681{
682 struct ethtool_regs regs;
76fd8593 683 const struct ethtool_ops *ops = dev->ethtool_ops;
1da177e4
LT
684 void *regbuf;
685 int reglen, ret;
686
687 if (!ops->get_regs || !ops->get_regs_len)
688 return -EOPNOTSUPP;
689
690 if (copy_from_user(&regs, useraddr, sizeof(regs)))
691 return -EFAULT;
692
693 reglen = ops->get_regs_len(dev);
694 if (regs.len > reglen)
695 regs.len = reglen;
696
697 regbuf = kmalloc(reglen, GFP_USER);
698 if (!regbuf)
699 return -ENOMEM;
700
701 ops->get_regs(dev, &regs, regbuf);
702
703 ret = -EFAULT;
704 if (copy_to_user(useraddr, &regs, sizeof(regs)))
705 goto out;
706 useraddr += offsetof(struct ethtool_regs, data);
707 if (copy_to_user(useraddr, regbuf, regs.len))
708 goto out;
709 ret = 0;
710
711 out:
712 kfree(regbuf);
713 return ret;
714}
715
d73d3a8c
BH
716static int ethtool_reset(struct net_device *dev, char __user *useraddr)
717{
718 struct ethtool_value reset;
719 int ret;
720
721 if (!dev->ethtool_ops->reset)
722 return -EOPNOTSUPP;
723
724 if (copy_from_user(&reset, useraddr, sizeof(reset)))
725 return -EFAULT;
726
727 ret = dev->ethtool_ops->reset(dev, &reset.data);
728 if (ret)
729 return ret;
730
731 if (copy_to_user(useraddr, &reset, sizeof(reset)))
732 return -EFAULT;
733 return 0;
734}
735
1da177e4
LT
736static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
737{
8e557421 738 struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
1da177e4
LT
739
740 if (!dev->ethtool_ops->get_wol)
741 return -EOPNOTSUPP;
742
743 dev->ethtool_ops->get_wol(dev, &wol);
744
745 if (copy_to_user(useraddr, &wol, sizeof(wol)))
746 return -EFAULT;
747 return 0;
748}
749
750static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
751{
752 struct ethtool_wolinfo wol;
753
754 if (!dev->ethtool_ops->set_wol)
755 return -EOPNOTSUPP;
756
757 if (copy_from_user(&wol, useraddr, sizeof(wol)))
758 return -EFAULT;
759
760 return dev->ethtool_ops->set_wol(dev, &wol);
761}
762
1da177e4
LT
763static int ethtool_nway_reset(struct net_device *dev)
764{
765 if (!dev->ethtool_ops->nway_reset)
766 return -EOPNOTSUPP;
767
768 return dev->ethtool_ops->nway_reset(dev);
769}
770
1da177e4
LT
771static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
772{
773 struct ethtool_eeprom eeprom;
76fd8593 774 const struct ethtool_ops *ops = dev->ethtool_ops;
b131dd5d
MSB
775 void __user *userbuf = useraddr + sizeof(eeprom);
776 u32 bytes_remaining;
1da177e4 777 u8 *data;
b131dd5d 778 int ret = 0;
1da177e4
LT
779
780 if (!ops->get_eeprom || !ops->get_eeprom_len)
781 return -EOPNOTSUPP;
782
783 if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
784 return -EFAULT;
785
786 /* Check for wrap and zero */
787 if (eeprom.offset + eeprom.len <= eeprom.offset)
788 return -EINVAL;
789
790 /* Check for exceeding total eeprom len */
791 if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
792 return -EINVAL;
793
b131dd5d 794 data = kmalloc(PAGE_SIZE, GFP_USER);
1da177e4
LT
795 if (!data)
796 return -ENOMEM;
797
b131dd5d
MSB
798 bytes_remaining = eeprom.len;
799 while (bytes_remaining > 0) {
800 eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
801
802 ret = ops->get_eeprom(dev, &eeprom, data);
803 if (ret)
804 break;
805 if (copy_to_user(userbuf, data, eeprom.len)) {
806 ret = -EFAULT;
807 break;
808 }
809 userbuf += eeprom.len;
810 eeprom.offset += eeprom.len;
811 bytes_remaining -= eeprom.len;
812 }
1da177e4 813
c5835df9
MSB
814 eeprom.len = userbuf - (useraddr + sizeof(eeprom));
815 eeprom.offset -= eeprom.len;
816 if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
817 ret = -EFAULT;
818
1da177e4
LT
819 kfree(data);
820 return ret;
821}
822
823static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
824{
825 struct ethtool_eeprom eeprom;
76fd8593 826 const struct ethtool_ops *ops = dev->ethtool_ops;
b131dd5d
MSB
827 void __user *userbuf = useraddr + sizeof(eeprom);
828 u32 bytes_remaining;
1da177e4 829 u8 *data;
b131dd5d 830 int ret = 0;
1da177e4
LT
831
832 if (!ops->set_eeprom || !ops->get_eeprom_len)
833 return -EOPNOTSUPP;
834
835 if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
836 return -EFAULT;
837
838 /* Check for wrap and zero */
839 if (eeprom.offset + eeprom.len <= eeprom.offset)
840 return -EINVAL;
841
842 /* Check for exceeding total eeprom len */
843 if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
844 return -EINVAL;
845
b131dd5d 846 data = kmalloc(PAGE_SIZE, GFP_USER);
1da177e4
LT
847 if (!data)
848 return -ENOMEM;
849
b131dd5d
MSB
850 bytes_remaining = eeprom.len;
851 while (bytes_remaining > 0) {
852 eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
853
854 if (copy_from_user(data, userbuf, eeprom.len)) {
855 ret = -EFAULT;
856 break;
857 }
858 ret = ops->set_eeprom(dev, &eeprom, data);
859 if (ret)
860 break;
861 userbuf += eeprom.len;
862 eeprom.offset += eeprom.len;
863 bytes_remaining -= eeprom.len;
864 }
1da177e4 865
1da177e4
LT
866 kfree(data);
867 return ret;
868}
869
339c6e99
ED
870/*
871 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
872 */
873static noinline int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr)
1da177e4 874{
8e557421 875 struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
1da177e4
LT
876
877 if (!dev->ethtool_ops->get_coalesce)
878 return -EOPNOTSUPP;
879
880 dev->ethtool_ops->get_coalesce(dev, &coalesce);
881
882 if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
883 return -EFAULT;
884 return 0;
885}
886
339c6e99
ED
887/*
888 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
889 */
890static noinline int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)
1da177e4
LT
891{
892 struct ethtool_coalesce coalesce;
893
fa04ae5c 894 if (!dev->ethtool_ops->set_coalesce)
1da177e4
LT
895 return -EOPNOTSUPP;
896
897 if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
898 return -EFAULT;
899
900 return dev->ethtool_ops->set_coalesce(dev, &coalesce);
901}
902
903static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
904{
8e557421 905 struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM };
1da177e4
LT
906
907 if (!dev->ethtool_ops->get_ringparam)
908 return -EOPNOTSUPP;
909
910 dev->ethtool_ops->get_ringparam(dev, &ringparam);
911
912 if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
913 return -EFAULT;
914 return 0;
915}
916
917static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
918{
919 struct ethtool_ringparam ringparam;
920
921 if (!dev->ethtool_ops->set_ringparam)
922 return -EOPNOTSUPP;
923
924 if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
925 return -EFAULT;
926
927 return dev->ethtool_ops->set_ringparam(dev, &ringparam);
928}
929
930static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
931{
932 struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
933
934 if (!dev->ethtool_ops->get_pauseparam)
935 return -EOPNOTSUPP;
936
937 dev->ethtool_ops->get_pauseparam(dev, &pauseparam);
938
939 if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
940 return -EFAULT;
941 return 0;
942}
943
944static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
945{
946 struct ethtool_pauseparam pauseparam;
947
e1b90c41 948 if (!dev->ethtool_ops->set_pauseparam)
1da177e4
LT
949 return -EOPNOTSUPP;
950
951 if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
952 return -EFAULT;
953
954 return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
955}
956
1da177e4
LT
957static int __ethtool_set_sg(struct net_device *dev, u32 data)
958{
959 int err;
960
961 if (!data && dev->ethtool_ops->set_tso) {
962 err = dev->ethtool_ops->set_tso(dev, 0);
963 if (err)
964 return err;
965 }
966
e89e9cf5
AR
967 if (!data && dev->ethtool_ops->set_ufo) {
968 err = dev->ethtool_ops->set_ufo(dev, 0);
969 if (err)
970 return err;
971 }
1da177e4
LT
972 return dev->ethtool_ops->set_sg(dev, data);
973}
974
975static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr)
976{
977 struct ethtool_value edata;
978 int err;
979
980 if (!dev->ethtool_ops->set_tx_csum)
981 return -EOPNOTSUPP;
982
983 if (copy_from_user(&edata, useraddr, sizeof(edata)))
984 return -EFAULT;
985
986 if (!edata.data && dev->ethtool_ops->set_sg) {
987 err = __ethtool_set_sg(dev, 0);
988 if (err)
989 return err;
990 }
991
992 return dev->ethtool_ops->set_tx_csum(dev, edata.data);
993}
994
b240a0e5
HX
995static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr)
996{
997 struct ethtool_value edata;
998
999 if (!dev->ethtool_ops->set_rx_csum)
1000 return -EOPNOTSUPP;
1001
1002 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1003 return -EFAULT;
1004
1005 if (!edata.data && dev->ethtool_ops->set_sg)
1006 dev->features &= ~NETIF_F_GRO;
1007
1008 return dev->ethtool_ops->set_rx_csum(dev, edata.data);
1009}
1010
1da177e4
LT
1011static int ethtool_set_sg(struct net_device *dev, char __user *useraddr)
1012{
1013 struct ethtool_value edata;
1014
1015 if (!dev->ethtool_ops->set_sg)
1016 return -EOPNOTSUPP;
1017
1018 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1019 return -EFAULT;
1020
4ec93edb 1021 if (edata.data &&
8648b305 1022 !(dev->features & NETIF_F_ALL_CSUM))
1da177e4
LT
1023 return -EINVAL;
1024
1025 return __ethtool_set_sg(dev, edata.data);
1026}
1027
1da177e4
LT
1028static int ethtool_set_tso(struct net_device *dev, char __user *useraddr)
1029{
1030 struct ethtool_value edata;
1031
1032 if (!dev->ethtool_ops->set_tso)
1033 return -EOPNOTSUPP;
1034
1035 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1036 return -EFAULT;
1037
1038 if (edata.data && !(dev->features & NETIF_F_SG))
1039 return -EINVAL;
1040
1041 return dev->ethtool_ops->set_tso(dev, edata.data);
1042}
1043
e89e9cf5
AR
1044static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
1045{
1046 struct ethtool_value edata;
1047
1048 if (!dev->ethtool_ops->set_ufo)
1049 return -EOPNOTSUPP;
1050 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1051 return -EFAULT;
1052 if (edata.data && !(dev->features & NETIF_F_SG))
1053 return -EINVAL;
1054 if (edata.data && !(dev->features & NETIF_F_HW_CSUM))
1055 return -EINVAL;
1056 return dev->ethtool_ops->set_ufo(dev, edata.data);
1057}
1058
37c3185a
HX
1059static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
1060{
1061 struct ethtool_value edata = { ETHTOOL_GGSO };
1062
1063 edata.data = dev->features & NETIF_F_GSO;
1064 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1065 return -EFAULT;
1066 return 0;
1067}
1068
1069static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
1070{
1071 struct ethtool_value edata;
1072
1073 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1074 return -EFAULT;
1075 if (edata.data)
1076 dev->features |= NETIF_F_GSO;
1077 else
1078 dev->features &= ~NETIF_F_GSO;
1079 return 0;
1080}
1081
b240a0e5
HX
1082static int ethtool_get_gro(struct net_device *dev, char __user *useraddr)
1083{
1084 struct ethtool_value edata = { ETHTOOL_GGRO };
1085
1086 edata.data = dev->features & NETIF_F_GRO;
1087 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1088 return -EFAULT;
1089 return 0;
1090}
1091
1092static int ethtool_set_gro(struct net_device *dev, char __user *useraddr)
1093{
1094 struct ethtool_value edata;
1095
1096 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1097 return -EFAULT;
1098
1099 if (edata.data) {
1100 if (!dev->ethtool_ops->get_rx_csum ||
1101 !dev->ethtool_ops->get_rx_csum(dev))
1102 return -EINVAL;
1103 dev->features |= NETIF_F_GRO;
1104 } else
1105 dev->features &= ~NETIF_F_GRO;
1106
1107 return 0;
1108}
1109
1da177e4
LT
1110static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
1111{
1112 struct ethtool_test test;
76fd8593 1113 const struct ethtool_ops *ops = dev->ethtool_ops;
1da177e4 1114 u64 *data;
ff03d49f 1115 int ret, test_len;
1da177e4 1116
a9828ec6 1117 if (!ops->self_test || !ops->get_sset_count)
1da177e4
LT
1118 return -EOPNOTSUPP;
1119
a9828ec6 1120 test_len = ops->get_sset_count(dev, ETH_SS_TEST);
ff03d49f
JG
1121 if (test_len < 0)
1122 return test_len;
1123 WARN_ON(test_len == 0);
1124
1da177e4
LT
1125 if (copy_from_user(&test, useraddr, sizeof(test)))
1126 return -EFAULT;
1127
ff03d49f
JG
1128 test.len = test_len;
1129 data = kmalloc(test_len * sizeof(u64), GFP_USER);
1da177e4
LT
1130 if (!data)
1131 return -ENOMEM;
1132
1133 ops->self_test(dev, &test, data);
1134
1135 ret = -EFAULT;
1136 if (copy_to_user(useraddr, &test, sizeof(test)))
1137 goto out;
1138 useraddr += sizeof(test);
1139 if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
1140 goto out;
1141 ret = 0;
1142
1143 out:
1144 kfree(data);
1145 return ret;
1146}
1147
1148static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
1149{
1150 struct ethtool_gstrings gstrings;
76fd8593 1151 const struct ethtool_ops *ops = dev->ethtool_ops;
1da177e4
LT
1152 u8 *data;
1153 int ret;
1154
a9828ec6 1155 if (!ops->get_strings || !ops->get_sset_count)
1da177e4
LT
1156 return -EOPNOTSUPP;
1157
1158 if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
1159 return -EFAULT;
1160
a9828ec6
BH
1161 ret = ops->get_sset_count(dev, gstrings.string_set);
1162 if (ret < 0)
1163 return ret;
1164
1165 gstrings.len = ret;
1da177e4
LT
1166
1167 data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
1168 if (!data)
1169 return -ENOMEM;
1170
1171 ops->get_strings(dev, gstrings.string_set, data);
1172
1173 ret = -EFAULT;
1174 if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
1175 goto out;
1176 useraddr += sizeof(gstrings);
1177 if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
1178 goto out;
1179 ret = 0;
1180
1181 out:
1182 kfree(data);
1183 return ret;
1184}
1185
1186static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
1187{
1188 struct ethtool_value id;
1189
1190 if (!dev->ethtool_ops->phys_id)
1191 return -EOPNOTSUPP;
1192
1193 if (copy_from_user(&id, useraddr, sizeof(id)))
1194 return -EFAULT;
1195
1196 return dev->ethtool_ops->phys_id(dev, id.data);
1197}
1198
1199static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
1200{
1201 struct ethtool_stats stats;
76fd8593 1202 const struct ethtool_ops *ops = dev->ethtool_ops;
1da177e4 1203 u64 *data;
ff03d49f 1204 int ret, n_stats;
1da177e4 1205
a9828ec6 1206 if (!ops->get_ethtool_stats || !ops->get_sset_count)
1da177e4
LT
1207 return -EOPNOTSUPP;
1208
a9828ec6 1209 n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
ff03d49f
JG
1210 if (n_stats < 0)
1211 return n_stats;
1212 WARN_ON(n_stats == 0);
1213
1da177e4
LT
1214 if (copy_from_user(&stats, useraddr, sizeof(stats)))
1215 return -EFAULT;
1216
ff03d49f
JG
1217 stats.n_stats = n_stats;
1218 data = kmalloc(n_stats * sizeof(u64), GFP_USER);
1da177e4
LT
1219 if (!data)
1220 return -ENOMEM;
1221
1222 ops->get_ethtool_stats(dev, &stats, data);
1223
1224 ret = -EFAULT;
1225 if (copy_to_user(useraddr, &stats, sizeof(stats)))
1226 goto out;
1227 useraddr += sizeof(stats);
1228 if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
1229 goto out;
1230 ret = 0;
1231
1232 out:
1233 kfree(data);
1234 return ret;
1235}
1236
0bf0519d 1237static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
a6f9a705
JW
1238{
1239 struct ethtool_perm_addr epaddr;
a6f9a705 1240
313674af 1241 if (copy_from_user(&epaddr, useraddr, sizeof(epaddr)))
a6f9a705
JW
1242 return -EFAULT;
1243
313674af
MW
1244 if (epaddr.size < dev->addr_len)
1245 return -ETOOSMALL;
1246 epaddr.size = dev->addr_len;
a6f9a705 1247
a6f9a705 1248 if (copy_to_user(useraddr, &epaddr, sizeof(epaddr)))
313674af 1249 return -EFAULT;
a6f9a705 1250 useraddr += sizeof(epaddr);
313674af
MW
1251 if (copy_to_user(useraddr, dev->perm_addr, epaddr.size))
1252 return -EFAULT;
1253 return 0;
a6f9a705
JW
1254}
1255
13c99b24
JG
1256static int ethtool_get_value(struct net_device *dev, char __user *useraddr,
1257 u32 cmd, u32 (*actor)(struct net_device *))
3ae7c0b2 1258{
8e557421 1259 struct ethtool_value edata = { .cmd = cmd };
3ae7c0b2 1260
13c99b24 1261 if (!actor)
3ae7c0b2
JG
1262 return -EOPNOTSUPP;
1263
13c99b24 1264 edata.data = actor(dev);
3ae7c0b2
JG
1265
1266 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1267 return -EFAULT;
1268 return 0;
1269}
1270
13c99b24
JG
1271static int ethtool_set_value_void(struct net_device *dev, char __user *useraddr,
1272 void (*actor)(struct net_device *, u32))
3ae7c0b2
JG
1273{
1274 struct ethtool_value edata;
1275
13c99b24 1276 if (!actor)
3ae7c0b2
JG
1277 return -EOPNOTSUPP;
1278
1279 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1280 return -EFAULT;
1281
13c99b24 1282 actor(dev, edata.data);
339bf024
JG
1283 return 0;
1284}
1285
13c99b24
JG
1286static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
1287 int (*actor)(struct net_device *, u32))
339bf024
JG
1288{
1289 struct ethtool_value edata;
1290
13c99b24 1291 if (!actor)
339bf024
JG
1292 return -EOPNOTSUPP;
1293
1294 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1295 return -EFAULT;
1296
13c99b24 1297 return actor(dev, edata.data);
339bf024
JG
1298}
1299
339c6e99
ED
1300/*
1301 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
1302 */
1303static noinline int ethtool_flash_device(struct net_device *dev, char __user *useraddr)
05c6a8d7
AK
1304{
1305 struct ethtool_flash efl;
1306
1307 if (copy_from_user(&efl, useraddr, sizeof(efl)))
1308 return -EFAULT;
1309
1310 if (!dev->ethtool_ops->flash_device)
1311 return -EOPNOTSUPP;
1312
1313 return dev->ethtool_ops->flash_device(dev, &efl);
1314}
1315
1da177e4
LT
1316/* The main entry point in this file. Called from net/core/dev.c */
1317
881d966b 1318int dev_ethtool(struct net *net, struct ifreq *ifr)
1da177e4 1319{
881d966b 1320 struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
1da177e4
LT
1321 void __user *useraddr = ifr->ifr_data;
1322 u32 ethcmd;
1323 int rc;
81e81575 1324 unsigned long old_features;
1da177e4 1325
1da177e4
LT
1326 if (!dev || !netif_device_present(dev))
1327 return -ENODEV;
1328
1329 if (!dev->ethtool_ops)
61a44b9c 1330 return -EOPNOTSUPP;
1da177e4
LT
1331
1332 if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
1333 return -EFAULT;
1334
75f3123c
SH
1335 /* Allow some commands to be done by anyone */
1336 switch(ethcmd) {
75f3123c 1337 case ETHTOOL_GDRVINFO:
75f3123c 1338 case ETHTOOL_GMSGLVL:
75f3123c
SH
1339 case ETHTOOL_GCOALESCE:
1340 case ETHTOOL_GRINGPARAM:
1341 case ETHTOOL_GPAUSEPARAM:
1342 case ETHTOOL_GRXCSUM:
1343 case ETHTOOL_GTXCSUM:
1344 case ETHTOOL_GSG:
1345 case ETHTOOL_GSTRINGS:
75f3123c
SH
1346 case ETHTOOL_GTSO:
1347 case ETHTOOL_GPERMADDR:
1348 case ETHTOOL_GUFO:
1349 case ETHTOOL_GGSO:
1cab819b 1350 case ETHTOOL_GGRO:
339bf024
JG
1351 case ETHTOOL_GFLAGS:
1352 case ETHTOOL_GPFLAGS:
0853ad66 1353 case ETHTOOL_GRXFH:
59089d8d
SB
1354 case ETHTOOL_GRXRINGS:
1355 case ETHTOOL_GRXCLSRLCNT:
1356 case ETHTOOL_GRXCLSRULE:
1357 case ETHTOOL_GRXCLSRLALL:
75f3123c
SH
1358 break;
1359 default:
1360 if (!capable(CAP_NET_ADMIN))
1361 return -EPERM;
1362 }
1363
e71a4783 1364 if (dev->ethtool_ops->begin)
1da177e4
LT
1365 if ((rc = dev->ethtool_ops->begin(dev)) < 0)
1366 return rc;
1367
d8a33ac4
SH
1368 old_features = dev->features;
1369
1da177e4
LT
1370 switch (ethcmd) {
1371 case ETHTOOL_GSET:
1372 rc = ethtool_get_settings(dev, useraddr);
1373 break;
1374 case ETHTOOL_SSET:
1375 rc = ethtool_set_settings(dev, useraddr);
1376 break;
1377 case ETHTOOL_GDRVINFO:
1378 rc = ethtool_get_drvinfo(dev, useraddr);
1da177e4
LT
1379 break;
1380 case ETHTOOL_GREGS:
1381 rc = ethtool_get_regs(dev, useraddr);
1382 break;
1383 case ETHTOOL_GWOL:
1384 rc = ethtool_get_wol(dev, useraddr);
1385 break;
1386 case ETHTOOL_SWOL:
1387 rc = ethtool_set_wol(dev, useraddr);
1388 break;
1389 case ETHTOOL_GMSGLVL:
13c99b24
JG
1390 rc = ethtool_get_value(dev, useraddr, ethcmd,
1391 dev->ethtool_ops->get_msglevel);
1da177e4
LT
1392 break;
1393 case ETHTOOL_SMSGLVL:
13c99b24
JG
1394 rc = ethtool_set_value_void(dev, useraddr,
1395 dev->ethtool_ops->set_msglevel);
1da177e4
LT
1396 break;
1397 case ETHTOOL_NWAY_RST:
1398 rc = ethtool_nway_reset(dev);
1399 break;
1400 case ETHTOOL_GLINK:
13c99b24
JG
1401 rc = ethtool_get_value(dev, useraddr, ethcmd,
1402 dev->ethtool_ops->get_link);
1da177e4
LT
1403 break;
1404 case ETHTOOL_GEEPROM:
1405 rc = ethtool_get_eeprom(dev, useraddr);
1406 break;
1407 case ETHTOOL_SEEPROM:
1408 rc = ethtool_set_eeprom(dev, useraddr);
1409 break;
1410 case ETHTOOL_GCOALESCE:
1411 rc = ethtool_get_coalesce(dev, useraddr);
1412 break;
1413 case ETHTOOL_SCOALESCE:
1414 rc = ethtool_set_coalesce(dev, useraddr);
1415 break;
1416 case ETHTOOL_GRINGPARAM:
1417 rc = ethtool_get_ringparam(dev, useraddr);
1418 break;
1419 case ETHTOOL_SRINGPARAM:
1420 rc = ethtool_set_ringparam(dev, useraddr);
1421 break;
1422 case ETHTOOL_GPAUSEPARAM:
1423 rc = ethtool_get_pauseparam(dev, useraddr);
1424 break;
1425 case ETHTOOL_SPAUSEPARAM:
1426 rc = ethtool_set_pauseparam(dev, useraddr);
1427 break;
1428 case ETHTOOL_GRXCSUM:
13c99b24 1429 rc = ethtool_get_value(dev, useraddr, ethcmd,
1896e61f
SS
1430 (dev->ethtool_ops->get_rx_csum ?
1431 dev->ethtool_ops->get_rx_csum :
1432 ethtool_op_get_rx_csum));
1da177e4
LT
1433 break;
1434 case ETHTOOL_SRXCSUM:
b240a0e5 1435 rc = ethtool_set_rx_csum(dev, useraddr);
1da177e4
LT
1436 break;
1437 case ETHTOOL_GTXCSUM:
13c99b24 1438 rc = ethtool_get_value(dev, useraddr, ethcmd,
88d3aafd
JG
1439 (dev->ethtool_ops->get_tx_csum ?
1440 dev->ethtool_ops->get_tx_csum :
1441 ethtool_op_get_tx_csum));
1da177e4
LT
1442 break;
1443 case ETHTOOL_STXCSUM:
1444 rc = ethtool_set_tx_csum(dev, useraddr);
1445 break;
1446 case ETHTOOL_GSG:
13c99b24 1447 rc = ethtool_get_value(dev, useraddr, ethcmd,
88d3aafd
JG
1448 (dev->ethtool_ops->get_sg ?
1449 dev->ethtool_ops->get_sg :
1450 ethtool_op_get_sg));
1da177e4
LT
1451 break;
1452 case ETHTOOL_SSG:
1453 rc = ethtool_set_sg(dev, useraddr);
1454 break;
1455 case ETHTOOL_GTSO:
13c99b24 1456 rc = ethtool_get_value(dev, useraddr, ethcmd,
88d3aafd
JG
1457 (dev->ethtool_ops->get_tso ?
1458 dev->ethtool_ops->get_tso :
1459 ethtool_op_get_tso));
1da177e4
LT
1460 break;
1461 case ETHTOOL_STSO:
1462 rc = ethtool_set_tso(dev, useraddr);
1463 break;
1464 case ETHTOOL_TEST:
1465 rc = ethtool_self_test(dev, useraddr);
1466 break;
1467 case ETHTOOL_GSTRINGS:
1468 rc = ethtool_get_strings(dev, useraddr);
1469 break;
1470 case ETHTOOL_PHYS_ID:
1471 rc = ethtool_phys_id(dev, useraddr);
1472 break;
1473 case ETHTOOL_GSTATS:
1474 rc = ethtool_get_stats(dev, useraddr);
1475 break;
a6f9a705
JW
1476 case ETHTOOL_GPERMADDR:
1477 rc = ethtool_get_perm_addr(dev, useraddr);
1478 break;
e89e9cf5 1479 case ETHTOOL_GUFO:
13c99b24 1480 rc = ethtool_get_value(dev, useraddr, ethcmd,
88d3aafd
JG
1481 (dev->ethtool_ops->get_ufo ?
1482 dev->ethtool_ops->get_ufo :
1483 ethtool_op_get_ufo));
e89e9cf5
AR
1484 break;
1485 case ETHTOOL_SUFO:
1486 rc = ethtool_set_ufo(dev, useraddr);
1487 break;
37c3185a
HX
1488 case ETHTOOL_GGSO:
1489 rc = ethtool_get_gso(dev, useraddr);
1490 break;
1491 case ETHTOOL_SGSO:
1492 rc = ethtool_set_gso(dev, useraddr);
1493 break;
3ae7c0b2 1494 case ETHTOOL_GFLAGS:
13c99b24 1495 rc = ethtool_get_value(dev, useraddr, ethcmd,
1896e61f
SS
1496 (dev->ethtool_ops->get_flags ?
1497 dev->ethtool_ops->get_flags :
1498 ethtool_op_get_flags));
3ae7c0b2
JG
1499 break;
1500 case ETHTOOL_SFLAGS:
13c99b24
JG
1501 rc = ethtool_set_value(dev, useraddr,
1502 dev->ethtool_ops->set_flags);
3ae7c0b2 1503 break;
339bf024 1504 case ETHTOOL_GPFLAGS:
13c99b24
JG
1505 rc = ethtool_get_value(dev, useraddr, ethcmd,
1506 dev->ethtool_ops->get_priv_flags);
339bf024
JG
1507 break;
1508 case ETHTOOL_SPFLAGS:
13c99b24
JG
1509 rc = ethtool_set_value(dev, useraddr,
1510 dev->ethtool_ops->set_priv_flags);
339bf024 1511 break;
0853ad66 1512 case ETHTOOL_GRXFH:
59089d8d
SB
1513 case ETHTOOL_GRXRINGS:
1514 case ETHTOOL_GRXCLSRLCNT:
1515 case ETHTOOL_GRXCLSRULE:
1516 case ETHTOOL_GRXCLSRLALL:
1517 rc = ethtool_get_rxnfc(dev, useraddr);
0853ad66
SB
1518 break;
1519 case ETHTOOL_SRXFH:
59089d8d
SB
1520 case ETHTOOL_SRXCLSRLDEL:
1521 case ETHTOOL_SRXCLSRLINS:
1522 rc = ethtool_set_rxnfc(dev, useraddr);
0853ad66 1523 break;
b240a0e5
HX
1524 case ETHTOOL_GGRO:
1525 rc = ethtool_get_gro(dev, useraddr);
1526 break;
1527 case ETHTOOL_SGRO:
1528 rc = ethtool_set_gro(dev, useraddr);
1529 break;
05c6a8d7
AK
1530 case ETHTOOL_FLASHDEV:
1531 rc = ethtool_flash_device(dev, useraddr);
1532 break;
d73d3a8c
BH
1533 case ETHTOOL_RESET:
1534 rc = ethtool_reset(dev, useraddr);
1535 break;
15682bc4
PWJ
1536 case ETHTOOL_SRXNTUPLE:
1537 rc = ethtool_set_rx_ntuple(dev, useraddr);
1538 break;
1539 case ETHTOOL_GRXNTUPLE:
1540 rc = ethtool_get_rx_ntuple(dev, useraddr);
1541 break;
723b2f57
JG
1542 case ETHTOOL_GSSET_INFO:
1543 rc = ethtool_get_sset_info(dev, useraddr);
1544 break;
1da177e4 1545 default:
61a44b9c 1546 rc = -EOPNOTSUPP;
1da177e4 1547 }
4ec93edb 1548
e71a4783 1549 if (dev->ethtool_ops->complete)
1da177e4 1550 dev->ethtool_ops->complete(dev);
d8a33ac4
SH
1551
1552 if (old_features != dev->features)
1553 netdev_features_change(dev);
1554
1da177e4 1555 return rc;
1da177e4
LT
1556}
1557
1da177e4
LT
1558EXPORT_SYMBOL(ethtool_op_get_link);
1559EXPORT_SYMBOL(ethtool_op_get_sg);
1560EXPORT_SYMBOL(ethtool_op_get_tso);
1da177e4
LT
1561EXPORT_SYMBOL(ethtool_op_set_sg);
1562EXPORT_SYMBOL(ethtool_op_set_tso);
1563EXPORT_SYMBOL(ethtool_op_set_tx_csum);
69f6a0fa 1564EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
6460d948 1565EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
e89e9cf5
AR
1566EXPORT_SYMBOL(ethtool_op_set_ufo);
1567EXPORT_SYMBOL(ethtool_op_get_ufo);
3ae7c0b2
JG
1568EXPORT_SYMBOL(ethtool_op_set_flags);
1569EXPORT_SYMBOL(ethtool_op_get_flags);
This page took 0.714441 seconds and 5 git commands to generate.