OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [net/] [core/] [ethtool.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
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
6
 * the information ethtool needs.
7
 *
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.
12
 */
13
 
14
#include <linux/module.h>
15
#include <linux/types.h>
16
#include <linux/capability.h>
17
#include <linux/errno.h>
18
#include <linux/ethtool.h>
19
#include <linux/netdevice.h>
20
#include <asm/uaccess.h>
21
 
22
/*
23
 * Some useful ethtool_ops methods that're device independent.
24
 * If we find that all drivers want to do the same thing here,
25
 * we can turn these into dev_() function calls.
26
 */
27
 
28
u32 ethtool_op_get_link(struct net_device *dev)
29
{
30
        return netif_carrier_ok(dev) ? 1 : 0;
31
}
32
 
33
u32 ethtool_op_get_tx_csum(struct net_device *dev)
34
{
35
        return (dev->features & NETIF_F_ALL_CSUM) != 0;
36
}
37
 
38
int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
39
{
40
        if (data)
41
                dev->features |= NETIF_F_IP_CSUM;
42
        else
43
                dev->features &= ~NETIF_F_IP_CSUM;
44
 
45
        return 0;
46
}
47
 
48
int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data)
49
{
50
        if (data)
51
                dev->features |= NETIF_F_HW_CSUM;
52
        else
53
                dev->features &= ~NETIF_F_HW_CSUM;
54
 
55
        return 0;
56
}
57
 
58
int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
59
{
60
        if (data)
61
                dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
62
        else
63
                dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
64
 
65
        return 0;
66
}
67
 
68
u32 ethtool_op_get_sg(struct net_device *dev)
69
{
70
        return (dev->features & NETIF_F_SG) != 0;
71
}
72
 
73
int ethtool_op_set_sg(struct net_device *dev, u32 data)
74
{
75
        if (data)
76
                dev->features |= NETIF_F_SG;
77
        else
78
                dev->features &= ~NETIF_F_SG;
79
 
80
        return 0;
81
}
82
 
83
u32 ethtool_op_get_tso(struct net_device *dev)
84
{
85
        return (dev->features & NETIF_F_TSO) != 0;
86
}
87
 
88
int ethtool_op_set_tso(struct net_device *dev, u32 data)
89
{
90
        if (data)
91
                dev->features |= NETIF_F_TSO;
92
        else
93
                dev->features &= ~NETIF_F_TSO;
94
 
95
        return 0;
96
}
97
 
98
u32 ethtool_op_get_ufo(struct net_device *dev)
99
{
100
        return (dev->features & NETIF_F_UFO) != 0;
101
}
102
 
103
int ethtool_op_set_ufo(struct net_device *dev, u32 data)
104
{
105
        if (data)
106
                dev->features |= NETIF_F_UFO;
107
        else
108
                dev->features &= ~NETIF_F_UFO;
109
        return 0;
110
}
111
 
112
/* the following list of flags are the same as their associated
113
 * NETIF_F_xxx values in include/linux/netdevice.h
114
 */
115
static const u32 flags_dup_features =
116
        ETH_FLAG_LRO;
117
 
118
u32 ethtool_op_get_flags(struct net_device *dev)
119
{
120
        /* in the future, this function will probably contain additional
121
         * handling for flags which are not so easily handled
122
         * by a simple masking operation
123
         */
124
 
125
        return dev->features & flags_dup_features;
126
}
127
 
128
int ethtool_op_set_flags(struct net_device *dev, u32 data)
129
{
130
        if (data & ETH_FLAG_LRO)
131
                dev->features |= NETIF_F_LRO;
132
        else
133
                dev->features &= ~NETIF_F_LRO;
134
 
135
        return 0;
136
}
137
 
138
/* Handlers for each ethtool command */
139
 
140
static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
141
{
142
        struct ethtool_cmd cmd = { ETHTOOL_GSET };
143
        int err;
144
 
145
        if (!dev->ethtool_ops->get_settings)
146
                return -EOPNOTSUPP;
147
 
148
        err = dev->ethtool_ops->get_settings(dev, &cmd);
149
        if (err < 0)
150
                return err;
151
 
152
        if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
153
                return -EFAULT;
154
        return 0;
155
}
156
 
