aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/ethtool.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r--net/core/ethtool.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 7a85367b3c2f..d2c4da5a6a4f 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -205,18 +205,24 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
205 struct ethtool_drvinfo info; 205 struct ethtool_drvinfo info;
206 const struct ethtool_ops *ops = dev->ethtool_ops; 206 const struct ethtool_ops *ops = dev->ethtool_ops;
207 207
208 if (!ops->get_drvinfo)
209 return -EOPNOTSUPP;
210
211 memset(&info, 0, sizeof(info)); 208 memset(&info, 0, sizeof(info));
212 info.cmd = ETHTOOL_GDRVINFO; 209 info.cmd = ETHTOOL_GDRVINFO;
213 ops->get_drvinfo(dev, &info); 210 if (ops && ops->get_drvinfo) {
211 ops->get_drvinfo(dev, &info);
212 } else if (dev->dev.parent && dev->dev.parent->driver) {
213 strlcpy(info.bus_info, dev_name(dev->dev.parent),
214 sizeof(info.bus_info));
215 strlcpy(info.driver, dev->dev.parent->driver->name,
216 sizeof(info.driver));
217 } else {
218 return -EOPNOTSUPP;
219 }
214 220
215 /* 221 /*
216 * this method of obtaining string set info is deprecated; 222 * this method of obtaining string set info is deprecated;
217 * Use ETHTOOL_GSSET_INFO instead. 223 * Use ETHTOOL_GSSET_INFO instead.
218 */ 224 */
219 if (ops->get_sset_count) { 225 if (ops && ops->get_sset_count) {
220 int rc; 226 int rc;
221 227
222 rc = ops->get_sset_count(dev, ETH_SS_TEST); 228 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,
229 if (rc >= 0) 235 if (rc >= 0)
230 info.n_priv_flags = rc; 236 info.n_priv_flags = rc;
231 } 237 }
232 if (ops->get_regs_len) 238 if (ops && ops->get_regs_len)
233 info.regdump_len = ops->get_regs_len(dev); 239 info.regdump_len = ops->get_regs_len(dev);
234 if (ops->get_eeprom_len) 240 if (ops && ops->get_eeprom_len)
235 info.eedump_len = ops->get_eeprom_len(dev); 241 info.eedump_len = ops->get_eeprom_len(dev);
236 242
237 if (copy_to_user(useraddr, &info, sizeof(info))) 243 if (copy_to_user(useraddr, &info, sizeof(info)))
@@ -1402,12 +1408,19 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1402 if (!dev || !netif_device_present(dev)) 1408 if (!dev || !netif_device_present(dev))
1403 return -ENODEV; 1409 return -ENODEV;
1404 1410
1405 if (!dev->ethtool_ops)
1406 return -EOPNOTSUPP;
1407
1408 if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd))) 1411 if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
1409 return -EFAULT; 1412 return -EFAULT;
1410 1413
1414 if (!dev->ethtool_ops) {
1415 /* ETHTOOL_GDRVINFO does not require any driver support.
1416 * It is also unprivileged and does not change anything,
1417 * so we can take a shortcut to it. */
1418 if (ethcmd == ETHTOOL_GDRVINFO)
1419 return ethtool_get_drvinfo(dev, useraddr);
1420 else
1421 return -EOPNOTSUPP;
1422 }
1423
1411 /* Allow some commands to be done by anyone */ 1424 /* Allow some commands to be done by anyone */
1412 switch (ethcmd) { 1425 switch (ethcmd) {
1413 case ETHTOOL_GDRVINFO: 1426 case ETHTOOL_GDRVINFO: