|
@@ -528,6 +528,22 @@ static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr)
|
|
return dev->ethtool_ops->set_tx_csum(dev, edata.data);
|
|
return dev->ethtool_ops->set_tx_csum(dev, edata.data);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr)
|
|
|
|
+{
|
|
|
|
+ struct ethtool_value edata;
|
|
|
|
+
|
|
|
|
+ if (!dev->ethtool_ops->set_rx_csum)
|
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
+
|
|
|
|
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ if (!edata.data && dev->ethtool_ops->set_sg)
|
|
|
|
+ dev->features &= ~NETIF_F_GRO;
|
|
|
|
+
|
|
|
|
+ return dev->ethtool_ops->set_rx_csum(dev, edata.data);
|
|
|
|
+}
|
|
|
|
+
|
|
static int ethtool_set_sg(struct net_device *dev, char __user *useraddr)
|
|
static int ethtool_set_sg(struct net_device *dev, char __user *useraddr)
|
|
{
|
|
{
|
|
struct ethtool_value edata;
|
|
struct ethtool_value edata;
|
|
@@ -599,6 +615,34 @@ static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int ethtool_get_gro(struct net_device *dev, char __user *useraddr)
|
|
|
|
+{
|
|
|
|
+ struct ethtool_value edata = { ETHTOOL_GGRO };
|
|
|
|
+
|
|
|
|
+ edata.data = dev->features & NETIF_F_GRO;
|
|
|
|
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int ethtool_set_gro(struct net_device *dev, char __user *useraddr)
|
|
|
|
+{
|
|
|
|
+ struct ethtool_value edata;
|
|
|
|
+
|
|
|
|
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ if (edata.data) {
|
|
|
|
+ if (!dev->ethtool_ops->get_rx_csum ||
|
|
|
|
+ !dev->ethtool_ops->get_rx_csum(dev))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ dev->features |= NETIF_F_GRO;
|
|
|
|
+ } else
|
|
|
|
+ dev->features &= ~NETIF_F_GRO;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
|
|
static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
|
|
{
|
|
{
|
|
struct ethtool_test test;
|
|
struct ethtool_test test;
|
|
@@ -932,8 +976,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
|
|
dev->ethtool_ops->get_rx_csum);
|
|
dev->ethtool_ops->get_rx_csum);
|
|
break;
|
|
break;
|
|
case ETHTOOL_SRXCSUM:
|
|
case ETHTOOL_SRXCSUM:
|
|
- rc = ethtool_set_value(dev, useraddr,
|
|
|
|
- dev->ethtool_ops->set_rx_csum);
|
|
|
|
|
|
+ rc = ethtool_set_rx_csum(dev, useraddr);
|
|
break;
|
|
break;
|
|
case ETHTOOL_GTXCSUM:
|
|
case ETHTOOL_GTXCSUM:
|
|
rc = ethtool_get_value(dev, useraddr, ethcmd,
|
|
rc = ethtool_get_value(dev, useraddr, ethcmd,
|
|
@@ -1014,6 +1057,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
|
|
case ETHTOOL_SRXFH:
|
|
case ETHTOOL_SRXFH:
|
|
rc = ethtool_set_rxhash(dev, useraddr);
|
|
rc = ethtool_set_rxhash(dev, useraddr);
|
|
break;
|
|
break;
|
|
|
|
+ case ETHTOOL_GGRO:
|
|
|
|
+ rc = ethtool_get_gro(dev, useraddr);
|
|
|
|
+ break;
|
|
|
|
+ case ETHTOOL_SGRO:
|
|
|
|
+ rc = ethtool_set_gro(dev, useraddr);
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
rc = -EOPNOTSUPP;
|
|
rc = -EOPNOTSUPP;
|
|
}
|
|
}
|