diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-07-12 06:30:59 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-07-13 14:49:43 -0400 |
commit | 95acac61ba66c4abd40e038dae8c1ed2e176c7b1 (patch) | |
tree | 8a1737bc3a2ca8af0031e1c2cda07608965ad282 | |
parent | 2fcf282471f04f465d0368e46e973e01504292b3 (diff) |
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>
-rw-r--r-- | include/net/mac80211.h | 23 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/key.h | 2 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 32 | ||||
-rw-r--r-- | net/mac80211/rx.c | 3 | ||||
-rw-r--r-- | net/mac80211/tx.c | 3 | ||||
-rw-r--r-- | net/mac80211/util.c | 27 |
7 files changed, 86 insertions, 6 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8ff3d8a1377c..ea2c8c36477c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -3024,6 +3024,29 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif); | |||
3024 | void ieee80211_connection_loss(struct ieee80211_vif *vif); | 3024 | void ieee80211_connection_loss(struct ieee80211_vif *vif); |
3025 | 3025 | ||
3026 | /** | 3026 | /** |
3027 | * ieee80211_resume_disconnect - disconnect from AP after resume | ||
3028 | * | ||
3029 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
3030 | * | ||
3031 | * Instructs mac80211 to disconnect from the AP after resume. | ||
3032 | * Drivers can use this after WoWLAN if they know that the | ||
3033 | * connection cannot be kept up, for example because keys were | ||
3034 | * used while the device was asleep but the replay counters or | ||
3035 | * similar cannot be retrieved from the device during resume. | ||
3036 | * | ||
3037 | * Note that due to implementation issues, if the driver uses | ||
3038 | * the reconfiguration functionality during resume the interface | ||
3039 | * will still be added as associated first during resume and then | ||
3040 | * disconnect normally later. | ||
3041 | * | ||
3042 | * This function can only be called from the resume callback and | ||
3043 | * the driver must not be holding any of its own locks while it | ||
3044 | * calls this function, or at least not any locks it needs in the | ||
3045 | * key configuration paths (if it supports HW crypto). | ||
3046 | */ | ||
3047 | void ieee80211_resume_disconnect(struct ieee80211_vif *vif); | ||
3048 | |||
3049 | /** | ||
3027 | * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm | 3050 | * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm |
3028 | * | 3051 | * |
3029 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | 3052 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 96600bec44c5..dda0d1ab34f3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -538,12 +538,14 @@ struct ieee80211_if_mesh { | |||
538 | * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between | 538 | * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between |
539 | * associated stations and deliver multicast frames both | 539 | * associated stations and deliver multicast frames both |
540 | * back to wireless media and to the local net stack. | 540 | * back to wireless media and to the local net stack. |
541 | * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume. | ||
541 | */ | 542 | */ |
542 | enum ieee80211_sub_if_data_flags { | 543 | enum ieee80211_sub_if_data_flags { |
543 | IEEE80211_SDATA_ALLMULTI = BIT(0), | 544 | IEEE80211_SDATA_ALLMULTI = BIT(0), |
544 | IEEE80211_SDATA_PROMISC = BIT(1), | 545 | IEEE80211_SDATA_PROMISC = BIT(1), |
545 | IEEE80211_SDATA_OPERATING_GMODE = BIT(2), | 546 | IEEE80211_SDATA_OPERATING_GMODE = BIT(2), |
546 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), | 547 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), |
548 | IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4), | ||
547 | }; | 549 | }; |
548 | 550 | ||
549 | /** | 551 | /** |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 86b216b01415..7d4e31f037d7 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -41,9 +41,11 @@ struct sta_info; | |||
41 | * | 41 | * |
42 | * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present | 42 | * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present |
43 | * in the hardware for TX crypto hardware acceleration. | 43 | * in the hardware for TX crypto hardware acceleration. |
44 | * @KEY_FLAG_TAINTED: Key is tainted and packets should be dropped. | ||
44 | */ | 45 | */ |
45 | enum ieee80211_internal_key_flags { | 46 | enum ieee80211_internal_key_flags { |
46 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), | 47 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), |
48 | KEY_FLAG_TAINTED = BIT(1), | ||
47 | }; | 49 | }; |
48 | 50 | ||
49 | enum ieee80211_internal_tkip_state { | 51 | enum ieee80211_internal_tkip_state { |
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) | |||
2052 | } | 2052 | } |
2053 | 2053 | ||
2054 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | 2054 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, |
2055 | u8 *bssid) | 2055 | u8 *bssid, u8 reason) |
2056 | { | 2056 | { |
2057 | struct ieee80211_local *local = sdata->local; | 2057 | struct ieee80211_local *local = sdata->local; |
2058 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2058 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -2070,8 +2070,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2070 | * but that's not a problem. | 2070 | * but that's not a problem. |
2071 | */ | 2071 | */ |
2072 | ieee80211_send_deauth_disassoc(sdata, bssid, | 2072 | ieee80211_send_deauth_disassoc(sdata, bssid, |
2073 | IEEE80211_STYPE_DEAUTH, | 2073 | IEEE80211_STYPE_DEAUTH, reason, |
2074 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
2075 | NULL, true); | 2074 | NULL, true); |
2076 | mutex_lock(&ifmgd->mtx); | 2075 | mutex_lock(&ifmgd->mtx); |
2077 | } | 2076 | } |
@@ -2117,7 +2116,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2117 | " AP %pM, disconnecting.\n", | 2116 | " AP %pM, disconnecting.\n", |
2118 | sdata->name, bssid); | 2117 | sdata->name, bssid); |
2119 | #endif | 2118 | #endif |
2120 | ieee80211_sta_connection_lost(sdata, bssid); | 2119 | ieee80211_sta_connection_lost(sdata, bssid, |
2120 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | ||
2121 | } | 2121 | } |
2122 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) | 2122 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) |
2123 | run_again(ifmgd, ifmgd->probe_timeout); | 2123 | run_again(ifmgd, ifmgd->probe_timeout); |
@@ -2129,7 +2129,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2129 | sdata->name, | 2129 | sdata->name, |
2130 | bssid, probe_wait_ms); | 2130 | bssid, probe_wait_ms); |
2131 | #endif | 2131 | #endif |
2132 | ieee80211_sta_connection_lost(sdata, bssid); | 2132 | ieee80211_sta_connection_lost(sdata, bssid, |
2133 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | ||
2133 | } else if (ifmgd->probe_send_count < max_tries) { | 2134 | } else if (ifmgd->probe_send_count < max_tries) { |
2134 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2135 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
2135 | wiphy_debug(local->hw.wiphy, | 2136 | wiphy_debug(local->hw.wiphy, |
@@ -2151,7 +2152,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2151 | sdata->name, | 2152 | sdata->name, |
2152 | bssid, probe_wait_ms); | 2153 | bssid, probe_wait_ms); |
2153 | 2154 | ||
2154 | ieee80211_sta_connection_lost(sdata, bssid); | 2155 | ieee80211_sta_connection_lost(sdata, bssid, |
2156 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | ||
2155 | } | 2157 | } |
2156 | } | 2158 | } |
2157 | 2159 | ||
@@ -2241,6 +2243,24 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | |||
2241 | if (!ifmgd->associated) | 2243 | if (!ifmgd->associated) |
2242 | return; | 2244 | return; |
2243 | 2245 | ||
2246 | if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { | ||
2247 | sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; | ||
2248 | mutex_lock(&ifmgd->mtx); | ||
2249 | if (ifmgd->associated) { | ||
2250 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
2251 | wiphy_debug(sdata->local->hw.wiphy, | ||
2252 | "%s: driver requested disconnect after resume.\n", | ||
2253 | sdata->name); | ||
2254 | #endif | ||
2255 | ieee80211_sta_connection_lost(sdata, | ||
2256 | ifmgd->associated->bssid, | ||
2257 | WLAN_REASON_UNSPECIFIED); | ||
2258 | mutex_unlock(&ifmgd->mtx); | ||
2259 | return; | ||
2260 | } | ||
2261 | mutex_unlock(&ifmgd->mtx); | ||
2262 | } | ||
2263 | |||
2244 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) | 2264 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) |
2245 | add_timer(&ifmgd->timer); | 2265 | add_timer(&ifmgd->timer); |
2246 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) | 2266 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e6dccc70931d..fe2c2a717793 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1019,6 +1019,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1019 | } | 1019 | } |
1020 | 1020 | ||
1021 | if (rx->key) { | 1021 | if (rx->key) { |
1022 | if (unlikely(rx->key->flags & KEY_FLAG_TAINTED)) | ||
1023 | return RX_DROP_MONITOR; | ||
1024 | |||
1022 | rx->key->tx_rx_count++; | 1025 | rx->key->tx_rx_count++; |
1023 | /* TODO: add threshold stuff again */ | 1026 | /* TODO: add threshold stuff again */ |
1024 | } else { | 1027 | } else { |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e8d0d2d22665..8cb0d2d0ac69 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -589,6 +589,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
589 | break; | 589 | break; |
590 | } | 590 | } |
591 | 591 | ||
592 | if (unlikely(tx->key && tx->key->flags & KEY_FLAG_TAINTED)) | ||
593 | return TX_DROP; | ||
594 | |||
592 | if (!skip_hw && tx->key && | 595 | if (!skip_hw && tx->key && |
593 | tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) | 596 | tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) |
594 | info->control.hw_key = &tx->key->conf; | 597 | info->control.hw_key = &tx->key->conf; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 190132063c99..5bfb80cba634 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1334,6 +1334,33 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1334 | return 0; | 1334 | return 0; |
1335 | } | 1335 | } |
1336 | 1336 | ||
1337 | void ieee80211_resume_disconnect(struct ieee80211_vif *vif) | ||
1338 | { | ||
1339 | struct ieee80211_sub_if_data *sdata; | ||
1340 | struct ieee80211_local *local; | ||
1341 | struct ieee80211_key *key; | ||
1342 | |||
1343 | if (WARN_ON(!vif)) | ||
1344 | return; | ||
1345 | |||
1346 | sdata = vif_to_sdata(vif); | ||
1347 | local = sdata->local; | ||
1348 | |||
1349 | if (WARN_ON(!local->resuming)) | ||
1350 | return; | ||
1351 | |||
1352 | if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) | ||
1353 | return; | ||
1354 | |||
1355 | sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME; | ||
1356 | |||
1357 | mutex_lock(&local->key_mtx); | ||
1358 | list_for_each_entry(key, &sdata->key_list, list) | ||
1359 | key->flags |= KEY_FLAG_TAINTED; | ||
1360 | mutex_unlock(&local->key_mtx); | ||
1361 | } | ||
1362 | EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect); | ||
1363 | |||
1337 | static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | 1364 | static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, |
1338 | enum ieee80211_smps_mode *smps_mode) | 1365 | enum ieee80211_smps_mode *smps_mode) |
1339 | { | 1366 | { |