157
static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
158
{
159
        struct ethtool_cmd cmd;
160
 
161
        if (!dev->ethtool_ops->set_settings)
162
                return -EOPNOTSUPP;
163
 
164
        if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
165
                return -EFAULT;
166
 
167
        return dev->ethtool_ops->set_settings(dev, &cmd);
168
}
169
 
170
static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
171
{
172
        struct ethtool_drvinfo info;
173
        const struct ethtool_ops *ops = dev->ethtool_ops;
174
 
175
        if (!ops->get_drvinfo)
176
                return -EOPNOTSUPP;
177
 
178
        memset(&info, 0, sizeof(info));
179
        info.cmd = ETHTOOL_GDRVINFO;
180
        ops->get_drvinfo(dev, &info);
181
 
182
        if (ops->get_sset_count) {
183
                int rc;
184
 
185
                rc = ops->get_sset_count(dev, ETH_SS_TEST);
186
                if (rc >= 0)
187
                        info.testinfo_len = rc;
188
                rc = ops->get_sset_count(dev, ETH_SS_STATS);
189
                if (rc >= 0)
190
                        info.n_stats = rc;
191
                rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
192
                if (rc >= 0)
193
                        info.n_priv_flags = rc;
194
        } else {
195
                /* code path for obsolete hooks */
196
 
197
                if (ops->self_test_count)
198
                        info.testinfo_len = ops->self_test_count(dev);
199
                if (ops->get_stats_count)
200
                        info.n_stats = ops->get_stats_count(dev);
201
        }
202
        if (ops->get_regs_len)
203
                info.regdump_len = ops->get_regs_len(dev);
204
        if (ops->get_eeprom_len)
205
                info.eedump_len = ops->get_eeprom_len(dev);
206
 
207
        if (copy_to_user(useraddr, &info, sizeof(info)))
208
                return -EFAULT;
209
        return 0;
210
}
211
 
212
static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
213
{
214
        struct ethtool_regs regs;
215
        const struct ethtool_ops *ops = dev->ethtool_ops;
216
        void *regbuf;
217
        int reglen, ret;
218
 
219
        if (!ops->get_regs || !ops->get_regs_len)
220
                return -EOPNOTSUPP;
221
 
222
        if (copy_from_user(&regs, useraddr, sizeof(regs)))
223
                return -EFAULT;
224
 
225
        reglen = ops->get_regs_len(dev);
226
        if (regs.len > reglen)
227
                regs.len = reglen;
228
 
229
        regbuf = kmalloc(reglen, GFP_USER);
230
        if (!regbuf)
231
                return -ENOMEM;
232
 
233
        ops->get_regs(dev, &regs, regbuf);
234
 
235
        ret = -EFAULT;
236
        if (copy_to_user(useraddr, &regs, sizeof(regs)))
237
                goto out;
238
        useraddr += offsetof(struct ethtool_regs, data);
239
        if (copy_to_user(useraddr, regbuf, regs.len))
240
                goto out;
241
        ret = 0;
242
 
243
 out:
244
        kfree(regbuf);
245
        return ret;
246
}
247
 
248
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
249
{
250
        struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
251
 
252
        if (!dev->ethtool_ops->get_wol)
253
                return -EOPNOTSUPP;
254
 
255
        dev->ethtool_ops->get_wol(dev, &wol);
256
 
257
        if (copy_to_user(useraddr, &wol, sizeof(wol)))
258
                return -EFAULT;
259
        return 0;
260
}
261
 
262
static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
263
{
264
        struct ethtool_wolinfo wol;
265
 
266
        if (!dev->ethtool_ops->set_wol)
267
                return -EOPNOTSUPP;
268
 
269
        if (copy_from_user(&wol, useraddr, sizeof(wol)))
270
                return -EFAULT;
271
 
272
        return dev->ethtool_ops->set_wol(dev, &wol);
273
}
274
 
