summaryrefslogtreecommitdiff
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-07-12 12:30:59 +0200
committerJohn W. Linville <linville@tuxdriver.com>2011-07-13 14:49:43 -0400
commit95acac61ba66c4abd40e038dae8c1ed2e176c7b1 (patch)
tree8a1737bc3a2ca8af0031e1c2cda07608965ad282 /net/mac80211/mlme.c
parent2fcf282471f04f465d0368e46e973e01504292b3 (diff)
downloadlwn-95acac61ba66c4abd40e038dae8c1ed2e176c7b1.tar.gz
lwn-95acac61ba66c4abd40e038dae8c1ed2e176c7b1.zip
mac80211: allow driver to disconnect after resume
In WoWLAN, devices may use crypto keys for TX/RX and could also implement GTK rekeying. If the driver isn't able to retrieve replay counters and similar information from the device upon resume, or if the device isn't responsive due to platform issues, it isn't safe to keep the connection up as GTK rekey messages from during the sleep time could be replayed against it. The only protection against that is disconnecting from the AP. Modifying mac80211 to do that while it is resuming would be very complex and invasive in the case that the driver requires a reconfig, so do it after it has resumed completely. In that case, however, packets might be replayed since it can then only happen after TX/RX are up again, so mark keys for interfaces that need to disconnect as "tainted" and drop all packets that are sent or received with those keys. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 4b0460ad8c8f..c99237cd4b98 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2052,7 +2052,7 @@ static void ieee80211_sta_timer(unsigned long data)
}
static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
- u8 *bssid)
+ u8 *bssid, u8 reason)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -2070,8 +2070,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
* but that's not a problem.
*/
ieee80211_send_deauth_disassoc(sdata, bssid,
- IEEE80211_STYPE_DEAUTH,
- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+ IEEE80211_STYPE_DEAUTH, reason,
NULL, true);
mutex_lock(&ifmgd->mtx);
}
@@ -2117,7 +2116,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
" AP %pM, disconnecting.\n",
sdata->name, bssid);
#endif
- ieee80211_sta_connection_lost(sdata, bssid);
+ ieee80211_sta_connection_lost(sdata, bssid,
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
}
} else if (time_is_after_jiffies(ifmgd->probe_timeout))
run_again(ifmgd, ifmgd->probe_timeout);
@@ -2129,7 +2129,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
sdata->name,
bssid, probe_wait_ms);
#endif
- ieee80211_sta_connection_lost(sdata, bssid);
+ ieee80211_sta_connection_lost(sdata, bssid,
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
} else if (ifmgd->probe_send_count < max_tries) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
wiphy_debug(local->hw.wiphy,
@@ -2151,7 +2152,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
sdata->name,
bssid, probe_wait_ms);
- ieee80211_sta_connection_lost(sdata, bssid);
+ ieee80211_sta_connection_lost(sdata, bssid,
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
}
}
@@ -2241,6 +2243,24 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
if (!ifmgd->associated)
return;
+ if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
+ sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
+ mutex_lock(&ifmgd->mtx);
+ if (ifmgd->associated) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ wiphy_debug(sdata->local->hw.wiphy,
+ "%s: driver requested disconnect after resume.\n",
+ sdata->name);
+#endif
+ ieee80211_sta_connection_lost(sdata,
+ ifmgd->associated->bssid,
+ WLAN_REASON_UNSPECIFIED);
+ mutex_unlock(&ifmgd->mtx);
+ return;
+ }
+ mutex_unlock(&ifmgd->mtx);
+ }
+
if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
add_timer(&ifmgd->timer);
if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))