18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2002-2005, Instant802 Networks, Inc.
48c2ecf20Sopenharmony_ci * Copyright 2005-2006, Devicescape Software, Inc.
58c2ecf20Sopenharmony_ci * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
68c2ecf20Sopenharmony_ci * Copyright 2007-2008	Johannes Berg <johannes@sipsolutions.net>
78c2ecf20Sopenharmony_ci * Copyright 2013-2014  Intel Mobile Communications GmbH
88c2ecf20Sopenharmony_ci * Copyright 2015-2017	Intel Deutschland GmbH
98c2ecf20Sopenharmony_ci * Copyright 2018-2020  Intel Corporation
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
138c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
148c2ecf20Sopenharmony_ci#include <linux/list.h>
158c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
168c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/export.h>
198c2ecf20Sopenharmony_ci#include <net/mac80211.h>
208c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
218c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
228c2ecf20Sopenharmony_ci#include "ieee80211_i.h"
238c2ecf20Sopenharmony_ci#include "driver-ops.h"
248c2ecf20Sopenharmony_ci#include "debugfs_key.h"
258c2ecf20Sopenharmony_ci#include "aes_ccm.h"
268c2ecf20Sopenharmony_ci#include "aes_cmac.h"
278c2ecf20Sopenharmony_ci#include "aes_gmac.h"
288c2ecf20Sopenharmony_ci#include "aes_gcm.h"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/**
328c2ecf20Sopenharmony_ci * DOC: Key handling basics
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * Key handling in mac80211 is done based on per-interface (sub_if_data)
358c2ecf20Sopenharmony_ci * keys and per-station keys. Since each station belongs to an interface,
368c2ecf20Sopenharmony_ci * each station key also belongs to that interface.
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci * Hardware acceleration is done on a best-effort basis for algorithms
398c2ecf20Sopenharmony_ci * that are implemented in software,  for each key the hardware is asked
408c2ecf20Sopenharmony_ci * to enable that key for offloading but if it cannot do that the key is
418c2ecf20Sopenharmony_ci * simply kept for software encryption (unless it is for an algorithm
428c2ecf20Sopenharmony_ci * that isn't implemented in software).
438c2ecf20Sopenharmony_ci * There is currently no way of knowing whether a key is handled in SW
448c2ecf20Sopenharmony_ci * or HW except by looking into debugfs.
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * All key management is internally protected by a mutex. Within all
478c2ecf20Sopenharmony_ci * other parts of mac80211, key references are, just as STA structure
488c2ecf20Sopenharmony_ci * references, protected by RCU. Note, however, that some things are
498c2ecf20Sopenharmony_ci * unprotected, namely the key->sta dereferences within the hardware
508c2ecf20Sopenharmony_ci * acceleration functions. This means that sta_info_destroy() must
518c2ecf20Sopenharmony_ci * remove the key which waits for an RCU grace period.
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic void assert_key_lock(struct ieee80211_local *local)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	lockdep_assert_held(&local->key_mtx);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic void
628c2ecf20Sopenharmony_ciupdate_vlan_tailroom_need_count(struct ieee80211_sub_if_data *sdata, int delta)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *vlan;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (sdata->vif.type != NL80211_IFTYPE_AP)
678c2ecf20Sopenharmony_ci		return;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* crypto_tx_tailroom_needed_cnt is protected by this */
708c2ecf20Sopenharmony_ci	assert_key_lock(sdata->local);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	rcu_read_lock();
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(vlan, &sdata->u.ap.vlans, u.vlan.list)
758c2ecf20Sopenharmony_ci		vlan->crypto_tx_tailroom_needed_cnt += delta;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	rcu_read_unlock();
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	/*
838c2ecf20Sopenharmony_ci	 * When this count is zero, SKB resizing for allocating tailroom
848c2ecf20Sopenharmony_ci	 * for IV or MMIC is skipped. But, this check has created two race
858c2ecf20Sopenharmony_ci	 * cases in xmit path while transiting from zero count to one:
868c2ecf20Sopenharmony_ci	 *
878c2ecf20Sopenharmony_ci	 * 1. SKB resize was skipped because no key was added but just before
888c2ecf20Sopenharmony_ci	 * the xmit key is added and SW encryption kicks off.
898c2ecf20Sopenharmony_ci	 *
908c2ecf20Sopenharmony_ci	 * 2. SKB resize was skipped because all the keys were hw planted but
918c2ecf20Sopenharmony_ci	 * just before xmit one of the key is deleted and SW encryption kicks
928c2ecf20Sopenharmony_ci	 * off.
938c2ecf20Sopenharmony_ci	 *
948c2ecf20Sopenharmony_ci	 * In both the above case SW encryption will find not enough space for
958c2ecf20Sopenharmony_ci	 * tailroom and exits with WARN_ON. (See WARN_ONs at wpa.c)
968c2ecf20Sopenharmony_ci	 *
978c2ecf20Sopenharmony_ci	 * Solution has been explained at
988c2ecf20Sopenharmony_ci	 * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net
998c2ecf20Sopenharmony_ci	 */
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	assert_key_lock(sdata->local);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	update_vlan_tailroom_need_count(sdata, 1);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (!sdata->crypto_tx_tailroom_needed_cnt++) {
1068c2ecf20Sopenharmony_ci		/*
1078c2ecf20Sopenharmony_ci		 * Flush all XMIT packets currently using HW encryption or no
1088c2ecf20Sopenharmony_ci		 * encryption at all if the count transition is from 0 -> 1.
1098c2ecf20Sopenharmony_ci		 */
1108c2ecf20Sopenharmony_ci		synchronize_net();
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic void decrease_tailroom_need_count(struct ieee80211_sub_if_data *sdata,
1158c2ecf20Sopenharmony_ci					 int delta)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	assert_key_lock(sdata->local);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt < delta);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	update_vlan_tailroom_need_count(sdata, -delta);
1228c2ecf20Sopenharmony_ci	sdata->crypto_tx_tailroom_needed_cnt -= delta;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = key->sdata;
1288c2ecf20Sopenharmony_ci	struct sta_info *sta;
1298c2ecf20Sopenharmony_ci	int ret = -EOPNOTSUPP;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	might_sleep();
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (key->flags & KEY_FLAG_TAINTED) {
1348c2ecf20Sopenharmony_ci		/* If we get here, it's during resume and the key is
1358c2ecf20Sopenharmony_ci		 * tainted so shouldn't be used/programmed any more.
1368c2ecf20Sopenharmony_ci		 * However, its flags may still indicate that it was
1378c2ecf20Sopenharmony_ci		 * programmed into the device (since we're in resume)
1388c2ecf20Sopenharmony_ci		 * so clear that flag now to avoid trying to remove
1398c2ecf20Sopenharmony_ci		 * it again later.
1408c2ecf20Sopenharmony_ci		 */
1418c2ecf20Sopenharmony_ci		if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
1428c2ecf20Sopenharmony_ci		    !(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
1438c2ecf20Sopenharmony_ci					 IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
1448c2ecf20Sopenharmony_ci					 IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
1458c2ecf20Sopenharmony_ci			increment_tailroom_need_count(sdata);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci		key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
1488c2ecf20Sopenharmony_ci		return -EINVAL;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (!key->local->ops->set_key)
1528c2ecf20Sopenharmony_ci		goto out_unsupported;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	assert_key_lock(key->local);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	sta = key->sta;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/*
1598c2ecf20Sopenharmony_ci	 * If this is a per-STA GTK, check if it
1608c2ecf20Sopenharmony_ci	 * is supported; if not, return.
1618c2ecf20Sopenharmony_ci	 */
1628c2ecf20Sopenharmony_ci	if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
1638c2ecf20Sopenharmony_ci	    !ieee80211_hw_check(&key->local->hw, SUPPORTS_PER_STA_GTK))
1648c2ecf20Sopenharmony_ci		goto out_unsupported;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (sta && !sta->uploaded)
1678c2ecf20Sopenharmony_ci		goto out_unsupported;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
1708c2ecf20Sopenharmony_ci		/*
1718c2ecf20Sopenharmony_ci		 * The driver doesn't know anything about VLAN interfaces.
1728c2ecf20Sopenharmony_ci		 * Hence, don't send GTKs for VLAN interfaces to the driver.
1738c2ecf20Sopenharmony_ci		 */
1748c2ecf20Sopenharmony_ci		if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
1758c2ecf20Sopenharmony_ci			ret = 1;
1768c2ecf20Sopenharmony_ci			goto out_unsupported;
1778c2ecf20Sopenharmony_ci		}
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	ret = drv_set_key(key->local, SET_KEY, sdata,
1818c2ecf20Sopenharmony_ci			  sta ? &sta->sta : NULL, &key->conf);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (!ret) {
1848c2ecf20Sopenharmony_ci		key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
1878c2ecf20Sopenharmony_ci					 IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
1888c2ecf20Sopenharmony_ci					 IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
1898c2ecf20Sopenharmony_ci			decrease_tailroom_need_count(sdata, 1);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
1928c2ecf20Sopenharmony_ci			(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV));
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_MIC_SPACE) &&
1958c2ecf20Sopenharmony_ci			(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC));
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		return 0;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (ret != -ENOSPC && ret != -EOPNOTSUPP && ret != 1)
2018c2ecf20Sopenharmony_ci		sdata_err(sdata,
2028c2ecf20Sopenharmony_ci			  "failed to set key (%d, %pM) to hardware (%d)\n",
2038c2ecf20Sopenharmony_ci			  key->conf.keyidx,
2048c2ecf20Sopenharmony_ci			  sta ? sta->sta.addr : bcast_addr, ret);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci out_unsupported:
2078c2ecf20Sopenharmony_ci	switch (key->conf.cipher) {
2088c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
2098c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
2108c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
2118c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
2128c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
2138c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
2148c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
2158c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
2168c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
2178c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
2188c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
2198c2ecf20Sopenharmony_ci		/* all of these we can do in software - if driver can */
2208c2ecf20Sopenharmony_ci		if (ret == 1)
2218c2ecf20Sopenharmony_ci			return 0;
2228c2ecf20Sopenharmony_ci		if (ieee80211_hw_check(&key->local->hw, SW_CRYPTO_CONTROL))
2238c2ecf20Sopenharmony_ci			return -EINVAL;
2248c2ecf20Sopenharmony_ci		return 0;
2258c2ecf20Sopenharmony_ci	default:
2268c2ecf20Sopenharmony_ci		return -EINVAL;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
2338c2ecf20Sopenharmony_ci	struct sta_info *sta;
2348c2ecf20Sopenharmony_ci	int ret;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	might_sleep();
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (!key || !key->local->ops->set_key)
2398c2ecf20Sopenharmony_ci		return;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	assert_key_lock(key->local);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
2448c2ecf20Sopenharmony_ci		return;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	sta = key->sta;
2478c2ecf20Sopenharmony_ci	sdata = key->sdata;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
2508c2ecf20Sopenharmony_ci				 IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
2518c2ecf20Sopenharmony_ci				 IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
2528c2ecf20Sopenharmony_ci		increment_tailroom_need_count(sdata);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
2558c2ecf20Sopenharmony_ci	ret = drv_set_key(key->local, DISABLE_KEY, sdata,
2568c2ecf20Sopenharmony_ci			  sta ? &sta->sta : NULL, &key->conf);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	if (ret)
2598c2ecf20Sopenharmony_ci		sdata_err(sdata,
2608c2ecf20Sopenharmony_ci			  "failed to remove key (%d, %pM) from hardware (%d)\n",
2618c2ecf20Sopenharmony_ci			  key->conf.keyidx,
2628c2ecf20Sopenharmony_ci			  sta ? sta->sta.addr : bcast_addr, ret);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int _ieee80211_set_tx_key(struct ieee80211_key *key, bool force)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct sta_info *sta = key->sta;
2688c2ecf20Sopenharmony_ci	struct ieee80211_local *local = key->local;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	assert_key_lock(local);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	set_sta_flag(sta, WLAN_STA_USES_ENCRYPTION);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	sta->ptk_idx = key->conf.keyidx;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if (force || !ieee80211_hw_check(&local->hw, AMPDU_KEYBORDER_SUPPORT))
2778c2ecf20Sopenharmony_ci		clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
2788c2ecf20Sopenharmony_ci	ieee80211_check_fast_xmit(sta);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return 0;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ciint ieee80211_set_tx_key(struct ieee80211_key *key)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	return _ieee80211_set_tx_key(key, false);
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic void ieee80211_pairwise_rekey(struct ieee80211_key *old,
2898c2ecf20Sopenharmony_ci				     struct ieee80211_key *new)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct ieee80211_local *local = new->local;
2928c2ecf20Sopenharmony_ci	struct sta_info *sta = new->sta;
2938c2ecf20Sopenharmony_ci	int i;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	assert_key_lock(local);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if (new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX) {
2988c2ecf20Sopenharmony_ci		/* Extended Key ID key install, initial one or rekey */
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		if (sta->ptk_idx != INVALID_PTK_KEYIDX &&
3018c2ecf20Sopenharmony_ci		    !ieee80211_hw_check(&local->hw, AMPDU_KEYBORDER_SUPPORT)) {
3028c2ecf20Sopenharmony_ci			/* Aggregation Sessions with Extended Key ID must not
3038c2ecf20Sopenharmony_ci			 * mix MPDUs with different keyIDs within one A-MPDU.
3048c2ecf20Sopenharmony_ci			 * Tear down running Tx aggregation sessions and block
3058c2ecf20Sopenharmony_ci			 * new Rx/Tx aggregation requests during rekey to
3068c2ecf20Sopenharmony_ci			 * ensure there are no A-MPDUs when the driver is not
3078c2ecf20Sopenharmony_ci			 * supporting A-MPDU key borders. (Blocking Tx only
3088c2ecf20Sopenharmony_ci			 * would be sufficient but WLAN_STA_BLOCK_BA gets the
3098c2ecf20Sopenharmony_ci			 * job done for the few ms we need it.)
3108c2ecf20Sopenharmony_ci			 */
3118c2ecf20Sopenharmony_ci			set_sta_flag(sta, WLAN_STA_BLOCK_BA);
3128c2ecf20Sopenharmony_ci			mutex_lock(&sta->ampdu_mlme.mtx);
3138c2ecf20Sopenharmony_ci			for (i = 0; i <  IEEE80211_NUM_TIDS; i++)
3148c2ecf20Sopenharmony_ci				___ieee80211_stop_tx_ba_session(sta, i,
3158c2ecf20Sopenharmony_ci								AGG_STOP_LOCAL_REQUEST);
3168c2ecf20Sopenharmony_ci			mutex_unlock(&sta->ampdu_mlme.mtx);
3178c2ecf20Sopenharmony_ci		}
3188c2ecf20Sopenharmony_ci	} else if (old) {
3198c2ecf20Sopenharmony_ci		/* Rekey without Extended Key ID.
3208c2ecf20Sopenharmony_ci		 * Aggregation sessions are OK when running on SW crypto.
3218c2ecf20Sopenharmony_ci		 * A broken remote STA may cause issues not observed with HW
3228c2ecf20Sopenharmony_ci		 * crypto, though.
3238c2ecf20Sopenharmony_ci		 */
3248c2ecf20Sopenharmony_ci		if (!(old->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
3258c2ecf20Sopenharmony_ci			return;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci		/* Stop Tx till we are on the new key */
3288c2ecf20Sopenharmony_ci		old->flags |= KEY_FLAG_TAINTED;
3298c2ecf20Sopenharmony_ci		ieee80211_clear_fast_xmit(sta);
3308c2ecf20Sopenharmony_ci		if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION)) {
3318c2ecf20Sopenharmony_ci			set_sta_flag(sta, WLAN_STA_BLOCK_BA);
3328c2ecf20Sopenharmony_ci			ieee80211_sta_tear_down_BA_sessions(sta,
3338c2ecf20Sopenharmony_ci							    AGG_STOP_LOCAL_REQUEST);
3348c2ecf20Sopenharmony_ci		}
3358c2ecf20Sopenharmony_ci		if (!wiphy_ext_feature_isset(local->hw.wiphy,
3368c2ecf20Sopenharmony_ci					     NL80211_EXT_FEATURE_CAN_REPLACE_PTK0)) {
3378c2ecf20Sopenharmony_ci			pr_warn_ratelimited("Rekeying PTK for STA %pM but driver can't safely do that.",
3388c2ecf20Sopenharmony_ci					    sta->sta.addr);
3398c2ecf20Sopenharmony_ci			/* Flushing the driver queues *may* help prevent
3408c2ecf20Sopenharmony_ci			 * the clear text leaks and freezes.
3418c2ecf20Sopenharmony_ci			 */
3428c2ecf20Sopenharmony_ci			ieee80211_flush_queues(local, old->sdata, false);
3438c2ecf20Sopenharmony_ci		}
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
3488c2ecf20Sopenharmony_ci					int idx, bool uni, bool multi)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	struct ieee80211_key *key = NULL;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	assert_key_lock(sdata->local);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
3558c2ecf20Sopenharmony_ci		key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (uni) {
3588c2ecf20Sopenharmony_ci		rcu_assign_pointer(sdata->default_unicast_key, key);
3598c2ecf20Sopenharmony_ci		ieee80211_check_fast_xmit_iface(sdata);
3608c2ecf20Sopenharmony_ci		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
3618c2ecf20Sopenharmony_ci			drv_set_default_unicast_key(sdata->local, sdata, idx);
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (multi)
3658c2ecf20Sopenharmony_ci		rcu_assign_pointer(sdata->default_multicast_key, key);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	ieee80211_debugfs_key_update_default(sdata);
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_civoid ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
3718c2ecf20Sopenharmony_ci			       bool uni, bool multi)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	mutex_lock(&sdata->local->key_mtx);
3748c2ecf20Sopenharmony_ci	__ieee80211_set_default_key(sdata, idx, uni, multi);
3758c2ecf20Sopenharmony_ci	mutex_unlock(&sdata->local->key_mtx);
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic void
3798c2ecf20Sopenharmony_ci__ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	struct ieee80211_key *key = NULL;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	assert_key_lock(sdata->local);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (idx >= NUM_DEFAULT_KEYS &&
3868c2ecf20Sopenharmony_ci	    idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
3878c2ecf20Sopenharmony_ci		key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	rcu_assign_pointer(sdata->default_mgmt_key, key);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	ieee80211_debugfs_key_update_default(sdata);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_civoid ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
3958c2ecf20Sopenharmony_ci				    int idx)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	mutex_lock(&sdata->local->key_mtx);
3988c2ecf20Sopenharmony_ci	__ieee80211_set_default_mgmt_key(sdata, idx);
3998c2ecf20Sopenharmony_ci	mutex_unlock(&sdata->local->key_mtx);
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic void
4038c2ecf20Sopenharmony_ci__ieee80211_set_default_beacon_key(struct ieee80211_sub_if_data *sdata, int idx)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	struct ieee80211_key *key = NULL;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	assert_key_lock(sdata->local);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	if (idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS &&
4108c2ecf20Sopenharmony_ci	    idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
4118c2ecf20Sopenharmony_ci	    NUM_DEFAULT_BEACON_KEYS)
4128c2ecf20Sopenharmony_ci		key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	rcu_assign_pointer(sdata->default_beacon_key, key);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	ieee80211_debugfs_key_update_default(sdata);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_civoid ieee80211_set_default_beacon_key(struct ieee80211_sub_if_data *sdata,
4208c2ecf20Sopenharmony_ci				      int idx)
4218c2ecf20Sopenharmony_ci{
4228c2ecf20Sopenharmony_ci	mutex_lock(&sdata->local->key_mtx);
4238c2ecf20Sopenharmony_ci	__ieee80211_set_default_beacon_key(sdata, idx);
4248c2ecf20Sopenharmony_ci	mutex_unlock(&sdata->local->key_mtx);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
4288c2ecf20Sopenharmony_ci				  struct sta_info *sta,
4298c2ecf20Sopenharmony_ci				  bool pairwise,
4308c2ecf20Sopenharmony_ci				  struct ieee80211_key *old,
4318c2ecf20Sopenharmony_ci				  struct ieee80211_key *new)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	int idx;
4348c2ecf20Sopenharmony_ci	int ret = 0;
4358c2ecf20Sopenharmony_ci	bool defunikey, defmultikey, defmgmtkey, defbeaconkey;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	/* caller must provide at least one old/new */
4388c2ecf20Sopenharmony_ci	if (WARN_ON(!new && !old))
4398c2ecf20Sopenharmony_ci		return 0;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (new)
4428c2ecf20Sopenharmony_ci		list_add_tail_rcu(&new->list, &sdata->key_list);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (new && sta && pairwise) {
4478c2ecf20Sopenharmony_ci		/* Unicast rekey needs special handling. With Extended Key ID
4488c2ecf20Sopenharmony_ci		 * old is still NULL for the first rekey.
4498c2ecf20Sopenharmony_ci		 */
4508c2ecf20Sopenharmony_ci		ieee80211_pairwise_rekey(old, new);
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (old) {
4548c2ecf20Sopenharmony_ci		idx = old->conf.keyidx;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		if (old->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
4578c2ecf20Sopenharmony_ci			ieee80211_key_disable_hw_accel(old);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci			if (new)
4608c2ecf20Sopenharmony_ci				ret = ieee80211_key_enable_hw_accel(new);
4618c2ecf20Sopenharmony_ci		}
4628c2ecf20Sopenharmony_ci	} else {
4638c2ecf20Sopenharmony_ci		/* new must be provided in case old is not */
4648c2ecf20Sopenharmony_ci		idx = new->conf.keyidx;
4658c2ecf20Sopenharmony_ci		if (!new->local->wowlan)
4668c2ecf20Sopenharmony_ci			ret = ieee80211_key_enable_hw_accel(new);
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	if (ret)
4708c2ecf20Sopenharmony_ci		return ret;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (sta) {
4738c2ecf20Sopenharmony_ci		if (pairwise) {
4748c2ecf20Sopenharmony_ci			rcu_assign_pointer(sta->ptk[idx], new);
4758c2ecf20Sopenharmony_ci			if (new &&
4768c2ecf20Sopenharmony_ci			    !(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX))
4778c2ecf20Sopenharmony_ci				_ieee80211_set_tx_key(new, true);
4788c2ecf20Sopenharmony_ci		} else {
4798c2ecf20Sopenharmony_ci			rcu_assign_pointer(sta->gtk[idx], new);
4808c2ecf20Sopenharmony_ci		}
4818c2ecf20Sopenharmony_ci		/* Only needed for transition from no key -> key.
4828c2ecf20Sopenharmony_ci		 * Still triggers unnecessary when using Extended Key ID
4838c2ecf20Sopenharmony_ci		 * and installing the second key ID the first time.
4848c2ecf20Sopenharmony_ci		 */
4858c2ecf20Sopenharmony_ci		if (new && !old)
4868c2ecf20Sopenharmony_ci			ieee80211_check_fast_rx(sta);
4878c2ecf20Sopenharmony_ci	} else {
4888c2ecf20Sopenharmony_ci		defunikey = old &&
4898c2ecf20Sopenharmony_ci			old == key_mtx_dereference(sdata->local,
4908c2ecf20Sopenharmony_ci						sdata->default_unicast_key);
4918c2ecf20Sopenharmony_ci		defmultikey = old &&
4928c2ecf20Sopenharmony_ci			old == key_mtx_dereference(sdata->local,
4938c2ecf20Sopenharmony_ci						sdata->default_multicast_key);
4948c2ecf20Sopenharmony_ci		defmgmtkey = old &&
4958c2ecf20Sopenharmony_ci			old == key_mtx_dereference(sdata->local,
4968c2ecf20Sopenharmony_ci						sdata->default_mgmt_key);
4978c2ecf20Sopenharmony_ci		defbeaconkey = old &&
4988c2ecf20Sopenharmony_ci			old == key_mtx_dereference(sdata->local,
4998c2ecf20Sopenharmony_ci						   sdata->default_beacon_key);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci		if (defunikey && !new)
5028c2ecf20Sopenharmony_ci			__ieee80211_set_default_key(sdata, -1, true, false);
5038c2ecf20Sopenharmony_ci		if (defmultikey && !new)
5048c2ecf20Sopenharmony_ci			__ieee80211_set_default_key(sdata, -1, false, true);
5058c2ecf20Sopenharmony_ci		if (defmgmtkey && !new)
5068c2ecf20Sopenharmony_ci			__ieee80211_set_default_mgmt_key(sdata, -1);
5078c2ecf20Sopenharmony_ci		if (defbeaconkey && !new)
5088c2ecf20Sopenharmony_ci			__ieee80211_set_default_beacon_key(sdata, -1);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci		rcu_assign_pointer(sdata->keys[idx], new);
5118c2ecf20Sopenharmony_ci		if (defunikey && new)
5128c2ecf20Sopenharmony_ci			__ieee80211_set_default_key(sdata, new->conf.keyidx,
5138c2ecf20Sopenharmony_ci						    true, false);
5148c2ecf20Sopenharmony_ci		if (defmultikey && new)
5158c2ecf20Sopenharmony_ci			__ieee80211_set_default_key(sdata, new->conf.keyidx,
5168c2ecf20Sopenharmony_ci						    false, true);
5178c2ecf20Sopenharmony_ci		if (defmgmtkey && new)
5188c2ecf20Sopenharmony_ci			__ieee80211_set_default_mgmt_key(sdata,
5198c2ecf20Sopenharmony_ci							 new->conf.keyidx);
5208c2ecf20Sopenharmony_ci		if (defbeaconkey && new)
5218c2ecf20Sopenharmony_ci			__ieee80211_set_default_beacon_key(sdata,
5228c2ecf20Sopenharmony_ci							   new->conf.keyidx);
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (old)
5268c2ecf20Sopenharmony_ci		list_del_rcu(&old->list);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	return 0;
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistruct ieee80211_key *
5328c2ecf20Sopenharmony_ciieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
5338c2ecf20Sopenharmony_ci		    const u8 *key_data,
5348c2ecf20Sopenharmony_ci		    size_t seq_len, const u8 *seq,
5358c2ecf20Sopenharmony_ci		    const struct ieee80211_cipher_scheme *cs)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	struct ieee80211_key *key;
5388c2ecf20Sopenharmony_ci	int i, j, err;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (WARN_ON(idx < 0 ||
5418c2ecf20Sopenharmony_ci		    idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
5428c2ecf20Sopenharmony_ci		    NUM_DEFAULT_BEACON_KEYS))
5438c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
5468c2ecf20Sopenharmony_ci	if (!key)
5478c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	/*
5508c2ecf20Sopenharmony_ci	 * Default to software encryption; we'll later upload the
5518c2ecf20Sopenharmony_ci	 * key to the hardware if possible.
5528c2ecf20Sopenharmony_ci	 */
5538c2ecf20Sopenharmony_ci	key->conf.flags = 0;
5548c2ecf20Sopenharmony_ci	key->flags = 0;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	key->conf.cipher = cipher;
5578c2ecf20Sopenharmony_ci	key->conf.keyidx = idx;
5588c2ecf20Sopenharmony_ci	key->conf.keylen = key_len;
5598c2ecf20Sopenharmony_ci	switch (cipher) {
5608c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
5618c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
5628c2ecf20Sopenharmony_ci		key->conf.iv_len = IEEE80211_WEP_IV_LEN;
5638c2ecf20Sopenharmony_ci		key->conf.icv_len = IEEE80211_WEP_ICV_LEN;
5648c2ecf20Sopenharmony_ci		break;
5658c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
5668c2ecf20Sopenharmony_ci		key->conf.iv_len = IEEE80211_TKIP_IV_LEN;
5678c2ecf20Sopenharmony_ci		key->conf.icv_len = IEEE80211_TKIP_ICV_LEN;
5688c2ecf20Sopenharmony_ci		if (seq) {
5698c2ecf20Sopenharmony_ci			for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
5708c2ecf20Sopenharmony_ci				key->u.tkip.rx[i].iv32 =
5718c2ecf20Sopenharmony_ci					get_unaligned_le32(&seq[2]);
5728c2ecf20Sopenharmony_ci				key->u.tkip.rx[i].iv16 =
5738c2ecf20Sopenharmony_ci					get_unaligned_le16(seq);
5748c2ecf20Sopenharmony_ci			}
5758c2ecf20Sopenharmony_ci		}
5768c2ecf20Sopenharmony_ci		spin_lock_init(&key->u.tkip.txlock);
5778c2ecf20Sopenharmony_ci		break;
5788c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
5798c2ecf20Sopenharmony_ci		key->conf.iv_len = IEEE80211_CCMP_HDR_LEN;
5808c2ecf20Sopenharmony_ci		key->conf.icv_len = IEEE80211_CCMP_MIC_LEN;
5818c2ecf20Sopenharmony_ci		if (seq) {
5828c2ecf20Sopenharmony_ci			for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
5838c2ecf20Sopenharmony_ci				for (j = 0; j < IEEE80211_CCMP_PN_LEN; j++)
5848c2ecf20Sopenharmony_ci					key->u.ccmp.rx_pn[i][j] =
5858c2ecf20Sopenharmony_ci						seq[IEEE80211_CCMP_PN_LEN - j - 1];
5868c2ecf20Sopenharmony_ci		}
5878c2ecf20Sopenharmony_ci		/*
5888c2ecf20Sopenharmony_ci		 * Initialize AES key state here as an optimization so that
5898c2ecf20Sopenharmony_ci		 * it does not need to be initialized for every packet.
5908c2ecf20Sopenharmony_ci		 */
5918c2ecf20Sopenharmony_ci		key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
5928c2ecf20Sopenharmony_ci			key_data, key_len, IEEE80211_CCMP_MIC_LEN);
5938c2ecf20Sopenharmony_ci		if (IS_ERR(key->u.ccmp.tfm)) {
5948c2ecf20Sopenharmony_ci			err = PTR_ERR(key->u.ccmp.tfm);
5958c2ecf20Sopenharmony_ci			kfree(key);
5968c2ecf20Sopenharmony_ci			return ERR_PTR(err);
5978c2ecf20Sopenharmony_ci		}
5988c2ecf20Sopenharmony_ci		break;
5998c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
6008c2ecf20Sopenharmony_ci		key->conf.iv_len = IEEE80211_CCMP_256_HDR_LEN;
6018c2ecf20Sopenharmony_ci		key->conf.icv_len = IEEE80211_CCMP_256_MIC_LEN;
6028c2ecf20Sopenharmony_ci		for (i = 0; seq && i < IEEE80211_NUM_TIDS + 1; i++)
6038c2ecf20Sopenharmony_ci			for (j = 0; j < IEEE80211_CCMP_256_PN_LEN; j++)
6048c2ecf20Sopenharmony_ci				key->u.ccmp.rx_pn[i][j] =
6058c2ecf20Sopenharmony_ci					seq[IEEE80211_CCMP_256_PN_LEN - j - 1];
6068c2ecf20Sopenharmony_ci		/* Initialize AES key state here as an optimization so that
6078c2ecf20Sopenharmony_ci		 * it does not need to be initialized for every packet.
6088c2ecf20Sopenharmony_ci		 */
6098c2ecf20Sopenharmony_ci		key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
6108c2ecf20Sopenharmony_ci			key_data, key_len, IEEE80211_CCMP_256_MIC_LEN);
6118c2ecf20Sopenharmony_ci		if (IS_ERR(key->u.ccmp.tfm)) {
6128c2ecf20Sopenharmony_ci			err = PTR_ERR(key->u.ccmp.tfm);
6138c2ecf20Sopenharmony_ci			kfree(key);
6148c2ecf20Sopenharmony_ci			return ERR_PTR(err);
6158c2ecf20Sopenharmony_ci		}
6168c2ecf20Sopenharmony_ci		break;
6178c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
6188c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
6198c2ecf20Sopenharmony_ci		key->conf.iv_len = 0;
6208c2ecf20Sopenharmony_ci		if (cipher == WLAN_CIPHER_SUITE_AES_CMAC)
6218c2ecf20Sopenharmony_ci			key->conf.icv_len = sizeof(struct ieee80211_mmie);
6228c2ecf20Sopenharmony_ci		else
6238c2ecf20Sopenharmony_ci			key->conf.icv_len = sizeof(struct ieee80211_mmie_16);
6248c2ecf20Sopenharmony_ci		if (seq)
6258c2ecf20Sopenharmony_ci			for (j = 0; j < IEEE80211_CMAC_PN_LEN; j++)
6268c2ecf20Sopenharmony_ci				key->u.aes_cmac.rx_pn[j] =
6278c2ecf20Sopenharmony_ci					seq[IEEE80211_CMAC_PN_LEN - j - 1];
6288c2ecf20Sopenharmony_ci		/*
6298c2ecf20Sopenharmony_ci		 * Initialize AES key state here as an optimization so that
6308c2ecf20Sopenharmony_ci		 * it does not need to be initialized for every packet.
6318c2ecf20Sopenharmony_ci		 */
6328c2ecf20Sopenharmony_ci		key->u.aes_cmac.tfm =
6338c2ecf20Sopenharmony_ci			ieee80211_aes_cmac_key_setup(key_data, key_len);
6348c2ecf20Sopenharmony_ci		if (IS_ERR(key->u.aes_cmac.tfm)) {
6358c2ecf20Sopenharmony_ci			err = PTR_ERR(key->u.aes_cmac.tfm);
6368c2ecf20Sopenharmony_ci			kfree(key);
6378c2ecf20Sopenharmony_ci			return ERR_PTR(err);
6388c2ecf20Sopenharmony_ci		}
6398c2ecf20Sopenharmony_ci		break;
6408c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
6418c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
6428c2ecf20Sopenharmony_ci		key->conf.iv_len = 0;
6438c2ecf20Sopenharmony_ci		key->conf.icv_len = sizeof(struct ieee80211_mmie_16);
6448c2ecf20Sopenharmony_ci		if (seq)
6458c2ecf20Sopenharmony_ci			for (j = 0; j < IEEE80211_GMAC_PN_LEN; j++)
6468c2ecf20Sopenharmony_ci				key->u.aes_gmac.rx_pn[j] =
6478c2ecf20Sopenharmony_ci					seq[IEEE80211_GMAC_PN_LEN - j - 1];
6488c2ecf20Sopenharmony_ci		/* Initialize AES key state here as an optimization so that
6498c2ecf20Sopenharmony_ci		 * it does not need to be initialized for every packet.
6508c2ecf20Sopenharmony_ci		 */
6518c2ecf20Sopenharmony_ci		key->u.aes_gmac.tfm =
6528c2ecf20Sopenharmony_ci			ieee80211_aes_gmac_key_setup(key_data, key_len);
6538c2ecf20Sopenharmony_ci		if (IS_ERR(key->u.aes_gmac.tfm)) {
6548c2ecf20Sopenharmony_ci			err = PTR_ERR(key->u.aes_gmac.tfm);
6558c2ecf20Sopenharmony_ci			kfree(key);
6568c2ecf20Sopenharmony_ci			return ERR_PTR(err);
6578c2ecf20Sopenharmony_ci		}
6588c2ecf20Sopenharmony_ci		break;
6598c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
6608c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
6618c2ecf20Sopenharmony_ci		key->conf.iv_len = IEEE80211_GCMP_HDR_LEN;
6628c2ecf20Sopenharmony_ci		key->conf.icv_len = IEEE80211_GCMP_MIC_LEN;
6638c2ecf20Sopenharmony_ci		for (i = 0; seq && i < IEEE80211_NUM_TIDS + 1; i++)
6648c2ecf20Sopenharmony_ci			for (j = 0; j < IEEE80211_GCMP_PN_LEN; j++)
6658c2ecf20Sopenharmony_ci				key->u.gcmp.rx_pn[i][j] =
6668c2ecf20Sopenharmony_ci					seq[IEEE80211_GCMP_PN_LEN - j - 1];
6678c2ecf20Sopenharmony_ci		/* Initialize AES key state here as an optimization so that
6688c2ecf20Sopenharmony_ci		 * it does not need to be initialized for every packet.
6698c2ecf20Sopenharmony_ci		 */
6708c2ecf20Sopenharmony_ci		key->u.gcmp.tfm = ieee80211_aes_gcm_key_setup_encrypt(key_data,
6718c2ecf20Sopenharmony_ci								      key_len);
6728c2ecf20Sopenharmony_ci		if (IS_ERR(key->u.gcmp.tfm)) {
6738c2ecf20Sopenharmony_ci			err = PTR_ERR(key->u.gcmp.tfm);
6748c2ecf20Sopenharmony_ci			kfree(key);
6758c2ecf20Sopenharmony_ci			return ERR_PTR(err);
6768c2ecf20Sopenharmony_ci		}
6778c2ecf20Sopenharmony_ci		break;
6788c2ecf20Sopenharmony_ci	default:
6798c2ecf20Sopenharmony_ci		if (cs) {
6808c2ecf20Sopenharmony_ci			if (seq_len && seq_len != cs->pn_len) {
6818c2ecf20Sopenharmony_ci				kfree(key);
6828c2ecf20Sopenharmony_ci				return ERR_PTR(-EINVAL);
6838c2ecf20Sopenharmony_ci			}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci			key->conf.iv_len = cs->hdr_len;
6868c2ecf20Sopenharmony_ci			key->conf.icv_len = cs->mic_len;
6878c2ecf20Sopenharmony_ci			for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
6888c2ecf20Sopenharmony_ci				for (j = 0; j < seq_len; j++)
6898c2ecf20Sopenharmony_ci					key->u.gen.rx_pn[i][j] =
6908c2ecf20Sopenharmony_ci							seq[seq_len - j - 1];
6918c2ecf20Sopenharmony_ci			key->flags |= KEY_FLAG_CIPHER_SCHEME;
6928c2ecf20Sopenharmony_ci		}
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci	memcpy(key->conf.key, key_data, key_len);
6958c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&key->list);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	return key;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic void ieee80211_key_free_common(struct ieee80211_key *key)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	switch (key->conf.cipher) {
7038c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
7048c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
7058c2ecf20Sopenharmony_ci		ieee80211_aes_key_free(key->u.ccmp.tfm);
7068c2ecf20Sopenharmony_ci		break;
7078c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
7088c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
7098c2ecf20Sopenharmony_ci		ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
7108c2ecf20Sopenharmony_ci		break;
7118c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
7128c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
7138c2ecf20Sopenharmony_ci		ieee80211_aes_gmac_key_free(key->u.aes_gmac.tfm);
7148c2ecf20Sopenharmony_ci		break;
7158c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
7168c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
7178c2ecf20Sopenharmony_ci		ieee80211_aes_gcm_key_free(key->u.gcmp.tfm);
7188c2ecf20Sopenharmony_ci		break;
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci	kfree_sensitive(key);
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_cistatic void __ieee80211_key_destroy(struct ieee80211_key *key,
7248c2ecf20Sopenharmony_ci				    bool delay_tailroom)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	if (key->local) {
7278c2ecf20Sopenharmony_ci		struct ieee80211_sub_if_data *sdata = key->sdata;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci		ieee80211_debugfs_key_remove(key);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		if (delay_tailroom) {
7328c2ecf20Sopenharmony_ci			/* see ieee80211_delayed_tailroom_dec */
7338c2ecf20Sopenharmony_ci			sdata->crypto_tx_tailroom_pending_dec++;
7348c2ecf20Sopenharmony_ci			schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
7358c2ecf20Sopenharmony_ci					      HZ/2);
7368c2ecf20Sopenharmony_ci		} else {
7378c2ecf20Sopenharmony_ci			decrease_tailroom_need_count(sdata, 1);
7388c2ecf20Sopenharmony_ci		}
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	ieee80211_key_free_common(key);
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cistatic void ieee80211_key_destroy(struct ieee80211_key *key,
7458c2ecf20Sopenharmony_ci				  bool delay_tailroom)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	if (!key)
7488c2ecf20Sopenharmony_ci		return;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	/*
7518c2ecf20Sopenharmony_ci	 * Synchronize so the TX path and rcu key iterators
7528c2ecf20Sopenharmony_ci	 * can no longer be using this key before we free/remove it.
7538c2ecf20Sopenharmony_ci	 */
7548c2ecf20Sopenharmony_ci	synchronize_net();
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	__ieee80211_key_destroy(key, delay_tailroom);
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_civoid ieee80211_key_free_unused(struct ieee80211_key *key)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	WARN_ON(key->sdata || key->local);
7628c2ecf20Sopenharmony_ci	ieee80211_key_free_common(key);
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic bool ieee80211_key_identical(struct ieee80211_sub_if_data *sdata,
7668c2ecf20Sopenharmony_ci				    struct ieee80211_key *old,
7678c2ecf20Sopenharmony_ci				    struct ieee80211_key *new)
7688c2ecf20Sopenharmony_ci{
7698c2ecf20Sopenharmony_ci	u8 tkip_old[WLAN_KEY_LEN_TKIP], tkip_new[WLAN_KEY_LEN_TKIP];
7708c2ecf20Sopenharmony_ci	u8 *tk_old, *tk_new;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	if (!old || new->conf.keylen != old->conf.keylen)
7738c2ecf20Sopenharmony_ci		return false;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	tk_old = old->conf.key;
7768c2ecf20Sopenharmony_ci	tk_new = new->conf.key;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	/*
7798c2ecf20Sopenharmony_ci	 * In station mode, don't compare the TX MIC key, as it's never used
7808c2ecf20Sopenharmony_ci	 * and offloaded rekeying may not care to send it to the host. This
7818c2ecf20Sopenharmony_ci	 * is the case in iwlwifi, for example.
7828c2ecf20Sopenharmony_ci	 */
7838c2ecf20Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
7848c2ecf20Sopenharmony_ci	    new->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
7858c2ecf20Sopenharmony_ci	    new->conf.keylen == WLAN_KEY_LEN_TKIP &&
7868c2ecf20Sopenharmony_ci	    !(new->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
7878c2ecf20Sopenharmony_ci		memcpy(tkip_old, tk_old, WLAN_KEY_LEN_TKIP);
7888c2ecf20Sopenharmony_ci		memcpy(tkip_new, tk_new, WLAN_KEY_LEN_TKIP);
7898c2ecf20Sopenharmony_ci		memset(tkip_old + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8);
7908c2ecf20Sopenharmony_ci		memset(tkip_new + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8);
7918c2ecf20Sopenharmony_ci		tk_old = tkip_old;
7928c2ecf20Sopenharmony_ci		tk_new = tkip_new;
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	return !crypto_memneq(tk_old, tk_new, new->conf.keylen);
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ciint ieee80211_key_link(struct ieee80211_key *key,
7998c2ecf20Sopenharmony_ci		       struct ieee80211_sub_if_data *sdata,
8008c2ecf20Sopenharmony_ci		       struct sta_info *sta)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	static atomic_t key_color = ATOMIC_INIT(0);
8038c2ecf20Sopenharmony_ci	struct ieee80211_key *old_key;
8048c2ecf20Sopenharmony_ci	int idx = key->conf.keyidx;
8058c2ecf20Sopenharmony_ci	bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
8068c2ecf20Sopenharmony_ci	/*
8078c2ecf20Sopenharmony_ci	 * We want to delay tailroom updates only for station - in that
8088c2ecf20Sopenharmony_ci	 * case it helps roaming speed, but in other cases it hurts and
8098c2ecf20Sopenharmony_ci	 * can cause warnings to appear.
8108c2ecf20Sopenharmony_ci	 */
8118c2ecf20Sopenharmony_ci	bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
8128c2ecf20Sopenharmony_ci	int ret = -EOPNOTSUPP;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	mutex_lock(&sdata->local->key_mtx);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	if (sta && pairwise) {
8178c2ecf20Sopenharmony_ci		struct ieee80211_key *alt_key;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
8208c2ecf20Sopenharmony_ci		alt_key = key_mtx_dereference(sdata->local, sta->ptk[idx ^ 1]);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci		/* The rekey code assumes that the old and new key are using
8238c2ecf20Sopenharmony_ci		 * the same cipher. Enforce the assumption for pairwise keys.
8248c2ecf20Sopenharmony_ci		 */
8258c2ecf20Sopenharmony_ci		if ((alt_key && alt_key->conf.cipher != key->conf.cipher) ||
8268c2ecf20Sopenharmony_ci		    (old_key && old_key->conf.cipher != key->conf.cipher))
8278c2ecf20Sopenharmony_ci			goto out;
8288c2ecf20Sopenharmony_ci	} else if (sta) {
8298c2ecf20Sopenharmony_ci		old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
8308c2ecf20Sopenharmony_ci	} else {
8318c2ecf20Sopenharmony_ci		old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	/* Non-pairwise keys must also not switch the cipher on rekey */
8358c2ecf20Sopenharmony_ci	if (!pairwise) {
8368c2ecf20Sopenharmony_ci		if (old_key && old_key->conf.cipher != key->conf.cipher)
8378c2ecf20Sopenharmony_ci			goto out;
8388c2ecf20Sopenharmony_ci	}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	/*
8418c2ecf20Sopenharmony_ci	 * Silently accept key re-installation without really installing the
8428c2ecf20Sopenharmony_ci	 * new version of the key to avoid nonce reuse or replay issues.
8438c2ecf20Sopenharmony_ci	 */
8448c2ecf20Sopenharmony_ci	if (ieee80211_key_identical(sdata, old_key, key)) {
8458c2ecf20Sopenharmony_ci		ieee80211_key_free_unused(key);
8468c2ecf20Sopenharmony_ci		ret = -EALREADY;
8478c2ecf20Sopenharmony_ci		goto out;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	key->local = sdata->local;
8518c2ecf20Sopenharmony_ci	key->sdata = sdata;
8528c2ecf20Sopenharmony_ci	key->sta = sta;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	/*
8558c2ecf20Sopenharmony_ci	 * Assign a unique ID to every key so we can easily prevent mixed
8568c2ecf20Sopenharmony_ci	 * key and fragment cache attacks.
8578c2ecf20Sopenharmony_ci	 */
8588c2ecf20Sopenharmony_ci	key->color = atomic_inc_return(&key_color);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	increment_tailroom_need_count(sdata);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	ret = ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	if (!ret) {
8658c2ecf20Sopenharmony_ci		ieee80211_debugfs_key_add(key);
8668c2ecf20Sopenharmony_ci		ieee80211_key_destroy(old_key, delay_tailroom);
8678c2ecf20Sopenharmony_ci	} else {
8688c2ecf20Sopenharmony_ci		ieee80211_key_free(key, delay_tailroom);
8698c2ecf20Sopenharmony_ci	}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci out:
8728c2ecf20Sopenharmony_ci	mutex_unlock(&sdata->local->key_mtx);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	return ret;
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_civoid ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	if (!key)
8808c2ecf20Sopenharmony_ci		return;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/*
8838c2ecf20Sopenharmony_ci	 * Replace key with nothingness if it was ever used.
8848c2ecf20Sopenharmony_ci	 */
8858c2ecf20Sopenharmony_ci	if (key->sdata)
8868c2ecf20Sopenharmony_ci		ieee80211_key_replace(key->sdata, key->sta,
8878c2ecf20Sopenharmony_ci				key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
8888c2ecf20Sopenharmony_ci				key, NULL);
8898c2ecf20Sopenharmony_ci	ieee80211_key_destroy(key, delay_tailroom);
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_civoid ieee80211_reenable_keys(struct ieee80211_sub_if_data *sdata)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	struct ieee80211_key *key;
8958c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *vlan;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	ASSERT_RTNL();
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	mutex_lock(&sdata->local->key_mtx);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	sdata->crypto_tx_tailroom_needed_cnt = 0;
9028c2ecf20Sopenharmony_ci	sdata->crypto_tx_tailroom_pending_dec = 0;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP) {
9058c2ecf20Sopenharmony_ci		list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
9068c2ecf20Sopenharmony_ci			vlan->crypto_tx_tailroom_needed_cnt = 0;
9078c2ecf20Sopenharmony_ci			vlan->crypto_tx_tailroom_pending_dec = 0;
9088c2ecf20Sopenharmony_ci		}
9098c2ecf20Sopenharmony_ci	}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	if (ieee80211_sdata_running(sdata)) {
9128c2ecf20Sopenharmony_ci		list_for_each_entry(key, &sdata->key_list, list) {
9138c2ecf20Sopenharmony_ci			increment_tailroom_need_count(sdata);
9148c2ecf20Sopenharmony_ci			ieee80211_key_enable_hw_accel(key);
9158c2ecf20Sopenharmony_ci		}
9168c2ecf20Sopenharmony_ci	}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	mutex_unlock(&sdata->local->key_mtx);
9198c2ecf20Sopenharmony_ci}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_civoid ieee80211_iter_keys(struct ieee80211_hw *hw,
9228c2ecf20Sopenharmony_ci			 struct ieee80211_vif *vif,
9238c2ecf20Sopenharmony_ci			 void (*iter)(struct ieee80211_hw *hw,
9248c2ecf20Sopenharmony_ci				      struct ieee80211_vif *vif,
9258c2ecf20Sopenharmony_ci				      struct ieee80211_sta *sta,
9268c2ecf20Sopenharmony_ci				      struct ieee80211_key_conf *key,
9278c2ecf20Sopenharmony_ci				      void *data),
9288c2ecf20Sopenharmony_ci			 void *iter_data)
9298c2ecf20Sopenharmony_ci{
9308c2ecf20Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
9318c2ecf20Sopenharmony_ci	struct ieee80211_key *key, *tmp;
9328c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	ASSERT_RTNL();
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	mutex_lock(&local->key_mtx);
9378c2ecf20Sopenharmony_ci	if (vif) {
9388c2ecf20Sopenharmony_ci		sdata = vif_to_sdata(vif);
9398c2ecf20Sopenharmony_ci		list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
9408c2ecf20Sopenharmony_ci			iter(hw, &sdata->vif,
9418c2ecf20Sopenharmony_ci			     key->sta ? &key->sta->sta : NULL,
9428c2ecf20Sopenharmony_ci			     &key->conf, iter_data);
9438c2ecf20Sopenharmony_ci	} else {
9448c2ecf20Sopenharmony_ci		list_for_each_entry(sdata, &local->interfaces, list)
9458c2ecf20Sopenharmony_ci			list_for_each_entry_safe(key, tmp,
9468c2ecf20Sopenharmony_ci						 &sdata->key_list, list)
9478c2ecf20Sopenharmony_ci				iter(hw, &sdata->vif,
9488c2ecf20Sopenharmony_ci				     key->sta ? &key->sta->sta : NULL,
9498c2ecf20Sopenharmony_ci				     &key->conf, iter_data);
9508c2ecf20Sopenharmony_ci	}
9518c2ecf20Sopenharmony_ci	mutex_unlock(&local->key_mtx);
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_iter_keys);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistatic void
9568c2ecf20Sopenharmony_ci_ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,
9578c2ecf20Sopenharmony_ci			 struct ieee80211_sub_if_data *sdata,
9588c2ecf20Sopenharmony_ci			 void (*iter)(struct ieee80211_hw *hw,
9598c2ecf20Sopenharmony_ci				      struct ieee80211_vif *vif,
9608c2ecf20Sopenharmony_ci				      struct ieee80211_sta *sta,
9618c2ecf20Sopenharmony_ci				      struct ieee80211_key_conf *key,
9628c2ecf20Sopenharmony_ci				      void *data),
9638c2ecf20Sopenharmony_ci			 void *iter_data)
9648c2ecf20Sopenharmony_ci{
9658c2ecf20Sopenharmony_ci	struct ieee80211_key *key;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(key, &sdata->key_list, list) {
9688c2ecf20Sopenharmony_ci		/* skip keys of station in removal process */
9698c2ecf20Sopenharmony_ci		if (key->sta && key->sta->removed)
9708c2ecf20Sopenharmony_ci			continue;
9718c2ecf20Sopenharmony_ci		if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
9728c2ecf20Sopenharmony_ci			continue;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci		iter(hw, &sdata->vif,
9758c2ecf20Sopenharmony_ci		     key->sta ? &key->sta->sta : NULL,
9768c2ecf20Sopenharmony_ci		     &key->conf, iter_data);
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_civoid ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,
9818c2ecf20Sopenharmony_ci			     struct ieee80211_vif *vif,
9828c2ecf20Sopenharmony_ci			     void (*iter)(struct ieee80211_hw *hw,
9838c2ecf20Sopenharmony_ci					  struct ieee80211_vif *vif,
9848c2ecf20Sopenharmony_ci					  struct ieee80211_sta *sta,
9858c2ecf20Sopenharmony_ci					  struct ieee80211_key_conf *key,
9868c2ecf20Sopenharmony_ci					  void *data),
9878c2ecf20Sopenharmony_ci			     void *iter_data)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	struct ieee80211_local *local = hw_to_local(hw);
9908c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	if (vif) {
9938c2ecf20Sopenharmony_ci		sdata = vif_to_sdata(vif);
9948c2ecf20Sopenharmony_ci		_ieee80211_iter_keys_rcu(hw, sdata, iter, iter_data);
9958c2ecf20Sopenharmony_ci	} else {
9968c2ecf20Sopenharmony_ci		list_for_each_entry_rcu(sdata, &local->interfaces, list)
9978c2ecf20Sopenharmony_ci			_ieee80211_iter_keys_rcu(hw, sdata, iter, iter_data);
9988c2ecf20Sopenharmony_ci	}
9998c2ecf20Sopenharmony_ci}
10008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_iter_keys_rcu);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_cistatic void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
10038c2ecf20Sopenharmony_ci				      struct list_head *keys)
10048c2ecf20Sopenharmony_ci{
10058c2ecf20Sopenharmony_ci	struct ieee80211_key *key, *tmp;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	decrease_tailroom_need_count(sdata,
10088c2ecf20Sopenharmony_ci				     sdata->crypto_tx_tailroom_pending_dec);
10098c2ecf20Sopenharmony_ci	sdata->crypto_tx_tailroom_pending_dec = 0;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	ieee80211_debugfs_key_remove_mgmt_default(sdata);
10128c2ecf20Sopenharmony_ci	ieee80211_debugfs_key_remove_beacon_default(sdata);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	list_for_each_entry_safe(key, tmp, &sdata->key_list, list) {
10158c2ecf20Sopenharmony_ci		ieee80211_key_replace(key->sdata, key->sta,
10168c2ecf20Sopenharmony_ci				key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
10178c2ecf20Sopenharmony_ci				key, NULL);
10188c2ecf20Sopenharmony_ci		list_add_tail(&key->list, keys);
10198c2ecf20Sopenharmony_ci	}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	ieee80211_debugfs_key_update_default(sdata);
10228c2ecf20Sopenharmony_ci}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_civoid ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
10258c2ecf20Sopenharmony_ci			 bool force_synchronize)
10268c2ecf20Sopenharmony_ci{
10278c2ecf20Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
10288c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *vlan;
10298c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *master;
10308c2ecf20Sopenharmony_ci	struct ieee80211_key *key, *tmp;
10318c2ecf20Sopenharmony_ci	LIST_HEAD(keys);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	mutex_lock(&local->key_mtx);
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	ieee80211_free_keys_iface(sdata, &keys);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP) {
10408c2ecf20Sopenharmony_ci		list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
10418c2ecf20Sopenharmony_ci			ieee80211_free_keys_iface(vlan, &keys);
10428c2ecf20Sopenharmony_ci	}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	if (!list_empty(&keys) || force_synchronize)
10458c2ecf20Sopenharmony_ci		synchronize_net();
10468c2ecf20Sopenharmony_ci	list_for_each_entry_safe(key, tmp, &keys, list)
10478c2ecf20Sopenharmony_ci		__ieee80211_key_destroy(key, false);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
10508c2ecf20Sopenharmony_ci		if (sdata->bss) {
10518c2ecf20Sopenharmony_ci			master = container_of(sdata->bss,
10528c2ecf20Sopenharmony_ci					      struct ieee80211_sub_if_data,
10538c2ecf20Sopenharmony_ci					      u.ap);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci			WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt !=
10568c2ecf20Sopenharmony_ci				     master->crypto_tx_tailroom_needed_cnt);
10578c2ecf20Sopenharmony_ci		}
10588c2ecf20Sopenharmony_ci	} else {
10598c2ecf20Sopenharmony_ci		WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
10608c2ecf20Sopenharmony_ci			     sdata->crypto_tx_tailroom_pending_dec);
10618c2ecf20Sopenharmony_ci	}
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP) {
10648c2ecf20Sopenharmony_ci		list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
10658c2ecf20Sopenharmony_ci			WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt ||
10668c2ecf20Sopenharmony_ci				     vlan->crypto_tx_tailroom_pending_dec);
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	mutex_unlock(&local->key_mtx);
10708c2ecf20Sopenharmony_ci}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_civoid ieee80211_free_sta_keys(struct ieee80211_local *local,
10738c2ecf20Sopenharmony_ci			     struct sta_info *sta)
10748c2ecf20Sopenharmony_ci{
10758c2ecf20Sopenharmony_ci	struct ieee80211_key *key;
10768c2ecf20Sopenharmony_ci	int i;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	mutex_lock(&local->key_mtx);
10798c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sta->gtk); i++) {
10808c2ecf20Sopenharmony_ci		key = key_mtx_dereference(local, sta->gtk[i]);
10818c2ecf20Sopenharmony_ci		if (!key)
10828c2ecf20Sopenharmony_ci			continue;
10838c2ecf20Sopenharmony_ci		ieee80211_key_replace(key->sdata, key->sta,
10848c2ecf20Sopenharmony_ci				key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
10858c2ecf20Sopenharmony_ci				key, NULL);
10868c2ecf20Sopenharmony_ci		__ieee80211_key_destroy(key, key->sdata->vif.type ==
10878c2ecf20Sopenharmony_ci					NL80211_IFTYPE_STATION);
10888c2ecf20Sopenharmony_ci	}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
10918c2ecf20Sopenharmony_ci		key = key_mtx_dereference(local, sta->ptk[i]);
10928c2ecf20Sopenharmony_ci		if (!key)
10938c2ecf20Sopenharmony_ci			continue;
10948c2ecf20Sopenharmony_ci		ieee80211_key_replace(key->sdata, key->sta,
10958c2ecf20Sopenharmony_ci				key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
10968c2ecf20Sopenharmony_ci				key, NULL);
10978c2ecf20Sopenharmony_ci		__ieee80211_key_destroy(key, key->sdata->vif.type ==
10988c2ecf20Sopenharmony_ci					NL80211_IFTYPE_STATION);
10998c2ecf20Sopenharmony_ci	}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	mutex_unlock(&local->key_mtx);
11028c2ecf20Sopenharmony_ci}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_civoid ieee80211_delayed_tailroom_dec(struct work_struct *wk)
11058c2ecf20Sopenharmony_ci{
11068c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	sdata = container_of(wk, struct ieee80211_sub_if_data,
11098c2ecf20Sopenharmony_ci			     dec_tailroom_needed_wk.work);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	/*
11128c2ecf20Sopenharmony_ci	 * The reason for the delayed tailroom needed decrementing is to
11138c2ecf20Sopenharmony_ci	 * make roaming faster: during roaming, all keys are first deleted
11148c2ecf20Sopenharmony_ci	 * and then new keys are installed. The first new key causes the
11158c2ecf20Sopenharmony_ci	 * crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes
11168c2ecf20Sopenharmony_ci	 * the cost of synchronize_net() (which can be slow). Avoid this
11178c2ecf20Sopenharmony_ci	 * by deferring the crypto_tx_tailroom_needed_cnt decrementing on
11188c2ecf20Sopenharmony_ci	 * key removal for a while, so if we roam the value is larger than
11198c2ecf20Sopenharmony_ci	 * zero and no 0->1 transition happens.
11208c2ecf20Sopenharmony_ci	 *
11218c2ecf20Sopenharmony_ci	 * The cost is that if the AP switching was from an AP with keys
11228c2ecf20Sopenharmony_ci	 * to one without, we still allocate tailroom while it would no
11238c2ecf20Sopenharmony_ci	 * longer be needed. However, in the typical (fast) roaming case
11248c2ecf20Sopenharmony_ci	 * within an ESS this usually won't happen.
11258c2ecf20Sopenharmony_ci	 */
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	mutex_lock(&sdata->local->key_mtx);
11288c2ecf20Sopenharmony_ci	decrease_tailroom_need_count(sdata,
11298c2ecf20Sopenharmony_ci				     sdata->crypto_tx_tailroom_pending_dec);
11308c2ecf20Sopenharmony_ci	sdata->crypto_tx_tailroom_pending_dec = 0;
11318c2ecf20Sopenharmony_ci	mutex_unlock(&sdata->local->key_mtx);
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_civoid ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
11358c2ecf20Sopenharmony_ci				const u8 *replay_ctr, gfp_t gfp)
11368c2ecf20Sopenharmony_ci{
11378c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	trace_api_gtk_rekey_notify(sdata, bssid, replay_ctr);
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	cfg80211_gtk_rekey_notify(sdata->dev, bssid, replay_ctr, gfp);
11428c2ecf20Sopenharmony_ci}
11438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_civoid ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
11468c2ecf20Sopenharmony_ci			      int tid, struct ieee80211_key_seq *seq)
11478c2ecf20Sopenharmony_ci{
11488c2ecf20Sopenharmony_ci	struct ieee80211_key *key;
11498c2ecf20Sopenharmony_ci	const u8 *pn;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	key = container_of(keyconf, struct ieee80211_key, conf);
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	switch (key->conf.cipher) {
11548c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
11558c2ecf20Sopenharmony_ci		if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS))
11568c2ecf20Sopenharmony_ci			return;
11578c2ecf20Sopenharmony_ci		seq->tkip.iv32 = key->u.tkip.rx[tid].iv32;
11588c2ecf20Sopenharmony_ci		seq->tkip.iv16 = key->u.tkip.rx[tid].iv16;
11598c2ecf20Sopenharmony_ci		break;
11608c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
11618c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
11628c2ecf20Sopenharmony_ci		if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
11638c2ecf20Sopenharmony_ci			return;
11648c2ecf20Sopenharmony_ci		if (tid < 0)
11658c2ecf20Sopenharmony_ci			pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS];
11668c2ecf20Sopenharmony_ci		else
11678c2ecf20Sopenharmony_ci			pn = key->u.ccmp.rx_pn[tid];
11688c2ecf20Sopenharmony_ci		memcpy(seq->ccmp.pn, pn, IEEE80211_CCMP_PN_LEN);
11698c2ecf20Sopenharmony_ci		break;
11708c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
11718c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
11728c2ecf20Sopenharmony_ci		if (WARN_ON(tid != 0))
11738c2ecf20Sopenharmony_ci			return;
11748c2ecf20Sopenharmony_ci		pn = key->u.aes_cmac.rx_pn;
11758c2ecf20Sopenharmony_ci		memcpy(seq->aes_cmac.pn, pn, IEEE80211_CMAC_PN_LEN);
11768c2ecf20Sopenharmony_ci		break;
11778c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
11788c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
11798c2ecf20Sopenharmony_ci		if (WARN_ON(tid != 0))
11808c2ecf20Sopenharmony_ci			return;
11818c2ecf20Sopenharmony_ci		pn = key->u.aes_gmac.rx_pn;
11828c2ecf20Sopenharmony_ci		memcpy(seq->aes_gmac.pn, pn, IEEE80211_GMAC_PN_LEN);
11838c2ecf20Sopenharmony_ci		break;
11848c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
11858c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
11868c2ecf20Sopenharmony_ci		if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
11878c2ecf20Sopenharmony_ci			return;
11888c2ecf20Sopenharmony_ci		if (tid < 0)
11898c2ecf20Sopenharmony_ci			pn = key->u.gcmp.rx_pn[IEEE80211_NUM_TIDS];
11908c2ecf20Sopenharmony_ci		else
11918c2ecf20Sopenharmony_ci			pn = key->u.gcmp.rx_pn[tid];
11928c2ecf20Sopenharmony_ci		memcpy(seq->gcmp.pn, pn, IEEE80211_GCMP_PN_LEN);
11938c2ecf20Sopenharmony_ci		break;
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci}
11968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ieee80211_get_key_rx_seq);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_civoid ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
11998c2ecf20Sopenharmony_ci			      int tid, struct ieee80211_key_seq *seq)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	struct ieee80211_key *key;
12028c2ecf20Sopenharmony_ci	u8 *pn;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	key = container_of(keyconf, struct ieee80211_key, conf);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	switch (key->conf.cipher) {
12078c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
12088c2ecf20Sopenharmony_ci		if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS))
12098c2ecf20Sopenharmony_ci			return;
12108c2ecf20Sopenharmony_ci		key->u.tkip.rx[tid].iv32 = seq->tkip.iv32;
12118c2ecf20Sopenharmony_ci		key->u.tkip.rx[tid].iv16 = seq->tkip.iv16;
12128c2ecf20Sopenharmony_ci		break;
12138c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
12148c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
12158c2ecf20Sopenharmony_ci		if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
12168c2ecf20Sopenharmony_ci			return;
12178c2ecf20Sopenharmony_ci		if (tid < 0)
12188c2ecf20Sopenharmony_ci			pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS];
12198c2ecf20Sopenharmony_ci		else
12208c2ecf20Sopenharmony_ci			pn = key->u.ccmp.rx_pn[tid];
12218c2ecf20Sopenharmony_ci		memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN);
12228c2ecf20Sopenharmony_ci		break;
12238c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
12248c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
12258c2ecf20Sopenharmony_ci		if (WARN_ON(tid != 0))
12268c2ecf20Sopenharmony_ci			return;
12278c2ecf20Sopenharmony_ci		pn = key->u.aes_cmac.rx_pn;
12288c2ecf20Sopenharmony_ci		memcpy(pn, seq->aes_cmac.pn, IEEE80211_CMAC_PN_LEN);
12298c2ecf20Sopenharmony_ci		break;
12308c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
12318c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
12328c2ecf20Sopenharmony_ci		if (WARN_ON(tid != 0))
12338c2ecf20Sopenharmony_ci			return;
12348c2ecf20Sopenharmony_ci		pn = key->u.aes_gmac.rx_pn;
12358c2ecf20Sopenharmony_ci		memcpy(pn, seq->aes_gmac.pn, IEEE80211_GMAC_PN_LEN);
12368c2ecf20Sopenharmony_ci		break;
12378c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
12388c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
12398c2ecf20Sopenharmony_ci		if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
12408c2ecf20Sopenharmony_ci			return;
12418c2ecf20Sopenharmony_ci		if (tid < 0)
12428c2ecf20Sopenharmony_ci			pn = key->u.gcmp.rx_pn[IEEE80211_NUM_TIDS];
12438c2ecf20Sopenharmony_ci		else
12448c2ecf20Sopenharmony_ci			pn = key->u.gcmp.rx_pn[tid];
12458c2ecf20Sopenharmony_ci		memcpy(pn, seq->gcmp.pn, IEEE80211_GCMP_PN_LEN);
12468c2ecf20Sopenharmony_ci		break;
12478c2ecf20Sopenharmony_ci	default:
12488c2ecf20Sopenharmony_ci		WARN_ON(1);
12498c2ecf20Sopenharmony_ci		break;
12508c2ecf20Sopenharmony_ci	}
12518c2ecf20Sopenharmony_ci}
12528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_set_key_rx_seq);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_civoid ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
12558c2ecf20Sopenharmony_ci{
12568c2ecf20Sopenharmony_ci	struct ieee80211_key *key;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	key = container_of(keyconf, struct ieee80211_key, conf);
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	assert_key_lock(key->local);
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	/*
12638c2ecf20Sopenharmony_ci	 * if key was uploaded, we assume the driver will/has remove(d)
12648c2ecf20Sopenharmony_ci	 * it, so adjust bookkeeping accordingly
12658c2ecf20Sopenharmony_ci	 */
12668c2ecf20Sopenharmony_ci	if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
12678c2ecf20Sopenharmony_ci		key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci		if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
12708c2ecf20Sopenharmony_ci					 IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
12718c2ecf20Sopenharmony_ci					 IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
12728c2ecf20Sopenharmony_ci			increment_tailroom_need_count(key->sdata);
12738c2ecf20Sopenharmony_ci	}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	ieee80211_key_free(key, false);
12768c2ecf20Sopenharmony_ci}
12778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_remove_key);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_cistruct ieee80211_key_conf *
12808c2ecf20Sopenharmony_ciieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
12818c2ecf20Sopenharmony_ci			struct ieee80211_key_conf *keyconf)
12828c2ecf20Sopenharmony_ci{
12838c2ecf20Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
12848c2ecf20Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
12858c2ecf20Sopenharmony_ci	struct ieee80211_key *key;
12868c2ecf20Sopenharmony_ci	int err;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	if (WARN_ON(!local->wowlan))
12898c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
12928c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx,
12958c2ecf20Sopenharmony_ci				  keyconf->keylen, keyconf->key,
12968c2ecf20Sopenharmony_ci				  0, NULL, NULL);
12978c2ecf20Sopenharmony_ci	if (IS_ERR(key))
12988c2ecf20Sopenharmony_ci		return ERR_CAST(key);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED)
13018c2ecf20Sopenharmony_ci		key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	err = ieee80211_key_link(key, sdata, NULL);
13048c2ecf20Sopenharmony_ci	if (err)
13058c2ecf20Sopenharmony_ci		return ERR_PTR(err);
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	return &key->conf;
13088c2ecf20Sopenharmony_ci}
13098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_add);
1310