275
static int ethtool_nway_reset(struct net_device *dev)
276
{
277
        if (!dev->ethtool_ops->nway_reset)
278
                return -EOPNOTSUPP;
279
 
280
        return dev->ethtool_ops->nway_reset(dev);
281
}
282
 
283
static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
284
{
285
        struct ethtool_eeprom eeprom;
286
        const struct ethtool_ops *ops = dev->ethtool_ops;
287
        u8 *data;
288
        int ret;
289
 
290
        if (!ops->get_eeprom || !ops->get_eeprom_len)
291
                return -EOPNOTSUPP;
292
 
293
        if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
294
                return -EFAULT;
295
 
296
        /* Check for wrap and zero */
297
        if (eeprom.offset + eeprom.len <= eeprom.offset)
298
                return -EINVAL;
299
 
300
        /* Check for exceeding total eeprom len */
301
        if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
302
                return -EINVAL;
303
 
304
        data = kmalloc(eeprom.len, GFP_USER);
305
        if (!data)
306
                return -ENOMEM;
307
 
308
        ret = -EFAULT;
309
        if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
310
                goto out;
311
 
312
        ret = ops->get_eeprom(dev, &eeprom, data);
313
        if (ret)
314
                goto out;
315
 
316
        ret = -EFAULT;
317
        if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
318
                goto out;
319
        if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
320
                goto out;
321
        ret = 0;
322
 
323
 out:
324
        kfree(data);
325
        return ret;
326
}
327
 
328
static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
329
{
330
        struct ethtool_eeprom eeprom;
331
        const struct ethtool_ops *ops = dev->ethtool_ops;
332
        u8 *data;
333
        int ret;
334
 
335
        if (!ops->set_eeprom || !ops->get_eeprom_len)
336
                return -EOPNOTSUPP;
337
 
338
        if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
339
                return -EFAULT;
340
 
341
        /* Check for wrap and zero */
342
        if (eeprom.offset + eeprom.len <= eeprom.offset)
343
                return -EINVAL;
344
 
345
        /* Check for exceeding total eeprom len */
346
        if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
347
                return -EINVAL;
348
 
349
        data = kmalloc(eeprom.len, GFP_USER);
350
        if (!data)
351
                return -ENOMEM;
352
 
353
        ret = -EFAULT;
354
        if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
355
                goto out;
356
 
357
        ret = ops->set_eeprom(dev, &eeprom, data);
358
        if (ret)
359
                goto out;
360
 
361
        if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
362
                ret = -EFAULT;
363
 
364
 out:
365
        kfree(data);
366
        return ret;
367
}
368
 
369
static int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr)
370
{
371
        struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE };
372
 
373
        if (!dev->ethtool_ops->get_coalesce)
374
                return -EOPNOTSUPP;
375
 
376
        dev->ethtool_ops->get_coalesce(dev, &coalesce);
377
 
378
        if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
379
                return -EFAULT;
380
        return 0;
381
}
382
 
383
static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)
384
{
385
        struct ethtool_coalesce coalesce;
386
 
387
        if (!dev->ethtool_ops->set_coalesce)
388
                return -EOPNOTSUPP;
389
 
390
        if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
391
                return -EFAULT;
392
 
393
        return dev->ethtool_ops->set_coalesce(dev, &coalesce);
394
}
395
 
396
static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
397
{
398
        struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM };
399
 
400
        if (!dev->ethtool_ops->get_ringparam)
401
                return -EOPNOTSUPP;
402
 
403
        dev->ethtool_ops->get_ringparam(dev, &ringparam);
404
 
405
        if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
406
                return -EFAULT;
407
        return 0;
408
}
409
 
410
static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
411
{
412
        struct ethtool_ringparam ringparam;
413
 
414
        if (!dev->ethtool_ops->set_ringparam)
415
                return -EOPNOTSUPP;
416
 
417
        if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
418
                return -EFAULT;
419
 
420
        return dev->ethtool_ops->set_ringparam(dev, &ringparam);
421
}
422
 
