From 1845c1d4a455e000dbf66dc4126c98837ac3e528 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Jul 2022 15:21:23 +0200 Subject: [PATCH] wifi: mac80211: mlme: refactor assoc link setup Factor out the code to set up the assoc link into a new function ieee80211_setup_assoc_link(). While at it, also modify the 'override' handling to just take into account whether or not the conn_flags were changed, which is what we need to setup again the channel later. Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 286 ++++++++++++++++++++++++-------------------- 1 file changed, 156 insertions(+), 130 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 326572b80ed8..292ad46daa9d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6145,22 +6145,138 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, return err; } +static ieee80211_conn_flags_t +ieee80211_setup_assoc_link(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_assoc_data *assoc_data, + struct cfg80211_assoc_request *req, + ieee80211_conn_flags_t conn_flags) +{ + struct ieee80211_local *local = sdata->local; + const struct cfg80211_bss_ies *beacon_ies; + struct ieee80211_supported_band *sband; + const struct element *ht_elem, *vht_elem; + struct ieee80211_link_data *link = &sdata->deflink; + struct cfg80211_bss *cbss = req->bss; + struct ieee80211_bss *bss = (void *)cbss->priv; + bool is_5ghz, is_6ghz; + + sband = local->hw.wiphy->bands[cbss->channel->band]; + if (WARN_ON(!sband)) + return false; + + is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ; + is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; + + assoc_data->supp_rates = bss->supp_rates; + assoc_data->supp_rates_len = bss->supp_rates_len; + + rcu_read_lock(); + ht_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_HT_OPERATION); + if (ht_elem && ht_elem->datalen >= sizeof(struct ieee80211_ht_operation)) + assoc_data->ap_ht_param = + ((struct ieee80211_ht_operation *)(ht_elem->data))->ht_param; + else if (!is_6ghz) + conn_flags |= IEEE80211_CONN_DISABLE_HT; + vht_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_VHT_CAPABILITY); + if (vht_elem && vht_elem->datalen >= sizeof(struct ieee80211_vht_cap)) { + memcpy(&assoc_data->ap_vht_cap, vht_elem->data, + sizeof(struct ieee80211_vht_cap)); + } else if (is_5ghz) { + link_info(link, + "VHT capa missing/short, disabling VHT/HE/EHT\n"); + conn_flags |= IEEE80211_CONN_DISABLE_VHT | + IEEE80211_CONN_DISABLE_HE | + IEEE80211_CONN_DISABLE_EHT; + } + rcu_read_unlock(); + + link->u.mgd.beacon_crc_valid = false; + link->u.mgd.dtim_period = 0; + link->u.mgd.have_beacon = false; + + /* override HT/VHT configuration only if the AP and we support it */ + if (!(conn_flags & IEEE80211_CONN_DISABLE_HT)) { + struct ieee80211_sta_ht_cap sta_ht_cap; + + memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); + ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); + } + + rcu_read_lock(); + beacon_ies = rcu_dereference(cbss->beacon_ies); + if (beacon_ies) { + const struct element *elem; + u8 dtim_count = 0; + + ieee80211_get_dtim(beacon_ies, &dtim_count, + &link->u.mgd.dtim_period); + + sdata->deflink.u.mgd.have_beacon = true; + + if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { + link->conf->sync_tsf = beacon_ies->tsf; + link->conf->sync_device_ts = bss->device_ts_beacon; + link->conf->sync_dtim_count = dtim_count; + } + + elem = cfg80211_find_ext_elem(WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION, + beacon_ies->data, beacon_ies->len); + if (elem && elem->datalen >= 3) + link->conf->profile_periodicity = elem->data[2]; + else + link->conf->profile_periodicity = 0; + + elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, + beacon_ies->data, beacon_ies->len); + if (elem && elem->datalen >= 11 && + (elem->data[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) + link->conf->ema_ap = true; + else + link->conf->ema_ap = false; + } + rcu_read_unlock(); + + if (bss->corrupt_data) { + char *corrupt_type = "data"; + + if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_BEACON) { + if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP) + corrupt_type = "beacon and probe response"; + else + corrupt_type = "beacon"; + } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP) { + corrupt_type = "probe response"; + } + sdata_info(sdata, "associating to AP %pM with corrupt %s\n", + cbss->bssid, corrupt_type); + } + + if (link->u.mgd.req_smps == IEEE80211_SMPS_AUTOMATIC) { + if (sdata->u.mgd.powersave) + link->smps_mode = IEEE80211_SMPS_DYNAMIC; + else + link->smps_mode = IEEE80211_SMPS_OFF; + } else { + link->smps_mode = link->u.mgd.req_smps; + } + + return conn_flags; +} + int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req) { - bool is_6ghz = req->bss->channel->band == NL80211_BAND_6GHZ; - bool is_5ghz = req->bss->channel->band == NL80211_BAND_5GHZ; struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss *bss = (void *)req->bss->priv; struct ieee80211_mgd_assoc_data *assoc_data; const struct cfg80211_bss_ies *beacon_ies; - struct ieee80211_supported_band *sband; struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; - const struct element *ssid_elem, *ht_elem, *vht_elem; + const struct element *ssid_elem; struct ieee80211_link_data *link = &sdata->deflink; + ieee80211_conn_flags_t conn_flags = 0; int i, err; - bool override = false; + bool override; assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL); if (!assoc_data) @@ -6216,8 +6332,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, /* prepare assoc data */ - link->u.mgd.beacon_crc_valid = false; - assoc_data->wmm = bss->wmm_used && (local->hw.queues >= IEEE80211_NUM_ACS); @@ -6232,27 +6346,44 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; + conn_flags |= IEEE80211_CONN_DISABLE_HT; + conn_flags |= IEEE80211_CONN_DISABLE_VHT; + conn_flags |= IEEE80211_CONN_DISABLE_HE; + conn_flags |= IEEE80211_CONN_DISABLE_EHT; netdev_info(sdata->dev, "disabling HT/VHT/HE due to WEP/TKIP use\n"); } } - sband = local->hw.wiphy->bands[req->bss->channel->band]; - /* also disable HT/VHT/HE/EHT if the AP doesn't use WMM */ if (!bss->wmm_used) { - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; + conn_flags |= IEEE80211_CONN_DISABLE_HT; + conn_flags |= IEEE80211_CONN_DISABLE_VHT; + conn_flags |= IEEE80211_CONN_DISABLE_HE; + conn_flags |= IEEE80211_CONN_DISABLE_EHT; netdev_info(sdata->dev, "disabling HT/VHT/HE as WMM/QoS is not supported by the AP\n"); } + if (req->flags & ASSOC_REQ_DISABLE_HT) { + mlme_dbg(sdata, "HT disabled by flag, disabling HT/VHT/HE\n"); + conn_flags |= IEEE80211_CONN_DISABLE_HT; + conn_flags |= IEEE80211_CONN_DISABLE_VHT; + conn_flags |= IEEE80211_CONN_DISABLE_HE; + conn_flags |= IEEE80211_CONN_DISABLE_EHT; + } + + if (req->flags & ASSOC_REQ_DISABLE_VHT) { + mlme_dbg(sdata, "VHT disabled by flag, disabling VHT\n"); + conn_flags |= IEEE80211_CONN_DISABLE_VHT; + } + + if (req->flags & ASSOC_REQ_DISABLE_HE) { + mlme_dbg(sdata, "HE disabled by flag, disabling HE/EHT\n"); + conn_flags |= IEEE80211_CONN_DISABLE_HE; + conn_flags |= IEEE80211_CONN_DISABLE_EHT; + } + memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, sizeof(ifmgd->ht_capa_mask)); @@ -6287,28 +6418,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, assoc_data->bss = req->bss; assoc_data->capability = req->bss->capability; - assoc_data->supp_rates = bss->supp_rates; - assoc_data->supp_rates_len = bss->supp_rates_len; - rcu_read_lock(); - ht_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_HT_OPERATION); - if (ht_elem && ht_elem->datalen >= sizeof(struct ieee80211_ht_operation)) - assoc_data->ap_ht_param = - ((struct ieee80211_ht_operation *)(ht_elem->data))->ht_param; - else if (!is_6ghz) - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT; - vht_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_VHT_CAPABILITY); - if (vht_elem && vht_elem->datalen >= sizeof(struct ieee80211_vht_cap)) { - memcpy(&assoc_data->ap_vht_cap, vht_elem->data, - sizeof(struct ieee80211_vht_cap)); - } else if (is_5ghz) { - sdata_info(sdata, - "VHT capa missing/short, disabling VHT/HE/EHT\n"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT | - IEEE80211_CONN_DISABLE_HE | - IEEE80211_CONN_DISABLE_EHT; - } - rcu_read_unlock(); + /* default timeout */ + assoc_data->timeout = jiffies; + assoc_data->timeout_started = true; + + conn_flags |= ieee80211_setup_assoc_link(sdata, assoc_data, req, + conn_flags); + override = link->u.mgd.conn_flags != conn_flags; + link->u.mgd.conn_flags |= conn_flags; if (WARN((sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD) && ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK), @@ -6352,50 +6470,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_no_preauth = req->crypto.control_port_no_preauth; /* kick off associate process */ - ifmgd->assoc_data = assoc_data; - link->u.mgd.dtim_period = 0; - link->u.mgd.have_beacon = false; - - /* override HT/VHT configuration only if the AP and we support it */ - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) { - struct ieee80211_sta_ht_cap sta_ht_cap; - - if (req->flags & ASSOC_REQ_DISABLE_HT) - override = true; - - memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); - ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); - - /* check for 40 MHz disable override */ - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_40MHZ) && - sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && - !(sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) - override = true; - - if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) && - req->flags & ASSOC_REQ_DISABLE_VHT) - override = true; - } - - if (req->flags & ASSOC_REQ_DISABLE_HT) { - mlme_dbg(sdata, "HT disabled by flag, disabling HT/VHT/HE\n"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HT; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } - - if (req->flags & ASSOC_REQ_DISABLE_VHT) { - mlme_dbg(sdata, "VHT disabled by flag, disabling VHT\n"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT; - } - - if (req->flags & ASSOC_REQ_DISABLE_HE) { - mlme_dbg(sdata, "HE disabled by flag, disabling HE/EHT\n"); - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE; - link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; - } if (req->flags & ASSOC_REQ_DISABLE_EHT) link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_EHT; @@ -6427,60 +6502,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval); assoc_data->timeout_started = true; assoc_data->need_beacon = true; - } else if (beacon_ies) { - const struct element *elem; - u8 dtim_count = 0; - - ieee80211_get_dtim(beacon_ies, &dtim_count, - &link->u.mgd.dtim_period); - - link->u.mgd.have_beacon = true; - assoc_data->timeout = jiffies; - assoc_data->timeout_started = true; - - if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { - link->conf->sync_tsf = beacon_ies->tsf; - link->conf->sync_device_ts = - bss->device_ts_beacon; - link->conf->sync_dtim_count = dtim_count; - } - - elem = cfg80211_find_ext_elem(WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION, - beacon_ies->data, beacon_ies->len); - if (elem && elem->datalen >= 3) - link->conf->profile_periodicity = elem->data[2]; - else - link->conf->profile_periodicity = 0; - - elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, - beacon_ies->data, beacon_ies->len); - if (elem && elem->datalen >= 11 && - (elem->data[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) - link->conf->ema_ap = true; - else - link->conf->ema_ap = false; - } else { - assoc_data->timeout = jiffies; - assoc_data->timeout_started = true; } rcu_read_unlock(); run_again(sdata, assoc_data->timeout); - if (bss->corrupt_data) { - char *corrupt_type = "data"; - if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_BEACON) { - if (bss->corrupt_data & - IEEE80211_BSS_CORRUPT_PROBE_RESP) - corrupt_type = "beacon and probe response"; - else - corrupt_type = "beacon"; - } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP) - corrupt_type = "probe response"; - sdata_info(sdata, "associating with AP with corrupt %s\n", - corrupt_type); - } - return 0; err_clear: eth_zero_addr(sdata->deflink.u.mgd.bssid);