diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 18a101710432..339faa7a0a0e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1898,6 +1898,15 @@ struct ieee802_11_elems { struct ieee80211_mle_per_sta_profile *prof; size_t sta_prof_len; + /* + * When parsing the beacon with MBSSID (from a transmitted BSS), this + * indicates that the profile the parser was instructed to look for + * (via the bss value in &struct ieee80211_elems_parse_params) couldn't + * be found (due to EMA, or perhaps broken AP) and the result cannot be + * considered complete. + */ + bool mbssid_nontx_profile_missing; + /* whether/which parse error occurred while retrieving these elements */ u8 parse_error; }; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f55cb376cbd5..2888a382677d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -7666,8 +7666,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, struct link_sta_info *link_sta; struct sta_info *sta; u64 changed = 0; - bool erp_valid; - u8 erp_value = 0; u32 ncrc = 0; u8 *bssid, *variable = mgmt->u.beacon.variable; u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; @@ -7788,6 +7786,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, if (!elems) return; + /* + * Note: with MBSSID and an EMA (or broken) AP, we could fail to find + * the correct multi-BSSID profile for the non-transmitting AP we're + * connected to. The result's elems->mbssid_nontx_profile_missing is + * indicating that, but some things must happen regardless. + */ + if (rx_status->flag & RX_FLAG_DECRYPTED && ieee80211_mgd_ssid_mismatch(sdata, elems)) { sdata_info(sdata, "SSID mismatch for AP %pM, disconnect\n", @@ -7823,6 +7828,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, } } + /* + * P2P will almost certainly not have MBSSID, but this just + * assumes that it would at least always inherit NoA anyway + * since it's absent from the channel. + */ if (sdata->vif.p2p || sdata->vif.driver_flags & IEEE80211_VIF_GET_NOA_UPDATE) { struct ieee80211_p2p_noa_attr noa = {}; @@ -7880,23 +7890,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, ieee80211_rx_bss_info(link, mgmt, len, rx_status); + /* + * This assumes that all members of a multiple BSS set must be + * switching together, so we can parse channel switch elements + * from the transmitted BSS even if our non-transmitted one is + * not present in this beacon (due to EMA.) + */ ieee80211_sta_process_chanswitch(link, rx_status->mactime, rx_status->device_timestamp, elems, elems, IEEE80211_CSA_SOURCE_BEACON); - /* note that after this elems->ml_basic can no longer be used fully */ - ieee80211_mgd_check_cross_link_csa(sdata, rx_status->link_id, elems); - - ieee80211_mgd_update_bss_param_ch_cnt(sdata, bss_conf, elems); - - if (!sdata->u.mgd.epcs.enabled && - !link->u.mgd.disable_wmm_tracking && - ieee80211_sta_wmm_params(local, link, elems->wmm_param, - elems->wmm_param_len, - elems->mu_edca_param_set)) - changed |= BSS_CHANGED_QOS; - /* * If we haven't had a beacon before, tell the driver about the * DTIM period (and beacon timing if desired) now. @@ -7913,17 +7917,53 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, ieee80211_recalc_ps_vif(sdata); } - if (elems->erp_info) { - erp_valid = true; - erp_value = elems->erp_info[0]; - } else { - erp_valid = false; - } + /* RNR isn't inside an MBSSID profile */ + ieee80211_mgd_update_bss_param_ch_cnt(sdata, bss_conf, elems); + + /* assume ERP would be inherited anyway */ + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) { + u8 erp_value = 0; + bool erp_valid; + + if (elems->erp_info) { + erp_valid = true; + erp_value = elems->erp_info[0]; + } else { + erp_valid = false; + } - if (!ieee80211_is_s1g_beacon(hdr->frame_control)) changed |= ieee80211_handle_bss_capability(link, le16_to_cpu(mgmt->u.beacon.capab_info), erp_valid, erp_value); + } + + /* + * There are some other things that we can only do when the + * real non-transmitted profile was actually parsed, so exit + * here before doing those. + */ + if (elems->mbssid_nontx_profile_missing) + goto apply; + + /* + * This requires multi-link element, which is from the MBSSID profile. + * Note that after this elems->ml_basic can no longer be used fully. + * + * Note also that currently the parsing is incorrect, so this will + * never actually do anything. + */ + ieee80211_mgd_check_cross_link_csa(sdata, rx_status->link_id, elems); + + /* + * EDCA parameters should be the same, but perhaps ACM can differ + * between BSSes in an MBSSID set. + */ + if (!sdata->u.mgd.epcs.enabled && + !link->u.mgd.disable_wmm_tracking && + ieee80211_sta_wmm_params(local, link, elems->wmm_param, + elems->wmm_param_len, + elems->mu_edca_param_set)) + changed |= BSS_CHANGED_QOS; sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); if (WARN_ON(!sta)) { @@ -7969,6 +8009,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, ieee80211_process_adv_ttlm(sdata, elems, le64_to_cpu(mgmt->u.beacon.timestamp)); +apply: ieee80211_link_info_change_notify(sdata, link, changed); free: kfree(elems); diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 2587284fa67b..c7d882ccc4c6 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -1109,6 +1109,10 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) sub.type = params->type; sub.link_id = params->link_id; + /* indicate to consumer whether or not profile was found */ + if (params->bss->transmitted_bss && !nontx_len) + elems->mbssid_nontx_profile_missing = true; + /* consume the space used for non-transmitted profile */ elems_parse->scratch_pos += nontx_len;