at v2.6.21 22 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_ALL_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 const 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 const 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 const 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 const 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->set_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_ALL_CSUM)) 555 return -EINVAL; 556 557 return __ethtool_set_sg(dev, edata.data); 558} 559 560static int ethtool_get_tso(struct net_device *dev, char __user *useraddr) 561{ 562 struct ethtool_value edata = { ETHTOOL_GTSO }; 563 564 if (!dev->ethtool_ops->get_tso) 565 return -EOPNOTSUPP; 566 567 edata.data = dev->ethtool_ops->get_tso(dev); 568 569 if (copy_to_user(useraddr, &edata, sizeof(edata))) 570 return -EFAULT; 571 return 0; 572} 573 574static int ethtool_set_tso(struct net_device *dev, char __user *useraddr) 575{ 576 struct ethtool_value edata; 577 578 if (!dev->ethtool_ops->set_tso) 579 return -EOPNOTSUPP; 580 581 if (copy_from_user(&edata, useraddr, sizeof(edata))) 582 return -EFAULT; 583 584 if (edata.data && !(dev->features & NETIF_F_SG)) 585 return -EINVAL; 586 587 return dev->ethtool_ops->set_tso(dev, edata.data); 588} 589 590static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr) 591{ 592 struct ethtool_value edata = { ETHTOOL_GUFO }; 593 594 if (!dev->ethtool_ops->get_ufo) 595 return -EOPNOTSUPP; 596 edata.data = dev->ethtool_ops->get_ufo(dev); 597 if (copy_to_user(useraddr, &edata, sizeof(edata))) 598 return -EFAULT; 599 return 0; 600} 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_get_gso(struct net_device *dev, char __user *useraddr) 618{ 619 struct ethtool_value edata = { ETHTOOL_GGSO }; 620 621 edata.data = dev->features & NETIF_F_GSO; 622 if (copy_to_user(useraddr, &edata, sizeof(edata))) 623 return -EFAULT; 624 return 0; 625} 626 627static int ethtool_set_gso(struct net_device *dev, char __user *useraddr) 628{ 629 struct ethtool_value edata; 630 631 if (copy_from_user(&edata, useraddr, sizeof(edata))) 632 return -EFAULT; 633 if (edata.data) 634 dev->features |= NETIF_F_GSO; 635 else 636 dev->features &= ~NETIF_F_GSO; 637 return 0; 638} 639 640static int ethtool_self_test(struct net_device *dev, char __user *useraddr) 641{ 642 struct ethtool_test test; 643 const struct ethtool_ops *ops = dev->ethtool_ops; 644 u64 *data; 645 int ret; 646 647 if (!ops->self_test || !ops->self_test_count) 648 return -EOPNOTSUPP; 649 650 if (copy_from_user(&test, useraddr, sizeof(test))) 651 return -EFAULT; 652 653 test.len = ops->self_test_count(dev); 654 data = kmalloc(test.len * sizeof(u64), GFP_USER); 655 if (!data) 656 return -ENOMEM; 657 658 ops->self_test(dev, &test, data); 659 660 ret = -EFAULT; 661 if (copy_to_user(useraddr, &test, sizeof(test))) 662 goto out; 663 useraddr += sizeof(test); 664 if (copy_to_user(useraddr, data, test.len * sizeof(u64))) 665 goto out; 666 ret = 0; 667 668 out: 669 kfree(data); 670 return ret; 671} 672 673static int ethtool_get_strings(struct net_device *dev, void __user *useraddr) 674{ 675 struct ethtool_gstrings gstrings; 676 const struct ethtool_ops *ops = dev->ethtool_ops; 677 u8 *data; 678 int ret; 679 680 if (!ops->get_strings) 681 return -EOPNOTSUPP; 682 683 if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) 684 return -EFAULT; 685 686 switch (gstrings.string_set) { 687 case ETH_SS_TEST: 688 if (!ops->self_test_count) 689 return -EOPNOTSUPP; 690 gstrings.len = ops->self_test_count(dev); 691 break; 692 case ETH_SS_STATS: 693 if (!ops->get_stats_count) 694 return -EOPNOTSUPP; 695 gstrings.len = ops->get_stats_count(dev); 696 break; 697 default: 698 return -EINVAL; 699 } 700 701 data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); 702 if (!data) 703 return -ENOMEM; 704 705 ops->get_strings(dev, gstrings.string_set, data); 706 707 ret = -EFAULT; 708 if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) 709 goto out; 710 useraddr += sizeof(gstrings); 711 if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN)) 712 goto out; 713 ret = 0; 714 715 out: 716 kfree(data); 717 return ret; 718} 719 720static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) 721{ 722 struct ethtool_value id; 723 724 if (!dev->ethtool_ops->phys_id) 725 return -EOPNOTSUPP; 726 727 if (copy_from_user(&id, useraddr, sizeof(id))) 728 return -EFAULT; 729 730 return dev->ethtool_ops->phys_id(dev, id.data); 731} 732 733static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) 734{ 735 struct ethtool_stats stats; 736 const struct ethtool_ops *ops = dev->ethtool_ops; 737 u64 *data; 738 int ret; 739 740 if (!ops->get_ethtool_stats || !ops->get_stats_count) 741 return -EOPNOTSUPP; 742 743 if (copy_from_user(&stats, useraddr, sizeof(stats))) 744 return -EFAULT; 745 746 stats.n_stats = ops->get_stats_count(dev); 747 data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER); 748 if (!data) 749 return -ENOMEM; 750 751 ops->get_ethtool_stats(dev, &stats, data); 752 753 ret = -EFAULT; 754 if (copy_to_user(useraddr, &stats, sizeof(stats))) 755 goto out; 756 useraddr += sizeof(stats); 757 if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64))) 758 goto out; 759 ret = 0; 760 761 out: 762 kfree(data); 763 return ret; 764} 765 766static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) 767{ 768 struct ethtool_perm_addr epaddr; 769 u8 *data; 770 int ret; 771 772 if (!dev->ethtool_ops->get_perm_addr) 773 return -EOPNOTSUPP; 774 775 if (copy_from_user(&epaddr,useraddr,sizeof(epaddr))) 776 return -EFAULT; 777 778 data = kmalloc(epaddr.size, GFP_USER); 779 if (!data) 780 return -ENOMEM; 781 782 ret = dev->ethtool_ops->get_perm_addr(dev,&epaddr,data); 783 if (ret) 784 return ret; 785 786 ret = -EFAULT; 787 if (copy_to_user(useraddr, &epaddr, sizeof(epaddr))) 788 goto out; 789 useraddr += sizeof(epaddr); 790 if (copy_to_user(useraddr, data, epaddr.size)) 791 goto out; 792 ret = 0; 793 794 out: 795 kfree(data); 796 return ret; 797} 798 799/* The main entry point in this file. Called from net/core/dev.c */ 800 801int dev_ethtool(struct ifreq *ifr) 802{ 803 struct net_device *dev = __dev_get_by_name(ifr->ifr_name); 804 void __user *useraddr = ifr->ifr_data; 805 u32 ethcmd; 806 int rc; 807 unsigned long old_features; 808 809 if (!dev || !netif_device_present(dev)) 810 return -ENODEV; 811 812 if (!dev->ethtool_ops) 813 goto ioctl; 814 815 if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd))) 816 return -EFAULT; 817 818 /* Allow some commands to be done by anyone */ 819 switch(ethcmd) { 820 case ETHTOOL_GDRVINFO: 821 case ETHTOOL_GMSGLVL: 822 case ETHTOOL_GCOALESCE: 823 case ETHTOOL_GRINGPARAM: 824 case ETHTOOL_GPAUSEPARAM: 825 case ETHTOOL_GRXCSUM: 826 case ETHTOOL_GTXCSUM: 827 case ETHTOOL_GSG: 828 case ETHTOOL_GSTRINGS: 829 case ETHTOOL_GTSO: 830 case ETHTOOL_GPERMADDR: 831 case ETHTOOL_GUFO: 832 case ETHTOOL_GGSO: 833 break; 834 default: 835 if (!capable(CAP_NET_ADMIN)) 836 return -EPERM; 837 } 838 839 if(dev->ethtool_ops->begin) 840 if ((rc = dev->ethtool_ops->begin(dev)) < 0) 841 return rc; 842 843 old_features = dev->features; 844 845 switch (ethcmd) { 846 case ETHTOOL_GSET: 847 rc = ethtool_get_settings(dev, useraddr); 848 break; 849 case ETHTOOL_SSET: 850 rc = ethtool_set_settings(dev, useraddr); 851 break; 852 case ETHTOOL_GDRVINFO: 853 rc = ethtool_get_drvinfo(dev, useraddr); 854 break; 855 case ETHTOOL_GREGS: 856 rc = ethtool_get_regs(dev, useraddr); 857 break; 858 case ETHTOOL_GWOL: 859 rc = ethtool_get_wol(dev, useraddr); 860 break; 861 case ETHTOOL_SWOL: 862 rc = ethtool_set_wol(dev, useraddr); 863 break; 864 case ETHTOOL_GMSGLVL: 865 rc = ethtool_get_msglevel(dev, useraddr); 866 break; 867 case ETHTOOL_SMSGLVL: 868 rc = ethtool_set_msglevel(dev, useraddr); 869 break; 870 case ETHTOOL_NWAY_RST: 871 rc = ethtool_nway_reset(dev); 872 break; 873 case ETHTOOL_GLINK: 874 rc = ethtool_get_link(dev, useraddr); 875 break; 876 case ETHTOOL_GEEPROM: 877 rc = ethtool_get_eeprom(dev, useraddr); 878 break; 879 case ETHTOOL_SEEPROM: 880 rc = ethtool_set_eeprom(dev, useraddr); 881 break; 882 case ETHTOOL_GCOALESCE: 883 rc = ethtool_get_coalesce(dev, useraddr); 884 break; 885 case ETHTOOL_SCOALESCE: 886 rc = ethtool_set_coalesce(dev, useraddr); 887 break; 888 case ETHTOOL_GRINGPARAM: 889 rc = ethtool_get_ringparam(dev, useraddr); 890 break; 891 case ETHTOOL_SRINGPARAM: 892 rc = ethtool_set_ringparam(dev, useraddr); 893 break; 894 case ETHTOOL_GPAUSEPARAM: 895 rc = ethtool_get_pauseparam(dev, useraddr); 896 break; 897 case ETHTOOL_SPAUSEPARAM: 898 rc = ethtool_set_pauseparam(dev, useraddr); 899 break; 900 case ETHTOOL_GRXCSUM: 901 rc = ethtool_get_rx_csum(dev, useraddr); 902 break; 903 case ETHTOOL_SRXCSUM: 904 rc = ethtool_set_rx_csum(dev, useraddr); 905 break; 906 case ETHTOOL_GTXCSUM: 907 rc = ethtool_get_tx_csum(dev, useraddr); 908 break; 909 case ETHTOOL_STXCSUM: 910 rc = ethtool_set_tx_csum(dev, useraddr); 911 break; 912 case ETHTOOL_GSG: 913 rc = ethtool_get_sg(dev, useraddr); 914 break; 915 case ETHTOOL_SSG: 916 rc = ethtool_set_sg(dev, useraddr); 917 break; 918 case ETHTOOL_GTSO: 919 rc = ethtool_get_tso(dev, useraddr); 920 break; 921 case ETHTOOL_STSO: 922 rc = ethtool_set_tso(dev, useraddr); 923 break; 924 case ETHTOOL_TEST: 925 rc = ethtool_self_test(dev, useraddr); 926 break; 927 case ETHTOOL_GSTRINGS: 928 rc = ethtool_get_strings(dev, useraddr); 929 break; 930 case ETHTOOL_PHYS_ID: 931 rc = ethtool_phys_id(dev, useraddr); 932 break; 933 case ETHTOOL_GSTATS: 934 rc = ethtool_get_stats(dev, useraddr); 935 break; 936 case ETHTOOL_GPERMADDR: 937 rc = ethtool_get_perm_addr(dev, useraddr); 938 break; 939 case ETHTOOL_GUFO: 940 rc = ethtool_get_ufo(dev, useraddr); 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 default: 952 rc = -EOPNOTSUPP; 953 } 954 955 if(dev->ethtool_ops->complete) 956 dev->ethtool_ops->complete(dev); 957 958 if (old_features != dev->features) 959 netdev_features_change(dev); 960 961 return rc; 962 963 ioctl: 964 /* Keep existing behaviour for the moment. */ 965 if (!capable(CAP_NET_ADMIN)) 966 return -EPERM; 967 968 if (dev->do_ioctl) 969 return dev->do_ioctl(dev, ifr, SIOCETHTOOL); 970 return -EOPNOTSUPP; 971} 972 973EXPORT_SYMBOL(dev_ethtool); 974EXPORT_SYMBOL(ethtool_op_get_link); 975EXPORT_SYMBOL_GPL(ethtool_op_get_perm_addr); 976EXPORT_SYMBOL(ethtool_op_get_sg); 977EXPORT_SYMBOL(ethtool_op_get_tso); 978EXPORT_SYMBOL(ethtool_op_get_tx_csum); 979EXPORT_SYMBOL(ethtool_op_set_sg); 980EXPORT_SYMBOL(ethtool_op_set_tso); 981EXPORT_SYMBOL(ethtool_op_set_tx_csum); 982EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum); 983EXPORT_SYMBOL(ethtool_op_set_ufo); 984EXPORT_SYMBOL(ethtool_op_get_ufo);