summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/core/ethtool.c48
1 files changed, 45 insertions, 3 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 6d6d7d25caaa..a723b1321691 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -17,6 +17,8 @@
17#include <linux/errno.h> 17#include <linux/errno.h>
18#include <linux/ethtool.h> 18#include <linux/ethtool.h>
19#include <linux/netdevice.h> 19#include <linux/netdevice.h>
20#include <linux/net_tstamp.h>
21#include <linux/phy.h>
20#include <linux/bitops.h> 22#include <linux/bitops.h>
21#include <linux/uaccess.h> 23#include <linux/uaccess.h>
22#include <linux/vmalloc.h> 24#include <linux/vmalloc.h>
@@ -1278,6 +1280,40 @@ out:
1278 return ret; 1280 return ret;
1279} 1281}
1280 1282
1283static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr)
1284{
1285 int err = 0;
1286 struct ethtool_ts_info info;
1287 const struct ethtool_ops *ops = dev->ethtool_ops;
1288 struct phy_device *phydev = dev->phydev;
1289
1290 memset(&info, 0, sizeof(info));
1291 info.cmd = ETHTOOL_GET_TS_INFO;
1292
1293 if (phydev && phydev->drv && phydev->drv->ts_info) {
1294
1295 err = phydev->drv->ts_info(phydev, &info);
1296
1297 } else if (dev->ethtool_ops && dev->ethtool_ops->get_ts_info) {
1298
1299 err = ops->get_ts_info(dev, &info);
1300
1301 } else {
1302 info.so_timestamping =
1303 SOF_TIMESTAMPING_RX_SOFTWARE |
1304 SOF_TIMESTAMPING_SOFTWARE;
1305 info.phc_index = -1;
1306 }
1307
1308 if (err)
1309 return err;
1310
1311 if (copy_to_user(useraddr, &info, sizeof(info)))
1312 err = -EFAULT;
1313
1314 return err;
1315}
1316
1281/* The main entry point in this file. Called from net/core/dev.c */ 1317/* The main entry point in this file. Called from net/core/dev.c */
1282 1318
1283int dev_ethtool(struct net *net, struct ifreq *ifr) 1319int dev_ethtool(struct net *net, struct ifreq *ifr)
@@ -1295,11 +1331,13 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1295 return -EFAULT; 1331 return -EFAULT;
1296 1332
1297 if (!dev->ethtool_ops) { 1333 if (!dev->ethtool_ops) {
1298 /* ETHTOOL_GDRVINFO does not require any driver support. 1334 /* A few commands do not require any driver support,
1299 * It is also unprivileged and does not change anything, 1335 * are unprivileged, and do not change anything, so we
1300 * so we can take a shortcut to it. */ 1336 * can take a shortcut to them. */
1301 if (ethcmd == ETHTOOL_GDRVINFO) 1337 if (ethcmd == ETHTOOL_GDRVINFO)
1302 return ethtool_get_drvinfo(dev, useraddr); 1338 return ethtool_get_drvinfo(dev, useraddr);
1339 else if (ethcmd == ETHTOOL_GET_TS_INFO)
1340 return ethtool_get_ts_info(dev, useraddr);
1303 else 1341 else
1304 return -EOPNOTSUPP; 1342 return -EOPNOTSUPP;
1305 } 1343 }
@@ -1330,6 +1368,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1330 case ETHTOOL_GRXCLSRULE: 1368 case ETHTOOL_GRXCLSRULE:
1331 case ETHTOOL_GRXCLSRLALL: 1369 case ETHTOOL_GRXCLSRLALL:
1332 case ETHTOOL_GFEATURES: 1370 case ETHTOOL_GFEATURES:
1371 case ETHTOOL_GET_TS_INFO:
1333 break; 1372 break;
1334 default: 1373 default:
1335 if (!capable(CAP_NET_ADMIN)) 1374 if (!capable(CAP_NET_ADMIN))
@@ -1496,6 +1535,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1496 case ETHTOOL_GET_DUMP_DATA: 1535 case ETHTOOL_GET_DUMP_DATA:
1497 rc = ethtool_get_dump_data(dev, useraddr); 1536 rc = ethtool_get_dump_data(dev, useraddr);
1498 break; 1537 break;
1538 case ETHTOOL_GET_TS_INFO:
1539 rc = ethtool_get_ts_info(dev, useraddr);
1540 break;
1499 default: 1541 default:
1500 rc = -EOPNOTSUPP; 1542 rc = -EOPNOTSUPP;
1501 } 1543 }