Skip to content

Commit 1e1007a

Browse files
Yu Wanggregkh
authored andcommitted
mac80211: handle deauthentication/disassociation from TDLS peer
commit 79c92ca upstream. When receiving a deauthentication/disassociation frame from a TDLS peer, a station should not disconnect the current AP, but only disable the current TDLS link if it's enabled. Without this change, a TDLS issue can be reproduced by following the steps as below: 1. STA-1 and STA-2 are connected to AP, bidirection traffic is running between STA-1 and STA-2. 2. Set up TDLS link between STA-1 and STA-2, stay for a while, then teardown TDLS link. 3. Repeat step #2 and monitor the connection between STA and AP. During the test, one STA may send a deauthentication/disassociation frame to another, after TDLS teardown, with reason code 6/7, which means: Class 2/3 frame received from nonassociated STA. On receive this frame, the receiver STA will disconnect the current AP and then reconnect. It's not a expected behavior, purpose of this frame should be disabling the TDLS link, not the link with AP. Cc: stable@vger.kernel.org Signed-off-by: Yu Wang <yyuwang@codeaurora.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent ccf6a15 commit 1e1007a

3 files changed

Lines changed: 37 additions & 1 deletion

File tree

net/mac80211/ieee80211_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,6 +2183,9 @@ void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy,
21832183
const u8 *addr);
21842184
void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata);
21852185
void ieee80211_tdls_chsw_work(struct work_struct *wk);
2186+
void ieee80211_tdls_handle_disconnect(struct ieee80211_sub_if_data *sdata,
2187+
const u8 *peer, u16 reason);
2188+
const char *ieee80211_get_reason_code_string(u16 reason_code);
21862189

21872190
extern const struct ethtool_ops ieee80211_ethtool_ops;
21882191

net/mac80211/mlme.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2868,7 +2868,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
28682868
#define case_WLAN(type) \
28692869
case WLAN_REASON_##type: return #type
28702870

2871-
static const char *ieee80211_get_reason_code_string(u16 reason_code)
2871+
const char *ieee80211_get_reason_code_string(u16 reason_code)
28722872
{
28732873
switch (reason_code) {
28742874
case_WLAN(UNSPECIFIED);
@@ -2933,6 +2933,11 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
29332933
if (len < 24 + 2)
29342934
return;
29352935

2936+
if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) {
2937+
ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code);
2938+
return;
2939+
}
2940+
29362941
if (ifmgd->associated &&
29372942
ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) {
29382943
const u8 *bssid = ifmgd->associated->bssid;
@@ -2982,6 +2987,11 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
29822987

29832988
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
29842989

2990+
if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) {
2991+
ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code);
2992+
return;
2993+
}
2994+
29852995
sdata_info(sdata, "disassociated from %pM (Reason: %u=%s)\n",
29862996
mgmt->sa, reason_code,
29872997
ieee80211_get_reason_code_string(reason_code));

net/mac80211/tdls.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,3 +1992,26 @@ void ieee80211_tdls_chsw_work(struct work_struct *wk)
19921992
}
19931993
rtnl_unlock();
19941994
}
1995+
1996+
void ieee80211_tdls_handle_disconnect(struct ieee80211_sub_if_data *sdata,
1997+
const u8 *peer, u16 reason)
1998+
{
1999+
struct ieee80211_sta *sta;
2000+
2001+
rcu_read_lock();
2002+
sta = ieee80211_find_sta(&sdata->vif, peer);
2003+
if (!sta || !sta->tdls) {
2004+
rcu_read_unlock();
2005+
return;
2006+
}
2007+
rcu_read_unlock();
2008+
2009+
tdls_dbg(sdata, "disconnected from TDLS peer %pM (Reason: %u=%s)\n",
2010+
peer, reason,
2011+
ieee80211_get_reason_code_string(reason));
2012+
2013+
ieee80211_tdls_oper_request(&sdata->vif, peer,
2014+
NL80211_TDLS_TEARDOWN,
2015+
WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE,
2016+
GFP_ATOMIC);
2017+
}

0 commit comments

Comments
 (0)