wifi: mac80211: Don't finalize CSA in IBSS mode if state is disconnected
[platform/kernel/linux-rpi.git] / net / mac80211 / mlme.c
index c0ea3b1..1548f53 100644 (file)
@@ -37,6 +37,7 @@
 #define IEEE80211_AUTH_TIMEOUT_SAE     (HZ * 2)
 #define IEEE80211_AUTH_MAX_TRIES       3
 #define IEEE80211_AUTH_WAIT_ASSOC      (HZ * 5)
+#define IEEE80211_AUTH_WAIT_SAE_RETRY  (HZ * 2)
 #define IEEE80211_ASSOC_TIMEOUT                (HZ / 5)
 #define IEEE80211_ASSOC_TIMEOUT_LONG   (HZ / 2)
 #define IEEE80211_ASSOC_TIMEOUT_SHORT  (HZ / 10)
@@ -629,7 +630,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
                                struct sk_buff *skb,
                                struct ieee80211_supported_band *sband)
 {
-       u8 *pos;
+       u8 *pos, *pre_he_pos;
        const struct ieee80211_sta_he_cap *he_cap = NULL;
        struct ieee80211_chanctx_conf *chanctx_conf;
        u8 he_cap_size;
@@ -646,25 +647,26 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
 
        he_cap = ieee80211_get_he_iftype_cap(sband,
                                             ieee80211_vif_type_p2p(&sdata->vif));
-       if (!he_cap || !reg_cap)
+       if (!he_cap || !chanctx_conf || !reg_cap)
                return;
 
-       /*
-        * TODO: the 1 added is because this temporarily is under the EXTENSION
-        * IE. Get rid of it when it moves.
-        */
+       /* get a max size estimate */
        he_cap_size =
                2 + 1 + sizeof(he_cap->he_cap_elem) +
                ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem) +
                ieee80211_he_ppe_size(he_cap->ppe_thres[0],
                                      he_cap->he_cap_elem.phy_cap_info);
        pos = skb_put(skb, he_cap_size);
-       ieee80211_ie_build_he_cap(pos, he_cap, pos + he_cap_size);
+       pre_he_pos = pos;
+       pos = ieee80211_ie_build_he_cap(sdata->u.mgd.flags,
+                                       pos, he_cap, pos + he_cap_size);
+       /* trim excess if any */
+       skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos));
 
        ieee80211_ie_build_he_6ghz_cap(sdata, skb);
 }
 
-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
+static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -684,6 +686,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
        const struct ieee80211_sband_iftype_data *iftd;
        struct ieee80211_prep_tx_info info = {};
+       int ret;
 
        /* we know it's writable, cast away the const */
        if (assoc_data->ie_len)
@@ -697,7 +700,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        if (WARN_ON(!chanctx_conf)) {
                rcu_read_unlock();
-               return;
+               return -EINVAL;
        }
        chan = chanctx_conf->def.chan;
        rcu_read_unlock();
@@ -748,7 +751,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                        (iftd ? iftd->vendor_elems.len : 0),
                        GFP_KERNEL);
        if (!skb)
-               return;
+               return -ENOMEM;
 
        skb_reserve(skb, local->hw.extra_tx_headroom);
 
@@ -1029,15 +1032,22 @@ skip_rates:
                skb_put_data(skb, assoc_data->ie + offset, noffset - offset);
        }
 
-       if (assoc_data->fils_kek_len &&
-           fils_encrypt_assoc_req(skb, assoc_data) < 0) {
-               dev_kfree_skb(skb);
-               return;
+       if (assoc_data->fils_kek_len) {
+               ret = fils_encrypt_assoc_req(skb, assoc_data);
+               if (ret < 0) {
+                       dev_kfree_skb(skb);
+                       return ret;
+               }
        }
 
        pos = skb_tail_pointer(skb);
        kfree(ifmgd->assoc_req_ies);
        ifmgd->assoc_req_ies = kmemdup(ie_start, pos - ie_start, GFP_ATOMIC);
+       if (!ifmgd->assoc_req_ies) {
+               dev_kfree_skb(skb);
+               return -ENOMEM;
+       }
+
        ifmgd->assoc_req_ies_len = pos - ie_start;
 
        drv_mgd_prepare_tx(local, sdata, &info);
@@ -1047,6 +1057,8 @@ skip_rates:
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
                                                IEEE80211_TX_INTFL_MLME_CONN_TX;
        ieee80211_tx_skb(sdata, skb);
+
+       return 0;
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -2446,11 +2458,18 @@ static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata,
                                           u16 tx_time)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       u16 tid = ieee80211_get_tid(hdr);
