162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2002-2005, Instant802 Networks, Inc.
462306a36Sopenharmony_ci * Copyright 2005-2006, Devicescape Software, Inc.
562306a36Sopenharmony_ci * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
662306a36Sopenharmony_ci * Copyright 2007-2008	Johannes Berg <johannes@sipsolutions.net>
762306a36Sopenharmony_ci * Copyright 2013-2014  Intel Mobile Communications GmbH
862306a36Sopenharmony_ci * Copyright 2015-2017	Intel Deutschland GmbH
962306a36Sopenharmony_ci * Copyright 2018-2020, 2022-2023  Intel Corporation
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <crypto/utils.h>
1362306a36Sopenharmony_ci#include <linux/if_ether.h>
1462306a36Sopenharmony_ci#include <linux/etherdevice.h>
1562306a36Sopenharmony_ci#include <linux/list.h>
1662306a36Sopenharmony_ci#include <linux/rcupdate.h>
1762306a36Sopenharmony_ci#include <linux/rtnetlink.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/export.h>
2062306a36Sopenharmony_ci#include <net/mac80211.h>
2162306a36Sopenharmony_ci#include <asm/unaligned.h>
2262306a36Sopenharmony_ci#include "ieee80211_i.h"
2362306a36Sopenharmony_ci#include "driver-ops.h"
2462306a36Sopenharmony_ci#include "debugfs_key.h"
2562306a36Sopenharmony_ci#include "aes_ccm.h"
2662306a36Sopenharmony_ci#include "aes_cmac.h"
2762306a36Sopenharmony_ci#include "aes_gmac.h"
2862306a36Sopenharmony_ci#include "aes_gcm.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/**
3262306a36Sopenharmony_ci * DOC: Key handling basics
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * Key handling in mac80211 is done based on per-interface (sub_if_data)
3562306a36Sopenharmony_ci * keys and per-station keys. Since each station belongs to an interface,
3662306a36Sopenharmony_ci * each station key also belongs to that interface.
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * Hardware acceleration is done on a best-effort basis for algorithms
3962306a36Sopenharmony_ci * that are implemented in software,  for each key the hardware is asked
4062306a36Sopenharmony_ci * to enable that key for offloading but if it cannot do that the key is
4162306a36Sopenharmony_ci * simply kept for software encryption (unless it is for an algorithm
4262306a36Sopenharmony_ci * that isn't implemented in software).
4362306a36Sopenharmony_ci * There is currently no way of knowing whether a key is handled in SW
4462306a36Sopenharmony_ci * or HW except by looking into debugfs.
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * All key management is internally protected by a mutex. Within all
4762306a36Sopenharmony_ci * other parts of mac80211, key references are, just as STA structure
4862306a36Sopenharmony_ci * references, protected by RCU. Note, however, that some things are
4962306a36Sopenharmony_ci * unprotected, namely the key->sta dereferences within the hardware
5062306a36Sopenharmony_ci * acceleration functions. This means that sta_info_destroy() must
5162306a36Sopenharmony_ci * remove the key which waits for an RCU grace period.
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic void assert_key_lock(struct ieee80211_local *local)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	lockdep_assert_held(&local->key_mtx);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void
6262306a36Sopenharmony_ciupdate_vlan_tailroom_need_count(struct ieee80211_sub_if_data *sdata, int delta)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct ieee80211_sub_if_data *vlan;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (sdata->vif.type != NL80211_IFTYPE_AP)
6762306a36Sopenharmony_ci		return;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* crypto_tx_tailroom_needed_cnt is protected by this */
7062306a36Sopenharmony_ci	assert_key_lock(sdata->local);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	rcu_read_lock();
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	list_for_each_entry_rcu(vlan, &sdata->u.ap.vlans, u.vlan.list)
7562306a36Sopenharmony_ci		vlan->crypto_tx_tailroom_needed_cnt += delta;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	rcu_read_unlock();
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	/*
8362306a36Sopenharmony_ci	 * When this count is zero, SKB resizing for allocating tailroom
8462306a36Sopenharmony_ci	 * for IV or MMIC is skipped. But, this check has created two race
8562306a36Sopenharmony_ci	 * cases in xmit path while transiting from zero count to one:
8662306a36Sopenharmony_ci	 *
8762306a36Sopenharmony_ci	 * 1. SKB resize was skipped because no key was added but just before
8862306a36Sopenharmony_ci	 * the xmit key is added and SW encryption kicks off.
8962306a36Sopenharmony_ci	 *
9062306a36Sopenharmony_ci	 * 2. SKB resize was skipped because all the keys were hw planted but
9162306a36Sopenharmony_ci	 * just before xmit one of the key is deleted and SW encryption kicks
9262306a36Sopenharmony_ci	 * off.
9362306a36Sopenharmony_ci	 *
9462306a36Sopenharmony_ci	 * In both the above case SW encryption will find not enough space for
9562306a36Sopenharmony_ci	 * tailroom and exits with WARN_ON. (See WARN_ONs at wpa.c)
9662306a36Sopenharmony_ci	 *
9762306a36Sopenharmony_ci	 * Solution has been explained at
9862306a36Sopenharmony_ci	 * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net
9962306a36Sopenharmony_ci	 */
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	assert_key_lock(sdata->local);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	update_vlan_tailroom_need_count(sdata, 1);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (!sdata->crypto_tx_tailroom_needed_cnt++) {
10662306a36Sopenharmony_ci		/*
10762306a36Sopenharmony_ci		 * Flush all XMIT packets currently using HW encryption or no
10862306a36Sopenharmony_ci		 * encryption at all if the count transition is from 0 -> 1.
10962306a36Sopenharmony_ci		 */
11062306a36Sopenharmony_ci		synchronize_net();
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic void decrease_tailroom_need_count(struct ieee80211_sub_if_data *sdata,
11562306a36Sopenharmony_ci					 int delta)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	assert_key_lock(sdata->local);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt < delta);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	update_vlan_tailroom_need_count(sdata, -delta);
12262306a36Sopenharmony_ci	sdata->crypto_tx_tailroom_needed_cnt -= delta;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = key->sdata;
12862306a36Sopenharmony_ci	struct sta_info *sta;
12962306a36Sopenharmony_ci	int ret = -EOPNOTSUPP;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	might_sleep();
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (key->flags & KEY_FLAG_TAINTED) {
13462306a36Sopenharmony_ci		/* If we get here, it's during resume and the key is
13562306a36Sopenharmony_ci		 * tainted so shouldn't be used/programmed any more.
13662306a36Sopenharmony_ci		 * However, its flags may still indicate that it was
13762306a36Sopenharmony_ci		 * programmed into the device (since we're in resume)
13862306a36Sopenharmony_ci		 * so clear that flag now to avoid trying to remove
13962306a36Sopenharmony_ci		 * it again later.
14062306a36Sopenharmony_ci		 */
14162306a36Sopenharmony_ci		if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
14262306a36Sopenharmony_ci		    !(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
14362306a36Sopenharmony_ci					 IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
14462306a36Sopenharmony_ci					 IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
14562306a36Sopenharmony_ci			increment_tailroom_need_count(sdata);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
14862306a36Sopenharmony_ci		return -EINVAL;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (!key->local->ops->set_key)
15262306a36Sopenharmony_ci		goto out_unsupported;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	assert_key_lock(key->local);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	sta = key->sta;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/*
15962306a36Sopenharmony_ci	 * If this is a per-STA GTK, check if it
16062306a36Sopenharmony_ci	 * is supported; if not, return.
16162306a36Sopenharmony_ci	 */
16262306a36Sopenharmony_ci	if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
16362306a36Sopenharmony_ci	    !ieee80211_hw_check(&key->local->hw, SUPPORTS_PER_STA_GTK))
16462306a36Sopenharmony_ci		goto out_unsupported;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (sta && !sta->uploaded)
16762306a36Sopenharmony_ci		goto out_unsupported;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
17062306a36Sopenharmony_ci		/*
17162306a36Sopenharmony_ci		 * The driver doesn't know anything about VLAN interfaces.
17262306a36Sopenharmony_ci		 * Hence, don't send GTKs for VLAN interfaces to the driver.
17362306a36Sopenharmony_ci		 */
17462306a36Sopenharmony_ci		if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
17562306a36Sopenharmony_ci			ret = 1;
17662306a36Sopenharmony_ci			goto out_unsupported;
17762306a36Sopenharmony_ci		}
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (key->conf.link_id >= 0 && sdata->vif.active_links &&
18162306a36Sopenharmony_ci	    !(sdata->vif.active_links & BIT(key->conf.link_id)))
18262306a36Sopenharmony_ci		return 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	ret = drv_set_key(key->local, SET_KEY, sdata,
18562306a36Sopenharmony_ci			  sta ? &sta->sta : NULL, &key->conf);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (!ret) {
18862306a36Sopenharmony_ci		key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
19162306a36Sopenharmony_ci					 IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
19262306a36Sopenharmony_ci					 IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
19362306a36Sopenharmony_ci			decrease_tailroom_need_count(sdata, 1);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
19662306a36Sopenharmony_ci			(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV));
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_MIC_SPACE) &&
19962306a36Sopenharmony_ci			(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC));
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		return 0;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (ret != -ENOSPC && ret != -EOPNOTSUPP && ret != 1)
20562306a36Sopenharmony_ci		sdata_err(sdata,
20662306a36Sopenharmony_ci			  "failed to set key (%d, %pM) to hardware (%d)\n",
20762306a36Sopenharmony_ci			  key->conf.keyidx,
20862306a36Sopenharmony_ci			  sta ? sta->sta.addr : bcast_addr, ret);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci out_unsupported:
21162306a36Sopenharmony_ci	switch (key->conf.cipher) {
21262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
21362306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
21462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
21562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
21662306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
21762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
21862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
21962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
22062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
22162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
22262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
22362306a36Sopenharmony_ci		/* all of these we can do in software - if driver can */
22462306a36Sopenharmony_ci		if (ret == 1)
22562306a36Sopenharmony_ci			return 0;
22662306a36Sopenharmony_ci		if (ieee80211_hw_check(&key->local->hw, SW_CRYPTO_CONTROL))
22762306a36Sopenharmony_ci			return -EINVAL;
22862306a36Sopenharmony_ci		return 0;
22962306a36Sopenharmony_ci	default:
23062306a36Sopenharmony_ci		return -EINVAL;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
23762306a36Sopenharmony_ci	struct sta_info *sta;
23862306a36Sopenharmony_ci	int ret;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	might_sleep();
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (!key || !key->local->ops->set_key)
24362306a36Sopenharmony_ci		return;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	assert_key_lock(key->local);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
24862306a36Sopenharmony_ci		return;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	sta = key->sta;
25162306a36Sopenharmony_ci	sdata = key->sdata;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (key->conf.link_id >= 0 && sdata->vif.active_links &&
25462306a36Sopenharmony_ci	    !(sdata->vif.active_links & BIT(key->conf.link_id)))
25562306a36Sopenharmony_ci		return;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
25862306a36Sopenharmony_ci				 IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
25962306a36Sopenharmony_ci				 IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
26062306a36Sopenharmony_ci		increment_tailroom_need_count(sdata);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
26362306a36Sopenharmony_ci	ret = drv_set_key(key->local, DISABLE_KEY, sdata,
26462306a36Sopenharmony_ci			  sta ? &sta->sta : NULL, &key->conf);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (ret)
26762306a36Sopenharmony_ci		sdata_err(sdata,
26862306a36Sopenharmony_ci			  "failed to remove key (%d, %pM) from hardware (%d)\n",
26962306a36Sopenharmony_ci			  key->conf.keyidx,
27062306a36Sopenharmony_ci			  sta ? sta->sta.addr : bcast_addr, ret);
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic int _ieee80211_set_tx_key(struct ieee80211_key *key, bool force)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct sta_info *sta = key->sta;
27662306a36Sopenharmony_ci	struct ieee80211_local *local = key->local;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	assert_key_lock(local);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	set_sta_flag(sta, WLAN_STA_USES_ENCRYPTION);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	sta->ptk_idx = key->conf.keyidx;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (force || !ieee80211_hw_check(&local->hw, AMPDU_KEYBORDER_SUPPORT))
28562306a36Sopenharmony_ci		clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
28662306a36Sopenharmony_ci	ieee80211_check_fast_xmit(sta);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	return 0;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ciint ieee80211_set_tx_key(struct ieee80211_key *key)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	return _ieee80211_set_tx_key(key, false);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void ieee80211_pairwise_rekey(struct ieee80211_key *old,
29762306a36Sopenharmony_ci				     struct ieee80211_key *new)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct ieee80211_local *local = new->local;
30062306a36Sopenharmony_ci	struct sta_info *sta = new->sta;
30162306a36Sopenharmony_ci	int i;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	assert_key_lock(local);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX) {
30662306a36Sopenharmony_ci		/* Extended Key ID key install, initial one or rekey */
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		if (sta->ptk_idx != INVALID_PTK_KEYIDX &&
30962306a36Sopenharmony_ci		    !ieee80211_hw_check(&local->hw, AMPDU_KEYBORDER_SUPPORT)) {
31062306a36Sopenharmony_ci			/* Aggregation Sessions with Extended Key ID must not
31162306a36Sopenharmony_ci			 * mix MPDUs with different keyIDs within one A-MPDU.
31262306a36Sopenharmony_ci			 * Tear down running Tx aggregation sessions and block
31362306a36Sopenharmony_ci			 * new Rx/Tx aggregation requests during rekey to
31462306a36Sopenharmony_ci			 * ensure there are no A-MPDUs when the driver is not
31562306a36Sopenharmony_ci			 * supporting A-MPDU key borders. (Blocking Tx only
31662306a36Sopenharmony_ci			 * would be sufficient but WLAN_STA_BLOCK_BA gets the
31762306a36Sopenharmony_ci			 * job done for the few ms we need it.)
31862306a36Sopenharmony_ci			 */
31962306a36Sopenharmony_ci			set_sta_flag(sta, WLAN_STA_BLOCK_BA);
32062306a36Sopenharmony_ci			mutex_lock(&sta->ampdu_mlme.mtx);
32162306a36Sopenharmony_ci			for (i = 0; i <  IEEE80211_NUM_TIDS; i++)
32262306a36Sopenharmony_ci				___ieee80211_stop_tx_ba_session(sta, i,
32362306a36Sopenharmony_ci								AGG_STOP_LOCAL_REQUEST);
32462306a36Sopenharmony_ci			mutex_unlock(&sta->ampdu_mlme.mtx);
32562306a36Sopenharmony_ci		}
32662306a36Sopenharmony_ci	} else if (old) {
32762306a36Sopenharmony_ci		/* Rekey without Extended Key ID.
32862306a36Sopenharmony_ci		 * Aggregation sessions are OK when running on SW crypto.
32962306a36Sopenharmony_ci		 * A broken remote STA may cause issues not observed with HW
33062306a36Sopenharmony_ci		 * crypto, though.
33162306a36Sopenharmony_ci		 */
33262306a36Sopenharmony_ci		if (!(old->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
33362306a36Sopenharmony_ci			return;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci		/* Stop Tx till we are on the new key */
33662306a36Sopenharmony_ci		old->flags |= KEY_FLAG_TAINTED;
33762306a36Sopenharmony_ci		ieee80211_clear_fast_xmit(sta);
33862306a36Sopenharmony_ci		if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION)) {
33962306a36Sopenharmony_ci			set_sta_flag(sta, WLAN_STA_BLOCK_BA);
34062306a36Sopenharmony_ci			ieee80211_sta_tear_down_BA_sessions(sta,
34162306a36Sopenharmony_ci							    AGG_STOP_LOCAL_REQUEST);
34262306a36Sopenharmony_ci		}
34362306a36Sopenharmony_ci		if (!wiphy_ext_feature_isset(local->hw.wiphy,
34462306a36Sopenharmony_ci					     NL80211_EXT_FEATURE_CAN_REPLACE_PTK0)) {
34562306a36Sopenharmony_ci			pr_warn_ratelimited("Rekeying PTK for STA %pM but driver can't safely do that.",
34662306a36Sopenharmony_ci					    sta->sta.addr);
34762306a36Sopenharmony_ci			/* Flushing the driver queues *may* help prevent
34862306a36Sopenharmony_ci			 * the clear text leaks and freezes.
34962306a36Sopenharmony_ci			 */
35062306a36Sopenharmony_ci			ieee80211_flush_queues(local, old->sdata, false);
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic void __ieee80211_set_default_key(struct ieee80211_link_data *link,
35662306a36Sopenharmony_ci					int idx, bool uni, bool multi)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = link->sdata;
35962306a36Sopenharmony_ci	struct ieee80211_key *key = NULL;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	assert_key_lock(sdata->local);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (idx >= 0 && idx < NUM_DEFAULT_KEYS) {
36462306a36Sopenharmony_ci		key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
36562306a36Sopenharmony_ci		if (!key)
36662306a36Sopenharmony_ci			key = key_mtx_dereference(sdata->local, link->gtk[idx]);
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (uni) {
37062306a36Sopenharmony_ci		rcu_assign_pointer(sdata->default_unicast_key, key);
37162306a36Sopenharmony_ci		ieee80211_check_fast_xmit_iface(sdata);
37262306a36Sopenharmony_ci		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
37362306a36Sopenharmony_ci			drv_set_default_unicast_key(sdata->local, sdata, idx);
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (multi)
37762306a36Sopenharmony_ci		rcu_assign_pointer(link->default_multicast_key, key);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	ieee80211_debugfs_key_update_default(sdata);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_civoid ieee80211_set_default_key(struct ieee80211_link_data *link, int idx,
38362306a36Sopenharmony_ci			       bool uni, bool multi)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	mutex_lock(&link->sdata->local->key_mtx);
38662306a36Sopenharmony_ci	__ieee80211_set_default_key(link, idx, uni, multi);
38762306a36Sopenharmony_ci	mutex_unlock(&link->sdata->local->key_mtx);
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic void
39162306a36Sopenharmony_ci__ieee80211_set_default_mgmt_key(struct ieee80211_link_data *link, int idx)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = link->sdata;
39462306a36Sopenharmony_ci	struct ieee80211_key *key = NULL;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	assert_key_lock(sdata->local);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (idx >= NUM_DEFAULT_KEYS &&
39962306a36Sopenharmony_ci	    idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
40062306a36Sopenharmony_ci		key = key_mtx_dereference(sdata->local, link->gtk[idx]);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	rcu_assign_pointer(link->default_mgmt_key, key);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	ieee80211_debugfs_key_update_default(sdata);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_civoid ieee80211_set_default_mgmt_key(struct ieee80211_link_data *link,
40862306a36Sopenharmony_ci				    int idx)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	mutex_lock(&link->sdata->local->key_mtx);
41162306a36Sopenharmony_ci	__ieee80211_set_default_mgmt_key(link, idx);
41262306a36Sopenharmony_ci	mutex_unlock(&link->sdata->local->key_mtx);
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic void
41662306a36Sopenharmony_ci__ieee80211_set_default_beacon_key(struct ieee80211_link_data *link, int idx)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = link->sdata;
41962306a36Sopenharmony_ci	struct ieee80211_key *key = NULL;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	assert_key_lock(sdata->local);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS &&
42462306a36Sopenharmony_ci	    idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
42562306a36Sopenharmony_ci	    NUM_DEFAULT_BEACON_KEYS)
42662306a36Sopenharmony_ci		key = key_mtx_dereference(sdata->local, link->gtk[idx]);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	rcu_assign_pointer(link->default_beacon_key, key);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	ieee80211_debugfs_key_update_default(sdata);
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_civoid ieee80211_set_default_beacon_key(struct ieee80211_link_data *link,
43462306a36Sopenharmony_ci				      int idx)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	mutex_lock(&link->sdata->local->key_mtx);
43762306a36Sopenharmony_ci	__ieee80211_set_default_beacon_key(link, idx);
43862306a36Sopenharmony_ci	mutex_unlock(&link->sdata->local->key_mtx);
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
44262306a36Sopenharmony_ci				 struct ieee80211_link_data *link,
44362306a36Sopenharmony_ci				 struct sta_info *sta,
44462306a36Sopenharmony_ci				 bool pairwise,
44562306a36Sopenharmony_ci				 struct ieee80211_key *old,
44662306a36Sopenharmony_ci				 struct ieee80211_key *new)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	struct link_sta_info *link_sta = sta ? &sta->deflink : NULL;
44962306a36Sopenharmony_ci	int link_id;
45062306a36Sopenharmony_ci	int idx;
45162306a36Sopenharmony_ci	int ret = 0;
45262306a36Sopenharmony_ci	bool defunikey, defmultikey, defmgmtkey, defbeaconkey;
45362306a36Sopenharmony_ci	bool is_wep;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/* caller must provide at least one old/new */
45662306a36Sopenharmony_ci	if (WARN_ON(!new && !old))
45762306a36Sopenharmony_ci		return 0;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (new) {
46062306a36Sopenharmony_ci		idx = new->conf.keyidx;
46162306a36Sopenharmony_ci		is_wep = new->conf.cipher == WLAN_CIPHER_SUITE_WEP40 ||
46262306a36Sopenharmony_ci			 new->conf.cipher == WLAN_CIPHER_SUITE_WEP104;
46362306a36Sopenharmony_ci		link_id = new->conf.link_id;
46462306a36Sopenharmony_ci	} else {
46562306a36Sopenharmony_ci		idx = old->conf.keyidx;
46662306a36Sopenharmony_ci		is_wep = old->conf.cipher == WLAN_CIPHER_SUITE_WEP40 ||
46762306a36Sopenharmony_ci			 old->conf.cipher == WLAN_CIPHER_SUITE_WEP104;
46862306a36Sopenharmony_ci		link_id = old->conf.link_id;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (WARN(old && old->conf.link_id != link_id,
47262306a36Sopenharmony_ci		 "old link ID %d doesn't match new link ID %d\n",
47362306a36Sopenharmony_ci		 old->conf.link_id, link_id))
47462306a36Sopenharmony_ci		return -EINVAL;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (link_id >= 0) {
47762306a36Sopenharmony_ci		if (!link) {
47862306a36Sopenharmony_ci			link = sdata_dereference(sdata->link[link_id], sdata);
47962306a36Sopenharmony_ci			if (!link)
48062306a36Sopenharmony_ci				return -ENOLINK;
48162306a36Sopenharmony_ci		}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		if (sta) {
48462306a36Sopenharmony_ci			link_sta = rcu_dereference_protected(sta->link[link_id],
48562306a36Sopenharmony_ci							     lockdep_is_held(&sta->local->sta_mtx));
48662306a36Sopenharmony_ci			if (!link_sta)
48762306a36Sopenharmony_ci				return -ENOLINK;
48862306a36Sopenharmony_ci		}
48962306a36Sopenharmony_ci	} else {
49062306a36Sopenharmony_ci		link = &sdata->deflink;
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if ((is_wep || pairwise) && idx >= NUM_DEFAULT_KEYS)
49462306a36Sopenharmony_ci		return -EINVAL;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (new && sta && pairwise) {
49962306a36Sopenharmony_ci		/* Unicast rekey needs special handling. With Extended Key ID
50062306a36Sopenharmony_ci		 * old is still NULL for the first rekey.
50162306a36Sopenharmony_ci		 */
50262306a36Sopenharmony_ci		ieee80211_pairwise_rekey(old, new);
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (old) {
50662306a36Sopenharmony_ci		if (old->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
50762306a36Sopenharmony_ci			ieee80211_key_disable_hw_accel(old);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci			if (new)
51062306a36Sopenharmony_ci				ret = ieee80211_key_enable_hw_accel(new);
51162306a36Sopenharmony_ci		}
51262306a36Sopenharmony_ci	} else {
51362306a36Sopenharmony_ci		if (!new->local->wowlan) {
51462306a36Sopenharmony_ci			ret = ieee80211_key_enable_hw_accel(new);
51562306a36Sopenharmony_ci		} else {
51662306a36Sopenharmony_ci			assert_key_lock(new->local);
51762306a36Sopenharmony_ci			new->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
51862306a36Sopenharmony_ci		}
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (ret)
52262306a36Sopenharmony_ci		return ret;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (new)
52562306a36Sopenharmony_ci		list_add_tail_rcu(&new->list, &sdata->key_list);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (sta) {
52862306a36Sopenharmony_ci		if (pairwise) {
52962306a36Sopenharmony_ci			rcu_assign_pointer(sta->ptk[idx], new);
53062306a36Sopenharmony_ci			if (new &&
53162306a36Sopenharmony_ci			    !(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX))
53262306a36Sopenharmony_ci				_ieee80211_set_tx_key(new, true);
53362306a36Sopenharmony_ci		} else {
53462306a36Sopenharmony_ci			rcu_assign_pointer(link_sta->gtk[idx], new);
53562306a36Sopenharmony_ci		}
53662306a36Sopenharmony_ci		/* Only needed for transition from no key -> key.
53762306a36Sopenharmony_ci		 * Still triggers unnecessary when using Extended Key ID
53862306a36Sopenharmony_ci		 * and installing the second key ID the first time.
53962306a36Sopenharmony_ci		 */
54062306a36Sopenharmony_ci		if (new && !old)
54162306a36Sopenharmony_ci			ieee80211_check_fast_rx(sta);
54262306a36Sopenharmony_ci	} else {
54362306a36Sopenharmony_ci		defunikey = old &&
54462306a36Sopenharmony_ci			old == key_mtx_dereference(sdata->local,
54562306a36Sopenharmony_ci						sdata->default_unicast_key);
54662306a36Sopenharmony_ci		defmultikey = old &&
54762306a36Sopenharmony_ci			old == key_mtx_dereference(sdata->local,
54862306a36Sopenharmony_ci						   link->default_multicast_key);
54962306a36Sopenharmony_ci		defmgmtkey = old &&
55062306a36Sopenharmony_ci			old == key_mtx_dereference(sdata->local,
55162306a36Sopenharmony_ci						   link->default_mgmt_key);
55262306a36Sopenharmony_ci		defbeaconkey = old &&
55362306a36Sopenharmony_ci			old == key_mtx_dereference(sdata->local,
55462306a36Sopenharmony_ci						   link->default_beacon_key);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		if (defunikey && !new)
55762306a36Sopenharmony_ci			__ieee80211_set_default_key(link, -1, true, false);
55862306a36Sopenharmony_ci		if (defmultikey && !new)
55962306a36Sopenharmony_ci			__ieee80211_set_default_key(link, -1, false, true);
56062306a36Sopenharmony_ci		if (defmgmtkey && !new)
56162306a36Sopenharmony_ci			__ieee80211_set_default_mgmt_key(link, -1);
56262306a36Sopenharmony_ci		if (defbeaconkey && !new)
56362306a36Sopenharmony_ci			__ieee80211_set_default_beacon_key(link, -1);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		if (is_wep || pairwise)
56662306a36Sopenharmony_ci			rcu_assign_pointer(sdata->keys[idx], new);
56762306a36Sopenharmony_ci		else
56862306a36Sopenharmony_ci			rcu_assign_pointer(link->gtk[idx], new);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		if (defunikey && new)
57162306a36Sopenharmony_ci			__ieee80211_set_default_key(link, new->conf.keyidx,
57262306a36Sopenharmony_ci						    true, false);
57362306a36Sopenharmony_ci		if (defmultikey && new)
57462306a36Sopenharmony_ci			__ieee80211_set_default_key(link, new->conf.keyidx,
57562306a36Sopenharmony_ci						    false, true);
57662306a36Sopenharmony_ci		if (defmgmtkey && new)
57762306a36Sopenharmony_ci			__ieee80211_set_default_mgmt_key(link,
57862306a36Sopenharmony_ci							 new->conf.keyidx);
57962306a36Sopenharmony_ci		if (defbeaconkey && new)
58062306a36Sopenharmony_ci			__ieee80211_set_default_beacon_key(link,
58162306a36Sopenharmony_ci							   new->conf.keyidx);
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (old)
58562306a36Sopenharmony_ci		list_del_rcu(&old->list);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	return 0;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistruct ieee80211_key *
59162306a36Sopenharmony_ciieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
59262306a36Sopenharmony_ci		    const u8 *key_data,
59362306a36Sopenharmony_ci		    size_t seq_len, const u8 *seq)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	struct ieee80211_key *key;
59662306a36Sopenharmony_ci	int i, j, err;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (WARN_ON(idx < 0 ||
59962306a36Sopenharmony_ci		    idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
60062306a36Sopenharmony_ci		    NUM_DEFAULT_BEACON_KEYS))
60162306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
60462306a36Sopenharmony_ci	if (!key)
60562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	/*
60862306a36Sopenharmony_ci	 * Default to software encryption; we'll later upload the
60962306a36Sopenharmony_ci	 * key to the hardware if possible.
61062306a36Sopenharmony_ci	 */
61162306a36Sopenharmony_ci	key->conf.flags = 0;
61262306a36Sopenharmony_ci	key->flags = 0;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	key->conf.link_id = -1;
61562306a36Sopenharmony_ci	key->conf.cipher = cipher;
61662306a36Sopenharmony_ci	key->conf.keyidx = idx;
61762306a36Sopenharmony_ci	key->conf.keylen = key_len;
61862306a36Sopenharmony_ci	switch (cipher) {
61962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
62062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
62162306a36Sopenharmony_ci		key->conf.iv_len = IEEE80211_WEP_IV_LEN;
62262306a36Sopenharmony_ci		key->conf.icv_len = IEEE80211_WEP_ICV_LEN;
62362306a36Sopenharmony_ci		break;
62462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
62562306a36Sopenharmony_ci		key->conf.iv_len = IEEE80211_TKIP_IV_LEN;
62662306a36Sopenharmony_ci		key->conf.icv_len = IEEE80211_TKIP_ICV_LEN;
62762306a36Sopenharmony_ci		if (seq) {
62862306a36Sopenharmony_ci			for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
62962306a36Sopenharmony_ci				key->u.tkip.rx[i].iv32 =
63062306a36Sopenharmony_ci					get_unaligned_le32(&seq[2]);
63162306a36Sopenharmony_ci				key->u.tkip.rx[i].iv16 =
63262306a36Sopenharmony_ci					get_unaligned_le16(seq);
63362306a36Sopenharmony_ci			}
63462306a36Sopenharmony_ci		}
63562306a36Sopenharmony_ci		spin_lock_init(&key->u.tkip.txlock);
63662306a36Sopenharmony_ci		break;
63762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
63862306a36Sopenharmony_ci		key->conf.iv_len = IEEE80211_CCMP_HDR_LEN;
63962306a36Sopenharmony_ci		key->conf.icv_len = IEEE80211_CCMP_MIC_LEN;
64062306a36Sopenharmony_ci		if (seq) {
64162306a36Sopenharmony_ci			for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
64262306a36Sopenharmony_ci				for (j = 0; j < IEEE80211_CCMP_PN_LEN; j++)
64362306a36Sopenharmony_ci					key->u.ccmp.rx_pn[i][j] =
64462306a36Sopenharmony_ci						seq[IEEE80211_CCMP_PN_LEN - j - 1];
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci		/*
64762306a36Sopenharmony_ci		 * Initialize AES key state here as an optimization so that
64862306a36Sopenharmony_ci		 * it does not need to be initialized for every packet.
64962306a36Sopenharmony_ci		 */
65062306a36Sopenharmony_ci		key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
65162306a36Sopenharmony_ci			key_data, key_len, IEEE80211_CCMP_MIC_LEN);
65262306a36Sopenharmony_ci		if (IS_ERR(key->u.ccmp.tfm)) {
65362306a36Sopenharmony_ci			err = PTR_ERR(key->u.ccmp.tfm);
65462306a36Sopenharmony_ci			kfree(key);
65562306a36Sopenharmony_ci			return ERR_PTR(err);
65662306a36Sopenharmony_ci		}
65762306a36Sopenharmony_ci		break;
65862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
65962306a36Sopenharmony_ci		key->conf.iv_len = IEEE80211_CCMP_256_HDR_LEN;
66062306a36Sopenharmony_ci		key->conf.icv_len = IEEE80211_CCMP_256_MIC_LEN;
66162306a36Sopenharmony_ci		for (i = 0; seq && i < IEEE80211_NUM_TIDS + 1; i++)
66262306a36Sopenharmony_ci			for (j = 0; j < IEEE80211_CCMP_256_PN_LEN; j++)
66362306a36Sopenharmony_ci				key->u.ccmp.rx_pn[i][j] =
66462306a36Sopenharmony_ci					seq[IEEE80211_CCMP_256_PN_LEN - j - 1];
66562306a36Sopenharmony_ci		/* Initialize AES key state here as an optimization so that
66662306a36Sopenharmony_ci		 * it does not need to be initialized for every packet.
66762306a36Sopenharmony_ci		 */
66862306a36Sopenharmony_ci		key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
66962306a36Sopenharmony_ci			key_data, key_len, IEEE80211_CCMP_256_MIC_LEN);
67062306a36Sopenharmony_ci		if (IS_ERR(key->u.ccmp.tfm)) {
67162306a36Sopenharmony_ci			err = PTR_ERR(key->u.ccmp.tfm);
67262306a36Sopenharmony_ci			kfree(key);
67362306a36Sopenharmony_ci			return ERR_PTR(err);
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci		break;
67662306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
67762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
67862306a36Sopenharmony_ci		key->conf.iv_len = 0;
67962306a36Sopenharmony_ci		if (cipher == WLAN_CIPHER_SUITE_AES_CMAC)
68062306a36Sopenharmony_ci			key->conf.icv_len = sizeof(struct ieee80211_mmie);
68162306a36Sopenharmony_ci		else
68262306a36Sopenharmony_ci			key->conf.icv_len = sizeof(struct ieee80211_mmie_16);
68362306a36Sopenharmony_ci		if (seq)
68462306a36Sopenharmony_ci			for (j = 0; j < IEEE80211_CMAC_PN_LEN; j++)
68562306a36Sopenharmony_ci				key->u.aes_cmac.rx_pn[j] =
68662306a36Sopenharmony_ci					seq[IEEE80211_CMAC_PN_LEN - j - 1];
68762306a36Sopenharmony_ci		/*
68862306a36Sopenharmony_ci		 * Initialize AES key state here as an optimization so that
68962306a36Sopenharmony_ci		 * it does not need to be initialized for every packet.
69062306a36Sopenharmony_ci		 */
69162306a36Sopenharmony_ci		key->u.aes_cmac.tfm =
69262306a36Sopenharmony_ci			ieee80211_aes_cmac_key_setup(key_data, key_len);
69362306a36Sopenharmony_ci		if (IS_ERR(key->u.aes_cmac.tfm)) {
69462306a36Sopenharmony_ci			err = PTR_ERR(key->u.aes_cmac.tfm);
69562306a36Sopenharmony_ci			kfree(key);
69662306a36Sopenharmony_ci			return ERR_PTR(err);
69762306a36Sopenharmony_ci		}
69862306a36Sopenharmony_ci		break;
69962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
70062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
70162306a36Sopenharmony_ci		key->conf.iv_len = 0;
70262306a36Sopenharmony_ci		key->conf.icv_len = sizeof(struct ieee80211_mmie_16);
70362306a36Sopenharmony_ci		if (seq)
70462306a36Sopenharmony_ci			for (j = 0; j < IEEE80211_GMAC_PN_LEN; j++)
70562306a36Sopenharmony_ci				key->u.aes_gmac.rx_pn[j] =
70662306a36Sopenharmony_ci					seq[IEEE80211_GMAC_PN_LEN - j - 1];
70762306a36Sopenharmony_ci		/* Initialize AES key state here as an optimization so that
70862306a36Sopenharmony_ci		 * it does not need to be initialized for every packet.
70962306a36Sopenharmony_ci		 */
71062306a36Sopenharmony_ci		key->u.aes_gmac.tfm =
71162306a36Sopenharmony_ci			ieee80211_aes_gmac_key_setup(key_data, key_len);
71262306a36Sopenharmony_ci		if (IS_ERR(key->u.aes_gmac.tfm)) {
71362306a36Sopenharmony_ci			err = PTR_ERR(key->u.aes_gmac.tfm);
71462306a36Sopenharmony_ci			kfree(key);
71562306a36Sopenharmony_ci			return ERR_PTR(err);
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci		break;
71862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
71962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
72062306a36Sopenharmony_ci		key->conf.iv_len = IEEE80211_GCMP_HDR_LEN;
72162306a36Sopenharmony_ci		key->conf.icv_len = IEEE80211_GCMP_MIC_LEN;
72262306a36Sopenharmony_ci		for (i = 0; seq && i < IEEE80211_NUM_TIDS + 1; i++)
72362306a36Sopenharmony_ci			for (j = 0; j < IEEE80211_GCMP_PN_LEN; j++)
72462306a36Sopenharmony_ci				key->u.gcmp.rx_pn[i][j] =
72562306a36Sopenharmony_ci					seq[IEEE80211_GCMP_PN_LEN - j - 1];
72662306a36Sopenharmony_ci		/* Initialize AES key state here as an optimization so that
72762306a36Sopenharmony_ci		 * it does not need to be initialized for every packet.
72862306a36Sopenharmony_ci		 */
72962306a36Sopenharmony_ci		key->u.gcmp.tfm = ieee80211_aes_gcm_key_setup_encrypt(key_data,
73062306a36Sopenharmony_ci								      key_len);
73162306a36Sopenharmony_ci		if (IS_ERR(key->u.gcmp.tfm)) {
73262306a36Sopenharmony_ci			err = PTR_ERR(key->u.gcmp.tfm);
73362306a36Sopenharmony_ci			kfree(key);
73462306a36Sopenharmony_ci			return ERR_PTR(err);
73562306a36Sopenharmony_ci		}
73662306a36Sopenharmony_ci		break;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci	memcpy(key->conf.key, key_data, key_len);
73962306a36Sopenharmony_ci	INIT_LIST_HEAD(&key->list);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	return key;
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_cistatic void ieee80211_key_free_common(struct ieee80211_key *key)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	switch (key->conf.cipher) {
74762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
74862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
74962306a36Sopenharmony_ci		ieee80211_aes_key_free(key->u.ccmp.tfm);
75062306a36Sopenharmony_ci		break;
75162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
75262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
75362306a36Sopenharmony_ci		ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
75462306a36Sopenharmony_ci		break;
75562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
75662306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
75762306a36Sopenharmony_ci		ieee80211_aes_gmac_key_free(key->u.aes_gmac.tfm);
75862306a36Sopenharmony_ci		break;
75962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
76062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
76162306a36Sopenharmony_ci		ieee80211_aes_gcm_key_free(key->u.gcmp.tfm);
76262306a36Sopenharmony_ci		break;
76362306a36Sopenharmony_ci	}
76462306a36Sopenharmony_ci	kfree_sensitive(key);
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_cistatic void __ieee80211_key_destroy(struct ieee80211_key *key,
76862306a36Sopenharmony_ci				    bool delay_tailroom)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	if (key->local) {
77162306a36Sopenharmony_ci		struct ieee80211_sub_if_data *sdata = key->sdata;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci		ieee80211_debugfs_key_remove(key);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci		if (delay_tailroom) {
77662306a36Sopenharmony_ci			/* see ieee80211_delayed_tailroom_dec */
77762306a36Sopenharmony_ci			sdata->crypto_tx_tailroom_pending_dec++;
77862306a36Sopenharmony_ci			schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
77962306a36Sopenharmony_ci					      HZ/2);
78062306a36Sopenharmony_ci		} else {
78162306a36Sopenharmony_ci			decrease_tailroom_need_count(sdata, 1);
78262306a36Sopenharmony_ci		}
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	ieee80211_key_free_common(key);
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistatic void ieee80211_key_destroy(struct ieee80211_key *key,
78962306a36Sopenharmony_ci				  bool delay_tailroom)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	if (!key)
79262306a36Sopenharmony_ci		return;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	/*
79562306a36Sopenharmony_ci	 * Synchronize so the TX path and rcu key iterators
79662306a36Sopenharmony_ci	 * can no longer be using this key before we free/remove it.
79762306a36Sopenharmony_ci	 */
79862306a36Sopenharmony_ci	synchronize_net();
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	__ieee80211_key_destroy(key, delay_tailroom);
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_civoid ieee80211_key_free_unused(struct ieee80211_key *key)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	if (!key)
80662306a36Sopenharmony_ci		return;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	WARN_ON(key->sdata || key->local);
80962306a36Sopenharmony_ci	ieee80211_key_free_common(key);
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic bool ieee80211_key_identical(struct ieee80211_sub_if_data *sdata,
81362306a36Sopenharmony_ci				    struct ieee80211_key *old,
81462306a36Sopenharmony_ci				    struct ieee80211_key *new)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	u8 tkip_old[WLAN_KEY_LEN_TKIP], tkip_new[WLAN_KEY_LEN_TKIP];
81762306a36Sopenharmony_ci	u8 *tk_old, *tk_new;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	if (!old || new->conf.keylen != old->conf.keylen)
82062306a36Sopenharmony_ci		return false;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	tk_old = old->conf.key;
82362306a36Sopenharmony_ci	tk_new = new->conf.key;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	/*
82662306a36Sopenharmony_ci	 * In station mode, don't compare the TX MIC key, as it's never used
82762306a36Sopenharmony_ci	 * and offloaded rekeying may not care to send it to the host. This
82862306a36Sopenharmony_ci	 * is the case in iwlwifi, for example.
82962306a36Sopenharmony_ci	 */
83062306a36Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
83162306a36Sopenharmony_ci	    new->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
83262306a36Sopenharmony_ci	    new->conf.keylen == WLAN_KEY_LEN_TKIP &&
83362306a36Sopenharmony_ci	    !(new->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
83462306a36Sopenharmony_ci		memcpy(tkip_old, tk_old, WLAN_KEY_LEN_TKIP);
83562306a36Sopenharmony_ci		memcpy(tkip_new, tk_new, WLAN_KEY_LEN_TKIP);
83662306a36Sopenharmony_ci		memset(tkip_old + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8);
83762306a36Sopenharmony_ci		memset(tkip_new + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8);
83862306a36Sopenharmony_ci		tk_old = tkip_old;
83962306a36Sopenharmony_ci		tk_new = tkip_new;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	return !crypto_memneq(tk_old, tk_new, new->conf.keylen);
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ciint ieee80211_key_link(struct ieee80211_key *key,
84662306a36Sopenharmony_ci		       struct ieee80211_link_data *link,
84762306a36Sopenharmony_ci		       struct sta_info *sta)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = link->sdata;
85062306a36Sopenharmony_ci	static atomic_t key_color = ATOMIC_INIT(0);
85162306a36Sopenharmony_ci	struct ieee80211_key *old_key = NULL;
85262306a36Sopenharmony_ci	int idx = key->conf.keyidx;
85362306a36Sopenharmony_ci	bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
85462306a36Sopenharmony_ci	/*
85562306a36Sopenharmony_ci	 * We want to delay tailroom updates only for station - in that
85662306a36Sopenharmony_ci	 * case it helps roaming speed, but in other cases it hurts and
85762306a36Sopenharmony_ci	 * can cause warnings to appear.
85862306a36Sopenharmony_ci	 */
85962306a36Sopenharmony_ci	bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
86062306a36Sopenharmony_ci	int ret;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	mutex_lock(&sdata->local->key_mtx);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	if (sta && pairwise) {
86562306a36Sopenharmony_ci		struct ieee80211_key *alt_key;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
86862306a36Sopenharmony_ci		alt_key = key_mtx_dereference(sdata->local, sta->ptk[idx ^ 1]);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci		/* The rekey code assumes that the old and new key are using
87162306a36Sopenharmony_ci		 * the same cipher. Enforce the assumption for pairwise keys.
87262306a36Sopenharmony_ci		 */
87362306a36Sopenharmony_ci		if ((alt_key && alt_key->conf.cipher != key->conf.cipher) ||
87462306a36Sopenharmony_ci		    (old_key && old_key->conf.cipher != key->conf.cipher)) {
87562306a36Sopenharmony_ci			ret = -EOPNOTSUPP;
87662306a36Sopenharmony_ci			goto out;
87762306a36Sopenharmony_ci		}
87862306a36Sopenharmony_ci	} else if (sta) {
87962306a36Sopenharmony_ci		struct link_sta_info *link_sta = &sta->deflink;
88062306a36Sopenharmony_ci		int link_id = key->conf.link_id;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci		if (link_id >= 0) {
88362306a36Sopenharmony_ci			link_sta = rcu_dereference_protected(sta->link[link_id],
88462306a36Sopenharmony_ci							     lockdep_is_held(&sta->local->sta_mtx));
88562306a36Sopenharmony_ci			if (!link_sta) {
88662306a36Sopenharmony_ci				ret = -ENOLINK;
88762306a36Sopenharmony_ci				goto out;
88862306a36Sopenharmony_ci			}
88962306a36Sopenharmony_ci		}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci		old_key = key_mtx_dereference(sdata->local, link_sta->gtk[idx]);
89262306a36Sopenharmony_ci	} else {
89362306a36Sopenharmony_ci		if (idx < NUM_DEFAULT_KEYS)
89462306a36Sopenharmony_ci			old_key = key_mtx_dereference(sdata->local,
89562306a36Sopenharmony_ci						      sdata->keys[idx]);
89662306a36Sopenharmony_ci		if (!old_key)
89762306a36Sopenharmony_ci			old_key = key_mtx_dereference(sdata->local,
89862306a36Sopenharmony_ci						      link->gtk[idx]);
89962306a36Sopenharmony_ci	}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	/* Non-pairwise keys must also not switch the cipher on rekey */
90262306a36Sopenharmony_ci	if (!pairwise) {
90362306a36Sopenharmony_ci		if (old_key && old_key->conf.cipher != key->conf.cipher) {
90462306a36Sopenharmony_ci			ret = -EOPNOTSUPP;
90562306a36Sopenharmony_ci			goto out;
90662306a36Sopenharmony_ci		}
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	/*
91062306a36Sopenharmony_ci	 * Silently accept key re-installation without really installing the
91162306a36Sopenharmony_ci	 * new version of the key to avoid nonce reuse or replay issues.
91262306a36Sopenharmony_ci	 */
91362306a36Sopenharmony_ci	if (ieee80211_key_identical(sdata, old_key, key)) {
91462306a36Sopenharmony_ci		ret = -EALREADY;
91562306a36Sopenharmony_ci		goto out;
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	key->local = sdata->local;
91962306a36Sopenharmony_ci	key->sdata = sdata;
92062306a36Sopenharmony_ci	key->sta = sta;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	/*
92362306a36Sopenharmony_ci	 * Assign a unique ID to every key so we can easily prevent mixed
92462306a36Sopenharmony_ci	 * key and fragment cache attacks.
92562306a36Sopenharmony_ci	 */
92662306a36Sopenharmony_ci	key->color = atomic_inc_return(&key_color);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	increment_tailroom_need_count(sdata);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	ret = ieee80211_key_replace(sdata, link, sta, pairwise, old_key, key);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	if (!ret) {
93362306a36Sopenharmony_ci		ieee80211_debugfs_key_add(key);
93462306a36Sopenharmony_ci		ieee80211_key_destroy(old_key, delay_tailroom);
93562306a36Sopenharmony_ci	} else {
93662306a36Sopenharmony_ci		ieee80211_key_free(key, delay_tailroom);
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	key = NULL;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci out:
94262306a36Sopenharmony_ci	ieee80211_key_free_unused(key);
94362306a36Sopenharmony_ci	mutex_unlock(&sdata->local->key_mtx);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	return ret;
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_civoid ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	if (!key)
95162306a36Sopenharmony_ci		return;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	/*
95462306a36Sopenharmony_ci	 * Replace key with nothingness if it was ever used.
95562306a36Sopenharmony_ci	 */
95662306a36Sopenharmony_ci	if (key->sdata)
95762306a36Sopenharmony_ci		ieee80211_key_replace(key->sdata, NULL, key->sta,
95862306a36Sopenharmony_ci				      key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
95962306a36Sopenharmony_ci				      key, NULL);
96062306a36Sopenharmony_ci	ieee80211_key_destroy(key, delay_tailroom);
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_civoid ieee80211_reenable_keys(struct ieee80211_sub_if_data *sdata)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct ieee80211_key *key;
96662306a36Sopenharmony_ci	struct ieee80211_sub_if_data *vlan;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	lockdep_assert_wiphy(sdata->local->hw.wiphy);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	mutex_lock(&sdata->local->key_mtx);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	sdata->crypto_tx_tailroom_needed_cnt = 0;
97362306a36Sopenharmony_ci	sdata->crypto_tx_tailroom_pending_dec = 0;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP) {
97662306a36Sopenharmony_ci		list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
97762306a36Sopenharmony_ci			vlan->crypto_tx_tailroom_needed_cnt = 0;
97862306a36Sopenharmony_ci			vlan->crypto_tx_tailroom_pending_dec = 0;
97962306a36Sopenharmony_ci		}
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	if (ieee80211_sdata_running(sdata)) {
98362306a36Sopenharmony_ci		list_for_each_entry(key, &sdata->key_list, list) {
98462306a36Sopenharmony_ci			increment_tailroom_need_count(sdata);
98562306a36Sopenharmony_ci			ieee80211_key_enable_hw_accel(key);
98662306a36Sopenharmony_ci		}
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	mutex_unlock(&sdata->local->key_mtx);
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_civoid ieee80211_iter_keys(struct ieee80211_hw *hw,
99362306a36Sopenharmony_ci			 struct ieee80211_vif *vif,
99462306a36Sopenharmony_ci			 void (*iter)(struct ieee80211_hw *hw,
99562306a36Sopenharmony_ci				      struct ieee80211_vif *vif,
99662306a36Sopenharmony_ci				      struct ieee80211_sta *sta,
99762306a36Sopenharmony_ci				      struct ieee80211_key_conf *key,
99862306a36Sopenharmony_ci				      void *data),
99962306a36Sopenharmony_ci			 void *iter_data)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
100262306a36Sopenharmony_ci	struct ieee80211_key *key, *tmp;
100362306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	lockdep_assert_wiphy(hw->wiphy);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	mutex_lock(&local->key_mtx);
100862306a36Sopenharmony_ci	if (vif) {
100962306a36Sopenharmony_ci		sdata = vif_to_sdata(vif);
101062306a36Sopenharmony_ci		list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
101162306a36Sopenharmony_ci			iter(hw, &sdata->vif,
101262306a36Sopenharmony_ci			     key->sta ? &key->sta->sta : NULL,
101362306a36Sopenharmony_ci			     &key->conf, iter_data);
101462306a36Sopenharmony_ci	} else {
101562306a36Sopenharmony_ci		list_for_each_entry(sdata, &local->interfaces, list)
101662306a36Sopenharmony_ci			list_for_each_entry_safe(key, tmp,
101762306a36Sopenharmony_ci						 &sdata->key_list, list)
101862306a36Sopenharmony_ci				iter(hw, &sdata->vif,
101962306a36Sopenharmony_ci				     key->sta ? &key->sta->sta : NULL,
102062306a36Sopenharmony_ci				     &key->conf, iter_data);
102162306a36Sopenharmony_ci	}
102262306a36Sopenharmony_ci	mutex_unlock(&local->key_mtx);
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_iter_keys);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cistatic void
102762306a36Sopenharmony_ci_ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,
102862306a36Sopenharmony_ci			 struct ieee80211_sub_if_data *sdata,
102962306a36Sopenharmony_ci			 void (*iter)(struct ieee80211_hw *hw,
103062306a36Sopenharmony_ci				      struct ieee80211_vif *vif,
103162306a36Sopenharmony_ci				      struct ieee80211_sta *sta,
103262306a36Sopenharmony_ci				      struct ieee80211_key_conf *key,
103362306a36Sopenharmony_ci				      void *data),
103462306a36Sopenharmony_ci			 void *iter_data)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	struct ieee80211_key *key;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	list_for_each_entry_rcu(key, &sdata->key_list, list) {
103962306a36Sopenharmony_ci		/* skip keys of station in removal process */
104062306a36Sopenharmony_ci		if (key->sta && key->sta->removed)
104162306a36Sopenharmony_ci			continue;
104262306a36Sopenharmony_ci		if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
104362306a36Sopenharmony_ci			continue;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci		iter(hw, &sdata->vif,
104662306a36Sopenharmony_ci		     key->sta ? &key->sta->sta : NULL,
104762306a36Sopenharmony_ci		     &key->conf, iter_data);
104862306a36Sopenharmony_ci	}
104962306a36Sopenharmony_ci}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_civoid ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,
105262306a36Sopenharmony_ci			     struct ieee80211_vif *vif,
105362306a36Sopenharmony_ci			     void (*iter)(struct ieee80211_hw *hw,
105462306a36Sopenharmony_ci					  struct ieee80211_vif *vif,
105562306a36Sopenharmony_ci					  struct ieee80211_sta *sta,
105662306a36Sopenharmony_ci					  struct ieee80211_key_conf *key,
105762306a36Sopenharmony_ci					  void *data),
105862306a36Sopenharmony_ci			     void *iter_data)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
106162306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	if (vif) {
106462306a36Sopenharmony_ci		sdata = vif_to_sdata(vif);
106562306a36Sopenharmony_ci		_ieee80211_iter_keys_rcu(hw, sdata, iter, iter_data);
106662306a36Sopenharmony_ci	} else {
106762306a36Sopenharmony_ci		list_for_each_entry_rcu(sdata, &local->interfaces, list)
106862306a36Sopenharmony_ci			_ieee80211_iter_keys_rcu(hw, sdata, iter, iter_data);
106962306a36Sopenharmony_ci	}
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_iter_keys_rcu);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_cistatic void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
107462306a36Sopenharmony_ci				      struct list_head *keys)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	struct ieee80211_key *key, *tmp;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	decrease_tailroom_need_count(sdata,
107962306a36Sopenharmony_ci				     sdata->crypto_tx_tailroom_pending_dec);
108062306a36Sopenharmony_ci	sdata->crypto_tx_tailroom_pending_dec = 0;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	ieee80211_debugfs_key_remove_mgmt_default(sdata);
108362306a36Sopenharmony_ci	ieee80211_debugfs_key_remove_beacon_default(sdata);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	list_for_each_entry_safe(key, tmp, &sdata->key_list, list) {
108662306a36Sopenharmony_ci		ieee80211_key_replace(key->sdata, NULL, key->sta,
108762306a36Sopenharmony_ci				      key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
108862306a36Sopenharmony_ci				      key, NULL);
108962306a36Sopenharmony_ci		list_add_tail(&key->list, keys);
109062306a36Sopenharmony_ci	}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	ieee80211_debugfs_key_update_default(sdata);
109362306a36Sopenharmony_ci}
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_civoid ieee80211_remove_link_keys(struct ieee80211_link_data *link,
109662306a36Sopenharmony_ci				struct list_head *keys)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = link->sdata;
109962306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
110062306a36Sopenharmony_ci	struct ieee80211_key *key, *tmp;
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	mutex_lock(&local->key_mtx);
110362306a36Sopenharmony_ci	list_for_each_entry_safe(key, tmp, &sdata->key_list, list) {
110462306a36Sopenharmony_ci		if (key->conf.link_id != link->link_id)
110562306a36Sopenharmony_ci			continue;
110662306a36Sopenharmony_ci		ieee80211_key_replace(key->sdata, link, key->sta,
110762306a36Sopenharmony_ci				      key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
110862306a36Sopenharmony_ci				      key, NULL);
110962306a36Sopenharmony_ci		list_add_tail(&key->list, keys);
111062306a36Sopenharmony_ci	}
111162306a36Sopenharmony_ci	mutex_unlock(&local->key_mtx);
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_civoid ieee80211_free_key_list(struct ieee80211_local *local,
111562306a36Sopenharmony_ci			     struct list_head *keys)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	struct ieee80211_key *key, *tmp;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	mutex_lock(&local->key_mtx);
112062306a36Sopenharmony_ci	list_for_each_entry_safe(key, tmp, keys, list)
112162306a36Sopenharmony_ci		__ieee80211_key_destroy(key, false);
112262306a36Sopenharmony_ci	mutex_unlock(&local->key_mtx);
112362306a36Sopenharmony_ci}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_civoid ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
112662306a36Sopenharmony_ci			 bool force_synchronize)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
112962306a36Sopenharmony_ci	struct ieee80211_sub_if_data *vlan;
113062306a36Sopenharmony_ci	struct ieee80211_sub_if_data *master;
113162306a36Sopenharmony_ci	struct ieee80211_key *key, *tmp;
113262306a36Sopenharmony_ci	LIST_HEAD(keys);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	mutex_lock(&local->key_mtx);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	ieee80211_free_keys_iface(sdata, &keys);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP) {
114162306a36Sopenharmony_ci		list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
114262306a36Sopenharmony_ci			ieee80211_free_keys_iface(vlan, &keys);
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	if (!list_empty(&keys) || force_synchronize)
114662306a36Sopenharmony_ci		synchronize_net();
114762306a36Sopenharmony_ci	list_for_each_entry_safe(key, tmp, &keys, list)
114862306a36Sopenharmony_ci		__ieee80211_key_destroy(key, false);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
115162306a36Sopenharmony_ci		if (sdata->bss) {
115262306a36Sopenharmony_ci			master = container_of(sdata->bss,
115362306a36Sopenharmony_ci					      struct ieee80211_sub_if_data,
115462306a36Sopenharmony_ci					      u.ap);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci			WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt !=
115762306a36Sopenharmony_ci				     master->crypto_tx_tailroom_needed_cnt);
115862306a36Sopenharmony_ci		}
115962306a36Sopenharmony_ci	} else {
116062306a36Sopenharmony_ci		WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
116162306a36Sopenharmony_ci			     sdata->crypto_tx_tailroom_pending_dec);
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP) {
116562306a36Sopenharmony_ci		list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
116662306a36Sopenharmony_ci			WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt ||
116762306a36Sopenharmony_ci				     vlan->crypto_tx_tailroom_pending_dec);
116862306a36Sopenharmony_ci	}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	mutex_unlock(&local->key_mtx);
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_civoid ieee80211_free_sta_keys(struct ieee80211_local *local,
117462306a36Sopenharmony_ci			     struct sta_info *sta)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	struct ieee80211_key *key;
117762306a36Sopenharmony_ci	int i;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	mutex_lock(&local->key_mtx);
118062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sta->deflink.gtk); i++) {
118162306a36Sopenharmony_ci		key = key_mtx_dereference(local, sta->deflink.gtk[i]);
118262306a36Sopenharmony_ci		if (!key)
118362306a36Sopenharmony_ci			continue;
118462306a36Sopenharmony_ci		ieee80211_key_replace(key->sdata, NULL, key->sta,
118562306a36Sopenharmony_ci				      key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
118662306a36Sopenharmony_ci				      key, NULL);
118762306a36Sopenharmony_ci		__ieee80211_key_destroy(key, key->sdata->vif.type ==
118862306a36Sopenharmony_ci					NL80211_IFTYPE_STATION);
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
119262306a36Sopenharmony_ci		key = key_mtx_dereference(local, sta->ptk[i]);
119362306a36Sopenharmony_ci		if (!key)
119462306a36Sopenharmony_ci			continue;
119562306a36Sopenharmony_ci		ieee80211_key_replace(key->sdata, NULL, key->sta,
119662306a36Sopenharmony_ci				      key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
119762306a36Sopenharmony_ci				      key, NULL);
119862306a36Sopenharmony_ci		__ieee80211_key_destroy(key, key->sdata->vif.type ==
119962306a36Sopenharmony_ci					NL80211_IFTYPE_STATION);
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	mutex_unlock(&local->key_mtx);
120362306a36Sopenharmony_ci}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_civoid ieee80211_delayed_tailroom_dec(struct work_struct *wk)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	sdata = container_of(wk, struct ieee80211_sub_if_data,
121062306a36Sopenharmony_ci			     dec_tailroom_needed_wk.work);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	/*
121362306a36Sopenharmony_ci	 * The reason for the delayed tailroom needed decrementing is to
121462306a36Sopenharmony_ci	 * make roaming faster: during roaming, all keys are first deleted
121562306a36Sopenharmony_ci	 * and then new keys are installed. The first new key causes the
121662306a36Sopenharmony_ci	 * crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes
121762306a36Sopenharmony_ci	 * the cost of synchronize_net() (which can be slow). Avoid this
121862306a36Sopenharmony_ci	 * by deferring the crypto_tx_tailroom_needed_cnt decrementing on
121962306a36Sopenharmony_ci	 * key removal for a while, so if we roam the value is larger than
122062306a36Sopenharmony_ci	 * zero and no 0->1 transition happens.
122162306a36Sopenharmony_ci	 *
122262306a36Sopenharmony_ci	 * The cost is that if the AP switching was from an AP with keys
122362306a36Sopenharmony_ci	 * to one without, we still allocate tailroom while it would no
122462306a36Sopenharmony_ci	 * longer be needed. However, in the typical (fast) roaming case
122562306a36Sopenharmony_ci	 * within an ESS this usually won't happen.
122662306a36Sopenharmony_ci	 */
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	mutex_lock(&sdata->local->key_mtx);
122962306a36Sopenharmony_ci	decrease_tailroom_need_count(sdata,
123062306a36Sopenharmony_ci				     sdata->crypto_tx_tailroom_pending_dec);
123162306a36Sopenharmony_ci	sdata->crypto_tx_tailroom_pending_dec = 0;
123262306a36Sopenharmony_ci	mutex_unlock(&sdata->local->key_mtx);
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_civoid ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
123662306a36Sopenharmony_ci				const u8 *replay_ctr, gfp_t gfp)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	trace_api_gtk_rekey_notify(sdata, bssid, replay_ctr);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	cfg80211_gtk_rekey_notify(sdata->dev, bssid, replay_ctr, gfp);
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_civoid ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
124762306a36Sopenharmony_ci			      int tid, struct ieee80211_key_seq *seq)
124862306a36Sopenharmony_ci{
124962306a36Sopenharmony_ci	struct ieee80211_key *key;
125062306a36Sopenharmony_ci	const u8 *pn;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	key = container_of(keyconf, struct ieee80211_key, conf);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	switch (key->conf.cipher) {
125562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
125662306a36Sopenharmony_ci		if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS))
125762306a36Sopenharmony_ci			return;
125862306a36Sopenharmony_ci		seq->tkip.iv32 = key->u.tkip.rx[tid].iv32;
125962306a36Sopenharmony_ci		seq->tkip.iv16 = key->u.tkip.rx[tid].iv16;
126062306a36Sopenharmony_ci		break;
126162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
126262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
126362306a36Sopenharmony_ci		if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
126462306a36Sopenharmony_ci			return;
126562306a36Sopenharmony_ci		if (tid < 0)
126662306a36Sopenharmony_ci			pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS];
126762306a36Sopenharmony_ci		else
126862306a36Sopenharmony_ci			pn = key->u.ccmp.rx_pn[tid];
126962306a36Sopenharmony_ci		memcpy(seq->ccmp.pn, pn, IEEE80211_CCMP_PN_LEN);
127062306a36Sopenharmony_ci		break;
127162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
127262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
127362306a36Sopenharmony_ci		if (WARN_ON(tid != 0))
127462306a36Sopenharmony_ci			return;
127562306a36Sopenharmony_ci		pn = key->u.aes_cmac.rx_pn;
127662306a36Sopenharmony_ci		memcpy(seq->aes_cmac.pn, pn, IEEE80211_CMAC_PN_LEN);
127762306a36Sopenharmony_ci		break;
127862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
127962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
128062306a36Sopenharmony_ci		if (WARN_ON(tid != 0))
128162306a36Sopenharmony_ci			return;
128262306a36Sopenharmony_ci		pn = key->u.aes_gmac.rx_pn;
128362306a36Sopenharmony_ci		memcpy(seq->aes_gmac.pn, pn, IEEE80211_GMAC_PN_LEN);
128462306a36Sopenharmony_ci		break;
128562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
128662306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
128762306a36Sopenharmony_ci		if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
128862306a36Sopenharmony_ci			return;
128962306a36Sopenharmony_ci		if (tid < 0)
129062306a36Sopenharmony_ci			pn = key->u.gcmp.rx_pn[IEEE80211_NUM_TIDS];
129162306a36Sopenharmony_ci		else
129262306a36Sopenharmony_ci			pn = key->u.gcmp.rx_pn[tid];
129362306a36Sopenharmony_ci		memcpy(seq->gcmp.pn, pn, IEEE80211_GCMP_PN_LEN);
129462306a36Sopenharmony_ci		break;
129562306a36Sopenharmony_ci	}
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_get_key_rx_seq);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_civoid ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
130062306a36Sopenharmony_ci			      int tid, struct ieee80211_key_seq *seq)
130162306a36Sopenharmony_ci{
130262306a36Sopenharmony_ci	struct ieee80211_key *key;
130362306a36Sopenharmony_ci	u8 *pn;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	key = container_of(keyconf, struct ieee80211_key, conf);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	switch (key->conf.cipher) {
130862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
130962306a36Sopenharmony_ci		if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS))
131062306a36Sopenharmony_ci			return;
131162306a36Sopenharmony_ci		key->u.tkip.rx[tid].iv32 = seq->tkip.iv32;
131262306a36Sopenharmony_ci		key->u.tkip.rx[tid].iv16 = seq->tkip.iv16;
131362306a36Sopenharmony_ci		break;
131462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
131562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
131662306a36Sopenharmony_ci		if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
131762306a36Sopenharmony_ci			return;
131862306a36Sopenharmony_ci		if (tid < 0)
131962306a36Sopenharmony_ci			pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS];
132062306a36Sopenharmony_ci		else
132162306a36Sopenharmony_ci			pn = key->u.ccmp.rx_pn[tid];
132262306a36Sopenharmony_ci		memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN);
132362306a36Sopenharmony_ci		break;
132462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
132562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
132662306a36Sopenharmony_ci		if (WARN_ON(tid != 0))
132762306a36Sopenharmony_ci			return;
132862306a36Sopenharmony_ci		pn = key->u.aes_cmac.rx_pn;
132962306a36Sopenharmony_ci		memcpy(pn, seq->aes_cmac.pn, IEEE80211_CMAC_PN_LEN);
133062306a36Sopenharmony_ci		break;
133162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
133262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
133362306a36Sopenharmony_ci		if (WARN_ON(tid != 0))
133462306a36Sopenharmony_ci			return;
133562306a36Sopenharmony_ci		pn = key->u.aes_gmac.rx_pn;
133662306a36Sopenharmony_ci		memcpy(pn, seq->aes_gmac.pn, IEEE80211_GMAC_PN_LEN);
133762306a36Sopenharmony_ci		break;
133862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
133962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
134062306a36Sopenharmony_ci		if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
134162306a36Sopenharmony_ci			return;
134262306a36Sopenharmony_ci		if (tid < 0)
134362306a36Sopenharmony_ci			pn = key->u.gcmp.rx_pn[IEEE80211_NUM_TIDS];
134462306a36Sopenharmony_ci		else
134562306a36Sopenharmony_ci			pn = key->u.gcmp.rx_pn[tid];
134662306a36Sopenharmony_ci		memcpy(pn, seq->gcmp.pn, IEEE80211_GCMP_PN_LEN);
134762306a36Sopenharmony_ci		break;
134862306a36Sopenharmony_ci	default:
134962306a36Sopenharmony_ci		WARN_ON(1);
135062306a36Sopenharmony_ci		break;
135162306a36Sopenharmony_ci	}
135262306a36Sopenharmony_ci}
135362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_set_key_rx_seq);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_civoid ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
135662306a36Sopenharmony_ci{
135762306a36Sopenharmony_ci	struct ieee80211_key *key;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	key = container_of(keyconf, struct ieee80211_key, conf);
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	assert_key_lock(key->local);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	/*
136462306a36Sopenharmony_ci	 * if key was uploaded, we assume the driver will/has remove(d)
136562306a36Sopenharmony_ci	 * it, so adjust bookkeeping accordingly
136662306a36Sopenharmony_ci	 */
136762306a36Sopenharmony_ci	if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
136862306a36Sopenharmony_ci		key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci		if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
137162306a36Sopenharmony_ci					 IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
137262306a36Sopenharmony_ci					 IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
137362306a36Sopenharmony_ci			increment_tailroom_need_count(key->sdata);
137462306a36Sopenharmony_ci	}
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	ieee80211_key_free(key, false);
137762306a36Sopenharmony_ci}
137862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_remove_key);
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_cistruct ieee80211_key_conf *
138162306a36Sopenharmony_ciieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
138262306a36Sopenharmony_ci			struct ieee80211_key_conf *keyconf)
138362306a36Sopenharmony_ci{
138462306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
138562306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
138662306a36Sopenharmony_ci	struct ieee80211_key *key;
138762306a36Sopenharmony_ci	int err;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	if (WARN_ON(!local->wowlan))
139062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
139362306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx,
139662306a36Sopenharmony_ci				  keyconf->keylen, keyconf->key,
139762306a36Sopenharmony_ci				  0, NULL);
139862306a36Sopenharmony_ci	if (IS_ERR(key))
139962306a36Sopenharmony_ci		return ERR_CAST(key);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED)
140262306a36Sopenharmony_ci		key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	/* FIXME: this function needs to get a link ID */
140562306a36Sopenharmony_ci	err = ieee80211_key_link(key, &sdata->deflink, NULL);
140662306a36Sopenharmony_ci	if (err)
140762306a36Sopenharmony_ci		return ERR_PTR(err);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	return &key->conf;
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_add);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_civoid ieee80211_key_mic_failure(struct ieee80211_key_conf *keyconf)
141462306a36Sopenharmony_ci{
141562306a36Sopenharmony_ci	struct ieee80211_key *key;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	key = container_of(keyconf, struct ieee80211_key, conf);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	switch (key->conf.cipher) {
142062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
142162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
142262306a36Sopenharmony_ci		key->u.aes_cmac.icverrors++;
142362306a36Sopenharmony_ci		break;
142462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
142562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
142662306a36Sopenharmony_ci		key->u.aes_gmac.icverrors++;
142762306a36Sopenharmony_ci		break;
142862306a36Sopenharmony_ci	default:
142962306a36Sopenharmony_ci		/* ignore the others for now, we don't keep counters now */
143062306a36Sopenharmony_ci		break;
143162306a36Sopenharmony_ci	}
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_key_mic_failure);
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_civoid ieee80211_key_replay(struct ieee80211_key_conf *keyconf)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct ieee80211_key *key;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	key = container_of(keyconf, struct ieee80211_key, conf);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	switch (key->conf.cipher) {
144262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
144362306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
144462306a36Sopenharmony_ci		key->u.ccmp.replays++;
144562306a36Sopenharmony_ci		break;
144662306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
144762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
144862306a36Sopenharmony_ci		key->u.aes_cmac.replays++;
144962306a36Sopenharmony_ci		break;
145062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
145162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
145262306a36Sopenharmony_ci		key->u.aes_gmac.replays++;
145362306a36Sopenharmony_ci		break;
145462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
145562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
145662306a36Sopenharmony_ci		key->u.gcmp.replays++;
145762306a36Sopenharmony_ci		break;
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci}
146062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_key_replay);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ciint ieee80211_key_switch_links(struct ieee80211_sub_if_data *sdata,
146362306a36Sopenharmony_ci			       unsigned long del_links_mask,
146462306a36Sopenharmony_ci			       unsigned long add_links_mask)
146562306a36Sopenharmony_ci{
146662306a36Sopenharmony_ci	struct ieee80211_key *key;
146762306a36Sopenharmony_ci	int ret;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	list_for_each_entry(key, &sdata->key_list, list) {
147062306a36Sopenharmony_ci		if (key->conf.link_id < 0 ||
147162306a36Sopenharmony_ci		    !(del_links_mask & BIT(key->conf.link_id)))
147262306a36Sopenharmony_ci			continue;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		/* shouldn't happen for per-link keys */
147562306a36Sopenharmony_ci		WARN_ON(key->sta);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci		ieee80211_key_disable_hw_accel(key);
147862306a36Sopenharmony_ci	}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	list_for_each_entry(key, &sdata->key_list, list) {
148162306a36Sopenharmony_ci		if (key->conf.link_id < 0 ||
148262306a36Sopenharmony_ci		    !(add_links_mask & BIT(key->conf.link_id)))
148362306a36Sopenharmony_ci			continue;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci		/* shouldn't happen for per-link keys */
148662306a36Sopenharmony_ci		WARN_ON(key->sta);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci		ret = ieee80211_key_enable_hw_accel(key);
148962306a36Sopenharmony_ci		if (ret)
149062306a36Sopenharmony_ci			return ret;
149162306a36Sopenharmony_ci	}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	return 0;
149462306a36Sopenharmony_ci}
1495