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