diff options
Diffstat (limited to 'net/mac80211/key.c')
-rw-r--r-- | net/mac80211/key.c | 62 |
1 files changed, 41 insertions, 21 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 3e51dd7d98b3..e568d98167d0 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -260,25 +260,29 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
260 | int idx; | 260 | int idx; |
261 | bool defunikey, defmultikey, defmgmtkey; | 261 | bool defunikey, defmultikey, defmgmtkey; |
262 | 262 | ||
263 | /* caller must provide at least one old/new */ | ||
264 | if (WARN_ON(!new && !old)) | ||
265 | return; | ||
266 | |||
263 | if (new) | 267 | if (new) |
264 | list_add_tail(&new->list, &sdata->key_list); | 268 | list_add_tail(&new->list, &sdata->key_list); |
265 | 269 | ||
266 | if (sta && pairwise) { | 270 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); |
267 | rcu_assign_pointer(sta->ptk, new); | ||
268 | } else if (sta) { | ||
269 | if (old) | ||
270 | idx = old->conf.keyidx; | ||
271 | else | ||
272 | idx = new->conf.keyidx; | ||
273 | rcu_assign_pointer(sta->gtk[idx], new); | ||
274 | } else { | ||
275 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); | ||
276 | 271 | ||
277 | if (old) | 272 | if (old) |
278 | idx = old->conf.keyidx; | 273 | idx = old->conf.keyidx; |
279 | else | 274 | else |
280 | idx = new->conf.keyidx; | 275 | idx = new->conf.keyidx; |
281 | 276 | ||
277 | if (sta) { | ||
278 | if (pairwise) { | ||
279 | rcu_assign_pointer(sta->ptk[idx], new); | ||
280 | sta->ptk_idx = idx; | ||
281 | } else { | ||
282 | rcu_assign_pointer(sta->gtk[idx], new); | ||
283 | sta->gtk_idx = idx; | ||
284 | } | ||
285 | } else { | ||
282 | defunikey = old && | 286 | defunikey = old && |
283 | old == key_mtx_dereference(sdata->local, | 287 | old == key_mtx_dereference(sdata->local, |
284 | sdata->default_unicast_key); | 288 | sdata->default_unicast_key); |
@@ -312,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
312 | list_del(&old->list); | 316 | list_del(&old->list); |
313 | } | 317 | } |
314 | 318 | ||
315 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | 319 | struct ieee80211_key * |
316 | const u8 *key_data, | 320 | ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
317 | size_t seq_len, const u8 *seq) | 321 | const u8 *key_data, |
322 | size_t seq_len, const u8 *seq, | ||
323 | const struct ieee80211_cipher_scheme *cs) | ||
318 | { | 324 | { |
319 | struct ieee80211_key *key; | 325 | struct ieee80211_key *key; |
320 | int i, j, err; | 326 | int i, j, err; |
@@ -393,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
393 | return ERR_PTR(err); | 399 | return ERR_PTR(err); |
394 | } | 400 | } |
395 | break; | 401 | break; |
402 | default: | ||
403 | if (cs) { | ||
404 | size_t len = (seq_len > MAX_PN_LEN) ? | ||
405 | MAX_PN_LEN : seq_len; | ||
406 | |||
407 | key->conf.iv_len = cs->hdr_len; | ||
408 | key->conf.icv_len = cs->mic_len; | ||
409 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) | ||
410 | for (j = 0; j < len; j++) | ||
411 | key->u.gen.rx_pn[i][j] = | ||
412 | seq[len - j - 1]; | ||
413 | } | ||
396 | } | 414 | } |
397 | memcpy(key->conf.key, key_data, key_len); | 415 | memcpy(key->conf.key, key_data, key_len); |
398 | INIT_LIST_HEAD(&key->list); | 416 | INIT_LIST_HEAD(&key->list); |
@@ -475,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
475 | mutex_lock(&sdata->local->key_mtx); | 493 | mutex_lock(&sdata->local->key_mtx); |
476 | 494 | ||
477 | if (sta && pairwise) | 495 | if (sta && pairwise) |
478 | old_key = key_mtx_dereference(sdata->local, sta->ptk); | 496 | old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); |
479 | else if (sta) | 497 | else if (sta) |
480 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); | 498 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
481 | else | 499 | else |
@@ -625,8 +643,10 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, | |||
625 | list_add(&key->list, &keys); | 643 | list_add(&key->list, &keys); |
626 | } | 644 | } |
627 | 645 | ||
628 | key = key_mtx_dereference(local, sta->ptk); | 646 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { |
629 | if (key) { | 647 | key = key_mtx_dereference(local, sta->ptk[i]); |
648 | if (!key) | ||
649 | continue; | ||
630 | ieee80211_key_replace(key->sdata, key->sta, | 650 | ieee80211_key_replace(key->sdata, key->sta, |
631 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 651 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
632 | key, NULL); | 652 | key, NULL); |
@@ -877,7 +897,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, | |||
877 | 897 | ||
878 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, | 898 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, |
879 | keyconf->keylen, keyconf->key, | 899 | keyconf->keylen, keyconf->key, |
880 | 0, NULL); | 900 | 0, NULL, NULL); |
881 | if (IS_ERR(key)) | 901 | if (IS_ERR(key)) |
882 | return ERR_CAST(key); | 902 | return ERR_CAST(key); |
883 | 903 | ||