Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[linux-2.6-block.git] / net / mac80211 / mlme.c
index 3dbecae4be73cb1aae05752807b717a329b80980..d2bc8d57c87eb40b943873732e5705514fcd2fc2 100644 (file)
@@ -220,7 +220,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
                memcpy(&he_oper_vht_cap, he_oper->optional, 3);
                he_oper_vht_cap.basic_mcs_set = cpu_to_le16(0);
 
-               if (!ieee80211_chandef_vht_oper(&he_oper_vht_cap,
+               if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
+                                               &he_oper_vht_cap, ht_oper,
                                                &vht_chandef)) {
                        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
                                sdata_info(sdata,
@@ -228,7 +229,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
                        ret = IEEE80211_STA_DISABLE_HE;
                        goto out;
                }
-       } else if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
+       } else if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_oper,
+                                              ht_oper, &vht_chandef)) {
                if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
                        sdata_info(sdata,
                                   "AP VHT information is invalid, disable VHT\n");
@@ -2759,13 +2761,40 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
                            auth_data->key_idx, tx_flags);
 }
 
+static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata,
+                                   const u8 *bssid)
+{
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct sta_info *sta;
+
+       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(sdata, ifmgd->auth_data->timeout);
+
+       /* move station state to auth */
+       mutex_lock(&sdata->local->sta_mtx);
+       sta = sta_info_get(sdata, bssid);
+       if (!sta) {
+               WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid);
+               return false;
+       }
+       if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) {
+               sdata_info(sdata, "failed moving %pM to auth\n", bssid);
+               return false;
+       }
+       mutex_unlock(&sdata->local->sta_mtx);
+
+       return true;
+}
+
 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;
        struct ieee80211_event event = {
                .type = MLME_EVENT,
                .u.mlme.data = AUTH_EVENT,
@@ -2789,7 +2818,11 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
        status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
        if (auth_alg != ifmgd->auth_data->algorithm ||
-           auth_transaction != ifmgd->auth_data->expected_transaction) {
+           (auth_alg != WLAN_AUTH_SAE &&
+            auth_transaction != ifmgd->auth_data->expected_transaction) ||
+           (auth_alg == WLAN_AUTH_SAE &&
+            (auth_transaction < ifmgd->auth_data->expected_transaction ||
+             auth_transaction > 2))) {
                sdata_info(sdata, "%pM unexpected authentication state: alg %d (expected %d) transact %d (expected %d)\n",
                           mgmt->sa, auth_alg, ifmgd->auth_data->algorithm,
                           auth_transaction,
@@ -2832,35 +2865,17 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
 
        event.u.mlme.status = MLME_SUCCESS;
        drv_event_callback(sdata->local, sdata, &event);
-       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(sdata, ifmgd->auth_data->timeout);
-
-       if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
-           ifmgd->auth_data->expected_transaction != 2) {
-               /*
-                * Report auth frame to user space for processing since another
-                * round of Authentication frames is still needed.
-                */
-               cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
-               return;
+       if (ifmgd->auth_data->algorithm != WLAN_AUTH_SAE ||
+           (auth_transaction == 2 &&
+            ifmgd->auth_data->expected_transaction == 2)) {
+               if (!ieee80211_mark_sta_auth(sdata, bssid))
+                       goto out_err;
+       } else if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
+                  auth_transaction == 2) {
+               sdata_info(sdata, "SAE peer confirmed\n");
+               ifmgd->auth_data->peer_confirmed = true;
        }
 
-       /* move station state to auth */
-       mutex_lock(&sdata->local->sta_mtx);
-       sta = sta_info_get(sdata, bssid);
-       if (!sta) {
-               WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid);
-               goto out_err;
-       }
-       if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) {
-               sdata_info(sdata, "failed moving %pM to auth\n", bssid);
-               goto out_err;
-       }
-       mutex_unlock(&sdata->local->sta_mtx);
-
        cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
        return;
  out_err:
