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.c108
1 files changed, 85 insertions, 23 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 75e4ffeb8cc..7a85367b3c2 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -144,31 +144,13 @@ u32 ethtool_op_get_flags(struct net_device *dev)
144} 144}
145EXPORT_SYMBOL(ethtool_op_get_flags); 145EXPORT_SYMBOL(ethtool_op_get_flags);
146 146
147int ethtool_op_set_flags(struct net_device *dev, u32 data) 147int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
148{ 148{
149 const struct ethtool_ops *ops = dev->ethtool_ops; 149 if (data & ~supported)
150 unsigned long features = dev->features; 150 return -EINVAL;
151
152 if (data & ETH_FLAG_LRO)
153 features |= NETIF_F_LRO;
154 else
155 features &= ~NETIF_F_LRO;
156
157 if (data & ETH_FLAG_NTUPLE) {
158 if (!ops->set_rx_ntuple)
159 return -EOPNOTSUPP;
160 features |= NETIF_F_NTUPLE;
161 } else {
162 /* safe to clear regardless */
163 features &= ~NETIF_F_NTUPLE;
164 }
165
166 if (data & ETH_FLAG_RXHASH)
167 features |= NETIF_F_RXHASH;
168 else
169 features &= ~NETIF_F_RXHASH;
170 151
171 dev->features = features; 152 dev->features = ((dev->features & ~flags_dup_features) |
153 (data & flags_dup_features));
172 return 0; 154 return 0;
173} 155}
174EXPORT_SYMBOL(ethtool_op_set_flags); 156EXPORT_SYMBOL(ethtool_op_set_flags);
@@ -395,6 +377,80 @@ err_out:
395 return ret; 377 return ret;
396} 378}
397 379
380static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
381 void __user *useraddr)
382{
383 struct ethtool_rxfh_indir *indir;
384 u32 table_size;
385 size_t full_size;
386 int ret;
387
388 if (!dev->ethtool_ops->get_rxfh_indir)
389 return -EOPNOTSUPP;
390
391 if (copy_from_user(&table_size,
392 useraddr + offsetof(struct ethtool_rxfh_indir, size),
393 sizeof(table_size)))
394 return -EFAULT;
395
396 if (table_size >
397 (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
398 return -ENOMEM;
399 full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
400 indir = kmalloc(full_size, GFP_USER);
401 if (!indir)
402 return -ENOMEM;
403
404 indir->cmd = ETHTOOL_GRXFHINDIR;
405 indir->size = table_size;
406 ret = dev->ethtool_ops->get_rxfh_indir(dev, indir);
407 if (ret)
408 goto out;
409
410 if (copy_to_user(useraddr, indir, full_size))
411 ret = -EFAULT;
412
413out:
414 kfree(indir);
415 return ret;
416}
417
418static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
419 void __user *useraddr)
420{
421 struct ethtool_rxfh_indir *indir;
422 u32 table_size;
423 size_t full_size;
424 int ret;
425
426 if (!dev->ethtool_ops->set_rxfh_indir)
427 return -EOPNOTSUPP;
428
429 if (copy_from_user(&table_size,
430 useraddr + offsetof(struct ethtool_rxfh_indir, size),
431 sizeof(table_size)))
432 return -EFAULT;
433
434 if (table_size >
435 (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
436 return -ENOMEM;
437 full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
438 indir = kmalloc(full_size, GFP_USER);
439 if (!indir)
440 return -ENOMEM;
441
442 if (copy_from_user(indir, useraddr, full_size)) {
443 ret = -EFAULT;
444 goto out;
445 }
446
447 ret = dev->ethtool_ops->set_rxfh_indir(dev, indir);
448
449out:
450 kfree(indir);
451 return ret;
452}
453
398static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, 454static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
399 struct ethtool_rx_ntuple_flow_spec *spec, 455 struct ethtool_rx_ntuple_flow_spec *spec,
400 struct ethtool_rx_ntuple_flow_spec_container *fsc) 456 struct ethtool_rx_ntuple_flow_spec_container *fsc)
@@ -1563,6 +1619,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1563 case ETHTOOL_GSSET_INFO: 1619 case ETHTOOL_GSSET_INFO:
1564 rc = ethtool_get_sset_info(dev, useraddr); 1620 rc = ethtool_get_sset_info(dev, useraddr);
1565 break; 1621 break;
1622 case ETHTOOL_GRXFHINDIR:
1623 rc = ethtool_get_rxfh_indir(dev, useraddr);
1624 break;
1625 case ETHTOOL_SRXFHINDIR:
1626 rc = ethtool_set_rxfh_indir(dev, useraddr);
1627 break;
1566 default: 1628 default:
1567 rc = -EOPNOTSUPP; 1629 rc = -EOPNOTSUPP;
1568 } 1630 }