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