423
static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
424
{
425
        struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
426
 
427
        if (!dev->ethtool_ops->get_pauseparam)
428
                return -EOPNOTSUPP;
429
 
430
        dev->ethtool_ops->get_pauseparam(dev, &pauseparam);
431
 
432
        if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
433
                return -EFAULT;
434
        return 0;
435
}
436
 
437
static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
438
{
439
        struct ethtool_pauseparam pauseparam;
440
 
441
        if (!dev->ethtool_ops->set_pauseparam)
442
                return -EOPNOTSUPP;
443
 
444
        if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
445
                return -EFAULT;
446
 
447
        return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
448
}
449
 
450
static int __ethtool_set_sg(struct net_device *dev, u32 data)
451
{
452
        int err;
453
 
454
        if (!data && dev->ethtool_ops->set_tso) {
455
                err = dev->ethtool_ops->set_tso(dev, 0);
456
                if (err)
457
                        return err;
458
        }
459
 
460
        if (!data && dev->ethtool_ops->set_ufo) {
461
                err = dev->ethtool_ops->set_ufo(dev, 0);
462
                if (err)
463
                        return err;
464
        }
465
        return dev->ethtool_ops->set_sg(dev, data);
466
}
467
 
468
static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr)
469
{
470
        struct ethtool_value edata;
471
        int err;
472
 
473
        if (!dev->ethtool_ops->set_tx_csum)
474
                return -EOPNOTSUPP;
475
 
476
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
477
                return -EFAULT;
478
 
479
        if (!edata.data && dev->ethtool_ops->set_sg) {
480
                err = __ethtool_set_sg(dev, 0);
481
                if (err)
482
                        return err;
483
        }
484
 
485
        return dev->ethtool_ops->set_tx_csum(dev, edata.data);
486
}
487
 
488
static int ethtool_set_sg(struct net_device *dev, char __user *useraddr)
489
{
490
        struct ethtool_value edata;
491
 
492
        if (!dev->ethtool_ops->set_sg)
493
                return -EOPNOTSUPP;
494
 
495
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
496
                return -EFAULT;
497
 
498
        if (edata.data &&
499
            !(dev->features & NETIF_F_ALL_CSUM))
500
                return -EINVAL;
501
 
502
        return __ethtool_set_sg(dev, edata.data);
503
}
504
 
505
static int ethtool_set_tso(struct net_device *dev, char __user *useraddr)
506
{
507
        struct ethtool_value edata;
508
 
509
        if (!dev->ethtool_ops->set_tso)
510
                return -EOPNOTSUPP;
511
 
512
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
513
                return -EFAULT;
514
 
515
        if (edata.data && !(dev->features & NETIF_F_SG))
516
                return -EINVAL;
517
 
518
        return dev->ethtool_ops->set_tso(dev, edata.data);
519
}
520
 
521
static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
522
{
523
        struct ethtool_value edata;
524
 
525
        if (!dev->ethtool_ops->set_ufo)
526
                return -EOPNOTSUPP;
527
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
528
                return -EFAULT;
529
        if (edata.data && !(dev->features & NETIF_F_SG))
530
                return -EINVAL;
531
        if (edata.data && !(dev->features & NETIF_F_HW_CSUM))
532
                return -EINVAL;
533
        return dev->ethtool_ops->set_ufo(dev, edata.data);
534
}
535
 
536
static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
537
{
538
        struct ethtool_value edata = { ETHTOOL_GGSO };
539
 
540
        edata.data = dev->features & NETIF_F_GSO;
541
        if (copy_to_user(useraddr, &edata, sizeof(edata)))
542
                 return -EFAULT;
543
        return 0;
544
}
545
 
546
static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
547
{
548
        struct ethtool_value edata;
549
 
550
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
551
                return -EFAULT;
552
        if (edata.data)
553
                dev->features |= NETIF_F_GSO;
554
        else
555
                dev->features &= ~NETIF_F_GSO;
556
        return 0;
557
}
558
 
