u32 ethtool_op_get_tx_csum(struct net_device *dev)
{
- return (dev->features & (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM)) != 0;
+ return (dev->features & NETIF_F_ALL_CSUM) != 0;
}
int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
{
struct ethtool_drvinfo info;
- struct ethtool_ops *ops = dev->ethtool_ops;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
if (!ops->get_drvinfo)
return -EOPNOTSUPP;
static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
{
struct ethtool_regs regs;
- struct ethtool_ops *ops = dev->ethtool_ops;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
void *regbuf;
int reglen, ret;
static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
{
struct ethtool_eeprom eeprom;
- struct ethtool_ops *ops = dev->ethtool_ops;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
u8 *data;
int ret;
static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
{
struct ethtool_eeprom eeprom;
- struct ethtool_ops *ops = dev->ethtool_ops;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
u8 *data;
int ret;
return -EFAULT;
if (edata.data &&
- !(dev->features & (NETIF_F_IP_CSUM |
- NETIF_F_NO_CSUM |
- NETIF_F_HW_CSUM)))
+ !(dev->features & NETIF_F_ALL_CSUM))
return -EINVAL;
return __ethtool_set_sg(dev, edata.data);
return dev->ethtool_ops->set_ufo(dev, edata.data);
}
+static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
+{
+ struct ethtool_value edata = { ETHTOOL_GGSO };
+
+ edata.data = dev->features & NETIF_F_GSO;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+}
+
+static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
+{
+ struct ethtool_value edata;
+
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if (edata.data)
+ dev->features |= NETIF_F_GSO;
+ else
+ dev->features &= ~NETIF_F_GSO;
+ return 0;
+}
+
static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
{
struct ethtool_test test;
- struct ethtool_ops *ops = dev->ethtool_ops;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
u64 *data;
int ret;
static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
{
struct ethtool_gstrings gstrings;
- struct ethtool_ops *ops = dev->ethtool_ops;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
u8 *data;
int ret;
static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
{
struct ethtool_stats stats;
- struct ethtool_ops *ops = dev->ethtool_ops;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
u64 *data;
int ret;
int rc;
unsigned long old_features;
- /*
- * XXX: This can be pushed down into the ethtool_* handlers that
- * need it. Keep existing behaviour for the moment.
- */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
if (!dev || !netif_device_present(dev))
return -ENODEV;
if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd)))
return -EFAULT;
+ /* Allow some commands to be done by anyone */
+ switch(ethcmd) {
+ case ETHTOOL_GDRVINFO:
+ case ETHTOOL_GMSGLVL:
+ case ETHTOOL_GCOALESCE:
+ case ETHTOOL_GRINGPARAM:
+ case ETHTOOL_GPAUSEPARAM:
+ case ETHTOOL_GRXCSUM:
+ case ETHTOOL_GTXCSUM:
+ case ETHTOOL_GSG:
+ case ETHTOOL_GSTRINGS:
+ case ETHTOOL_GTSO:
+ case ETHTOOL_GPERMADDR:
+ case ETHTOOL_GUFO:
+ case ETHTOOL_GGSO:
+ break;
+ default:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ }
+
if(dev->ethtool_ops->begin)
if ((rc = dev->ethtool_ops->begin(dev)) < 0)
return rc;
case ETHTOOL_SUFO:
rc = ethtool_set_ufo(dev, useraddr);
break;
+ case ETHTOOL_GGSO:
+ rc = ethtool_get_gso(dev, useraddr);
+ break;
+ case ETHTOOL_SGSO:
+ rc = ethtool_set_gso(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
return rc;
ioctl:
+ /* Keep existing behaviour for the moment. */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
if (dev->do_ioctl)
return dev->do_ioctl(dev, ifr, SIOCETHTOOL);
return -EOPNOTSUPP;