aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-07-12 06:30:59 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-07-13 14:49:43 -0400
commit95acac61ba66c4abd40e038dae8c1ed2e176c7b1 (patch)
tree8a1737bc3a2ca8af0031e1c2cda07608965ad282
parent2fcf282471f04f465d0368e46e973e01504292b3 (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.h23
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/key.h2
-rw-r--r--net/mac80211/mlme.c32
-rw-r--r--net/mac80211/rx.c3
-rw-r--r--net/mac80211/tx.c3
-rw-r--r--net/mac80211/util.c27
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);
3024void ieee80211_connection_loss(struct ieee80211_vif *vif); 3024void 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 */
3047void 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 */
542enum ieee80211_sub_if_data_flags { 543enum 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 */
45enum ieee80211_internal_key_flags { 46enum 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
49enum ieee80211_internal_tkip_state { 51enum 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
2054static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, 2054static 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
1337void 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}
1362EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
1363
1337static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, 1364static 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{