559
static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
560
{
561
        struct ethtool_test test;
562
        const struct ethtool_ops *ops = dev->ethtool_ops;
563
        u64 *data;
564
        int ret, test_len;
565
 
566
        if (!ops->self_test)
567
                return -EOPNOTSUPP;
568
        if (!ops->get_sset_count && !ops->self_test_count)
569
                return -EOPNOTSUPP;
570
 
571
        if (ops->get_sset_count)
572
                test_len = ops->get_sset_count(dev, ETH_SS_TEST);
573
        else
574
                /* code path for obsolete hook */
575
                test_len = ops->self_test_count(dev);
576
        if (test_len < 0)
577
                return test_len;
578
        WARN_ON(test_len == 0);
579
 
580
        if (copy_from_user(&test, useraddr, sizeof(test)))
581
                return -EFAULT;
582
 
583
        test.len = test_len;
584
        data = kmalloc(test_len * sizeof(u64), GFP_USER);
585
        if (!data)
586
                return -ENOMEM;
587
 
588
        ops->self_test(dev, &test, data);
589
 
590
        ret = -EFAULT;
591
        if (copy_to_user(useraddr, &test, sizeof(test)))
592
                goto out;
593
        useraddr += sizeof(test);
594
        if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
595
                goto out;
596
        ret = 0;
597
 
598
 out:
599
        kfree(data);
600
        return ret;
601
}
602
 
603
static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
604
{
605
        struct ethtool_gstrings gstrings;
606
        const struct ethtool_ops *ops = dev->ethtool_ops;
607
        u8 *data;
608
        int ret;
609
 
610
        if (!ops->get_strings)
611
                return -EOPNOTSUPP;
612
 
613
        if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
614
                return -EFAULT;
615
 
616
        if (ops->get_sset_count) {
617
                ret = ops->get_sset_count(dev, gstrings.string_set);
618
                if (ret < 0)
619
                        return ret;
620
 
621
                gstrings.len = ret;
622
        } else {
623
                /* code path for obsolete hooks */
624
 
625
                switch (gstrings.string_set) {
626
                case ETH_SS_TEST:
627
                        if (!ops->self_test_count)
628
                                return -EOPNOTSUPP;
629
                        gstrings.len = ops->self_test_count(dev);
630
                        break;
631
                case ETH_SS_STATS:
632
                        if (!ops->get_stats_count)
633
                                return -EOPNOTSUPP;
634
                        gstrings.len = ops->get_stats_count(dev);
635
                        break;
636
                default:
637
                        return -EINVAL;
638
                }
639
        }
640
 
641
        data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
642
        if (!data)
643
                return -ENOMEM;
644
 
645
        ops->get_strings(dev, gstrings.string_set, data);
646
 
647
        ret = -EFAULT;
648
        if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
649
                goto out;
650
        useraddr += sizeof(gstrings);
651
        if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
652
                goto out;
653
        ret = 0;
654
 
655
 out:
656
        kfree(data);
657
        return ret;
658
}
659
 
660
static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
661
{
662
        struct ethtool_value id;
663
 
664
        if (!dev->ethtool_ops->phys_id)
665
                return -EOPNOTSUPP;
666
 
667
        if (copy_from_user(&id, useraddr, sizeof(id)))
668
                return -EFAULT;
669
 
670
        return dev->ethtool_ops->phys_id(dev, id.data);
671
}
672
 
