Skip to content

Commit 35e2385

Browse files
committed
wifi: mac80211: improve CSA/ECSA connection refusal
As mentioned in the previous commit, we pretty quickly found that some APs have ECSA elements stuck in their probe response, so using that to not attempt to connect while CSA is happening we never connect to such an AP. Improve this situation by checking more carefully and ignoring the ECSA if cfg80211 has previously detected the ECSA element being stuck in the probe response. Additionally, allow connecting to an AP that's switching to a channel it's already using, unless it's using quiet mode. In this case, we may just have to adjust bandwidth later. If it's actually switching channels, it's better not to try to connect in the middle of that. Reported-by: coldolt <andypalmadi@gmail.com> Closes: https://lore.kernel.org/linux-wireless/CAJvGw+DQhBk_mHXeu6RTOds5iramMW2FbMB01VbKRA4YbHHDTA@mail.gmail.com/ Fixes: c09c4f3 ("wifi: mac80211: don't connect to an AP while it's in a CSA process") Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com> Link: https://msgid.link/20240129131413.cc2d0a26226e.I682c016af76e35b6c47007db50e8554c5a426910@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent 177fbbc commit 35e2385

1 file changed

Lines changed: 76 additions & 27 deletions

File tree

net/mac80211/mlme.c

Lines changed: 76 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7309,6 +7309,75 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
73097309
return err;
73107310
}
73117311

7312+
static bool ieee80211_mgd_csa_present(struct ieee80211_sub_if_data *sdata,
7313+
const struct cfg80211_bss_ies *ies,
7314+
u8 cur_channel, bool ignore_ecsa)
7315+
{
7316+
const struct element *csa_elem, *ecsa_elem;
7317+
struct ieee80211_channel_sw_ie *csa = NULL;
7318+
struct ieee80211_ext_chansw_ie *ecsa = NULL;
7319+
7320+
if (!ies)
7321+
return false;
7322+
7323+
csa_elem = cfg80211_find_elem(WLAN_EID_CHANNEL_SWITCH,
7324+
ies->data, ies->len);
7325+
if (csa_elem && csa_elem->datalen == sizeof(*csa))
7326+
csa = (void *)csa_elem->data;
7327+
7328+
ecsa_elem = cfg80211_find_elem(WLAN_EID_EXT_CHANSWITCH_ANN,
7329+
ies->data, ies->len);
7330+
if (ecsa_elem && ecsa_elem->datalen == sizeof(*ecsa))
7331+
ecsa = (void *)ecsa_elem->data;
7332+
7333+
if (csa && csa->count == 0)
7334+
csa = NULL;
7335+
if (csa && !csa->mode && csa->new_ch_num == cur_channel)
7336+
csa = NULL;
7337+
7338+
if (ecsa && ecsa->count == 0)
7339+
ecsa = NULL;
7340+
if (ecsa && !ecsa->mode && ecsa->new_ch_num == cur_channel)
7341+
ecsa = NULL;
7342+
7343+
if (ignore_ecsa && ecsa) {
7344+
sdata_info(sdata,
7345+
"Ignoring ECSA in probe response - was considered stuck!\n");
7346+
return csa;
7347+
}
7348+
7349+
return csa || ecsa;
7350+
}
7351+
7352+
static bool ieee80211_mgd_csa_in_process(struct ieee80211_sub_if_data *sdata,
7353+
struct cfg80211_bss *bss)
7354+
{
7355+
u8 cur_channel;
7356+
bool ret;
7357+
7358+
cur_channel = ieee80211_frequency_to_channel(bss->channel->center_freq);
7359+
7360+
rcu_read_lock();
7361+
if (ieee80211_mgd_csa_present(sdata,
7362+
rcu_dereference(bss->beacon_ies),
7363+
cur_channel, false)) {
7364+
ret = true;
7365+
goto out;
7366+
}
7367+
7368+
if (ieee80211_mgd_csa_present(sdata,
7369+
rcu_dereference(bss->proberesp_ies),
7370+
cur_channel, bss->proberesp_ecsa_stuck)) {
7371+
ret = true;
7372+
goto out;
7373+
}
7374+
7375+
ret = false;
7376+
out:
7377+
rcu_read_unlock();
7378+
return ret;
7379+
}
7380+
73127381
/* config hooks */
73137382
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
73147383
struct cfg80211_auth_request *req)
@@ -7317,7 +7386,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
73177386
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
73187387
struct ieee80211_mgd_auth_data *auth_data;
73197388
struct ieee80211_link_data *link;
7320-
const struct element *csa_elem, *ecsa_elem;
73217389
u16 auth_alg;
73227390
int err;
73237391
bool cont_auth;
@@ -7360,21 +7428,10 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
73607428
if (ifmgd->assoc_data)
73617429
return -EBUSY;
73627430

