aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c68
1 files changed, 44 insertions, 24 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 640afab304d7..9ed49ad0380f 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) 81static 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;
@@ -87,7 +87,7 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local)
87 return IEEE80211_CONF_CHANGE_IDLE; 87 return IEEE80211_CONF_CHANGE_IDLE;
88} 88}
89 89
90static u32 ieee80211_idle_on(struct ieee80211_local *local) 90static u32 __ieee80211_idle_on(struct ieee80211_local *local)
91{ 91{
92 if (local->hw.conf.flags & IEEE80211_CONF_IDLE) 92 if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
93 return 0; 93 return 0;
@@ -98,16 +98,18 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
98 return IEEE80211_CONF_CHANGE_IDLE; 98 return IEEE80211_CONF_CHANGE_IDLE;
99} 99}
100 100
101void ieee80211_recalc_idle(struct ieee80211_local *local) 101static u32 __ieee80211_recalc_idle(struct ieee80211_local *local,
102 bool force_active)
102{ 103{
103 bool working = false, scanning, active; 104 bool working = false, scanning, active;
104 unsigned int led_trig_start = 0, led_trig_stop = 0; 105 unsigned int led_trig_start = 0, led_trig_stop = 0;
105 struct ieee80211_roc_work *roc; 106 struct ieee80211_roc_work *roc;
106 u32 change;
107 107
108 lockdep_assert_held(&local->mtx); 108 lockdep_assert_held(&local->mtx);
109 109
110 active = !list_empty(&local->chanctx_list) || local->monitors; 110 active = force_active ||
111 !list_empty(&local->chanctx_list) ||
112 local->monitors;
111 113
112 if (!local->ops->remain_on_channel) { 114 if (!local->ops->remain_on_channel) {
113 list_for_each_entry(roc, &local->roc_list, list) { 115 list_for_each_entry(roc, &local->roc_list, list) {
@@ -132,9 +134,18 @@ void ieee80211_recalc_idle(struct ieee80211_local *local)
132 ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); 134 ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
133 135
134 if (working || scanning || active) 136 if (working || scanning || active)
135 change = ieee80211_idle_off(local); 137 return __ieee80211_idle_off(local);
136 else 138 return __ieee80211_idle_on(local);
137 change = ieee80211_idle_on(local); 139}
140
141u32 ieee80211_idle_off(struct ieee80211_local *local)
142{
143 return __ieee80211_recalc_idle(local, true);
144}
145
146void ieee80211_recalc_idle(struct ieee80211_local *local)
147{
148 u32 change = __ieee80211_recalc_idle(local, false);
138 if (change) 149 if (change)
139 ieee80211_hw_config(local, change); 150 ieee80211_hw_config(local, change);
140} 151}
@@ -349,21 +360,19 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
349static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) 360static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
350{ 361{
351 struct ieee80211_sub_if_data *sdata; 362 struct ieee80211_sub_if_data *sdata;
352 int ret = 0; 363 int ret;
353 364
354 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) 365 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
355 return 0; 366 return 0;
356 367
357 mutex_lock(&local->iflist_mtx); 368 ASSERT_RTNL();
358 369
359 if (local->monitor_sdata) 370 if (local->monitor_sdata)
360 goto out_unlock; 371 return 0;
361 372
362 sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); 373 sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
363 if (!sdata) { 374 if (!sdata)
364 ret = -ENOMEM; 375 return -ENOMEM;
365 goto out_unlock;
366 }
367 376
368 /* set up data */ 377 /* set up data */
369 sdata->local = local; 378 sdata->local = local;
@@ -377,13 +386,13 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
377 if (WARN_ON(ret)) { 386 if (WARN_ON(ret)) {
378 /* ok .. stupid driver, it asked for this! */ 387 /* ok .. stupid driver, it asked for this! */
379 kfree(sdata); 388 kfree(sdata);
380 goto out_unlock; 389 return ret;
381 } 390 }
382 391
383 ret = ieee80211_check_queues(sdata); 392 ret = ieee80211_check_queues(sdata);
384 if (ret) { 393 if (ret) {
385 kfree(sdata); 394 kfree(sdata);
386 goto out_unlock; 395 return ret;
387 } 396 }
388 397
389 ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, 398 ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
@@ -391,13 +400,14 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
391 if (ret) { 400 if (ret) {
392 drv_remove_interface(local, sdata); 401 drv_remove_interface(local, sdata);
393 kfree(sdata); 402 kfree(sdata);
394 goto out_unlock; 403 return ret;
395 } 404 }
396 405
406 mutex_lock(&local->iflist_mtx);
397 rcu_assign_pointer(local->monitor_sdata, sdata); 407 rcu_assign_pointer(local->monitor_sdata, sdata);
398 out_unlock:
399 mutex_unlock(&local->iflist_mtx); 408 mutex_unlock(&local->iflist_mtx);
400 return ret; 409
410 return 0;
401} 411}
402 412
403static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) 413static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
@@ -407,14 +417,20 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
407 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) 417 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
408 return; 418 return;
409 419
420 ASSERT_RTNL();
421
410 mutex_lock(&local->iflist_mtx); 422 mutex_lock(&local->iflist_mtx);
411 423
412 sdata = rcu_dereference_protected(local->monitor_sdata, 424 sdata = rcu_dereference_protected(local->monitor_sdata,
413 lockdep_is_held(&local->iflist_mtx)); 425 lockdep_is_held(&local->iflist_mtx));
414 if (!sdata) 426 if (!sdata) {
415 goto out_unlock; 427 mutex_unlock(&local->iflist_mtx);
428 return;
429 }
416 430
417 rcu_assign_pointer(local->monitor_sdata, NULL); 431 rcu_assign_pointer(local->monitor_sdata, NULL);
432 mutex_unlock(&local->iflist_mtx);
433
418 synchronize_net(); 434 synchronize_net();
419 435
420 ieee80211_vif_release_channel(sdata); 436 ieee80211_vif_release_channel(sdata);
@@ -422,8 +438,6 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
422 drv_remove_interface(local, sdata); 438 drv_remove_interface(local, sdata);
423 439
424 kfree(sdata); 440 kfree(sdata);
425 out_unlock:
426 mutex_unlock(&local->iflist_mtx);
427} 441}
428 442
429/* 443/*
@@ -541,6 +555,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
541 555
542 ieee80211_adjust_monitor_flags(sdata, 1); 556 ieee80211_adjust_monitor_flags(sdata, 1);
543 ieee80211_configure_filter(local); 557 ieee80211_configure_filter(local);
558 mutex_lock(&local->mtx);
559 ieee80211_recalc_idle(local);
560 mutex_unlock(&local->mtx);
544 561
545 netif_carrier_on(dev); 562 netif_carrier_on(dev);
546 break; 563 break;
@@ -812,6 +829,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
812 829
813 ieee80211_adjust_monitor_flags(sdata, -1); 830 ieee80211_adjust_monitor_flags(sdata, -1);
814 ieee80211_configure_filter(local); 831 ieee80211_configure_filter(local);
832 mutex_lock(&local->mtx);
833 ieee80211_recalc_idle(local);
834 mutex_unlock(&local->mtx);
815 break; 835 break;
816 case NL80211_IFTYPE_P2P_DEVICE: 836 case NL80211_IFTYPE_P2P_DEVICE:
817 /* relies on synchronize_rcu() below */ 837 /* relies on synchronize_rcu() below */