diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/ethtool.c | 40 |
1 files changed, 24 insertions, 16 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index a1280f643bf4..fbbe4b49116b 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -283,18 +283,17 @@ err_out: | |||
283 | return ret; | 283 | return ret; |
284 | } | 284 | } |
285 | 285 | ||
286 | static int __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, | 286 | static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, |
287 | struct ethtool_rx_ntuple_flow_spec *spec) | 287 | struct ethtool_rx_ntuple_flow_spec *spec, |
288 | struct ethtool_rx_ntuple_flow_spec_container *fsc) | ||
288 | { | 289 | { |
289 | struct ethtool_rx_ntuple_flow_spec_container *fsc; | ||
290 | 290 | ||
291 | /* don't add filters forever */ | 291 | /* don't add filters forever */ |
292 | if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) | 292 | if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) { |
293 | return 0; | 293 | /* free the container */ |
294 | 294 | kfree(fsc); | |
295 | fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC); | 295 | return; |
296 | if (!fsc) | 296 | } |
297 | return -ENOMEM; | ||
298 | 297 | ||
299 | /* Copy the whole filter over */ | 298 | /* Copy the whole filter over */ |
300 | fsc->fs.flow_type = spec->flow_type; | 299 | fsc->fs.flow_type = spec->flow_type; |
@@ -310,14 +309,13 @@ static int __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, | |||
310 | /* add to the list */ | 309 | /* add to the list */ |
311 | list_add_tail_rcu(&fsc->list, &list->list); | 310 | list_add_tail_rcu(&fsc->list, &list->list); |
312 | list->count++; | 311 | list->count++; |
313 | |||
314 | return 0; | ||
315 | } | 312 | } |
316 | 313 | ||
317 | static int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr) | 314 | static int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr) |
318 | { | 315 | { |
319 | struct ethtool_rx_ntuple cmd; | 316 | struct ethtool_rx_ntuple cmd; |
320 | const struct ethtool_ops *ops = dev->ethtool_ops; | 317 | const struct ethtool_ops *ops = dev->ethtool_ops; |
318 | struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL; | ||
321 | int ret; | 319 | int ret; |
322 | 320 | ||
323 | if (!ops->set_rx_ntuple) | 321 | if (!ops->set_rx_ntuple) |
@@ -329,16 +327,26 @@ static int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr) | |||
329 | if (copy_from_user(&cmd, useraddr, sizeof(cmd))) | 327 | if (copy_from_user(&cmd, useraddr, sizeof(cmd))) |
330 | return -EFAULT; | 328 | return -EFAULT; |
331 | 329 | ||
332 | ret = ops->set_rx_ntuple(dev, &cmd); | ||
333 | |||
334 | /* | 330 | /* |
335 | * Cache filter in dev struct for GET operation only if | 331 | * Cache filter in dev struct for GET operation only if |
336 | * the underlying driver doesn't have its own GET operation, and | 332 | * the underlying driver doesn't have its own GET operation, and |
337 | * only if the filter was added successfully. | 333 | * only if the filter was added successfully. First make sure we |
334 | * can allocate the filter, then continue if successful. | ||
338 | */ | 335 | */ |
339 | if (!ops->get_rx_ntuple && !ret) | 336 | if (!ops->get_rx_ntuple) { |
340 | if (__rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs)) | 337 | fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC); |
338 | if (!fsc) | ||
341 | return -ENOMEM; | 339 | return -ENOMEM; |
340 | } | ||
341 | |||
342 | ret = ops->set_rx_ntuple(dev, &cmd); | ||
343 | if (ret) { | ||
344 | kfree(fsc); | ||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | if (!ops->get_rx_ntuple) | ||
349 | __rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs, fsc); | ||
342 | 350 | ||
343 | return ret; | 351 | return ret; |
344 | } | 352 | } |