/****************************************************************************** * * Copyright(c) 2019 Realtek Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * ******************************************************************************/ #include "security_cam.h" #define ADDR_CAM_SECINFO_OFFSET 0x1C #define HW_SUPPORT_ENC_TYPE_NUM 0x0A #define OUTRANGE_KEY_INDEX 0xFF #define NO_MACID_ROLE 0xFF #define VALID 0x01 #define INVALID 0x00 #define FORCE_KEYCAM_INDEX_TYPE 0xF0 struct addr_sec_only_info { u32 dword0; u32 dword1; u32 dword2; }; enum SEC_CAM_KEY_TYPE { SEC_CAM_KEY_TYPE_UNI = 0, SEC_CAM_KEY_TYPE_GROUP = 1, SEC_CAM_KEY_TYPE_BIP = 2, SEC_CAM_KEY_TYPE_DEFAULT = 3 }; enum ADDR_CAM_SEC_MODE { ADDR_CAM_SEC_MODE_ZERO = 0, ADDR_CAM_SEC_MODE_ONE = 1, ADDR_CAM_SEC_MODE_TWO = 2, ADDR_CAM_SEC_MODE_THREE = 3, }; enum HW_SUPPORT_ENC_TYPE { HW_SUPPORT_ENC_TYPE_NONE = 0x0, HW_SUPPORT_ENC_TYPE_WEP40 = 0x1, HW_SUPPORT_ENC_TYPE_WEP104 = 0x2, HW_SUPPORT_ENC_TYPE_TKIP = 0x3, HW_SUPPORT_ENC_TYPE_WAPI = 0x4, HW_SUPPORT_ENC_TYPE_GCMSMS4 = 0x5, HW_SUPPORT_ENC_TYPE_CCMP128 = 0x6, HW_SUPPORT_ENC_TYPE_CCMP256 = 0x7, HW_SUPPORT_ENC_TYPE_GCMP128 = 0x8, HW_SUPPORT_ENC_TYPE_GCMP256 = 0x9, HW_SUPPORT_ENC_TYPE_BIP128 = 0xA, }; u32 sec_info_tbl_init(struct mac_ax_adapter *adapter, u8 op_mode) { u8 i = 0; struct sec_cam_table_t **sec_cam_table; if (op_mode == SEC_CAM_BACKUP) sec_cam_table = &adapter->hw_info->sec_cam_table_bk; else sec_cam_table = &adapter->hw_info->sec_cam_table; /*First time access sec cam , initial sec cam table INVALID */ if ((*sec_cam_table) == NULL) { (*sec_cam_table) = (struct sec_cam_table_t *)PLTFM_MALLOC (sizeof(struct sec_cam_table_t)); if (!(*sec_cam_table)) return MACNOBUF; for (i = 0; i < SEC_CAM_ENTRY_NUM; i++) { (*sec_cam_table)->sec_cam_entry[i] = (struct sec_cam_entry_t *)PLTFM_MALLOC (sizeof(struct sec_cam_entry_t)); if (!(*sec_cam_table)->sec_cam_entry[i]) return MACNOBUF; (*sec_cam_table)->sec_cam_entry[i]->sec_cam_info = (struct mac_ax_sec_cam_info *)PLTFM_MALLOC (sizeof(struct mac_ax_sec_cam_info)); if (!(*sec_cam_table)->sec_cam_entry[i]->sec_cam_info) return MACNOBUF; /* initial value*/ (*sec_cam_table)->sec_cam_entry[i]->valid = INVALID; (*sec_cam_table)->sec_cam_entry[i]->mac_id = 0; (*sec_cam_table)->sec_cam_entry[i]->key_id = 0; (*sec_cam_table)->sec_cam_entry[i]->key_type = 0; } (*sec_cam_table)->next_cam_storage_idx = 0; } return MACSUCCESS; } u32 free_sec_info_tbl(struct mac_ax_adapter *adapter, u8 op_mode) { u8 i; struct sec_cam_table_t *sec_cam_table; if (op_mode == SEC_CAM_RESTORE) sec_cam_table = adapter->hw_info->sec_cam_table_bk; else sec_cam_table = adapter->hw_info->sec_cam_table; if (!sec_cam_table) return MACSUCCESS; for (i = 0; i < SEC_CAM_ENTRY_NUM; i++) { PLTFM_FREE(sec_cam_table->sec_cam_entry[i]->sec_cam_info, sizeof(struct mac_ax_sec_cam_info)); } for (i = 0; i < SEC_CAM_ENTRY_NUM; i++) { PLTFM_FREE(sec_cam_table->sec_cam_entry[i], sizeof(struct sec_cam_entry_t)); } PLTFM_FREE(sec_cam_table, sizeof(struct sec_cam_table_t)); if (op_mode == SEC_CAM_RESTORE) adapter->hw_info->sec_cam_table_bk = NULL; else adapter->hw_info->sec_cam_table = NULL; return MACSUCCESS; } u32 fill_sec_cam_info(struct mac_ax_adapter *adapter, struct mac_ax_sec_cam_info *s_info, struct fwcmd_seccam_info *sec_info, u8 clear) { if (clear == INVALID) { sec_info->dword0 = cpu_to_le32(SET_WORD(s_info->sec_cam_idx, FWCMD_H2C_SECCAM_INFO_IDX) | SET_WORD(s_info->offset, FWCMD_H2C_SECCAM_INFO_OFFSET) | SET_WORD(s_info->len, FWCMD_H2C_SECCAM_INFO_LEN)); sec_info->dword1 = cpu_to_le32(SET_WORD(s_info->type, FWCMD_H2C_SECCAM_INFO_TYPE) | ((s_info->ext_key) ? FWCMD_H2C_SECCAM_INFO_EXT_KEY : 0) | ((s_info->spp_mode) ? FWCMD_H2C_SECCAM_INFO_SPP_MODE : 0)); sec_info->dword2 = s_info->key[0]; sec_info->dword3 = s_info->key[1]; sec_info->dword4 = s_info->key[2]; sec_info->dword5 = s_info->key[3]; } else { sec_info->dword0 = cpu_to_le32(SET_WORD(s_info->sec_cam_idx, FWCMD_H2C_SECCAM_INFO_IDX) | SET_WORD(s_info->offset, FWCMD_H2C_SECCAM_INFO_OFFSET) | SET_WORD(s_info->len, FWCMD_H2C_SECCAM_INFO_LEN)); sec_info->dword1 = 0x0; sec_info->dword2 = 0x0; sec_info->dword3 = 0x0; sec_info->dword4 = 0x0; sec_info->dword5 = 0x0; } return MACSUCCESS; } u32 fill_addr_cam_sec_only(struct mac_ax_adapter *adapter, struct mac_ax_role_info *info, struct addr_sec_only_info *addr_sec_info) { struct mac_ax_addr_cam_info a_info; a_info = info->a_info; addr_sec_info->dword0 = cpu_to_le32((a_info.aid12 & 0xfff) | ((a_info.wol_pattern) ? FWCMD_H2C_ADDRCAM_INFO_WOL_PATTERN : 0) | ((a_info.wol_uc) ? FWCMD_H2C_ADDRCAM_INFO_WOL_UC : 0) | ((a_info.wol_magic) ? FWCMD_H2C_ADDRCAM_INFO_WOL_MAGIC : 0) | ((a_info.wapi) ? FWCMD_H2C_ADDRCAM_INFO_WAPI : 0) | SET_WORD(a_info.sec_ent_mode, FWCMD_H2C_ADDRCAM_INFO_SEC_ENT_MODE) | SET_WORD(a_info.sec_ent_keyid[0], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT0_KEYID) | SET_WORD(a_info.sec_ent_keyid[1], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT1_KEYID) | SET_WORD(a_info.sec_ent_keyid[2], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT2_KEYID) | SET_WORD(a_info.sec_ent_keyid[3], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT3_KEYID) | SET_WORD(a_info.sec_ent_keyid[4], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT4_KEYID) | SET_WORD(a_info.sec_ent_keyid[5], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT5_KEYID) | SET_WORD(a_info.sec_ent_keyid[6], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT6_KEYID)); addr_sec_info->dword1 = cpu_to_le32(SET_WORD(a_info.sec_ent_valid, FWCMD_H2C_ADDRCAM_INFO_SEC_ENT_VALID) | SET_WORD(a_info.sec_ent[0], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT0) | SET_WORD(a_info.sec_ent[1], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT1) | SET_WORD(a_info.sec_ent[2], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT2)); addr_sec_info->dword2 = cpu_to_le32(SET_WORD(a_info.sec_ent[3], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT3) | SET_WORD(a_info.sec_ent[4], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT4) | SET_WORD(a_info.sec_ent[5], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT5) | SET_WORD(a_info.sec_ent[6], FWCMD_H2C_ADDRCAM_INFO_SEC_ENT6)); return MACSUCCESS; } u32 mac_upd_sec_infotbl(struct mac_ax_adapter *adapter, struct fwcmd_seccam_info *info) { u32 ret = 0, s_info_tbl[6], cam_address = 0; u8 *buf, i; #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif struct fwcmd_seccam_info *tbl; struct mac_ax_sec_cam_info *s_info; /*h2c access*/ h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; buf = h2cb_put(h2cb, sizeof(struct fwcmd_seccam_info)); if (!buf) { ret = MACNOBUF; goto fail; } tbl = (struct fwcmd_seccam_info *)buf; tbl->dword0 = info->dword0; tbl->dword1 = info->dword1; tbl->dword2 = info->dword2; tbl->dword3 = info->dword3; tbl->dword4 = info->dword4; tbl->dword5 = info->dword5; if (adapter->sm.fwdl == MAC_AX_FWDL_INIT_RDY) { ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_SEC_CAM, FWCMD_H2C_FUNC_SECCAM_INFO, 0, 1); if (ret != MACSUCCESS) goto fail; // return MACSUCCESS if h2c aggregation is enabled and enqueued successfully. // H2C shall be sent by mac_h2c_agg_tx. ret = h2c_agg_enqueue(adapter, h2cb); if (ret == MACSUCCESS) return MACSUCCESS; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret != MACSUCCESS) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret != MACSUCCESS) goto fail; h2cb_free(adapter, h2cb); return MACSUCCESS; fail: h2cb_free(adapter, h2cb); } else { /* Indirect Access */ s_info = (struct mac_ax_sec_cam_info *)info; s_info_tbl[0] = info->dword0; s_info_tbl[1] = info->dword1; s_info_tbl[2] = info->dword2; s_info_tbl[3] = info->dword3; s_info_tbl[4] = info->dword4; s_info_tbl[5] = info->dword5; /* Indirect write security cam */ PLTFM_MSG_WARN("%s ind access start\n", __func__); cam_address = s_info->sec_cam_idx * SEC_CAM_ENTRY_SIZE; for (i = 0; i < 5; i++) mac_sram_dbg_write(adapter, cam_address + (i * 4), cpu_to_le32(s_info_tbl[i + 1]), SEC_CAM_SEL); PLTFM_MSG_WARN("%s ind access end\n", __func__); return MACSUCCESS; } return ret; } u8 check_key_index(u8 addr_cam_sec_mode, u8 key_type, u8 key_index) { switch (addr_cam_sec_mode) { case ADDR_CAM_SEC_MODE_ZERO: switch (key_type) { case SEC_CAM_KEY_TYPE_UNI: if (key_index <= 6) return MACSUCCESS; default: break; } break; case ADDR_CAM_SEC_MODE_ONE: switch (key_type) { case SEC_CAM_KEY_TYPE_UNI: if (key_index <= 6) return MACSUCCESS; default: break; } break; case ADDR_CAM_SEC_MODE_TWO: switch (key_type) { case SEC_CAM_KEY_TYPE_UNI: if (key_index <= 1) return MACSUCCESS; break; case SEC_CAM_KEY_TYPE_GROUP: if (key_index >= 2 && key_index <= 4) return MACSUCCESS; break; case SEC_CAM_KEY_TYPE_BIP: if (key_index >= 5 && key_index <= 6) return MACSUCCESS; break; default: break; } break; case ADDR_CAM_SEC_MODE_THREE: switch (key_type) { case SEC_CAM_KEY_TYPE_UNI: if (key_index <= 1) return MACSUCCESS; break; case SEC_CAM_KEY_TYPE_GROUP: if (key_index >= 2 && key_index <= 5) return MACSUCCESS; break; case SEC_CAM_KEY_TYPE_BIP: if (key_index == 6) return MACSUCCESS; break; default: break; } break; } return 1; } u8 decide_key_index(u8 addr_cam_sec_mode, u8 key_type) { u8 key_index = 0; switch (addr_cam_sec_mode) { case ADDR_CAM_SEC_MODE_ZERO: if (key_type == SEC_CAM_KEY_TYPE_UNI) key_index = 0; else if (key_type == SEC_CAM_KEY_TYPE_GROUP) return MACWNGKEYTYPE; else if (key_type == SEC_CAM_KEY_TYPE_BIP) return MACWNGKEYTYPE; break; case ADDR_CAM_SEC_MODE_ONE: if (key_type == SEC_CAM_KEY_TYPE_UNI) key_index = 0; else if (key_type == SEC_CAM_KEY_TYPE_GROUP) return MACWNGKEYTYPE; else if (key_type == SEC_CAM_KEY_TYPE_BIP) return MACWNGKEYTYPE; break; case ADDR_CAM_SEC_MODE_TWO: if (key_type == SEC_CAM_KEY_TYPE_UNI) key_index = 0; else if (key_type == SEC_CAM_KEY_TYPE_GROUP) key_index = 2; else if (key_type == SEC_CAM_KEY_TYPE_BIP) key_index = 5; break; case ADDR_CAM_SEC_MODE_THREE: if (key_type == SEC_CAM_KEY_TYPE_UNI) key_index = 0; else if (key_type == SEC_CAM_KEY_TYPE_GROUP) key_index = 2; else if (key_type == SEC_CAM_KEY_TYPE_BIP) key_index = 6; break; default: break; } return key_index; } u8 decide_sec_cam_index(struct mac_ax_adapter *adapter, u8 *sec_cam_idx) { u8 sec_idx = 0, i = 0; /* call by pointer */ struct sec_cam_table_t **sec_cam_table = &adapter->hw_info->sec_cam_table; /*First time access sec cam , initial sec cam table INVALID */ if ((*sec_cam_table) == NULL) { (*sec_cam_table) = (struct sec_cam_table_t *)PLTFM_MALLOC (sizeof(struct sec_cam_table_t)); if (!(*sec_cam_table)) return MACNOBUF; for (i = 0; i < SEC_CAM_ENTRY_NUM; i++) { (*sec_cam_table)->sec_cam_entry[i] = (struct sec_cam_entry_t *)PLTFM_MALLOC (sizeof(struct sec_cam_entry_t)); if (!(*sec_cam_table)->sec_cam_entry[i]) return MACNOBUF; (*sec_cam_table)->sec_cam_entry[i]->sec_cam_info = (struct mac_ax_sec_cam_info *)PLTFM_MALLOC (sizeof(struct mac_ax_sec_cam_info)); if (!(*sec_cam_table)->sec_cam_entry[i]->sec_cam_info) return MACNOBUF; /* initial value*/ (*sec_cam_table)->sec_cam_entry[i]->valid = INVALID; (*sec_cam_table)->sec_cam_entry[i]->mac_id = 0; (*sec_cam_table)->sec_cam_entry[i]->key_id = 0; (*sec_cam_table)->sec_cam_entry[i]->key_type = 0; } (*sec_cam_table)->next_cam_storage_idx = 0; } /*If table has been initialize, assgin the sec cam storge idx */ sec_idx = (*sec_cam_table)->next_cam_storage_idx; for (i = 0; i < SEC_CAM_ENTRY_NUM; i++) { if ((*sec_cam_table)->sec_cam_entry[sec_idx]->valid == INVALID) { (*sec_cam_table)->next_cam_storage_idx = (sec_idx + 1) % SEC_CAM_ENTRY_NUM; *sec_cam_idx = sec_idx; return MACSUCCESS; } sec_idx++; sec_idx %= SEC_CAM_ENTRY_NUM; } return MACSECCAMFL; } u8 delete_key_from_addr_cam(struct mac_ax_adapter *adapter, struct mac_role_tbl *role, u8 key_type, u8 key_id, u8 *sec_cam_idx) { u32 ret = 0; u8 key_index = 0, key_valid_byte = 0, i = 0; u8 key_valid[7] = {0}, hit_flag = 0; key_valid_byte = role->info.a_info.sec_ent_valid; key_index = decide_key_index(role->info.a_info.sec_ent_mode, key_type); if (key_index == MACWNGKEYTYPE) return MACWNGKEYTYPE; for (i = 0; i < 7; i++) { key_valid[i] = key_valid_byte % 2; key_valid_byte = key_valid_byte >> 1; } /* find the key real storage idx */ for (i = key_index; i < 7; i++) { if (role->info.a_info.sec_ent_keyid[i] == key_id && key_valid[i] == VALID) { key_index = i; hit_flag = 1; break; } } if (hit_flag == 0) return MACKEYNOTEXT; if (check_key_index(role->info.a_info.sec_ent_mode, key_type, key_index)) { PLTFM_MSG_TRACE("check addr key index full\n"); return MACADDRCAMKEYFL; } /*get the key cam index*/ *sec_cam_idx = role->info.a_info.sec_ent[key_index]; role->info.a_info.sec_ent_keyid[key_index] = 0; role->info.a_info.sec_ent_valid &= ~(BIT(key_index)); role->info.a_info.sec_ent[key_index] = 0; /* update addr cam */ ret = mac_upd_addr_cam(adapter, &role->info, CHG); if (ret == MACBSSIDCAMFL) { PLTFM_MSG_ERR("[ERR]: BSSID CAM full\n"); return MACBSSIDCAMFL; } return MACSUCCESS; } u8 insert_key_to_addr_cam(struct mac_ax_adapter *adapter, struct mac_role_tbl *role, u8 key_type, u8 key_id, u8 sec_cam_idx) { u32 ret = 0; u8 key_index = 0, key_valid_byte = 0, i = 0; u8 key_valid[7] = {0}, hit_flag = 0; key_valid_byte = role->info.a_info.sec_ent_valid; key_index = decide_key_index(role->info.a_info.sec_ent_mode, key_type); if (key_index == MACWNGKEYTYPE) return MACWNGKEYTYPE; for (i = 0; i < 7; i++) { key_valid[i] = key_valid_byte % 2; key_valid_byte = key_valid_byte >> 1; } /* find the key real storage idx */ for (i = key_index; i < 7; i++) { if (key_valid[i] != VALID) { key_index = i; hit_flag = 1; break; } } if (hit_flag == 0) return MACADDRCAMKEYFL; if (check_key_index(role->info.a_info.sec_ent_mode, key_type, key_index)) { PLTFM_MSG_TRACE("check addr key index full\n"); return MACADDRCAMKEYFL; } role->info.a_info.sec_ent_keyid[key_index] = key_id; role->info.a_info.sec_ent_valid |= BIT(key_index); role->info.a_info.sec_ent[key_index] = sec_cam_idx; ret = mac_upd_addr_cam(adapter, &role->info, CHG); if (ret == MACBSSIDCAMFL) { PLTFM_MSG_ERR("[ERR]: BSSID CAM full\n"); return MACBSSIDCAMFL; } return MACSUCCESS; } u32 m_security_cam_hal(struct mac_ax_adapter *adapter, struct mac_ax_sec_cam_info *sec_cam_info, u8 mac_id, u8 key_id, u8 key_type, u8 sec_cam_idx, u8 opmode) { u8 i = 0; struct sec_cam_entry_t *sec_cam_entry = NULL; struct sec_cam_entry_t *sec_cam_bk_entry = NULL; struct sec_cam_table_t *sec_cam_table = adapter->hw_info->sec_cam_table; struct sec_cam_table_t *sec_cam_table_bk = adapter->hw_info->sec_cam_table_bk; if (!sec_cam_table) return MACSUCCESS; sec_cam_entry = adapter->hw_info->sec_cam_table->sec_cam_entry[sec_cam_idx]; if (opmode == SEC_CAM_CLEAR) { sec_cam_entry->valid = INVALID; sec_cam_entry->mac_id = 0; sec_cam_entry->key_id = 0; sec_cam_entry->key_type = 0; sec_cam_entry->sec_cam_info->type = 0; sec_cam_entry->sec_cam_info->ext_key = 0; sec_cam_entry->sec_cam_info->spp_mode = 0; for (i = 0; i < 3; i++) sec_cam_entry->sec_cam_info->key[i] = 0; } else if (opmode == SEC_CAM_BACKUP) { if (!sec_cam_table_bk) return MACSUCCESS; sec_cam_bk_entry = adapter->hw_info->sec_cam_table_bk ->sec_cam_entry[sec_cam_idx]; // backup security entry in halmac sec_cam_bk_entry->valid = sec_cam_entry->valid; sec_cam_bk_entry->mac_id = sec_cam_entry->mac_id; sec_cam_bk_entry->key_id = sec_cam_entry->key_id; sec_cam_bk_entry->key_type = sec_cam_entry->key_type; sec_cam_bk_entry->sec_cam_info->type = sec_cam_entry->sec_cam_info->type; sec_cam_bk_entry->sec_cam_info->ext_key = sec_cam_entry->sec_cam_info->ext_key; sec_cam_bk_entry->sec_cam_info->spp_mode = sec_cam_entry->sec_cam_info->spp_mode; for (i = 0; i < 4; i++) sec_cam_bk_entry->sec_cam_info->key[i] = sec_cam_entry->sec_cam_info->key[i]; } else { if (!sec_cam_info) { sec_cam_entry->valid = VALID; sec_cam_entry->mac_id = mac_id; sec_cam_entry->key_id = key_id; sec_cam_entry->key_type = key_type; sec_cam_entry->sec_cam_info->type = 0x0; sec_cam_entry->sec_cam_info->ext_key = 0x0; sec_cam_entry->sec_cam_info->spp_mode = 0x0; for (i = 0; i < 4; i++) sec_cam_entry->sec_cam_info->key[i] = 0x0; } else { sec_cam_entry->valid = VALID; sec_cam_entry->mac_id = mac_id; sec_cam_entry->key_id = key_id; sec_cam_entry->key_type = key_type; sec_cam_entry->sec_cam_info->type = sec_cam_info->type; sec_cam_entry->sec_cam_info->ext_key = sec_cam_info->ext_key; sec_cam_entry->sec_cam_info->spp_mode = sec_cam_info->spp_mode; for (i = 0; i < 4; i++) sec_cam_entry->sec_cam_info->key[i] = sec_cam_info->key[i]; } } return MACSUCCESS; } u32 disconnect_flush_key(struct mac_ax_adapter *adapter, struct mac_role_tbl *role) { struct mac_ax_sec_cam_info *sec_cam_info = NULL; u8 i, sec_ent_valid, mac_id, key_type, key_index; u8 key_valid[7] = {0}, sec_cam_index[7] = {0}, sec_ent_keyid[7] = {0}; sec_ent_valid = role->info.a_info.sec_ent_valid; mac_id = role->info.a_info.sec_ent_valid; for (i = 0; i < 7; i++) { key_valid[i] = sec_ent_valid % 2; sec_ent_valid = sec_ent_valid >> 1; sec_cam_index[i] = role->info.a_info.sec_ent[i]; sec_ent_keyid[i] = role->info.a_info.sec_ent_keyid[i]; } key_type = SEC_CAM_KEY_TYPE_DEFAULT; for (key_index = 0; key_index < 7; key_index++) { if (key_valid[key_index] == VALID) { m_security_cam_hal(adapter, sec_cam_info, mac_id, sec_ent_keyid[key_index], key_type, sec_cam_index[key_index], SEC_CAM_CLEAR); } } return MACSUCCESS; } u32 mac_sta_del_key(struct mac_ax_adapter *adapter, u8 mac_id, u8 key_id, u8 key_type) { struct mac_ax_sec_cam_info sec_cam_info; struct mac_role_tbl *role = NULL; u8 sec_cam_idx = 0; u32 sec_table[6] = {0}, ret = 0; role = mac_role_srch(adapter, mac_id); if (!role) return MACNOROLE; ret = delete_key_from_addr_cam(adapter, role, key_type, key_id, &sec_cam_idx); if (ret != MACSUCCESS) return ret; sec_cam_info.sec_cam_idx = sec_cam_idx; sec_cam_info.offset = 0x00; sec_cam_info.len = SEC_CAM_ENTRY_SIZE; fill_sec_cam_info(adapter, &sec_cam_info, (struct fwcmd_seccam_info *)sec_table, 1); ret = (u8)mac_upd_sec_infotbl(adapter, (struct fwcmd_seccam_info *)sec_table); if (ret != MACSUCCESS) return ret; m_security_cam_hal(adapter, NULL, mac_id, key_id, key_type, sec_cam_idx, SEC_CAM_CLEAR); return MACSUCCESS; } u32 mac_sta_add_key(struct mac_ax_adapter *adapter, struct mac_ax_sec_cam_info *sec_cam_info, u8 mac_id, u8 key_id, u8 key_type) { u8 sec_cam_idx = 0; u32 sec_table[6] = {0}, ret = 0; struct mac_role_tbl *role = NULL; if (sec_cam_info->type > HW_SUPPORT_ENC_TYPE_NUM) return MACWNGKEYTYPE; role = mac_role_srch(adapter, mac_id); if (!role) return MACNOROLE; if (sec_cam_info->offset != FORCE_KEYCAM_INDEX_TYPE) { ret = decide_sec_cam_index(adapter, &sec_cam_idx); if (ret != MACSUCCESS) return ret; } else { sec_cam_idx = sec_cam_info->sec_cam_idx; } sec_cam_info->sec_cam_idx = sec_cam_idx; sec_cam_info->offset = 0x00; sec_cam_info->len = SEC_CAM_ENTRY_SIZE; ret = insert_key_to_addr_cam(adapter, role, key_type, key_id, sec_cam_info->sec_cam_idx); if (ret != MACSUCCESS) return ret; fill_sec_cam_info(adapter, sec_cam_info, (struct fwcmd_seccam_info *)sec_table, 0); ret = (u8)mac_upd_sec_infotbl(adapter, (struct fwcmd_seccam_info *)sec_table); if (ret != MACSUCCESS) return ret; m_security_cam_hal(adapter, sec_cam_info, mac_id, key_id, key_type, sec_cam_idx, SEC_CAM_NORMAL); return MACSUCCESS; } u32 mac_sta_keycam_backup(struct mac_ax_adapter *adapter, u8 op_mode) { u8 sec_cam_idx = 0, i = 0; u32 ret = 0; struct sec_cam_entry_t *s_entry = NULL; struct mac_ax_sec_cam_info sec_cam_info; struct sec_cam_table_t *sec_cam_table = adapter->hw_info->sec_cam_table; struct sec_cam_table_t *sec_cam_table_bk = adapter->hw_info->sec_cam_table_bk; if (op_mode > SEC_CAM_RESTORE) return MACNOITEM; if (op_mode == SEC_CAM_BACKUP) { /*Initial backup sec cam table */ ret = sec_info_tbl_init(adapter, SEC_CAM_BACKUP); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]sec info tbl backup %d\n", ret); return ret; } /*Backup sec cam table valid entry*/ for (sec_cam_idx = 0; sec_cam_idx < SEC_CAM_ENTRY_NUM; sec_cam_idx++) { /* Only search valid entry */ if (sec_cam_table->sec_cam_entry[sec_cam_idx]->valid == VALID) { m_security_cam_hal(adapter, NULL, 0, 0, 0, sec_cam_idx, SEC_CAM_BACKUP); } } ret = free_sec_info_tbl(adapter, SEC_CAM_NORMAL); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]sec info tbl backup %d\n", ret); return ret; } } else if (op_mode == SEC_CAM_RESTORE) { ret = sec_info_tbl_init(adapter, SEC_CAM_NORMAL); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]sec info tbl backup %d\n", ret); return ret; } /*Force sec cam table */ for (sec_cam_idx = 0; sec_cam_idx < SEC_CAM_ENTRY_NUM; sec_cam_idx++) { s_entry = sec_cam_table_bk->sec_cam_entry[sec_cam_idx]; PLTFM_MSG_ERR("sec_cam_idx %d\n", sec_cam_idx); /* Only search valid entry */ if (s_entry->valid == VALID) { sec_cam_info.offset = FORCE_KEYCAM_INDEX_TYPE; sec_cam_info.sec_cam_idx = sec_cam_idx; sec_cam_info.type = s_entry->sec_cam_info->type; sec_cam_info.ext_key = s_entry->sec_cam_info->ext_key; sec_cam_info.spp_mode = s_entry->sec_cam_info->spp_mode; for (i = 0; i < 4; i++) { sec_cam_info.key[i] = s_entry->sec_cam_info->key[i]; } mac_sta_add_key(adapter, &sec_cam_info, s_entry->mac_id, s_entry->key_id, s_entry->key_type); } } /*Free backup sec cam table */ ret = free_sec_info_tbl(adapter, SEC_CAM_RESTORE); if (ret != MACSUCCESS) { PLTFM_MSG_ERR("[ERR]sec info tbl backup %d\n", ret); return ret; } } else { return MACNOITEM; } return MACSUCCESS; } u32 mac_sta_search_key_idx(struct mac_ax_adapter *adapter, u8 mac_id, u8 key_id, u8 key_type) { u32 sec_cam_idx = 0; struct sec_cam_entry_t *s_entry = NULL; struct sec_cam_table_t *sec_cam_table = adapter->hw_info->sec_cam_table; if (!sec_cam_table) return MACNOKEYINDEX; /*Search SEC CAM Table */ for (sec_cam_idx = 0; sec_cam_idx < SEC_CAM_ENTRY_NUM; sec_cam_idx++) { /* Only search valid entry */ if (sec_cam_table->sec_cam_entry[sec_cam_idx]->valid == VALID) { s_entry = sec_cam_table->sec_cam_entry[sec_cam_idx]; if (s_entry->mac_id != mac_id) continue; if (s_entry->key_id != key_id) continue; if (s_entry->key_type != key_type) continue; return sec_cam_idx; } } return MACNOKEYINDEX; } u32 mac_sta_hw_security_support(struct mac_ax_adapter *adapter, u8 hw_security_support_type, u8 enable) { u32 val32 = 0; struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter); switch (enable) { case 1: val32 = MAC_REG_R32(R_AX_SEC_ENG_CTRL); switch (hw_security_support_type) { case SEC_TX_ENC: val32 |= B_AX_SEC_TX_ENC; break; case SEC_RX_ENC: val32 |= B_AX_SEC_RX_DEC; break; case SEC_BC_ENC: val32 |= B_AX_BC_DEC; break; case SEC_MC_ENC: val32 |= B_AX_MC_DEC; break; case SEC_UC_MGNT_ENC: val32 |= B_AX_UC_MGNT_DEC; break; case SEC_BMC_MGNT_ENC: val32 |= B_AX_BMC_MGNT_DEC; break; default: break; } MAC_REG_W32(R_AX_SEC_ENG_CTRL, val32); break; case 0: val32 = MAC_REG_R32(R_AX_SEC_ENG_CTRL); switch (hw_security_support_type) { case SEC_TX_ENC: val32 &= ~B_AX_SEC_TX_ENC; break; case SEC_RX_ENC: val32 &= ~B_AX_SEC_RX_DEC; break; case SEC_BC_ENC: val32 &= ~B_AX_BC_DEC; break; case SEC_MC_ENC: val32 &= ~B_AX_MC_DEC; break; case SEC_UC_MGNT_ENC: val32 &= ~B_AX_UC_MGNT_DEC; break; case SEC_BMC_MGNT_ENC: val32 &= ~B_AX_BMC_MGNT_DEC; break; default: break; } MAC_REG_W32(R_AX_SEC_ENG_CTRL, val32); break; default: break; } return MACSUCCESS; } u8 check_key_type(u8 addr_cam_sec_mode, u8 key_index) { switch (addr_cam_sec_mode) { case ADDR_CAM_SEC_MODE_ZERO: if (key_index <= 6) return SEC_CAM_KEY_TYPE_UNI; break; case ADDR_CAM_SEC_MODE_ONE: if (key_index <= 6) return SEC_CAM_KEY_TYPE_UNI; break; case ADDR_CAM_SEC_MODE_TWO: if (key_index <= 1) return SEC_CAM_KEY_TYPE_UNI; else if (key_index >= 2 && key_index <= 4) return SEC_CAM_KEY_TYPE_GROUP; else if (key_index >= 5 && key_index <= 6) return SEC_CAM_KEY_TYPE_BIP; else break; break; case ADDR_CAM_SEC_MODE_THREE: if (key_index <= 1) return SEC_CAM_KEY_TYPE_UNI; else if (key_index >= 2 && key_index <= 5) return SEC_CAM_KEY_TYPE_GROUP; else if (key_index == 6) return SEC_CAM_KEY_TYPE_BIP; else break; break; } return MACKEYNOTEXT; } u32 refresh_security_cam_info(struct mac_ax_adapter *adapter, u8 mac_id) { u32 addr_idx = 0, cam_address = 0; u32 i = 0; u8 key_valid[7] = {0}, key_cam_index[7] = {0}, sec_ent_keyid[7] = {0}; u8 macid = 0, hit_flag = VALID, key_id_sh = 0, key_cam_idx_sh = 0; u8 key_valid_byte = 0, key_valid_byte_ori = 0, key_type = 0; u8 key_index = 0, sec_ent_mode = 0, sec_cam_idx = 0; u32 dword[10] = {0}; u8 addr_cam_size = get_addr_cam_size(adapter); struct sec_cam_entry_t *s_entry = NULL; struct sec_cam_table_t *sec_cam_table = adapter->hw_info->sec_cam_table; struct mac_role_tbl *role = NULL; /*read HW key in address cam */ for (addr_idx = 0; addr_idx < 0x80; addr_idx++) { hit_flag = INVALID; PLTFM_MSG_WARN("%s ind access macid %d start\n", __func__, mac_id); cam_address = addr_idx * addr_cam_size; for (i = 0; i < 10; i++) dword[i] = mac_sram_dbg_read(adapter, cam_address, ADDR_CAM_SEL); PLTFM_MSG_WARN("%s ind access macid %d end\n", __func__, mac_id); if ((dword[0] & ADDRCAM_VALID) == VALID) { macid = (dword[6] & ADDRCAM_MACID_MSK); if (macid == mac_id) { sec_ent_mode = (dword[7] >> ADDRCAM_SEC_MODE_SH) & ADDRCAM_SECMODE_MSK; key_id_sh = ADDRCAM_SEC_ENT0_KEYID_SH; for (i = 0; i < 7; i++) { sec_ent_keyid[i] = (dword[7] >> key_id_sh) & ADDRCAM_KEYID_MSK; key_id_sh += 2; } key_valid_byte = dword[8] & ADDRCAM_KEY_VALID_MSK; key_valid_byte_ori = key_valid_byte; for (i = 0; i < 7; i++) { key_valid[i] = key_valid_byte % 2; key_valid_byte = key_valid_byte >> 1; } key_cam_idx_sh = 0; for (i = 0; i < 3; i++) { key_cam_idx_sh = (i + 1) * 8; key_cam_index[i] = (dword[8] >> key_cam_idx_sh) & ADDRCAM_KEY_CAM_IDX_MSK; } key_cam_idx_sh = 0; for (i = 3; i < 7; i++) { key_cam_idx_sh = (i - 3) * 8; key_cam_index[i] = (dword[9] >> key_cam_idx_sh) & ADDRCAM_KEY_CAM_IDX_MSK; } hit_flag = VALID; break; } } } if (hit_flag == INVALID) { PLTFM_MSG_TRACE("MACID : %d not exist\n", mac_id); return MACNOROLE; } // clear halmac table for (sec_cam_idx = 0; sec_cam_idx < SEC_CAM_ENTRY_NUM; sec_cam_idx++) { // Only search valid entry if (sec_cam_table->sec_cam_entry[sec_cam_idx]->valid == VALID) { s_entry = sec_cam_table->sec_cam_entry[sec_cam_idx]; if (s_entry->mac_id == mac_id) { m_security_cam_hal(adapter, NULL, mac_id, DEFAULT_KEYID, DEFAULT_KEYTYPE, sec_cam_idx, SEC_CAM_CLEAR); } } } // insert halmac table for (key_index = 0; key_index < 7; key_index++) { if (key_valid[key_index] == VALID) { key_type = check_key_type(sec_ent_mode, key_index); m_security_cam_hal(adapter, NULL, mac_id, sec_ent_keyid[key_index], key_type, key_cam_index[key_index], SEC_CAM_NORMAL); } } // write back to address cam sec part role = mac_role_srch(adapter, mac_id); if (!role) return MACNOROLE; role->info.a_info.sec_ent_valid = key_valid_byte_ori; for (i = 0; i < 7; i++) { role->info.a_info.sec_ent_keyid[i] = sec_ent_keyid[i]; role->info.a_info.sec_ent[i] = key_cam_index[i]; } return MACSUCCESS; }