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