From: Johannes Berg For UHR AIDs 56-63 are reserved, for EHT 2007, and for any multi-BSSID the lower values whose bits are used for the multicast indications. Check for these issues, log a message, and disconnect in strict mode. Since this isn't affected by the connection mode, it requires tracking the AP mode while parsing elements. Reviewed-by: Miriam Rachel Korenblit Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/mlme.c | 28 ++++++++++++++++++++++++++++ net/mac80211/parse.c | 20 ++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9906a62ee99c..6fd7f29349ab 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1851,6 +1851,9 @@ struct ieee802_11_elems { u8 frame_type; bool from_ap; + /* the AP mode, not restricted to the parse mode */ + enum ieee80211_conn_mode unrestricted_ap_mode; + /* pointers to IEs */ const struct ieee80211_tdls_lnkie *lnk_id; const struct ieee80211_ch_switch_timing *ch_sw_timing; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8eda8154ba3d..d918f7ca36e7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6175,6 +6175,34 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, goto out; } + /* AIDs 56-63 are reserved in UHR APs (Critical Update Type/Counter) */ + if (elems->unrestricted_ap_mode >= IEEE80211_CONN_MODE_UHR && + sdata->vif.cfg.aid >= 56 && sdata->vif.cfg.aid <= 63) { + link_info(link, "UHR AP %pM assigned AID %d, expect PS issues\n", + link->u.mgd.bssid, sdata->vif.cfg.aid); + if (ieee80211_hw_check(&sdata->local->hw, STRICT)) { + ret = false; + goto out; + } + } else if (elems->unrestricted_ap_mode >= IEEE80211_CONN_MODE_EHT && + sdata->vif.cfg.aid == 2007) { + link_info(link, "EHT AP %pM assigned AID 2007, expect trigger issues\n", + link->u.mgd.bssid); + if (ieee80211_hw_check(&sdata->local->hw, STRICT)) { + ret = false; + goto out; + } + } else if (sdata->vif.cfg.aid && + sdata->vif.cfg.aid < (1 << cbss->max_bssid_indicator)) { + link_info(link, "multi-BSSID AP %pM with MaxBSSID %d assigned AID %d, expect PS issues\n", + link->u.mgd.bssid, cbss->max_bssid_indicator, + sdata->vif.cfg.aid); + if (ieee80211_hw_check(&sdata->local->hw, STRICT)) { + ret = false; + goto out; + } + } + /* check/update if AP changed anything in assoc response vs. scan */ if (ieee80211_config_bw(link, elems, link_id == assoc_data->assoc_link_id, diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 22bba5adef26..debc0dcd3bdf 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -69,6 +69,12 @@ struct ieee80211_elems_parse { u8 scratch[] __counted_by(scratch_len); }; +static void ieee80211_update_unr_ap_mode(struct ieee802_11_elems *elems, + enum ieee80211_conn_mode mode) +{ + elems->unrestricted_ap_mode = max(mode, elems->unrestricted_ap_mode); +} + static void ieee80211_parse_extension_element(u32 *crc, const struct element *elem, @@ -94,6 +100,7 @@ ieee80211_parse_extension_element(u32 *crc, elems->mu_edca_param_set = data; break; case WLAN_EID_EXT_HE_CAPABILITY: + ieee80211_update_unr_ap_mode(elems, IEEE80211_CONN_MODE_HE); if (params->mode < IEEE80211_CONN_MODE_HE) break; if (ieee80211_he_capa_size_ok(data, len)) { @@ -102,6 +109,7 @@ ieee80211_parse_extension_element(u32 *crc, } break; case WLAN_EID_EXT_HE_OPERATION: + ieee80211_update_unr_ap_mode(elems, IEEE80211_CONN_MODE_HE); if (params->mode < IEEE80211_CONN_MODE_HE) break; calc_crc = true; @@ -137,6 +145,7 @@ ieee80211_parse_extension_element(u32 *crc, elems->he_6ghz_capa = data; break; case WLAN_EID_EXT_EHT_CAPABILITY: + ieee80211_update_unr_ap_mode(elems, IEEE80211_CONN_MODE_EHT); if (params->mode < IEEE80211_CONN_MODE_EHT) break; if (ieee80211_eht_capa_size_ok(elems->he_cap, @@ -147,6 +156,7 @@ ieee80211_parse_extension_element(u32 *crc, } break; case WLAN_EID_EXT_EHT_OPERATION: + ieee80211_update_unr_ap_mode(elems, IEEE80211_CONN_MODE_EHT); if (params->mode < IEEE80211_CONN_MODE_EHT) break; if (ieee80211_eht_oper_size_ok(data, len)) @@ -211,6 +221,7 @@ ieee80211_parse_extension_element(u32 *crc, elems->cip_cap = data; break; case WLAN_EID_EXT_UHR_OPER: + ieee80211_update_unr_ap_mode(elems, IEEE80211_CONN_MODE_UHR); if (params->mode < IEEE80211_CONN_MODE_UHR) break; calc_crc = true; @@ -220,6 +231,7 @@ ieee80211_parse_extension_element(u32 *crc, } break; case WLAN_EID_EXT_UHR_CAPA: + ieee80211_update_unr_ap_mode(elems, IEEE80211_CONN_MODE_UHR); if (params->mode < IEEE80211_CONN_MODE_UHR) break; calc_crc = true; @@ -507,6 +519,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elems->ext_supp_rates_len = elen; break; case WLAN_EID_HT_CAPABILITY: + ieee80211_update_unr_ap_mode(elems, + IEEE80211_CONN_MODE_HT); if (params->mode < IEEE80211_CONN_MODE_HT) break; if (elen >= sizeof(struct ieee80211_ht_cap)) @@ -516,6 +530,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_HT_OPERATION: + ieee80211_update_unr_ap_mode(elems, + IEEE80211_CONN_MODE_HT); if (params->mode < IEEE80211_CONN_MODE_HT) break; if (elen >= sizeof(struct ieee80211_ht_operation)) @@ -525,6 +541,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_VHT_CAPABILITY: + ieee80211_update_unr_ap_mode(elems, + IEEE80211_CONN_MODE_VHT); if (params->mode < IEEE80211_CONN_MODE_VHT) break; if (elen >= sizeof(struct ieee80211_vht_cap)) @@ -534,6 +552,8 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_VHT_OPERATION: + ieee80211_update_unr_ap_mode(elems, + IEEE80211_CONN_MODE_VHT); if (params->mode < IEEE80211_CONN_MODE_VHT) break; if (elen >= sizeof(struct ieee80211_vht_operation)) { -- 2.56.0