[ETHTOOL]: let mortals use ethtool
[linux-2.6-microblaze.git] / net / core / ethtool.c
index 33ce7ed..120786a 100644 (file)
@@ -143,7 +143,7 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
 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;
@@ -169,7 +169,7 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
 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;
 
@@ -282,7 +282,7 @@ static int ethtool_get_link(struct net_device *dev, void __user *useraddr)
 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;
 
@@ -327,7 +327,7 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
 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;
 
@@ -437,7 +437,7 @@ static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
 {
        struct ethtool_pauseparam pauseparam;
 
-       if (!dev->ethtool_ops->get_pauseparam)
+       if (!dev->ethtool_ops->set_pauseparam)
                return -EOPNOTSUPP;
 
        if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
@@ -614,10 +614,33 @@ static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
        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;
 
@@ -650,7 +673,7 @@ static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
 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;
 
@@ -710,7 +733,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
 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;
 
@@ -783,13 +806,6 @@ int dev_ethtool(struct ifreq *ifr)
        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;
 
@@ -799,6 +815,31 @@ int dev_ethtool(struct ifreq *ifr)
        if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
                return -EFAULT;
 
+       /* Allow some commands to be done by anyone */
+       switch(ethcmd) {
+       case ETHTOOL_GSET:
+       case ETHTOOL_GDRVINFO:
+       case ETHTOOL_GWOL:
+       case ETHTOOL_GMSGLVL:
+       case ETHTOOL_GLINK:
+       case ETHTOOL_GCOALESCE:
+       case ETHTOOL_GRINGPARAM:
+       case ETHTOOL_GPAUSEPARAM:
+       case ETHTOOL_GRXCSUM:
+       case ETHTOOL_GTXCSUM:
+       case ETHTOOL_GSG:
+       case ETHTOOL_GSTRINGS:
+       case ETHTOOL_GSTATS:
+       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;
@@ -905,6 +946,12 @@ int dev_ethtool(struct ifreq *ifr)
        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;
        }
@@ -918,6 +965,10 @@ int dev_ethtool(struct ifreq *ifr)
        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;