diff options
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r-- | net/core/ethtool.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 5d42fae520d9..072d1d3796cb 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -358,6 +358,80 @@ err_out: | |||
358 | return ret; | 358 | return ret; |
359 | } | 359 | } |
360 | 360 | ||
361 | static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, | ||
362 | void __user *useraddr) | ||
363 | { | ||
364 | struct ethtool_rxfh_indir *indir; | ||
365 | u32 table_size; | ||
366 | size_t full_size; | ||
367 | int ret; | ||
368 | |||
369 | if (!dev->ethtool_ops->get_rxfh_indir) | ||
370 | return -EOPNOTSUPP; | ||
371 | |||
372 | if (copy_from_user(&table_size, | ||
373 | useraddr + offsetof(struct ethtool_rxfh_indir, size), | ||
374 | sizeof(table_size))) | ||
375 | return -EFAULT; | ||
376 | |||
377 | if (table_size > | ||
378 | (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index)) | ||
379 | return -ENOMEM; | ||
380 | full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size; | ||
381 | indir = kmalloc(full_size, GFP_USER); | ||
382 | if (!indir) | ||
383 | return -ENOMEM; | ||
384 | |||
385 | indir->cmd = ETHTOOL_GRXFHINDIR; | ||
386 | indir->size = table_size; | ||
387 | ret = dev->ethtool_ops->get_rxfh_indir(dev, indir); | ||
388 | if (ret) | ||
389 | goto out; | ||
390 | |||
391 | if (copy_to_user(useraddr, indir, full_size)) | ||
392 | ret = -EFAULT; | ||
393 | |||
394 | out: | ||
395 | kfree(indir); | ||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, | ||
400 | void __user *useraddr) | ||
401 | { | ||
402 | struct ethtool_rxfh_indir *indir; | ||
403 | u32 table_size; | ||
404 | size_t full_size; | ||
405 | int ret; | ||
406 | |||
407 | if (!dev->ethtool_ops->set_rxfh_indir) | ||
408 | return -EOPNOTSUPP; | ||
409 | |||
410 | if (copy_from_user(&table_size, | ||
411 | useraddr + offsetof(struct ethtool_rxfh_indir, size), | ||
412 | sizeof(table_size))) | ||
413 | return -EFAULT; | ||
414 | |||
415 | if (table_size > | ||
416 | (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index)) | ||
417 | return -ENOMEM; | ||
418 | full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size; | ||
419 | indir = kmalloc(full_size, GFP_USER); | ||
420 | if (!indir) | ||
421 | return -ENOMEM; | ||
422 | |||
423 | if (copy_from_user(indir, useraddr, full_size)) { | ||
424 | ret = -EFAULT; | ||
425 | goto out; | ||
426 | } | ||
427 | |||
428 | ret = dev->ethtool_ops->set_rxfh_indir(dev, indir); | ||
429 | |||
430 | out: | ||
431 | kfree(indir); | ||
432 | return ret; | ||
433 | } | ||
434 | |||
361 | static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, | 435 | static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, |
362 | struct ethtool_rx_ntuple_flow_spec *spec, | 436 | struct ethtool_rx_ntuple_flow_spec *spec, |
363 | struct ethtool_rx_ntuple_flow_spec_container *fsc) | 437 | struct ethtool_rx_ntuple_flow_spec_container *fsc) |
@@ -1526,6 +1600,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1526 | case ETHTOOL_GSSET_INFO: | 1600 | case ETHTOOL_GSSET_INFO: |
1527 | rc = ethtool_get_sset_info(dev, useraddr); | 1601 | rc = ethtool_get_sset_info(dev, useraddr); |
1528 | break; | 1602 | break; |
1603 | case ETHTOOL_GRXFHINDIR: | ||
1604 | rc = ethtool_get_rxfh_indir(dev, useraddr); | ||
1605 | break; | ||
1606 | case ETHTOOL_SRXFHINDIR: | ||
1607 | rc = ethtool_set_rxfh_indir(dev, useraddr); | ||
1608 | break; | ||
1529 | default: | 1609 | default: |
1530 | rc = -EOPNOTSUPP; | 1610 | rc = -EOPNOTSUPP; |
1531 | } | 1611 | } |