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