linux/net/core/ethtool.c
<<
>>
Prefs
   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
   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
  28u32 ethtool_op_get_link(struct net_device *dev)
  29{
  30        return netif_carrier_ok(dev) ? 1 : 0;
  31}
  32
  33u32 ethtool_op_get_tx_csum(struct net_device *dev)
  34{
  35        return (dev->features & NETIF_F_ALL_CSUM) != 0;
  36}
  37
  38int 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
  48int 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
  58int 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
  68u32 ethtool_op_get_sg(struct net_device *dev)
  69{
  70        return (dev->features & NETIF_F_SG) != 0;
  71}
  72
  73int 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
  83u32 ethtool_op_get_tso(struct net_device *dev)
  84{
  85        return (dev->features & NETIF_F_TSO) != 0;
  86}
  87
  88int 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
  98u32 ethtool_op_get_ufo(struct net_device *dev)
  99{
 100        return (dev->features & NETIF_F_UFO) != 0;
 101}
 102
 103int 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 */
 115static const u32 flags_dup_features =
 116        ETH_FLAG_LRO;
 117
 118u32 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
 128int 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
 140static 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
 157static 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
 170static 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
 212static 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
 248static 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
 262static 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
 275static 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
 283static 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
 328static 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
 369static 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
 383static 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
 396static 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
 410static 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
 423static 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
 437static 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
 450static 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
 468static 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
 488static 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
 505static 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
 521static 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
 536static 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
 546static 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
 559static 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
 603static 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
 660static 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
 673static 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
 717static 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
 736static 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
 751static 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
 766static 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
 782int 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
 980EXPORT_SYMBOL(ethtool_op_get_link);
 981EXPORT_SYMBOL(ethtool_op_get_sg);
 982EXPORT_SYMBOL(ethtool_op_get_tso);
 983EXPORT_SYMBOL(ethtool_op_get_tx_csum);
 984EXPORT_SYMBOL(ethtool_op_set_sg);
 985EXPORT_SYMBOL(ethtool_op_set_tso);
 986EXPORT_SYMBOL(ethtool_op_set_tx_csum);
 987EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
 988EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
 989EXPORT_SYMBOL(ethtool_op_set_ufo);
 990EXPORT_SYMBOL(ethtool_op_get_ufo);
 991EXPORT_SYMBOL(ethtool_op_set_flags);
 992EXPORT_SYMBOL(ethtool_op_get_flags);
 993