net_cls_act: Make act_simple use of netlink policy.
[safe/jmp/linux-2.6] / net / core / ethtool.c
index 7c43f03..0133b5e 100644 (file)
@@ -284,8 +284,10 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
 {
        struct ethtool_eeprom eeprom;
        const struct ethtool_ops *ops = dev->ethtool_ops;
+       void __user *userbuf = useraddr + sizeof(eeprom);
+       u32 bytes_remaining;
        u8 *data;
-       int ret;
+       int ret = 0;
 
        if (!ops->get_eeprom || !ops->get_eeprom_len)
                return -EOPNOTSUPP;
@@ -301,26 +303,31 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
        if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
                return -EINVAL;
 
-       data = kmalloc(eeprom.len, GFP_USER);
+       data = kmalloc(PAGE_SIZE, GFP_USER);
        if (!data)
                return -ENOMEM;
 
-       ret = -EFAULT;
-       if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
-               goto out;
+       bytes_remaining = eeprom.len;
+       while (bytes_remaining > 0) {
+               eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
 
-       ret = ops->get_eeprom(dev, &eeprom, data);
-       if (ret)
-               goto out;
+               ret = ops->get_eeprom(dev, &eeprom, data);
+               if (ret)
+                       break;
+               if (copy_to_user(userbuf, data, eeprom.len)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               userbuf += eeprom.len;
+               eeprom.offset += eeprom.len;
+               bytes_remaining -= eeprom.len;
+       }
 
-       ret = -EFAULT;
+       eeprom.len = userbuf - (useraddr + sizeof(eeprom));
+       eeprom.offset -= eeprom.len;
        if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
-               goto out;
-       if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
-               goto out;
-       ret = 0;
+               ret = -EFAULT;
 
- out:
        kfree(data);
        return ret;
 }
@@ -329,8 +336,10 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
 {
        struct ethtool_eeprom eeprom;
        const struct ethtool_ops *ops = dev->ethtool_ops;
+       void __user *userbuf = useraddr + sizeof(eeprom);
+       u32 bytes_remaining;
        u8 *data;
-       int ret;
+       int ret = 0;
 
        if (!ops->set_eeprom || !ops->get_eeprom_len)
                return -EOPNOTSUPP;
@@ -346,22 +355,26 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
        if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
                return -EINVAL;
 
-       data = kmalloc(eeprom.len, GFP_USER);
+       data = kmalloc(PAGE_SIZE, GFP_USER);
        if (!data)
                return -ENOMEM;
 
-       ret = -EFAULT;
-       if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
-               goto out;
-
-       ret = ops->set_eeprom(dev, &eeprom, data);
-       if (ret)
-               goto out;
+       bytes_remaining = eeprom.len;
+       while (bytes_remaining > 0) {
+               eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
 
-       if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
-               ret = -EFAULT;
+               if (copy_from_user(data, userbuf, eeprom.len)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = ops->set_eeprom(dev, &eeprom, data);
+               if (ret)
+                       break;
+               userbuf += eeprom.len;
+               eeprom.offset += eeprom.len;
+               bytes_remaining -= eeprom.len;
+       }
 
- out:
        kfree(data);
        return ret;
 }
@@ -779,9 +792,9 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
 
 /* The main entry point in this file.  Called from net/core/dev.c */
 
-int dev_ethtool(struct ifreq *ifr)
+int dev_ethtool(struct net *net, struct ifreq *ifr)
 {
-       struct net_device *dev = __dev_get_by_name(ifr->ifr_name);
+       struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
        void __user *useraddr = ifr->ifr_data;
        u32 ethcmd;
        int rc;
@@ -893,21 +906,27 @@ int dev_ethtool(struct ifreq *ifr)
                break;
        case ETHTOOL_GTXCSUM:
                rc = ethtool_get_value(dev, useraddr, ethcmd,
-                                      dev->ethtool_ops->get_tx_csum);
+                                      (dev->ethtool_ops->get_tx_csum ?
+                                       dev->ethtool_ops->get_tx_csum :
+                                       ethtool_op_get_tx_csum));
                break;
        case ETHTOOL_STXCSUM:
                rc = ethtool_set_tx_csum(dev, useraddr);
                break;
        case ETHTOOL_GSG:
                rc = ethtool_get_value(dev, useraddr, ethcmd,
-                                      dev->ethtool_ops->get_sg);
+                                      (dev->ethtool_ops->get_sg ?
+                                       dev->ethtool_ops->get_sg :
+                                       ethtool_op_get_sg));
                break;
        case ETHTOOL_SSG:
                rc = ethtool_set_sg(dev, useraddr);
                break;
        case ETHTOOL_GTSO:
                rc = ethtool_get_value(dev, useraddr, ethcmd,
-                                      dev->ethtool_ops->get_tso);
+                                      (dev->ethtool_ops->get_tso ?
+                                       dev->ethtool_ops->get_tso :
+                                       ethtool_op_get_tso));
                break;
        case ETHTOOL_STSO:
                rc = ethtool_set_tso(dev, useraddr);
@@ -929,7 +948,9 @@ int dev_ethtool(struct ifreq *ifr)
                break;
        case ETHTOOL_GUFO:
                rc = ethtool_get_value(dev, useraddr, ethcmd,
-                                      dev->ethtool_ops->get_ufo);
+                                      (dev->ethtool_ops->get_ufo ?
+                                       dev->ethtool_ops->get_ufo :
+                                       ethtool_op_get_ufo));
                break;
        case ETHTOOL_SUFO:
                rc = ethtool_set_ufo(dev, useraddr);