]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/mac80211/mlme.c
Merge branch 'core-printk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-bionic-kernel.git] / net / mac80211 / mlme.c
index 741448b308257c3a6f01c3d09ca36d7ddaa31ca3..ae31968d42d3b855eebe05dcf0e660b4d367ff8f 100644 (file)
@@ -90,41 +90,6 @@ MODULE_PARM_DESC(probe_wait_ms,
  */
 #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
 
-/*
- * All cfg80211 functions have to be called outside a locked
- * section so that they can acquire a lock themselves... This
- * is much simpler than queuing up things in cfg80211, but we
- * do need some indirection for that here.
- */
-enum rx_mgmt_action {
-       /* no action required */
-       RX_MGMT_NONE,
-
-       /* caller must call cfg80211_send_deauth() */
-       RX_MGMT_CFG80211_DEAUTH,
-
-       /* caller must call cfg80211_send_disassoc() */
-       RX_MGMT_CFG80211_DISASSOC,
-
-       /* caller must call cfg80211_send_rx_auth() */
-       RX_MGMT_CFG80211_RX_AUTH,
-
-       /* caller must call cfg80211_send_rx_assoc() */
-       RX_MGMT_CFG80211_RX_ASSOC,
-
-       /* caller must call cfg80211_send_assoc_timeout() */
-       RX_MGMT_CFG80211_ASSOC_TIMEOUT,
-
-       /* used when a processed beacon causes a deauth */
-       RX_MGMT_CFG80211_TX_DEAUTH,
-};
-
-/* utils */
-static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd)
-{
-       lockdep_assert_held(&ifmgd->mtx);
-}
-
 /*
  * We can have multiple work items (and connection probing)
  * scheduling this timer, but we need to take care to only
@@ -135,13 +100,14 @@ static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd)
  * has happened -- the work that runs from this timer will
  * do that.
  */
-static void run_again(struct ieee80211_if_managed *ifmgd, unsigned long timeout)
+static void run_again(struct ieee80211_sub_if_data *sdata,
+                     unsigned long timeout)
 {
-       ASSERT_MGD_MTX(ifmgd);
+       sdata_assert_lock(sdata);
 
-       if (!timer_pending(&ifmgd->timer) ||
-           time_before(timeout, ifmgd->timer.expires))
-               mod_timer(&ifmgd->timer, timeout);
+       if (!timer_pending(&sdata->u.mgd.timer) ||
+           time_before(timeout, sdata->u.mgd.timer.expires))
+               mod_timer(&sdata->u.mgd.timer, timeout);
 }
 
 void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata)
@@ -224,6 +190,12 @@ static u32 chandef_downgrade(struct cfg80211_chan_def *c)
                c->width = NL80211_CHAN_WIDTH_20_NOHT;
                ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
                break;
+       case NL80211_CHAN_WIDTH_5:
+       case NL80211_CHAN_WIDTH_10:
+               WARN_ON_ONCE(1);
+               /* keep c->width */
+               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+               break;
        }
 
        WARN_ON_ONCE(!cfg80211_chandef_valid(c));
@@ -652,7 +624,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_channel *chan;
        u32 rates = 0;
 
-       lockdep_assert_held(&ifmgd->mtx);
+       sdata_assert_lock(sdata);
 
        rcu_read_lock();
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
@@ -914,6 +886,10 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
 
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
                                        IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
+
+       if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
+               IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+
        if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
                            IEEE80211_STA_CONNECTION_POLL))
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
@@ -962,7 +938,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        if (!ieee80211_sdata_running(sdata))
                return;
 
-       mutex_lock(&ifmgd->mtx);
+       sdata_lock(sdata);
        if (!ifmgd->associated)
                goto out;
 
@@ -985,7 +961,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
  out:
        ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
-       mutex_unlock(&ifmgd->mtx);
+       sdata_unlock(sdata);
 }
 
 void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
@@ -1036,7 +1012,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        const struct ieee80211_ht_operation *ht_oper;
        int secondary_channel_offset = -1;
 
-       ASSERT_MGD_MTX(ifmgd);
+       sdata_assert_lock(sdata);
 
        if (!cbss)
                return;
@@ -1390,6 +1366,9 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
                          IEEE80211_STA_CONNECTION_POLL))
                return false;
 
+       if (!mgd->have_beacon)
+               return false;
+
        rcu_read_lock();
        sta = sta_info_get(sdata, mgd->bssid);
        if (sta)
@@ -1798,7 +1777,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_led_assoc(local, 1);
 
