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.c103
1 files changed, 75 insertions, 28 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 0f2f82185ec4..f4cb6b6299d9 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -17,6 +17,7 @@
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/bitops.h>
20#include <asm/uaccess.h> 21#include <asm/uaccess.h>
21 22
22/* 23/*
@@ -199,10 +200,7 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
199 return dev->ethtool_ops->set_settings(dev, &cmd); 200 return dev->ethtool_ops->set_settings(dev, &cmd);
200} 201}
201 202
202/* 203static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
203 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
204 */
205static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
206{ 204{
207 struct ethtool_drvinfo info; 205 struct ethtool_drvinfo info;
208 const struct ethtool_ops *ops = dev->ethtool_ops; 206 const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -214,6 +212,10 @@ static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *use
214 info.cmd = ETHTOOL_GDRVINFO; 212 info.cmd = ETHTOOL_GDRVINFO;
215 ops->get_drvinfo(dev, &info); 213 ops->get_drvinfo(dev, &info);
216 214
215 /*
216 * this method of obtaining string set info is deprecated;
217 * Use ETHTOOL_GSSET_INFO instead.
218 */
217 if (ops->get_sset_count) { 219 if (ops->get_sset_count) {
218 int rc; 220 int rc;
219 221
@@ -237,10 +239,67 @@ static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *use
237 return 0; 239 return 0;
238} 240}
239 241
240/* 242static noinline_for_stack int ethtool_get_sset_info(struct net_device *dev,
241 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() 243 void __user *useraddr)
242 */ 244{
243static noinline int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr) 245 struct ethtool_sset_info info;
246 const struct ethtool_ops *ops = dev->ethtool_ops;
247 u64 sset_mask;
248 int i, idx = 0, n_bits = 0, ret, rc;
249 u32 *info_buf = NULL;
250
251 if (!ops->get_sset_count)
252 return -EOPNOTSUPP;
253
254 if (copy_from_user(&info, useraddr, sizeof(info)))
255 return -EFAULT;
256
257 /* store copy of mask, because we zero struct later on */
258 sset_mask = info.sset_mask;
259 if (!sset_mask)
260 return 0;
261
262 /* calculate size of return buffer */
263 n_bits = hweight64(sset_mask);
264
265 memset(&info, 0, sizeof(info));
266 info.cmd = ETHTOOL_GSSET_INFO;
267
268 info_buf = kzalloc(n_bits * sizeof(u32), GFP_USER);
269 if (!info_buf)
270 return -ENOMEM;
271
272 /*
273 * fill return buffer based on input bitmask and successful
274 * get_sset_count return
275 */
276 for (i = 0; i < 64; i++) {
277 if (!(sset_mask & (1ULL << i)))
278 continue;
279
280 rc = ops->get_sset_count(dev, i);
281 if (rc >= 0) {
282 info.sset_mask |= (1ULL << i);
283 info_buf[idx++] = rc;
284 }
285 }
286
287 ret = -EFAULT;
288 if (copy_to_user(useraddr, &info, sizeof(info)))
289 goto out;
290
291 useraddr += offsetof(struct ethtool_sset_info, data);
292 if (copy_to_user(useraddr, info_buf, idx * sizeof(u32)))
293 goto out;
294
295 ret = 0;
296
297out:
298 kfree(info_buf);
299 return ret;
300}
301
302static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)
244{ 303{
245 struct ethtool_rxnfc cmd; 304 struct ethtool_rxnfc cmd;
246 305
@@ -253,10 +312,7 @@ static noinline int ethtool_set_rxnfc(struct net_device *dev, void __user *usera
253 return dev->ethtool_ops->set_rxnfc(dev, &cmd); 312 return dev->ethtool_ops->set_rxnfc(dev, &cmd);
254} 313}
255 314
256/* 315static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)
257 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
258 */
259static noinline int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)
260{ 316{
261 struct ethtool_rxnfc info; 317 struct ethtool_rxnfc info;
262 const struct ethtool_ops *ops = dev->ethtool_ops; 318 const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -328,10 +384,7 @@ static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
328 list->count++; 384 list->count++;
329} 385}
330 386
331/* 387static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr)
332 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
333 */
334static noinline int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr)
335{ 388{
336 struct ethtool_rx_ntuple cmd; 389 struct ethtool_rx_ntuple cmd;
337 const struct ethtool_ops *ops = dev->ethtool_ops; 390 const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -799,10 +852,7 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
799 return ret; 852 return ret;
800} 853}
801 854
802/* 855static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr)
803 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
804 */
805static noinline int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr)
806{ 856{
807 struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE }; 857 struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
808 858
@@ -816,10 +866,7 @@ static noinline int ethtool_get_coalesce(struct net_device *dev, void __user *us
816 return 0; 866 return 0;
817} 867}
818 868
819/* 869static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)
820 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
821 */
822static noinline int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)
823{ 870{
824 struct ethtool_coalesce coalesce; 871 struct ethtool_coalesce coalesce;
825 872
@@ -1229,10 +1276,7 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
1229 return actor(dev, edata.data); 1276 return actor(dev, edata.data);
1230} 1277}
1231 1278
1232/* 1279static noinline_for_stack int ethtool_flash_device(struct net_device *dev, char __user *useraddr)
1233 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
1234 */
1235static noinline int ethtool_flash_device(struct net_device *dev, char __user *useraddr)
1236{ 1280{
1237 struct ethtool_flash efl; 1281 struct ethtool_flash efl;
1238 1282
@@ -1471,6 +1515,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1471 case ETHTOOL_GRXNTUPLE: 1515 case ETHTOOL_GRXNTUPLE:
1472 rc = ethtool_get_rx_ntuple(dev, useraddr); 1516 rc = ethtool_get_rx_ntuple(dev, useraddr);
1473 break; 1517 break;
1518 case ETHTOOL_GSSET_INFO:
1519 rc = ethtool_get_sset_info(dev, useraddr);
1520 break;
1474 default: 1521 default:
1475 rc = -EOPNOTSUPP; 1522 rc = -EOPNOTSUPP;
1476 } 1523 }