diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index af237223a8cd..653f5eb07a27 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -766,10 +766,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
766 | int i, flushed; | 766 | int i, flushed; |
767 | struct ps_data *ps; | 767 | struct ps_data *ps; |
768 | struct cfg80211_chan_def chandef; | 768 | struct cfg80211_chan_def chandef; |
769 | bool cancel_scan; | ||
769 | 770 | ||
770 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 771 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
771 | 772 | ||
772 | if (rcu_access_pointer(local->scan_sdata) == sdata) | 773 | cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; |
774 | if (cancel_scan) | ||
773 | ieee80211_scan_cancel(local); | 775 | ieee80211_scan_cancel(local); |
774 | 776 | ||
775 | /* | 777 | /* |
@@ -898,6 +900,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
898 | list_del(&sdata->u.vlan.list); | 900 | list_del(&sdata->u.vlan.list); |
899 | mutex_unlock(&local->mtx); | 901 | mutex_unlock(&local->mtx); |
900 | RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL); | 902 | RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL); |
903 | /* see comment in the default case below */ | ||
904 | ieee80211_free_keys(sdata, true); | ||
901 | /* no need to tell driver */ | 905 | /* no need to tell driver */ |
902 | break; | 906 | break; |
903 | case NL80211_IFTYPE_MONITOR: | 907 | case NL80211_IFTYPE_MONITOR: |
@@ -923,17 +927,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
923 | /* | 927 | /* |
924 | * When we get here, the interface is marked down. | 928 | * When we get here, the interface is marked down. |
925 | * Free the remaining keys, if there are any | 929 | * Free the remaining keys, if there are any |
926 | * (shouldn't be, except maybe in WDS mode?) | 930 | * (which can happen in AP mode if userspace sets |
931 | * keys before the interface is operating, and maybe | ||
932 | * also in WDS mode) | ||
927 | * | 933 | * |
928 | * Force the key freeing to always synchronize_net() | 934 | * Force the key freeing to always synchronize_net() |
929 | * to wait for the RX path in case it is using this | 935 | * to wait for the RX path in case it is using this |
930 | * interface enqueuing frames * at this very time on | 936 | * interface enqueuing frames at this very time on |
931 | * another CPU. | 937 | * another CPU. |
932 | */ | 938 | */ |
933 | ieee80211_free_keys(sdata, true); | 939 | ieee80211_free_keys(sdata, true); |
934 | |||
935 | /* fall through */ | ||
936 | case NL80211_IFTYPE_AP: | ||
937 | skb_queue_purge(&sdata->skb_queue); | 940 | skb_queue_purge(&sdata->skb_queue); |
938 | } | 941 | } |
939 | 942 | ||
@@ -991,6 +994,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
991 | 994 | ||
992 | ieee80211_recalc_ps(local, -1); | 995 | ieee80211_recalc_ps(local, -1); |
993 | 996 | ||
997 | if (cancel_scan) | ||
998 | flush_delayed_work(&local->scan_work); | ||
999 | |||
994 | if (local->open_count == 0) { | 1000 | if (local->open_count == 0) { |
995 | ieee80211_stop_device(local); | 1001 | ieee80211_stop_device(local); |
996 | 1002 | ||