diff options
| -rw-r--r-- | include/linux/ethtool.h | 31 | ||||
| -rw-r--r-- | net/core/ethtool.c | 90 |
2 files changed, 121 insertions, 0 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index bd0b50b85f06..c6a850ab2ec5 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h | |||
| @@ -601,6 +601,26 @@ struct ethtool_flash { | |||
| 601 | char data[ETHTOOL_FLASH_MAX_FILENAME]; | 601 | char data[ETHTOOL_FLASH_MAX_FILENAME]; |
| 602 | }; | 602 | }; |
| 603 | 603 | ||
| 604 | /** | ||
| 605 | * struct ethtool_dump - used for retrieving, setting device dump | ||
| 606 | * @cmd: Command number - %ETHTOOL_GET_DUMP_FLAG, %ETHTOOL_GET_DUMP_DATA, or | ||
| 607 | * %ETHTOOL_SET_DUMP | ||
| 608 | * @version: FW version of the dump, filled in by driver | ||
| 609 | * @flag: driver dependent flag for dump setting, filled in by driver during | ||
| 610 | * get and filled in by ethtool for set operation | ||
| 611 | * @len: length of dump data, used as the length of the user buffer on entry to | ||
| 612 | * %ETHTOOL_GET_DUMP_DATA and this is returned as dump length by driver | ||
| 613 | * for %ETHTOOL_GET_DUMP_FLAG command | ||
| 614 | * @data: data collected for get dump data operation | ||
| 615 | */ | ||
| 616 | struct ethtool_dump { | ||
| 617 | __u32 cmd; | ||
| 618 | __u32 version; | ||
| 619 | __u32 flag; | ||
| 620 | __u32 len; | ||
| 621 | __u8 data[0]; | ||
| 622 | }; | ||
| 623 | |||
| 604 | /* for returning and changing feature sets */ | 624 | /* for returning and changing feature sets */ |
| 605 | 625 | ||
| 606 | /** | 626 | /** |
| @@ -853,6 +873,10 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); | |||
| 853 | * @get_channels: Get number of channels. | 873 | * @get_channels: Get number of channels. |
| 854 | * @set_channels: Set number of channels. Returns a negative error code or | 874 | * @set_channels: Set number of channels. Returns a negative error code or |
| 855 | * zero. | 875 | * zero. |
| 876 | * @get_dump_flag: Get dump flag indicating current dump length, version, | ||
| 877 | * and flag of the device. | ||
| 878 | * @get_dump_data: Get dump data. | ||
| 879 | * @set_dump: Set dump specific flags to the device. | ||
| 856 | * | 880 | * |
| 857 | * All operations are optional (i.e. the function pointer may be set | 881 | * All operations are optional (i.e. the function pointer may be set |
| 858 | * to %NULL) and callers must take this into account. Callers must | 882 | * to %NULL) and callers must take this into account. Callers must |
| @@ -927,6 +951,10 @@ struct ethtool_ops { | |||
| 927 | const struct ethtool_rxfh_indir *); | 951 | const struct ethtool_rxfh_indir *); |
| 928 | void (*get_channels)(struct net_device *, struct ethtool_channels *); | 952 | void (*get_channels)(struct net_device *, struct ethtool_channels *); |
| 929 | int (*set_channels)(struct net_device *, struct ethtool_channels *); | 953 | int (*set_channels)(struct net_device *, struct ethtool_channels *); |
| 954 | int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); | ||
| 955 | int (*get_dump_data)(struct net_device *, | ||
| 956 | struct ethtool_dump *, void *); | ||
| 957 | int (*set_dump)(struct net_device *, struct ethtool_dump *); | ||
| 930 | 958 | ||
| 931 | }; | 959 | }; |
| 932 | #endif /* __KERNEL__ */ | 960 | #endif /* __KERNEL__ */ |
| @@ -998,6 +1026,9 @@ struct ethtool_ops { | |||
| 998 | #define ETHTOOL_SFEATURES 0x0000003b /* Change device offload settings */ | 1026 | #define ETHTOOL_SFEATURES 0x0000003b /* Change device offload settings */ |
| 999 | #define ETHTOOL_GCHANNELS 0x0000003c /* Get no of channels */ | 1027 | #define ETHTOOL_GCHANNELS 0x0000003c /* Get no of channels */ |
| 1000 | #define ETHTOOL_SCHANNELS 0x0000003d /* Set no of channels */ | 1028 | #define ETHTOOL_SCHANNELS 0x0000003d /* Set no of channels */ |
| 1029 | #define ETHTOOL_SET_DUMP 0x0000003e /* Set dump settings */ | ||
| 1030 | #define ETHTOOL_GET_DUMP_FLAG 0x0000003f /* Get dump settings */ | ||
| 1031 | #define ETHTOOL_GET_DUMP_DATA 0x00000040 /* Get dump data */ | ||
| 1001 | 1032 | ||
| 1002 | /* compatibility with older code */ | 1033 | /* compatibility with older code */ |
| 1003 | #define SPARC_ETH_GSET ETHTOOL_GSET | 1034 | #define SPARC_ETH_GSET ETHTOOL_GSET |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index b8c2b10f397a..b8c2bcfee6af 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
| @@ -1823,6 +1823,87 @@ static noinline_for_stack int ethtool_flash_device(struct net_device *dev, | |||
| 1823 | return dev->ethtool_ops->flash_device(dev, &efl); | 1823 | return dev->ethtool_ops->flash_device(dev, &efl); |
| 1824 | } | 1824 | } |
| 1825 | 1825 | ||
| 1826 | static int ethtool_set_dump(struct net_device *dev, | ||
| 1827 | void __user *useraddr) | ||
| 1828 | { | ||
| 1829 | struct ethtool_dump dump; | ||
| 1830 | |||
| 1831 | if (!dev->ethtool_ops->set_dump) | ||
| 1832 | return -EOPNOTSUPP; | ||
| 1833 | |||
| 1834 | if (copy_from_user(&dump, useraddr, sizeof(dump))) | ||
| 1835 | return -EFAULT; | ||
| 1836 | |||
| 1837 | return dev->ethtool_ops->set_dump(dev, &dump); | ||
| 1838 | } | ||
| 1839 | |||
| 1840 | static int ethtool_get_dump_flag(struct net_device *dev, | ||
| 1841 | void __user *useraddr) | ||
| 1842 | { | ||
| 1843 | int ret; | ||
| 1844 | struct ethtool_dump dump; | ||
| 1845 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
| 1846 | |||
| 1847 | if (!dev->ethtool_ops->get_dump_flag) | ||
| 1848 | return -EOPNOTSUPP; | ||
| 1849 | |||
| 1850 | if (copy_from_user(&dump, useraddr, sizeof(dump))) | ||
| 1851 | return -EFAULT; | ||
| 1852 | |||
| 1853 | ret = ops->get_dump_flag(dev, &dump); | ||
| 1854 | if (ret) | ||
| 1855 | return ret; | ||
| 1856 | |||
| 1857 | if (copy_to_user(useraddr, &dump, sizeof(dump))) | ||
| 1858 | return -EFAULT; | ||
| 1859 | return 0; | ||
| 1860 | } | ||
| 1861 | |||
| 1862 | static int ethtool_get_dump_data(struct net_device *dev, | ||
| 1863 | void __user *useraddr) | ||
| 1864 | { | ||
| 1865 | int ret; | ||
| 1866 | __u32 len; | ||
| 1867 | struct ethtool_dump dump, tmp; | ||
| 1868 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
| 1869 | void *data = NULL; | ||
| 1870 | |||
| 1871 | if (!dev->ethtool_ops->get_dump_data || | ||
| 1872 | !dev->ethtool_ops->get_dump_flag) | ||
| 1873 | return -EOPNOTSUPP; | ||
| 1874 | |||
| 1875 | if (copy_from_user(&dump, useraddr, sizeof(dump))) | ||
| 1876 | return -EFAULT; | ||
| 1877 | |||
| 1878 | memset(&tmp, 0, sizeof(tmp)); | ||
| 1879 | tmp.cmd = ETHTOOL_GET_DUMP_FLAG; | ||
| 1880 | ret = ops->get_dump_flag(dev, &tmp); | ||
| 1881 | if (ret) | ||
| 1882 | return ret; | ||
| 1883 | |||
| 1884 | len = (tmp.len > dump.len) ? dump.len : tmp.len; | ||
| 1885 | if (!len) | ||
| 1886 | return -EFAULT; | ||
| 1887 | |||
| 1888 | data = vzalloc(tmp.len); | ||
| 1889 | if (!data) | ||
| 1890 | return -ENOMEM; | ||
| 1891 | ret = ops->get_dump_data(dev, &dump, data); | ||
| 1892 | if (ret) | ||
| 1893 | goto out; | ||
| 1894 | |||
| 1895 | if (copy_to_user(useraddr, &dump, sizeof(dump))) { | ||
| 1896 | ret = -EFAULT; | ||
| 1897 | goto out; | ||
| 1898 | } | ||
| 1899 | useraddr += offsetof(struct ethtool_dump, data); | ||
| 1900 | if (copy_to_user(useraddr, data, len)) | ||
| 1901 | ret = -EFAULT; | ||
| 1902 | out: | ||
| 1903 | vfree(data); | ||
| 1904 | return ret; | ||
| 1905 | } | ||
| 1906 | |||
| 1826 | /* The main entry point in this file. Called from net/core/dev.c */ | 1907 | /* The main entry point in this file. Called from net/core/dev.c */ |
| 1827 | 1908 | ||
| 1828 | int dev_ethtool(struct net *net, struct ifreq *ifr) | 1909 | int dev_ethtool(struct net *net, struct ifreq *ifr) |
| @@ -2039,6 +2120,15 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
| 2039 | case ETHTOOL_SCHANNELS: | 2120 | case ETHTOOL_SCHANNELS: |
| 2040 | rc = ethtool_set_channels(dev, useraddr); | 2121 | rc = ethtool_set_channels(dev, useraddr); |
| 2041 | break; | 2122 | break; |
| 2123 | case ETHTOOL_SET_DUMP: | ||
| 2124 | rc = ethtool_set_dump(dev, useraddr); | ||
| 2125 | break; | ||
| 2126 | case ETHTOOL_GET_DUMP_FLAG: | ||
| 2127 | rc = ethtool_get_dump_flag(dev, useraddr); | ||
| 2128 | break; | ||
| 2129 | case ETHTOOL_GET_DUMP_DATA: | ||
| 2130 | rc = ethtool_get_dump_data(dev, useraddr); | ||
| 2131 | break; | ||
| 2042 | default: | 2132 | default: |
| 2043 | rc = -EOPNOTSUPP; | 2133 | rc = -EOPNOTSUPP; |
| 2044 | } | 2134 | } |
