diff options
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r-- | net/core/ethtool.c | 108 |
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 | } |
145 | EXPORT_SYMBOL(ethtool_op_get_flags); | 145 | EXPORT_SYMBOL(ethtool_op_get_flags); |
146 | 146 | ||
147 | int ethtool_op_set_flags(struct net_device *dev, u32 data) | 147 | int 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 | } |
174 | EXPORT_SYMBOL(ethtool_op_set_flags); | 156 | EXPORT_SYMBOL(ethtool_op_set_flags); |
@@ -395,6 +377,80 @@ err_out: | |||
395 | return ret; | 377 | return ret; |
396 | } | 378 | } |
397 | 379 | ||
380 | static 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 | |||
413 | out: | ||
414 | kfree(indir); | ||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | static 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 | |||
449 | out: | ||
450 | kfree(indir); | ||
451 | return ret; | ||
452 | } | ||
453 | |||
398 | static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, | 454 | static 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 | } |