aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-04-22 09:31:43 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-04-22 09:31:43 -0400
commita42c74ee608a424342ef7069ccddf196d873040c (patch)
tree75adfb9f5e06ebb7c7d5d5e5a5408fa0d6d504b9 /net/mac80211
parent97990a060e6757f48b931a3946b17c1c4362c3fb (diff)
parent9b383672452bb1097124c76fcb4903e0021f6baf (diff)
Merge remote-tracking branch 'wireless-next/master' into mac80211-next
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/cfg.c6
-rw-r--r--net/mac80211/chan.c17
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/iface.c37
-rw-r--r--net/mac80211/mesh.c3
-rw-r--r--net/mac80211/mlme.c6
-rw-r--r--net/mac80211/offchannel.c23
-rw-r--r--net/mac80211/rx.c14
8 files changed, 77 insertions, 33 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 72ab1c0e3ca7..490990e3fc38 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2661,7 +2661,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
2661 list_del(&dep->list); 2661 list_del(&dep->list);
2662 mutex_unlock(&local->mtx); 2662 mutex_unlock(&local->mtx);
2663 2663
2664 ieee80211_roc_notify_destroy(dep); 2664 ieee80211_roc_notify_destroy(dep, true);
2665 return 0; 2665 return 0;
2666 } 2666 }
2667 2667
@@ -2701,7 +2701,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
2701 ieee80211_start_next_roc(local); 2701 ieee80211_start_next_roc(local);
2702 mutex_unlock(&local->mtx); 2702 mutex_unlock(&local->mtx);
2703 2703
2704 ieee80211_roc_notify_destroy(found); 2704 ieee80211_roc_notify_destroy(found, true);
2705 } else { 2705 } else {
2706 /* work may be pending so use it all the time */ 2706 /* work may be pending so use it all the time */
2707 found->abort = true; 2707 found->abort = true;
@@ -2711,6 +2711,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
2711 2711
2712 /* work will clean up etc */ 2712 /* work will clean up etc */
2713 flush_delayed_work(&found->work); 2713 flush_delayed_work(&found->work);
2714 WARN_ON(!found->to_be_freed);
2715 kfree(found);
2714 } 2716 }
2715 2717
2716 return 0; 2718 return 0;
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 166165efd8e2..03e8d2e3270e 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -79,6 +79,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
79 enum ieee80211_chanctx_mode mode) 79 enum ieee80211_chanctx_mode mode)
80{ 80{
81 struct ieee80211_chanctx *ctx; 81 struct ieee80211_chanctx *ctx;
82 u32 changed;
82 int err; 83 int err;
83 84
84 lockdep_assert_held(&local->chanctx_mtx); 85 lockdep_assert_held(&local->chanctx_mtx);
@@ -95,6 +96,13 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
95 if (!local->use_chanctx) 96 if (!local->use_chanctx)
96 local->hw.conf.radar_enabled = ctx->conf.radar_enabled; 97 local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
97 98
99 /* acquire mutex to prevent idle from changing */
100 mutex_lock(&local->mtx);
101 /* turn idle off *before* setting channel -- some drivers need that */
102 changed = ieee80211_idle_off(local);
103 if (changed)
104 ieee80211_hw_config(local, changed);
105
98 if (!local->use_chanctx) { 106 if (!local->use_chanctx) {
99 local->_oper_chandef = *chandef; 107 local->_oper_chandef = *chandef;
100 ieee80211_hw_config(local, 0); 108 ieee80211_hw_config(local, 0);
@@ -102,14 +110,17 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
102 err = drv_add_chanctx(local, ctx); 110 err = drv_add_chanctx(local, ctx);
103 if (err) { 111 if (err) {
104 kfree(ctx); 112 kfree(ctx);
105 return ERR_PTR(err); 113 ctx = ERR_PTR(err);
114
115 ieee80211_recalc_idle(local);
116 goto out;
106 } 117 }
107 } 118 }
108 119
120 /* and keep the mutex held until the new chanctx is on the list */
109 list_add_rcu(&ctx->list, &local->chanctx_list); 121 list_add_rcu(&ctx->list, &local->chanctx_list);
110 122
111 mutex_lock(&local->mtx); 123 out:
112 ieee80211_recalc_idle(local);
113 mutex_unlock(&local->mtx); 124 mutex_unlock(&local->mtx);
114 125
115 return ctx; 126 return ctx;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 21c1720eee00..af8410e1291e 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
@@ -1318,7 +1319,7 @@ void ieee80211_roc_setup(struct ieee80211_local *local);
1318void ieee80211_start_next_roc(struct ieee80211_local *local); 1319void ieee80211_start_next_roc(struct ieee80211_local *local);
1319void ieee80211_roc_purge(struct ieee80211_local *local, 1320void ieee80211_roc_purge(struct ieee80211_local *local,
1320 struct ieee80211_sub_if_data *sdata); 1321 struct ieee80211_sub_if_data *sdata);
1321void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc); 1322void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free);
1322void ieee80211_sw_roc_work(struct work_struct *work); 1323void ieee80211_sw_roc_work(struct work_struct *work);
1323void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); 1324void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
1324 1325
@@ -1332,6 +1333,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
1332 enum nl80211_iftype type); 1333 enum nl80211_iftype type);
1333void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); 1334void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
1334void ieee80211_remove_interfaces(struct ieee80211_local *local); 1335void ieee80211_remove_interfaces(struct ieee80211_local *local);
1336u32 ieee80211_idle_off(struct ieee80211_local *local);
1335void ieee80211_recalc_idle(struct ieee80211_local *local); 1337void ieee80211_recalc_idle(struct ieee80211_local *local);
1336void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, 1338void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
1337 const int offset); 1339 const int offset);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index b6abaaa3676f..146b1320af4e 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
81static u32 ieee80211_idle_off(struct ieee80211_local *local) 81u32 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;
@@ -349,21 +349,19 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
349int ieee80211_add_virtual_monitor(struct ieee80211_local *local) 349int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
350{ 350{
351 struct ieee80211_sub_if_data *sdata; 351 struct ieee80211_sub_if_data *sdata;
352 int ret = 0; 352 int ret;
353 353
354 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) 354 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
355 return 0; 355 return 0;
356 356
357 mutex_lock(&local->iflist_mtx); 357 ASSERT_RTNL();
358 358
359 if (local->monitor_sdata) 359 if (local->monitor_sdata)
360 goto out_unlock; 360 return 0;
361 361
362 sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); 362 sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
363 if (!sdata) { 363 if (!sdata)
364 ret = -ENOMEM; 364 return -ENOMEM;
365 goto out_unlock;
366 }
367 365
368 /* set up data */ 366 /* set up data */
369 sdata->local = local; 367 sdata->local = local;
@@ -377,13 +375,13 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
377 if (WARN_ON(ret)) { 375 if (WARN_ON(ret)) {
378 /* ok .. stupid driver, it asked for this! */ 376 /* ok .. stupid driver, it asked for this! */
379 kfree(sdata); 377 kfree(sdata);
380 goto out_unlock; 378 return ret;
381 } 379 }
382 380
383 ret = ieee80211_check_queues(sdata); 381 ret = ieee80211_check_queues(sdata);
384 if (ret) { 382 if (ret) {
385 kfree(sdata); 383 kfree(sdata);
386 goto out_unlock; 384 return ret;
387 } 385 }
388 386
389 ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, 387 ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
@@ -391,13 +389,14 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
391 if (ret) { 389 if (ret) {
392 drv_remove_interface(local, sdata); 390 drv_remove_interface(local, sdata);
393 kfree(sdata); 391 kfree(sdata);
394 goto out_unlock; 392 return ret;
395 } 393 }
396 394
395 mutex_lock(&local->iflist_mtx);
397 rcu_assign_pointer(local->monitor_sdata, sdata); 396 rcu_assign_pointer(local->monitor_sdata, sdata);
398 out_unlock:
399 mutex_unlock(&local->iflist_mtx); 397 mutex_unlock(&local->iflist_mtx);
400 return ret; 398
399 return 0;
401} 400}
402 401
403void ieee80211_del_virtual_monitor(struct ieee80211_local *local) 402void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
@@ -407,14 +406,20 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
407 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) 406 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
408 return; 407 return;
409 408
409 ASSERT_RTNL();
410
410 mutex_lock(&local->iflist_mtx); 411 mutex_lock(&local->iflist_mtx);
411 412
412 sdata = rcu_dereference_protected(local->monitor_sdata, 413 sdata = rcu_dereference_protected(local->monitor_sdata,
413 lockdep_is_held(&local->iflist_mtx)); 414 lockdep_is_held(&local->iflist_mtx));
414 if (!sdata) 415 if (!sdata) {
415 goto out_unlock; 416 mutex_unlock(&local->iflist_mtx);
417 return;
418 }
416 419
417 rcu_assign_pointer(local->monitor_sdata, NULL); 420 rcu_assign_pointer(local->monitor_sdata, NULL);
421 mutex_unlock(&local->iflist_mtx);
422
418 synchronize_net(); 423 synchronize_net();
419 424
420 ieee80211_vif_release_channel(sdata); 425 ieee80211_vif_release_channel(sdata);
@@ -422,8 +427,6 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
422 drv_remove_interface(local, sdata); 427 drv_remove_interface(local, sdata);
423 428
424 kfree(sdata); 429 kfree(sdata);
425 out_unlock:
426 mutex_unlock(&local->iflist_mtx);
427} 430}
428 431
429/* 432/*
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 4b984765d62d..6952760881c8 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1004,7 +1004,8 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
1004 1004
1005 rcu_read_lock(); 1005 rcu_read_lock();
1006 list_for_each_entry_rcu(sdata, &local->interfaces, list) 1006 list_for_each_entry_rcu(sdata, &local->interfaces, list)
1007 if (ieee80211_vif_is_mesh(&sdata->vif)) 1007 if (ieee80211_vif_is_mesh(&sdata->vif) &&
1008 ieee80211_sdata_running(sdata))
1008 ieee80211_queue_work(&local->hw, &sdata->work); 1009 ieee80211_queue_work(&local->hw, &sdata->work);
1009 rcu_read_unlock(); 1010 rcu_read_unlock();
1010} 1011}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c7860d0450dd..f7beb12abde2 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3665,8 +3665,10 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
3665 3665
3666 /* Restart STA timers */ 3666 /* Restart STA timers */
3667 rcu_read_lock(); 3667 rcu_read_lock();
3668 list_for_each_entry_rcu(sdata, &local->interfaces, list) 3668 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
3669 ieee80211_restart_sta_timer(sdata); 3669 if (ieee80211_sdata_running(sdata))
3670 ieee80211_restart_sta_timer(sdata);
3671 }
3670 rcu_read_unlock(); 3672 rcu_read_unlock();
3671} 3673}
3672 3674
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index e19d6cf26dde..acd1f71adc03 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 ieee80211_flush_queues(local, NULL); 385 ieee80211_flush_queues(local, NULL);
@@ -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_local *local,
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
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 14b32a4cd7bb..c8447af76ead 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2679,7 +2679,19 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
2679 2679
2680 memset(nskb->cb, 0, sizeof(nskb->cb)); 2680 memset(nskb->cb, 0, sizeof(nskb->cb));
2681 2681
2682 ieee80211_tx_skb(rx->sdata, nskb); 2682 if (rx->sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
2683 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb);
2684
2685 info->flags = IEEE80211_TX_CTL_TX_OFFCHAN |
2686 IEEE80211_TX_INTFL_OFFCHAN_TX_OK |
2687 IEEE80211_TX_CTL_NO_CCK_RATE;
2688 if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
2689 info->hw_queue =
2690 local->hw.offchannel_tx_hw_queue;
2691 }
2692
2693 __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7,
2694 status->band);
2683 } 2695 }
2684 dev_kfree_skb(rx->skb); 2696 dev_kfree_skb(rx->skb);
2685 return RX_QUEUED; 2697 return RX_QUEUED;