-       if (sdata->u.mgd.assoc_data->have_beacon) {
+       if (sdata->u.mgd.have_beacon) {
                /*
                 * If the AP is buggy we may get here with no DTIM period
                 * known, so assume it's 1 which is the only safe assumption
@@ -1806,8 +1785,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
                 * probably just won't work at all.
                 */
                bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1;
-               bss_info_changed |= BSS_CHANGED_DTIM_PERIOD;
+               bss_conf->beacon_rate = bss->beacon_rate;
+               bss_info_changed |= BSS_CHANGED_BEACON_INFO;
        } else {
+               bss_conf->beacon_rate = NULL;
                bss_conf->dtim_period = 0;
        }
 
@@ -1842,7 +1823,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        u32 changed = 0;
 
-       ASSERT_MGD_MTX(ifmgd);
+       sdata_assert_lock(sdata);
 
        if (WARN_ON_ONCE(tx && !frame_buf))
                return;
@@ -1930,6 +1911,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        del_timer_sync(&sdata->u.mgd.chswitch_timer);
 
        sdata->vif.bss_conf.dtim_period = 0;
+       sdata->vif.bss_conf.beacon_rate = NULL;
+
+       ifmgd->have_beacon = false;
 
        ifmgd->flags = 0;
        ieee80211_vif_release_channel(sdata);
@@ -2051,7 +2035,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
        }
 
        ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
-       run_again(ifmgd, ifmgd->probe_timeout);
+       run_again(sdata, ifmgd->probe_timeout);
        if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
                ieee80211_flush_queues(sdata->local, sdata);
 }
@@ -2065,7 +2049,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
        if (!ieee80211_sdata_running(sdata))
                return;
 
-       mutex_lock(&ifmgd->mtx);
+       sdata_lock(sdata);
 
        if (!ifmgd->associated)
                goto out;
@@ -2119,7 +2103,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
        ifmgd->probe_send_count = 0;
        ieee80211_mgd_probe_ap_send(sdata);
  out:
-       mutex_unlock(&ifmgd->mtx);
+       sdata_unlock(sdata);
 }
 
 struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
@@ -2135,7 +2119,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
        if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
                return NULL;
 
-       ASSERT_MGD_MTX(ifmgd);
+       sdata_assert_lock(sdata);
 
        if (ifmgd->associated)
                cbss = ifmgd->associated;
@@ -2168,9 +2152,9 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
 
-       mutex_lock(&ifmgd->mtx);
+       sdata_lock(sdata);
        if (!ifmgd->associated) {
-               mutex_unlock(&ifmgd->mtx);
+               sdata_unlock(sdata);
                return;
        }
 
@@ -2181,13 +2165,10 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
        ieee80211_wake_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
-       mutex_unlock(&ifmgd->mtx);
 
-       /*
-        * must be outside lock due to cfg80211,
-        * but that's not a problem.
-        */
-       cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
+       cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                             IEEE80211_DEAUTH_FRAME_LEN);
+       sdata_unlock(sdata);
 }
 
 static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
@@ -2254,7 +2235,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
 
-       lockdep_assert_held(&sdata->u.mgd.mtx);
+       sdata_assert_lock(sdata);
 
        if (!assoc) {
                sta_info_destroy_addr(sdata, auth_data->bss->bssid);
@@ -2295,27 +2276,26 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
                            auth_data->key_idx, tx_flags);
 }
 
-static enum rx_mgmt_action __must_check
-ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
-                      struct ieee80211_mgmt *mgmt, size_t len)
+static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
+                                  struct ieee80211_mgmt *mgmt, size_t len)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u8 bssid[ETH_ALEN];
        u16 auth_alg, auth_transaction, status_code;
        struct sta_info *sta;
 
-       lockdep_assert_held(&ifmgd->mtx);
+       sdata_assert_lock(sdata);
 
        if (len < 24 + 6)
-               return RX_MGMT_NONE;
+               return;
 
        if (!ifmgd->auth_data || ifmgd->auth_data->done)
-               return RX_MGMT_NONE;
+               return;
 
        memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN);
 
        if (!ether_addr_equal(bssid, mgmt->bssid))
-               return RX_MGMT_NONE;
+               return;
 
        auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
        auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
@@ -2327,14 +2307,15 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                           mgmt->sa, auth_alg, ifmgd->auth_data->algorithm,
                           auth_transaction,
                           ifmgd->auth_data->expected_transaction);
