Skip to content

Commit 177fbbc

Browse files
committed
wifi: cfg80211: detect stuck ECSA element in probe resp
We recently added some validation that we don't try to connect to an AP that is currently in a channel switch process, since that might want the channel to be quiet or we might not be able to connect in time to hear the switching in a beacon. This was in commit c09c4f3 ("wifi: mac80211: don't connect to an AP while it's in a CSA process"). However, we promptly got a report that this caused new connection failures, and it turns out that the AP that we now cannot connect to is permanently advertising an extended channel switch announcement, even with quiet. The AP in question was an Asus RT-AC53, with firmware 3.0.0.4.380_10760-g21a5898. As a first step, attempt to detect that we're dealing with such a situation, so mac80211 can use this later. 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.246972c8775e.Ibf834d7f52f9951a353b6872383da710a7358338@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent aa125f2 commit 177fbbc

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

include/net/cfg80211.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2910,6 +2910,8 @@ struct cfg80211_bss_ies {
29102910
* own the beacon_ies, but they're just pointers to the ones from the
29112911
* @hidden_beacon_bss struct)
29122912
* @proberesp_ies: the information elements from the last Probe Response frame
2913+
* @proberesp_ecsa_stuck: ECSA element is stuck in the Probe Response frame,
2914+
* cannot rely on it having valid data
29132915
* @hidden_beacon_bss: in case this BSS struct represents a probe response from
29142916
* a BSS that hides the SSID in its beacon, this points to the BSS struct
29152917
* that holds the beacon data. @beacon_ies is still valid, of course, and
@@ -2950,6 +2952,8 @@ struct cfg80211_bss {
29502952
u8 chains;
29512953
s8 chain_signal[IEEE80211_MAX_CHAINS];
29522954

2955+
u8 proberesp_ecsa_stuck:1;
2956+
29532957
u8 bssid_index;
29542958
u8 max_bssid_indicator;
29552959

net/wireless/scan.c

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1731,6 +1731,61 @@ static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known,
17311731
}
17321732
}
17331733

1734+
static void cfg80211_check_stuck_ecsa(struct cfg80211_registered_device *rdev,
1735+
struct cfg80211_internal_bss *known,
1736+
const struct cfg80211_bss_ies *old)
1737+
{
1738+
const struct ieee80211_ext_chansw_ie *ecsa;
1739+
const struct element *elem_new, *elem_old;
1740+
const struct cfg80211_bss_ies *new, *bcn;
1741+
1742+
if (known->pub.proberesp_ecsa_stuck)
1743+
return;
1744+
1745+
new = rcu_dereference_protected(known->pub.proberesp_ies,
1746+
lockdep_is_held(&rdev->bss_lock));
1747+
if (WARN_ON(!new))
1748+
return;
1749+
1750+
if (new->tsf - old->tsf < USEC_PER_SEC)
1751+
return;
1752+
1753+
elem_old = cfg80211_find_elem(WLAN_EID_EXT_CHANSWITCH_ANN,
1754+
old->data, old->len);
1755+
if (!elem_old)
1756+
return;
1757+
1758+
elem_new = cfg80211_find_elem(WLAN_EID_EXT_CHANSWITCH_ANN,
1759+
new->data, new->len);
1760+
if (!elem_new)
1761+
return;
1762+
1763+
bcn = rcu_dereference_protected(known->pub.beacon_ies,
1764+
lockdep_is_held(&rdev->bss_lock));
1765+
if (bcn &&
1766+
cfg80211_find_elem(WLAN_EID_EXT_CHANSWITCH_ANN,
1767+
bcn->data, bcn->len))
1768+
return;
1769+
1770+
if (elem_new->datalen != elem_old->datalen)
1771+
return;
1772+
if (elem_new->datalen < sizeof(struct ieee80211_ext_chansw_ie))
1773+
return;
1774+
if (memcmp(elem_new->data, elem_old->data, elem_new->datalen))
1775+
return;
1776+
1777+
ecsa = (void *)elem_new->data;
1778+
1779+
if (!ecsa->mode)
1780+
return;
1781+
1782+
if (ecsa->new_ch_num !=
1783+
ieee80211_frequency_to_channel(known->pub.channel->center_freq))
1784+
return;
1785+
1786+
known->pub.proberesp_ecsa_stuck = 1;
1787+
}
1788+
17341789
static bool
17351790
cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
17361791
struct cfg80211_internal_bss *known,
@@ -1750,8 +1805,10 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
17501805
/* Override possible earlier Beacon frame IEs */
17511806
rcu_assign_pointer(known->pub.ies,
17521807
new->pub.proberesp_ies);
1753-
if (old)
1808+
if (old) {
1809+
cfg80211_check_stuck_ecsa(rdev, known, old);
17541810
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
1811+
}
17551812
}
17561813

17571814
if (rcu_access_pointer(new->pub.beacon_ies)) {

0 commit comments

Comments
 (0)