diff options
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/ethtool.c | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 14ada537f895..947710a36ced 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -528,6 +528,22 @@ static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr) | |||
528 | return dev->ethtool_ops->set_tx_csum(dev, edata.data); | 528 | return dev->ethtool_ops->set_tx_csum(dev, edata.data); |
529 | } | 529 | } |
530 | 530 | ||
531 | static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr) | ||
532 | { | ||
533 | struct ethtool_value edata; | ||
534 | |||
535 | if (!dev->ethtool_ops->set_rx_csum) | ||
536 | return -EOPNOTSUPP; | ||
537 | |||
538 | if (copy_from_user(&edata, useraddr, sizeof(edata))) | ||
539 | return -EFAULT; | ||
540 | |||
541 | if (!edata.data && dev->ethtool_ops->set_sg) | ||
542 | dev->features &= ~NETIF_F_GRO; | ||
543 | |||
544 | return dev->ethtool_ops->set_rx_csum(dev, edata.data); | ||
545 | } | ||
546 | |||
531 | static int ethtool_set_sg(struct net_device *dev, char __user *useraddr) | 547 | static int ethtool_set_sg(struct net_device *dev, char __user *useraddr) |
532 | { | 548 | { |
533 | struct ethtool_value edata; | 549 | struct ethtool_value edata; |
@@ -599,6 +615,34 @@ static int ethtool_set_gso(struct net_device *dev, char __user *useraddr) | |||
599 | return 0; | 615 | return 0; |
600 | } | 616 | } |
601 | 617 | ||
618 | static int ethtool_get_gro(struct net_device *dev, char __user *useraddr) | ||
619 | { | ||
620 | struct ethtool_value edata = { ETHTOOL_GGRO }; | ||
621 | |||
622 | edata.data = dev->features & NETIF_F_GRO; | ||
623 | if (copy_to_user(useraddr, &edata, sizeof(edata))) | ||
624 | return -EFAULT; | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static int ethtool_set_gro(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 | |||
635 | if (edata.data) { | ||
636 | if (!dev->ethtool_ops->get_rx_csum || | ||
637 | !dev->ethtool_ops->get_rx_csum(dev)) | ||
638 | return -EINVAL; | ||
639 | dev->features |= NETIF_F_GRO; | ||
640 | } else | ||
641 | dev->features &= ~NETIF_F_GRO; | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
602 | static int ethtool_self_test(struct net_device *dev, char __user *useraddr) | 646 | static int ethtool_self_test(struct net_device *dev, char __user *useraddr) |
603 | { | 647 | { |
604 | struct ethtool_test test; | 648 | struct ethtool_test test; |
@@ -932,8 +976,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
932 | dev->ethtool_ops->get_rx_csum); | 976 | dev->ethtool_ops->get_rx_csum); |
933 | break; | 977 | break; |
934 | case ETHTOOL_SRXCSUM: | 978 | case ETHTOOL_SRXCSUM: |
935 | rc = ethtool_set_value(dev, useraddr, | 979 | rc = ethtool_set_rx_csum(dev, useraddr); |
936 | dev->ethtool_ops->set_rx_csum); | ||
937 | break; | 980 | break; |
938 | case ETHTOOL_GTXCSUM: | 981 | case ETHTOOL_GTXCSUM: |
939 | rc = ethtool_get_value(dev, useraddr, ethcmd, | 982 | rc = ethtool_get_value(dev, useraddr, ethcmd, |
@@ -1014,6 +1057,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1014 | case ETHTOOL_SRXFH: | 1057 | case ETHTOOL_SRXFH: |
1015 | rc = ethtool_set_rxhash(dev, useraddr); | 1058 | rc = ethtool_set_rxhash(dev, useraddr); |
1016 | break; | 1059 | break; |
1060 | case ETHTOOL_GGRO: | ||
1061 | rc = ethtool_get_gro(dev, useraddr); | ||
1062 | break; | ||
1063 | case ETHTOOL_SGRO: | ||
1064 | rc = ethtool_set_gro(dev, useraddr); | ||
1065 | break; | ||
1017 | default: | 1066 | default: |
1018 | rc = -EOPNOTSUPP; | 1067 | rc = -EOPNOTSUPP; |
1019 | } | 1068 | } |