673
static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
674
{
675
        struct ethtool_stats stats;
676
        const struct ethtool_ops *ops = dev->ethtool_ops;
677
        u64 *data;
678
        int ret, n_stats;
679
 
680
        if (!ops->get_ethtool_stats)
681
                return -EOPNOTSUPP;
682
        if (!ops->get_sset_count && !ops->get_stats_count)
683
                return -EOPNOTSUPP;
684
 
685
        if (ops->get_sset_count)
686
                n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
687
        else
688
                /* code path for obsolete hook */
689
                n_stats = ops->get_stats_count(dev);
690
        if (n_stats < 0)
691
                return n_stats;
692
        WARN_ON(n_stats == 0);
693
 
694
        if (copy_from_user(&stats, useraddr, sizeof(stats)))
695
                return -EFAULT;
696
 
697
        stats.n_stats = n_stats;
698
        data = kmalloc(n_stats * sizeof(u64), GFP_USER);
699
        if (!data)
700
                return -ENOMEM;
701
 
702
        ops->get_ethtool_stats(dev, &stats, data);
703
 
704
        ret = -EFAULT;
705
        if (copy_to_user(useraddr, &stats, sizeof(stats)))
706
                goto out;
707
        useraddr += sizeof(stats);
708
        if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
709
                goto out;
710
        ret = 0;
711
 
712
 out:
713
        kfree(data);
714
        return ret;
715
}
716
 
717
static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
718
{
719
        struct ethtool_perm_addr epaddr;
720
 
721
        if (copy_from_user(&epaddr, useraddr, sizeof(epaddr)))
722
                return -EFAULT;
723
 
724
        if (epaddr.size < dev->addr_len)
725
                return -ETOOSMALL;
726
        epaddr.size = dev->addr_len;
727
 
728
        if (copy_to_user(useraddr, &epaddr, sizeof(epaddr)))
729
                return -EFAULT;
730
        useraddr += sizeof(epaddr);
731
        if (copy_to_user(useraddr, dev->perm_addr, epaddr.size))
732
                return -EFAULT;
733
        return 0;
734
}
735
 
736
static int ethtool_get_value(struct net_device *dev, char __user *useraddr,
737
                             u32 cmd, u32 (*actor)(struct net_device *))
738
{
739
        struct ethtool_value edata = { cmd };
740
 
741
        if (!actor)
742
                return -EOPNOTSUPP;
743
 
744
        edata.data = actor(dev);
745
 
746
        if (copy_to_user(useraddr, &edata, sizeof(edata)))
747
                return -EFAULT;
748
        return 0;
749
}
750
 
751
static int ethtool_set_value_void(struct net_device *dev, char __user *useraddr,
752
                             void (*actor)(struct net_device *, u32))
753
{
754
        struct ethtool_value edata;
755
 
756
        if (!actor)
757
                return -EOPNOTSUPP;
758
 
759
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
760
                return -EFAULT;
761
 
762
        actor(dev, edata.data);
763
        return 0;
764
}
765
 
766
static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
767
                             int (*actor)(struct net_device *, u32))
768
{
769
        struct ethtool_value edata;
770
 
771
        if (!actor)
772
                return -EOPNOTSUPP;
773
 
774
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
775
                return -EFAULT;
776
 
777
        return actor(dev, edata.data);
778
}
779
 
780
/* The main entry point in this file.  Called from net/core/dev.c */
781
 
