at v2.6.25-rc5 992 lines 23 kB view raw
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);