diff options
author | Alexander Wetzel <alexander@wetzel-home.de> | 2019-03-19 16:34:08 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2019-04-26 07:02:11 -0400 |
commit | 96fc6efb9ad9d0cd8cbb4462f0eb2a07092649e6 (patch) | |
tree | 5c17bac2a0df2ddcc155aaaa158c32ab5f87f4bd | |
parent | 6cdd3979a2bdc16116c5b2eb09475abf54ba9e70 (diff) |
mac80211: IEEE 802.11 Extended Key ID support
Add support for Extended Key ID as defined in IEEE 802.11-2016.
- Implement the nl80211 API for Extended Key ID
- Extend mac80211 API to allow drivers to support Extended Key ID
- Enable Extended Key ID by default for drivers only supporting SW
crypto (e.g. mac80211_hwsim)
- Allow unicast Tx usage to be supressed (IEEE80211_KEY_FLAG_NO_AUTO_TX)
- Select the decryption key based on the MPDU keyid
- Enforce existing assumptions in the code that rekeys don't change the
cipher
Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
[remove module parameter]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/mac80211.h | 6 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 36 | ||||
-rw-r--r-- | net/mac80211/debugfs.c | 1 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/key.c | 63 | ||||
-rw-r--r-- | net/mac80211/key.h | 2 | ||||
-rw-r--r-- | net/mac80211/main.c | 5 | ||||
-rw-r--r-- | net/mac80211/rx.c | 74 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 9 | ||||
-rw-r--r-- | net/mac80211/tx.c | 13 |
10 files changed, 151 insertions, 60 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ac2ed8ec662b..c10abca55fde 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1697,6 +1697,7 @@ struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif); | |||
1697 | * @IEEE80211_KEY_FLAG_PUT_MIC_SPACE: This flag should be set by the driver for | 1697 | * @IEEE80211_KEY_FLAG_PUT_MIC_SPACE: This flag should be set by the driver for |
1698 | * a TKIP key if it only requires MIC space. Do not set together with | 1698 | * a TKIP key if it only requires MIC space. Do not set together with |
1699 | * @IEEE80211_KEY_FLAG_GENERATE_MMIC on the same key. | 1699 | * @IEEE80211_KEY_FLAG_GENERATE_MMIC on the same key. |
1700 | * @IEEE80211_KEY_FLAG_NO_AUTO_TX: Key needs explicit Tx activation. | ||
1700 | */ | 1701 | */ |
1701 | enum ieee80211_key_flags { | 1702 | enum ieee80211_key_flags { |
1702 | IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0), | 1703 | IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0), |
@@ -1708,6 +1709,7 @@ enum ieee80211_key_flags { | |||
1708 | IEEE80211_KEY_FLAG_RX_MGMT = BIT(6), | 1709 | IEEE80211_KEY_FLAG_RX_MGMT = BIT(6), |
1709 | IEEE80211_KEY_FLAG_RESERVE_TAILROOM = BIT(7), | 1710 | IEEE80211_KEY_FLAG_RESERVE_TAILROOM = BIT(7), |
1710 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE = BIT(8), | 1711 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE = BIT(8), |
1712 | IEEE80211_KEY_FLAG_NO_AUTO_TX = BIT(9), | ||
1711 | }; | 1713 | }; |
1712 | 1714 | ||
1713 | /** | 1715 | /** |
@@ -2243,6 +2245,9 @@ struct ieee80211_txq { | |||
2243 | * @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID | 2245 | * @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID |
2244 | * only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set. | 2246 | * only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set. |
2245 | * | 2247 | * |
2248 | * @IEEE80211_HW_EXT_KEY_ID_NATIVE: Driver and hardware are supporting Extended | ||
2249 | * Key ID and can handle two unicast keys per station for Rx and Tx. | ||
2250 | * | ||
2246 | * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays | 2251 | * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays |
2247 | */ | 2252 | */ |
2248 | enum ieee80211_hw_flags { | 2253 | enum ieee80211_hw_flags { |
@@ -2294,6 +2299,7 @@ enum ieee80211_hw_flags { | |||
2294 | IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN, | 2299 | IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN, |
2295 | IEEE80211_HW_SUPPORTS_MULTI_BSSID, | 2300 | IEEE80211_HW_SUPPORTS_MULTI_BSSID, |
2296 | IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID, | 2301 | IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID, |
2302 | IEEE80211_HW_EXT_KEY_ID_NATIVE, | ||
2297 | 2303 | ||
2298 | /* keep last, obviously */ | 2304 | /* keep last, obviously */ |
2299 | NUM_IEEE80211_HW_FLAGS | 2305 | NUM_IEEE80211_HW_FLAGS |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 09dd1c2860fc..14bbb7e8ad0e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -351,6 +351,36 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy, | |||
351 | return 0; | 351 | return 0; |
352 | } | 352 | } |
353 | 353 | ||
354 | static int ieee80211_set_tx(struct ieee80211_sub_if_data *sdata, | ||
355 | const u8 *mac_addr, u8 key_idx) | ||
356 | { | ||
357 | struct ieee80211_local *local = sdata->local; | ||
358 | struct ieee80211_key *key; | ||
359 | struct sta_info *sta; | ||
360 | int ret = -EINVAL; | ||
361 | |||
362 | if (!wiphy_ext_feature_isset(local->hw.wiphy, | ||
363 | NL80211_EXT_FEATURE_EXT_KEY_ID)) | ||
364 | return -EINVAL; | ||
365 | |||
366 | sta = sta_info_get_bss(sdata, mac_addr); | ||
367 | |||
368 | if (!sta) | ||
369 | return -EINVAL; | ||
370 | |||
371 | if (sta->ptk_idx == key_idx) | ||
372 | return 0; | ||
373 | |||
374 | mutex_lock(&local->key_mtx); | ||
375 | key = key_mtx_dereference(local, sta->ptk[key_idx]); | ||
376 | |||
377 | if (key && key->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX) | ||
378 | ret = ieee80211_set_tx_key(key); | ||
379 | |||
380 | mutex_unlock(&local->key_mtx); | ||
381 | return ret; | ||
382 | } | ||
383 | |||
354 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | 384 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, |
355 | u8 key_idx, bool pairwise, const u8 *mac_addr, | 385 | u8 key_idx, bool pairwise, const u8 *mac_addr, |
356 | struct key_params *params) | 386 | struct key_params *params) |
@@ -365,6 +395,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
365 | if (!ieee80211_sdata_running(sdata)) | 395 | if (!ieee80211_sdata_running(sdata)) |
366 | return -ENETDOWN; | 396 | return -ENETDOWN; |
367 | 397 | ||
398 | if (pairwise && params->mode == NL80211_KEY_SET_TX) | ||
399 | return ieee80211_set_tx(sdata, mac_addr, key_idx); | ||
400 | |||
368 | /* reject WEP and TKIP keys if WEP failed to initialize */ | 401 | /* reject WEP and TKIP keys if WEP failed to initialize */ |
369 | switch (params->cipher) { | 402 | switch (params->cipher) { |
370 | case WLAN_CIPHER_SUITE_WEP40: | 403 | case WLAN_CIPHER_SUITE_WEP40: |
@@ -396,6 +429,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
396 | if (pairwise) | 429 | if (pairwise) |
397 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; | 430 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; |
398 | 431 | ||
432 | if (params->mode == NL80211_KEY_NO_TX) | ||
433 | key->conf.flags |= IEEE80211_KEY_FLAG_NO_AUTO_TX; | ||
434 | |||
399 | mutex_lock(&local->sta_mtx); | 435 | mutex_lock(&local->sta_mtx); |
400 | 436 | ||
401 | if (mac_addr) { | 437 | if (mac_addr) { |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 2d43bc127043..aa6f23e1a457 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -221,6 +221,7 @@ static const char *hw_flag_names[] = { | |||
221 | FLAG(TX_STATUS_NO_AMPDU_LEN), | 221 | FLAG(TX_STATUS_NO_AMPDU_LEN), |
222 | FLAG(SUPPORTS_MULTI_BSSID), | 222 | FLAG(SUPPORTS_MULTI_BSSID), |
223 | FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID), | 223 | FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID), |
224 | FLAG(EXT_KEY_ID_NATIVE), | ||
224 | #undef FLAG | 225 | #undef FLAG |
225 | }; | 226 | }; |
226 | 227 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c5708f8a7401..32094e2ac0cb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1269,7 +1269,7 @@ struct ieee80211_local { | |||
1269 | 1269 | ||
1270 | /* | 1270 | /* |
1271 | * Key mutex, protects sdata's key_list and sta_info's | 1271 | * Key mutex, protects sdata's key_list and sta_info's |
1272 | * key pointers (write access, they're RCU.) | 1272 | * key pointers and ptk_idx (write access, they're RCU.) |
1273 | */ | 1273 | */ |
1274 | struct mutex key_mtx; | 1274 | struct mutex key_mtx; |
1275 | 1275 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 41b8db37c7c1..42d52cded4c1 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -265,9 +265,24 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
265 | sta ? sta->sta.addr : bcast_addr, ret); | 265 | sta ? sta->sta.addr : bcast_addr, ret); |
266 | } | 266 | } |
267 | 267 | ||
268 | int ieee80211_set_tx_key(struct ieee80211_key *key) | ||
269 | { | ||
270 | struct sta_info *sta = key->sta; | ||
271 | struct ieee80211_local *local = key->local; | ||
272 | struct ieee80211_key *old; | ||
273 | |||
274 | assert_key_lock(local); | ||
275 | |||
276 | old = key_mtx_dereference(local, sta->ptk[sta->ptk_idx]); | ||
277 | sta->ptk_idx = key->conf.keyidx; | ||
278 | ieee80211_check_fast_xmit(sta); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
268 | static int ieee80211_hw_key_replace(struct ieee80211_key *old_key, | 283 | static int ieee80211_hw_key_replace(struct ieee80211_key *old_key, |
269 | struct ieee80211_key *new_key, | 284 | struct ieee80211_key *new_key, |
270 | bool ptk0rekey) | 285 | bool pairwise) |
271 | { | 286 | { |
272 | struct ieee80211_sub_if_data *sdata; | 287 | struct ieee80211_sub_if_data *sdata; |
273 | struct ieee80211_local *local; | 288 | struct ieee80211_local *local; |
@@ -284,8 +299,9 @@ static int ieee80211_hw_key_replace(struct ieee80211_key *old_key, | |||
284 | assert_key_lock(old_key->local); | 299 | assert_key_lock(old_key->local); |
285 | sta = old_key->sta; | 300 | sta = old_key->sta; |
286 | 301 | ||
287 | /* PTK only using key ID 0 needs special handling on rekey */ | 302 | /* Unicast rekey without Extended Key ID needs special handling */ |
288 | if (new_key && sta && ptk0rekey) { | 303 | if (new_key && sta && pairwise && |
304 | rcu_access_pointer(sta->ptk[sta->ptk_idx]) == old_key) { | ||
289 | local = old_key->local; | 305 | local = old_key->local; |
290 | sdata = old_key->sdata; | 306 | sdata = old_key->sdata; |
291 | 307 | ||
@@ -401,10 +417,6 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
401 | 417 | ||
402 | if (old) { | 418 | if (old) { |
403 | idx = old->conf.keyidx; | 419 | idx = old->conf.keyidx; |
404 | /* TODO: proper implement and test "Extended Key ID for | ||
405 | * Individually Addressed Frames" from IEEE 802.11-2016. | ||
406 | * Till then always assume only key ID 0 is used for | ||
407 | * pairwise keys.*/ | ||
408 | ret = ieee80211_hw_key_replace(old, new, pairwise); | 420 | ret = ieee80211_hw_key_replace(old, new, pairwise); |
409 | } else { | 421 | } else { |
410 | /* new must be provided in case old is not */ | 422 | /* new must be provided in case old is not */ |
@@ -421,15 +433,20 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
421 | if (sta) { | 433 | if (sta) { |
422 | if (pairwise) { | 434 | if (pairwise) { |
423 | rcu_assign_pointer(sta->ptk[idx], new); | 435 | rcu_assign_pointer(sta->ptk[idx], new); |
424 | sta->ptk_idx = idx; | 436 | if (new && |
425 | if (new) { | 437 | !(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)) { |
438 | sta->ptk_idx = idx; | ||
426 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); | 439 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); |
427 | ieee80211_check_fast_xmit(sta); | 440 | ieee80211_check_fast_xmit(sta); |
428 | } | 441 | } |
429 | } else { | 442 | } else { |
430 | rcu_assign_pointer(sta->gtk[idx], new); | 443 | rcu_assign_pointer(sta->gtk[idx], new); |
431 | } | 444 | } |
432 | if (new) | 445 | /* Only needed for transition from no key -> key. |
446 | * Still triggers unnecessary when using Extended Key ID | ||
447 | * and installing the second key ID the first time. | ||
448 | */ | ||
449 | if (new && !old) | ||
433 | ieee80211_check_fast_rx(sta); | 450 | ieee80211_check_fast_rx(sta); |
434 | } else { | 451 | } else { |
435 | defunikey = old && | 452 | defunikey = old && |
@@ -745,16 +762,34 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
745 | * can cause warnings to appear. | 762 | * can cause warnings to appear. |
746 | */ | 763 | */ |
747 | bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION; | 764 | bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION; |
748 | int ret; | 765 | int ret = -EOPNOTSUPP; |
749 | 766 | ||
750 | mutex_lock(&sdata->local->key_mtx); | 767 | mutex_lock(&sdata->local->key_mtx); |
751 | 768 | ||
752 | if (sta && pairwise) | 769 | if (sta && pairwise) { |
770 | struct ieee80211_key *alt_key; | ||
771 | |||
753 | old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); | 772 | old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); |
754 | else if (sta) | 773 | alt_key = key_mtx_dereference(sdata->local, sta->ptk[idx ^ 1]); |
774 | |||
775 | /* The rekey code assumes that the old and new key are using | ||
776 | * the same cipher. Enforce the assumption for pairwise keys. | ||
777 | */ | ||
778 | if (key && | ||
779 | ((alt_key && alt_key->conf.cipher != key->conf.cipher) || | ||
780 | (old_key && old_key->conf.cipher != key->conf.cipher))) | ||
781 | goto out; | ||
782 | } else if (sta) { | ||
755 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); | 783 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
756 | else | 784 | } else { |
757 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); | 785 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
786 | } | ||
787 | |||
788 | /* Non-pairwise keys must also not switch the cipher on rekey */ | ||
789 | if (!pairwise) { | ||
790 | if (key && old_key && old_key->conf.cipher != key->conf.cipher) | ||
791 | goto out; | ||
792 | } | ||
758 | 793 | ||
759 | /* | 794 | /* |
760 | * Silently accept key re-installation without really installing the | 795 | * Silently accept key re-installation without really installing the |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index ebdb80b85dc3..f06fbd03d235 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #define NUM_DEFAULT_KEYS 4 | 19 | #define NUM_DEFAULT_KEYS 4 |
20 | #define NUM_DEFAULT_MGMT_KEYS 2 | 20 | #define NUM_DEFAULT_MGMT_KEYS 2 |
21 | #define INVALID_PTK_KEYIDX 2 /* Keyidx always pointing to a NULL key for PTK */ | ||
21 | 22 | ||
22 | struct ieee80211_local; | 23 | struct ieee80211_local; |
23 | struct ieee80211_sub_if_data; | 24 | struct ieee80211_sub_if_data; |
@@ -146,6 +147,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
146 | int ieee80211_key_link(struct ieee80211_key *key, | 147 | int ieee80211_key_link(struct ieee80211_key *key, |
147 | struct ieee80211_sub_if_data *sdata, | 148 | struct ieee80211_sub_if_data *sdata, |
148 | struct sta_info *sta); | 149 | struct sta_info *sta); |
150 | int ieee80211_set_tx_key(struct ieee80211_key *key); | ||
149 | void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom); | 151 | void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom); |
150 | void ieee80211_key_free_unused(struct ieee80211_key *key); | 152 | void ieee80211_key_free_unused(struct ieee80211_key *key); |
151 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | 153 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 800e67615e2a..5d6b93050c0b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -1051,6 +1051,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1051 | } | 1051 | } |
1052 | } | 1052 | } |
1053 | 1053 | ||
1054 | if (!local->ops->set_key || | ||
1055 | ieee80211_hw_check(&local->hw, EXT_KEY_ID_NATIVE)) | ||
1056 | wiphy_ext_feature_set(local->hw.wiphy, | ||
1057 | NL80211_EXT_FEATURE_EXT_KEY_ID); | ||
1058 | |||
1054 | /* | 1059 | /* |
1055 | * Calculate scan IE length -- we need this to alloc | 1060 | * Calculate scan IE length -- we need this to alloc |
1056 | * memory and to subtract from the driver limit. It | 1061 | * memory and to subtract from the driver limit. It |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7f8d93401ce0..4a03c18b39a8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1005,23 +1005,43 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
1005 | return -1; | 1005 | return -1; |
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | static int ieee80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, | 1008 | static int ieee80211_get_keyid(struct sk_buff *skb, |
1009 | struct sk_buff *skb) | 1009 | const struct ieee80211_cipher_scheme *cs) |
1010 | { | 1010 | { |
1011 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1011 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
1012 | __le16 fc; | 1012 | __le16 fc; |
1013 | int hdrlen; | 1013 | int hdrlen; |
1014 | int minlen; | ||
1015 | u8 key_idx_off; | ||
1016 | u8 key_idx_shift; | ||
1014 | u8 keyid; | 1017 | u8 keyid; |
1015 | 1018 | ||
1016 | fc = hdr->frame_control; | 1019 | fc = hdr->frame_control; |
1017 | hdrlen = ieee80211_hdrlen(fc); | 1020 | hdrlen = ieee80211_hdrlen(fc); |
1018 | 1021 | ||
1019 | if (skb->len < hdrlen + cs->hdr_len) | 1022 | if (cs) { |
1023 | minlen = hdrlen + cs->hdr_len; | ||
1024 | key_idx_off = hdrlen + cs->key_idx_off; | ||
1025 | key_idx_shift = cs->key_idx_shift; | ||
1026 | } else { | ||
1027 | /* WEP, TKIP, CCMP and GCMP */ | ||
1028 | minlen = hdrlen + IEEE80211_WEP_IV_LEN; | ||
1029 | key_idx_off = hdrlen + 3; | ||
1030 | key_idx_shift = 6; | ||
1031 | } | ||
1032 | |||
1033 | if (unlikely(skb->len < minlen)) | ||
1020 | return -EINVAL; | 1034 | return -EINVAL; |
1021 | 1035 | ||
1022 | skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1); | 1036 | skb_copy_bits(skb, key_idx_off, &keyid, 1); |
1023 | keyid &= cs->key_idx_mask; | 1037 | |
1024 | keyid >>= cs->key_idx_shift; | 1038 | if (cs) |
1039 | keyid &= cs->key_idx_mask; | ||
1040 | keyid >>= key_idx_shift; | ||
1041 | |||
1042 | /* cs could use more than the usual two bits for the keyid */ | ||
1043 | if (unlikely(keyid >= NUM_DEFAULT_KEYS)) | ||
1044 | return -EINVAL; | ||
1025 | 1045 | ||
1026 | return keyid; | 1046 | return keyid; |
1027 | } | 1047 | } |
@@ -1852,9 +1872,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1852 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 1872 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
1853 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1873 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
1854 | int keyidx; | 1874 | int keyidx; |
1855 | int hdrlen; | ||
1856 | ieee80211_rx_result result = RX_DROP_UNUSABLE; | 1875 | ieee80211_rx_result result = RX_DROP_UNUSABLE; |
1857 | struct ieee80211_key *sta_ptk = NULL; | 1876 | struct ieee80211_key *sta_ptk = NULL; |
1877 | struct ieee80211_key *ptk_idx = NULL; | ||
1858 | int mmie_keyidx = -1; | 1878 | int mmie_keyidx = -1; |
1859 | __le16 fc; | 1879 | __le16 fc; |
1860 | const struct ieee80211_cipher_scheme *cs = NULL; | 1880 | const struct ieee80211_cipher_scheme *cs = NULL; |
@@ -1892,21 +1912,24 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1892 | 1912 | ||
1893 | if (rx->sta) { | 1913 | if (rx->sta) { |
1894 | int keyid = rx->sta->ptk_idx; | 1914 | int keyid = rx->sta->ptk_idx; |
1915 | sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); | ||
1895 | 1916 | ||
1896 | if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) { | 1917 | if (ieee80211_has_protected(fc)) { |
1897 | cs = rx->sta->cipher_scheme; | 1918 | cs = rx->sta->cipher_scheme; |
1898 | keyid = ieee80211_get_cs_keyid(cs, rx->skb); | 1919 | keyid = ieee80211_get_keyid(rx->skb, cs); |
1920 | |||
1899 | if (unlikely(keyid < 0)) | 1921 | if (unlikely(keyid < 0)) |
1900 | return RX_DROP_UNUSABLE; | 1922 | return RX_DROP_UNUSABLE; |
1923 | |||
1924 | ptk_idx = rcu_dereference(rx->sta->ptk[keyid]); | ||
1901 | } | 1925 | } |
1902 | sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); | ||
1903 | } | 1926 | } |
1904 | 1927 | ||
1905 | if (!ieee80211_has_protected(fc)) | 1928 | if (!ieee80211_has_protected(fc)) |
1906 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); | 1929 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); |
1907 | 1930 | ||
1908 | if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) { | 1931 | if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) { |
1909 | rx->key = sta_ptk; | 1932 | rx->key = ptk_idx ? ptk_idx : sta_ptk; |
1910 | if ((status->flag & RX_FLAG_DECRYPTED) && | 1933 | if ((status->flag & RX_FLAG_DECRYPTED) && |
1911 | (status->flag & RX_FLAG_IV_STRIPPED)) | 1934 | (status->flag & RX_FLAG_IV_STRIPPED)) |
1912 | return RX_CONTINUE; | 1935 | return RX_CONTINUE; |
@@ -1966,8 +1989,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1966 | } | 1989 | } |
1967 | return RX_CONTINUE; | 1990 | return RX_CONTINUE; |
1968 | } else { | 1991 | } else { |
1969 | u8 keyid; | ||
1970 | |||
1971 | /* | 1992 | /* |
1972 | * The device doesn't give us the IV so we won't be | 1993 | * The device doesn't give us the IV so we won't be |
1973 | * able to look up the key. That's ok though, we | 1994 | * able to look up the key. That's ok though, we |
@@ -1981,23 +2002,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1981 | (status->flag & RX_FLAG_IV_STRIPPED)) | 2002 | (status->flag & RX_FLAG_IV_STRIPPED)) |
1982 | return RX_CONTINUE; | 2003 | return RX_CONTINUE; |
1983 | 2004 | ||
1984 | hdrlen = ieee80211_hdrlen(fc); | 2005 | keyidx = ieee80211_get_keyid(rx->skb, cs); |
1985 | |||
1986 | if (cs) { | ||
1987 | keyidx = ieee80211_get_cs_keyid(cs, rx->skb); | ||
1988 | 2006 | ||
1989 | if (unlikely(keyidx < 0)) | 2007 | if (unlikely(keyidx < 0)) |
1990 | return RX_DROP_UNUSABLE; | 2008 | return RX_DROP_UNUSABLE; |
1991 | } else { | ||
1992 | if (rx->skb->len < 8 + hdrlen) | ||
1993 | return RX_DROP_UNUSABLE; /* TODO: count this? */ | ||
1994 | /* | ||
1995 | * no need to call ieee80211_wep_get_keyidx, | ||
1996 | * it verifies a bunch of things we've done already | ||
1997 | */ | ||
1998 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); | ||
1999 | keyidx = keyid >> 6; | ||
2000 | } | ||
2001 | 2009 | ||
2002 | /* check per-station GTK first, if multicast packet */ | 2010 | /* check per-station GTK first, if multicast packet */ |
2003 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) | 2011 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) |
@@ -4042,12 +4050,8 @@ void ieee80211_check_fast_rx(struct sta_info *sta) | |||
4042 | case WLAN_CIPHER_SUITE_GCMP_256: | 4050 | case WLAN_CIPHER_SUITE_GCMP_256: |
4043 | break; | 4051 | break; |
4044 | default: | 4052 | default: |
4045 | /* we also don't want to deal with WEP or cipher scheme | 4053 | /* We also don't want to deal with |
4046 | * since those require looking up the key idx in the | 4054 | * WEP or cipher scheme. |
4047 | * frame, rather than assuming the PTK is used | ||
4048 | * (we need to revisit this once we implement the real | ||
4049 | * PTK index, which is now valid in the spec, but we | ||
4050 | * haven't implemented that part yet) | ||
4051 | */ | 4055 | */ |
4052 | goto clear_rcu; | 4056 | goto clear_rcu; |
4053 | } | 4057 | } |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a81e1279a76d..a4932ee3595c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -347,6 +347,15 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
347 | sta->sta.max_rx_aggregation_subframes = | 347 | sta->sta.max_rx_aggregation_subframes = |
348 | local->hw.max_rx_aggregation_subframes; | 348 | local->hw.max_rx_aggregation_subframes; |
349 | 349 | ||
350 | /* Extended Key ID needs to install keys for keyid 0 and 1 Rx-only. | ||
351 | * The Tx path starts to use a key as soon as the key slot ptk_idx | ||
352 | * references to is not NULL. To not use the initial Rx-only key | ||
353 | * prematurely for Tx initialize ptk_idx to an impossible PTK keyid | ||
354 | * which always will refer to a NULL key. | ||
355 | */ | ||
356 | BUILD_BUG_ON(ARRAY_SIZE(sta->ptk) <= INVALID_PTK_KEYIDX); | ||
357 | sta->ptk_idx = INVALID_PTK_KEYIDX; | ||
358 | |||
350 | sta->local = local; | 359 | sta->local = local; |
351 | sta->sdata = sdata; | 360 | sta->sdata = sdata; |
352 | sta->rx_stats.last_rx = jiffies; | 361 | sta->rx_stats.last_rx = jiffies; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a3c6053cdffe..c49fd1e961d0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -3001,23 +3001,15 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) | |||
3001 | switch (build.key->conf.cipher) { | 3001 | switch (build.key->conf.cipher) { |
3002 | case WLAN_CIPHER_SUITE_CCMP: | 3002 | case WLAN_CIPHER_SUITE_CCMP: |
3003 | case WLAN_CIPHER_SUITE_CCMP_256: | 3003 | case WLAN_CIPHER_SUITE_CCMP_256: |
3004 | /* add fixed key ID */ | 3004 | if (gen_iv) |
3005 | if (gen_iv) { | ||
3006 | (build.hdr + build.hdr_len)[3] = | ||
3007 | 0x20 | (build.key->conf.keyidx << 6); | ||
3008 | build.pn_offs = build.hdr_len; | 3005 | build.pn_offs = build.hdr_len; |
3009 | } | ||
3010 | if (gen_iv || iv_spc) | 3006 | if (gen_iv || iv_spc) |
3011 | build.hdr_len += IEEE80211_CCMP_HDR_LEN; | 3007 | build.hdr_len += IEEE80211_CCMP_HDR_LEN; |
3012 | break; | 3008 | break; |
3013 | case WLAN_CIPHER_SUITE_GCMP: | 3009 | case WLAN_CIPHER_SUITE_GCMP: |
3014 | case WLAN_CIPHER_SUITE_GCMP_256: | 3010 | case WLAN_CIPHER_SUITE_GCMP_256: |
3015 | /* add fixed key ID */ | 3011 | if (gen_iv) |
3016 | if (gen_iv) { | ||
3017 | (build.hdr + build.hdr_len)[3] = | ||
3018 | 0x20 | (build.key->conf.keyidx << 6); | ||
3019 | build.pn_offs = build.hdr_len; | 3012 | build.pn_offs = build.hdr_len; |
3020 | } | ||
3021 | if (gen_iv || iv_spc) | 3013 | if (gen_iv || iv_spc) |
3022 | build.hdr_len += IEEE80211_GCMP_HDR_LEN; | 3014 | build.hdr_len += IEEE80211_GCMP_HDR_LEN; |
3023 | break; | 3015 | break; |
@@ -3388,6 +3380,7 @@ static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, | |||
3388 | pn = atomic64_inc_return(&key->conf.tx_pn); | 3380 | pn = atomic64_inc_return(&key->conf.tx_pn); |
3389 | crypto_hdr[0] = pn; | 3381 | crypto_hdr[0] = pn; |
3390 | crypto_hdr[1] = pn >> 8; | 3382 | crypto_hdr[1] = pn >> 8; |
3383 | crypto_hdr[3] = 0x20 | (key->conf.keyidx << 6); | ||
3391 | crypto_hdr[4] = pn >> 16; | 3384 | crypto_hdr[4] = pn >> 16; |
3392 | crypto_hdr[5] = pn >> 24; | 3385 | crypto_hdr[5] = pn >> 24; |
3393 | crypto_hdr[6] = pn >> 32; | 3386 | crypto_hdr[6] = pn >> 32; |