diff options
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r-- | net/core/ethtool.c | 103 |
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 | /* | 203 | static 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 | */ | ||
205 | static 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 | /* | 242 | static 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 | { |
243 | static 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 | |||
297 | out: | ||
298 | kfree(info_buf); | ||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | static 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 | /* | 315 | static 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 | */ | ||
259 | static 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 | /* | 387 | static 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 | */ | ||
334 | static 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 | /* | 855 | static 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 | */ | ||
805 | static 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 | /* | 869 | static 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 | */ | ||
822 | static 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 | /* | 1279 | static 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 | */ | ||
1235 | static 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 | } |