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