-               return RX_MGMT_NONE;
+               return;
        }
 
        if (status_code != WLAN_STATUS_SUCCESS) {
                sdata_info(sdata, "%pM denied authentication (status %d)\n",
                           mgmt->sa, status_code);
                ieee80211_destroy_auth_data(sdata, false);
-               return RX_MGMT_CFG80211_RX_AUTH;
+               cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
+               return;
        }
 
        switch (ifmgd->auth_data->algorithm) {
@@ -2347,20 +2328,20 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                if (ifmgd->auth_data->expected_transaction != 4) {
                        ieee80211_auth_challenge(sdata, mgmt, len);
                        /* need another frame */
-                       return RX_MGMT_NONE;
+                       return;
                }
                break;
        default:
                WARN_ONCE(1, "invalid auth alg %d",
                          ifmgd->auth_data->algorithm);
-               return RX_MGMT_NONE;
+               return;
        }
 
        sdata_info(sdata, "authenticated\n");
        ifmgd->auth_data->done = true;
        ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
        ifmgd->auth_data->timeout_started = true;
-       run_again(ifmgd, ifmgd->auth_data->timeout);
+       run_again(sdata, ifmgd->auth_data->timeout);
 
        if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
            ifmgd->auth_data->expected_transaction != 2) {
@@ -2368,7 +2349,8 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                 * Report auth frame to user space for processing since another
                 * round of Authentication frames is still needed.
                 */
-               return RX_MGMT_CFG80211_RX_AUTH;
+               cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
+               return;
        }
 
        /* move station state to auth */
@@ -2384,30 +2366,29 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
        }
        mutex_unlock(&sdata->local->sta_mtx);
 
-       return RX_MGMT_CFG80211_RX_AUTH;
+       cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
+       return;
  out_err:
        mutex_unlock(&sdata->local->sta_mtx);
        /* ignore frame -- wait for timeout */
-       return RX_MGMT_NONE;
 }
 
 
-static enum rx_mgmt_action __must_check
-ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
-                        struct ieee80211_mgmt *mgmt, size_t len)
+static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
+                                    struct ieee80211_mgmt *mgmt, size_t len)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        const u8 *bssid = NULL;
        u16 reason_code;
 
-       lockdep_assert_held(&ifmgd->mtx);
+       sdata_assert_lock(sdata);
 
        if (len < 24 + 2)
-               return RX_MGMT_NONE;
+               return;
 
        if (!ifmgd->associated ||
            !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
-               return RX_MGMT_NONE;
+               return;
 
        bssid = ifmgd->associated->bssid;
 
@@ -2418,25 +2399,24 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
-       return RX_MGMT_CFG80211_DEAUTH;
+       cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
 }
 
 
-static enum rx_mgmt_action __must_check
-ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
-                          struct ieee80211_mgmt *mgmt, size_t len)
+static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
+                                      struct ieee80211_mgmt *mgmt, size_t len)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u16 reason_code;
 
-       lockdep_assert_held(&ifmgd->mtx);
+       sdata_assert_lock(sdata);
 
        if (len < 24 + 2)
-               return RX_MGMT_NONE;
+               return;
 
        if (!ifmgd->associated ||
            !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
-               return RX_MGMT_NONE;
+               return;
 
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
@@ -2445,7 +2425,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
-       return RX_MGMT_CFG80211_DISASSOC;
+       cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
 }
 
 static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
@@ -2495,7 +2475,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
 
-       lockdep_assert_held(&sdata->u.mgd.mtx);
+       sdata_assert_lock(sdata);
 
        if (!assoc) {
                sta_info_destroy_addr(sdata, assoc_data->bss->bssid);
@@ -2749,10 +2729,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        return ret;
 }
 
-static enum rx_mgmt_action __must_check
-ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
-                            struct ieee80211_mgmt *mgmt, size_t len,
-                            struct cfg80211_bss **bss)
+static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
+                                        struct ieee80211_mgmt *mgmt,
+                                        size_t len)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
@@ -2760,13 +2739,14 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        struct ieee802_11_elems elems;
        u8 *pos;
        bool reassoc;
+       struct cfg80211_bss *bss;
 
-       lockdep_assert_held(&ifmgd->mtx);
+       sdata_assert_lock(sdata);
 
        if (!assoc_data)
-               return RX_MGMT_NONE;
+               return;
        if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid))
-               return RX_MGMT_NONE;
+               return;
 
        /*
         * AssocResp and ReassocResp have identical structure, so process both
@@ -2774,7 +2754,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
         */
 
        if (len < 24 + 6)
-               return RX_MGMT_NONE;
+               return;
 
        reassoc = ieee80211_is_reassoc_req(mgmt->frame_control);
        capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
