|
@@ -205,18 +205,24 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
|
|
|
struct ethtool_drvinfo info;
|
|
|
const struct ethtool_ops *ops = dev->ethtool_ops;
|
|
|
|
|
|
- if (!ops->get_drvinfo)
|
|
|
- return -EOPNOTSUPP;
|
|
|
-
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
info.cmd = ETHTOOL_GDRVINFO;
|
|
|
- ops->get_drvinfo(dev, &info);
|
|
|
+ if (ops && ops->get_drvinfo) {
|
|
|
+ ops->get_drvinfo(dev, &info);
|
|
|
+ } else if (dev->dev.parent && dev->dev.parent->driver) {
|
|
|
+ strlcpy(info.bus_info, dev_name(dev->dev.parent),
|
|
|
+ sizeof(info.bus_info));
|
|
|
+ strlcpy(info.driver, dev->dev.parent->driver->name,
|
|
|
+ sizeof(info.driver));
|
|
|
+ } else {
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* this method of obtaining string set info is deprecated;
|
|
|
* Use ETHTOOL_GSSET_INFO instead.
|
|
|
*/
|
|
|
- if (ops->get_sset_count) {
|
|
|
+ if (ops && ops->get_sset_count) {
|
|
|
int rc;
|
|
|
|
|
|
rc = ops->get_sset_count(dev, ETH_SS_TEST);
|
|
@@ -229,9 +235,9 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
|
|
|
if (rc >= 0)
|
|
|
info.n_priv_flags = rc;
|
|
|
}
|
|
|
- if (ops->get_regs_len)
|
|
|
+ if (ops && ops->get_regs_len)
|
|
|
info.regdump_len = ops->get_regs_len(dev);
|
|
|
- if (ops->get_eeprom_len)
|
|
|
+ if (ops && ops->get_eeprom_len)
|
|
|
info.eedump_len = ops->get_eeprom_len(dev);
|
|
|
|
|
|
if (copy_to_user(useraddr, &info, sizeof(info)))
|
|
@@ -1402,12 +1408,19 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
|
|
|
if (!dev || !netif_device_present(dev))
|
|
|
return -ENODEV;
|
|
|
|
|
|
- if (!dev->ethtool_ops)
|
|
|
- return -EOPNOTSUPP;
|
|
|
-
|
|
|
if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
+ if (!dev->ethtool_ops) {
|
|
|
+ /* ETHTOOL_GDRVINFO does not require any driver support.
|
|
|
+ * It is also unprivileged and does not change anything,
|
|
|
+ * so we can take a shortcut to it. */
|
|
|
+ if (ethcmd == ETHTOOL_GDRVINFO)
|
|
|
+ return ethtool_get_drvinfo(dev, useraddr);
|
|
|
+ else
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+
|
|
|
/* Allow some commands to be done by anyone */
|
|
|
switch (ethcmd) {
|
|
|
case ETHTOOL_GDRVINFO:
|