mac80211: handle no-preauth flag for control port
[sfrench/cifs-2.6.git] / net / mac80211 / mlme.c
index 88d7a692a9658137f06128c7a7c98b2a358d12b2..16d75da0996a1636d496d85636a76ec2b29d567b 100644 (file)
@@ -164,7 +164,9 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        chandef->center_freq1 = channel->center_freq;
 
        if (!ht_oper || !sta_ht_cap.ht_supported) {
-               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+               ret = IEEE80211_STA_DISABLE_HT |
+                     IEEE80211_STA_DISABLE_VHT |
+                     IEEE80211_STA_DISABLE_HE;
                goto out;
        }
 
@@ -185,7 +187,9 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
                           "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
                           channel->center_freq, ht_cfreq,
                           ht_oper->primary_chan, channel->band);
-               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+               ret = IEEE80211_STA_DISABLE_HT |
+                     IEEE80211_STA_DISABLE_VHT |
+                     IEEE80211_STA_DISABLE_HE;
                goto out;
        }
 
@@ -301,13 +305,18 @@ out:
                                                   IEEE80211_CHAN_DISABLED)) {
                if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) {
                        ret = IEEE80211_STA_DISABLE_HT |
-                             IEEE80211_STA_DISABLE_VHT;
+                             IEEE80211_STA_DISABLE_VHT |
+                             IEEE80211_STA_DISABLE_HE;
                        break;
                }
 
                ret |= ieee80211_chandef_downgrade(chandef);
        }
 
+       if (!he_oper || !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef,
+                                                IEEE80211_CHAN_NO_HE))
+               ret |= IEEE80211_STA_DISABLE_HE;
+
        if (chandef->width != vht_chandef.width && !tracking)
                sdata_info(sdata,
                           "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
@@ -393,6 +402,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
 
        if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
                                      IEEE80211_STA_DISABLE_VHT |
+                                     IEEE80211_STA_DISABLE_HE |
                                      IEEE80211_STA_DISABLE_40MHZ |
                                      IEEE80211_STA_DISABLE_80P80MHZ |
                                      IEEE80211_STA_DISABLE_160MHZ)) ||
@@ -616,10 +626,21 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
 {
        u8 *pos;
        const struct ieee80211_sta_he_cap *he_cap = NULL;
+       struct ieee80211_chanctx_conf *chanctx_conf;
        u8 he_cap_size;
+       bool reg_cap = false;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (!WARN_ON_ONCE(!chanctx_conf))
+               reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy,
+                                                 &chanctx_conf->def,
+                                                 IEEE80211_CHAN_NO_HE);
+
+       rcu_read_unlock();
 
        he_cap = ieee80211_get_he_sta_cap(sband);
-       if (!he_cap)
+       if (!he_cap || !reg_cap)
                return;
 
        /*
@@ -650,6 +671,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_channel *chan;
        u32 rates = 0;
+       struct element *ext_capa = NULL;
+
+       /* we know it's writable, cast away the const */
+       if (assoc_data->ie_len)
+               ext_capa = (void *)cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
+                                                     assoc_data->ie,
+                                                     assoc_data->ie_len);
 
        sdata_assert_lock(sdata);
 
@@ -800,7 +828,15 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                *pos++ = ieee80211_chandef_max_power(&chanctx_conf->def);
        }
 
-       if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
+       /*
+        * Per spec, we shouldn't include the list of channels if we advertise
+        * support for extended channel switching, but we've always done that;
+        * (for now?) apply this restriction only on the (new) 6 GHz band.
+        */
+       if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT &&
+           (sband->band != NL80211_BAND_6GHZ ||
+            !ext_capa || ext_capa->datalen < 1 ||
+            !(ext_capa->data[0] & WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING))) {
                /* TODO: get this in reg domain format */
                pos = skb_put(skb, 2 * sband->n_channels + 2);
                *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
@@ -814,18 +850,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 
        /* Set MBSSID support for HE AP if needed */
        if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) &&