@@ -2801,22 +2781,22 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                assoc_data->timeout = jiffies + msecs_to_jiffies(ms);
                assoc_data->timeout_started = true;
                if (ms > IEEE80211_ASSOC_TIMEOUT)
-                       run_again(ifmgd, assoc_data->timeout);
-               return RX_MGMT_NONE;
+                       run_again(sdata, assoc_data->timeout);
+               return;
        }
 
-       *bss = assoc_data->bss;
+       bss = assoc_data->bss;
 
        if (status_code != WLAN_STATUS_SUCCESS) {
                sdata_info(sdata, "%pM denied association (code=%d)\n",
                           mgmt->sa, status_code);
                ieee80211_destroy_assoc_data(sdata, false);
        } else {
-               if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
+               if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) {
                        /* oops -- internal error -- send timeout for now */
                        ieee80211_destroy_assoc_data(sdata, false);
-                       cfg80211_put_bss(sdata->local->hw.wiphy, *bss);
-                       return RX_MGMT_CFG80211_ASSOC_TIMEOUT;
+                       cfg80211_assoc_timeout(sdata->dev, bss);
+                       return;
                }
                sdata_info(sdata, "associated\n");
 
@@ -2828,7 +2808,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                ieee80211_destroy_assoc_data(sdata, true);
        }
 
-       return RX_MGMT_CFG80211_RX_ASSOC;
+       cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len);
 }
 
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
@@ -2840,23 +2820,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        int freq;
        struct ieee80211_bss *bss;
        struct ieee80211_channel *channel;
-       bool need_ps = false;
-
-       lockdep_assert_held(&sdata->u.mgd.mtx);
 
-       if ((sdata->u.mgd.associated &&
-            ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) ||
-           (sdata->u.mgd.assoc_data &&
-            ether_addr_equal(mgmt->bssid,
-                             sdata->u.mgd.assoc_data->bss->bssid))) {
-               /* not previously set so we may need to recalc */
-               need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period;
-
-               if (elems->tim && !elems->parse_error) {
-                       const struct ieee80211_tim_ie *tim_ie = elems->tim;
-                       sdata->u.mgd.dtim_period = tim_ie->dtim_period;
-               }
-       }
+       sdata_assert_lock(sdata);
 
        if (elems->ds_params)
                freq = ieee80211_channel_to_frequency(elems->ds_params[0],
@@ -2871,19 +2836,15 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
        bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
                                        channel);
-       if (bss)
+       if (bss) {
                ieee80211_rx_bss_put(local, bss);
+               sdata->vif.bss_conf.beacon_rate = bss->beacon_rate;
+       }
 
        if (!sdata->u.mgd.associated ||
            !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid))
                return;
 
-       if (need_ps) {
-               mutex_lock(&local->iflist_mtx);
-               ieee80211_recalc_ps(local, -1);
-               mutex_unlock(&local->iflist_mtx);
-       }
-
        ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
                                         elems, true);
 
@@ -2901,7 +2862,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 
        ifmgd = &sdata->u.mgd;
 
-       ASSERT_MGD_MTX(ifmgd);
+       sdata_assert_lock(sdata);
 
        if (!ether_addr_equal(mgmt->da, sdata->vif.addr))
                return; /* ignore ProbeResp to foreign address */
@@ -2926,7 +2887,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
                ifmgd->auth_data->tries = 0;
                ifmgd->auth_data->timeout = jiffies;
                ifmgd->auth_data->timeout_started = true;
-               run_again(ifmgd, ifmgd->auth_data->timeout);
+               run_again(sdata, ifmgd->auth_data->timeout);
        }
 }
 
@@ -2951,10 +2912,9 @@ static const u64 care_about_ies =
        (1ULL << WLAN_EID_HT_CAPABILITY) |
        (1ULL << WLAN_EID_HT_OPERATION);
 
-static enum rx_mgmt_action
-ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
-                        struct ieee80211_mgmt *mgmt, size_t len,
-                        u8 *deauth_buf, struct ieee80211_rx_status *rx_status)
+static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
+                                    struct ieee80211_mgmt *mgmt, size_t len,
+                                    struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
@@ -2969,24 +2929,25 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        u8 erp_value = 0;
        u32 ncrc;
        u8 *bssid;
+       u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
 
-       lockdep_assert_held(&ifmgd->mtx);
+       sdata_assert_lock(sdata);
 
        /* Process beacon from the current BSS */
        baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
        if (baselen > len)
