162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci/* Copyright(c) 2019-2020  Realtek Corporation
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include "cam.h"
662306a36Sopenharmony_ci#include "debug.h"
762306a36Sopenharmony_ci#include "fw.h"
862306a36Sopenharmony_ci#include "mac.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistatic struct sk_buff *
1162306a36Sopenharmony_cirtw89_cam_get_sec_key_cmd(struct rtw89_dev *rtwdev,
1262306a36Sopenharmony_ci			  struct rtw89_sec_cam_entry *sec_cam,
1362306a36Sopenharmony_ci			  bool ext_key)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	struct sk_buff *skb;
1662306a36Sopenharmony_ci	u32 cmd_len = H2C_SEC_CAM_LEN;
1762306a36Sopenharmony_ci	u32 key32[4];
1862306a36Sopenharmony_ci	u8 *cmd;
1962306a36Sopenharmony_ci	int i, j;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, cmd_len);
2262306a36Sopenharmony_ci	if (!skb)
2362306a36Sopenharmony_ci		return NULL;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	skb_put_zero(skb, cmd_len);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
2862306a36Sopenharmony_ci		j = i * 4;
2962306a36Sopenharmony_ci		j += ext_key ? 16 : 0;
3062306a36Sopenharmony_ci		key32[i] = FIELD_PREP(GENMASK(7, 0), sec_cam->key[j + 0]) |
3162306a36Sopenharmony_ci			   FIELD_PREP(GENMASK(15, 8), sec_cam->key[j + 1]) |
3262306a36Sopenharmony_ci			   FIELD_PREP(GENMASK(23, 16), sec_cam->key[j + 2]) |
3362306a36Sopenharmony_ci			   FIELD_PREP(GENMASK(31, 24), sec_cam->key[j + 3]);
3462306a36Sopenharmony_ci	}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	cmd = skb->data;
3762306a36Sopenharmony_ci	RTW89_SET_FWCMD_SEC_IDX(cmd, sec_cam->sec_cam_idx + (ext_key ? 1 : 0));
3862306a36Sopenharmony_ci	RTW89_SET_FWCMD_SEC_OFFSET(cmd, sec_cam->offset);
3962306a36Sopenharmony_ci	RTW89_SET_FWCMD_SEC_LEN(cmd, sec_cam->len);
4062306a36Sopenharmony_ci	RTW89_SET_FWCMD_SEC_TYPE(cmd, sec_cam->type);
4162306a36Sopenharmony_ci	RTW89_SET_FWCMD_SEC_EXT_KEY(cmd, ext_key);
4262306a36Sopenharmony_ci	RTW89_SET_FWCMD_SEC_SPP_MODE(cmd, sec_cam->spp_mode);
4362306a36Sopenharmony_ci	RTW89_SET_FWCMD_SEC_KEY0(cmd, key32[0]);
4462306a36Sopenharmony_ci	RTW89_SET_FWCMD_SEC_KEY1(cmd, key32[1]);
4562306a36Sopenharmony_ci	RTW89_SET_FWCMD_SEC_KEY2(cmd, key32[2]);
4662306a36Sopenharmony_ci	RTW89_SET_FWCMD_SEC_KEY3(cmd, key32[3]);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	return skb;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int rtw89_cam_send_sec_key_cmd(struct rtw89_dev *rtwdev,
5262306a36Sopenharmony_ci				      struct rtw89_sec_cam_entry *sec_cam)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct sk_buff *skb, *ext_skb;
5562306a36Sopenharmony_ci	int ret;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	skb = rtw89_cam_get_sec_key_cmd(rtwdev, sec_cam, false);
5862306a36Sopenharmony_ci	if (!skb) {
5962306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to get sec key command\n");
6062306a36Sopenharmony_ci		return -ENOMEM;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	rtw89_h2c_pkt_set_hdr(rtwdev, skb,
6462306a36Sopenharmony_ci			      FWCMD_TYPE_H2C,
6562306a36Sopenharmony_ci			      H2C_CAT_MAC,
6662306a36Sopenharmony_ci			      H2C_CL_MAC_SEC_CAM,
6762306a36Sopenharmony_ci			      H2C_FUNC_MAC_SEC_UPD, 1, 0,
6862306a36Sopenharmony_ci			      H2C_SEC_CAM_LEN);
6962306a36Sopenharmony_ci	ret = rtw89_h2c_tx(rtwdev, skb, false);
7062306a36Sopenharmony_ci	if (ret) {
7162306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to send sec key h2c: %d\n", ret);
7262306a36Sopenharmony_ci		dev_kfree_skb(skb);
7362306a36Sopenharmony_ci		return ret;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (!sec_cam->ext_key)
7762306a36Sopenharmony_ci		return 0;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	ext_skb = rtw89_cam_get_sec_key_cmd(rtwdev, sec_cam, true);
8062306a36Sopenharmony_ci	if (!ext_skb) {
8162306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to get ext sec key command\n");
8262306a36Sopenharmony_ci		return -ENOMEM;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	rtw89_h2c_pkt_set_hdr(rtwdev, ext_skb,
8662306a36Sopenharmony_ci			      FWCMD_TYPE_H2C,
8762306a36Sopenharmony_ci			      H2C_CAT_MAC,
8862306a36Sopenharmony_ci			      H2C_CL_MAC_SEC_CAM,
8962306a36Sopenharmony_ci			      H2C_FUNC_MAC_SEC_UPD,
9062306a36Sopenharmony_ci			      1, 0, H2C_SEC_CAM_LEN);
9162306a36Sopenharmony_ci	ret = rtw89_h2c_tx(rtwdev, ext_skb, false);
9262306a36Sopenharmony_ci	if (ret) {
9362306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to send ext sec key h2c: %d\n", ret);
9462306a36Sopenharmony_ci		dev_kfree_skb(ext_skb);
9562306a36Sopenharmony_ci		return ret;
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return 0;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int rtw89_cam_get_avail_sec_cam(struct rtw89_dev *rtwdev,
10262306a36Sopenharmony_ci				       u8 *sec_cam_idx, bool ext_key)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	const struct rtw89_chip_info *chip = rtwdev->chip;
10562306a36Sopenharmony_ci	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
10662306a36Sopenharmony_ci	u8 sec_cam_num = chip->scam_num;
10762306a36Sopenharmony_ci	u8 idx = 0;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (!ext_key) {
11062306a36Sopenharmony_ci		idx = find_first_zero_bit(cam_info->sec_cam_map, sec_cam_num);
11162306a36Sopenharmony_ci		if (idx >= sec_cam_num)
11262306a36Sopenharmony_ci			return -EBUSY;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		set_bit(idx, cam_info->sec_cam_map);
11562306a36Sopenharmony_ci		*sec_cam_idx = idx;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		return 0;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ciagain:
12162306a36Sopenharmony_ci	idx = find_next_zero_bit(cam_info->sec_cam_map, sec_cam_num, idx);
12262306a36Sopenharmony_ci	if (idx >= sec_cam_num - 1)
12362306a36Sopenharmony_ci		return -EBUSY;
12462306a36Sopenharmony_ci	/* ext keys need two cam entries for 256-bit key */
12562306a36Sopenharmony_ci	if (test_bit(idx + 1, cam_info->sec_cam_map)) {
12662306a36Sopenharmony_ci		idx++;
12762306a36Sopenharmony_ci		goto again;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	set_bit(idx, cam_info->sec_cam_map);
13162306a36Sopenharmony_ci	set_bit(idx + 1, cam_info->sec_cam_map);
13262306a36Sopenharmony_ci	*sec_cam_idx = idx;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return 0;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic int rtw89_cam_get_addr_cam_key_idx(struct rtw89_addr_cam_entry *addr_cam,
13862306a36Sopenharmony_ci					  struct rtw89_sec_cam_entry *sec_cam,
13962306a36Sopenharmony_ci					  struct ieee80211_key_conf *key,
14062306a36Sopenharmony_ci					  u8 *key_idx)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	u8 idx;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* RTW89_ADDR_CAM_SEC_NONE	: not enabled
14562306a36Sopenharmony_ci	 * RTW89_ADDR_CAM_SEC_ALL_UNI	: 0 - 6 unicast
14662306a36Sopenharmony_ci	 * RTW89_ADDR_CAM_SEC_NORMAL	: 0 - 1 unicast, 2 - 4 group, 5 - 6 BIP
14762306a36Sopenharmony_ci	 * RTW89_ADDR_CAM_SEC_4GROUP	: 0 - 1 unicast, 2 - 5 group, 6 BIP
14862306a36Sopenharmony_ci	 */
14962306a36Sopenharmony_ci	switch (addr_cam->sec_ent_mode) {
15062306a36Sopenharmony_ci	case RTW89_ADDR_CAM_SEC_NONE:
15162306a36Sopenharmony_ci		return -EINVAL;
15262306a36Sopenharmony_ci	case RTW89_ADDR_CAM_SEC_ALL_UNI:
15362306a36Sopenharmony_ci		if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
15462306a36Sopenharmony_ci			return -EINVAL;
15562306a36Sopenharmony_ci		idx = find_first_zero_bit(addr_cam->sec_cam_map,
15662306a36Sopenharmony_ci					  RTW89_SEC_CAM_IN_ADDR_CAM);
15762306a36Sopenharmony_ci		if (idx >= RTW89_SEC_CAM_IN_ADDR_CAM)
15862306a36Sopenharmony_ci			return -EBUSY;
15962306a36Sopenharmony_ci		*key_idx = idx;
16062306a36Sopenharmony_ci		break;
16162306a36Sopenharmony_ci	case RTW89_ADDR_CAM_SEC_NORMAL:
16262306a36Sopenharmony_ci		if (sec_cam->type == RTW89_SEC_KEY_TYPE_BIP_CCMP128) {
16362306a36Sopenharmony_ci			idx = find_next_zero_bit(addr_cam->sec_cam_map,
16462306a36Sopenharmony_ci						 RTW89_SEC_CAM_IN_ADDR_CAM, 5);
16562306a36Sopenharmony_ci			if (idx > 6)
16662306a36Sopenharmony_ci				return -EBUSY;
16762306a36Sopenharmony_ci			*key_idx = idx;
16862306a36Sopenharmony_ci			break;
16962306a36Sopenharmony_ci		}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci		if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
17262306a36Sopenharmony_ci			idx = find_next_zero_bit(addr_cam->sec_cam_map,
17362306a36Sopenharmony_ci						 RTW89_SEC_CAM_IN_ADDR_CAM, 0);
17462306a36Sopenharmony_ci			if (idx > 1)
17562306a36Sopenharmony_ci				return -EBUSY;
17662306a36Sopenharmony_ci			*key_idx = idx;
17762306a36Sopenharmony_ci			break;
17862306a36Sopenharmony_ci		}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		/* Group keys */
18162306a36Sopenharmony_ci		idx = find_next_zero_bit(addr_cam->sec_cam_map,
18262306a36Sopenharmony_ci					 RTW89_SEC_CAM_IN_ADDR_CAM, 2);
18362306a36Sopenharmony_ci		if (idx > 4)
18462306a36Sopenharmony_ci			return -EBUSY;
18562306a36Sopenharmony_ci		*key_idx = idx;
18662306a36Sopenharmony_ci		break;
18762306a36Sopenharmony_ci	case RTW89_ADDR_CAM_SEC_4GROUP:
18862306a36Sopenharmony_ci		if (sec_cam->type == RTW89_SEC_KEY_TYPE_BIP_CCMP128) {
18962306a36Sopenharmony_ci			if (test_bit(6, addr_cam->sec_cam_map))
19062306a36Sopenharmony_ci				return -EINVAL;
19162306a36Sopenharmony_ci			*key_idx = 6;
19262306a36Sopenharmony_ci			break;
19362306a36Sopenharmony_ci		}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
19662306a36Sopenharmony_ci			idx = find_next_zero_bit(addr_cam->sec_cam_map,
19762306a36Sopenharmony_ci						 RTW89_SEC_CAM_IN_ADDR_CAM, 0);
19862306a36Sopenharmony_ci			if (idx > 1)
19962306a36Sopenharmony_ci				return -EBUSY;
20062306a36Sopenharmony_ci			*key_idx = idx;
20162306a36Sopenharmony_ci			break;
20262306a36Sopenharmony_ci		}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		/* Group keys */
20562306a36Sopenharmony_ci		idx = find_next_zero_bit(addr_cam->sec_cam_map,
20662306a36Sopenharmony_ci					 RTW89_SEC_CAM_IN_ADDR_CAM, 2);
20762306a36Sopenharmony_ci		if (idx > 5)
20862306a36Sopenharmony_ci			return -EBUSY;
20962306a36Sopenharmony_ci		*key_idx = idx;
21062306a36Sopenharmony_ci		break;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return 0;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
21762306a36Sopenharmony_ci				    struct ieee80211_vif *vif,
21862306a36Sopenharmony_ci				    struct ieee80211_sta *sta,
21962306a36Sopenharmony_ci				    struct ieee80211_key_conf *key,
22062306a36Sopenharmony_ci				    struct rtw89_sec_cam_entry *sec_cam)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
22362306a36Sopenharmony_ci	struct rtw89_vif *rtwvif;
22462306a36Sopenharmony_ci	struct rtw89_addr_cam_entry *addr_cam;
22562306a36Sopenharmony_ci	u8 key_idx = 0;
22662306a36Sopenharmony_ci	int ret;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (!vif) {
22962306a36Sopenharmony_ci		rtw89_err(rtwdev, "No iface for adding sec cam\n");
23062306a36Sopenharmony_ci		return -EINVAL;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	rtwvif = (struct rtw89_vif *)vif->drv_priv;
23462306a36Sopenharmony_ci	addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
23562306a36Sopenharmony_ci	ret = rtw89_cam_get_addr_cam_key_idx(addr_cam, sec_cam, key, &key_idx);
23662306a36Sopenharmony_ci	if (ret) {
23762306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to get addr cam key idx %d, %d\n",
23862306a36Sopenharmony_ci			  addr_cam->sec_ent_mode, sec_cam->type);
23962306a36Sopenharmony_ci		return ret;
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	key->hw_key_idx = key_idx;
24362306a36Sopenharmony_ci	addr_cam->sec_ent_keyid[key_idx] = key->keyidx;
24462306a36Sopenharmony_ci	addr_cam->sec_ent[key_idx] = sec_cam->sec_cam_idx;
24562306a36Sopenharmony_ci	addr_cam->sec_entries[key_idx] = sec_cam;
24662306a36Sopenharmony_ci	set_bit(key_idx, addr_cam->sec_cam_map);
24762306a36Sopenharmony_ci	ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
24862306a36Sopenharmony_ci	if (ret) {
24962306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n",
25062306a36Sopenharmony_ci			  ret);
25162306a36Sopenharmony_ci		return ret;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci	ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
25462306a36Sopenharmony_ci	if (ret) {
25562306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to update addr cam sec entry: %d\n",
25662306a36Sopenharmony_ci			  ret);
25762306a36Sopenharmony_ci		clear_bit(key_idx, addr_cam->sec_cam_map);
25862306a36Sopenharmony_ci		addr_cam->sec_entries[key_idx] = NULL;
25962306a36Sopenharmony_ci		return ret;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return 0;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic int rtw89_cam_sec_key_install(struct rtw89_dev *rtwdev,
26662306a36Sopenharmony_ci				     struct ieee80211_vif *vif,
26762306a36Sopenharmony_ci				     struct ieee80211_sta *sta,
26862306a36Sopenharmony_ci				     struct ieee80211_key_conf *key,
26962306a36Sopenharmony_ci				     u8 hw_key_type, bool ext_key)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct rtw89_sec_cam_entry *sec_cam = NULL;
27262306a36Sopenharmony_ci	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
27362306a36Sopenharmony_ci	u8 sec_cam_idx;
27462306a36Sopenharmony_ci	int ret;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	/* maximum key length 256-bit */
27762306a36Sopenharmony_ci	if (key->keylen > 32) {
27862306a36Sopenharmony_ci		rtw89_err(rtwdev, "invalid sec key length %d\n", key->keylen);
27962306a36Sopenharmony_ci		return -EINVAL;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	ret = rtw89_cam_get_avail_sec_cam(rtwdev, &sec_cam_idx, ext_key);
28362306a36Sopenharmony_ci	if (ret) {
28462306a36Sopenharmony_ci		rtw89_warn(rtwdev, "no available sec cam: %d ext: %d\n",
28562306a36Sopenharmony_ci			   ret, ext_key);
28662306a36Sopenharmony_ci		return ret;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	sec_cam = kzalloc(sizeof(*sec_cam), GFP_KERNEL);
29062306a36Sopenharmony_ci	if (!sec_cam) {
29162306a36Sopenharmony_ci		ret = -ENOMEM;
29262306a36Sopenharmony_ci		goto err_release_cam;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	sec_cam->sec_cam_idx = sec_cam_idx;
29662306a36Sopenharmony_ci	sec_cam->type = hw_key_type;
29762306a36Sopenharmony_ci	sec_cam->len = RTW89_SEC_CAM_LEN;
29862306a36Sopenharmony_ci	sec_cam->ext_key = ext_key;
29962306a36Sopenharmony_ci	memcpy(sec_cam->key, key->key, key->keylen);
30062306a36Sopenharmony_ci	ret = rtw89_cam_send_sec_key_cmd(rtwdev, sec_cam);
30162306a36Sopenharmony_ci	if (ret) {
30262306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to send sec key cmd: %d\n", ret);
30362306a36Sopenharmony_ci		goto err_release_cam;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* associate with addr cam */
30762306a36Sopenharmony_ci	ret = rtw89_cam_attach_sec_cam(rtwdev, vif, sta, key, sec_cam);
30862306a36Sopenharmony_ci	if (ret) {
30962306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to attach sec cam: %d\n", ret);
31062306a36Sopenharmony_ci		goto err_release_cam;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	return 0;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cierr_release_cam:
31662306a36Sopenharmony_ci	kfree(sec_cam);
31762306a36Sopenharmony_ci	clear_bit(sec_cam_idx, cam_info->sec_cam_map);
31862306a36Sopenharmony_ci	if (ext_key)
31962306a36Sopenharmony_ci		clear_bit(sec_cam_idx + 1, cam_info->sec_cam_map);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return ret;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ciint rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev,
32562306a36Sopenharmony_ci			  struct ieee80211_vif *vif,
32662306a36Sopenharmony_ci			  struct ieee80211_sta *sta,
32762306a36Sopenharmony_ci			  struct ieee80211_key_conf *key)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	const struct rtw89_chip_info *chip = rtwdev->chip;
33062306a36Sopenharmony_ci	u8 hw_key_type;
33162306a36Sopenharmony_ci	bool ext_key = false;
33262306a36Sopenharmony_ci	int ret;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	switch (key->cipher) {
33562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
33662306a36Sopenharmony_ci		hw_key_type = RTW89_SEC_KEY_TYPE_WEP40;
33762306a36Sopenharmony_ci		break;
33862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
33962306a36Sopenharmony_ci		hw_key_type = RTW89_SEC_KEY_TYPE_WEP104;
34062306a36Sopenharmony_ci		break;
34162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
34262306a36Sopenharmony_ci		hw_key_type = RTW89_SEC_KEY_TYPE_CCMP128;
34362306a36Sopenharmony_ci		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
34462306a36Sopenharmony_ci		break;
34562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
34662306a36Sopenharmony_ci		hw_key_type = RTW89_SEC_KEY_TYPE_CCMP256;
34762306a36Sopenharmony_ci		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
34862306a36Sopenharmony_ci		ext_key = true;
34962306a36Sopenharmony_ci		break;
35062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
35162306a36Sopenharmony_ci		hw_key_type = RTW89_SEC_KEY_TYPE_GCMP128;
35262306a36Sopenharmony_ci		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
35362306a36Sopenharmony_ci		break;
35462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
35562306a36Sopenharmony_ci		hw_key_type = RTW89_SEC_KEY_TYPE_GCMP256;
35662306a36Sopenharmony_ci		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
35762306a36Sopenharmony_ci		ext_key = true;
35862306a36Sopenharmony_ci		break;
35962306a36Sopenharmony_ci	default:
36062306a36Sopenharmony_ci		return -EOPNOTSUPP;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (!chip->hw_sec_hdr)
36462306a36Sopenharmony_ci		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	ret = rtw89_cam_sec_key_install(rtwdev, vif, sta, key, hw_key_type,
36762306a36Sopenharmony_ci					ext_key);
36862306a36Sopenharmony_ci	if (ret) {
36962306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to install key type %d ext %d: %d\n",
37062306a36Sopenharmony_ci			  hw_key_type, ext_key, ret);
37162306a36Sopenharmony_ci		return ret;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	return 0;
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ciint rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev,
37862306a36Sopenharmony_ci			  struct ieee80211_vif *vif,
37962306a36Sopenharmony_ci			  struct ieee80211_sta *sta,
38062306a36Sopenharmony_ci			  struct ieee80211_key_conf *key,
38162306a36Sopenharmony_ci			  bool inform_fw)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
38462306a36Sopenharmony_ci	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
38562306a36Sopenharmony_ci	struct rtw89_vif *rtwvif;
38662306a36Sopenharmony_ci	struct rtw89_addr_cam_entry *addr_cam;
38762306a36Sopenharmony_ci	struct rtw89_sec_cam_entry *sec_cam;
38862306a36Sopenharmony_ci	u8 key_idx = key->hw_key_idx;
38962306a36Sopenharmony_ci	u8 sec_cam_idx;
39062306a36Sopenharmony_ci	int ret = 0;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (!vif) {
39362306a36Sopenharmony_ci		rtw89_err(rtwdev, "No iface for deleting sec cam\n");
39462306a36Sopenharmony_ci		return -EINVAL;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	rtwvif = (struct rtw89_vif *)vif->drv_priv;
39862306a36Sopenharmony_ci	addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
39962306a36Sopenharmony_ci	sec_cam = addr_cam->sec_entries[key_idx];
40062306a36Sopenharmony_ci	if (!sec_cam)
40162306a36Sopenharmony_ci		return -EINVAL;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/* detach sec cam from addr cam */
40462306a36Sopenharmony_ci	clear_bit(key_idx, addr_cam->sec_cam_map);
40562306a36Sopenharmony_ci	addr_cam->sec_entries[key_idx] = NULL;
40662306a36Sopenharmony_ci	if (inform_fw) {
40762306a36Sopenharmony_ci		ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
40862306a36Sopenharmony_ci		if (ret)
40962306a36Sopenharmony_ci			rtw89_err(rtwdev, "failed to update dctl cam del key: %d\n", ret);
41062306a36Sopenharmony_ci		ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
41162306a36Sopenharmony_ci		if (ret)
41262306a36Sopenharmony_ci			rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret);
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* clear valid bit in addr cam will disable sec cam,
41662306a36Sopenharmony_ci	 * so we don't need to send H2C command again
41762306a36Sopenharmony_ci	 */
41862306a36Sopenharmony_ci	sec_cam_idx = sec_cam->sec_cam_idx;
41962306a36Sopenharmony_ci	clear_bit(sec_cam_idx, cam_info->sec_cam_map);
42062306a36Sopenharmony_ci	if (sec_cam->ext_key)
42162306a36Sopenharmony_ci		clear_bit(sec_cam_idx + 1, cam_info->sec_cam_map);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	kfree(sec_cam);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	return ret;
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic void rtw89_cam_reset_key_iter(struct ieee80211_hw *hw,
42962306a36Sopenharmony_ci				     struct ieee80211_vif *vif,
43062306a36Sopenharmony_ci				     struct ieee80211_sta *sta,
43162306a36Sopenharmony_ci				     struct ieee80211_key_conf *key,
43262306a36Sopenharmony_ci				     void *data)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct rtw89_dev *rtwdev = (struct rtw89_dev *)data;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	rtw89_cam_sec_key_del(rtwdev, vif, sta, key, false);
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_civoid rtw89_cam_deinit_addr_cam(struct rtw89_dev *rtwdev,
44062306a36Sopenharmony_ci			       struct rtw89_addr_cam_entry *addr_cam)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	addr_cam->valid = false;
44562306a36Sopenharmony_ci	clear_bit(addr_cam->addr_cam_idx, cam_info->addr_cam_map);
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_civoid rtw89_cam_deinit_bssid_cam(struct rtw89_dev *rtwdev,
44962306a36Sopenharmony_ci				struct rtw89_bssid_cam_entry *bssid_cam)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	bssid_cam->valid = false;
45462306a36Sopenharmony_ci	clear_bit(bssid_cam->bssid_cam_idx, cam_info->bssid_cam_map);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_civoid rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
46062306a36Sopenharmony_ci	struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	rtw89_cam_deinit_addr_cam(rtwdev, addr_cam);
46362306a36Sopenharmony_ci	rtw89_cam_deinit_bssid_cam(rtwdev, bssid_cam);
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_civoid rtw89_cam_reset_keys(struct rtw89_dev *rtwdev)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	rcu_read_lock();
46962306a36Sopenharmony_ci	ieee80211_iter_keys_rcu(rtwdev->hw, NULL, rtw89_cam_reset_key_iter, rtwdev);
47062306a36Sopenharmony_ci	rcu_read_unlock();
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic int rtw89_cam_get_avail_addr_cam(struct rtw89_dev *rtwdev,
47462306a36Sopenharmony_ci					u8 *addr_cam_idx)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	const struct rtw89_chip_info *chip = rtwdev->chip;
47762306a36Sopenharmony_ci	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
47862306a36Sopenharmony_ci	u8 addr_cam_num = chip->acam_num;
47962306a36Sopenharmony_ci	u8 idx;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	idx = find_first_zero_bit(cam_info->addr_cam_map, addr_cam_num);
48262306a36Sopenharmony_ci	if (idx >= addr_cam_num)
48362306a36Sopenharmony_ci		return -EBUSY;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	set_bit(idx, cam_info->addr_cam_map);
48662306a36Sopenharmony_ci	*addr_cam_idx = idx;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	return 0;
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ciint rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev,
49262306a36Sopenharmony_ci			    struct rtw89_addr_cam_entry *addr_cam,
49362306a36Sopenharmony_ci			    const struct rtw89_bssid_cam_entry *bssid_cam)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	u8 addr_cam_idx;
49662306a36Sopenharmony_ci	int i;
49762306a36Sopenharmony_ci	int ret;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (unlikely(addr_cam->valid)) {
50062306a36Sopenharmony_ci		rtw89_debug(rtwdev, RTW89_DBG_FW,
50162306a36Sopenharmony_ci			    "addr cam is already valid; skip init\n");
50262306a36Sopenharmony_ci		return 0;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	ret = rtw89_cam_get_avail_addr_cam(rtwdev, &addr_cam_idx);
50662306a36Sopenharmony_ci	if (ret) {
50762306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to get available addr cam\n");
50862306a36Sopenharmony_ci		return ret;
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	addr_cam->addr_cam_idx = addr_cam_idx;
51262306a36Sopenharmony_ci	addr_cam->len = ADDR_CAM_ENT_SIZE;
51362306a36Sopenharmony_ci	addr_cam->offset = 0;
51462306a36Sopenharmony_ci	addr_cam->valid = true;
51562306a36Sopenharmony_ci	addr_cam->addr_mask = 0;
51662306a36Sopenharmony_ci	addr_cam->mask_sel = RTW89_NO_MSK;
51762306a36Sopenharmony_ci	addr_cam->sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL;
51862306a36Sopenharmony_ci	bitmap_zero(addr_cam->sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	for (i = 0; i < RTW89_SEC_CAM_IN_ADDR_CAM; i++) {
52162306a36Sopenharmony_ci		addr_cam->sec_ent_keyid[i] = 0;
52262306a36Sopenharmony_ci		addr_cam->sec_ent[i] = 0;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* associate addr cam with bssid cam */
52662306a36Sopenharmony_ci	addr_cam->bssid_cam_idx = bssid_cam->bssid_cam_idx;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return 0;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic int rtw89_cam_get_avail_bssid_cam(struct rtw89_dev *rtwdev,
53262306a36Sopenharmony_ci					 u8 *bssid_cam_idx)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	const struct rtw89_chip_info *chip = rtwdev->chip;
53562306a36Sopenharmony_ci	struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
53662306a36Sopenharmony_ci	u8 bssid_cam_num = chip->bcam_num;
53762306a36Sopenharmony_ci	u8 idx;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	idx = find_first_zero_bit(cam_info->bssid_cam_map, bssid_cam_num);
54062306a36Sopenharmony_ci	if (idx >= bssid_cam_num)
54162306a36Sopenharmony_ci		return -EBUSY;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	set_bit(idx, cam_info->bssid_cam_map);
54462306a36Sopenharmony_ci	*bssid_cam_idx = idx;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return 0;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ciint rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev,
55062306a36Sopenharmony_ci			     struct rtw89_vif *rtwvif,
55162306a36Sopenharmony_ci			     struct rtw89_bssid_cam_entry *bssid_cam,
55262306a36Sopenharmony_ci			     const u8 *bssid)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	u8 bssid_cam_idx;
55562306a36Sopenharmony_ci	int ret;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (unlikely(bssid_cam->valid)) {
55862306a36Sopenharmony_ci		rtw89_debug(rtwdev, RTW89_DBG_FW,
55962306a36Sopenharmony_ci			    "bssid cam is already valid; skip init\n");
56062306a36Sopenharmony_ci		return 0;
56162306a36Sopenharmony_ci	}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	ret = rtw89_cam_get_avail_bssid_cam(rtwdev, &bssid_cam_idx);
56462306a36Sopenharmony_ci	if (ret) {
56562306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to get available bssid cam\n");
56662306a36Sopenharmony_ci		return ret;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	bssid_cam->bssid_cam_idx = bssid_cam_idx;
57062306a36Sopenharmony_ci	bssid_cam->phy_idx = rtwvif->phy_idx;
57162306a36Sopenharmony_ci	bssid_cam->len = BSSID_CAM_ENT_SIZE;
57262306a36Sopenharmony_ci	bssid_cam->offset = 0;
57362306a36Sopenharmony_ci	bssid_cam->valid = true;
57462306a36Sopenharmony_ci	ether_addr_copy(bssid_cam->bssid, bssid);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	return 0;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_civoid rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	ether_addr_copy(bssid_cam->bssid, rtwvif->bssid);
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ciint rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
58962306a36Sopenharmony_ci	struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
59062306a36Sopenharmony_ci	int ret;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, rtwvif->bssid);
59362306a36Sopenharmony_ci	if (ret) {
59462306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to init bssid cam\n");
59562306a36Sopenharmony_ci		return ret;
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	ret = rtw89_cam_init_addr_cam(rtwdev, addr_cam, bssid_cam);
59962306a36Sopenharmony_ci	if (ret) {
60062306a36Sopenharmony_ci		rtw89_err(rtwdev, "failed to init addr cam\n");
60162306a36Sopenharmony_ci		return ret;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	return 0;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ciint rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev,
60862306a36Sopenharmony_ci				  struct rtw89_vif *rtwvif,
60962306a36Sopenharmony_ci				  struct rtw89_sta *rtwsta, u8 *cmd)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
61262306a36Sopenharmony_ci	struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta);
61362306a36Sopenharmony_ci	u8 bss_color = vif->bss_conf.he_bss_color.color;
61462306a36Sopenharmony_ci	u8 bss_mask;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (vif->bss_conf.nontransmitted)
61762306a36Sopenharmony_ci		bss_mask = RTW89_BSSID_MATCH_5_BYTES;
61862306a36Sopenharmony_ci	else
61962306a36Sopenharmony_ci		bss_mask = RTW89_BSSID_MATCH_ALL;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_IDX(cmd, bssid_cam->bssid_cam_idx);
62262306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_OFFSET(cmd, bssid_cam->offset);
62362306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_LEN(cmd, bssid_cam->len);
62462306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_VALID(cmd, bssid_cam->valid);
62562306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_MASK(cmd, bss_mask);
62662306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_BB_SEL(cmd, bssid_cam->phy_idx);
62762306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_BSS_COLOR(cmd, bss_color);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_BSSID0(cmd, bssid_cam->bssid[0]);
63062306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_BSSID1(cmd, bssid_cam->bssid[1]);
63162306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_BSSID2(cmd, bssid_cam->bssid[2]);
63262306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_BSSID3(cmd, bssid_cam->bssid[3]);
63362306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_BSSID4(cmd, bssid_cam->bssid[4]);
63462306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_BSSID5(cmd, bssid_cam->bssid[5]);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	return 0;
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic u8 rtw89_cam_addr_hash(u8 start, const u8 *addr)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	u8 hash = 0;
64262306a36Sopenharmony_ci	u8 i;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	for (i = start; i < ETH_ALEN; i++)
64562306a36Sopenharmony_ci		hash ^= addr[i];
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	return hash;
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_civoid rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
65162306a36Sopenharmony_ci				  struct rtw89_vif *rtwvif,
65262306a36Sopenharmony_ci				  struct rtw89_sta *rtwsta,
65362306a36Sopenharmony_ci				  const u8 *scan_mac_addr,
65462306a36Sopenharmony_ci				  u8 *cmd)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
65762306a36Sopenharmony_ci	struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
65862306a36Sopenharmony_ci	struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta);
65962306a36Sopenharmony_ci	const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif->mac_addr;
66062306a36Sopenharmony_ci	u8 sma_hash, tma_hash, addr_msk_start;
66162306a36Sopenharmony_ci	u8 sma_start = 0;
66262306a36Sopenharmony_ci	u8 tma_start = 0;
66362306a36Sopenharmony_ci	u8 *tma = sta ? sta->addr : rtwvif->bssid;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (addr_cam->addr_mask != 0) {
66662306a36Sopenharmony_ci		addr_msk_start = __ffs(addr_cam->addr_mask);
66762306a36Sopenharmony_ci		if (addr_cam->mask_sel == RTW89_SMA)
66862306a36Sopenharmony_ci			sma_start = addr_msk_start;
66962306a36Sopenharmony_ci		else if (addr_cam->mask_sel == RTW89_TMA)
67062306a36Sopenharmony_ci			tma_start = addr_msk_start;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci	sma_hash = rtw89_cam_addr_hash(sma_start, sma);
67362306a36Sopenharmony_ci	tma_hash = rtw89_cam_addr_hash(tma_start, tma);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	FWCMD_SET_ADDR_IDX(cmd, addr_cam->addr_cam_idx);
67662306a36Sopenharmony_ci	FWCMD_SET_ADDR_OFFSET(cmd, addr_cam->offset);
67762306a36Sopenharmony_ci	FWCMD_SET_ADDR_LEN(cmd, addr_cam->len);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	FWCMD_SET_ADDR_VALID(cmd, addr_cam->valid);
68062306a36Sopenharmony_ci	FWCMD_SET_ADDR_NET_TYPE(cmd, rtwvif->net_type);
68162306a36Sopenharmony_ci	FWCMD_SET_ADDR_BCN_HIT_COND(cmd, rtwvif->bcn_hit_cond);
68262306a36Sopenharmony_ci	FWCMD_SET_ADDR_HIT_RULE(cmd, rtwvif->hit_rule);
68362306a36Sopenharmony_ci	FWCMD_SET_ADDR_BB_SEL(cmd, rtwvif->phy_idx);
68462306a36Sopenharmony_ci	FWCMD_SET_ADDR_ADDR_MASK(cmd, addr_cam->addr_mask);
68562306a36Sopenharmony_ci	FWCMD_SET_ADDR_MASK_SEL(cmd, addr_cam->mask_sel);
68662306a36Sopenharmony_ci	FWCMD_SET_ADDR_SMA_HASH(cmd, sma_hash);
68762306a36Sopenharmony_ci	FWCMD_SET_ADDR_TMA_HASH(cmd, tma_hash);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	FWCMD_SET_ADDR_BSSID_CAM_IDX(cmd, addr_cam->bssid_cam_idx);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	FWCMD_SET_ADDR_SMA0(cmd, sma[0]);
69262306a36Sopenharmony_ci	FWCMD_SET_ADDR_SMA1(cmd, sma[1]);
69362306a36Sopenharmony_ci	FWCMD_SET_ADDR_SMA2(cmd, sma[2]);
69462306a36Sopenharmony_ci	FWCMD_SET_ADDR_SMA3(cmd, sma[3]);
69562306a36Sopenharmony_ci	FWCMD_SET_ADDR_SMA4(cmd, sma[4]);
69662306a36Sopenharmony_ci	FWCMD_SET_ADDR_SMA5(cmd, sma[5]);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	FWCMD_SET_ADDR_TMA0(cmd, tma[0]);
69962306a36Sopenharmony_ci	FWCMD_SET_ADDR_TMA1(cmd, tma[1]);
70062306a36Sopenharmony_ci	FWCMD_SET_ADDR_TMA2(cmd, tma[2]);
70162306a36Sopenharmony_ci	FWCMD_SET_ADDR_TMA3(cmd, tma[3]);
70262306a36Sopenharmony_ci	FWCMD_SET_ADDR_TMA4(cmd, tma[4]);
70362306a36Sopenharmony_ci	FWCMD_SET_ADDR_TMA5(cmd, tma[5]);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif->port);
70662306a36Sopenharmony_ci	FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif->port);
70762306a36Sopenharmony_ci	FWCMD_SET_ADDR_TF_TRS(cmd, rtwvif->trigger);
70862306a36Sopenharmony_ci	FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif->lsig_txop);
70962306a36Sopenharmony_ci	FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif->tgt_ind);
71062306a36Sopenharmony_ci	FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif->frm_tgt_ind);
71162306a36Sopenharmony_ci	FWCMD_SET_ADDR_MACID(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id);
71262306a36Sopenharmony_ci	if (rtwvif->net_type == RTW89_NET_TYPE_INFRA)
71362306a36Sopenharmony_ci		FWCMD_SET_ADDR_AID12(cmd, vif->cfg.aid & 0xfff);
71462306a36Sopenharmony_ci	else if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
71562306a36Sopenharmony_ci		FWCMD_SET_ADDR_AID12(cmd, sta ? sta->aid & 0xfff : 0);
71662306a36Sopenharmony_ci	FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif->wowlan_pattern);
71762306a36Sopenharmony_ci	FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif->wowlan_uc);
71862306a36Sopenharmony_ci	FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif->wowlan_magic);
71962306a36Sopenharmony_ci	FWCMD_SET_ADDR_WAPI(cmd, addr_cam->wapi);
72062306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT_MODE(cmd, addr_cam->sec_ent_mode);
72162306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT0_KEYID(cmd, addr_cam->sec_ent_keyid[0]);
72262306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT1_KEYID(cmd, addr_cam->sec_ent_keyid[1]);
72362306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT2_KEYID(cmd, addr_cam->sec_ent_keyid[2]);
72462306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT3_KEYID(cmd, addr_cam->sec_ent_keyid[3]);
72562306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT4_KEYID(cmd, addr_cam->sec_ent_keyid[4]);
72662306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT5_KEYID(cmd, addr_cam->sec_ent_keyid[5]);
72762306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT6_KEYID(cmd, addr_cam->sec_ent_keyid[6]);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT_VALID(cmd, addr_cam->sec_cam_map[0] & 0xff);
73062306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT0(cmd, addr_cam->sec_ent[0]);
73162306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT1(cmd, addr_cam->sec_ent[1]);
73262306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT2(cmd, addr_cam->sec_ent[2]);
73362306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT3(cmd, addr_cam->sec_ent[3]);
73462306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT4(cmd, addr_cam->sec_ent[4]);
73562306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT5(cmd, addr_cam->sec_ent[5]);
73662306a36Sopenharmony_ci	FWCMD_SET_ADDR_SEC_ENT6(cmd, addr_cam->sec_ent[6]);
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_civoid rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev,
74062306a36Sopenharmony_ci					 struct rtw89_vif *rtwvif,
74162306a36Sopenharmony_ci					 struct rtw89_sta *rtwsta,
74262306a36Sopenharmony_ci					 u8 *cmd)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	SET_DCTL_MACID_V1(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id);
74762306a36Sopenharmony_ci	SET_DCTL_OPERATION_V1(cmd, 1);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	SET_DCTL_SEC_ENT0_KEYID_V1(cmd, addr_cam->sec_ent_keyid[0]);
75062306a36Sopenharmony_ci	SET_DCTL_SEC_ENT1_KEYID_V1(cmd, addr_cam->sec_ent_keyid[1]);
75162306a36Sopenharmony_ci	SET_DCTL_SEC_ENT2_KEYID_V1(cmd, addr_cam->sec_ent_keyid[2]);
75262306a36Sopenharmony_ci	SET_DCTL_SEC_ENT3_KEYID_V1(cmd, addr_cam->sec_ent_keyid[3]);
75362306a36Sopenharmony_ci	SET_DCTL_SEC_ENT4_KEYID_V1(cmd, addr_cam->sec_ent_keyid[4]);
75462306a36Sopenharmony_ci	SET_DCTL_SEC_ENT5_KEYID_V1(cmd, addr_cam->sec_ent_keyid[5]);
75562306a36Sopenharmony_ci	SET_DCTL_SEC_ENT6_KEYID_V1(cmd, addr_cam->sec_ent_keyid[6]);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	SET_DCTL_SEC_ENT_VALID_V1(cmd, addr_cam->sec_cam_map[0] & 0xff);
75862306a36Sopenharmony_ci	SET_DCTL_SEC_ENT0_V1(cmd, addr_cam->sec_ent[0]);
75962306a36Sopenharmony_ci	SET_DCTL_SEC_ENT1_V1(cmd, addr_cam->sec_ent[1]);
76062306a36Sopenharmony_ci	SET_DCTL_SEC_ENT2_V1(cmd, addr_cam->sec_ent[2]);
76162306a36Sopenharmony_ci	SET_DCTL_SEC_ENT3_V1(cmd, addr_cam->sec_ent[3]);
76262306a36Sopenharmony_ci	SET_DCTL_SEC_ENT4_V1(cmd, addr_cam->sec_ent[4]);
76362306a36Sopenharmony_ci	SET_DCTL_SEC_ENT5_V1(cmd, addr_cam->sec_ent[5]);
76462306a36Sopenharmony_ci	SET_DCTL_SEC_ENT6_V1(cmd, addr_cam->sec_ent[6]);
76562306a36Sopenharmony_ci}
766