782
int dev_ethtool(struct net *net, struct ifreq *ifr)
783
{
784
        struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
785
        void __user *useraddr = ifr->ifr_data;
786
        u32 ethcmd;
787
        int rc;
788
        unsigned long old_features;
789
 
790
        if (!dev || !netif_device_present(dev))
791
                return -ENODEV;
792
 
793
        if (!dev->ethtool_ops)
794
                return -EOPNOTSUPP;
795
 
796
        if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
797
                return -EFAULT;
798
 
799
        /* Allow some commands to be done by anyone */
800
        switch(ethcmd) {
801
        case ETHTOOL_GDRVINFO:
802
        case ETHTOOL_GMSGLVL:
803
        case ETHTOOL_GCOALESCE:
804
        case ETHTOOL_GRINGPARAM:
805
        case ETHTOOL_GPAUSEPARAM:
806
        case ETHTOOL_GRXCSUM:
807
        case ETHTOOL_GTXCSUM:
808
        case ETHTOOL_GSG:
809
        case ETHTOOL_GSTRINGS:
810
        case ETHTOOL_GTSO:
811
        case ETHTOOL_GPERMADDR:
812
        case ETHTOOL_GUFO:
813
        case ETHTOOL_GGSO:
814
        case ETHTOOL_GFLAGS:
815
        case ETHTOOL_GPFLAGS:
816
                break;
817
        default:
818
                if (!capable(CAP_NET_ADMIN))
819
                        return -EPERM;
820
        }
821
 
822
        if (dev->ethtool_ops->begin)
823
                if ((rc = dev->ethtool_ops->begin(dev)) < 0)
824
                        return rc;
825
 
826
        old_features = dev->features;
827
 
828
        switch (ethcmd) {
829
        case ETHTOOL_GSET:
830
                rc = ethtool_get_settings(dev, useraddr);
831
                break;
832
        case ETHTOOL_SSET:
833
                rc = ethtool_set_settings(dev, useraddr);
834
                break;
835
        case ETHTOOL_GDRVINFO:
836
                rc = ethtool_get_drvinfo(dev, useraddr);
837
                break;
838
        case ETHTOOL_GREGS:
839
                rc = ethtool_get_regs(dev, useraddr);
840
                break;
841
        case ETHTOOL_GWOL:
842
                rc = ethtool_get_wol(dev, useraddr);
843
                break;
844
        case ETHTOOL_SWOL:
845
                rc = ethtool_set_wol(dev, useraddr);
846
                break;
847
        case ETHTOOL_GMSGLVL:
848
                rc = ethtool_get_value(dev, useraddr, ethcmd,
849
                                       dev->ethtool_ops->get_msglevel);
850
                break;
851
        case ETHTOOL_SMSGLVL:
852
                rc = ethtool_set_value_void(dev, useraddr,
853
                                       dev->ethtool_ops->set_msglevel);
854
                break;
855
        case ETHTOOL_NWAY_RST:
856
                rc = ethtool_nway_reset(dev);
857
                break;
858
        case ETHTOOL_GLINK:
859
                rc = ethtool_get_value(dev, useraddr, ethcmd,
860
                                       dev->ethtool_ops->get_link);
861
                break;
862
        case ETHTOOL_GEEPROM:
863
                rc = ethtool_get_eeprom(dev, useraddr);
864
                break;
865
        case ETHTOOL_SEEPROM:
866
                rc = ethtool_set_eeprom(dev, useraddr);
867
                break;
868
        case ETHTOOL_GCOALESCE:
869
                rc = ethtool_get_coalesce(dev, useraddr);
870
                break;
871
        case ETHTOOL_SCOALESCE:
872
                rc = ethtool_set_coalesce(dev, useraddr);
873
                break;
874
        case ETHTOOL_GRINGPARAM:
875
                rc = ethtool_get_ringparam(dev, useraddr);
876
                break;
877
        case ETHTOOL_SRINGPARAM:
878
                rc = ethtool_set_ringparam(dev, useraddr);
879
                break;
880
        case ETHTOOL_GPAUSEPARAM:
881
                rc = ethtool_get_pauseparam(dev, useraddr);
882
                break;
883
        case ETHTOOL_SPAUSEPARAM:
884
                rc = ethtool_set_pauseparam(dev, useraddr);
885
                break;
886
        case ETHTOOL_GRXCSUM:
887
                rc = ethtool_get_value(dev, useraddr, ethcmd,
888
                                       dev->ethtool_ops->get_rx_csum);
889
                break;
890
        case ETHTOOL_SRXCSUM:
891
                rc = ethtool_set_value(dev, useraddr,
892
                                       dev->ethtool_ops->set_rx_csum);
893
                break;
894
        case ETHTOOL_GTXCSUM:
895
                rc = ethtool_get_value(dev, useraddr, ethcmd,
896
                                       (dev->ethtool_ops->get_tx_csum ?
897
                                        dev->ethtool_ops->get_tx_csum :
898
                                        ethtool_op_get_tx_csum));
899
                break;
900
        case ETHTOOL_STXCSUM:
901
                rc = ethtool_set_tx_csum(dev, useraddr);
902
                break;
903
        case ETHTOOL_GSG:
904
                rc = ethtool_get_value(dev, useraddr, ethcmd,
905
                                       (dev->ethtool_ops->get_sg ?
906
                                        dev->ethtool_ops->get_sg :
907
                                        ethtool_op_get_sg));
908
                break;
909
        case ETHTOOL_SSG:
910
                rc = ethtool_set_sg(dev, useraddr);
911
                break;
912
        case ETHTOOL_GTSO:
913
                rc = ethtool_get_value(dev, useraddr, ethcmd,
914
                                       (dev->ethtool_ops->get_tso ?
915
                                        dev->ethtool_ops->get_tso :
916
                                        ethtool_op_get_tso));
917
                break;
918
        case ETHTOOL_STSO:
919
                rc = ethtool_set_tso(dev, useraddr);
920
                break;
921
        case ETHTOOL_TEST:
922
                rc = ethtool_self_test(dev, useraddr);
923
                break;
924
        case ETHTOOL_GSTRINGS:
925
                rc = ethtool_get_strings(dev, useraddr);
926
                break;
927
        case ETHTOOL_PHYS_ID:
928
                rc = ethtool_phys_id(dev, useraddr);
929
                break;
930
        case ETHTOOL_GSTATS:
931
                rc = ethtool_get_stats(dev, useraddr);
932
                break;
933
        case ETHTOOL_GPERMADDR:
934
                rc = ethtool_get_perm_addr(dev, useraddr);
935
                break;
936
        case ETHTOOL_GUFO:
937
                rc = ethtool_get_value(dev, useraddr, ethcmd,
938
                                       (dev->ethtool_ops->get_ufo ?
939
                                        dev->ethtool_ops->get_ufo :
940
                                        ethtool_op_get_ufo));
941
                break;
942
        case ETHTOOL_SUFO:
943
                rc = ethtool_set_ufo(dev, useraddr);
944
                break;
945
        case ETHTOOL_GGSO:
946
                rc = ethtool_get_gso(dev, useraddr);
947
                break;
948
        case ETHTOOL_SGSO:
949
                rc = ethtool_set_gso(dev, useraddr);
950
                break;
951
        case ETHTOOL_GFLAGS:
952
                rc = ethtool_get_value(dev, useraddr, ethcmd,
953
                                       dev->ethtool_ops->get_flags);
954
                break;
955
        case ETHTOOL_SFLAGS:
956
                rc = ethtool_set_value(dev, useraddr,
957
                                       dev->ethtool_ops->set_flags);
958
                break;
959
        case ETHTOOL_GPFLAGS:
960
                rc = ethtool_get_value(dev, useraddr, ethcmd,
961
                                       dev->ethtool_ops->get_priv_flags);
962
                break;
963
        case ETHTOOL_SPFLAGS:
964
                rc = ethtool_set_value(dev, useraddr,
965
                                       dev->ethtool_ops->set_priv_flags);
966
                break;
967
        default:
968
                rc = -EOPNOTSUPP;
969
        }
970
 
971
        if (dev->ethtool_ops->complete)
972
                dev->ethtool_ops->complete(dev);
973
 
974
        if (old_features != dev->features)
975
                netdev_features_change(dev);
976
 
977
        return rc;
978
}
979
 
980
EXPORT_SYMBOL(ethtool_op_get_link);
981
EXPORT_SYMBOL(ethtool_op_get_sg);
982
EXPORT_SYMBOL(ethtool_op_get_tso);
983
EXPORT_SYMBOL(ethtool_op_get_tx_csum);
984
EXPORT_SYMBOL(ethtool_op_set_sg);
985
EXPORT_SYMBOL(ethtool_op_set_tso);
986
EXPORT_SYMBOL(ethtool_op_set_tx_csum);
987
EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
988
EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
989
EXPORT_SYMBOL(ethtool_op_set_ufo);
990
EXPORT_SYMBOL(ethtool_op_get_ufo);
991
EXPORT_SYMBOL(ethtool_op_set_flags);
992
EXPORT_SYMBOL(ethtool_op_get_flags);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.