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 | ||
