summaryrefslogtreecommitdiff
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2020-02-17 06:00:22 +0300
committerDavid S. Miller <davem@davemloft.net>2020-02-17 06:00:22 +0300
commitddb535a6a04edf4b9053956ab3adc4f4eb7f945c (patch)
tree72e3fcea2abe9d37bd81f397dd58f2567c409ace /net/mac80211/mlme.c
parent1e5946f5f7fe9267c71097a83615a6e5eb0f4cfd (diff)
parent1f6e0baa703d31002c312c3e423c108b04325df0 (diff)
downloadlinux-ddb535a6a04edf4b9053956ab3adc4f4eb7f945c.tar.xz
Merge tag 'mac80211-next-for-net-next-2020-02-14' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says: ==================== A few big new things: * 802.11 frame encapsulation offload support * more HE (802.11ax) support, including some for 6 GHz band * powersave in hwsim, for better testing Of course as usual there are various cleanups and small fixes. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c139
1 files changed, 93 insertions, 46 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e041af2f021a..9ab0842a7c37 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -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);
@@ -3368,9 +3395,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,
@@ -3649,13 +3683,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;
@@ -4753,10 +4802,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);
@@ -4773,8 +4834,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,
@@ -4784,9 +4844,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);
@@ -4796,9 +4857,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;
@@ -5297,27 +5355,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));
@@ -5449,6 +5495,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)