-               return RX_MGMT_NONE;
+               return;
 
        rcu_read_lock();
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        if (!chanctx_conf) {
                rcu_read_unlock();
-               return RX_MGMT_NONE;
+               return;
        }
 
        if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
                rcu_read_unlock();
-               return RX_MGMT_NONE;
+               return;
        }
        chan = chanctx_conf->def.chan;
        rcu_read_unlock();
@@ -2997,7 +2958,11 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                       len - baselen, false, &elems);
 
                ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
-               ifmgd->assoc_data->have_beacon = true;
+               if (elems.tim && !elems.parse_error) {
+                       const struct ieee80211_tim_ie *tim_ie = elems.tim;
+                       ifmgd->dtim_period = tim_ie->dtim_period;
+               }
+               ifmgd->have_beacon = true;
                ifmgd->assoc_data->need_beacon = false;
                if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
                        sdata->vif.bss_conf.sync_tsf =
@@ -3013,13 +2978,13 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                /* continue assoc process */
                ifmgd->assoc_data->timeout = jiffies;
                ifmgd->assoc_data->timeout_started = true;
-               run_again(ifmgd, ifmgd->assoc_data->timeout);
-               return RX_MGMT_NONE;
+               run_again(sdata, ifmgd->assoc_data->timeout);
+               return;
        }
 
        if (!ifmgd->associated ||
            !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
-               return RX_MGMT_NONE;
+               return;
        bssid = ifmgd->associated->bssid;
 
        /* Track average RSSI from the Beacon frames of the current AP */
@@ -3165,7 +3130,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        }
 
        if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
-               return RX_MGMT_NONE;
+               return;
        ifmgd->beacon_crc = ncrc;
        ifmgd->beacon_crc_valid = true;
 
@@ -3179,7 +3144,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
         * If we haven't had a beacon before, tell the driver about the
         * DTIM period (and beacon timing if desired) now.
         */
-       if (!bss_conf->dtim_period) {
+       if (!ifmgd->have_beacon) {
                /* a few bogus AP send dtim_period = 0 or no TIM IE */
                if (elems.tim)
                        bss_conf->dtim_period = elems.tim->dtim_period ?: 1;
@@ -3198,7 +3163,14 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                sdata->vif.bss_conf.sync_dtim_count = 0;
                }
 
-               changed |= BSS_CHANGED_DTIM_PERIOD;
+               changed |= BSS_CHANGED_BEACON_INFO;
+               ifmgd->have_beacon = true;
+
+               mutex_lock(&local->iflist_mtx);
+               ieee80211_recalc_ps(local, -1);
+               mutex_unlock(&local->iflist_mtx);
+
+               ieee80211_recalc_ps_vif(sdata);
        }
 
        if (elems.erp_info) {
@@ -3220,7 +3192,9 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_DEAUTH_LEAVING,
                                       true, deauth_buf);
-               return RX_MGMT_CFG80211_TX_DEAUTH;
+               cfg80211_tx_mlme_mgmt(sdata->dev, deauth_buf,
+                                     sizeof(deauth_buf));
+               return;
        }
 
        if (sta && elems.opmode_notif)
@@ -3237,19 +3211,13 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                                       elems.pwr_constr_elem);
 
        ieee80211_bss_info_change_notify(sdata, changed);
-
-       return RX_MGMT_NONE;
 }
 
 void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                  struct sk_buff *skb)
 {
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_rx_status *rx_status;
        struct ieee80211_mgmt *mgmt;
-       struct cfg80211_bss *bss = NULL;
-       enum rx_mgmt_action rma = RX_MGMT_NONE;
-       u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
        u16 fc;
        struct ieee802_11_elems elems;
        int ies_len;
@@ -3258,28 +3226,27 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        mgmt = (struct ieee80211_mgmt *) skb->data;
        fc = le16_to_cpu(mgmt->frame_control);
 
-       mutex_lock(&ifmgd->mtx);
+       sdata_lock(sdata);
 
        switch (fc & IEEE80211_FCTL_STYPE) {
        case IEEE80211_STYPE_BEACON:
-               rma = ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
-                                              deauth_buf, rx_status);
+               ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status);
                break;
        case IEEE80211_STYPE_PROBE_RESP:
                ieee80211_rx_mgmt_probe_resp(sdata, skb);
                break;
        case IEEE80211_STYPE_AUTH:
-               rma = ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len);
+               ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len);
                break;
        case IEEE80211_STYPE_DEAUTH:
-               rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
+               ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
                break;
        case IEEE80211_STYPE_DISASSOC:
