diff options
| author | John W. Linville <linville@tuxdriver.com> | 2013-04-01 15:09:28 -0400 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2013-04-01 15:09:28 -0400 |
| commit | 95bc6b8461d809d7573ad8cadae3f307a472c017 (patch) | |
| tree | a3c53eda59b3f9303bce86ba92186495774fba78 | |
| parent | 2e1253d640eb7f8707d2591c93097c1e9f9c71d5 (diff) | |
| parent | 382a103b2b528a3085cde4ac56fc69d92a828b72 (diff) | |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211
| -rw-r--r-- | net/mac80211/cfg.c | 6 | ||||
| -rw-r--r-- | net/mac80211/chan.c | 17 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 4 | ||||
| -rw-r--r-- | net/mac80211/iface.c | 2 | ||||
| -rw-r--r-- | net/mac80211/offchannel.c | 23 |
5 files changed, 39 insertions, 13 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/chan.c b/net/mac80211/chan.c index 78c0d90dd641..931be419ab5a 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
| @@ -63,6 +63,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
| 63 | enum ieee80211_chanctx_mode mode) | 63 | enum ieee80211_chanctx_mode mode) |
| 64 | { | 64 | { |
| 65 | struct ieee80211_chanctx *ctx; | 65 | struct ieee80211_chanctx *ctx; |
| 66 | u32 changed; | ||
| 66 | int err; | 67 | int err; |
| 67 | 68 | ||
| 68 | lockdep_assert_held(&local->chanctx_mtx); | 69 | lockdep_assert_held(&local->chanctx_mtx); |
| @@ -76,6 +77,13 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
| 76 | ctx->conf.rx_chains_dynamic = 1; | 77 | ctx->conf.rx_chains_dynamic = 1; |
| 77 | ctx->mode = mode; | 78 | ctx->mode = mode; |
| 78 | 79 | ||
| 80 | /* acquire mutex to prevent idle from changing */ | ||
| 81 | mutex_lock(&local->mtx); | ||
| 82 | /* turn idle off *before* setting channel -- some drivers need that */ | ||
| 83 | changed = ieee80211_idle_off(local); | ||
| 84 | if (changed) | ||
| 85 | ieee80211_hw_config(local, changed); | ||
| 86 | |||
| 79 | if (!local->use_chanctx) { | 87 | if (!local->use_chanctx) { |
| 80 | local->_oper_channel_type = | 88 | local->_oper_channel_type = |
| 81 | cfg80211_get_chandef_type(chandef); | 89 | cfg80211_get_chandef_type(chandef); |
| @@ -85,14 +93,17 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
| 85 | err = drv_add_chanctx(local, ctx); | 93 | err = drv_add_chanctx(local, ctx); |
| 86 | if (err) { | 94 | if (err) { |
| 87 | kfree(ctx); | 95 | kfree(ctx); |
| 88 | return ERR_PTR(err); | 96 | ctx = ERR_PTR(err); |
| 97 | |||
| 98 | ieee80211_recalc_idle(local); | ||
| 99 | goto out; | ||
| 89 | } | 100 | } |
| 90 | } | 101 | } |
| 91 | 102 | ||
| 103 | /* and keep the mutex held until the new chanctx is on the list */ | ||
| 92 | list_add_rcu(&ctx->list, &local->chanctx_list); | 104 | list_add_rcu(&ctx->list, &local->chanctx_list); |
| 93 | 105 | ||
| 94 | mutex_lock(&local->mtx); | 106 | out: |
| 95 | ieee80211_recalc_idle(local); | ||
| 96 | mutex_unlock(&local->mtx); | 107 | mutex_unlock(&local->mtx); |
| 97 | 108 | ||
| 98 | return ctx; | 109 | return ctx; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 388580a1bada..5672533a0832 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 | ||
| @@ -1361,6 +1362,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
| 1361 | enum nl80211_iftype type); | 1362 | enum nl80211_iftype type); |
| 1362 | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); | 1363 | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); |
| 1363 | void ieee80211_remove_interfaces(struct ieee80211_local *local); | 1364 | void ieee80211_remove_interfaces(struct ieee80211_local *local); |
| 1365 | u32 ieee80211_idle_off(struct ieee80211_local *local); | ||
| 1364 | void ieee80211_recalc_idle(struct ieee80211_local *local); | 1366 | void ieee80211_recalc_idle(struct ieee80211_local *local); |
| 1365 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | 1367 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, |
| 1366 | const int offset); | 1368 | const int offset); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3bfe2612c8c2..58150f877ec3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -78,7 +78,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) | |||
| 78 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); | 78 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static u32 ieee80211_idle_off(struct ieee80211_local *local) | 81 | u32 ieee80211_idle_off(struct ieee80211_local *local) |
| 82 | { | 82 | { |
| 83 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) | 83 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) |
| 84 | return 0; | 84 | return 0; |
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 | ||