7363-
rcu_read_lock();
7364-
csa_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_CHANNEL_SWITCH);
7365-
ecsa_elem = ieee80211_bss_get_elem(req->bss,
7366-
WLAN_EID_EXT_CHANSWITCH_ANN);
7367-
if ((csa_elem &&
7368-
csa_elem->datalen == sizeof(struct ieee80211_channel_sw_ie) &&
7369-
((struct ieee80211_channel_sw_ie *)csa_elem->data)->count != 0) ||
7370-
(ecsa_elem &&
7371-
ecsa_elem->datalen == sizeof(struct ieee80211_ext_chansw_ie) &&
7372-
((struct ieee80211_ext_chansw_ie *)ecsa_elem->data)->count != 0)) {
7373-
rcu_read_unlock();
7431+
if (ieee80211_mgd_csa_in_process(sdata, req->bss)) {
73747432
sdata_info(sdata, "AP is in CSA process, reject auth\n");
73757433
return -EINVAL;
73767434
}
7377-
rcu_read_unlock();
73787435

73797436
auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len +
73807437
req->ie_len, GFP_KERNEL);
@@ -7684,7 +7741,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
76847741
struct ieee80211_local *local = sdata->local;
76857742
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
76867743
struct ieee80211_mgd_assoc_data *assoc_data;
7687-
const struct element *ssid_elem, *csa_elem, *ecsa_elem;
7744+
const struct element *ssid_elem;
76887745
struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg;
76897746
ieee80211_conn_flags_t conn_flags = 0;
76907747
struct ieee80211_link_data *link;
@@ -7707,23 +7764,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
77077764

77087765
cbss = req->link_id < 0 ? req->bss : req->links[req->link_id].bss;
77097766

7710-
rcu_read_lock();
7711-
ssid_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_SSID);
7712-
if (!ssid_elem || ssid_elem->datalen > sizeof(assoc_data->ssid)) {
7713-
rcu_read_unlock();
7767+
if (ieee80211_mgd_csa_in_process(sdata, cbss)) {
7768+
sdata_info(sdata, "AP is in CSA process, reject assoc\n");
77147769
kfree(assoc_data);
77157770
return -EINVAL;
77167771
}
77177772

7718-
csa_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_CHANNEL_SWITCH);
7719-
ecsa_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_EXT_CHANSWITCH_ANN);
7720-
if ((csa_elem &&
7721-
csa_elem->datalen == sizeof(struct ieee80211_channel_sw_ie) &&
7722-
((struct ieee80211_channel_sw_ie *)csa_elem->data)->count != 0) ||
7723-
(ecsa_elem &&
7724-
ecsa_elem->datalen == sizeof(struct ieee80211_ext_chansw_ie) &&
7725-
((struct ieee80211_ext_chansw_ie *)ecsa_elem->data)->count != 0)) {
7726-
sdata_info(sdata, "AP is in CSA process, reject assoc\n");
7773+
rcu_read_lock();
7774+
ssid_elem = ieee80211_bss_get_elem(cbss, WLAN_EID_SSID);
7775+
if (!ssid_elem || ssid_elem->datalen > sizeof(assoc_data->ssid)) {
77277776
rcu_read_unlock();
77287777
kfree(assoc_data);
77297778
return -EINVAL;

0 commit comments

Comments
 (0)