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 6b631c049eba..9df26adb864a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -777,10 +777,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
777 | int i, flushed; | 777 | int i, flushed; |
778 | struct ps_data *ps; | 778 | struct ps_data *ps; |
779 | struct cfg80211_chan_def chandef; | 779 | struct cfg80211_chan_def chandef; |
780 | bool cancel_scan; | ||
780 | 781 | ||
781 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 782 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
782 | 783 | ||
783 | if (rcu_access_pointer(local->scan_sdata) == sdata) | 784 | cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; |
785 | if (cancel_scan) | ||
784 | ieee80211_scan_cancel(local); | 786 | ieee80211_scan_cancel(local); |
785 | 787 | ||
786 | /* | 788 | /* |
@@ -911,6 +913,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
911 | list_del(&sdata->u.vlan.list); | 913 | list_del(&sdata->u.vlan.list); |
912 | mutex_unlock(&local->mtx); | 914 | mutex_unlock(&local->mtx); |
913 | RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL); | 915 | RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL); |
916 | /* see comment in the default case below */ | ||
917 | ieee80211_free_keys(sdata, true); | ||
914 | /* no need to tell driver */ | 918 | /* no need to tell driver */ |
915 | break; | 919 | break; |
916 | case NL80211_IFTYPE_MONITOR: | 920 | case NL80211_IFTYPE_MONITOR: |
@@ -936,17 +940,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
936 | /* | 940 | /* |
937 | * When we get here, the interface is marked down. | 941 | * When we get here, the interface is marked down. |
938 | * Free the remaining keys, if there are any | 942 | * Free the remaining keys, if there are any |
939 | * (shouldn't be, except maybe in WDS mode?) | 943 | * (which can happen in AP mode if userspace sets |
944 | * keys before the interface is operating, and maybe | ||
945 | * also in WDS mode) | ||
940 | * | 946 | * |
941 | * Force the key freeing to always synchronize_net() | 947 | * Force the key freeing to always synchronize_net() |
942 | * to wait for the RX path in case it is using this | 948 | * to wait for the RX path in case it is using this |
943 | * interface enqueuing frames * at this very time on | 949 | * interface enqueuing frames at this very time on |
944 | * another CPU. | 950 | * another CPU. |
945 | */ | 951 | */ |
946 | ieee80211_free_keys(sdata, true); | 952 | ieee80211_free_keys(sdata, true); |
947 | |||
948 | /* fall through */ | ||
949 | case NL80211_IFTYPE_AP: | ||
950 | skb_queue_purge(&sdata->skb_queue); | 953 | skb_queue_purge(&sdata->skb_queue); |
951 | } | 954 | } |
952 | 955 | ||
@@ -1004,6 +1007,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
1004 | 1007 | ||
1005 | ieee80211_recalc_ps(local, -1); | 1008 | ieee80211_recalc_ps(local, -1); |
1006 | 1009 | ||
1010 | if (cancel_scan) | ||
1011 | flush_delayed_work(&local->scan_work); | ||
1012 | |||
1007 | if (local->open_count == 0) { | 1013 | if (local->open_count == 0) { |
1008 | ieee80211_stop_device(local); | 1014 | ieee80211_stop_device(local); |
1009 | 1015 | ||