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.c80
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
361static 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
394out:
395 kfree(indir);
396 return ret;
397}
398
399static 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
430out:
431 kfree(indir);
432 return ret;
433}
434
361static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, 435static 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 }