-               rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
+               ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
                break;
        case IEEE80211_STYPE_ASSOC_RESP:
        case IEEE80211_STYPE_REASSOC_RESP:
-               rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss);
+               ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len);
                break;
        case IEEE80211_STYPE_ACTION:
                if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) {
@@ -3325,34 +3292,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                }
                break;
        }
-       mutex_unlock(&ifmgd->mtx);
-
-       switch (rma) {
-       case RX_MGMT_NONE:
-               /* no action */
-               break;
-       case RX_MGMT_CFG80211_DEAUTH:
-               cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
-               break;
-       case RX_MGMT_CFG80211_DISASSOC:
-               cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
-               break;
-       case RX_MGMT_CFG80211_RX_AUTH:
-               cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, skb->len);
-               break;
-       case RX_MGMT_CFG80211_RX_ASSOC:
-               cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, skb->len);
-               break;
-       case RX_MGMT_CFG80211_ASSOC_TIMEOUT:
-               cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid);
-               break;
-       case RX_MGMT_CFG80211_TX_DEAUTH:
-               cfg80211_send_deauth(sdata->dev, deauth_buf,
-                                    sizeof(deauth_buf));
-               break;
-       default:
-               WARN(1, "unexpected: %d", rma);
-       }
+       sdata_unlock(sdata);
 }
 
 static void ieee80211_sta_timer(unsigned long data)
@@ -3366,20 +3306,13 @@ static void ieee80211_sta_timer(unsigned long data)
 static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
                                          u8 *bssid, u8 reason, bool tx)
 {
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
 
        ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
                               tx, frame_buf);
-       mutex_unlock(&ifmgd->mtx);
 
-       /*
-        * must be outside lock due to cfg80211,
-        * but that's not a problem.
-        */
-       cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
-
-       mutex_lock(&ifmgd->mtx);
+       cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                             IEEE80211_DEAUTH_FRAME_LEN);
 }
 
 static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
@@ -3389,7 +3322,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data;
        u32 tx_flags = 0;
 
-       lockdep_assert_held(&ifmgd->mtx);
+       sdata_assert_lock(sdata);
 
        if (WARN_ON_ONCE(!auth_data))
                return -EINVAL;
@@ -3462,7 +3395,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
        if (tx_flags == 0) {
                auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
                ifmgd->auth_data->timeout_started = true;
-               run_again(ifmgd, auth_data->timeout);
+               run_again(sdata, auth_data->timeout);
        } else {
                auth_data->timeout_started = false;
        }
@@ -3475,7 +3408,7 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
        struct ieee80211_local *local = sdata->local;
 
-       lockdep_assert_held(&sdata->u.mgd.mtx);
+       sdata_assert_lock(sdata);
 
        assoc_data->tries++;
        if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) {
@@ -3499,7 +3432,7 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
        if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) {
                assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
                assoc_data->timeout_started = true;
-               run_again(&sdata->u.mgd, assoc_data->timeout);
+               run_again(sdata, assoc_data->timeout);
        } else {
                assoc_data->timeout_started = false;
        }
@@ -3524,7 +3457,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       mutex_lock(&ifmgd->mtx);
+       sdata_lock(sdata);
 
        if (ifmgd->status_received) {
                __le16 fc = ifmgd->status_fc;
@@ -3536,7 +3469,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                        if (status_acked) {
                                ifmgd->auth_data->timeout =
                                        jiffies + IEEE80211_AUTH_TIMEOUT_SHORT;
-                               run_again(ifmgd, ifmgd->auth_data->timeout);
+                               run_again(sdata, ifmgd->auth_data->timeout);
                        } else {
                                ifmgd->auth_data->timeout = jiffies - 1;
                        }
@@ -3547,7 +3480,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                        if (status_acked) {
                                ifmgd->assoc_data->timeout =
                                        jiffies + IEEE80211_ASSOC_TIMEOUT_SHORT;
-                               run_again(ifmgd, ifmgd->assoc_data->timeout);
+                               run_again(sdata, ifmgd->assoc_data->timeout);
                        } else {
                                ifmgd->assoc_data->timeout = jiffies - 1;
                        }
@@ -3570,30 +3503,22 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
 
                        ieee80211_destroy_auth_data(sdata, false);
 
-                       mutex_unlock(&ifmgd->mtx);
-                       cfg80211_send_auth_timeout(sdata->dev, bssid);
-                       mutex_lock(&ifmgd->mtx);
+                       cfg80211_auth_timeout(sdata->dev, bssid);
                }
        } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started)
