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.c221
1 files changed, 210 insertions, 11 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 74ead9eca126..fd14116ad7f0 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -21,6 +21,8 @@
21#include <linux/uaccess.h> 21#include <linux/uaccess.h>
22#include <linux/vmalloc.h> 22#include <linux/vmalloc.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/rtnetlink.h>
25#include <linux/sched.h>
24 26
25/* 27/*
26 * Some useful ethtool_ops methods that're device independent. 28 * Some useful ethtool_ops methods that're device independent.
@@ -231,6 +233,29 @@ static int ethtool_set_feature_compat(struct net_device *dev,
231 return 1; 233 return 1;
232} 234}
233 235
236static int ethtool_set_flags_compat(struct net_device *dev,
237 int (*legacy_set)(struct net_device *, u32),
238 struct ethtool_set_features_block *features, u32 mask)
239{
240 u32 value;
241
242 if (!legacy_set)
243 return 0;
244
245 if (!(features[0].valid & mask))
246 return 0;
247
248 value = dev->features & ~features[0].valid;
249 value |= features[0].requested;
250
251 features[0].valid &= ~mask;
252
253 if (legacy_set(dev, value & mask) < 0)
254 netdev_info(dev, "Legacy flags change failed\n");
255
256 return 1;
257}
258
234static int ethtool_set_features_compat(struct net_device *dev, 259static int ethtool_set_features_compat(struct net_device *dev,
235 struct ethtool_set_features_block *features) 260 struct ethtool_set_features_block *features)
236{ 261{
@@ -247,7 +272,7 @@ static int ethtool_set_features_compat(struct net_device *dev,
247 features, NETIF_F_ALL_TSO); 272 features, NETIF_F_ALL_TSO);
248 compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum, 273 compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum,
249 features, NETIF_F_RXCSUM); 274 features, NETIF_F_RXCSUM);
250 compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_flags, 275 compat |= ethtool_set_flags_compat(dev, dev->ethtool_ops->set_flags,
251 features, flags_dup_features); 276 features, flags_dup_features);
252 277
253 return compat; 278 return compat;
@@ -317,7 +342,7 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
317 342
318 dev->wanted_features &= ~features[0].valid; 343 dev->wanted_features &= ~features[0].valid;
319 dev->wanted_features |= features[0].valid & features[0].requested; 344 dev->wanted_features |= features[0].valid & features[0].requested;
320 netdev_update_features(dev); 345 __netdev_update_features(dev);
321 346
322 if ((dev->wanted_features ^ dev->features) & features[0].valid) 347 if ((dev->wanted_features ^ dev->features) & features[0].valid)
323 ret |= ETHTOOL_F_WISH; 348 ret |= ETHTOOL_F_WISH;
@@ -330,7 +355,7 @@ static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GS
330 /* NETIF_F_IP_CSUM */ "tx-checksum-ipv4", 355 /* NETIF_F_IP_CSUM */ "tx-checksum-ipv4",
331 /* NETIF_F_NO_CSUM */ "tx-checksum-unneeded", 356 /* NETIF_F_NO_CSUM */ "tx-checksum-unneeded",
332 /* NETIF_F_HW_CSUM */ "tx-checksum-ip-generic", 357 /* NETIF_F_HW_CSUM */ "tx-checksum-ip-generic",
333 /* NETIF_F_IPV6_CSUM */ "tx_checksum-ipv6", 358 /* NETIF_F_IPV6_CSUM */ "tx-checksum-ipv6",
334 /* NETIF_F_HIGHDMA */ "highdma", 359 /* NETIF_F_HIGHDMA */ "highdma",
335 /* NETIF_F_FRAGLIST */ "tx-scatter-gather-fraglist", 360 /* NETIF_F_FRAGLIST */ "tx-scatter-gather-fraglist",
336 /* NETIF_F_HW_VLAN_TX */ "tx-vlan-hw-insert", 361 /* NETIF_F_HW_VLAN_TX */ "tx-vlan-hw-insert",
@@ -359,8 +384,8 @@ static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GS
359 /* NETIF_F_NTUPLE */ "rx-ntuple-filter", 384 /* NETIF_F_NTUPLE */ "rx-ntuple-filter",
360 /* NETIF_F_RXHASH */ "rx-hashing", 385 /* NETIF_F_RXHASH */ "rx-hashing",
361 /* NETIF_F_RXCSUM */ "rx-checksum", 386 /* NETIF_F_RXCSUM */ "rx-checksum",
362 "", 387 /* NETIF_F_NOCACHE_COPY */ "tx-nocache-copy",
363 "", 388 /* NETIF_F_LOOPBACK */ "loopback",
364}; 389};
365 390
366static int __ethtool_get_sset_count(struct net_device *dev, int sset) 391static int __ethtool_get_sset_count(struct net_device *dev, int sset)
@@ -499,7 +524,7 @@ static int ethtool_set_one_feature(struct net_device *dev,
499 else 524 else
500 dev->wanted_features &= ~mask; 525 dev->wanted_features &= ~mask;
501 526
502 netdev_update_features(dev); 527 __netdev_update_features(dev);
503 return 0; 528 return 0;
504 } 529 }
505 530
@@ -544,14 +569,14 @@ int __ethtool_set_flags(struct net_device *dev, u32 data)
544 } 569 }
545 570
546 /* allow changing only bits set in hw_features */ 571 /* allow changing only bits set in hw_features */
547 changed = (data ^ dev->wanted_features) & flags_dup_features; 572 changed = (data ^ dev->features) & flags_dup_features;
548 if (changed & ~dev->hw_features) 573 if (changed & ~dev->hw_features)
549 return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP; 574 return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;
550 575
551 dev->wanted_features = 576 dev->wanted_features =
552 (dev->wanted_features & ~changed) | data; 577 (dev->wanted_features & ~changed) | (data & dev->hw_features);
553 578
554 netdev_update_features(dev); 579 __netdev_update_features(dev);
555 580
556 return 0; 581 return 0;
557} 582}
@@ -908,6 +933,9 @@ static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev,
908 struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL; 933 struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL;
909 int ret; 934 int ret;
910 935
936 if (!ops->set_rx_ntuple)
937 return -EOPNOTSUPP;
938
911 if (!(dev->features & NETIF_F_NTUPLE)) 939 if (!(dev->features & NETIF_F_NTUPLE))
912 return -EINVAL; 940 return -EINVAL;
913 941
@@ -1441,6 +1469,35 @@ static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
1441 return dev->ethtool_ops->set_ringparam(dev, &ringparam); 1469 return dev->ethtool_ops->set_ringparam(dev, &ringparam);
1442} 1470}
1443 1471
1472static noinline_for_stack int ethtool_get_channels(struct net_device *dev,
1473 void __user *useraddr)
1474{
1475 struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
1476
1477 if (!dev->ethtool_ops->get_channels)
1478 return -EOPNOTSUPP;
1479
1480 dev->ethtool_ops->get_channels(dev, &channels);
1481
1482 if (copy_to_user(useraddr, &channels, sizeof(channels)))
1483 return -EFAULT;
1484 return 0;
1485}
1486
1487static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
1488 void __user *useraddr)
1489{
1490 struct ethtool_channels channels;
1491
1492 if (!dev->ethtool_ops->set_channels)
1493 return -EOPNOTSUPP;
1494
1495 if (copy_from_user(&channels, useraddr, sizeof(channels)))
1496 return -EFAULT;
1497
1498 return dev->ethtool_ops->set_channels(dev, &channels);
1499}
1500
1444static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr) 1501static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
1445{ 1502{
1446 struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM }; 1503 struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
@@ -1618,14 +1675,60 @@ out:
1618static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) 1675static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
1619{ 1676{
1620 struct ethtool_value id; 1677 struct ethtool_value id;
1678 static bool busy;
1679 int rc;
1621 1680
1622 if (!dev->ethtool_ops->phys_id) 1681 if (!dev->ethtool_ops->set_phys_id)
1623 return -EOPNOTSUPP; 1682 return -EOPNOTSUPP;
1624 1683
1684 if (busy)
1685 return -EBUSY;
1686
1625 if (copy_from_user(&id, useraddr, sizeof(id))) 1687 if (copy_from_user(&id, useraddr, sizeof(id)))
1626 return -EFAULT; 1688 return -EFAULT;
1627 1689
1628 return dev->ethtool_ops->phys_id(dev, id.data); 1690 rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE);
1691 if (rc < 0)
1692 return rc;
1693
1694 /* Drop the RTNL lock while waiting, but prevent reentry or
1695 * removal of the device.
1696 */
1697 busy = true;
1698 dev_hold(dev);
1699 rtnl_unlock();
1700
1701 if (rc == 0) {
1702 /* Driver will handle this itself */
1703 schedule_timeout_interruptible(
1704 id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT);
1705 } else {
1706 /* Driver expects to be called at twice the frequency in rc */
1707 int n = rc * 2, i, interval = HZ / n;
1708
1709 /* Count down seconds */
1710 do {
1711 /* Count down iterations per second */
1712 i = n;
1713 do {
1714 rtnl_lock();
1715 rc = dev->ethtool_ops->set_phys_id(dev,
1716 (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
1717 rtnl_unlock();
1718 if (rc)
1719 break;
1720 schedule_timeout_interruptible(interval);
1721 } while (!signal_pending(current) && --i != 0);
1722 } while (!signal_pending(current) &&
1723 (id.data == 0 || --id.data != 0));
1724 }
1725
1726 rtnl_lock();
1727 dev_put(dev);
1728 busy = false;
1729
1730 (void)dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
1731 return rc;
1629} 1732}
1630 1733
1631static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) 1734static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
@@ -1743,6 +1846,87 @@ static noinline_for_stack int ethtool_flash_device(struct net_device *dev,
1743 return dev->ethtool_ops->flash_device(dev, &efl); 1846 return dev->ethtool_ops->flash_device(dev, &efl);
1744} 1847}
1745 1848
1849static int ethtool_set_dump(struct net_device *dev,
1850 void __user *useraddr)
1851{
1852 struct ethtool_dump dump;
1853
1854 if (!dev->ethtool_ops->set_dump)
1855 return -EOPNOTSUPP;
1856
1857 if (copy_from_user(&dump, useraddr, sizeof(dump)))
1858 return -EFAULT;
1859
1860 return dev->ethtool_ops->set_dump(dev, &dump);
1861}
1862
1863static int ethtool_get_dump_flag(struct net_device *dev,
1864 void __user *useraddr)
1865{
1866 int ret;
1867 struct ethtool_dump dump;
1868 const struct ethtool_ops *ops = dev->ethtool_ops;
1869
1870 if (!dev->ethtool_ops->get_dump_flag)
1871 return -EOPNOTSUPP;
1872
1873 if (copy_from_user(&dump, useraddr, sizeof(dump)))
1874 return -EFAULT;
1875
1876 ret = ops->get_dump_flag(dev, &dump);
1877 if (ret)
1878 return ret;
1879
1880 if (copy_to_user(useraddr, &dump, sizeof(dump)))
1881 return -EFAULT;
1882 return 0;
1883}
1884
1885static int ethtool_get_dump_data(struct net_device *dev,
1886 void __user *useraddr)
1887{
1888 int ret;
1889 __u32 len;
1890 struct ethtool_dump dump, tmp;
1891 const struct ethtool_ops *ops = dev->ethtool_ops;
1892 void *data = NULL;
1893
1894 if (!dev->ethtool_ops->get_dump_data ||
1895 !dev->ethtool_ops->get_dump_flag)
1896 return -EOPNOTSUPP;
1897
1898 if (copy_from_user(&dump, useraddr, sizeof(dump)))
1899 return -EFAULT;
1900
1901 memset(&tmp, 0, sizeof(tmp));
1902 tmp.cmd = ETHTOOL_GET_DUMP_FLAG;
1903 ret = ops->get_dump_flag(dev, &tmp);
1904 if (ret)
1905 return ret;
1906
1907 len = (tmp.len > dump.len) ? dump.len : tmp.len;
1908 if (!len)
1909 return -EFAULT;
1910
1911 data = vzalloc(tmp.len);
1912 if (!data)
1913 return -ENOMEM;
1914 ret = ops->get_dump_data(dev, &dump, data);
1915 if (ret)
1916 goto out;
1917
1918 if (copy_to_user(useraddr, &dump, sizeof(dump))) {
1919 ret = -EFAULT;
1920 goto out;
1921 }
1922 useraddr += offsetof(struct ethtool_dump, data);
1923 if (copy_to_user(useraddr, data, len))
1924 ret = -EFAULT;
1925out:
1926 vfree(data);
1927 return ret;
1928}
1929
1746/* The main entry point in this file. Called from net/core/dev.c */ 1930/* The main entry point in this file. Called from net/core/dev.c */
1747 1931
1748int dev_ethtool(struct net *net, struct ifreq *ifr) 1932int dev_ethtool(struct net *net, struct ifreq *ifr)
@@ -1953,6 +2137,21 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1953 case ETHTOOL_SGRO: 2137 case ETHTOOL_SGRO:
1954 rc = ethtool_set_one_feature(dev, useraddr, ethcmd); 2138 rc = ethtool_set_one_feature(dev, useraddr, ethcmd);
1955 break; 2139 break;
2140 case ETHTOOL_GCHANNELS:
2141 rc = ethtool_get_channels(dev, useraddr);
2142 break;
2143 case ETHTOOL_SCHANNELS:
2144 rc = ethtool_set_channels(dev, useraddr);
2145 break;
2146 case ETHTOOL_SET_DUMP:
2147 rc = ethtool_set_dump(dev, useraddr);
2148 break;
2149 case ETHTOOL_GET_DUMP_FLAG:
2150 rc = ethtool_get_dump_flag(dev, useraddr);
2151 break;
2152 case ETHTOOL_GET_DUMP_DATA:
2153 rc = ethtool_get_dump_data(dev, useraddr);
2154 break;
1956 default: 2155 default:
1957 rc = -EOPNOTSUPP; 2156 rc = -EOPNOTSUPP;
1958 } 2157 }