1*8e93258fSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2*8e93258fSBjoern A. Zeeb /* Copyright(c) 2019-2020 Realtek Corporation 3*8e93258fSBjoern A. Zeeb */ 4*8e93258fSBjoern A. Zeeb 5*8e93258fSBjoern A. Zeeb #include "cam.h" 6*8e93258fSBjoern A. Zeeb #include "debug.h" 7*8e93258fSBjoern A. Zeeb #include "fw.h" 8*8e93258fSBjoern A. Zeeb #include "mac.h" 9*8e93258fSBjoern A. Zeeb 10*8e93258fSBjoern A. Zeeb static struct sk_buff * 11*8e93258fSBjoern A. Zeeb rtw89_cam_get_sec_key_cmd(struct rtw89_dev *rtwdev, 12*8e93258fSBjoern A. Zeeb struct rtw89_sec_cam_entry *sec_cam, 13*8e93258fSBjoern A. Zeeb bool ext_key) 14*8e93258fSBjoern A. Zeeb { 15*8e93258fSBjoern A. Zeeb struct sk_buff *skb; 16*8e93258fSBjoern A. Zeeb u32 cmd_len = H2C_SEC_CAM_LEN; 17*8e93258fSBjoern A. Zeeb u32 key32[4]; 18*8e93258fSBjoern A. Zeeb u8 *cmd; 19*8e93258fSBjoern A. Zeeb int i, j; 20*8e93258fSBjoern A. Zeeb 21*8e93258fSBjoern A. Zeeb skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, cmd_len); 22*8e93258fSBjoern A. Zeeb if (!skb) 23*8e93258fSBjoern A. Zeeb return NULL; 24*8e93258fSBjoern A. Zeeb 25*8e93258fSBjoern A. Zeeb skb_put_zero(skb, cmd_len); 26*8e93258fSBjoern A. Zeeb 27*8e93258fSBjoern A. Zeeb for (i = 0; i < 4; i++) { 28*8e93258fSBjoern A. Zeeb j = i * 4; 29*8e93258fSBjoern A. Zeeb j += ext_key ? 16 : 0; 30*8e93258fSBjoern A. Zeeb key32[i] = FIELD_PREP(GENMASK(7, 0), sec_cam->key[j + 0]) | 31*8e93258fSBjoern A. Zeeb FIELD_PREP(GENMASK(15, 8), sec_cam->key[j + 1]) | 32*8e93258fSBjoern A. Zeeb FIELD_PREP(GENMASK(23, 16), sec_cam->key[j + 2]) | 33*8e93258fSBjoern A. Zeeb FIELD_PREP(GENMASK(31, 24), sec_cam->key[j + 3]); 34*8e93258fSBjoern A. Zeeb } 35*8e93258fSBjoern A. Zeeb 36*8e93258fSBjoern A. Zeeb cmd = skb->data; 37*8e93258fSBjoern A. Zeeb RTW89_SET_FWCMD_SEC_IDX(cmd, sec_cam->sec_cam_idx + (ext_key ? 1 : 0)); 38*8e93258fSBjoern A. Zeeb RTW89_SET_FWCMD_SEC_OFFSET(cmd, sec_cam->offset); 39*8e93258fSBjoern A. Zeeb RTW89_SET_FWCMD_SEC_LEN(cmd, sec_cam->len); 40*8e93258fSBjoern A. Zeeb RTW89_SET_FWCMD_SEC_TYPE(cmd, sec_cam->type); 41*8e93258fSBjoern A. Zeeb RTW89_SET_FWCMD_SEC_EXT_KEY(cmd, ext_key); 42*8e93258fSBjoern A. Zeeb RTW89_SET_FWCMD_SEC_SPP_MODE(cmd, sec_cam->spp_mode); 43*8e93258fSBjoern A. Zeeb RTW89_SET_FWCMD_SEC_KEY0(cmd, key32[0]); 44*8e93258fSBjoern A. Zeeb RTW89_SET_FWCMD_SEC_KEY1(cmd, key32[1]); 45*8e93258fSBjoern A. Zeeb RTW89_SET_FWCMD_SEC_KEY2(cmd, key32[2]); 46*8e93258fSBjoern A. Zeeb RTW89_SET_FWCMD_SEC_KEY3(cmd, key32[3]); 47*8e93258fSBjoern A. Zeeb 48*8e93258fSBjoern A. Zeeb return skb; 49*8e93258fSBjoern A. Zeeb } 50*8e93258fSBjoern A. Zeeb 51*8e93258fSBjoern A. Zeeb static int rtw89_cam_send_sec_key_cmd(struct rtw89_dev *rtwdev, 52*8e93258fSBjoern A. Zeeb struct rtw89_sec_cam_entry *sec_cam) 53*8e93258fSBjoern A. Zeeb { 54*8e93258fSBjoern A. Zeeb struct sk_buff *skb, *ext_skb; 55*8e93258fSBjoern A. Zeeb int ret; 56*8e93258fSBjoern A. Zeeb 57*8e93258fSBjoern A. Zeeb skb = rtw89_cam_get_sec_key_cmd(rtwdev, sec_cam, false); 58*8e93258fSBjoern A. Zeeb if (!skb) { 59*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to get sec key command\n"); 60*8e93258fSBjoern A. Zeeb return -ENOMEM; 61*8e93258fSBjoern A. Zeeb } 62*8e93258fSBjoern A. Zeeb 63*8e93258fSBjoern A. Zeeb rtw89_h2c_pkt_set_hdr(rtwdev, skb, 64*8e93258fSBjoern A. Zeeb FWCMD_TYPE_H2C, 65*8e93258fSBjoern A. Zeeb H2C_CAT_MAC, 66*8e93258fSBjoern A. Zeeb H2C_CL_MAC_SEC_CAM, 67*8e93258fSBjoern A. Zeeb H2C_FUNC_MAC_SEC_UPD, 1, 0, 68*8e93258fSBjoern A. Zeeb H2C_SEC_CAM_LEN); 69*8e93258fSBjoern A. Zeeb ret = rtw89_h2c_tx(rtwdev, skb, false); 70*8e93258fSBjoern A. Zeeb if (ret) { 71*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to send sec key h2c: %d\n", ret); 72*8e93258fSBjoern A. Zeeb dev_kfree_skb(skb); 73*8e93258fSBjoern A. Zeeb return ret; 74*8e93258fSBjoern A. Zeeb } 75*8e93258fSBjoern A. Zeeb 76*8e93258fSBjoern A. Zeeb if (!sec_cam->ext_key) 77*8e93258fSBjoern A. Zeeb return 0; 78*8e93258fSBjoern A. Zeeb 79*8e93258fSBjoern A. Zeeb ext_skb = rtw89_cam_get_sec_key_cmd(rtwdev, sec_cam, true); 80*8e93258fSBjoern A. Zeeb if (!ext_skb) { 81*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to get ext sec key command\n"); 82*8e93258fSBjoern A. Zeeb return -ENOMEM; 83*8e93258fSBjoern A. Zeeb } 84*8e93258fSBjoern A. Zeeb 85*8e93258fSBjoern A. Zeeb rtw89_h2c_pkt_set_hdr(rtwdev, ext_skb, 86*8e93258fSBjoern A. Zeeb FWCMD_TYPE_H2C, 87*8e93258fSBjoern A. Zeeb H2C_CAT_MAC, 88*8e93258fSBjoern A. Zeeb H2C_CL_MAC_SEC_CAM, 89*8e93258fSBjoern A. Zeeb H2C_FUNC_MAC_SEC_UPD, 90*8e93258fSBjoern A. Zeeb 1, 0, H2C_SEC_CAM_LEN); 91*8e93258fSBjoern A. Zeeb ret = rtw89_h2c_tx(rtwdev, ext_skb, false); 92*8e93258fSBjoern A. Zeeb if (ret) { 93*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to send ext sec key h2c: %d\n", ret); 94*8e93258fSBjoern A. Zeeb dev_kfree_skb(ext_skb); 95*8e93258fSBjoern A. Zeeb return ret; 96*8e93258fSBjoern A. Zeeb } 97*8e93258fSBjoern A. Zeeb 98*8e93258fSBjoern A. Zeeb return 0; 99*8e93258fSBjoern A. Zeeb } 100*8e93258fSBjoern A. Zeeb 101*8e93258fSBjoern A. Zeeb static int rtw89_cam_get_avail_sec_cam(struct rtw89_dev *rtwdev, 102*8e93258fSBjoern A. Zeeb u8 *sec_cam_idx, bool ext_key) 103*8e93258fSBjoern A. Zeeb { 104*8e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip; 105*8e93258fSBjoern A. Zeeb struct rtw89_cam_info *cam_info = &rtwdev->cam_info; 106*8e93258fSBjoern A. Zeeb u8 sec_cam_num = chip->scam_num; 107*8e93258fSBjoern A. Zeeb u8 idx = 0; 108*8e93258fSBjoern A. Zeeb 109*8e93258fSBjoern A. Zeeb if (!ext_key) { 110*8e93258fSBjoern A. Zeeb idx = find_first_zero_bit(cam_info->sec_cam_map, sec_cam_num); 111*8e93258fSBjoern A. Zeeb if (idx >= sec_cam_num) 112*8e93258fSBjoern A. Zeeb return -EBUSY; 113*8e93258fSBjoern A. Zeeb 114*8e93258fSBjoern A. Zeeb set_bit(idx, cam_info->sec_cam_map); 115*8e93258fSBjoern A. Zeeb *sec_cam_idx = idx; 116*8e93258fSBjoern A. Zeeb 117*8e93258fSBjoern A. Zeeb return 0; 118*8e93258fSBjoern A. Zeeb } 119*8e93258fSBjoern A. Zeeb 120*8e93258fSBjoern A. Zeeb again: 121*8e93258fSBjoern A. Zeeb idx = find_next_zero_bit(cam_info->sec_cam_map, sec_cam_num, idx); 122*8e93258fSBjoern A. Zeeb if (idx >= sec_cam_num - 1) 123*8e93258fSBjoern A. Zeeb return -EBUSY; 124*8e93258fSBjoern A. Zeeb /* ext keys need two cam entries for 256-bit key */ 125*8e93258fSBjoern A. Zeeb if (test_bit(idx + 1, cam_info->sec_cam_map)) { 126*8e93258fSBjoern A. Zeeb idx++; 127*8e93258fSBjoern A. Zeeb goto again; 128*8e93258fSBjoern A. Zeeb } 129*8e93258fSBjoern A. Zeeb 130*8e93258fSBjoern A. Zeeb set_bit(idx, cam_info->sec_cam_map); 131*8e93258fSBjoern A. Zeeb set_bit(idx + 1, cam_info->sec_cam_map); 132*8e93258fSBjoern A. Zeeb *sec_cam_idx = idx; 133*8e93258fSBjoern A. Zeeb 134*8e93258fSBjoern A. Zeeb return 0; 135*8e93258fSBjoern A. Zeeb } 136*8e93258fSBjoern A. Zeeb 137*8e93258fSBjoern A. Zeeb static int rtw89_cam_get_addr_cam_key_idx(struct rtw89_addr_cam_entry *addr_cam, 138*8e93258fSBjoern A. Zeeb struct rtw89_sec_cam_entry *sec_cam, 139*8e93258fSBjoern A. Zeeb struct ieee80211_key_conf *key, 140*8e93258fSBjoern A. Zeeb u8 *key_idx) 141*8e93258fSBjoern A. Zeeb { 142*8e93258fSBjoern A. Zeeb u8 idx; 143*8e93258fSBjoern A. Zeeb 144*8e93258fSBjoern A. Zeeb /* RTW89_ADDR_CAM_SEC_NONE : not enabled 145*8e93258fSBjoern A. Zeeb * RTW89_ADDR_CAM_SEC_ALL_UNI : 0 - 6 unicast 146*8e93258fSBjoern A. Zeeb * RTW89_ADDR_CAM_SEC_NORMAL : 0 - 1 unicast, 2 - 4 group, 5 - 6 BIP 147*8e93258fSBjoern A. Zeeb * RTW89_ADDR_CAM_SEC_4GROUP : 0 - 1 unicast, 2 - 5 group, 6 BIP 148*8e93258fSBjoern A. Zeeb */ 149*8e93258fSBjoern A. Zeeb switch (addr_cam->sec_ent_mode) { 150*8e93258fSBjoern A. Zeeb case RTW89_ADDR_CAM_SEC_NONE: 151*8e93258fSBjoern A. Zeeb return -EINVAL; 152*8e93258fSBjoern A. Zeeb case RTW89_ADDR_CAM_SEC_ALL_UNI: 153*8e93258fSBjoern A. Zeeb if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 154*8e93258fSBjoern A. Zeeb return -EINVAL; 155*8e93258fSBjoern A. Zeeb idx = find_first_zero_bit(addr_cam->sec_cam_map, 156*8e93258fSBjoern A. Zeeb RTW89_SEC_CAM_IN_ADDR_CAM); 157*8e93258fSBjoern A. Zeeb if (idx >= RTW89_SEC_CAM_IN_ADDR_CAM) 158*8e93258fSBjoern A. Zeeb return -EBUSY; 159*8e93258fSBjoern A. Zeeb *key_idx = idx; 160*8e93258fSBjoern A. Zeeb break; 161*8e93258fSBjoern A. Zeeb case RTW89_ADDR_CAM_SEC_NORMAL: 162*8e93258fSBjoern A. Zeeb if (sec_cam->type == RTW89_SEC_KEY_TYPE_BIP_CCMP128) { 163*8e93258fSBjoern A. Zeeb idx = find_next_zero_bit(addr_cam->sec_cam_map, 164*8e93258fSBjoern A. Zeeb RTW89_SEC_CAM_IN_ADDR_CAM, 5); 165*8e93258fSBjoern A. Zeeb if (idx > 6) 166*8e93258fSBjoern A. Zeeb return -EBUSY; 167*8e93258fSBjoern A. Zeeb *key_idx = idx; 168*8e93258fSBjoern A. Zeeb break; 169*8e93258fSBjoern A. Zeeb } 170*8e93258fSBjoern A. Zeeb 171*8e93258fSBjoern A. Zeeb if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { 172*8e93258fSBjoern A. Zeeb idx = find_next_zero_bit(addr_cam->sec_cam_map, 173*8e93258fSBjoern A. Zeeb RTW89_SEC_CAM_IN_ADDR_CAM, 0); 174*8e93258fSBjoern A. Zeeb if (idx > 1) 175*8e93258fSBjoern A. Zeeb return -EBUSY; 176*8e93258fSBjoern A. Zeeb *key_idx = idx; 177*8e93258fSBjoern A. Zeeb break; 178*8e93258fSBjoern A. Zeeb } 179*8e93258fSBjoern A. Zeeb 180*8e93258fSBjoern A. Zeeb /* Group keys */ 181*8e93258fSBjoern A. Zeeb idx = find_next_zero_bit(addr_cam->sec_cam_map, 182*8e93258fSBjoern A. Zeeb RTW89_SEC_CAM_IN_ADDR_CAM, 2); 183*8e93258fSBjoern A. Zeeb if (idx > 4) 184*8e93258fSBjoern A. Zeeb return -EBUSY; 185*8e93258fSBjoern A. Zeeb *key_idx = idx; 186*8e93258fSBjoern A. Zeeb break; 187*8e93258fSBjoern A. Zeeb case RTW89_ADDR_CAM_SEC_4GROUP: 188*8e93258fSBjoern A. Zeeb if (sec_cam->type == RTW89_SEC_KEY_TYPE_BIP_CCMP128) { 189*8e93258fSBjoern A. Zeeb if (test_bit(6, addr_cam->sec_cam_map)) 190*8e93258fSBjoern A. Zeeb return -EINVAL; 191*8e93258fSBjoern A. Zeeb *key_idx = 6; 192*8e93258fSBjoern A. Zeeb break; 193*8e93258fSBjoern A. Zeeb } 194*8e93258fSBjoern A. Zeeb 195*8e93258fSBjoern A. Zeeb if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { 196*8e93258fSBjoern A. Zeeb idx = find_next_zero_bit(addr_cam->sec_cam_map, 197*8e93258fSBjoern A. Zeeb RTW89_SEC_CAM_IN_ADDR_CAM, 0); 198*8e93258fSBjoern A. Zeeb if (idx > 1) 199*8e93258fSBjoern A. Zeeb return -EBUSY; 200*8e93258fSBjoern A. Zeeb *key_idx = idx; 201*8e93258fSBjoern A. Zeeb break; 202*8e93258fSBjoern A. Zeeb } 203*8e93258fSBjoern A. Zeeb 204*8e93258fSBjoern A. Zeeb /* Group keys */ 205*8e93258fSBjoern A. Zeeb idx = find_next_zero_bit(addr_cam->sec_cam_map, 206*8e93258fSBjoern A. Zeeb RTW89_SEC_CAM_IN_ADDR_CAM, 2); 207*8e93258fSBjoern A. Zeeb if (idx > 5) 208*8e93258fSBjoern A. Zeeb return -EBUSY; 209*8e93258fSBjoern A. Zeeb *key_idx = idx; 210*8e93258fSBjoern A. Zeeb break; 211*8e93258fSBjoern A. Zeeb } 212*8e93258fSBjoern A. Zeeb 213*8e93258fSBjoern A. Zeeb return 0; 214*8e93258fSBjoern A. Zeeb } 215*8e93258fSBjoern A. Zeeb 216*8e93258fSBjoern A. Zeeb static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, 217*8e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 218*8e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, 219*8e93258fSBjoern A. Zeeb struct ieee80211_key_conf *key, 220*8e93258fSBjoern A. Zeeb struct rtw89_sec_cam_entry *sec_cam) 221*8e93258fSBjoern A. Zeeb { 222*8e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); 223*8e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif; 224*8e93258fSBjoern A. Zeeb struct rtw89_addr_cam_entry *addr_cam; 225*8e93258fSBjoern A. Zeeb u8 key_idx = 0; 226*8e93258fSBjoern A. Zeeb int ret; 227*8e93258fSBjoern A. Zeeb 228*8e93258fSBjoern A. Zeeb if (!vif) { 229*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "No iface for adding sec cam\n"); 230*8e93258fSBjoern A. Zeeb return -EINVAL; 231*8e93258fSBjoern A. Zeeb } 232*8e93258fSBjoern A. Zeeb 233*8e93258fSBjoern A. Zeeb rtwvif = (struct rtw89_vif *)vif->drv_priv; 234*8e93258fSBjoern A. Zeeb addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); 235*8e93258fSBjoern A. Zeeb ret = rtw89_cam_get_addr_cam_key_idx(addr_cam, sec_cam, key, &key_idx); 236*8e93258fSBjoern A. Zeeb if (ret) { 237*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to get addr cam key idx %d, %d\n", 238*8e93258fSBjoern A. Zeeb addr_cam->sec_ent_mode, sec_cam->type); 239*8e93258fSBjoern A. Zeeb return ret; 240*8e93258fSBjoern A. Zeeb } 241*8e93258fSBjoern A. Zeeb 242*8e93258fSBjoern A. Zeeb key->hw_key_idx = key_idx; 243*8e93258fSBjoern A. Zeeb addr_cam->sec_ent_keyid[key_idx] = key->keyidx; 244*8e93258fSBjoern A. Zeeb addr_cam->sec_ent[key_idx] = sec_cam->sec_cam_idx; 245*8e93258fSBjoern A. Zeeb addr_cam->sec_entries[key_idx] = sec_cam; 246*8e93258fSBjoern A. Zeeb set_bit(key_idx, addr_cam->sec_cam_map); 247*8e93258fSBjoern A. Zeeb ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); 248*8e93258fSBjoern A. Zeeb if (ret) { 249*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n", 250*8e93258fSBjoern A. Zeeb ret); 251*8e93258fSBjoern A. Zeeb return ret; 252*8e93258fSBjoern A. Zeeb } 253*8e93258fSBjoern A. Zeeb ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); 254*8e93258fSBjoern A. Zeeb if (ret) { 255*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to update addr cam sec entry: %d\n", 256*8e93258fSBjoern A. Zeeb ret); 257*8e93258fSBjoern A. Zeeb clear_bit(key_idx, addr_cam->sec_cam_map); 258*8e93258fSBjoern A. Zeeb addr_cam->sec_entries[key_idx] = NULL; 259*8e93258fSBjoern A. Zeeb return ret; 260*8e93258fSBjoern A. Zeeb } 261*8e93258fSBjoern A. Zeeb 262*8e93258fSBjoern A. Zeeb return 0; 263*8e93258fSBjoern A. Zeeb } 264*8e93258fSBjoern A. Zeeb 265*8e93258fSBjoern A. Zeeb static int rtw89_cam_sec_key_install(struct rtw89_dev *rtwdev, 266*8e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 267*8e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, 268*8e93258fSBjoern A. Zeeb struct ieee80211_key_conf *key, 269*8e93258fSBjoern A. Zeeb u8 hw_key_type, bool ext_key) 270*8e93258fSBjoern A. Zeeb { 271*8e93258fSBjoern A. Zeeb struct rtw89_sec_cam_entry *sec_cam = NULL; 272*8e93258fSBjoern A. Zeeb struct rtw89_cam_info *cam_info = &rtwdev->cam_info; 273*8e93258fSBjoern A. Zeeb u8 sec_cam_idx; 274*8e93258fSBjoern A. Zeeb int ret; 275*8e93258fSBjoern A. Zeeb 276*8e93258fSBjoern A. Zeeb /* maximum key length 256-bit */ 277*8e93258fSBjoern A. Zeeb if (key->keylen > 32) { 278*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "invalid sec key length %d\n", key->keylen); 279*8e93258fSBjoern A. Zeeb return -EINVAL; 280*8e93258fSBjoern A. Zeeb } 281*8e93258fSBjoern A. Zeeb 282*8e93258fSBjoern A. Zeeb ret = rtw89_cam_get_avail_sec_cam(rtwdev, &sec_cam_idx, ext_key); 283*8e93258fSBjoern A. Zeeb if (ret) { 284*8e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "no available sec cam: %d ext: %d\n", 285*8e93258fSBjoern A. Zeeb ret, ext_key); 286*8e93258fSBjoern A. Zeeb return ret; 287*8e93258fSBjoern A. Zeeb } 288*8e93258fSBjoern A. Zeeb 289*8e93258fSBjoern A. Zeeb sec_cam = kzalloc(sizeof(*sec_cam), GFP_KERNEL); 290*8e93258fSBjoern A. Zeeb if (!sec_cam) { 291*8e93258fSBjoern A. Zeeb ret = -ENOMEM; 292*8e93258fSBjoern A. Zeeb goto err_release_cam; 293*8e93258fSBjoern A. Zeeb } 294*8e93258fSBjoern A. Zeeb 295*8e93258fSBjoern A. Zeeb sec_cam->sec_cam_idx = sec_cam_idx; 296*8e93258fSBjoern A. Zeeb sec_cam->type = hw_key_type; 297*8e93258fSBjoern A. Zeeb sec_cam->len = RTW89_SEC_CAM_LEN; 298*8e93258fSBjoern A. Zeeb sec_cam->ext_key = ext_key; 299*8e93258fSBjoern A. Zeeb memcpy(sec_cam->key, key->key, key->keylen); 300*8e93258fSBjoern A. Zeeb ret = rtw89_cam_send_sec_key_cmd(rtwdev, sec_cam); 301*8e93258fSBjoern A. Zeeb if (ret) { 302*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to send sec key cmd: %d\n", ret); 303*8e93258fSBjoern A. Zeeb goto err_release_cam; 304*8e93258fSBjoern A. Zeeb } 305*8e93258fSBjoern A. Zeeb 306*8e93258fSBjoern A. Zeeb /* associate with addr cam */ 307*8e93258fSBjoern A. Zeeb ret = rtw89_cam_attach_sec_cam(rtwdev, vif, sta, key, sec_cam); 308*8e93258fSBjoern A. Zeeb if (ret) { 309*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to attach sec cam: %d\n", ret); 310*8e93258fSBjoern A. Zeeb goto err_release_cam; 311*8e93258fSBjoern A. Zeeb } 312*8e93258fSBjoern A. Zeeb 313*8e93258fSBjoern A. Zeeb return 0; 314*8e93258fSBjoern A. Zeeb 315*8e93258fSBjoern A. Zeeb err_release_cam: 316*8e93258fSBjoern A. Zeeb kfree(sec_cam); 317*8e93258fSBjoern A. Zeeb clear_bit(sec_cam_idx, cam_info->sec_cam_map); 318*8e93258fSBjoern A. Zeeb if (ext_key) 319*8e93258fSBjoern A. Zeeb clear_bit(sec_cam_idx + 1, cam_info->sec_cam_map); 320*8e93258fSBjoern A. Zeeb 321*8e93258fSBjoern A. Zeeb return ret; 322*8e93258fSBjoern A. Zeeb } 323*8e93258fSBjoern A. Zeeb 324*8e93258fSBjoern A. Zeeb int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev, 325*8e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 326*8e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, 327*8e93258fSBjoern A. Zeeb struct ieee80211_key_conf *key) 328*8e93258fSBjoern A. Zeeb { 329*8e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip; 330*8e93258fSBjoern A. Zeeb u8 hw_key_type; 331*8e93258fSBjoern A. Zeeb bool ext_key = false; 332*8e93258fSBjoern A. Zeeb int ret; 333*8e93258fSBjoern A. Zeeb 334*8e93258fSBjoern A. Zeeb switch (key->cipher) { 335*8e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP40: 336*8e93258fSBjoern A. Zeeb hw_key_type = RTW89_SEC_KEY_TYPE_WEP40; 337*8e93258fSBjoern A. Zeeb break; 338*8e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP104: 339*8e93258fSBjoern A. Zeeb hw_key_type = RTW89_SEC_KEY_TYPE_WEP104; 340*8e93258fSBjoern A. Zeeb break; 341*8e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP: 342*8e93258fSBjoern A. Zeeb hw_key_type = RTW89_SEC_KEY_TYPE_CCMP128; 343*8e93258fSBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; 344*8e93258fSBjoern A. Zeeb break; 345*8e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP_256: 346*8e93258fSBjoern A. Zeeb hw_key_type = RTW89_SEC_KEY_TYPE_CCMP256; 347*8e93258fSBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; 348*8e93258fSBjoern A. Zeeb ext_key = true; 349*8e93258fSBjoern A. Zeeb break; 350*8e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_GCMP: 351*8e93258fSBjoern A. Zeeb hw_key_type = RTW89_SEC_KEY_TYPE_GCMP128; 352*8e93258fSBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; 353*8e93258fSBjoern A. Zeeb break; 354*8e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_GCMP_256: 355*8e93258fSBjoern A. Zeeb hw_key_type = RTW89_SEC_KEY_TYPE_GCMP256; 356*8e93258fSBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; 357*8e93258fSBjoern A. Zeeb ext_key = true; 358*8e93258fSBjoern A. Zeeb break; 359*8e93258fSBjoern A. Zeeb default: 360*8e93258fSBjoern A. Zeeb return -EOPNOTSUPP; 361*8e93258fSBjoern A. Zeeb } 362*8e93258fSBjoern A. Zeeb 363*8e93258fSBjoern A. Zeeb if (!chip->hw_sec_hdr) 364*8e93258fSBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 365*8e93258fSBjoern A. Zeeb 366*8e93258fSBjoern A. Zeeb ret = rtw89_cam_sec_key_install(rtwdev, vif, sta, key, hw_key_type, 367*8e93258fSBjoern A. Zeeb ext_key); 368*8e93258fSBjoern A. Zeeb if (ret) { 369*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to install key type %d ext %d: %d\n", 370*8e93258fSBjoern A. Zeeb hw_key_type, ext_key, ret); 371*8e93258fSBjoern A. Zeeb return ret; 372*8e93258fSBjoern A. Zeeb } 373*8e93258fSBjoern A. Zeeb 374*8e93258fSBjoern A. Zeeb return 0; 375*8e93258fSBjoern A. Zeeb } 376*8e93258fSBjoern A. Zeeb 377*8e93258fSBjoern A. Zeeb int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev, 378*8e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 379*8e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, 380*8e93258fSBjoern A. Zeeb struct ieee80211_key_conf *key, 381*8e93258fSBjoern A. Zeeb bool inform_fw) 382*8e93258fSBjoern A. Zeeb { 383*8e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); 384*8e93258fSBjoern A. Zeeb struct rtw89_cam_info *cam_info = &rtwdev->cam_info; 385*8e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif; 386*8e93258fSBjoern A. Zeeb struct rtw89_addr_cam_entry *addr_cam; 387*8e93258fSBjoern A. Zeeb struct rtw89_sec_cam_entry *sec_cam; 388*8e93258fSBjoern A. Zeeb u8 key_idx = key->hw_key_idx; 389*8e93258fSBjoern A. Zeeb u8 sec_cam_idx; 390*8e93258fSBjoern A. Zeeb int ret = 0; 391*8e93258fSBjoern A. Zeeb 392*8e93258fSBjoern A. Zeeb if (!vif) { 393*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "No iface for deleting sec cam\n"); 394*8e93258fSBjoern A. Zeeb return -EINVAL; 395*8e93258fSBjoern A. Zeeb } 396*8e93258fSBjoern A. Zeeb 397*8e93258fSBjoern A. Zeeb rtwvif = (struct rtw89_vif *)vif->drv_priv; 398*8e93258fSBjoern A. Zeeb addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); 399*8e93258fSBjoern A. Zeeb sec_cam = addr_cam->sec_entries[key_idx]; 400*8e93258fSBjoern A. Zeeb if (!sec_cam) 401*8e93258fSBjoern A. Zeeb return -EINVAL; 402*8e93258fSBjoern A. Zeeb 403*8e93258fSBjoern A. Zeeb /* detach sec cam from addr cam */ 404*8e93258fSBjoern A. Zeeb clear_bit(key_idx, addr_cam->sec_cam_map); 405*8e93258fSBjoern A. Zeeb addr_cam->sec_entries[key_idx] = NULL; 406*8e93258fSBjoern A. Zeeb if (inform_fw) { 407*8e93258fSBjoern A. Zeeb ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); 408*8e93258fSBjoern A. Zeeb if (ret) 409*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to update dctl cam del key: %d\n", ret); 410*8e93258fSBjoern A. Zeeb ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); 411*8e93258fSBjoern A. Zeeb if (ret) 412*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret); 413*8e93258fSBjoern A. Zeeb } 414*8e93258fSBjoern A. Zeeb 415*8e93258fSBjoern A. Zeeb /* clear valid bit in addr cam will disable sec cam, 416*8e93258fSBjoern A. Zeeb * so we don't need to send H2C command again 417*8e93258fSBjoern A. Zeeb */ 418*8e93258fSBjoern A. Zeeb sec_cam_idx = sec_cam->sec_cam_idx; 419*8e93258fSBjoern A. Zeeb clear_bit(sec_cam_idx, cam_info->sec_cam_map); 420*8e93258fSBjoern A. Zeeb if (sec_cam->ext_key) 421*8e93258fSBjoern A. Zeeb clear_bit(sec_cam_idx + 1, cam_info->sec_cam_map); 422*8e93258fSBjoern A. Zeeb 423*8e93258fSBjoern A. Zeeb kfree(sec_cam); 424*8e93258fSBjoern A. Zeeb 425*8e93258fSBjoern A. Zeeb return ret; 426*8e93258fSBjoern A. Zeeb } 427*8e93258fSBjoern A. Zeeb 428*8e93258fSBjoern A. Zeeb static void rtw89_cam_reset_key_iter(struct ieee80211_hw *hw, 429*8e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 430*8e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, 431*8e93258fSBjoern A. Zeeb struct ieee80211_key_conf *key, 432*8e93258fSBjoern A. Zeeb void *data) 433*8e93258fSBjoern A. Zeeb { 434*8e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = (struct rtw89_dev *)data; 435*8e93258fSBjoern A. Zeeb 436*8e93258fSBjoern A. Zeeb rtw89_cam_sec_key_del(rtwdev, vif, sta, key, false); 437*8e93258fSBjoern A. Zeeb } 438*8e93258fSBjoern A. Zeeb 439*8e93258fSBjoern A. Zeeb void rtw89_cam_deinit_addr_cam(struct rtw89_dev *rtwdev, 440*8e93258fSBjoern A. Zeeb struct rtw89_addr_cam_entry *addr_cam) 441*8e93258fSBjoern A. Zeeb { 442*8e93258fSBjoern A. Zeeb struct rtw89_cam_info *cam_info = &rtwdev->cam_info; 443*8e93258fSBjoern A. Zeeb 444*8e93258fSBjoern A. Zeeb addr_cam->valid = false; 445*8e93258fSBjoern A. Zeeb clear_bit(addr_cam->addr_cam_idx, cam_info->addr_cam_map); 446*8e93258fSBjoern A. Zeeb } 447*8e93258fSBjoern A. Zeeb 448*8e93258fSBjoern A. Zeeb void rtw89_cam_deinit_bssid_cam(struct rtw89_dev *rtwdev, 449*8e93258fSBjoern A. Zeeb struct rtw89_bssid_cam_entry *bssid_cam) 450*8e93258fSBjoern A. Zeeb { 451*8e93258fSBjoern A. Zeeb struct rtw89_cam_info *cam_info = &rtwdev->cam_info; 452*8e93258fSBjoern A. Zeeb 453*8e93258fSBjoern A. Zeeb bssid_cam->valid = false; 454*8e93258fSBjoern A. Zeeb clear_bit(bssid_cam->bssid_cam_idx, cam_info->bssid_cam_map); 455*8e93258fSBjoern A. Zeeb } 456*8e93258fSBjoern A. Zeeb 457*8e93258fSBjoern A. Zeeb void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 458*8e93258fSBjoern A. Zeeb { 459*8e93258fSBjoern A. Zeeb struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam; 460*8e93258fSBjoern A. Zeeb struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; 461*8e93258fSBjoern A. Zeeb 462*8e93258fSBjoern A. Zeeb rtw89_cam_deinit_addr_cam(rtwdev, addr_cam); 463*8e93258fSBjoern A. Zeeb rtw89_cam_deinit_bssid_cam(rtwdev, bssid_cam); 464*8e93258fSBjoern A. Zeeb } 465*8e93258fSBjoern A. Zeeb 466*8e93258fSBjoern A. Zeeb void rtw89_cam_reset_keys(struct rtw89_dev *rtwdev) 467*8e93258fSBjoern A. Zeeb { 468*8e93258fSBjoern A. Zeeb rcu_read_lock(); 469*8e93258fSBjoern A. Zeeb ieee80211_iter_keys_rcu(rtwdev->hw, NULL, rtw89_cam_reset_key_iter, rtwdev); 470*8e93258fSBjoern A. Zeeb rcu_read_unlock(); 471*8e93258fSBjoern A. Zeeb } 472*8e93258fSBjoern A. Zeeb 473*8e93258fSBjoern A. Zeeb static int rtw89_cam_get_avail_addr_cam(struct rtw89_dev *rtwdev, 474*8e93258fSBjoern A. Zeeb u8 *addr_cam_idx) 475*8e93258fSBjoern A. Zeeb { 476*8e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip; 477*8e93258fSBjoern A. Zeeb struct rtw89_cam_info *cam_info = &rtwdev->cam_info; 478*8e93258fSBjoern A. Zeeb u8 addr_cam_num = chip->acam_num; 479*8e93258fSBjoern A. Zeeb u8 idx; 480*8e93258fSBjoern A. Zeeb 481*8e93258fSBjoern A. Zeeb idx = find_first_zero_bit(cam_info->addr_cam_map, addr_cam_num); 482*8e93258fSBjoern A. Zeeb if (idx >= addr_cam_num) 483*8e93258fSBjoern A. Zeeb return -EBUSY; 484*8e93258fSBjoern A. Zeeb 485*8e93258fSBjoern A. Zeeb set_bit(idx, cam_info->addr_cam_map); 486*8e93258fSBjoern A. Zeeb *addr_cam_idx = idx; 487*8e93258fSBjoern A. Zeeb 488*8e93258fSBjoern A. Zeeb return 0; 489*8e93258fSBjoern A. Zeeb } 490*8e93258fSBjoern A. Zeeb 491*8e93258fSBjoern A. Zeeb int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, 492*8e93258fSBjoern A. Zeeb struct rtw89_addr_cam_entry *addr_cam, 493*8e93258fSBjoern A. Zeeb const struct rtw89_bssid_cam_entry *bssid_cam) 494*8e93258fSBjoern A. Zeeb { 495*8e93258fSBjoern A. Zeeb u8 addr_cam_idx; 496*8e93258fSBjoern A. Zeeb int i; 497*8e93258fSBjoern A. Zeeb int ret; 498*8e93258fSBjoern A. Zeeb 499*8e93258fSBjoern A. Zeeb if (unlikely(addr_cam->valid)) { 500*8e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_FW, 501*8e93258fSBjoern A. Zeeb "addr cam is already valid; skip init\n"); 502*8e93258fSBjoern A. Zeeb return 0; 503*8e93258fSBjoern A. Zeeb } 504*8e93258fSBjoern A. Zeeb 505*8e93258fSBjoern A. Zeeb ret = rtw89_cam_get_avail_addr_cam(rtwdev, &addr_cam_idx); 506*8e93258fSBjoern A. Zeeb if (ret) { 507*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to get available addr cam\n"); 508*8e93258fSBjoern A. Zeeb return ret; 509*8e93258fSBjoern A. Zeeb } 510*8e93258fSBjoern A. Zeeb 511*8e93258fSBjoern A. Zeeb addr_cam->addr_cam_idx = addr_cam_idx; 512*8e93258fSBjoern A. Zeeb addr_cam->len = ADDR_CAM_ENT_SIZE; 513*8e93258fSBjoern A. Zeeb addr_cam->offset = 0; 514*8e93258fSBjoern A. Zeeb addr_cam->valid = true; 515*8e93258fSBjoern A. Zeeb addr_cam->addr_mask = 0; 516*8e93258fSBjoern A. Zeeb addr_cam->mask_sel = RTW89_NO_MSK; 517*8e93258fSBjoern A. Zeeb addr_cam->sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL; 518*8e93258fSBjoern A. Zeeb bitmap_zero(addr_cam->sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM); 519*8e93258fSBjoern A. Zeeb 520*8e93258fSBjoern A. Zeeb for (i = 0; i < RTW89_SEC_CAM_IN_ADDR_CAM; i++) { 521*8e93258fSBjoern A. Zeeb addr_cam->sec_ent_keyid[i] = 0; 522*8e93258fSBjoern A. Zeeb addr_cam->sec_ent[i] = 0; 523*8e93258fSBjoern A. Zeeb } 524*8e93258fSBjoern A. Zeeb 525*8e93258fSBjoern A. Zeeb /* associate addr cam with bssid cam */ 526*8e93258fSBjoern A. Zeeb addr_cam->bssid_cam_idx = bssid_cam->bssid_cam_idx; 527*8e93258fSBjoern A. Zeeb 528*8e93258fSBjoern A. Zeeb return 0; 529*8e93258fSBjoern A. Zeeb } 530*8e93258fSBjoern A. Zeeb 531*8e93258fSBjoern A. Zeeb static int rtw89_cam_get_avail_bssid_cam(struct rtw89_dev *rtwdev, 532*8e93258fSBjoern A. Zeeb u8 *bssid_cam_idx) 533*8e93258fSBjoern A. Zeeb { 534*8e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip; 535*8e93258fSBjoern A. Zeeb struct rtw89_cam_info *cam_info = &rtwdev->cam_info; 536*8e93258fSBjoern A. Zeeb u8 bssid_cam_num = chip->bcam_num; 537*8e93258fSBjoern A. Zeeb u8 idx; 538*8e93258fSBjoern A. Zeeb 539*8e93258fSBjoern A. Zeeb idx = find_first_zero_bit(cam_info->bssid_cam_map, bssid_cam_num); 540*8e93258fSBjoern A. Zeeb if (idx >= bssid_cam_num) 541*8e93258fSBjoern A. Zeeb return -EBUSY; 542*8e93258fSBjoern A. Zeeb 543*8e93258fSBjoern A. Zeeb set_bit(idx, cam_info->bssid_cam_map); 544*8e93258fSBjoern A. Zeeb *bssid_cam_idx = idx; 545*8e93258fSBjoern A. Zeeb 546*8e93258fSBjoern A. Zeeb return 0; 547*8e93258fSBjoern A. Zeeb } 548*8e93258fSBjoern A. Zeeb 549*8e93258fSBjoern A. Zeeb int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev, 550*8e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif, 551*8e93258fSBjoern A. Zeeb struct rtw89_bssid_cam_entry *bssid_cam, 552*8e93258fSBjoern A. Zeeb const u8 *bssid) 553*8e93258fSBjoern A. Zeeb { 554*8e93258fSBjoern A. Zeeb u8 bssid_cam_idx; 555*8e93258fSBjoern A. Zeeb int ret; 556*8e93258fSBjoern A. Zeeb 557*8e93258fSBjoern A. Zeeb if (unlikely(bssid_cam->valid)) { 558*8e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_FW, 559*8e93258fSBjoern A. Zeeb "bssid cam is already valid; skip init\n"); 560*8e93258fSBjoern A. Zeeb return 0; 561*8e93258fSBjoern A. Zeeb } 562*8e93258fSBjoern A. Zeeb 563*8e93258fSBjoern A. Zeeb ret = rtw89_cam_get_avail_bssid_cam(rtwdev, &bssid_cam_idx); 564*8e93258fSBjoern A. Zeeb if (ret) { 565*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to get available bssid cam\n"); 566*8e93258fSBjoern A. Zeeb return ret; 567*8e93258fSBjoern A. Zeeb } 568*8e93258fSBjoern A. Zeeb 569*8e93258fSBjoern A. Zeeb bssid_cam->bssid_cam_idx = bssid_cam_idx; 570*8e93258fSBjoern A. Zeeb bssid_cam->phy_idx = rtwvif->phy_idx; 571*8e93258fSBjoern A. Zeeb bssid_cam->len = BSSID_CAM_ENT_SIZE; 572*8e93258fSBjoern A. Zeeb bssid_cam->offset = 0; 573*8e93258fSBjoern A. Zeeb bssid_cam->valid = true; 574*8e93258fSBjoern A. Zeeb ether_addr_copy(bssid_cam->bssid, bssid); 575*8e93258fSBjoern A. Zeeb 576*8e93258fSBjoern A. Zeeb return 0; 577*8e93258fSBjoern A. Zeeb } 578*8e93258fSBjoern A. Zeeb 579*8e93258fSBjoern A. Zeeb void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 580*8e93258fSBjoern A. Zeeb { 581*8e93258fSBjoern A. Zeeb struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; 582*8e93258fSBjoern A. Zeeb 583*8e93258fSBjoern A. Zeeb ether_addr_copy(bssid_cam->bssid, rtwvif->bssid); 584*8e93258fSBjoern A. Zeeb } 585*8e93258fSBjoern A. Zeeb 586*8e93258fSBjoern A. Zeeb int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 587*8e93258fSBjoern A. Zeeb { 588*8e93258fSBjoern A. Zeeb struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam; 589*8e93258fSBjoern A. Zeeb struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; 590*8e93258fSBjoern A. Zeeb int ret; 591*8e93258fSBjoern A. Zeeb 592*8e93258fSBjoern A. Zeeb ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, rtwvif->bssid); 593*8e93258fSBjoern A. Zeeb if (ret) { 594*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to init bssid cam\n"); 595*8e93258fSBjoern A. Zeeb return ret; 596*8e93258fSBjoern A. Zeeb } 597*8e93258fSBjoern A. Zeeb 598*8e93258fSBjoern A. Zeeb ret = rtw89_cam_init_addr_cam(rtwdev, addr_cam, bssid_cam); 599*8e93258fSBjoern A. Zeeb if (ret) { 600*8e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to init addr cam\n"); 601*8e93258fSBjoern A. Zeeb return ret; 602*8e93258fSBjoern A. Zeeb } 603*8e93258fSBjoern A. Zeeb 604*8e93258fSBjoern A. Zeeb return 0; 605*8e93258fSBjoern A. Zeeb } 606*8e93258fSBjoern A. Zeeb 607*8e93258fSBjoern A. Zeeb int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, 608*8e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif, 609*8e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta, u8 *cmd) 610*8e93258fSBjoern A. Zeeb { 611*8e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); 612*8e93258fSBjoern A. Zeeb struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta); 613*8e93258fSBjoern A. Zeeb u8 bss_color = vif->bss_conf.he_bss_color.color; 614*8e93258fSBjoern A. Zeeb u8 bss_mask; 615*8e93258fSBjoern A. Zeeb 616*8e93258fSBjoern A. Zeeb if (vif->bss_conf.nontransmitted) 617*8e93258fSBjoern A. Zeeb bss_mask = RTW89_BSSID_MATCH_5_BYTES; 618*8e93258fSBjoern A. Zeeb else 619*8e93258fSBjoern A. Zeeb bss_mask = RTW89_BSSID_MATCH_ALL; 620*8e93258fSBjoern A. Zeeb 621*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_IDX(cmd, bssid_cam->bssid_cam_idx); 622*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_OFFSET(cmd, bssid_cam->offset); 623*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_LEN(cmd, bssid_cam->len); 624*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_VALID(cmd, bssid_cam->valid); 625*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_MASK(cmd, bss_mask); 626*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_BB_SEL(cmd, bssid_cam->phy_idx); 627*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_BSS_COLOR(cmd, bss_color); 628*8e93258fSBjoern A. Zeeb 629*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_BSSID0(cmd, bssid_cam->bssid[0]); 630*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_BSSID1(cmd, bssid_cam->bssid[1]); 631*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_BSSID2(cmd, bssid_cam->bssid[2]); 632*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_BSSID3(cmd, bssid_cam->bssid[3]); 633*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_BSSID4(cmd, bssid_cam->bssid[4]); 634*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_BSSID5(cmd, bssid_cam->bssid[5]); 635*8e93258fSBjoern A. Zeeb 636*8e93258fSBjoern A. Zeeb return 0; 637*8e93258fSBjoern A. Zeeb } 638*8e93258fSBjoern A. Zeeb 639*8e93258fSBjoern A. Zeeb static u8 rtw89_cam_addr_hash(u8 start, const u8 *addr) 640*8e93258fSBjoern A. Zeeb { 641*8e93258fSBjoern A. Zeeb u8 hash = 0; 642*8e93258fSBjoern A. Zeeb u8 i; 643*8e93258fSBjoern A. Zeeb 644*8e93258fSBjoern A. Zeeb for (i = start; i < ETH_ALEN; i++) 645*8e93258fSBjoern A. Zeeb hash ^= addr[i]; 646*8e93258fSBjoern A. Zeeb 647*8e93258fSBjoern A. Zeeb return hash; 648*8e93258fSBjoern A. Zeeb } 649*8e93258fSBjoern A. Zeeb 650*8e93258fSBjoern A. Zeeb void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, 651*8e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif, 652*8e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta, 653*8e93258fSBjoern A. Zeeb const u8 *scan_mac_addr, 654*8e93258fSBjoern A. Zeeb u8 *cmd) 655*8e93258fSBjoern A. Zeeb { 656*8e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); 657*8e93258fSBjoern A. Zeeb struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); 658*8e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta); 659*8e93258fSBjoern A. Zeeb const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif->mac_addr; 660*8e93258fSBjoern A. Zeeb u8 sma_hash, tma_hash, addr_msk_start; 661*8e93258fSBjoern A. Zeeb u8 sma_start = 0; 662*8e93258fSBjoern A. Zeeb u8 tma_start = 0; 663*8e93258fSBjoern A. Zeeb u8 *tma = sta ? sta->addr : rtwvif->bssid; 664*8e93258fSBjoern A. Zeeb 665*8e93258fSBjoern A. Zeeb if (addr_cam->addr_mask != 0) { 666*8e93258fSBjoern A. Zeeb addr_msk_start = __ffs(addr_cam->addr_mask); 667*8e93258fSBjoern A. Zeeb if (addr_cam->mask_sel == RTW89_SMA) 668*8e93258fSBjoern A. Zeeb sma_start = addr_msk_start; 669*8e93258fSBjoern A. Zeeb else if (addr_cam->mask_sel == RTW89_TMA) 670*8e93258fSBjoern A. Zeeb tma_start = addr_msk_start; 671*8e93258fSBjoern A. Zeeb } 672*8e93258fSBjoern A. Zeeb sma_hash = rtw89_cam_addr_hash(sma_start, sma); 673*8e93258fSBjoern A. Zeeb tma_hash = rtw89_cam_addr_hash(tma_start, tma); 674*8e93258fSBjoern A. Zeeb 675*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_IDX(cmd, addr_cam->addr_cam_idx); 676*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_OFFSET(cmd, addr_cam->offset); 677*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_LEN(cmd, addr_cam->len); 678*8e93258fSBjoern A. Zeeb 679*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_VALID(cmd, addr_cam->valid); 680*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_NET_TYPE(cmd, rtwvif->net_type); 681*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BCN_HIT_COND(cmd, rtwvif->bcn_hit_cond); 682*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_HIT_RULE(cmd, rtwvif->hit_rule); 683*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BB_SEL(cmd, rtwvif->phy_idx); 684*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_ADDR_MASK(cmd, addr_cam->addr_mask); 685*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_MASK_SEL(cmd, addr_cam->mask_sel); 686*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SMA_HASH(cmd, sma_hash); 687*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_TMA_HASH(cmd, tma_hash); 688*8e93258fSBjoern A. Zeeb 689*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_BSSID_CAM_IDX(cmd, addr_cam->bssid_cam_idx); 690*8e93258fSBjoern A. Zeeb 691*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SMA0(cmd, sma[0]); 692*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SMA1(cmd, sma[1]); 693*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SMA2(cmd, sma[2]); 694*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SMA3(cmd, sma[3]); 695*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SMA4(cmd, sma[4]); 696*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SMA5(cmd, sma[5]); 697*8e93258fSBjoern A. Zeeb 698*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_TMA0(cmd, tma[0]); 699*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_TMA1(cmd, tma[1]); 700*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_TMA2(cmd, tma[2]); 701*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_TMA3(cmd, tma[3]); 702*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_TMA4(cmd, tma[4]); 703*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_TMA5(cmd, tma[5]); 704*8e93258fSBjoern A. Zeeb 705*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif->port); 706*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif->port); 707*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_TF_TRS(cmd, rtwvif->trigger); 708*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif->lsig_txop); 709*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif->tgt_ind); 710*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif->frm_tgt_ind); 711*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_MACID(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id); 712*8e93258fSBjoern A. Zeeb if (rtwvif->net_type == RTW89_NET_TYPE_INFRA) 713*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_AID12(cmd, vif->cfg.aid & 0xfff); 714*8e93258fSBjoern A. Zeeb else if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) 715*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_AID12(cmd, sta ? sta->aid & 0xfff : 0); 716*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif->wowlan_pattern); 717*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif->wowlan_uc); 718*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif->wowlan_magic); 719*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_WAPI(cmd, addr_cam->wapi); 720*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT_MODE(cmd, addr_cam->sec_ent_mode); 721*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT0_KEYID(cmd, addr_cam->sec_ent_keyid[0]); 722*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT1_KEYID(cmd, addr_cam->sec_ent_keyid[1]); 723*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT2_KEYID(cmd, addr_cam->sec_ent_keyid[2]); 724*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT3_KEYID(cmd, addr_cam->sec_ent_keyid[3]); 725*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT4_KEYID(cmd, addr_cam->sec_ent_keyid[4]); 726*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT5_KEYID(cmd, addr_cam->sec_ent_keyid[5]); 727*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT6_KEYID(cmd, addr_cam->sec_ent_keyid[6]); 728*8e93258fSBjoern A. Zeeb 729*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT_VALID(cmd, addr_cam->sec_cam_map[0] & 0xff); 730*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT0(cmd, addr_cam->sec_ent[0]); 731*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT1(cmd, addr_cam->sec_ent[1]); 732*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT2(cmd, addr_cam->sec_ent[2]); 733*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT3(cmd, addr_cam->sec_ent[3]); 734*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT4(cmd, addr_cam->sec_ent[4]); 735*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT5(cmd, addr_cam->sec_ent[5]); 736*8e93258fSBjoern A. Zeeb FWCMD_SET_ADDR_SEC_ENT6(cmd, addr_cam->sec_ent[6]); 737*8e93258fSBjoern A. Zeeb } 738*8e93258fSBjoern A. Zeeb 739*8e93258fSBjoern A. Zeeb void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, 740*8e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif, 741*8e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta, 742*8e93258fSBjoern A. Zeeb u8 *cmd) 743*8e93258fSBjoern A. Zeeb { 744*8e93258fSBjoern A. Zeeb struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); 745*8e93258fSBjoern A. Zeeb 746*8e93258fSBjoern A. Zeeb SET_DCTL_MACID_V1(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id); 747*8e93258fSBjoern A. Zeeb SET_DCTL_OPERATION_V1(cmd, 1); 748*8e93258fSBjoern A. Zeeb 749*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT0_KEYID_V1(cmd, addr_cam->sec_ent_keyid[0]); 750*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT1_KEYID_V1(cmd, addr_cam->sec_ent_keyid[1]); 751*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT2_KEYID_V1(cmd, addr_cam->sec_ent_keyid[2]); 752*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT3_KEYID_V1(cmd, addr_cam->sec_ent_keyid[3]); 753*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT4_KEYID_V1(cmd, addr_cam->sec_ent_keyid[4]); 754*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT5_KEYID_V1(cmd, addr_cam->sec_ent_keyid[5]); 755*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT6_KEYID_V1(cmd, addr_cam->sec_ent_keyid[6]); 756*8e93258fSBjoern A. Zeeb 757*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT_VALID_V1(cmd, addr_cam->sec_cam_map[0] & 0xff); 758*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT0_V1(cmd, addr_cam->sec_ent[0]); 759*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT1_V1(cmd, addr_cam->sec_ent[1]); 760*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT2_V1(cmd, addr_cam->sec_ent[2]); 761*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT3_V1(cmd, addr_cam->sec_ent[3]); 762*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT4_V1(cmd, addr_cam->sec_ent[4]); 763*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT5_V1(cmd, addr_cam->sec_ent[5]); 764*8e93258fSBjoern A. Zeeb SET_DCTL_SEC_ENT6_V1(cmd, addr_cam->sec_ent[6]); 765*8e93258fSBjoern A. Zeeb } 766