wifi: mac80211: mlme: refactor assoc success handling
Refactor the per-link setup out of ieee80211_assoc_success() into a new function ieee80211_assoc_config_link(). It looks useless for now to parse the elements again inside ieee80211_assoc_config_link(), but that will be done with the link ID in the future. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
7781f0d81c
commit
6911458dc4
@ -3541,6 +3541,326 @@ static bool ieee80211_twt_bcast_support(struct ieee80211_sub_if_data *sdata,
|
||||
IEEE80211_HE_MAC_CAP2_BCAST_TWT);
|
||||
}
|
||||
|
||||
static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
|
||||
struct link_sta_info *link_sta,
|
||||
struct cfg80211_bss *cbss,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
const u8 *elem_start,
|
||||
unsigned int elem_len,
|
||||
u64 *changed)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = link->sdata;
|
||||
struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
|
||||
struct ieee80211_bss_conf *bss_conf = link->conf;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_elems_parse_params parse_params = {
|
||||
.start = elem_start,
|
||||
.len = elem_len,
|
||||
.bss = cbss,
|
||||
};
|
||||
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
|
||||
bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ;
|
||||
const struct cfg80211_bss_ies *bss_ies = NULL;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee802_11_elems *elems;
|
||||
u16 capab_info;
|
||||
bool ret;
|
||||
|
||||
elems = ieee802_11_parse_elems_full(&parse_params);
|
||||
if (!elems)
|
||||
return false;
|
||||
|
||||
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
|
||||
|
||||
if (!is_s1g && !elems->supp_rates) {
|
||||
sdata_info(sdata, "no SuppRates element in AssocResp\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
link->u.mgd.tdls_chan_switch_prohibited =
|
||||
elems->ext_capab && elems->ext_capab_len >= 5 &&
|
||||
(elems->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED);
|
||||
|
||||
/*
|
||||
* Some APs are erroneously not including some information in their
|
||||
* (re)association response frames. Try to recover by using the data
|
||||
* from the beacon or probe response. This seems to afflict mobile
|
||||
* 2G/3G/4G wifi routers, reported models include the "Onda PN51T",
|
||||
* "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device.
|
||||
*/
|
||||
if (!is_6ghz &&
|
||||
((assoc_data->wmm && !elems->wmm_param) ||
|
||||
(!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
|
||||
(!elems->ht_cap_elem || !elems->ht_operation)) ||
|
||||
(!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
|
||||
(!elems->vht_cap_elem || !elems->vht_operation)))) {
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
struct ieee802_11_elems *bss_elems;
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(cbss->ies);
|
||||
if (ies)
|
||||
bss_ies = kmemdup(ies, sizeof(*ies) + ies->len,
|
||||
GFP_ATOMIC);
|
||||
rcu_read_unlock();
|
||||
if (!bss_ies) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
parse_params.start = bss_ies->data;
|
||||
parse_params.len = bss_ies->len;
|
||||
bss_elems = ieee802_11_parse_elems_full(&parse_params);
|
||||
if (!bss_elems) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (assoc_data->wmm &&
|
||||
!elems->wmm_param && bss_elems->wmm_param) {
|
||||
elems->wmm_param = bss_elems->wmm_param;
|
||||
sdata_info(sdata,
|
||||
"AP bug: WMM param missing from AssocResp\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Also check if we requested HT/VHT, otherwise the AP doesn't
|
||||
* have to include the IEs in the (re)association response.
|
||||
*/
|
||||
if (!elems->ht_cap_elem && bss_elems->ht_cap_elem &&
|
||||
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
|
||||
elems->ht_cap_elem = bss_elems->ht_cap_elem;
|
||||
sdata_info(sdata,
|
||||
"AP bug: HT capability missing from AssocResp\n");
|
||||
}
|
||||
if (!elems->ht_operation && bss_elems->ht_operation &&
|
||||
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
|
||||
elems->ht_operation = bss_elems->ht_operation;
|
||||
sdata_info(sdata,
|
||||
"AP bug: HT operation missing from AssocResp\n");
|
||||
}
|
||||
if (!elems->vht_cap_elem && bss_elems->vht_cap_elem &&
|
||||
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
|
||||
elems->vht_cap_elem = bss_elems->vht_cap_elem;
|
||||
sdata_info(sdata,
|
||||
"AP bug: VHT capa missing from AssocResp\n");
|
||||
}
|
||||
if (!elems->vht_operation && bss_elems->vht_operation &&
|
||||
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
|
||||
elems->vht_operation = bss_elems->vht_operation;
|
||||
sdata_info(sdata,
|
||||
"AP bug: VHT operation missing from AssocResp\n");
|
||||
}
|
||||
|
||||
kfree(bss_elems);
|
||||
}
|
||||
|
||||
/*
|
||||
* We previously checked these in the beacon/probe response, so
|
||||
* they should be present here. This is just a safety net.
|
||||
*/
|
||||
if (!is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
|
||||
(!elems->wmm_param || !elems->ht_cap_elem || !elems->ht_operation)) {
|
||||
sdata_info(sdata,
|
||||
"HT AP is missing WMM params or HT capability/operation\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
|
||||
(!elems->vht_cap_elem || !elems->vht_operation)) {
|
||||
sdata_info(sdata,
|
||||
"VHT AP is missing VHT capability/operation\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
|
||||
!elems->he_6ghz_capa) {
|
||||
sdata_info(sdata,
|
||||
"HE 6 GHz AP is missing HE 6 GHz band capability\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sband = ieee80211_get_link_sband(link);
|
||||
if (!sband) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
|
||||
(!elems->he_cap || !elems->he_operation)) {
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
sdata_info(sdata,
|
||||
"HE AP is missing HE capability/operation\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up internal HT/VHT capabilities */
|
||||
if (elems->ht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
elems->ht_cap_elem,
|
||||
link_sta);
|
||||
|
||||
if (elems->vht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
|
||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||
elems->vht_cap_elem,
|
||||
link_sta);
|
||||
|
||||
if (elems->he_operation && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
|
||||
elems->he_cap) {
|
||||
ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
|
||||
elems->he_cap,
|
||||
elems->he_cap_len,
|
||||
elems->he_6ghz_capa,
|
||||
link_sta);
|
||||
|
||||
bss_conf->he_support = link_sta->pub->he_cap.has_he;
|
||||
if (elems->rsnx && elems->rsnx_len &&
|
||||
(elems->rsnx[0] & WLAN_RSNX_CAPA_PROTECTED_TWT) &&
|
||||
wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
NL80211_EXT_FEATURE_PROTECTED_TWT))
|
||||
bss_conf->twt_protected = true;
|
||||
else
|
||||
bss_conf->twt_protected = false;
|
||||
|
||||
*changed |= ieee80211_recalc_twt_req(link, link_sta, elems);
|
||||
|
||||
if (elems->eht_operation && elems->eht_cap &&
|
||||
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) {
|
||||
ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
|
||||
elems->he_cap,
|
||||
elems->he_cap_len,
|
||||
elems->eht_cap,
|
||||
elems->eht_cap_len,
|
||||
link_sta);
|
||||
|
||||
bss_conf->eht_support = link_sta->pub->eht_cap.has_eht;
|
||||
} else {
|
||||
bss_conf->eht_support = false;
|
||||
}
|
||||
} else {
|
||||
bss_conf->he_support = false;
|
||||
bss_conf->twt_requester = false;
|
||||
bss_conf->twt_protected = false;
|
||||
bss_conf->eht_support = false;
|
||||
}
|
||||
|
||||
bss_conf->twt_broadcast =
|
||||
ieee80211_twt_bcast_support(sdata, bss_conf, sband, link_sta);
|
||||
|
||||
if (bss_conf->he_support) {
|
||||
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.enabled =
|
||||
!le32_get_bits(elems->he_operation->he_oper_params,
|
||||
IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED);
|
||||
|
||||
if (bss_conf->he_bss_color.enabled)
|
||||
*changed |= BSS_CHANGED_HE_BSS_COLOR;
|
||||
|
||||
bss_conf->htc_trig_based_pkt_ext =
|
||||
le32_get_bits(elems->he_operation->he_oper_params,
|
||||
IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK);
|
||||
bss_conf->frame_time_rts_th =
|
||||
le32_get_bits(elems->he_operation->he_oper_params,
|
||||
IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK);
|
||||
|
||||
bss_conf->uora_exists = !!elems->uora_element;
|
||||
if (elems->uora_element)
|
||||
bss_conf->uora_ocw_range = elems->uora_element[0];
|
||||
|
||||
ieee80211_he_op_ie_to_bss_conf(&sdata->vif, elems->he_operation);
|
||||
ieee80211_he_spr_ie_to_bss_conf(&sdata->vif, elems->he_spr);
|
||||
/* TODO: OPEN: what happens if BSS color disable is set? */
|
||||
}
|
||||
|
||||
if (cbss->transmitted_bss) {
|
||||
bss_conf->nontransmitted = true;
|
||||
ether_addr_copy(bss_conf->transmitter_bssid,
|
||||
cbss->transmitted_bss->bssid);
|
||||
bss_conf->bssid_indicator = cbss->max_bssid_indicator;
|
||||
bss_conf->bssid_index = cbss->bssid_index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some APs, e.g. Netgear WNDR3700, report invalid HT operation data
|
||||
* in their association response, so ignore that data for our own
|
||||
* configuration. If it changed since the last beacon, we'll get the
|
||||
* next beacon and update then.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If an operating mode notification IE is present, override the
|
||||
* NSS calculation (that would be done in rate_control_rate_init())
|
||||
* and use the # of streams from that element.
|
||||
*/
|
||||
if (elems->opmode_notif &&
|
||||
!(*elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) {
|
||||
u8 nss;
|
||||
|
||||
nss = *elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK;
|
||||
nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
|
||||
nss += 1;
|
||||
link_sta->pub->rx_nss = nss;
|
||||
}
|
||||
|
||||
/*
|
||||
* Always handle WMM once after association regardless
|
||||
* of the first value the AP uses. Setting -1 here has
|
||||
* that effect because the AP values is an unsigned
|
||||
* 4-bit value.
|
||||
*/
|
||||
link->u.mgd.wmm_last_param_set = -1;
|
||||
link->u.mgd.mu_edca_last_param_set = -1;
|
||||
|
||||
if (link->u.mgd.disable_wmm_tracking) {
|
||||
ieee80211_set_wmm_default(link, false, false);
|
||||
} else if (!ieee80211_sta_wmm_params(local, link, elems->wmm_param,
|
||||
elems->wmm_param_len,
|
||||
elems->mu_edca_param_set)) {
|
||||
/* still enable QoS since we might have HT/VHT */
|
||||
ieee80211_set_wmm_default(link, false, true);
|
||||
/* disable WMM tracking in this case to disable
|
||||
* tracking WMM parameter changes in the beacon if
|
||||
* the parameters weren't actually valid. Doing so
|
||||
* avoids changing parameters very strangely when
|
||||
* the AP is going back and forth between valid and
|
||||
* invalid parameters.
|
||||
*/
|
||||
link->u.mgd.disable_wmm_tracking = true;
|
||||
}
|
||||
|
||||
if (elems->max_idle_period_ie) {
|
||||
bss_conf->max_idle_period =
|
||||
le16_to_cpu(elems->max_idle_period_ie->max_idle_period);
|
||||
bss_conf->protected_keep_alive =
|
||||
!!(elems->max_idle_period_ie->idle_options &
|
||||
WLAN_IDLE_OPTIONS_PROTECTED_KEEP_ALIVE);
|
||||
*changed |= BSS_CHANGED_KEEP_ALIVE;
|
||||
} else {
|
||||
bss_conf->max_idle_period = 0;
|
||||
bss_conf->protected_keep_alive = false;
|
||||
}
|
||||
|
||||
/* set assoc capability (AID was already set earlier),
|
||||
* ieee80211_set_associated() will tell the driver */
|
||||
bss_conf->assoc_capability = capab_info;
|
||||
|
||||
ret = true;
|
||||
out:
|
||||
kfree(elems);
|
||||
kfree(bss_ies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
@ -4120,160 +4440,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_bss *cbss,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee802_11_elems *elems)
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
struct ieee802_11_elems *elems,
|
||||
const u8 *elem_start, unsigned int elem_len)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct link_sta_info *link_sta;
|
||||
struct sta_info *sta;
|
||||
u16 capab_info, aid;
|
||||
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
|
||||
const struct cfg80211_bss_ies *bss_ies = NULL;
|
||||
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
|
||||
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
|
||||
bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ;
|
||||
struct ieee80211_link_data *link = &sdata->deflink;
|
||||
u32 changed = 0;
|
||||
u64 changed = 0;
|
||||
int err;
|
||||
bool ret;
|
||||
|
||||
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
|
||||
|
||||
if (elems->aid_resp)
|
||||
aid = le16_to_cpu(elems->aid_resp->aid);
|
||||
else if (is_s1g)
|
||||
aid = 0; /* TODO */
|
||||
else
|
||||
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
|
||||
|
||||
/*
|
||||
* The 5 MSB of the AID field are reserved
|
||||
* (802.11-2016 9.4.1.8 AID field)
|
||||
*/
|
||||
aid &= 0x7ff;
|
||||
|
||||
ifmgd->broken_ap = false;
|
||||
|
||||
if (aid == 0 || aid > IEEE80211_MAX_AID) {
|
||||
sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n",
|
||||
aid);
|
||||
aid = 0;
|
||||
ifmgd->broken_ap = true;
|
||||
}
|
||||
|
||||
if (!is_s1g && !elems->supp_rates) {
|
||||
sdata_info(sdata, "no SuppRates element in AssocResp\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdata->vif.cfg.aid = aid;
|
||||
sdata->deflink.u.mgd.tdls_chan_switch_prohibited =
|
||||
elems->ext_capab && elems->ext_capab_len >= 5 &&
|
||||
(elems->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED);
|
||||
|
||||
/*
|
||||
* Some APs are erroneously not including some information in their
|
||||
* (re)association response frames. Try to recover by using the data
|
||||
* from the beacon or probe response. This seems to afflict mobile
|
||||
* 2G/3G/4G wifi routers, reported models include the "Onda PN51T",
|
||||
* "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device.
|
||||
*/
|
||||
if (!is_6ghz &&
|
||||
((assoc_data->wmm && !elems->wmm_param) ||
|
||||
(!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
|
||||
(!elems->ht_cap_elem || !elems->ht_operation)) ||
|
||||
(!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
|
||||
(!elems->vht_cap_elem || !elems->vht_operation)))) {
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
struct ieee802_11_elems *bss_elems;
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(cbss->ies);
|
||||
if (ies)
|
||||
bss_ies = kmemdup(ies, sizeof(*ies) + ies->len,
|
||||
GFP_ATOMIC);
|
||||
rcu_read_unlock();
|
||||
if (!bss_ies) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
|
||||
false, assoc_data->bss);
|
||||
if (!bss_elems) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (assoc_data->wmm &&
|
||||
!elems->wmm_param && bss_elems->wmm_param) {
|
||||
elems->wmm_param = bss_elems->wmm_param;
|
||||
sdata_info(sdata,
|
||||
"AP bug: WMM param missing from AssocResp\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Also check if we requested HT/VHT, otherwise the AP doesn't
|
||||
* have to include the IEs in the (re)association response.
|
||||
*/
|
||||
if (!elems->ht_cap_elem && bss_elems->ht_cap_elem &&
|
||||
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
|
||||
elems->ht_cap_elem = bss_elems->ht_cap_elem;
|
||||
sdata_info(sdata,
|
||||
"AP bug: HT capability missing from AssocResp\n");
|
||||
}
|
||||
if (!elems->ht_operation && bss_elems->ht_operation &&
|
||||
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)) {
|
||||
elems->ht_operation = bss_elems->ht_operation;
|
||||
sdata_info(sdata,
|
||||
"AP bug: HT operation missing from AssocResp\n");
|
||||
}
|
||||
if (!elems->vht_cap_elem && bss_elems->vht_cap_elem &&
|
||||
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
|
||||
elems->vht_cap_elem = bss_elems->vht_cap_elem;
|
||||
sdata_info(sdata,
|
||||
"AP bug: VHT capa missing from AssocResp\n");
|
||||
}
|
||||
if (!elems->vht_operation && bss_elems->vht_operation &&
|
||||
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
|
||||
elems->vht_operation = bss_elems->vht_operation;
|
||||
sdata_info(sdata,
|
||||
"AP bug: VHT operation missing from AssocResp\n");
|
||||
}
|
||||
|
||||
kfree(bss_elems);
|
||||
}
|
||||
|
||||
/*
|
||||
* We previously checked these in the beacon/probe response, so
|
||||
* they should be present here. This is just a safety net.
|
||||
*/
|
||||
if (!is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
|
||||
(!elems->wmm_param || !elems->ht_cap_elem || !elems->ht_operation)) {
|
||||
sdata_info(sdata,
|
||||
"HT AP is missing WMM params or HT capability/operation\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) &&
|
||||
(!elems->vht_cap_elem || !elems->vht_operation)) {
|
||||
sdata_info(sdata,
|
||||
"VHT AP is missing VHT capability/operation\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_6ghz && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
|
||||
!elems->he_6ghz_capa) {
|
||||
sdata_info(sdata,
|
||||
"HE 6 GHz AP is missing HE 6 GHz band capability\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&sdata->local->sta_mtx);
|
||||
/*
|
||||
@ -4281,154 +4456,13 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
* the association and should be available to us
|
||||
*/
|
||||
sta = sta_info_get(sdata, cbss->bssid);
|
||||
if (WARN_ON(!sta)) {
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
if (WARN_ON(!sta))
|
||||
goto out_err;
|
||||
|
||||
link_sta = rcu_dereference_protected(sta->link[link->link_id],
|
||||
lockdep_is_held(&local->sta_mtx));
|
||||
if (WARN_ON(!link_sta)) {
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sband = ieee80211_get_link_sband(link);
|
||||
if (!sband) {
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
|
||||
(!elems->he_cap || !elems->he_operation)) {
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
sdata_info(sdata,
|
||||
"HE AP is missing HE capability/operation\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up internal HT/VHT capabilities */
|
||||
if (elems->ht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
elems->ht_cap_elem,
|
||||
link_sta);
|
||||
|
||||
if (elems->vht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
|
||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||
elems->vht_cap_elem,
|
||||
link_sta);
|
||||
|
||||
if (elems->he_operation && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
|
||||
elems->he_cap) {
|
||||
ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
|
||||
elems->he_cap,
|
||||
elems->he_cap_len,
|
||||
elems->he_6ghz_capa,
|
||||
link_sta);
|
||||
|
||||
bss_conf->he_support = link_sta->pub->he_cap.has_he;
|
||||
if (elems->rsnx && elems->rsnx_len &&
|
||||
(elems->rsnx[0] & WLAN_RSNX_CAPA_PROTECTED_TWT) &&
|
||||
wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
NL80211_EXT_FEATURE_PROTECTED_TWT))
|
||||
bss_conf->twt_protected = true;
|
||||
else
|
||||
bss_conf->twt_protected = false;
|
||||
|
||||
changed |= ieee80211_recalc_twt_req(link, link_sta, elems);
|
||||
|
||||
if (elems->eht_operation && elems->eht_cap &&
|
||||
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT)) {
|
||||
ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
|
||||
elems->he_cap,
|
||||
elems->he_cap_len,
|
||||
elems->eht_cap,
|
||||
elems->eht_cap_len,
|
||||
link_sta);
|
||||
|
||||
bss_conf->eht_support = link_sta->pub->eht_cap.has_eht;
|
||||
} else {
|
||||
bss_conf->eht_support = false;
|
||||
}
|
||||
} else {
|
||||
bss_conf->he_support = false;
|
||||
bss_conf->twt_requester = false;
|
||||
bss_conf->twt_protected = false;
|
||||
bss_conf->eht_support = false;
|
||||
}
|
||||
|
||||
bss_conf->twt_broadcast =
|
||||
ieee80211_twt_bcast_support(sdata, bss_conf, sband, link_sta);
|
||||
|
||||
if (bss_conf->he_support) {
|
||||
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.enabled =
|
||||
!le32_get_bits(elems->he_operation->he_oper_params,
|
||||
IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED);
|
||||
|
||||
if (bss_conf->he_bss_color.enabled)
|
||||
changed |= BSS_CHANGED_HE_BSS_COLOR;
|
||||
|
||||
bss_conf->htc_trig_based_pkt_ext =
|
||||
le32_get_bits(elems->he_operation->he_oper_params,
|
||||
IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK);
|
||||
bss_conf->frame_time_rts_th =
|
||||
le32_get_bits(elems->he_operation->he_oper_params,
|
||||
IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK);
|
||||
|
||||
bss_conf->uora_exists = !!elems->uora_element;
|
||||
if (elems->uora_element)
|
||||
bss_conf->uora_ocw_range = elems->uora_element[0];
|
||||
|
||||
ieee80211_he_op_ie_to_bss_conf(&sdata->vif, elems->he_operation);
|
||||
ieee80211_he_spr_ie_to_bss_conf(&sdata->vif, elems->he_spr);
|
||||
/* TODO: OPEN: what happens if BSS color disable is set? */
|
||||
}
|
||||
|
||||
if (cbss->transmitted_bss) {
|
||||
bss_conf->nontransmitted = true;
|
||||
ether_addr_copy(bss_conf->transmitter_bssid,
|
||||
cbss->transmitted_bss->bssid);
|
||||
bss_conf->bssid_indicator = cbss->max_bssid_indicator;
|
||||
bss_conf->bssid_index = cbss->bssid_index;
|
||||
} else {
|
||||
bss_conf->nontransmitted = false;
|
||||
memset(bss_conf->transmitter_bssid, 0,
|
||||
sizeof(bss_conf->transmitter_bssid));
|
||||
bss_conf->bssid_indicator = 0;
|
||||
bss_conf->bssid_index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some APs, e.g. Netgear WNDR3700, report invalid HT operation data
|
||||
* in their association response, so ignore that data for our own
|
||||
* configuration. If it changed since the last beacon, we'll get the
|
||||
* next beacon and update then.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If an operating mode notification IE is present, override the
|
||||
* NSS calculation (that would be done in rate_control_rate_init())
|
||||
* and use the # of streams from that element.
|
||||
*/
|
||||
if (elems->opmode_notif &&
|
||||
!(*elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) {
|
||||
u8 nss;
|
||||
|
||||
nss = *elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK;
|
||||
nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
|
||||
nss += 1;
|
||||
link_sta->pub->rx_nss = nss;
|
||||
}
|
||||
if (!ieee80211_assoc_config_link(&sdata->deflink, &sta->deflink,
|
||||
cbss, mgmt, elem_start, elem_len,
|
||||
&changed))
|
||||
goto out_err;
|
||||
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
@ -4450,9 +4484,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
"failed to move station %pM to desired state\n",
|
||||
sta->sta.addr);
|
||||
WARN_ON(__sta_info_destroy(sta));
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
ret = false;
|
||||
goto out;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (sdata->wdev.use_4addr)
|
||||
@ -4460,48 +4492,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
|
||||
/*
|
||||
* Always handle WMM once after association regardless
|
||||
* of the first value the AP uses. Setting -1 here has
|
||||
* that effect because the AP values is an unsigned
|
||||
* 4-bit value.
|
||||
*/
|
||||
link->u.mgd.wmm_last_param_set = -1;
|
||||
link->u.mgd.mu_edca_last_param_set = -1;
|
||||
|
||||
if (link->u.mgd.disable_wmm_tracking) {
|
||||
ieee80211_set_wmm_default(link, false, false);
|
||||
} else if (!ieee80211_sta_wmm_params(local, link, elems->wmm_param,
|
||||
elems->wmm_param_len,
|
||||
elems->mu_edca_param_set)) {
|
||||
/* still enable QoS since we might have HT/VHT */
|
||||
ieee80211_set_wmm_default(link, false, true);
|
||||
/* disable WMM tracking in this case to disable
|
||||
* tracking WMM parameter changes in the beacon if
|
||||
* the parameters weren't actually valid. Doing so
|
||||
* avoids changing parameters very strangely when
|
||||
* the AP is going back and forth between valid and
|
||||
* invalid parameters.
|
||||
*/
|
||||
link->u.mgd.disable_wmm_tracking = true;
|
||||
}
|
||||
changed |= BSS_CHANGED_QOS;
|
||||
|
||||
if (elems->max_idle_period_ie) {
|
||||
bss_conf->max_idle_period =
|
||||
le16_to_cpu(elems->max_idle_period_ie->max_idle_period);
|
||||
bss_conf->protected_keep_alive =
|
||||
!!(elems->max_idle_period_ie->idle_options &
|
||||
WLAN_IDLE_OPTIONS_PROTECTED_KEEP_ALIVE);
|
||||
changed |= BSS_CHANGED_KEEP_ALIVE;
|
||||
} else {
|
||||
bss_conf->max_idle_period = 0;
|
||||
bss_conf->protected_keep_alive = false;
|
||||
}
|
||||
|
||||
/* set assoc capability (AID was already set earlier),
|
||||
* ieee80211_set_associated() will tell the driver */
|
||||
bss_conf->assoc_capability = capab_info;
|
||||
ieee80211_set_associated(sdata, cbss, changed);
|
||||
|
||||
/*
|
||||
@ -4518,10 +4508,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_sta_reset_beacon_monitor(sdata);
|
||||
ieee80211_sta_reset_conn_monitor(sdata);
|
||||
|
||||
ret = true;
|
||||
out:
|
||||
kfree(bss_ies);
|
||||
return ret;
|
||||
return true;
|
||||
out_err:
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
@ -4533,7 +4523,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
u16 capab_info, status_code, aid;
|
||||
struct ieee802_11_elems *elems;
|
||||
int ac;
|
||||
u8 *pos;
|
||||
const u8 *elem_start;
|
||||
unsigned int elem_len;
|
||||
bool reassoc;
|
||||
struct cfg80211_bss *cbss;
|
||||
struct ieee80211_event event = {
|
||||
@ -4566,12 +4557,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
reassoc = ieee80211_is_reassoc_resp(mgmt->frame_control);
|
||||
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
|
||||
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
||||
pos = mgmt->u.assoc_resp.variable;
|
||||
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
|
||||
if (cbss->channel->band == NL80211_BAND_S1GHZ) {
|
||||
pos = (u8 *) mgmt->u.s1g_assoc_resp.variable;
|
||||
aid = 0; /* TODO */
|
||||
}
|
||||
if (cbss->channel->band == NL80211_BAND_S1GHZ)
|
||||
elem_start = mgmt->u.s1g_assoc_resp.variable;
|
||||
else
|
||||
elem_start = mgmt->u.assoc_resp.variable;
|
||||
|
||||
/*
|
||||
* Note: this may not be perfect, AP might misbehave - if
|
||||
@ -4582,19 +4571,34 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
info.subtype = reassoc ? IEEE80211_STYPE_REASSOC_REQ :
|
||||
IEEE80211_STYPE_ASSOC_REQ;
|
||||
|
||||
if (assoc_data->fils_kek_len &&
|
||||
fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0)
|
||||
return;
|
||||
|
||||
elem_len = len - (elem_start - (u8 *)mgmt);
|
||||
elems = ieee802_11_parse_elems(elem_start, elem_len, false, NULL);
|
||||
if (!elems)
|
||||
goto notify_driver;
|
||||
|
||||
if (elems->aid_resp)
|
||||
aid = le16_to_cpu(elems->aid_resp->aid);
|
||||
else if (cbss->channel->band == NL80211_BAND_S1GHZ)
|
||||
aid = 0; /* TODO */
|
||||
else
|
||||
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
|
||||
|
||||
/*
|
||||
* The 5 MSB of the AID field are reserved
|
||||
* (802.11-2016 9.4.1.8 AID field)
|
||||
*/
|
||||
aid &= 0x7ff;
|
||||
|
||||
sdata_info(sdata,
|
||||
"RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
|
||||
reassoc ? "Rea" : "A", mgmt->sa,
|
||||
capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
|
||||
|
||||
if (assoc_data->fils_kek_len &&
|
||||
fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0)
|
||||
return;
|
||||
|
||||
elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
|
||||
assoc_data->bss);
|
||||
if (!elems)
|
||||
goto notify_driver;
|
||||
ifmgd->broken_ap = false;
|
||||
|
||||
if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
|
||||
elems->timeout_int &&
|
||||
@ -4624,7 +4628,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
event.u.mlme.reason = status_code;
|
||||
drv_event_callback(sdata->local, sdata, &event);
|
||||
} else {
|
||||
if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) {
|
||||
if (aid == 0 || aid > IEEE80211_MAX_AID) {
|
||||
sdata_info(sdata,
|
||||
"invalid AID value %d (out of range), turn off PS\n",
|
||||
aid);
|
||||
aid = 0;
|
||||
ifmgd->broken_ap = true;
|
||||
}
|
||||
|
||||
sdata->vif.cfg.aid = aid;
|
||||
|
||||
if (!ieee80211_assoc_success(sdata, cbss, mgmt, elems,
|
||||
elem_start, elem_len)) {
|
||||
/* oops -- internal error -- send timeout for now */
|
||||
ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT);
|
||||
goto notify_driver;
|
||||
|
Loading…
Reference in New Issue
Block a user