-               run_again(ifmgd, ifmgd->auth_data->timeout);
+               run_again(sdata, ifmgd->auth_data->timeout);
 
        if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started &&
            time_after(jiffies, ifmgd->assoc_data->timeout)) {
-               if ((ifmgd->assoc_data->need_beacon &&
-                    !ifmgd->assoc_data->have_beacon) ||
+               if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) ||
                    ieee80211_do_assoc(sdata)) {
-                       u8 bssid[ETH_ALEN];
-
-                       memcpy(bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN);
+                       struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
 
                        ieee80211_destroy_assoc_data(sdata, false);
-
-                       mutex_unlock(&ifmgd->mtx);
-                       cfg80211_send_assoc_timeout(sdata->dev, bssid);
-                       mutex_lock(&ifmgd->mtx);
+                       cfg80211_assoc_timeout(sdata->dev, bss);
                }
        } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
-               run_again(ifmgd, ifmgd->assoc_data->timeout);
+               run_again(sdata, ifmgd->assoc_data->timeout);
 
        if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
                            IEEE80211_STA_CONNECTION_POLL) &&
@@ -3627,7 +3552,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                                        false);
                        }
                } else if (time_is_after_jiffies(ifmgd->probe_timeout))
-                       run_again(ifmgd, ifmgd->probe_timeout);
+                       run_again(sdata, ifmgd->probe_timeout);
                else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
                        mlme_dbg(sdata,
                                 "Failed to send nullfunc to AP %pM after %dms, disconnecting\n",
@@ -3656,7 +3581,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                }
        }
 
-       mutex_unlock(&ifmgd->mtx);
+       sdata_unlock(sdata);
 }
 
 static void ieee80211_sta_bcn_mon_timer(unsigned long data)
@@ -3717,9 +3642,9 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       mutex_lock(&ifmgd->mtx);
+       sdata_lock(sdata);
        if (!ifmgd->associated) {
-               mutex_unlock(&ifmgd->mtx);
+               sdata_unlock(sdata);
                return;
        }
 
@@ -3730,10 +3655,10 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
                                              ifmgd->associated->bssid,
                                              WLAN_REASON_UNSPECIFIED,
                                              true);
-               mutex_unlock(&ifmgd->mtx);
+               sdata_unlock(sdata);
                return;
        }
-       mutex_unlock(&ifmgd->mtx);
+       sdata_unlock(sdata);
 }
 #endif
 
@@ -3765,8 +3690,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
        ifmgd->uapsd_max_sp_len = sdata->local->hw.uapsd_max_sp_len;
        ifmgd->p2p_noa_index = -1;
 
-       mutex_init(&ifmgd->mtx);
-
        if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
                ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC;
        else
@@ -3923,6 +3846,12 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
         */
        ret = ieee80211_vif_use_channel(sdata, &chandef,
                                        IEEE80211_CHANCTX_SHARED);
+
+       /* don't downgrade for 5 and 10 MHz channels, though. */
+       if (chandef.width == NL80211_CHAN_WIDTH_5 ||
+           chandef.width == NL80211_CHAN_WIDTH_10)
+               return ret;
+
        while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
                ifmgd->flags |= chandef_downgrade(&chandef);
                ret = ieee80211_vif_use_channel(sdata, &chandef,
@@ -4122,8 +4051,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 
        /* try to authenticate/probe */
 
-       mutex_lock(&ifmgd->mtx);
-
        if ((ifmgd->auth_data && !ifmgd->auth_data->done) ||
            ifmgd->assoc_data) {
                err = -EBUSY;
@@ -4143,8 +4070,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
                                       WLAN_REASON_UNSPECIFIED,
                                       false, frame_buf);
 
-               __cfg80211_send_deauth(sdata->dev, frame_buf,
-                                      sizeof(frame_buf));
+               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                                     sizeof(frame_buf));
        }
 
        sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
@@ -4161,8 +4088,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 
        /* hold our own reference */
        cfg80211_ref_bss(local->hw.wiphy, auth_data->bss);
-       err = 0;
-       goto out_unlock;
+       return 0;
 
  err_clear:
        memset(ifmgd->bssid, 0, ETH_ALEN);
@@ -4170,9 +4096,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        ifmgd->auth_data = NULL;
  err_free:
        kfree(auth_data);
- out_unlock:
-       mutex_unlock(&ifmgd->mtx);
-
        return err;
 }
 
@@ -4203,8 +4126,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        assoc_data->ssid_len = ssidie[1];
        rcu_read_unlock();
 
