diff options
| author | Scott Feldman <scott.feldman@intel.com> | 2003-10-14 05:52:16 -0400 |
|---|---|---|
| committer | Stephen Hemminger <shemminger@osdl.org> | 2003-10-14 05:52:16 -0400 |
| commit | 06191dd615af60ddb97a894f76ca88d68f7a79ed (patch) | |
| tree | 7bcaa2358ab8921c40ba76d10a5c996a522fb933 | |
| parent | 019904d0dee2a4bf329f1778551dda0b3686a83a (diff) | |
[PATCH] ethtool_ops eeprom stuff
Finally got around to adding ethtool_ops to e100-3.0.x. I found a bug
with get_eeprom() and it seems to work best if we add get_eeprom_len() to
the ops list. Also moved check for offest + len < size into ethtool.c.
I was able to test [GS]EEPROM, PHYS_ID, GSTATS, GSTRINGS, and TEST, and
everything looks good.
Should I send same for 2.4?
| -rw-r--r-- | include/linux/ethtool.h | 11 | ||||
| -rw-r--r-- | net/core/ethtool.c | 49 |
2 files changed, 36 insertions, 24 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index cc942f675ae9..8d4d0e397ed5 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -307,14 +307,14 @@ int ethtool_op_set_tso(struct net_device *dev, u32 data); * * get_eeprom: * Should fill in the magic field. Don't need to check len for zero - * or wraparound but must check offset + len < size. Fill in the data - * argument with the eeprom values from offset to offset + len. Update - * len to the amount read. Returns an error or zero. + * or wraparound. Fill in the data argument with the eeprom values + * from offset to offset + len. Update len to the amount read. + * Returns an error or zero. * * set_eeprom: * Should validate the magic field. Don't need to check len for zero - * or wraparound but must check offset + len < size. Update len to - * the amount written. Returns an error or zero. + * or wraparound. Update len to the amount written. Returns an error + * or zero. */ struct ethtool_ops { int (*get_settings)(struct net_device *, struct ethtool_cmd *); @@ -328,6 +328,7 @@ struct ethtool_ops { void (*set_msglevel)(struct net_device *, u32); int (*nway_reset)(struct net_device *); u32 (*get_link)(struct net_device *); + int (*get_eeprom_len)(struct net_device *); int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 35f27196b154..46e3cf090b3c 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -122,7 +122,8 @@ static int ethtool_get_drvinfo(struct net_device *dev, void *useraddr) info.n_stats = ops->get_stats_count(dev); if (ops->get_regs_len) info.regdump_len = ops->get_regs_len(dev); - /* XXX: eeprom? */ + if (ops->get_eeprom_len) + info.eedump_len = ops->get_eeprom_len(dev); if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; @@ -245,29 +246,34 @@ static int ethtool_get_link(struct net_device *dev, void *useraddr) static int ethtool_get_eeprom(struct net_device *dev, void *useraddr) { struct ethtool_eeprom eeprom; + struct ethtool_ops *ops = dev->ethtool_ops; u8 *data; - int len, ret; + int ret; - if (!dev->ethtool_ops->get_eeprom) + if (!ops->get_eeprom || !ops->get_eeprom_len) return -EOPNOTSUPP; if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) return -EFAULT; - len = eeprom.len; /* Check for wrap and zero */ - if (eeprom.offset + len <= eeprom.offset) + if (eeprom.offset + eeprom.len <= eeprom.offset) + return -EINVAL; + + /* Check for exceeding total eeprom len */ + if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) return -EINVAL; - data = kmalloc(len, GFP_USER); + data = kmalloc(eeprom.len, GFP_USER); if (!data) return -ENOMEM; - if (copy_from_user(data, useraddr + sizeof(eeprom), len)) - return -EFAULT; + ret = -EFAULT; + if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) + goto out; - ret = dev->ethtool_ops->get_eeprom(dev, &eeprom, data); - if (!ret) + ret = ops->get_eeprom(dev, &eeprom, data); + if (ret) goto out; ret = -EFAULT; @@ -285,32 +291,37 @@ static int ethtool_get_eeprom(struct net_device *dev, void *useraddr) static int ethtool_set_eeprom(struct net_device *dev, void *useraddr) { struct ethtool_eeprom eeprom; + struct ethtool_ops *ops = dev->ethtool_ops; u8 *data; - int len, ret; + int ret; - if (!dev->ethtool_ops->set_eeprom) + if (!ops->set_eeprom || !ops->get_eeprom_len) return -EOPNOTSUPP; if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) return -EFAULT; - len = eeprom.len; /* Check for wrap and zero */ - if (eeprom.offset + len <= eeprom.offset) + if (eeprom.offset + eeprom.len <= eeprom.offset) + return -EINVAL; + + /* Check for exceeding total eeprom len */ + if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) return -EINVAL; - data = kmalloc(len, GFP_USER); + data = kmalloc(eeprom.len, GFP_USER); if (!data) return -ENOMEM; - if (copy_from_user(data, useraddr + sizeof(eeprom), len)) - return -EFAULT; + ret = -EFAULT; + if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) + goto out; - ret = dev->ethtool_ops->set_eeprom(dev, &eeprom, data); + ret = ops->set_eeprom(dev, &eeprom, data); if (ret) goto out; - if (copy_to_user(useraddr + sizeof(eeprom), data, len)) + if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len)) ret = -EFAULT; out: |