-           !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && assoc_data->ie_len) {
-               struct element *elem;
-
-               /* we know it's writable, cast away the const */
-               elem = (void *)cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
-                                                 assoc_data->ie,
-                                                 assoc_data->ie_len);
-
-               /* We can probably assume both always true */
-               if (elem && elem->datalen >= 3)
-                       elem->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
-       }
+           !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && assoc_data->ie_len &&
+           ext_capa && ext_capa->datalen >= 3)
+               ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
 
        /* if present, add any custom IEs that go before HT */
        if (assoc_data->ie_len) {
@@ -2460,7 +2487,7 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
        if (!ieee80211_is_data(hdr->frame_control))
            return;
 
-       if (ieee80211_is_nullfunc(hdr->frame_control) &&
+       if (ieee80211_is_any_nullfunc(hdr->frame_control) &&
            sdata->u.mgd.probe_send_count > 0) {
                if (ack)
                        ieee80211_sta_reset_conn_monitor(sdata);
@@ -3364,9 +3391,16 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        }
 
        if (bss_conf->he_support) {
-               bss_conf->bss_color =
+               bss_conf->he_bss_color.color =
                        le32_get_bits(elems->he_operation->he_oper_params,
                                      IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
+               bss_conf->he_bss_color.partial =
+                       le32_get_bits(elems->he_operation->he_oper_params,
+                                     IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR);
+               bss_conf->he_bss_color.disabled =
+                       le32_get_bits(elems->he_operation->he_oper_params,
+                                     IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED);
+               changed |= BSS_CHANGED_HE_BSS_COLOR;
 
                bss_conf->htc_trig_based_pkt_ext =
                        le32_get_bits(elems->he_operation->he_oper_params,
@@ -3645,13 +3679,28 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_mgmt *mgmt = (void *)skb->data;
        struct ieee80211_if_managed *ifmgd;
        struct ieee80211_rx_status *rx_status = (void *) skb->cb;
+       struct ieee80211_channel *channel;
        size_t baselen, len = skb->len;
 
        ifmgd = &sdata->u.mgd;
 
        sdata_assert_lock(sdata);
 
-       if (!ether_addr_equal(mgmt->da, sdata->vif.addr))
+       /*
+        * According to Draft P802.11ax D6.0 clause 26.17.2.3.2:
+        * "If a 6 GHz AP receives a Probe Request frame  and responds with
+        * a Probe Response frame [..], the Address 1 field of the Probe
+        * Response frame shall be set to the broadcast address [..]"
+        * So, on 6GHz band we should also accept broadcast responses.
+        */
+       channel = ieee80211_get_channel(sdata->local->hw.wiphy,
+                                       rx_status->freq);
+       if (!channel)
+               return;
+
+       if (!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
+           (channel->band != NL80211_BAND_6GHZ ||
+            !is_broadcast_ether_addr(mgmt->da)))
                return; /* ignore ProbeResp to foreign address */
 
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
@@ -4749,10 +4798,22 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                          IEEE80211_STA_DISABLE_80P80MHZ |
                          IEEE80211_STA_DISABLE_160MHZ);
 
+       /* disable HT/VHT/HE if we don't support them */
+       if (!sband->ht_cap.ht_supported) {
+               ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
+               ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+               ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
+       }
+
+       if (!sband->vht_cap.vht_supported)
+               ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+
+       if (!ieee80211_get_he_sta_cap(sband))
+               ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
+
        rcu_read_lock();
 
-       if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
-           sband->ht_cap.ht_supported) {
+       if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
                const u8 *ht_oper_ie, *ht_cap_ie;
 
                ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION);
@@ -4769,8 +4830,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
-           sband->vht_cap.vht_supported) {
+       if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
                const u8 *vht_oper_ie, *vht_cap;
 
                vht_oper_ie = ieee80211_bss_get_ie(cbss,
@@ -4780,9 +4840,10 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                if (vht_oper && !ht_oper) {
                        vht_oper = NULL;
                        sdata_info(sdata,
-                                  "AP advertised VHT without HT, disabling both\n");
+                                  "AP advertised VHT without HT, disabling HT/VHT/HE\n");
                        ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
                        ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+                       ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
                }
 
                vht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY);
@@ -4792,9 +4853,6 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       if (!ieee80211_get_he_sta_cap(sband))
-               ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
-
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) {
                const struct cfg80211_bss_ies *ies;
                const u8 *he_oper_ie;
@@ -5293,27 +5351,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       /* Also disable HT if we don't support it or the AP doesn't use WMM */
        sband = local->hw.wiphy->bands[req->bss->channel->band];
-       if (!sband->ht_cap.ht_supported ||
-           local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used ||
-           ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
-               ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
-               if (!bss->wmm_used &&
-                   !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM))
-                       netdev_info(sdata->dev,
-                                   "disabling HT as WMM/QoS is not supported by the AP\n");
-       }
 
-       /* disable VHT if we don't support it or the AP doesn't use WMM */
-       if (!sband->vht_cap.vht_supported ||
-           local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used ||
-           ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
+       /* also disable HT/VHT/HE if the AP doesn't use WMM */
+       if (!bss->wmm_used) {
+               ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
                ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
-               if (!bss->wmm_used &&
-                   !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM))
-                       netdev_info(sdata->dev,
-                                   "disabling VHT as WMM/QoS is not supported by the AP\n");
+               ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
+               netdev_info(sdata->dev,
+                           "disabling HT/VHT/HE as WMM/QoS is not supported by the AP\n");
        }
 
        memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
@@ -5412,6 +5458,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
        sdata->control_port_over_nl80211 =
                                        req->crypto.control_port_over_nl80211;
+       sdata->control_port_no_preauth = req->crypto.control_port_no_preauth;
        sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto,
                                                        sdata->vif.type);
 
@@ -5445,6 +5492,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        if (req->flags & ASSOC_REQ_DISABLE_HT) {
                ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
                ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+               ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
        }
 
        if (req->flags & ASSOC_REQ_DISABLE_VHT)