summaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2015-06-14 15:53:46 +0200
committerJohannes Berg <johannes.berg@intel.com>2015-07-17 15:38:18 +0200
commitd51c2ea3704be07f030c78d57641d6b972e301ee (patch)
treeecaa23ed4251a33e7b7ba1629f23c9b2a82673b9 /net/mac80211/cfg.c
parentmac80211: enable assoc check for mesh interfaces (diff)
downloadlinux-d51c2ea3704be07f030c78d57641d6b972e301ee.tar.xz
linux-d51c2ea3704be07f030c78d57641d6b972e301ee.zip
mac80211: TDLS: correctly configure SMPS state
The IEEE802.11-2012 specification is vague regarding SMPS operation during TDLS. It does not define a clear way to transition between SMPS states. To avoid interop issues, set SMPS to off when TDLS peers are connected. Accomplish this by extending the definition of the AUTOMATIC state. If the driver forces a state other than OFF, disconnect all TDLS peers. While at it, avoid changing the SMPS state of the peer STA. We have no way to control it, so try and behave correctly towards it. Move the TDLS peer-teardown function to where the rest of the TDLS code resides. Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r--net/mac80211/cfg.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a32575bf0546..5789d8353505 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2368,6 +2368,8 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
const u8 *ap;
enum ieee80211_smps_mode old_req;
int err;
+ struct sta_info *sta;
+ bool tdls_peer_found = false;
lockdep_assert_held(&sdata->wdev.mtx);
@@ -2392,11 +2394,22 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
ap = sdata->u.mgd.associated->bssid;
+ rcu_read_lock();
+ list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
+ if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded ||
+ !test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ continue;
+
+ tdls_peer_found = true;
+ break;
+ }
+ rcu_read_unlock();
+
if (smps_mode == IEEE80211_SMPS_AUTOMATIC) {
- if (sdata->u.mgd.powersave)
- smps_mode = IEEE80211_SMPS_DYNAMIC;
- else
+ if (tdls_peer_found || !sdata->u.mgd.powersave)
smps_mode = IEEE80211_SMPS_OFF;
+ else
+ smps_mode = IEEE80211_SMPS_DYNAMIC;
}
/* send SM PS frame to AP */
@@ -2404,6 +2417,8 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
ap, ap);
if (err)
sdata->u.mgd.req_smps = old_req;
+ else if (smps_mode != IEEE80211_SMPS_OFF && tdls_peer_found)
+ ieee80211_teardown_tdls_peers(sdata);
return err;
}