| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright 2002-2005, Instant802 Networks, Inc. |
|---|
| 3 | 4 | * Copyright 2005-2006, Devicescape Software, Inc. |
|---|
| .. | .. |
|---|
| 5 | 6 | * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> |
|---|
| 6 | 7 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
|---|
| 7 | 8 | * Copyright 2015-2017 Intel Deutschland GmbH |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 11 | | - * published by the Free Software Foundation. |
|---|
| 9 | + * Copyright 2018-2020 Intel Corporation |
|---|
| 12 | 10 | */ |
|---|
| 13 | 11 | |
|---|
| 14 | 12 | #include <linux/if_ether.h> |
|---|
| .. | .. |
|---|
| 140 | 138 | * so clear that flag now to avoid trying to remove |
|---|
| 141 | 139 | * it again later. |
|---|
| 142 | 140 | */ |
|---|
| 141 | + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && |
|---|
| 142 | + !(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | |
|---|
| 143 | + IEEE80211_KEY_FLAG_PUT_MIC_SPACE | |
|---|
| 144 | + IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) |
|---|
| 145 | + increment_tailroom_need_count(sdata); |
|---|
| 146 | + |
|---|
| 143 | 147 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
|---|
| 144 | 148 | return -EINVAL; |
|---|
| 145 | 149 | } |
|---|
| .. | .. |
|---|
| 179 | 183 | if (!ret) { |
|---|
| 180 | 184 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
|---|
| 181 | 185 | |
|---|
| 182 | | - if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | |
|---|
| 183 | | - IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) || |
|---|
| 184 | | - (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) |
|---|
| 186 | + if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | |
|---|
| 187 | + IEEE80211_KEY_FLAG_PUT_MIC_SPACE | |
|---|
| 188 | + IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) |
|---|
| 185 | 189 | decrease_tailroom_need_count(sdata, 1); |
|---|
| 186 | 190 | |
|---|
| 187 | 191 | WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && |
|---|
| .. | .. |
|---|
| 206 | 210 | case WLAN_CIPHER_SUITE_TKIP: |
|---|
| 207 | 211 | case WLAN_CIPHER_SUITE_CCMP: |
|---|
| 208 | 212 | case WLAN_CIPHER_SUITE_CCMP_256: |
|---|
| 213 | + case WLAN_CIPHER_SUITE_GCMP: |
|---|
| 214 | + case WLAN_CIPHER_SUITE_GCMP_256: |
|---|
| 209 | 215 | case WLAN_CIPHER_SUITE_AES_CMAC: |
|---|
| 210 | 216 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: |
|---|
| 211 | 217 | case WLAN_CIPHER_SUITE_BIP_GMAC_128: |
|---|
| 212 | 218 | case WLAN_CIPHER_SUITE_BIP_GMAC_256: |
|---|
| 213 | | - case WLAN_CIPHER_SUITE_GCMP: |
|---|
| 214 | | - case WLAN_CIPHER_SUITE_GCMP_256: |
|---|
| 215 | 219 | /* all of these we can do in software - if driver can */ |
|---|
| 216 | 220 | if (ret == 1) |
|---|
| 217 | 221 | return 0; |
|---|
| .. | .. |
|---|
| 242 | 246 | sta = key->sta; |
|---|
| 243 | 247 | sdata = key->sdata; |
|---|
| 244 | 248 | |
|---|
| 245 | | - if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | |
|---|
| 246 | | - IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) || |
|---|
| 247 | | - (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) |
|---|
| 249 | + if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | |
|---|
| 250 | + IEEE80211_KEY_FLAG_PUT_MIC_SPACE | |
|---|
| 251 | + IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) |
|---|
| 248 | 252 | increment_tailroom_need_count(sdata); |
|---|
| 249 | 253 | |
|---|
| 254 | + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
|---|
| 250 | 255 | ret = drv_set_key(key->local, DISABLE_KEY, sdata, |
|---|
| 251 | 256 | sta ? &sta->sta : NULL, &key->conf); |
|---|
| 252 | 257 | |
|---|
| .. | .. |
|---|
| 255 | 260 | "failed to remove key (%d, %pM) from hardware (%d)\n", |
|---|
| 256 | 261 | key->conf.keyidx, |
|---|
| 257 | 262 | sta ? sta->sta.addr : bcast_addr, ret); |
|---|
| 263 | +} |
|---|
| 258 | 264 | |
|---|
| 259 | | - key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
|---|
| 265 | +static int _ieee80211_set_tx_key(struct ieee80211_key *key, bool force) |
|---|
| 266 | +{ |
|---|
| 267 | + struct sta_info *sta = key->sta; |
|---|
| 268 | + struct ieee80211_local *local = key->local; |
|---|
| 269 | + |
|---|
| 270 | + assert_key_lock(local); |
|---|
| 271 | + |
|---|
| 272 | + set_sta_flag(sta, WLAN_STA_USES_ENCRYPTION); |
|---|
| 273 | + |
|---|
| 274 | + sta->ptk_idx = key->conf.keyidx; |
|---|
| 275 | + |
|---|
| 276 | + if (force || !ieee80211_hw_check(&local->hw, AMPDU_KEYBORDER_SUPPORT)) |
|---|
| 277 | + clear_sta_flag(sta, WLAN_STA_BLOCK_BA); |
|---|
| 278 | + ieee80211_check_fast_xmit(sta); |
|---|
| 279 | + |
|---|
| 280 | + return 0; |
|---|
| 281 | +} |
|---|
| 282 | + |
|---|
| 283 | +int ieee80211_set_tx_key(struct ieee80211_key *key) |
|---|
| 284 | +{ |
|---|
| 285 | + return _ieee80211_set_tx_key(key, false); |
|---|
| 286 | +} |
|---|
| 287 | + |
|---|
| 288 | +static void ieee80211_pairwise_rekey(struct ieee80211_key *old, |
|---|
| 289 | + struct ieee80211_key *new) |
|---|
| 290 | +{ |
|---|
| 291 | + struct ieee80211_local *local = new->local; |
|---|
| 292 | + struct sta_info *sta = new->sta; |
|---|
| 293 | + int i; |
|---|
| 294 | + |
|---|
| 295 | + assert_key_lock(local); |
|---|
| 296 | + |
|---|
| 297 | + if (new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX) { |
|---|
| 298 | + /* Extended Key ID key install, initial one or rekey */ |
|---|
| 299 | + |
|---|
| 300 | + if (sta->ptk_idx != INVALID_PTK_KEYIDX && |
|---|
| 301 | + !ieee80211_hw_check(&local->hw, AMPDU_KEYBORDER_SUPPORT)) { |
|---|
| 302 | + /* Aggregation Sessions with Extended Key ID must not |
|---|
| 303 | + * mix MPDUs with different keyIDs within one A-MPDU. |
|---|
| 304 | + * Tear down running Tx aggregation sessions and block |
|---|
| 305 | + * new Rx/Tx aggregation requests during rekey to |
|---|
| 306 | + * ensure there are no A-MPDUs when the driver is not |
|---|
| 307 | + * supporting A-MPDU key borders. (Blocking Tx only |
|---|
| 308 | + * would be sufficient but WLAN_STA_BLOCK_BA gets the |
|---|
| 309 | + * job done for the few ms we need it.) |
|---|
| 310 | + */ |
|---|
| 311 | + set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
|---|
| 312 | + mutex_lock(&sta->ampdu_mlme.mtx); |
|---|
| 313 | + for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
|---|
| 314 | + ___ieee80211_stop_tx_ba_session(sta, i, |
|---|
| 315 | + AGG_STOP_LOCAL_REQUEST); |
|---|
| 316 | + mutex_unlock(&sta->ampdu_mlme.mtx); |
|---|
| 317 | + } |
|---|
| 318 | + } else if (old) { |
|---|
| 319 | + /* Rekey without Extended Key ID. |
|---|
| 320 | + * Aggregation sessions are OK when running on SW crypto. |
|---|
| 321 | + * A broken remote STA may cause issues not observed with HW |
|---|
| 322 | + * crypto, though. |
|---|
| 323 | + */ |
|---|
| 324 | + if (!(old->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) |
|---|
| 325 | + return; |
|---|
| 326 | + |
|---|
| 327 | + /* Stop Tx till we are on the new key */ |
|---|
| 328 | + old->flags |= KEY_FLAG_TAINTED; |
|---|
| 329 | + ieee80211_clear_fast_xmit(sta); |
|---|
| 330 | + if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION)) { |
|---|
| 331 | + set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
|---|
| 332 | + ieee80211_sta_tear_down_BA_sessions(sta, |
|---|
| 333 | + AGG_STOP_LOCAL_REQUEST); |
|---|
| 334 | + } |
|---|
| 335 | + if (!wiphy_ext_feature_isset(local->hw.wiphy, |
|---|
| 336 | + NL80211_EXT_FEATURE_CAN_REPLACE_PTK0)) { |
|---|
| 337 | + pr_warn_ratelimited("Rekeying PTK for STA %pM but driver can't safely do that.", |
|---|
| 338 | + sta->sta.addr); |
|---|
| 339 | + /* Flushing the driver queues *may* help prevent |
|---|
| 340 | + * the clear text leaks and freezes. |
|---|
| 341 | + */ |
|---|
| 342 | + ieee80211_flush_queues(local, old->sdata, false); |
|---|
| 343 | + } |
|---|
| 344 | + } |
|---|
| 260 | 345 | } |
|---|
| 261 | 346 | |
|---|
| 262 | 347 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, |
|---|
| .. | .. |
|---|
| 314 | 399 | mutex_unlock(&sdata->local->key_mtx); |
|---|
| 315 | 400 | } |
|---|
| 316 | 401 | |
|---|
| 402 | +static void |
|---|
| 403 | +__ieee80211_set_default_beacon_key(struct ieee80211_sub_if_data *sdata, int idx) |
|---|
| 404 | +{ |
|---|
| 405 | + struct ieee80211_key *key = NULL; |
|---|
| 317 | 406 | |
|---|
| 318 | | -static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, |
|---|
| 407 | + assert_key_lock(sdata->local); |
|---|
| 408 | + |
|---|
| 409 | + if (idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS && |
|---|
| 410 | + idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + |
|---|
| 411 | + NUM_DEFAULT_BEACON_KEYS) |
|---|
| 412 | + key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
|---|
| 413 | + |
|---|
| 414 | + rcu_assign_pointer(sdata->default_beacon_key, key); |
|---|
| 415 | + |
|---|
| 416 | + ieee80211_debugfs_key_update_default(sdata); |
|---|
| 417 | +} |
|---|
| 418 | + |
|---|
| 419 | +void ieee80211_set_default_beacon_key(struct ieee80211_sub_if_data *sdata, |
|---|
| 420 | + int idx) |
|---|
| 421 | +{ |
|---|
| 422 | + mutex_lock(&sdata->local->key_mtx); |
|---|
| 423 | + __ieee80211_set_default_beacon_key(sdata, idx); |
|---|
| 424 | + mutex_unlock(&sdata->local->key_mtx); |
|---|
| 425 | +} |
|---|
| 426 | + |
|---|
| 427 | +static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, |
|---|
| 319 | 428 | struct sta_info *sta, |
|---|
| 320 | 429 | bool pairwise, |
|---|
| 321 | 430 | struct ieee80211_key *old, |
|---|
| 322 | 431 | struct ieee80211_key *new) |
|---|
| 323 | 432 | { |
|---|
| 324 | 433 | int idx; |
|---|
| 325 | | - bool defunikey, defmultikey, defmgmtkey; |
|---|
| 434 | + int ret = 0; |
|---|
| 435 | + bool defunikey, defmultikey, defmgmtkey, defbeaconkey; |
|---|
| 326 | 436 | |
|---|
| 327 | 437 | /* caller must provide at least one old/new */ |
|---|
| 328 | 438 | if (WARN_ON(!new && !old)) |
|---|
| 329 | | - return; |
|---|
| 439 | + return 0; |
|---|
| 330 | 440 | |
|---|
| 331 | 441 | if (new) |
|---|
| 332 | 442 | list_add_tail_rcu(&new->list, &sdata->key_list); |
|---|
| 333 | 443 | |
|---|
| 334 | 444 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); |
|---|
| 335 | 445 | |
|---|
| 336 | | - if (old) |
|---|
| 446 | + if (new && sta && pairwise) { |
|---|
| 447 | + /* Unicast rekey needs special handling. With Extended Key ID |
|---|
| 448 | + * old is still NULL for the first rekey. |
|---|
| 449 | + */ |
|---|
| 450 | + ieee80211_pairwise_rekey(old, new); |
|---|
| 451 | + } |
|---|
| 452 | + |
|---|
| 453 | + if (old) { |
|---|
| 337 | 454 | idx = old->conf.keyidx; |
|---|
| 338 | | - else |
|---|
| 455 | + |
|---|
| 456 | + if (old->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { |
|---|
| 457 | + ieee80211_key_disable_hw_accel(old); |
|---|
| 458 | + |
|---|
| 459 | + if (new) |
|---|
| 460 | + ret = ieee80211_key_enable_hw_accel(new); |
|---|
| 461 | + } |
|---|
| 462 | + } else { |
|---|
| 463 | + /* new must be provided in case old is not */ |
|---|
| 339 | 464 | idx = new->conf.keyidx; |
|---|
| 465 | + if (!new->local->wowlan) |
|---|
| 466 | + ret = ieee80211_key_enable_hw_accel(new); |
|---|
| 467 | + } |
|---|
| 468 | + |
|---|
| 469 | + if (ret) |
|---|
| 470 | + return ret; |
|---|
| 340 | 471 | |
|---|
| 341 | 472 | if (sta) { |
|---|
| 342 | 473 | if (pairwise) { |
|---|
| 343 | 474 | rcu_assign_pointer(sta->ptk[idx], new); |
|---|
| 344 | | - set_sta_flag(sta, WLAN_STA_USES_ENCRYPTION); |
|---|
| 345 | | - sta->ptk_idx = idx; |
|---|
| 346 | | - ieee80211_check_fast_xmit(sta); |
|---|
| 475 | + if (new && |
|---|
| 476 | + !(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)) |
|---|
| 477 | + _ieee80211_set_tx_key(new, true); |
|---|
| 347 | 478 | } else { |
|---|
| 348 | 479 | rcu_assign_pointer(sta->gtk[idx], new); |
|---|
| 349 | 480 | } |
|---|
| 350 | | - ieee80211_check_fast_rx(sta); |
|---|
| 481 | + /* Only needed for transition from no key -> key. |
|---|
| 482 | + * Still triggers unnecessary when using Extended Key ID |
|---|
| 483 | + * and installing the second key ID the first time. |
|---|
| 484 | + */ |
|---|
| 485 | + if (new && !old) |
|---|
| 486 | + ieee80211_check_fast_rx(sta); |
|---|
| 351 | 487 | } else { |
|---|
| 352 | 488 | defunikey = old && |
|---|
| 353 | 489 | old == key_mtx_dereference(sdata->local, |
|---|
| .. | .. |
|---|
| 358 | 494 | defmgmtkey = old && |
|---|
| 359 | 495 | old == key_mtx_dereference(sdata->local, |
|---|
| 360 | 496 | sdata->default_mgmt_key); |
|---|
| 497 | + defbeaconkey = old && |
|---|
| 498 | + old == key_mtx_dereference(sdata->local, |
|---|
| 499 | + sdata->default_beacon_key); |
|---|
| 361 | 500 | |
|---|
| 362 | 501 | if (defunikey && !new) |
|---|
| 363 | 502 | __ieee80211_set_default_key(sdata, -1, true, false); |
|---|
| .. | .. |
|---|
| 365 | 504 | __ieee80211_set_default_key(sdata, -1, false, true); |
|---|
| 366 | 505 | if (defmgmtkey && !new) |
|---|
| 367 | 506 | __ieee80211_set_default_mgmt_key(sdata, -1); |
|---|
| 507 | + if (defbeaconkey && !new) |
|---|
| 508 | + __ieee80211_set_default_beacon_key(sdata, -1); |
|---|
| 368 | 509 | |
|---|
| 369 | 510 | rcu_assign_pointer(sdata->keys[idx], new); |
|---|
| 370 | 511 | if (defunikey && new) |
|---|
| .. | .. |
|---|
| 376 | 517 | if (defmgmtkey && new) |
|---|
| 377 | 518 | __ieee80211_set_default_mgmt_key(sdata, |
|---|
| 378 | 519 | new->conf.keyidx); |
|---|
| 520 | + if (defbeaconkey && new) |
|---|
| 521 | + __ieee80211_set_default_beacon_key(sdata, |
|---|
| 522 | + new->conf.keyidx); |
|---|
| 379 | 523 | } |
|---|
| 380 | 524 | |
|---|
| 381 | 525 | if (old) |
|---|
| 382 | 526 | list_del_rcu(&old->list); |
|---|
| 527 | + |
|---|
| 528 | + return 0; |
|---|
| 383 | 529 | } |
|---|
| 384 | 530 | |
|---|
| 385 | 531 | struct ieee80211_key * |
|---|
| .. | .. |
|---|
| 391 | 537 | struct ieee80211_key *key; |
|---|
| 392 | 538 | int i, j, err; |
|---|
| 393 | 539 | |
|---|
| 394 | | - if (WARN_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)) |
|---|
| 540 | + if (WARN_ON(idx < 0 || |
|---|
| 541 | + idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + |
|---|
| 542 | + NUM_DEFAULT_BEACON_KEYS)) |
|---|
| 395 | 543 | return ERR_PTR(-EINVAL); |
|---|
| 396 | 544 | |
|---|
| 397 | 545 | key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 569 | 717 | ieee80211_aes_gcm_key_free(key->u.gcmp.tfm); |
|---|
| 570 | 718 | break; |
|---|
| 571 | 719 | } |
|---|
| 572 | | - kzfree(key); |
|---|
| 720 | + kfree_sensitive(key); |
|---|
| 573 | 721 | } |
|---|
| 574 | 722 | |
|---|
| 575 | 723 | static void __ieee80211_key_destroy(struct ieee80211_key *key, |
|---|
| 576 | 724 | bool delay_tailroom) |
|---|
| 577 | 725 | { |
|---|
| 578 | | - if (key->local) |
|---|
| 579 | | - ieee80211_key_disable_hw_accel(key); |
|---|
| 580 | | - |
|---|
| 581 | 726 | if (key->local) { |
|---|
| 582 | 727 | struct ieee80211_sub_if_data *sdata = key->sdata; |
|---|
| 583 | 728 | |
|---|
| .. | .. |
|---|
| 655 | 800 | struct sta_info *sta) |
|---|
| 656 | 801 | { |
|---|
| 657 | 802 | static atomic_t key_color = ATOMIC_INIT(0); |
|---|
| 658 | | - struct ieee80211_local *local = sdata->local; |
|---|
| 659 | 803 | struct ieee80211_key *old_key; |
|---|
| 660 | 804 | int idx = key->conf.keyidx; |
|---|
| 661 | 805 | bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; |
|---|
| .. | .. |
|---|
| 665 | 809 | * can cause warnings to appear. |
|---|
| 666 | 810 | */ |
|---|
| 667 | 811 | bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION; |
|---|
| 668 | | - int ret; |
|---|
| 812 | + int ret = -EOPNOTSUPP; |
|---|
| 669 | 813 | |
|---|
| 670 | 814 | mutex_lock(&sdata->local->key_mtx); |
|---|
| 671 | 815 | |
|---|
| 672 | | - if (sta && pairwise) |
|---|
| 816 | + if (sta && pairwise) { |
|---|
| 817 | + struct ieee80211_key *alt_key; |
|---|
| 818 | + |
|---|
| 673 | 819 | old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); |
|---|
| 674 | | - else if (sta) |
|---|
| 820 | + alt_key = key_mtx_dereference(sdata->local, sta->ptk[idx ^ 1]); |
|---|
| 821 | + |
|---|
| 822 | + /* The rekey code assumes that the old and new key are using |
|---|
| 823 | + * the same cipher. Enforce the assumption for pairwise keys. |
|---|
| 824 | + */ |
|---|
| 825 | + if ((alt_key && alt_key->conf.cipher != key->conf.cipher) || |
|---|
| 826 | + (old_key && old_key->conf.cipher != key->conf.cipher)) |
|---|
| 827 | + goto out; |
|---|
| 828 | + } else if (sta) { |
|---|
| 675 | 829 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
|---|
| 676 | | - else |
|---|
| 830 | + } else { |
|---|
| 677 | 831 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
|---|
| 832 | + } |
|---|
| 833 | + |
|---|
| 834 | + /* Non-pairwise keys must also not switch the cipher on rekey */ |
|---|
| 835 | + if (!pairwise) { |
|---|
| 836 | + if (old_key && old_key->conf.cipher != key->conf.cipher) |
|---|
| 837 | + goto out; |
|---|
| 838 | + } |
|---|
| 678 | 839 | |
|---|
| 679 | 840 | /* |
|---|
| 680 | 841 | * Silently accept key re-installation without really installing the |
|---|
| .. | .. |
|---|
| 698 | 859 | |
|---|
| 699 | 860 | increment_tailroom_need_count(sdata); |
|---|
| 700 | 861 | |
|---|
| 701 | | - ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
|---|
| 702 | | - ieee80211_key_destroy(old_key, delay_tailroom); |
|---|
| 862 | + ret = ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
|---|
| 703 | 863 | |
|---|
| 704 | | - ieee80211_debugfs_key_add(key); |
|---|
| 705 | | - |
|---|
| 706 | | - if (!local->wowlan) { |
|---|
| 707 | | - ret = ieee80211_key_enable_hw_accel(key); |
|---|
| 708 | | - if (ret) |
|---|
| 709 | | - ieee80211_key_free(key, delay_tailroom); |
|---|
| 864 | + if (!ret) { |
|---|
| 865 | + ieee80211_debugfs_key_add(key); |
|---|
| 866 | + ieee80211_key_destroy(old_key, delay_tailroom); |
|---|
| 710 | 867 | } else { |
|---|
| 711 | | - ret = 0; |
|---|
| 868 | + ieee80211_key_free(key, delay_tailroom); |
|---|
| 712 | 869 | } |
|---|
| 713 | 870 | |
|---|
| 714 | 871 | out: |
|---|
| .. | .. |
|---|
| 732 | 889 | ieee80211_key_destroy(key, delay_tailroom); |
|---|
| 733 | 890 | } |
|---|
| 734 | 891 | |
|---|
| 735 | | -void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) |
|---|
| 892 | +void ieee80211_reenable_keys(struct ieee80211_sub_if_data *sdata) |
|---|
| 736 | 893 | { |
|---|
| 737 | 894 | struct ieee80211_key *key; |
|---|
| 738 | 895 | struct ieee80211_sub_if_data *vlan; |
|---|
| 739 | 896 | |
|---|
| 740 | 897 | ASSERT_RTNL(); |
|---|
| 741 | 898 | |
|---|
| 742 | | - if (WARN_ON(!ieee80211_sdata_running(sdata))) |
|---|
| 743 | | - return; |
|---|
| 744 | | - |
|---|
| 745 | | - mutex_lock(&sdata->local->key_mtx); |
|---|
| 746 | | - |
|---|
| 747 | | - WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || |
|---|
| 748 | | - sdata->crypto_tx_tailroom_pending_dec); |
|---|
| 749 | | - |
|---|
| 750 | | - if (sdata->vif.type == NL80211_IFTYPE_AP) { |
|---|
| 751 | | - list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
|---|
| 752 | | - WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt || |
|---|
| 753 | | - vlan->crypto_tx_tailroom_pending_dec); |
|---|
| 754 | | - } |
|---|
| 755 | | - |
|---|
| 756 | | - list_for_each_entry(key, &sdata->key_list, list) { |
|---|
| 757 | | - increment_tailroom_need_count(sdata); |
|---|
| 758 | | - ieee80211_key_enable_hw_accel(key); |
|---|
| 759 | | - } |
|---|
| 760 | | - |
|---|
| 761 | | - mutex_unlock(&sdata->local->key_mtx); |
|---|
| 762 | | -} |
|---|
| 763 | | - |
|---|
| 764 | | -void ieee80211_reset_crypto_tx_tailroom(struct ieee80211_sub_if_data *sdata) |
|---|
| 765 | | -{ |
|---|
| 766 | | - struct ieee80211_sub_if_data *vlan; |
|---|
| 767 | | - |
|---|
| 768 | 899 | mutex_lock(&sdata->local->key_mtx); |
|---|
| 769 | 900 | |
|---|
| 770 | 901 | sdata->crypto_tx_tailroom_needed_cnt = 0; |
|---|
| 902 | + sdata->crypto_tx_tailroom_pending_dec = 0; |
|---|
| 771 | 903 | |
|---|
| 772 | 904 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
|---|
| 773 | | - list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
|---|
| 905 | + list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { |
|---|
| 774 | 906 | vlan->crypto_tx_tailroom_needed_cnt = 0; |
|---|
| 907 | + vlan->crypto_tx_tailroom_pending_dec = 0; |
|---|
| 908 | + } |
|---|
| 909 | + } |
|---|
| 910 | + |
|---|
| 911 | + if (ieee80211_sdata_running(sdata)) { |
|---|
| 912 | + list_for_each_entry(key, &sdata->key_list, list) { |
|---|
| 913 | + increment_tailroom_need_count(sdata); |
|---|
| 914 | + ieee80211_key_enable_hw_accel(key); |
|---|
| 915 | + } |
|---|
| 775 | 916 | } |
|---|
| 776 | 917 | |
|---|
| 777 | 918 | mutex_unlock(&sdata->local->key_mtx); |
|---|
| .. | .. |
|---|
| 868 | 1009 | sdata->crypto_tx_tailroom_pending_dec = 0; |
|---|
| 869 | 1010 | |
|---|
| 870 | 1011 | ieee80211_debugfs_key_remove_mgmt_default(sdata); |
|---|
| 1012 | + ieee80211_debugfs_key_remove_beacon_default(sdata); |
|---|
| 871 | 1013 | |
|---|
| 872 | 1014 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) { |
|---|
| 873 | 1015 | ieee80211_key_replace(key->sdata, key->sta, |
|---|
| .. | .. |
|---|
| 1124 | 1266 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { |
|---|
| 1125 | 1267 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
|---|
| 1126 | 1268 | |
|---|
| 1127 | | - if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | |
|---|
| 1128 | | - IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) || |
|---|
| 1129 | | - (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) |
|---|
| 1269 | + if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | |
|---|
| 1270 | + IEEE80211_KEY_FLAG_PUT_MIC_SPACE | |
|---|
| 1271 | + IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) |
|---|
| 1130 | 1272 | increment_tailroom_need_count(key->sdata); |
|---|
| 1131 | 1273 | } |
|---|
| 1132 | 1274 | |
|---|