-       int ac = ieee80211_ac_from_tid(tid);
-       struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
+       u16 tid;
+       int ac;
+       struct ieee80211_sta_tx_tspec *tx_tspec;
        unsigned long now = jiffies;
 
+       if (!ieee80211_is_data_qos(hdr->frame_control))
+               return;
+
+       tid = ieee80211_get_tid(hdr);
+       ac = ieee80211_ac_from_tid(tid);
+       tx_tspec = &ifmgd->tx_tspec[ac];
+
        if (likely(!tx_tspec->admitted_time))
                return;
 
@@ -2977,8 +2996,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                    (status_code == WLAN_STATUS_ANTI_CLOG_REQUIRED ||
                     (auth_transaction == 1 &&
                      (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
-                      status_code == WLAN_STATUS_SAE_PK))))
+                      status_code == WLAN_STATUS_SAE_PK)))) {
+                       /* waiting for userspace now */
+                       ifmgd->auth_data->waiting = true;
+                       ifmgd->auth_data->timeout =
+                               jiffies + IEEE80211_AUTH_WAIT_SAE_RETRY;
+                       ifmgd->auth_data->timeout_started = true;
+                       run_again(sdata, ifmgd->auth_data->timeout);
                        goto notify_driver;
+               }
 
                sdata_info(sdata, "%pM denied authentication (status %d)\n",
                           mgmt->sa, status_code);
@@ -3515,6 +3541,12 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
                                cbss->transmitted_bss->bssid);
                bss_conf->bssid_indicator = cbss->max_bssid_indicator;
                bss_conf->bssid_index = cbss->bssid_index;
+       } else {
+               bss_conf->nontransmitted = false;
+               memset(bss_conf->transmitter_bssid, 0,
+                      sizeof(bss_conf->transmitter_bssid));
+               bss_conf->bssid_indicator = 0;
+               bss_conf->bssid_index = 0;
        }
 
        /*
@@ -4444,6 +4476,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;
+       int ret;
 
        sdata_assert_lock(sdata);
 
@@ -4464,7 +4497,9 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
        sdata_info(sdata, "associate with %pM (try %d/%d)\n",
                   assoc_data->bss->bssid, assoc_data->tries,
                   IEEE80211_ASSOC_MAX_TRIES);
-       ieee80211_send_assoc(sdata);
+       ret = ieee80211_send_assoc(sdata);
+       if (ret)
+               return ret;
 
        if (!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
                assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
@@ -4537,10 +4572,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
 
        if (ifmgd->auth_data && ifmgd->auth_data->timeout_started &&
            time_after(jiffies, ifmgd->auth_data->timeout)) {
-               if (ifmgd->auth_data->done) {
+               if (ifmgd->auth_data->done || ifmgd->auth_data->waiting) {
                        /*
-                        * ok ... we waited for assoc but userspace didn't,
-                        * so let's just kill the auth data
+                        * ok ... we waited for assoc or continuation but
+                        * userspace didn't do it, so kill the auth data
                         */
                        ieee80211_destroy_auth_data(sdata, false);
                } else if (ieee80211_auth(sdata)) {
@@ -5209,7 +5244,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
         */
        if (new_sta) {
                u32 rates = 0, basic_rates = 0;
-               bool have_higher_than_11mbit;
+               bool have_higher_than_11mbit = false;
                int min_rate = INT_MAX, min_rate_index = -1;
                const struct cfg80211_bss_ies *ies;
                int shift = ieee80211_vif_get_shift(&sdata->vif);