diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 68 |
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 | ||
81 | static u32 ieee80211_idle_off(struct ieee80211_local *local) | 81 | static 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 | ||
90 | static u32 ieee80211_idle_on(struct ieee80211_local *local) | 90 | static 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 | ||
101 | void ieee80211_recalc_idle(struct ieee80211_local *local) | 101 | static 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 | |||
141 | u32 ieee80211_idle_off(struct ieee80211_local *local) | ||
142 | { | ||
143 | return __ieee80211_recalc_idle(local, true); | ||
144 | } | ||
145 | |||
146 | void 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) | |||
349 | static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | 360 | static 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 | ||
403 | static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | 413 | static 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 */ |