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