diff options
| -rw-r--r-- | include/linux/ethtool.h | 15 | ||||
| -rw-r--r-- | net/core/ethtool.c | 80 |
2 files changed, 95 insertions, 0 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 084ddb3c8032..c1be61f3938b 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h | |||
| @@ -384,6 +384,15 @@ struct ethtool_rxnfc { | |||
| 384 | __u32 rule_locs[0]; | 384 | __u32 rule_locs[0]; |
| 385 | }; | 385 | }; |
| 386 | 386 | ||
| 387 | struct ethtool_rxfh_indir { | ||
| 388 | __u32 cmd; | ||
| 389 | /* On entry, this is the array size of the user buffer. On | ||
| 390 | * return from ETHTOOL_GRXFHINDIR, this is the array size of | ||
| 391 | * the hardware indirection table. */ | ||
| 392 | __u32 size; | ||
| 393 | __u32 ring_index[0]; /* ring/queue index for each hash value */ | ||
| 394 | }; | ||
| 395 | |||
| 387 | struct ethtool_rx_ntuple_flow_spec { | 396 | struct ethtool_rx_ntuple_flow_spec { |
| 388 | __u32 flow_type; | 397 | __u32 flow_type; |
| 389 | union { | 398 | union { |
| @@ -576,6 +585,10 @@ struct ethtool_ops { | |||
| 576 | int (*set_rx_ntuple)(struct net_device *, | 585 | int (*set_rx_ntuple)(struct net_device *, |
| 577 | struct ethtool_rx_ntuple *); | 586 | struct ethtool_rx_ntuple *); |
| 578 | int (*get_rx_ntuple)(struct net_device *, u32 stringset, void *); | 587 | int (*get_rx_ntuple)(struct net_device *, u32 stringset, void *); |
| 588 | int (*get_rxfh_indir)(struct net_device *, | ||
| 589 | struct ethtool_rxfh_indir *); | ||
| 590 | int (*set_rxfh_indir)(struct net_device *, | ||
| 591 | const struct ethtool_rxfh_indir *); | ||
| 579 | }; | 592 | }; |
| 580 | #endif /* __KERNEL__ */ | 593 | #endif /* __KERNEL__ */ |
| 581 | 594 | ||
| @@ -637,6 +650,8 @@ struct ethtool_ops { | |||
| 637 | #define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */ | 650 | #define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */ |
| 638 | #define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */ | 651 | #define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */ |
| 639 | #define ETHTOOL_GSSET_INFO 0x00000037 /* Get string set info */ | 652 | #define ETHTOOL_GSSET_INFO 0x00000037 /* Get string set info */ |
| 653 | #define ETHTOOL_GRXFHINDIR 0x00000038 /* Get RX flow hash indir'n table */ | ||
| 654 | #define ETHTOOL_SRXFHINDIR 0x00000039 /* Set RX flow hash indir'n table */ | ||
| 640 | 655 | ||
| 641 | /* compatibility with older code */ | 656 | /* compatibility with older code */ |
| 642 | #define SPARC_ETH_GSET ETHTOOL_GSET | 657 | #define SPARC_ETH_GSET ETHTOOL_GSET |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 5d42fae520d9..072d1d3796cb 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
| @@ -358,6 +358,80 @@ err_out: | |||
| 358 | return ret; | 358 | return ret; |
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, | ||
| 362 | void __user *useraddr) | ||
| 363 | { | ||
| 364 | struct ethtool_rxfh_indir *indir; | ||
| 365 | u32 table_size; | ||
| 366 | size_t full_size; | ||
| 367 | int ret; | ||
| 368 | |||
| 369 | if (!dev->ethtool_ops->get_rxfh_indir) | ||
| 370 | return -EOPNOTSUPP; | ||
| 371 | |||
| 372 | if (copy_from_user(&table_size, | ||
| 373 | useraddr + offsetof(struct ethtool_rxfh_indir, size), | ||
| 374 | sizeof(table_size))) | ||
| 375 | return -EFAULT; | ||
| 376 | |||
| 377 | if (table_size > | ||
| 378 | (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index)) | ||
| 379 | return -ENOMEM; | ||
| 380 | full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size; | ||
| 381 | indir = kmalloc(full_size, GFP_USER); | ||
| 382 | if (!indir) | ||
| 383 | return -ENOMEM; | ||
| 384 | |||
| 385 | indir->cmd = ETHTOOL_GRXFHINDIR; | ||
| 386 | indir->size = table_size; | ||
| 387 | ret = dev->ethtool_ops->get_rxfh_indir(dev, indir); | ||
| 388 | if (ret) | ||
| 389 | goto out; | ||
| 390 | |||
| 391 | if (copy_to_user(useraddr, indir, full_size)) | ||
| 392 | ret = -EFAULT; | ||
| 393 | |||
| 394 | out: | ||
| 395 | kfree(indir); | ||
| 396 | return ret; | ||
| 397 | } | ||
| 398 | |||
| 399 | static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, | ||
| 400 | void __user *useraddr) | ||
| 401 | { | ||
| 402 | struct ethtool_rxfh_indir *indir; | ||
| 403 | u32 table_size; | ||
| 404 | size_t full_size; | ||
| 405 | int ret; | ||
| 406 | |||
| 407 | if (!dev->ethtool_ops->set_rxfh_indir) | ||
| 408 | return -EOPNOTSUPP; | ||
| 409 | |||
| 410 | if (copy_from_user(&table_size, | ||
| 411 | useraddr + offsetof(struct ethtool_rxfh_indir, size), | ||
| 412 | sizeof(table_size))) | ||
| 413 | return -EFAULT; | ||
| 414 | |||
| 415 | if (table_size > | ||
| 416 | (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index)) | ||
| 417 | return -ENOMEM; | ||
| 418 | full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size; | ||
| 419 | indir = kmalloc(full_size, GFP_USER); | ||
| 420 | if (!indir) | ||
| 421 | return -ENOMEM; | ||
| 422 | |||
| 423 | if (copy_from_user(indir, useraddr, full_size)) { | ||
| 424 | ret = -EFAULT; | ||
| 425 | goto out; | ||
| 426 | } | ||
| 427 | |||
| 428 | ret = dev->ethtool_ops->set_rxfh_indir(dev, indir); | ||
| 429 | |||
| 430 | out: | ||
| 431 | kfree(indir); | ||
| 432 | return ret; | ||
| 433 | } | ||
| 434 | |||
| 361 | static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, | 435 | static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, |
| 362 | struct ethtool_rx_ntuple_flow_spec *spec, | 436 | struct ethtool_rx_ntuple_flow_spec *spec, |
| 363 | struct ethtool_rx_ntuple_flow_spec_container *fsc) | 437 | struct ethtool_rx_ntuple_flow_spec_container *fsc) |
| @@ -1526,6 +1600,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
| 1526 | case ETHTOOL_GSSET_INFO: | 1600 | case ETHTOOL_GSSET_INFO: |
| 1527 | rc = ethtool_get_sset_info(dev, useraddr); | 1601 | rc = ethtool_get_sset_info(dev, useraddr); |
| 1528 | break; | 1602 | break; |
| 1603 | case ETHTOOL_GRXFHINDIR: | ||
| 1604 | rc = ethtool_get_rxfh_indir(dev, useraddr); | ||
| 1605 | break; | ||
| 1606 | case ETHTOOL_SRXFHINDIR: | ||
| 1607 | rc = ethtool_set_rxfh_indir(dev, useraddr); | ||
| 1608 | break; | ||
| 1529 | default: | 1609 | default: |
| 1530 | rc = -EOPNOTSUPP; | 1610 | rc = -EOPNOTSUPP; |
| 1531 | } | 1611 | } |
