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