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