diff options
Diffstat (limited to 'net/mac80211/key.c')
-rw-r--r-- | net/mac80211/key.c | 63 |
1 files changed, 49 insertions, 14 deletions
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 |