322 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2009-2012 Realtek Corporation.*/3 4#include "wifi.h"5#include "cam.h"6#include <linux/export.h>7 8void rtl_cam_reset_sec_info(struct ieee80211_hw *hw)9{10 struct rtl_priv *rtlpriv = rtl_priv(hw);11 12 rtlpriv->sec.use_defaultkey = false;13 rtlpriv->sec.pairwise_enc_algorithm = NO_ENCRYPTION;14 rtlpriv->sec.group_enc_algorithm = NO_ENCRYPTION;15 memset(rtlpriv->sec.key_buf, 0, KEY_BUF_SIZE * MAX_KEY_LEN);16 memset(rtlpriv->sec.key_len, 0, KEY_BUF_SIZE);17 rtlpriv->sec.pairwise_key = NULL;18}19 20static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,21 const u8 *mac_addr, u8 *key_cont_128,22 u16 us_config)23{24 struct rtl_priv *rtlpriv = rtl_priv(hw);25 26 u32 target_command;27 u32 target_content = 0;28 int entry_i;29 30 RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_DMESG, "Key content :",31 key_cont_128, 16);32 33 /* 0-1 config + mac, 2-5 fill 128key,6-7 are reserved */34 for (entry_i = CAM_CONTENT_COUNT - 1; entry_i >= 0; entry_i--) {35 target_command = entry_i + CAM_CONTENT_COUNT * entry_no;36 target_command = target_command | BIT(31) | BIT(16);37 38 if (entry_i == 0) {39 target_content = (u32) (*(mac_addr + 0)) << 16 |40 (u32) (*(mac_addr + 1)) << 24 | (u32) us_config;41 42 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],43 target_content);44 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],45 target_command);46 47 rtl_dbg(rtlpriv, COMP_SEC, DBG_LOUD,48 "WRITE %x: %x\n",49 rtlpriv->cfg->maps[WCAMI], target_content);50 rtl_dbg(rtlpriv, COMP_SEC, DBG_LOUD,51 "The Key ID is %d\n", entry_no);52 rtl_dbg(rtlpriv, COMP_SEC, DBG_LOUD,53 "WRITE %x: %x\n",54 rtlpriv->cfg->maps[RWCAM], target_command);55 56 } else if (entry_i == 1) {57 58 target_content = (u32) (*(mac_addr + 5)) << 24 |59 (u32) (*(mac_addr + 4)) << 16 |60 (u32) (*(mac_addr + 3)) << 8 |61 (u32) (*(mac_addr + 2));62 63 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],64 target_content);65 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],66 target_command);67 68 rtl_dbg(rtlpriv, COMP_SEC, DBG_LOUD,69 "WRITE A4: %x\n", target_content);70 rtl_dbg(rtlpriv, COMP_SEC, DBG_LOUD,71 "WRITE A0: %x\n", target_command);72 73 } else {74 75 target_content =76 (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 3)) <<77 24 | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 2))78 << 16 |79 (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 880 | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 0));81 82 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],83 target_content);84 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],85 target_command);86 87 rtl_dbg(rtlpriv, COMP_SEC, DBG_LOUD,88 "WRITE A4: %x\n", target_content);89 rtl_dbg(rtlpriv, COMP_SEC, DBG_LOUD,90 "WRITE A0: %x\n", target_command);91 }92 }93 94 rtl_dbg(rtlpriv, COMP_SEC, DBG_LOUD,95 "after set key, usconfig:%x\n", us_config);96}97 98u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, const u8 *mac_addr,99 u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,100 u32 ul_default_key, u8 *key_content)101{102 u32 us_config;103 struct rtl_priv *rtlpriv = rtl_priv(hw);104 105 rtl_dbg(rtlpriv, COMP_SEC, DBG_DMESG,106 "EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n",107 ul_entry_idx, ul_key_id, ul_enc_alg,108 ul_default_key, mac_addr);109 110 if (ul_key_id == TOTAL_CAM_ENTRY) {111 rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING,112 "ulKeyId exceed!\n");113 return 0;114 }115 116 if (ul_default_key == 1)117 us_config = CFG_VALID | ((u16) (ul_enc_alg) << 2);118 else119 us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id;120 121 rtl_cam_program_entry(hw, ul_entry_idx, mac_addr,122 (u8 *)key_content, us_config);123 124 rtl_dbg(rtlpriv, COMP_SEC, DBG_DMESG, "end\n");125 126 return 1;127 128}129EXPORT_SYMBOL(rtl_cam_add_one_entry);130 131int rtl_cam_delete_one_entry(struct ieee80211_hw *hw,132 u8 *mac_addr, u32 ul_key_id)133{134 u32 ul_command;135 struct rtl_priv *rtlpriv = rtl_priv(hw);136 137 rtl_dbg(rtlpriv, COMP_SEC, DBG_DMESG, "key_idx:%d\n", ul_key_id);138 139 ul_command = ul_key_id * CAM_CONTENT_COUNT;140 ul_command = ul_command | BIT(31) | BIT(16);141 142 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0);143 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);144 145 rtl_dbg(rtlpriv, COMP_SEC, DBG_DMESG,146 "%s: WRITE A4: %x\n", __func__, 0);147 rtl_dbg(rtlpriv, COMP_SEC, DBG_DMESG,148 "%s: WRITE A0: %x\n", __func__, ul_command);149 150 return 0;151 152}153EXPORT_SYMBOL(rtl_cam_delete_one_entry);154 155void rtl_cam_reset_all_entry(struct ieee80211_hw *hw)156{157 u32 ul_command;158 struct rtl_priv *rtlpriv = rtl_priv(hw);159 160 ul_command = BIT(31) | BIT(30);161 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);162}163EXPORT_SYMBOL(rtl_cam_reset_all_entry);164 165void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index)166{167 struct rtl_priv *rtlpriv = rtl_priv(hw);168 169 u32 ul_command;170 u32 ul_content;171 u32 ul_enc_algo;172 173 switch (rtlpriv->sec.pairwise_enc_algorithm) {174 case WEP40_ENCRYPTION:175 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40];176 break;177 case WEP104_ENCRYPTION:178 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104];179 break;180 case TKIP_ENCRYPTION:181 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP];182 break;183 case AESCCMP_ENCRYPTION:184 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];185 break;186 default:187 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];188 }189 190 ul_content = (uc_index & 3) | ((u16) (ul_enc_algo) << 2);191 192 ul_content |= BIT(15);193 ul_command = CAM_CONTENT_COUNT * uc_index;194 ul_command = ul_command | BIT(31) | BIT(16);195 196 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);197 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);198 199 rtl_dbg(rtlpriv, COMP_SEC, DBG_DMESG,200 "%s: WRITE A4: %x\n", __func__, ul_content);201 rtl_dbg(rtlpriv, COMP_SEC, DBG_DMESG,202 "%s: WRITE A0: %x\n", __func__, ul_command);203}204EXPORT_SYMBOL(rtl_cam_mark_invalid);205 206void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index)207{208 struct rtl_priv *rtlpriv = rtl_priv(hw);209 210 u32 ul_command;211 u32 ul_content;212 u32 ul_encalgo;213 u8 entry_i;214 215 switch (rtlpriv->sec.pairwise_enc_algorithm) {216 case WEP40_ENCRYPTION:217 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40];218 break;219 case WEP104_ENCRYPTION:220 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104];221 break;222 case TKIP_ENCRYPTION:223 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP];224 break;225 case AESCCMP_ENCRYPTION:226 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];227 break;228 default:229 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];230 }231 232 for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {233 234 if (entry_i == 0) {235 ul_content =236 (uc_index & 0x03) | ((u16) (ul_encalgo) << 2);237 ul_content |= BIT(15);238 239 } else {240 ul_content = 0;241 }242 243 ul_command = CAM_CONTENT_COUNT * uc_index + entry_i;244 ul_command = ul_command | BIT(31) | BIT(16);245 246 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);247 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);248 249 rtl_dbg(rtlpriv, COMP_SEC, DBG_LOUD,250 "%s: WRITE A4: %x\n", __func__, ul_content);251 rtl_dbg(rtlpriv, COMP_SEC, DBG_LOUD,252 "%s: WRITE A0: %x\n", __func__, ul_command);253 }254 255}256EXPORT_SYMBOL(rtl_cam_empty_entry);257 258u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr)259{260 struct rtl_priv *rtlpriv = rtl_priv(hw);261 u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4;262 u8 entry_idx = 0;263 u8 i, *addr;264 265 if (NULL == sta_addr) {266 pr_err("sta_addr is NULL.\n");267 return TOTAL_CAM_ENTRY;268 }269 /* Does STA already exist? */270 for (i = 4; i < TOTAL_CAM_ENTRY; i++) {271 addr = rtlpriv->sec.hwsec_cam_sta_addr[i];272 if (ether_addr_equal_unaligned(addr, sta_addr))273 return i;274 }275 /* Get a free CAM entry. */276 for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) {277 if ((bitmap & BIT(0)) == 0) {278 pr_err("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n",279 rtlpriv->sec.hwsec_cam_bitmap, entry_idx);280 rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx;281 memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx],282 sta_addr, ETH_ALEN);283 return entry_idx;284 }285 bitmap = bitmap >> 1;286 }287 return TOTAL_CAM_ENTRY;288}289EXPORT_SYMBOL(rtl_cam_get_free_entry);290 291void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr)292{293 struct rtl_priv *rtlpriv = rtl_priv(hw);294 u32 bitmap;295 u8 i, *addr;296 297 if (NULL == sta_addr) {298 pr_err("sta_addr is NULL.\n");299 return;300 }301 302 if (is_zero_ether_addr(sta_addr)) {303 pr_err("sta_addr is %pM\n", sta_addr);304 return;305 }306 /* Does STA already exist? */307 for (i = 4; i < TOTAL_CAM_ENTRY; i++) {308 addr = rtlpriv->sec.hwsec_cam_sta_addr[i];309 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i;310 if (((bitmap & BIT(0)) == BIT(0)) &&311 (ether_addr_equal_unaligned(addr, sta_addr))) {312 /* Remove from HW Security CAM */313 eth_zero_addr(rtlpriv->sec.hwsec_cam_sta_addr[i]);314 rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i);315 rtl_dbg(rtlpriv, COMP_SEC, DBG_DMESG,316 "&&&&&&&&&del entry %d\n", i);317 }318 }319 return;320}321EXPORT_SYMBOL(rtl_cam_del_entry);322