@@ -3237,19 +3252,16 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        }
 
        if (bss_conf->he_support) {
-               u32 he_oper_params =
-                       le32_to_cpu(elems.he_operation->he_oper_params);
+               bss_conf->bss_color =
+                       le32_get_bits(elems.he_operation->he_oper_params,
+                                     IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
 
-               bss_conf->bss_color = he_oper_params &
-                                     IEEE80211_HE_OPERATION_BSS_COLOR_MASK;
                bss_conf->htc_trig_based_pkt_ext =
-                       (he_oper_params &
-                        IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK) <<
-                       IEEE80211_HE_OPERATION_DFLT_PE_DURATION_OFFSET;
+                       le32_get_bits(elems.he_operation->he_oper_params,
+                             IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK);
                bss_conf->frame_time_rts_th =
-                       (he_oper_params &
-                        IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK) <<
-                       IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET;
+                       le32_get_bits(elems.he_operation->he_oper_params,
+                             IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK);
 
                bss_conf->multi_sta_back_32bit =
                        sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
@@ -4879,6 +4891,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_mgd_auth_data *auth_data;
        u16 auth_alg;
        int err;
+       bool cont_auth;
 
        /* prepare auth data structure */
 
@@ -4913,6 +4926,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
                return -EOPNOTSUPP;
        }
 
+       if (ifmgd->assoc_data)
+               return -EBUSY;
+
        auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len +
                            req->ie_len, GFP_KERNEL);
        if (!auth_data)
@@ -4932,6 +4948,13 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
                auth_data->data_len += req->auth_data_len - 4;
        }
 
+       /* Check if continuing authentication or trying to authenticate with the
+        * same BSS that we were in the process of authenticating with and avoid
+        * removal and re-addition of the STA entry in
+        * ieee80211_prep_connection().
+        */
+       cont_auth = ifmgd->auth_data && req->bss == ifmgd->auth_data->bss;
+
        if (req->ie && req->ie_len) {
                memcpy(&auth_data->data[auth_data->data_len],
                       req->ie, req->ie_len);
@@ -4948,18 +4971,26 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 
        /* try to authenticate/probe */
 
-       if ((ifmgd->auth_data && !ifmgd->auth_data->done) ||
-           ifmgd->assoc_data) {
-               err = -EBUSY;
-               goto err_free;
+       if (ifmgd->auth_data) {
+               if (cont_auth && req->auth_type == NL80211_AUTHTYPE_SAE) {
+                       auth_data->peer_confirmed =
+                               ifmgd->auth_data->peer_confirmed;
+               }
+               ieee80211_destroy_auth_data(sdata, cont_auth);
        }
 
-       if (ifmgd->auth_data)
-               ieee80211_destroy_auth_data(sdata, false);
-
        /* prep auth_data so we don't go into idle on disassoc */
        ifmgd->auth_data = auth_data;
 
+       /* If this is continuation of an ongoing SAE authentication exchange
+        * (i.e., request to send SAE Confirm) and the peer has already
+        * confirmed, mark authentication completed since we are about to send
+        * out SAE Confirm.
+        */
+       if (cont_auth && req->auth_type == NL80211_AUTHTYPE_SAE &&
+           auth_data->peer_confirmed && auth_data->sae_trans == 2)
+               ieee80211_mark_sta_auth(sdata, req->bss->bssid);
+
        if (ifmgd->associated) {
                u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
 
@@ -4977,7 +5008,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 
        sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
 
-       err = ieee80211_prep_connection(sdata, req->bss, false, false);
+       err = ieee80211_prep_connection(sdata, req->bss, cont_auth, false);
        if (err)
                goto err_clear;
 
@@ -4998,7 +5029,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        mutex_lock(&sdata->local->mtx);
        ieee80211_vif_release_channel(sdata);
        mutex_unlock(&sdata->local->mtx);
- err_free:
        kfree(auth_data);
        return err;
 }