aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/cfg.c6
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/offchannel.c23
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);
1347void ieee80211_roc_setup(struct ieee80211_local *local); 1348void ieee80211_roc_setup(struct ieee80211_local *local);
1348void ieee80211_start_next_roc(struct ieee80211_local *local); 1349void ieee80211_start_next_roc(struct ieee80211_local *local);
1349void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata); 1350void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata);
1350void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc); 1351void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free);
1351void ieee80211_sw_roc_work(struct work_struct *work); 1352void ieee80211_sw_roc_work(struct work_struct *work);
1352void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); 1353void 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
300void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) 300void 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
324void ieee80211_sw_roc_work(struct work_struct *work) 330void 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