-       mutex_lock(&ifmgd->mtx);
-
        if (ifmgd->associated) {
                u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
 
@@ -4212,8 +4133,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                                       WLAN_REASON_UNSPECIFIED,
                                       false, frame_buf);
 
-               __cfg80211_send_deauth(sdata->dev, frame_buf,
-                                      sizeof(frame_buf));
+               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                                     sizeof(frame_buf));
        }
 
        if (ifmgd->auth_data && !ifmgd->auth_data->done) {
@@ -4360,6 +4281,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 
        ifmgd->assoc_data = assoc_data;
        ifmgd->dtim_period = 0;
+       ifmgd->have_beacon = false;
 
        err = ieee80211_prep_connection(sdata, req->bss, true);
        if (err)
@@ -4391,7 +4313,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                        ifmgd->dtim_period = tim->dtim_period;
                        dtim_count = tim->dtim_count;
                }
-               assoc_data->have_beacon = true;
+               ifmgd->have_beacon = true;
                assoc_data->timeout = jiffies;
                assoc_data->timeout_started = true;
 
@@ -4407,7 +4329,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        }
        rcu_read_unlock();
 
-       run_again(ifmgd, assoc_data->timeout);
+       run_again(sdata, assoc_data->timeout);
 
        if (bss->corrupt_data) {
                char *corrupt_type = "data";
@@ -4423,17 +4345,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                           corrupt_type);
        }
 
-       err = 0;
-       goto out;
+       return 0;
  err_clear:
        memset(ifmgd->bssid, 0, ETH_ALEN);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
        ifmgd->assoc_data = NULL;
  err_free:
        kfree(assoc_data);
- out:
-       mutex_unlock(&ifmgd->mtx);
-
        return err;
 }
 
@@ -4445,8 +4363,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        bool tx = !req->local_state_change;
        bool report_frame = false;
 
-       mutex_lock(&ifmgd->mtx);
-
        sdata_info(sdata,
                   "deauthenticating from %pM by local choice (reason=%d)\n",
                   req->bssid, req->reason_code);
@@ -4458,7 +4374,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
                                               req->reason_code, tx,
                                               frame_buf);
                ieee80211_destroy_auth_data(sdata, false);
-               mutex_unlock(&ifmgd->mtx);
 
                report_frame = true;
                goto out;
@@ -4470,12 +4385,11 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
                                       req->reason_code, tx, frame_buf);
                report_frame = true;
        }
-       mutex_unlock(&ifmgd->mtx);
 
  out:
        if (report_frame)
-               __cfg80211_send_deauth(sdata->dev, frame_buf,
-                                      IEEE80211_DEAUTH_FRAME_LEN);
+               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                                     IEEE80211_DEAUTH_FRAME_LEN);
 
        return 0;
 }
@@ -4487,18 +4401,14 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
        u8 bssid[ETH_ALEN];
        u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
 
-       mutex_lock(&ifmgd->mtx);
-
        /*
         * cfg80211 should catch this ... but it's racy since
         * we can receive a disassoc frame, process it, hand it
         * to cfg80211 while that's in a locked section already
         * trying to tell us that the user wants to disconnect.
         */
-       if (ifmgd->associated != req->bss) {
-               mutex_unlock(&ifmgd->mtx);
+       if (ifmgd->associated != req->bss)
                return -ENOLINK;
-       }
 
        sdata_info(sdata,
                   "disassociating from %pM by local choice (reason=%d)\n",
@@ -4508,10 +4418,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
        ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
                               req->reason_code, !req->local_state_change,
                               frame_buf);
-       mutex_unlock(&ifmgd->mtx);
 
-       __cfg80211_send_disassoc(sdata->dev, frame_buf,
-                                IEEE80211_DEAUTH_FRAME_LEN);
+       cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                             IEEE80211_DEAUTH_FRAME_LEN);
 
        return 0;
 }
@@ -4531,13 +4440,16 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
        cancel_work_sync(&ifmgd->csa_connection_drop_work);
        cancel_work_sync(&ifmgd->chswitch_work);
 
-       mutex_lock(&ifmgd->mtx);
-       if (ifmgd->assoc_data)
+       sdata_lock(sdata);
+       if (ifmgd->assoc_data) {
+               struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
                ieee80211_destroy_assoc_data(sdata, false);
+               cfg80211_assoc_timeout(sdata->dev, bss);
+       }
        if (ifmgd->auth_data)
                ieee80211_destroy_auth_data(sdata, false);
        del_timer_sync(&ifmgd->timer);
-       mutex_unlock(&ifmgd->mtx);
+       sdata_unlock(sdata);
 }
 
 void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,