diff options
-rw-r--r-- | net/mac80211/cfg.c | 6 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/offchannel.c | 23 |
3 files changed, 23 insertions, 9 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fb306814576a..a6893602f87a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2582,7 +2582,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, | |||
2582 | list_del(&dep->list); | 2582 | list_del(&dep->list); |
2583 | mutex_unlock(&local->mtx); | 2583 | mutex_unlock(&local->mtx); |
2584 | 2584 | ||
2585 | ieee80211_roc_notify_destroy(dep); | 2585 | ieee80211_roc_notify_destroy(dep, true); |
2586 | return 0; | 2586 | return 0; |
2587 | } | 2587 | } |
2588 | 2588 | ||
@@ -2622,7 +2622,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, | |||
2622 | ieee80211_start_next_roc(local); | 2622 | ieee80211_start_next_roc(local); |
2623 | mutex_unlock(&local->mtx); | 2623 | mutex_unlock(&local->mtx); |
2624 | 2624 | ||
2625 | ieee80211_roc_notify_destroy(found); | 2625 | ieee80211_roc_notify_destroy(found, true); |
2626 | } else { | 2626 | } else { |
2627 | /* work may be pending so use it all the time */ | 2627 | /* work may be pending so use it all the time */ |
2628 | found->abort = true; | 2628 | found->abort = true; |
@@ -2632,6 +2632,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, | |||
2632 | 2632 | ||
2633 | /* work will clean up etc */ | 2633 | /* work will clean up etc */ |
2634 | flush_delayed_work(&found->work); | 2634 | flush_delayed_work(&found->work); |
2635 | WARN_ON(!found->to_be_freed); | ||
2636 | kfree(found); | ||
2635 | } | 2637 | } |
2636 | 2638 | ||
2637 | return 0; | 2639 | return 0; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 388580a1bada..7bdefd901f9d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -309,6 +309,7 @@ struct ieee80211_roc_work { | |||
309 | struct ieee80211_channel *chan; | 309 | struct ieee80211_channel *chan; |
310 | 310 | ||
311 | bool started, abort, hw_begun, notified; | 311 | bool started, abort, hw_begun, notified; |
312 | bool to_be_freed; | ||
312 | 313 | ||
313 | unsigned long hw_start_time; | 314 | unsigned long hw_start_time; |
314 | 315 | ||
@@ -1347,7 +1348,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local); | |||
1347 | void ieee80211_roc_setup(struct ieee80211_local *local); | 1348 | void ieee80211_roc_setup(struct ieee80211_local *local); |
1348 | void ieee80211_start_next_roc(struct ieee80211_local *local); | 1349 | void ieee80211_start_next_roc(struct ieee80211_local *local); |
1349 | void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata); | 1350 | void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata); |
1350 | void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc); | 1351 | void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free); |
1351 | void ieee80211_sw_roc_work(struct work_struct *work); | 1352 | void ieee80211_sw_roc_work(struct work_struct *work); |
1352 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); | 1353 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); |
1353 | 1354 | ||
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index cc79b4a2e821..430bd254e496 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -297,10 +297,13 @@ void ieee80211_start_next_roc(struct ieee80211_local *local) | |||
297 | } | 297 | } |
298 | } | 298 | } |
299 | 299 | ||
300 | void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) | 300 | void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free) |
301 | { | 301 | { |
302 | struct ieee80211_roc_work *dep, *tmp; | 302 | struct ieee80211_roc_work *dep, *tmp; |
303 | 303 | ||
304 | if (WARN_ON(roc->to_be_freed)) | ||
305 | return; | ||
306 | |||
304 | /* was never transmitted */ | 307 | /* was never transmitted */ |
305 | if (roc->frame) { | 308 | if (roc->frame) { |
306 | cfg80211_mgmt_tx_status(&roc->sdata->wdev, | 309 | cfg80211_mgmt_tx_status(&roc->sdata->wdev, |
@@ -316,9 +319,12 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) | |||
316 | GFP_KERNEL); | 319 | GFP_KERNEL); |
317 | 320 | ||
318 | list_for_each_entry_safe(dep, tmp, &roc->dependents, list) | 321 | list_for_each_entry_safe(dep, tmp, &roc->dependents, list) |
319 | ieee80211_roc_notify_destroy(dep); | 322 | ieee80211_roc_notify_destroy(dep, true); |
320 | 323 | ||
321 | kfree(roc); | 324 | if (free) |
325 | kfree(roc); | ||
326 | else | ||
327 | roc->to_be_freed = true; | ||
322 | } | 328 | } |
323 | 329 | ||
324 | void ieee80211_sw_roc_work(struct work_struct *work) | 330 | void ieee80211_sw_roc_work(struct work_struct *work) |
@@ -331,6 +337,9 @@ void ieee80211_sw_roc_work(struct work_struct *work) | |||
331 | 337 | ||
332 | mutex_lock(&local->mtx); | 338 | mutex_lock(&local->mtx); |
333 | 339 | ||
340 | if (roc->to_be_freed) | ||
341 | goto out_unlock; | ||
342 | |||
334 | if (roc->abort) | 343 | if (roc->abort) |
335 | goto finish; | 344 | goto finish; |
336 | 345 | ||
@@ -370,7 +379,7 @@ void ieee80211_sw_roc_work(struct work_struct *work) | |||
370 | finish: | 379 | finish: |
371 | list_del(&roc->list); | 380 | list_del(&roc->list); |
372 | started = roc->started; | 381 | started = roc->started; |
373 | ieee80211_roc_notify_destroy(roc); | 382 | ieee80211_roc_notify_destroy(roc, !roc->abort); |
374 | 383 | ||
375 | if (started) { | 384 | if (started) { |
376 | drv_flush(local, false); | 385 | drv_flush(local, false); |
@@ -410,7 +419,7 @@ static void ieee80211_hw_roc_done(struct work_struct *work) | |||
410 | 419 | ||
411 | list_del(&roc->list); | 420 | list_del(&roc->list); |
412 | 421 | ||
413 | ieee80211_roc_notify_destroy(roc); | 422 | ieee80211_roc_notify_destroy(roc, true); |
414 | 423 | ||
415 | /* if there's another roc, start it now */ | 424 | /* if there's another roc, start it now */ |
416 | ieee80211_start_next_roc(local); | 425 | ieee80211_start_next_roc(local); |
@@ -460,12 +469,14 @@ void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata) | |||
460 | list_for_each_entry_safe(roc, tmp, &tmp_list, list) { | 469 | list_for_each_entry_safe(roc, tmp, &tmp_list, list) { |
461 | if (local->ops->remain_on_channel) { | 470 | if (local->ops->remain_on_channel) { |
462 | list_del(&roc->list); | 471 | list_del(&roc->list); |
463 | ieee80211_roc_notify_destroy(roc); | 472 | ieee80211_roc_notify_destroy(roc, true); |
464 | } else { | 473 | } else { |
465 | ieee80211_queue_delayed_work(&local->hw, &roc->work, 0); | 474 | ieee80211_queue_delayed_work(&local->hw, &roc->work, 0); |
466 | 475 | ||
467 | /* work will clean up etc */ | 476 | /* work will clean up etc */ |
468 | flush_delayed_work(&roc->work); | 477 | flush_delayed_work(&roc->work); |
478 | WARN_ON(!roc->to_be_freed); | ||
479 | kfree(roc); | ||
469 | } | 480 | } |
470 | } | 481 | } |
471 | 482 | ||