blob: f135f1c92c9d68da606fb00cbef27e61ace082bc [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * net/core/ethtool.c - Ethtool ioctl handler
3 * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
4 *
5 * This file is where we call all the ethtool_ops commands to get
Matthew Wilcox61a44b92007-07-31 14:00:02 -07006 * the information ethtool needs.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Matthew Wilcox61a44b92007-07-31 14:00:02 -07008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 */
13
14#include <linux/module.h>
15#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080016#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/errno.h>
18#include <linux/ethtool.h>
19#include <linux/netdevice.h>
Jeff Garzikd17792e2010-03-04 08:21:53 +000020#include <linux/bitops.h>
chavey97f8aef2010-04-07 21:54:42 -070021#include <linux/uaccess.h>
David S. Miller73da16c2010-09-21 16:12:11 -070022#include <linux/vmalloc.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Ben Hutchings68f512f2011-04-02 00:35:15 +010024#include <linux/rtnetlink.h>
25#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +090027/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 * Some useful ethtool_ops methods that're device independent.
29 * If we find that all drivers want to do the same thing here,
30 * we can turn these into dev_() function calls.
31 */
32
33u32 ethtool_op_get_link(struct net_device *dev)
34{
35 return netif_carrier_ok(dev) ? 1 : 0;
36}
chavey97f8aef2010-04-07 21:54:42 -070037EXPORT_SYMBOL(ethtool_op_get_link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Linus Torvalds1da177e2005-04-16 15:20:36 -070039/* Handlers for each ethtool command */
40
Michał Mirosław5455c692011-02-15 16:59:17 +000041#define ETHTOOL_DEV_FEATURE_WORDS 1
42
43static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
44{
45 struct ethtool_gfeatures cmd = {
46 .cmd = ETHTOOL_GFEATURES,
47 .size = ETHTOOL_DEV_FEATURE_WORDS,
48 };
49 struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS] = {
50 {
51 .available = dev->hw_features,
52 .requested = dev->wanted_features,
53 .active = dev->features,
54 .never_changed = NETIF_F_NEVER_CHANGE,
55 },
56 };
57 u32 __user *sizeaddr;
58 u32 copy_size;
59
60 sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size);
61 if (get_user(copy_size, sizeaddr))
62 return -EFAULT;
63
64 if (copy_size > ETHTOOL_DEV_FEATURE_WORDS)
65 copy_size = ETHTOOL_DEV_FEATURE_WORDS;
66
67 if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
68 return -EFAULT;
69 useraddr += sizeof(cmd);
70 if (copy_to_user(useraddr, features, copy_size * sizeof(*features)))
71 return -EFAULT;
72
73 return 0;
74}
75
76static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
77{
78 struct ethtool_sfeatures cmd;
79 struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
80 int ret = 0;
81
82 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
83 return -EFAULT;
84 useraddr += sizeof(cmd);
85
86 if (cmd.size != ETHTOOL_DEV_FEATURE_WORDS)
87 return -EINVAL;
88
89 if (copy_from_user(features, useraddr, sizeof(features)))
90 return -EFAULT;
91
92 if (features[0].valid & ~NETIF_F_ETHTOOL_BITS)
93 return -EINVAL;
94
95 if (features[0].valid & ~dev->hw_features) {
96 features[0].valid &= dev->hw_features;
97 ret |= ETHTOOL_F_UNSUPPORTED;
98 }
99
100 dev->wanted_features &= ~features[0].valid;
101 dev->wanted_features |= features[0].valid & features[0].requested;
Michał Mirosław6cb6a272011-04-02 22:48:47 -0700102 __netdev_update_features(dev);
Michał Mirosław5455c692011-02-15 16:59:17 +0000103
104 if ((dev->wanted_features ^ dev->features) & features[0].valid)
105 ret |= ETHTOOL_F_WISH;
106
107 return ret;
108}
109
110static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GSTRING_LEN] = {
111 /* NETIF_F_SG */ "tx-scatter-gather",
112 /* NETIF_F_IP_CSUM */ "tx-checksum-ipv4",
113 /* NETIF_F_NO_CSUM */ "tx-checksum-unneeded",
114 /* NETIF_F_HW_CSUM */ "tx-checksum-ip-generic",
Michał Mirosław7cc31a92011-05-17 16:50:02 -0400115 /* NETIF_F_IPV6_CSUM */ "tx-checksum-ipv6",
Michał Mirosław5455c692011-02-15 16:59:17 +0000116 /* NETIF_F_HIGHDMA */ "highdma",
117 /* NETIF_F_FRAGLIST */ "tx-scatter-gather-fraglist",
118 /* NETIF_F_HW_VLAN_TX */ "tx-vlan-hw-insert",
119
120 /* NETIF_F_HW_VLAN_RX */ "rx-vlan-hw-parse",
121 /* NETIF_F_HW_VLAN_FILTER */ "rx-vlan-filter",
122 /* NETIF_F_VLAN_CHALLENGED */ "vlan-challenged",
123 /* NETIF_F_GSO */ "tx-generic-segmentation",
124 /* NETIF_F_LLTX */ "tx-lockless",
125 /* NETIF_F_NETNS_LOCAL */ "netns-local",
126 /* NETIF_F_GRO */ "rx-gro",
127 /* NETIF_F_LRO */ "rx-lro",
128
129 /* NETIF_F_TSO */ "tx-tcp-segmentation",
130 /* NETIF_F_UFO */ "tx-udp-fragmentation",
131 /* NETIF_F_GSO_ROBUST */ "tx-gso-robust",
132 /* NETIF_F_TSO_ECN */ "tx-tcp-ecn-segmentation",
133 /* NETIF_F_TSO6 */ "tx-tcp6-segmentation",
134 /* NETIF_F_FSO */ "tx-fcoe-segmentation",
135 "",
136 "",
137
138 /* NETIF_F_FCOE_CRC */ "tx-checksum-fcoe-crc",
139 /* NETIF_F_SCTP_CSUM */ "tx-checksum-sctp",
140 /* NETIF_F_FCOE_MTU */ "fcoe-mtu",
141 /* NETIF_F_NTUPLE */ "rx-ntuple-filter",
142 /* NETIF_F_RXHASH */ "rx-hashing",
Michał Mirosławe83d3602011-02-15 16:59:18 +0000143 /* NETIF_F_RXCSUM */ "rx-checksum",
Franco Fichtner864b54182011-05-12 06:42:04 +0000144 /* NETIF_F_NOCACHE_COPY */ "tx-nocache-copy",
Mahesh Bandewareed2a122011-05-04 15:30:11 +0000145 /* NETIF_F_LOOPBACK */ "loopback",
Michał Mirosław5455c692011-02-15 16:59:17 +0000146};
147
Michał Mirosław340ae162011-02-15 16:59:16 +0000148static int __ethtool_get_sset_count(struct net_device *dev, int sset)
149{
150 const struct ethtool_ops *ops = dev->ethtool_ops;
151
Michał Mirosław5455c692011-02-15 16:59:17 +0000152 if (sset == ETH_SS_FEATURES)
153 return ARRAY_SIZE(netdev_features_strings);
154
Michał Mirosław340ae162011-02-15 16:59:16 +0000155 if (ops && ops->get_sset_count && ops->get_strings)
156 return ops->get_sset_count(dev, sset);
157 else
158 return -EOPNOTSUPP;
159}
160
161static void __ethtool_get_strings(struct net_device *dev,
162 u32 stringset, u8 *data)
163{
164 const struct ethtool_ops *ops = dev->ethtool_ops;
165
Michał Mirosław5455c692011-02-15 16:59:17 +0000166 if (stringset == ETH_SS_FEATURES)
167 memcpy(data, netdev_features_strings,
168 sizeof(netdev_features_strings));
169 else
170 /* ops->get_strings is valid because checked earlier */
171 ops->get_strings(dev, stringset, data);
Michał Mirosław340ae162011-02-15 16:59:16 +0000172}
173
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000174static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd)
Michał Mirosław0a417702011-02-15 16:59:17 +0000175{
176 /* feature masks of legacy discrete ethtool ops */
177
178 switch (eth_cmd) {
179 case ETHTOOL_GTXCSUM:
180 case ETHTOOL_STXCSUM:
181 return NETIF_F_ALL_CSUM | NETIF_F_SCTP_CSUM;
Michał Mirosławe83d3602011-02-15 16:59:18 +0000182 case ETHTOOL_GRXCSUM:
183 case ETHTOOL_SRXCSUM:
184 return NETIF_F_RXCSUM;
Michał Mirosław0a417702011-02-15 16:59:17 +0000185 case ETHTOOL_GSG:
186 case ETHTOOL_SSG:
187 return NETIF_F_SG;
188 case ETHTOOL_GTSO:
189 case ETHTOOL_STSO:
190 return NETIF_F_ALL_TSO;
191 case ETHTOOL_GUFO:
192 case ETHTOOL_SUFO:
193 return NETIF_F_UFO;
194 case ETHTOOL_GGSO:
195 case ETHTOOL_SGSO:
196 return NETIF_F_GSO;
197 case ETHTOOL_GGRO:
198 case ETHTOOL_SGRO:
199 return NETIF_F_GRO;
200 default:
201 BUG();
202 }
203}
204
Michał Mirosław0a417702011-02-15 16:59:17 +0000205static int ethtool_get_one_feature(struct net_device *dev,
206 char __user *useraddr, u32 ethcmd)
207{
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000208 netdev_features_t mask = ethtool_get_feature_mask(ethcmd);
Michał Mirosław0a417702011-02-15 16:59:17 +0000209 struct ethtool_value edata = {
210 .cmd = ethcmd,
Michał Mirosław86794882011-02-15 16:59:17 +0000211 .data = !!(dev->features & mask),
Michał Mirosław0a417702011-02-15 16:59:17 +0000212 };
Michał Mirosław0a417702011-02-15 16:59:17 +0000213
Michał Mirosław0a417702011-02-15 16:59:17 +0000214 if (copy_to_user(useraddr, &edata, sizeof(edata)))
215 return -EFAULT;
216 return 0;
217}
218
Michał Mirosław0a417702011-02-15 16:59:17 +0000219static int ethtool_set_one_feature(struct net_device *dev,
220 void __user *useraddr, u32 ethcmd)
221{
222 struct ethtool_value edata;
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000223 netdev_features_t mask;
Michał Mirosław0a417702011-02-15 16:59:17 +0000224
225 if (copy_from_user(&edata, useraddr, sizeof(edata)))
226 return -EFAULT;
227
Michał Mirosław86794882011-02-15 16:59:17 +0000228 mask = ethtool_get_feature_mask(ethcmd);
229 mask &= dev->hw_features;
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000230 if (!mask)
Michał Mirosław0a417702011-02-15 16:59:17 +0000231 return -EOPNOTSUPP;
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000232
233 if (edata.data)
234 dev->wanted_features |= mask;
235 else
236 dev->wanted_features &= ~mask;
237
238 __netdev_update_features(dev);
239
240 return 0;
Michał Mirosław0a417702011-02-15 16:59:17 +0000241}
242
Michał Mirosław02b3a552011-11-15 15:29:55 +0000243#define ETH_ALL_FLAGS (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \
244 ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH)
245#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_RX | \
246 NETIF_F_HW_VLAN_TX | NETIF_F_NTUPLE | NETIF_F_RXHASH)
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000247
248static u32 __ethtool_get_flags(struct net_device *dev)
249{
Michał Mirosław02b3a552011-11-15 15:29:55 +0000250 u32 flags = 0;
251
252 if (dev->features & NETIF_F_LRO) flags |= ETH_FLAG_LRO;
253 if (dev->features & NETIF_F_HW_VLAN_RX) flags |= ETH_FLAG_RXVLAN;
254 if (dev->features & NETIF_F_HW_VLAN_TX) flags |= ETH_FLAG_TXVLAN;
255 if (dev->features & NETIF_F_NTUPLE) flags |= ETH_FLAG_NTUPLE;
256 if (dev->features & NETIF_F_RXHASH) flags |= ETH_FLAG_RXHASH;
257
258 return flags;
Michał Mirosławbc5787c62011-11-15 15:29:55 +0000259}
260
261static int __ethtool_set_flags(struct net_device *dev, u32 data)
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000262{
Michał Mirosławc8f44af2011-11-15 15:29:55 +0000263 netdev_features_t features = 0, changed;
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000264
Michał Mirosław02b3a552011-11-15 15:29:55 +0000265 if (data & ~ETH_ALL_FLAGS)
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000266 return -EINVAL;
267
Michał Mirosław02b3a552011-11-15 15:29:55 +0000268 if (data & ETH_FLAG_LRO) features |= NETIF_F_LRO;
269 if (data & ETH_FLAG_RXVLAN) features |= NETIF_F_HW_VLAN_RX;
270 if (data & ETH_FLAG_TXVLAN) features |= NETIF_F_HW_VLAN_TX;
271 if (data & ETH_FLAG_NTUPLE) features |= NETIF_F_NTUPLE;
272 if (data & ETH_FLAG_RXHASH) features |= NETIF_F_RXHASH;
273
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000274 /* allow changing only bits set in hw_features */
Michał Mirosław02b3a552011-11-15 15:29:55 +0000275 changed = (features ^ dev->features) & ETH_ALL_FEATURES;
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000276 if (changed & ~dev->hw_features)
277 return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;
278
279 dev->wanted_features =
Michał Mirosław02b3a552011-11-15 15:29:55 +0000280 (dev->wanted_features & ~changed) | (features & changed);
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000281
Michał Mirosław6cb6a272011-04-02 22:48:47 -0700282 __netdev_update_features(dev);
Michał Mirosławda8ac86c2011-02-15 16:59:18 +0000283
284 return 0;
285}
286
Jiri Pirko4bc71cb2011-09-03 03:34:30 +0000287int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Jiri Pirko4bc71cb2011-09-03 03:34:30 +0000289 ASSERT_RTNL();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Jiri Pirko4bc71cb2011-09-03 03:34:30 +0000291 if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return -EOPNOTSUPP;
293
Jiri Pirko4bc71cb2011-09-03 03:34:30 +0000294 memset(cmd, 0, sizeof(struct ethtool_cmd));
295 cmd->cmd = ETHTOOL_GSET;
296 return dev->ethtool_ops->get_settings(dev, cmd);
297}
298EXPORT_SYMBOL(__ethtool_get_settings);
299
300static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
301{
302 int err;
303 struct ethtool_cmd cmd;
304
305 err = __ethtool_get_settings(dev, &cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 if (err < 0)
307 return err;
308
309 if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
310 return -EFAULT;
311 return 0;
312}
313
314static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
315{
316 struct ethtool_cmd cmd;
317
318 if (!dev->ethtool_ops->set_settings)
319 return -EOPNOTSUPP;
320
321 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
322 return -EFAULT;
323
324 return dev->ethtool_ops->set_settings(dev, &cmd);
325}
326
chavey97f8aef2010-04-07 21:54:42 -0700327static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
328 void __user *useraddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 struct ethtool_drvinfo info;
Stephen Hemminger76fd8592006-09-08 11:16:13 -0700331 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 memset(&info, 0, sizeof(info));
334 info.cmd = ETHTOOL_GDRVINFO;
Ben Hutchings01414802010-08-17 02:31:15 -0700335 if (ops && ops->get_drvinfo) {
336 ops->get_drvinfo(dev, &info);
337 } else if (dev->dev.parent && dev->dev.parent->driver) {
338 strlcpy(info.bus_info, dev_name(dev->dev.parent),
339 sizeof(info.bus_info));
340 strlcpy(info.driver, dev->dev.parent->driver->name,
341 sizeof(info.driver));
342 } else {
343 return -EOPNOTSUPP;
344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Jeff Garzik723b2f52010-03-03 22:51:50 +0000346 /*
347 * this method of obtaining string set info is deprecated;
Jeff Garzikd17792e2010-03-04 08:21:53 +0000348 * Use ETHTOOL_GSSET_INFO instead.
Jeff Garzik723b2f52010-03-03 22:51:50 +0000349 */
Ben Hutchings01414802010-08-17 02:31:15 -0700350 if (ops && ops->get_sset_count) {
Jeff Garzikff03d492007-08-15 16:01:08 -0700351 int rc;
352
353 rc = ops->get_sset_count(dev, ETH_SS_TEST);
354 if (rc >= 0)
355 info.testinfo_len = rc;
356 rc = ops->get_sset_count(dev, ETH_SS_STATS);
357 if (rc >= 0)
358 info.n_stats = rc;
Jeff Garzik339bf022007-08-15 16:01:32 -0700359 rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
360 if (rc >= 0)
361 info.n_priv_flags = rc;
Jeff Garzikff03d492007-08-15 16:01:08 -0700362 }
Ben Hutchings01414802010-08-17 02:31:15 -0700363 if (ops && ops->get_regs_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 info.regdump_len = ops->get_regs_len(dev);
Ben Hutchings01414802010-08-17 02:31:15 -0700365 if (ops && ops->get_eeprom_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 info.eedump_len = ops->get_eeprom_len(dev);
367
368 if (copy_to_user(useraddr, &info, sizeof(info)))
369 return -EFAULT;
370 return 0;
371}
372
Eric Dumazetf5c445e2010-03-08 12:17:04 -0800373static noinline_for_stack int ethtool_get_sset_info(struct net_device *dev,
chavey97f8aef2010-04-07 21:54:42 -0700374 void __user *useraddr)
Jeff Garzik723b2f52010-03-03 22:51:50 +0000375{
376 struct ethtool_sset_info info;
Jeff Garzik723b2f52010-03-03 22:51:50 +0000377 u64 sset_mask;
378 int i, idx = 0, n_bits = 0, ret, rc;
379 u32 *info_buf = NULL;
380
Jeff Garzik723b2f52010-03-03 22:51:50 +0000381 if (copy_from_user(&info, useraddr, sizeof(info)))
382 return -EFAULT;
383
384 /* store copy of mask, because we zero struct later on */
385 sset_mask = info.sset_mask;
386 if (!sset_mask)
387 return 0;
388
389 /* calculate size of return buffer */
Jeff Garzikd17792e2010-03-04 08:21:53 +0000390 n_bits = hweight64(sset_mask);
Jeff Garzik723b2f52010-03-03 22:51:50 +0000391
392 memset(&info, 0, sizeof(info));
393 info.cmd = ETHTOOL_GSSET_INFO;
394
395 info_buf = kzalloc(n_bits * sizeof(u32), GFP_USER);
396 if (!info_buf)
397 return -ENOMEM;
398
399 /*
400 * fill return buffer based on input bitmask and successful
401 * get_sset_count return
402 */
403 for (i = 0; i < 64; i++) {
404 if (!(sset_mask & (1ULL << i)))
405 continue;
406
Michał Mirosław340ae162011-02-15 16:59:16 +0000407 rc = __ethtool_get_sset_count(dev, i);
Jeff Garzik723b2f52010-03-03 22:51:50 +0000408 if (rc >= 0) {
409 info.sset_mask |= (1ULL << i);
410 info_buf[idx++] = rc;
411 }
412 }
413
414 ret = -EFAULT;
415 if (copy_to_user(useraddr, &info, sizeof(info)))
416 goto out;
417
418 useraddr += offsetof(struct ethtool_sset_info, data);
419 if (copy_to_user(useraddr, info_buf, idx * sizeof(u32)))
420 goto out;
421
422 ret = 0;
423
424out:
425 kfree(info_buf);
426 return ret;
427}
428
chavey97f8aef2010-04-07 21:54:42 -0700429static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
Ben Hutchingsbf988432010-06-28 08:45:58 +0000430 u32 cmd, void __user *useraddr)
Santwona Behera0853ad62008-07-02 03:47:41 -0700431{
Ben Hutchingsbf988432010-06-28 08:45:58 +0000432 struct ethtool_rxnfc info;
433 size_t info_size = sizeof(info);
Santwona Behera0853ad62008-07-02 03:47:41 -0700434
Santwona Behera59089d82009-02-20 00:58:13 -0800435 if (!dev->ethtool_ops->set_rxnfc)
Santwona Behera0853ad62008-07-02 03:47:41 -0700436 return -EOPNOTSUPP;
437
Ben Hutchingsbf988432010-06-28 08:45:58 +0000438 /* struct ethtool_rxnfc was originally defined for
439 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
440 * members. User-space might still be using that
441 * definition. */
442 if (cmd == ETHTOOL_SRXFH)
443 info_size = (offsetof(struct ethtool_rxnfc, data) +
444 sizeof(info.data));
445
446 if (copy_from_user(&info, useraddr, info_size))
Santwona Behera0853ad62008-07-02 03:47:41 -0700447 return -EFAULT;
448
Ben Hutchingsbf988432010-06-28 08:45:58 +0000449 return dev->ethtool_ops->set_rxnfc(dev, &info);
Santwona Behera0853ad62008-07-02 03:47:41 -0700450}
451
chavey97f8aef2010-04-07 21:54:42 -0700452static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
Ben Hutchingsbf988432010-06-28 08:45:58 +0000453 u32 cmd, void __user *useraddr)
Santwona Behera0853ad62008-07-02 03:47:41 -0700454{
455 struct ethtool_rxnfc info;
Ben Hutchingsbf988432010-06-28 08:45:58 +0000456 size_t info_size = sizeof(info);
Santwona Behera59089d82009-02-20 00:58:13 -0800457 const struct ethtool_ops *ops = dev->ethtool_ops;
458 int ret;
459 void *rule_buf = NULL;
Santwona Behera0853ad62008-07-02 03:47:41 -0700460
Santwona Behera59089d82009-02-20 00:58:13 -0800461 if (!ops->get_rxnfc)
Santwona Behera0853ad62008-07-02 03:47:41 -0700462 return -EOPNOTSUPP;
463
Ben Hutchingsbf988432010-06-28 08:45:58 +0000464 /* struct ethtool_rxnfc was originally defined for
465 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
466 * members. User-space might still be using that
467 * definition. */
468 if (cmd == ETHTOOL_GRXFH)
469 info_size = (offsetof(struct ethtool_rxnfc, data) +
470 sizeof(info.data));
471
472 if (copy_from_user(&info, useraddr, info_size))
Santwona Behera0853ad62008-07-02 03:47:41 -0700473 return -EFAULT;
474
Santwona Behera59089d82009-02-20 00:58:13 -0800475 if (info.cmd == ETHTOOL_GRXCLSRLALL) {
476 if (info.rule_cnt > 0) {
Ben Hutchingsdb048b62010-06-28 08:44:07 +0000477 if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32))
Kees Cookae6df5f2010-10-07 10:03:48 +0000478 rule_buf = kzalloc(info.rule_cnt * sizeof(u32),
Ben Hutchingsdb048b62010-06-28 08:44:07 +0000479 GFP_USER);
Santwona Behera59089d82009-02-20 00:58:13 -0800480 if (!rule_buf)
481 return -ENOMEM;
482 }
483 }
Santwona Behera0853ad62008-07-02 03:47:41 -0700484
Santwona Behera59089d82009-02-20 00:58:13 -0800485 ret = ops->get_rxnfc(dev, &info, rule_buf);
486 if (ret < 0)
487 goto err_out;
488
489 ret = -EFAULT;
Ben Hutchingsbf988432010-06-28 08:45:58 +0000490 if (copy_to_user(useraddr, &info, info_size))
Santwona Behera59089d82009-02-20 00:58:13 -0800491 goto err_out;
492
493 if (rule_buf) {
494 useraddr += offsetof(struct ethtool_rxnfc, rule_locs);
495 if (copy_to_user(useraddr, rule_buf,
496 info.rule_cnt * sizeof(u32)))
497 goto err_out;
498 }
499 ret = 0;
500
501err_out:
Wei Yongjunc9cacec2009-03-31 15:06:26 -0700502 kfree(rule_buf);
Santwona Behera59089d82009-02-20 00:58:13 -0800503
504 return ret;
Santwona Behera0853ad62008-07-02 03:47:41 -0700505}
506
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000507static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
508 void __user *useraddr)
509{
510 struct ethtool_rxfh_indir *indir;
511 u32 table_size;
512 size_t full_size;
513 int ret;
514
515 if (!dev->ethtool_ops->get_rxfh_indir)
516 return -EOPNOTSUPP;
517
518 if (copy_from_user(&table_size,
519 useraddr + offsetof(struct ethtool_rxfh_indir, size),
520 sizeof(table_size)))
521 return -EFAULT;
522
523 if (table_size >
524 (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
525 return -ENOMEM;
526 full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
Kees Cookb00916b2010-10-11 12:23:25 -0700527 indir = kzalloc(full_size, GFP_USER);
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +0000528 if (!indir)
529 return -ENOMEM;
530
531 indir->cmd = ETHTOOL_GRXFHINDIR;
532 indir->size = table_size;
533 ret = dev->ethtool_ops->get_rxfh_indir(dev, indir);
534 if (ret)
535 goto out;
536
537 if (copy_to_user(useraddr, indir, full_size))
538 ret = -EFAULT;
539
540out:
541 kfree(indir);
542 return ret;
543}
544
545static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
546 void __user *useraddr)
547{
548 struct ethtool_rxfh_indir *indir;
549 u32 table_size;
550 size_t full_size;
551 int ret;
552
553 if (!dev->ethtool_ops->set_rxfh_indir)
554 return -EOPNOTSUPP;
555
556 if (copy_from_user(&table_size,
557 useraddr + offsetof(struct ethtool_rxfh_indir, size),
558 sizeof(table_size)))
559 return -EFAULT;
560
561 if (table_size >
562 (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
563 return -ENOMEM;
564 full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
565 indir = kmalloc(full_size, GFP_USER);
566 if (!indir)
567 return -ENOMEM;
568
569 if (copy_from_user(indir, useraddr, full_size)) {
570 ret = -EFAULT;
571 goto out;
572 }
573
574 ret = dev->ethtool_ops->set_rxfh_indir(dev, indir);
575
576out:
577 kfree(indir);
578 return ret;
579}
580
Ben Hutchingsbe2902d2010-09-16 11:28:07 +0000581/*
582 * ethtool does not (or did not) set masks for flow parameters that are
583 * not specified, so if both value and mask are 0 then this must be
584 * treated as equivalent to a mask with all bits set. Implement that
585 * here rather than in drivers.
586 */
587static void rx_ntuple_fix_masks(struct ethtool_rx_ntuple_flow_spec *fs)
588{
589 struct ethtool_tcpip4_spec *entry = &fs->h_u.tcp_ip4_spec;
590 struct ethtool_tcpip4_spec *mask = &fs->m_u.tcp_ip4_spec;
591
592 if (fs->flow_type != TCP_V4_FLOW &&
593 fs->flow_type != UDP_V4_FLOW &&
594 fs->flow_type != SCTP_V4_FLOW)
595 return;
596
597 if (!(entry->ip4src | mask->ip4src))
598 mask->ip4src = htonl(0xffffffff);
599 if (!(entry->ip4dst | mask->ip4dst))
600 mask->ip4dst = htonl(0xffffffff);
601 if (!(entry->psrc | mask->psrc))
602 mask->psrc = htons(0xffff);
603 if (!(entry->pdst | mask->pdst))
604 mask->pdst = htons(0xffff);
605 if (!(entry->tos | mask->tos))
606 mask->tos = 0xff;
607 if (!(fs->vlan_tag | fs->vlan_tag_mask))
608 fs->vlan_tag_mask = 0xffff;
609 if (!(fs->data | fs->data_mask))
610 fs->data_mask = 0xffffffffffffffffULL;
611}
612
chavey97f8aef2010-04-07 21:54:42 -0700613static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev,
614 void __user *useraddr)
Peter P Waskiewicz Jr15682bc2010-02-10 20:03:05 -0800615{
616 struct ethtool_rx_ntuple cmd;
617 const struct ethtool_ops *ops = dev->ethtool_ops;
Peter P Waskiewicz Jr15682bc2010-02-10 20:03:05 -0800618
Alexander Duyck5d9f11c2011-04-08 12:07:22 +0000619 if (!ops->set_rx_ntuple)
620 return -EOPNOTSUPP;
621
Peter P Waskiewicz Jr15682bc2010-02-10 20:03:05 -0800622 if (!(dev->features & NETIF_F_NTUPLE))
623 return -EINVAL;
624
625 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
626 return -EFAULT;
627
Ben Hutchingsbe2902d2010-09-16 11:28:07 +0000628 rx_ntuple_fix_masks(&cmd.fs);
629
Alexander Duyckbff55272011-06-08 12:35:08 +0000630 return ops->set_rx_ntuple(dev, &cmd);
Peter P Waskiewicz Jr15682bc2010-02-10 20:03:05 -0800631}
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
634{
635 struct ethtool_regs regs;
Stephen Hemminger76fd8592006-09-08 11:16:13 -0700636 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 void *regbuf;
638 int reglen, ret;
639
640 if (!ops->get_regs || !ops->get_regs_len)
641 return -EOPNOTSUPP;
642
643 if (copy_from_user(&regs, useraddr, sizeof(regs)))
644 return -EFAULT;
645
646 reglen = ops->get_regs_len(dev);
647 if (regs.len > reglen)
648 regs.len = reglen;
649
Eugene Teob7c7d012011-01-24 21:05:17 -0800650 regbuf = vzalloc(reglen);
Ben Hutchings67ae7cf2011-07-21 15:25:30 -0700651 if (reglen && !regbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 return -ENOMEM;
653
654 ops->get_regs(dev, &regs, regbuf);
655
656 ret = -EFAULT;
657 if (copy_to_user(useraddr, &regs, sizeof(regs)))
658 goto out;
659 useraddr += offsetof(struct ethtool_regs, data);
Ben Hutchings67ae7cf2011-07-21 15:25:30 -0700660 if (regbuf && copy_to_user(useraddr, regbuf, regs.len))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 goto out;
662 ret = 0;
663
664 out:
Ben Hutchingsa77f5db2010-09-20 08:42:17 +0000665 vfree(regbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 return ret;
667}
668
Ben Hutchingsd73d3a82009-10-05 10:59:58 +0000669static int ethtool_reset(struct net_device *dev, char __user *useraddr)
670{
671 struct ethtool_value reset;
672 int ret;
673
674 if (!dev->ethtool_ops->reset)
675 return -EOPNOTSUPP;
676
677 if (copy_from_user(&reset, useraddr, sizeof(reset)))
678 return -EFAULT;
679
680 ret = dev->ethtool_ops->reset(dev, &reset.data);
681 if (ret)
682 return ret;
683
684 if (copy_to_user(useraddr, &reset, sizeof(reset)))
685 return -EFAULT;
686 return 0;
687}
688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
690{
Roland Dreier8e557422010-02-11 12:14:23 -0800691 struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693 if (!dev->ethtool_ops->get_wol)
694 return -EOPNOTSUPP;
695
696 dev->ethtool_ops->get_wol(dev, &wol);
697
698 if (copy_to_user(useraddr, &wol, sizeof(wol)))
699 return -EFAULT;
700 return 0;
701}
702
703static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
704{
705 struct ethtool_wolinfo wol;
706
707 if (!dev->ethtool_ops->set_wol)
708 return -EOPNOTSUPP;
709
710 if (copy_from_user(&wol, useraddr, sizeof(wol)))
711 return -EFAULT;
712
713 return dev->ethtool_ops->set_wol(dev, &wol);
714}
715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716static int ethtool_nway_reset(struct net_device *dev)
717{
718 if (!dev->ethtool_ops->nway_reset)
719 return -EOPNOTSUPP;
720
721 return dev->ethtool_ops->nway_reset(dev);
722}
723
Ben Hutchingse596e6e2010-12-09 12:08:35 +0000724static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
725{
726 struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };
727
728 if (!dev->ethtool_ops->get_link)
729 return -EOPNOTSUPP;
730
731 edata.data = netif_running(dev) && dev->ethtool_ops->get_link(dev);
732
733 if (copy_to_user(useraddr, &edata, sizeof(edata)))
734 return -EFAULT;
735 return 0;
736}
737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
739{
740 struct ethtool_eeprom eeprom;
Stephen Hemminger76fd8592006-09-08 11:16:13 -0700741 const struct ethtool_ops *ops = dev->ethtool_ops;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -0700742 void __user *userbuf = useraddr + sizeof(eeprom);
743 u32 bytes_remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 u8 *data;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -0700745 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
747 if (!ops->get_eeprom || !ops->get_eeprom_len)
748 return -EOPNOTSUPP;
749
750 if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
751 return -EFAULT;
752
753 /* Check for wrap and zero */
754 if (eeprom.offset + eeprom.len <= eeprom.offset)
755 return -EINVAL;
756
757 /* Check for exceeding total eeprom len */
758 if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
759 return -EINVAL;
760
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -0700761 data = kmalloc(PAGE_SIZE, GFP_USER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if (!data)
763 return -ENOMEM;
764
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -0700765 bytes_remaining = eeprom.len;
766 while (bytes_remaining > 0) {
767 eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -0700769 ret = ops->get_eeprom(dev, &eeprom, data);
770 if (ret)
771 break;
772 if (copy_to_user(userbuf, data, eeprom.len)) {
773 ret = -EFAULT;
774 break;
775 }
776 userbuf += eeprom.len;
777 eeprom.offset += eeprom.len;
778 bytes_remaining -= eeprom.len;
779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Mandeep Singh Bainesc5835df2008-04-24 20:55:56 -0700781 eeprom.len = userbuf - (useraddr + sizeof(eeprom));
782 eeprom.offset -= eeprom.len;
783 if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
784 ret = -EFAULT;
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 kfree(data);
787 return ret;
788}
789
790static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
791{
792 struct ethtool_eeprom eeprom;
Stephen Hemminger76fd8592006-09-08 11:16:13 -0700793 const struct ethtool_ops *ops = dev->ethtool_ops;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -0700794 void __user *userbuf = useraddr + sizeof(eeprom);
795 u32 bytes_remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 u8 *data;
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -0700797 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 if (!ops->set_eeprom || !ops->get_eeprom_len)
800 return -EOPNOTSUPP;
801
802 if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
803 return -EFAULT;
804
805 /* Check for wrap and zero */
806 if (eeprom.offset + eeprom.len <= eeprom.offset)
807 return -EINVAL;
808
809 /* Check for exceeding total eeprom len */
810 if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
811 return -EINVAL;
812
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -0700813 data = kmalloc(PAGE_SIZE, GFP_USER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 if (!data)
815 return -ENOMEM;
816
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -0700817 bytes_remaining = eeprom.len;
818 while (bytes_remaining > 0) {
819 eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Mandeep Singh Bainesb131dd52008-04-15 19:24:17 -0700821 if (copy_from_user(data, userbuf, eeprom.len)) {
822 ret = -EFAULT;
823 break;
824 }
825 ret = ops->set_eeprom(dev, &eeprom, data);
826 if (ret)
827 break;
828 userbuf += eeprom.len;
829 eeprom.offset += eeprom.len;
830 bytes_remaining -= eeprom.len;
831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 kfree(data);
834 return ret;
835}
836
chavey97f8aef2010-04-07 21:54:42 -0700837static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev,
838 void __user *useraddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839{
Roland Dreier8e557422010-02-11 12:14:23 -0800840 struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
842 if (!dev->ethtool_ops->get_coalesce)
843 return -EOPNOTSUPP;
844
845 dev->ethtool_ops->get_coalesce(dev, &coalesce);
846
847 if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
848 return -EFAULT;
849 return 0;
850}
851
chavey97f8aef2010-04-07 21:54:42 -0700852static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
853 void __user *useraddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854{
855 struct ethtool_coalesce coalesce;
856
David S. Millerfa04ae52005-06-06 15:07:19 -0700857 if (!dev->ethtool_ops->set_coalesce)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 return -EOPNOTSUPP;
859
860 if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
861 return -EFAULT;
862
863 return dev->ethtool_ops->set_coalesce(dev, &coalesce);
864}
865
866static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
867{
Roland Dreier8e557422010-02-11 12:14:23 -0800868 struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
870 if (!dev->ethtool_ops->get_ringparam)
871 return -EOPNOTSUPP;
872
873 dev->ethtool_ops->get_ringparam(dev, &ringparam);
874
875 if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
876 return -EFAULT;
877 return 0;
878}
879
880static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
881{
882 struct ethtool_ringparam ringparam;
883
884 if (!dev->ethtool_ops->set_ringparam)
885 return -EOPNOTSUPP;
886
887 if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
888 return -EFAULT;
889
890 return dev->ethtool_ops->set_ringparam(dev, &ringparam);
891}
892
amit salecha8b5933c2011-04-07 01:58:42 +0000893static noinline_for_stack int ethtool_get_channels(struct net_device *dev,
894 void __user *useraddr)
895{
896 struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
897
898 if (!dev->ethtool_ops->get_channels)
899 return -EOPNOTSUPP;
900
901 dev->ethtool_ops->get_channels(dev, &channels);
902
903 if (copy_to_user(useraddr, &channels, sizeof(channels)))
904 return -EFAULT;
905 return 0;
906}
907
908static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
909 void __user *useraddr)
910{
911 struct ethtool_channels channels;
912
913 if (!dev->ethtool_ops->set_channels)
914 return -EOPNOTSUPP;
915
916 if (copy_from_user(&channels, useraddr, sizeof(channels)))
917 return -EFAULT;
918
919 return dev->ethtool_ops->set_channels(dev, &channels);
920}
921
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
923{
924 struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
925
926 if (!dev->ethtool_ops->get_pauseparam)
927 return -EOPNOTSUPP;
928
929 dev->ethtool_ops->get_pauseparam(dev, &pauseparam);
930
931 if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
932 return -EFAULT;
933 return 0;
934}
935
936static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
937{
938 struct ethtool_pauseparam pauseparam;
939
Jeff Garzike1b90c42006-07-17 12:54:40 -0400940 if (!dev->ethtool_ops->set_pauseparam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 return -EOPNOTSUPP;
942
943 if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
944 return -EFAULT;
945
946 return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
947}
948
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
950{
951 struct ethtool_test test;
Stephen Hemminger76fd8592006-09-08 11:16:13 -0700952 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 u64 *data;
Jeff Garzikff03d492007-08-15 16:01:08 -0700954 int ret, test_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Ben Hutchingsa9828ec2009-10-01 11:33:03 +0000956 if (!ops->self_test || !ops->get_sset_count)
Jeff Garzikff03d492007-08-15 16:01:08 -0700957 return -EOPNOTSUPP;
958
Ben Hutchingsa9828ec2009-10-01 11:33:03 +0000959 test_len = ops->get_sset_count(dev, ETH_SS_TEST);
Jeff Garzikff03d492007-08-15 16:01:08 -0700960 if (test_len < 0)
961 return test_len;
962 WARN_ON(test_len == 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
964 if (copy_from_user(&test, useraddr, sizeof(test)))
965 return -EFAULT;
966
Jeff Garzikff03d492007-08-15 16:01:08 -0700967 test.len = test_len;
968 data = kmalloc(test_len * sizeof(u64), GFP_USER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if (!data)
970 return -ENOMEM;
971
972 ops->self_test(dev, &test, data);
973
974 ret = -EFAULT;
975 if (copy_to_user(useraddr, &test, sizeof(test)))
976 goto out;
977 useraddr += sizeof(test);
978 if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
979 goto out;
980 ret = 0;
981
982 out:
983 kfree(data);
984 return ret;
985}
986
987static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
988{
989 struct ethtool_gstrings gstrings;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 u8 *data;
991 int ret;
992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
994 return -EFAULT;
995
Michał Mirosław340ae162011-02-15 16:59:16 +0000996 ret = __ethtool_get_sset_count(dev, gstrings.string_set);
Ben Hutchingsa9828ec2009-10-01 11:33:03 +0000997 if (ret < 0)
998 return ret;
Jeff Garzikff03d492007-08-15 16:01:08 -0700999
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001000 gstrings.len = ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002 data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
1003 if (!data)
1004 return -ENOMEM;
1005
Michał Mirosław340ae162011-02-15 16:59:16 +00001006 __ethtool_get_strings(dev, gstrings.string_set, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 ret = -EFAULT;
1009 if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
1010 goto out;
1011 useraddr += sizeof(gstrings);
1012 if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
1013 goto out;
1014 ret = 0;
1015
Michał Mirosław340ae162011-02-15 16:59:16 +00001016out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 kfree(data);
1018 return ret;
1019}
1020
1021static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
1022{
1023 struct ethtool_value id;
Ben Hutchings68f512f2011-04-02 00:35:15 +01001024 static bool busy;
1025 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Stephen Hemminger1ab7b6a2011-04-14 23:46:06 -07001027 if (!dev->ethtool_ops->set_phys_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 return -EOPNOTSUPP;
1029
Ben Hutchings68f512f2011-04-02 00:35:15 +01001030 if (busy)
1031 return -EBUSY;
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 if (copy_from_user(&id, useraddr, sizeof(id)))
1034 return -EFAULT;
1035
Ben Hutchings68f512f2011-04-02 00:35:15 +01001036 rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE);
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001037 if (rc < 0)
Ben Hutchings68f512f2011-04-02 00:35:15 +01001038 return rc;
1039
1040 /* Drop the RTNL lock while waiting, but prevent reentry or
1041 * removal of the device.
1042 */
1043 busy = true;
1044 dev_hold(dev);
1045 rtnl_unlock();
1046
1047 if (rc == 0) {
1048 /* Driver will handle this itself */
1049 schedule_timeout_interruptible(
Allan, Bruce W143780c2011-04-11 13:01:59 +00001050 id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT);
Ben Hutchings68f512f2011-04-02 00:35:15 +01001051 } else {
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001052 /* Driver expects to be called at twice the frequency in rc */
1053 int n = rc * 2, i, interval = HZ / n;
Ben Hutchings68f512f2011-04-02 00:35:15 +01001054
Allan, Bruce Wfce55922011-04-13 13:09:10 +00001055 /* Count down seconds */
1056 do {
1057 /* Count down iterations per second */
1058 i = n;
1059 do {
1060 rtnl_lock();
1061 rc = dev->ethtool_ops->set_phys_id(dev,
1062 (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
1063 rtnl_unlock();
1064 if (rc)
1065 break;
1066 schedule_timeout_interruptible(interval);
1067 } while (!signal_pending(current) && --i != 0);
Ben Hutchings68f512f2011-04-02 00:35:15 +01001068 } while (!signal_pending(current) &&
1069 (id.data == 0 || --id.data != 0));
1070 }
1071
1072 rtnl_lock();
1073 dev_put(dev);
1074 busy = false;
1075
1076 (void)dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
1077 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078}
1079
1080static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
1081{
1082 struct ethtool_stats stats;
Stephen Hemminger76fd8592006-09-08 11:16:13 -07001083 const struct ethtool_ops *ops = dev->ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 u64 *data;
Jeff Garzikff03d492007-08-15 16:01:08 -07001085 int ret, n_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001087 if (!ops->get_ethtool_stats || !ops->get_sset_count)
Jeff Garzikff03d492007-08-15 16:01:08 -07001088 return -EOPNOTSUPP;
1089
Ben Hutchingsa9828ec2009-10-01 11:33:03 +00001090 n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
Jeff Garzikff03d492007-08-15 16:01:08 -07001091 if (n_stats < 0)
1092 return n_stats;
1093 WARN_ON(n_stats == 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
1095 if (copy_from_user(&stats, useraddr, sizeof(stats)))
1096 return -EFAULT;
1097
Jeff Garzikff03d492007-08-15 16:01:08 -07001098 stats.n_stats = n_stats;
1099 data = kmalloc(n_stats * sizeof(u64), GFP_USER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 if (!data)
1101 return -ENOMEM;
1102
1103 ops->get_ethtool_stats(dev, &stats, data);
1104
1105 ret = -EFAULT;
1106 if (copy_to_user(useraddr, &stats, sizeof(stats)))
1107 goto out;
1108 useraddr += sizeof(stats);
1109 if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
1110 goto out;
1111 ret = 0;
1112
1113 out:
1114 kfree(data);
1115 return ret;
1116}
1117
viro@ftp.linux.org.uk0bf0519d2005-09-05 03:26:18 +01001118static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
Jon Wetzela6f9a702005-08-20 17:15:54 -07001119{
1120 struct ethtool_perm_addr epaddr;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001121
Matthew Wilcox313674a2007-07-31 14:00:29 -07001122 if (copy_from_user(&epaddr, useraddr, sizeof(epaddr)))
Jon Wetzela6f9a702005-08-20 17:15:54 -07001123 return -EFAULT;
1124
Matthew Wilcox313674a2007-07-31 14:00:29 -07001125 if (epaddr.size < dev->addr_len)
1126 return -ETOOSMALL;
1127 epaddr.size = dev->addr_len;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001128
Jon Wetzela6f9a702005-08-20 17:15:54 -07001129 if (copy_to_user(useraddr, &epaddr, sizeof(epaddr)))
Matthew Wilcox313674a2007-07-31 14:00:29 -07001130 return -EFAULT;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001131 useraddr += sizeof(epaddr);
Matthew Wilcox313674a2007-07-31 14:00:29 -07001132 if (copy_to_user(useraddr, dev->perm_addr, epaddr.size))
1133 return -EFAULT;
1134 return 0;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001135}
1136
Jeff Garzik13c99b22007-08-15 16:01:56 -07001137static int ethtool_get_value(struct net_device *dev, char __user *useraddr,
1138 u32 cmd, u32 (*actor)(struct net_device *))
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001139{
Roland Dreier8e557422010-02-11 12:14:23 -08001140 struct ethtool_value edata = { .cmd = cmd };
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001141
Jeff Garzik13c99b22007-08-15 16:01:56 -07001142 if (!actor)
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001143 return -EOPNOTSUPP;
1144
Jeff Garzik13c99b22007-08-15 16:01:56 -07001145 edata.data = actor(dev);
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001146
1147 if (copy_to_user(useraddr, &edata, sizeof(edata)))
1148 return -EFAULT;
1149 return 0;
1150}
1151
Jeff Garzik13c99b22007-08-15 16:01:56 -07001152static int ethtool_set_value_void(struct net_device *dev, char __user *useraddr,
1153 void (*actor)(struct net_device *, u32))
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001154{
1155 struct ethtool_value edata;
1156
Jeff Garzik13c99b22007-08-15 16:01:56 -07001157 if (!actor)
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001158 return -EOPNOTSUPP;
1159
1160 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1161 return -EFAULT;
1162
Jeff Garzik13c99b22007-08-15 16:01:56 -07001163 actor(dev, edata.data);
Jeff Garzik339bf022007-08-15 16:01:32 -07001164 return 0;
1165}
1166
Jeff Garzik13c99b22007-08-15 16:01:56 -07001167static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
1168 int (*actor)(struct net_device *, u32))
Jeff Garzik339bf022007-08-15 16:01:32 -07001169{
1170 struct ethtool_value edata;
1171
Jeff Garzik13c99b22007-08-15 16:01:56 -07001172 if (!actor)
Jeff Garzik339bf022007-08-15 16:01:32 -07001173 return -EOPNOTSUPP;
1174
1175 if (copy_from_user(&edata, useraddr, sizeof(edata)))
1176 return -EFAULT;
1177
Jeff Garzik13c99b22007-08-15 16:01:56 -07001178 return actor(dev, edata.data);
Jeff Garzik339bf022007-08-15 16:01:32 -07001179}
1180
chavey97f8aef2010-04-07 21:54:42 -07001181static noinline_for_stack int ethtool_flash_device(struct net_device *dev,
1182 char __user *useraddr)
Ajit Khaparde05c6a8d2009-09-02 17:02:55 +00001183{
1184 struct ethtool_flash efl;
1185
1186 if (copy_from_user(&efl, useraddr, sizeof(efl)))
1187 return -EFAULT;
1188
1189 if (!dev->ethtool_ops->flash_device)
1190 return -EOPNOTSUPP;
1191
1192 return dev->ethtool_ops->flash_device(dev, &efl);
1193}
1194
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00001195static int ethtool_set_dump(struct net_device *dev,
1196 void __user *useraddr)
1197{
1198 struct ethtool_dump dump;
1199
1200 if (!dev->ethtool_ops->set_dump)
1201 return -EOPNOTSUPP;
1202
1203 if (copy_from_user(&dump, useraddr, sizeof(dump)))
1204 return -EFAULT;
1205
1206 return dev->ethtool_ops->set_dump(dev, &dump);
1207}
1208
1209static int ethtool_get_dump_flag(struct net_device *dev,
1210 void __user *useraddr)
1211{
1212 int ret;
1213 struct ethtool_dump dump;
1214 const struct ethtool_ops *ops = dev->ethtool_ops;
1215
1216 if (!dev->ethtool_ops->get_dump_flag)
1217 return -EOPNOTSUPP;
1218
1219 if (copy_from_user(&dump, useraddr, sizeof(dump)))
1220 return -EFAULT;
1221
1222 ret = ops->get_dump_flag(dev, &dump);
1223 if (ret)
1224 return ret;
1225
1226 if (copy_to_user(useraddr, &dump, sizeof(dump)))
1227 return -EFAULT;
1228 return 0;
1229}
1230
1231static int ethtool_get_dump_data(struct net_device *dev,
1232 void __user *useraddr)
1233{
1234 int ret;
1235 __u32 len;
1236 struct ethtool_dump dump, tmp;
1237 const struct ethtool_ops *ops = dev->ethtool_ops;
1238 void *data = NULL;
1239
1240 if (!dev->ethtool_ops->get_dump_data ||
1241 !dev->ethtool_ops->get_dump_flag)
1242 return -EOPNOTSUPP;
1243
1244 if (copy_from_user(&dump, useraddr, sizeof(dump)))
1245 return -EFAULT;
1246
1247 memset(&tmp, 0, sizeof(tmp));
1248 tmp.cmd = ETHTOOL_GET_DUMP_FLAG;
1249 ret = ops->get_dump_flag(dev, &tmp);
1250 if (ret)
1251 return ret;
1252
1253 len = (tmp.len > dump.len) ? dump.len : tmp.len;
1254 if (!len)
1255 return -EFAULT;
1256
1257 data = vzalloc(tmp.len);
1258 if (!data)
1259 return -ENOMEM;
1260 ret = ops->get_dump_data(dev, &dump, data);
1261 if (ret)
1262 goto out;
1263
1264 if (copy_to_user(useraddr, &dump, sizeof(dump))) {
1265 ret = -EFAULT;
1266 goto out;
1267 }
1268 useraddr += offsetof(struct ethtool_dump, data);
1269 if (copy_to_user(useraddr, data, len))
1270 ret = -EFAULT;
1271out:
1272 vfree(data);
1273 return ret;
1274}
1275
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276/* The main entry point in this file. Called from net/core/dev.c */
1277
Eric W. Biederman881d9662007-09-17 11:56:21 -07001278int dev_ethtool(struct net *net, struct ifreq *ifr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
Eric W. Biederman881d9662007-09-17 11:56:21 -07001280 struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 void __user *useraddr = ifr->ifr_data;
1282 u32 ethcmd;
1283 int rc;
Michał Mirosław04ed3e72011-01-24 15:32:47 -08001284 u32 old_features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if (!dev || !netif_device_present(dev))
1287 return -ENODEV;
1288
chavey97f8aef2010-04-07 21:54:42 -07001289 if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 return -EFAULT;
1291
Ben Hutchings01414802010-08-17 02:31:15 -07001292 if (!dev->ethtool_ops) {
1293 /* ETHTOOL_GDRVINFO does not require any driver support.
1294 * It is also unprivileged and does not change anything,
1295 * so we can take a shortcut to it. */
1296 if (ethcmd == ETHTOOL_GDRVINFO)
1297 return ethtool_get_drvinfo(dev, useraddr);
1298 else
1299 return -EOPNOTSUPP;
1300 }
1301
Stephen Hemminger75f31232006-09-28 15:13:37 -07001302 /* Allow some commands to be done by anyone */
chavey97f8aef2010-04-07 21:54:42 -07001303 switch (ethcmd) {
stephen hemminger0fdc1002010-08-23 10:24:18 +00001304 case ETHTOOL_GSET:
Stephen Hemminger75f31232006-09-28 15:13:37 -07001305 case ETHTOOL_GDRVINFO:
Stephen Hemminger75f31232006-09-28 15:13:37 -07001306 case ETHTOOL_GMSGLVL:
Stephen Hemminger75f31232006-09-28 15:13:37 -07001307 case ETHTOOL_GCOALESCE:
1308 case ETHTOOL_GRINGPARAM:
1309 case ETHTOOL_GPAUSEPARAM:
1310 case ETHTOOL_GRXCSUM:
1311 case ETHTOOL_GTXCSUM:
1312 case ETHTOOL_GSG:
1313 case ETHTOOL_GSTRINGS:
Stephen Hemminger75f31232006-09-28 15:13:37 -07001314 case ETHTOOL_GTSO:
1315 case ETHTOOL_GPERMADDR:
1316 case ETHTOOL_GUFO:
1317 case ETHTOOL_GGSO:
stephen hemminger1cab8192010-02-11 13:48:29 +00001318 case ETHTOOL_GGRO:
Jeff Garzik339bf022007-08-15 16:01:32 -07001319 case ETHTOOL_GFLAGS:
1320 case ETHTOOL_GPFLAGS:
Santwona Behera0853ad62008-07-02 03:47:41 -07001321 case ETHTOOL_GRXFH:
Santwona Behera59089d82009-02-20 00:58:13 -08001322 case ETHTOOL_GRXRINGS:
1323 case ETHTOOL_GRXCLSRLCNT:
1324 case ETHTOOL_GRXCLSRULE:
1325 case ETHTOOL_GRXCLSRLALL:
Michał Mirosław5455c692011-02-15 16:59:17 +00001326 case ETHTOOL_GFEATURES:
Stephen Hemminger75f31232006-09-28 15:13:37 -07001327 break;
1328 default:
1329 if (!capable(CAP_NET_ADMIN))
1330 return -EPERM;
1331 }
1332
chavey97f8aef2010-04-07 21:54:42 -07001333 if (dev->ethtool_ops->begin) {
1334 rc = dev->ethtool_ops->begin(dev);
1335 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 return rc;
chavey97f8aef2010-04-07 21:54:42 -07001337 }
Stephen Hemmingerd8a33ac2005-05-29 14:13:47 -07001338 old_features = dev->features;
1339
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 switch (ethcmd) {
1341 case ETHTOOL_GSET:
1342 rc = ethtool_get_settings(dev, useraddr);
1343 break;
1344 case ETHTOOL_SSET:
1345 rc = ethtool_set_settings(dev, useraddr);
1346 break;
1347 case ETHTOOL_GDRVINFO:
1348 rc = ethtool_get_drvinfo(dev, useraddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 break;
1350 case ETHTOOL_GREGS:
1351 rc = ethtool_get_regs(dev, useraddr);
1352 break;
1353 case ETHTOOL_GWOL:
1354 rc = ethtool_get_wol(dev, useraddr);
1355 break;
1356 case ETHTOOL_SWOL:
1357 rc = ethtool_set_wol(dev, useraddr);
1358 break;
1359 case ETHTOOL_GMSGLVL:
Jeff Garzik13c99b22007-08-15 16:01:56 -07001360 rc = ethtool_get_value(dev, useraddr, ethcmd,
1361 dev->ethtool_ops->get_msglevel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 break;
1363 case ETHTOOL_SMSGLVL:
Jeff Garzik13c99b22007-08-15 16:01:56 -07001364 rc = ethtool_set_value_void(dev, useraddr,
1365 dev->ethtool_ops->set_msglevel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 break;
1367 case ETHTOOL_NWAY_RST:
1368 rc = ethtool_nway_reset(dev);
1369 break;
1370 case ETHTOOL_GLINK:
Ben Hutchingse596e6e2010-12-09 12:08:35 +00001371 rc = ethtool_get_link(dev, useraddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 break;
1373 case ETHTOOL_GEEPROM:
1374 rc = ethtool_get_eeprom(dev, useraddr);
1375 break;
1376 case ETHTOOL_SEEPROM:
1377 rc = ethtool_set_eeprom(dev, useraddr);
1378 break;
1379 case ETHTOOL_GCOALESCE:
1380 rc = ethtool_get_coalesce(dev, useraddr);
1381 break;
1382 case ETHTOOL_SCOALESCE:
1383 rc = ethtool_set_coalesce(dev, useraddr);
1384 break;
1385 case ETHTOOL_GRINGPARAM:
1386 rc = ethtool_get_ringparam(dev, useraddr);
1387 break;
1388 case ETHTOOL_SRINGPARAM:
1389 rc = ethtool_set_ringparam(dev, useraddr);
1390 break;
1391 case ETHTOOL_GPAUSEPARAM:
1392 rc = ethtool_get_pauseparam(dev, useraddr);
1393 break;
1394 case ETHTOOL_SPAUSEPARAM:
1395 rc = ethtool_set_pauseparam(dev, useraddr);
1396 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 case ETHTOOL_TEST:
1398 rc = ethtool_self_test(dev, useraddr);
1399 break;
1400 case ETHTOOL_GSTRINGS:
1401 rc = ethtool_get_strings(dev, useraddr);
1402 break;
1403 case ETHTOOL_PHYS_ID:
1404 rc = ethtool_phys_id(dev, useraddr);
1405 break;
1406 case ETHTOOL_GSTATS:
1407 rc = ethtool_get_stats(dev, useraddr);
1408 break;
Jon Wetzela6f9a702005-08-20 17:15:54 -07001409 case ETHTOOL_GPERMADDR:
1410 rc = ethtool_get_perm_addr(dev, useraddr);
1411 break;
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001412 case ETHTOOL_GFLAGS:
Jeff Garzik13c99b22007-08-15 16:01:56 -07001413 rc = ethtool_get_value(dev, useraddr, ethcmd,
Michał Mirosławbc5787c62011-11-15 15:29:55 +00001414 __ethtool_get_flags);
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001415 break;
1416 case ETHTOOL_SFLAGS:
Michał Mirosławda8ac86c2011-02-15 16:59:18 +00001417 rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags);
Jeff Garzik3ae7c0b2007-08-15 16:00:51 -07001418 break;
Jeff Garzik339bf022007-08-15 16:01:32 -07001419 case ETHTOOL_GPFLAGS:
Jeff Garzik13c99b22007-08-15 16:01:56 -07001420 rc = ethtool_get_value(dev, useraddr, ethcmd,
1421 dev->ethtool_ops->get_priv_flags);
Jeff Garzik339bf022007-08-15 16:01:32 -07001422 break;
1423 case ETHTOOL_SPFLAGS:
Jeff Garzik13c99b22007-08-15 16:01:56 -07001424 rc = ethtool_set_value(dev, useraddr,
1425 dev->ethtool_ops->set_priv_flags);
Jeff Garzik339bf022007-08-15 16:01:32 -07001426 break;
Santwona Behera0853ad62008-07-02 03:47:41 -07001427 case ETHTOOL_GRXFH:
Santwona Behera59089d82009-02-20 00:58:13 -08001428 case ETHTOOL_GRXRINGS:
1429 case ETHTOOL_GRXCLSRLCNT:
1430 case ETHTOOL_GRXCLSRULE:
1431 case ETHTOOL_GRXCLSRLALL:
Ben Hutchingsbf988432010-06-28 08:45:58 +00001432 rc = ethtool_get_rxnfc(dev, ethcmd, useraddr);
Santwona Behera0853ad62008-07-02 03:47:41 -07001433 break;
1434 case ETHTOOL_SRXFH:
Santwona Behera59089d82009-02-20 00:58:13 -08001435 case ETHTOOL_SRXCLSRLDEL:
1436 case ETHTOOL_SRXCLSRLINS:
Ben Hutchingsbf988432010-06-28 08:45:58 +00001437 rc = ethtool_set_rxnfc(dev, ethcmd, useraddr);
Santwona Behera0853ad62008-07-02 03:47:41 -07001438 break;
Ajit Khaparde05c6a8d2009-09-02 17:02:55 +00001439 case ETHTOOL_FLASHDEV:
1440 rc = ethtool_flash_device(dev, useraddr);
1441 break;
Ben Hutchingsd73d3a82009-10-05 10:59:58 +00001442 case ETHTOOL_RESET:
1443 rc = ethtool_reset(dev, useraddr);
1444 break;
Peter P Waskiewicz Jr15682bc2010-02-10 20:03:05 -08001445 case ETHTOOL_SRXNTUPLE:
1446 rc = ethtool_set_rx_ntuple(dev, useraddr);
1447 break;
Jeff Garzik723b2f52010-03-03 22:51:50 +00001448 case ETHTOOL_GSSET_INFO:
1449 rc = ethtool_get_sset_info(dev, useraddr);
1450 break;
Ben Hutchingsa5b6ee22010-06-30 05:05:23 +00001451 case ETHTOOL_GRXFHINDIR:
1452 rc = ethtool_get_rxfh_indir(dev, useraddr);
1453 break;
1454 case ETHTOOL_SRXFHINDIR:
1455 rc = ethtool_set_rxfh_indir(dev, useraddr);
1456 break;
Michał Mirosław5455c692011-02-15 16:59:17 +00001457 case ETHTOOL_GFEATURES:
1458 rc = ethtool_get_features(dev, useraddr);
1459 break;
1460 case ETHTOOL_SFEATURES:
1461 rc = ethtool_set_features(dev, useraddr);
1462 break;
Michał Mirosław0a417702011-02-15 16:59:17 +00001463 case ETHTOOL_GTXCSUM:
Michał Mirosławe83d3602011-02-15 16:59:18 +00001464 case ETHTOOL_GRXCSUM:
Michał Mirosław0a417702011-02-15 16:59:17 +00001465 case ETHTOOL_GSG:
1466 case ETHTOOL_GTSO:
1467 case ETHTOOL_GUFO:
1468 case ETHTOOL_GGSO:
1469 case ETHTOOL_GGRO:
1470 rc = ethtool_get_one_feature(dev, useraddr, ethcmd);
1471 break;
1472 case ETHTOOL_STXCSUM:
Michał Mirosławe83d3602011-02-15 16:59:18 +00001473 case ETHTOOL_SRXCSUM:
Michał Mirosław0a417702011-02-15 16:59:17 +00001474 case ETHTOOL_SSG:
1475 case ETHTOOL_STSO:
1476 case ETHTOOL_SUFO:
1477 case ETHTOOL_SGSO:
1478 case ETHTOOL_SGRO:
1479 rc = ethtool_set_one_feature(dev, useraddr, ethcmd);
1480 break;
amit salecha8b5933c2011-04-07 01:58:42 +00001481 case ETHTOOL_GCHANNELS:
1482 rc = ethtool_get_channels(dev, useraddr);
1483 break;
1484 case ETHTOOL_SCHANNELS:
1485 rc = ethtool_set_channels(dev, useraddr);
1486 break;
Anirban Chakraborty29dd54b2011-05-12 12:48:32 +00001487 case ETHTOOL_SET_DUMP:
1488 rc = ethtool_set_dump(dev, useraddr);
1489 break;
1490 case ETHTOOL_GET_DUMP_FLAG:
1491 rc = ethtool_get_dump_flag(dev, useraddr);
1492 break;
1493 case ETHTOOL_GET_DUMP_DATA:
1494 rc = ethtool_get_dump_data(dev, useraddr);
1495 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 default:
Matthew Wilcox61a44b92007-07-31 14:00:02 -07001497 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001499
Stephen Hemmingere71a4782007-04-10 20:10:33 -07001500 if (dev->ethtool_ops->complete)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 dev->ethtool_ops->complete(dev);
Stephen Hemmingerd8a33ac2005-05-29 14:13:47 -07001502
1503 if (old_features != dev->features)
1504 netdev_features_change(dev);
1505
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507}