1/****************************************************************************** 2 * 3 * Copyright(c) 2009-2012 Realtek Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 17 * 18 * The full GNU General Public License is included in this distribution in the 19 * file called LICENSE. 20 * 21 * Contact Information: 22 * wlanfae <wlanfae@realtek.com> 23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, 24 * Hsinchu 300, Taiwan. 25 * 26 * Larry Finger <Larry.Finger@lwfinger.net> 27 * 28 *****************************************************************************/ 29 30#include <linux/export.h> 31#include "wifi.h" 32#include "cam.h" 33 34void rtl_cam_reset_sec_info(struct ieee80211_hw *hw) 35{ 36 struct rtl_priv *rtlpriv = rtl_priv(hw); 37 38 rtlpriv->sec.use_defaultkey = false; 39 rtlpriv->sec.pairwise_enc_algorithm = NO_ENCRYPTION; 40 rtlpriv->sec.group_enc_algorithm = NO_ENCRYPTION; 41 memset(rtlpriv->sec.key_buf, 0, KEY_BUF_SIZE * MAX_KEY_LEN); 42 memset(rtlpriv->sec.key_len, 0, KEY_BUF_SIZE); 43 rtlpriv->sec.pairwise_key = NULL; 44} 45 46static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, 47 u8 *mac_addr, u8 *key_cont_128, u16 us_config) 48{ 49 struct rtl_priv *rtlpriv = rtl_priv(hw); 50 51 u32 target_command; 52 u32 target_content = 0; 53 u8 entry_i; 54 55 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, 56 "key_cont_128:\n %x:%x:%x:%x:%x:%x\n", 57 key_cont_128[0], key_cont_128[1], 58 key_cont_128[2], key_cont_128[3], 59 key_cont_128[4], key_cont_128[5]); 60 61 for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { 62 target_command = entry_i + CAM_CONTENT_COUNT * entry_no; 63 target_command = target_command | BIT(31) | BIT(16); 64 65 if (entry_i == 0) { 66 target_content = (u32) (*(mac_addr + 0)) << 16 | 67 (u32) (*(mac_addr + 1)) << 24 | (u32) us_config; 68 69 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 70 target_content); 71 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], 72 target_command); 73 74 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE %x: %x\n", 75 rtlpriv->cfg->maps[WCAMI], target_content); 76 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, 77 "The Key ID is %d\n", entry_no); 78 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE %x: %x\n", 79 rtlpriv->cfg->maps[RWCAM], target_command); 80 81 } else if (entry_i == 1) { 82 83 target_content = (u32) (*(mac_addr + 5)) << 24 | 84 (u32) (*(mac_addr + 4)) << 16 | 85 (u32) (*(mac_addr + 3)) << 8 | 86 (u32) (*(mac_addr + 2)); 87 88 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 89 target_content); 90 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], 91 target_command); 92 93 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A4: %x\n", 94 target_content); 95 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A0: %x\n", 96 target_command); 97 98 } else { 99 100 target_content = 101 (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 3)) << 102 24 | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 2)) 103 << 16 | 104 (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 8 105 | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 0)); 106 107 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 108 target_content); 109 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], 110 target_command); 111 udelay(100); 112 113 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A4: %x\n", 114 target_content); 115 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A0: %x\n", 116 target_command); 117 } 118 } 119 120 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "after set key, usconfig:%x\n", 121 us_config); 122} 123 124u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, 125 u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg, 126 u32 ul_default_key, u8 *key_content) 127{ 128 u32 us_config; 129 struct rtl_priv *rtlpriv = rtl_priv(hw); 130 131 RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, 132 "EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n", 133 ul_entry_idx, ul_key_id, ul_enc_alg, 134 ul_default_key, mac_addr); 135 136 if (ul_key_id == TOTAL_CAM_ENTRY) { 137 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 138 "<=== ulKeyId exceed!\n"); 139 return 0; 140 } 141 142 if (ul_default_key == 1) { 143 us_config = CFG_VALID | ((u16) (ul_enc_alg) << 2); 144 } else { 145 us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id; 146 } 147 148 rtl_cam_program_entry(hw, ul_entry_idx, mac_addr, 149 (u8 *) key_content, us_config); 150 151 RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "<===\n"); 152 153 return 1; 154 155} 156EXPORT_SYMBOL(rtl_cam_add_one_entry); 157 158int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, 159 u8 *mac_addr, u32 ul_key_id) 160{ 161 u32 ul_command; 162 struct rtl_priv *rtlpriv = rtl_priv(hw); 163 164 RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "key_idx:%d\n", ul_key_id); 165 166 ul_command = ul_key_id * CAM_CONTENT_COUNT; 167 ul_command = ul_command | BIT(31) | BIT(16); 168 169 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0); 170 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); 171 172 RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, 173 "rtl_cam_delete_one_entry(): WRITE A4: %x\n", 0); 174 RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, 175 "rtl_cam_delete_one_entry(): WRITE A0: %x\n", ul_command); 176 177 return 0; 178 179} 180EXPORT_SYMBOL(rtl_cam_delete_one_entry); 181 182void rtl_cam_reset_all_entry(struct ieee80211_hw *hw) 183{ 184 u32 ul_command; 185 struct rtl_priv *rtlpriv = rtl_priv(hw); 186 187 ul_command = BIT(31) | BIT(30); 188 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); 189} 190EXPORT_SYMBOL(rtl_cam_reset_all_entry); 191 192void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index) 193{ 194 struct rtl_priv *rtlpriv = rtl_priv(hw); 195 196 u32 ul_command; 197 u32 ul_content; 198 u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; 199 200 switch (rtlpriv->sec.pairwise_enc_algorithm) { 201 case WEP40_ENCRYPTION: 202 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40]; 203 break; 204 case WEP104_ENCRYPTION: 205 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104]; 206 break; 207 case TKIP_ENCRYPTION: 208 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP]; 209 break; 210 case AESCCMP_ENCRYPTION: 211 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; 212 break; 213 default: 214 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; 215 } 216 217 ul_content = (uc_index & 3) | ((u16) (ul_enc_algo) << 2); 218 219 ul_content |= BIT(15); 220 ul_command = CAM_CONTENT_COUNT * uc_index; 221 ul_command = ul_command | BIT(31) | BIT(16); 222 223 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content); 224 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); 225 226 RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, 227 "rtl_cam_mark_invalid(): WRITE A4: %x\n", ul_content); 228 RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, 229 "rtl_cam_mark_invalid(): WRITE A0: %x\n", ul_command); 230} 231EXPORT_SYMBOL(rtl_cam_mark_invalid); 232 233void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index) 234{ 235 struct rtl_priv *rtlpriv = rtl_priv(hw); 236 237 u32 ul_command; 238 u32 ul_content; 239 u32 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; 240 u8 entry_i; 241 242 switch (rtlpriv->sec.pairwise_enc_algorithm) { 243 case WEP40_ENCRYPTION: 244 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40]; 245 break; 246 case WEP104_ENCRYPTION: 247 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104]; 248 break; 249 case TKIP_ENCRYPTION: 250 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP]; 251 break; 252 case AESCCMP_ENCRYPTION: 253 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; 254 break; 255 default: 256 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES]; 257 } 258 259 for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) { 260 261 if (entry_i == 0) { 262 ul_content = 263 (uc_index & 0x03) | ((u16) (ul_encalgo) << 2); 264 ul_content |= BIT(15); 265 266 } else { 267 ul_content = 0; 268 } 269 270 ul_command = CAM_CONTENT_COUNT * uc_index + entry_i; 271 ul_command = ul_command | BIT(31) | BIT(16); 272 273 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content); 274 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command); 275 276 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, 277 "rtl_cam_empty_entry(): WRITE A4: %x\n", 278 ul_content); 279 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, 280 "rtl_cam_empty_entry(): WRITE A0: %x\n", 281 ul_command); 282 } 283 284} 285EXPORT_SYMBOL(rtl_cam_empty_entry); 286 287u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr) 288{ 289 struct rtl_priv *rtlpriv = rtl_priv(hw); 290 u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4; 291 u8 entry_idx = 0; 292 u8 i, *addr; 293 294 if (NULL == sta_addr) { 295 RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, "sta_addr is NULL\n"); 296 return TOTAL_CAM_ENTRY; 297 } 298 /* Does STA already exist? */ 299 for (i = 4; i < TOTAL_CAM_ENTRY; i++) { 300 addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; 301 if (memcmp(addr, sta_addr, ETH_ALEN) == 0) 302 return i; 303 } 304 /* Get a free CAM entry. */ 305 for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) { 306 if ((bitmap & BIT(0)) == 0) { 307 RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, 308 "-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n", 309 rtlpriv->sec.hwsec_cam_bitmap, entry_idx); 310 rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx; 311 memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx], 312 sta_addr, ETH_ALEN); 313 return entry_idx; 314 } 315 bitmap = bitmap >> 1; 316 } 317 return TOTAL_CAM_ENTRY; 318} 319EXPORT_SYMBOL(rtl_cam_get_free_entry); 320 321void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) 322{ 323 struct rtl_priv *rtlpriv = rtl_priv(hw); 324 u32 bitmap; 325 u8 i, *addr; 326 327 if (NULL == sta_addr) { 328 RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, "sta_addr is NULL\n"); 329 } 330 331 if ((sta_addr[0]|sta_addr[1]|sta_addr[2]|sta_addr[3]|\ 332 sta_addr[4]|sta_addr[5]) == 0) { 333 RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, 334 "sta_addr is 00:00:00:00:00:00\n"); 335 return; 336 } 337 /* Does STA already exist? */ 338 for (i = 4; i < TOTAL_CAM_ENTRY; i++) { 339 addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; 340 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i; 341 if (((bitmap & BIT(0)) == BIT(0)) && 342 (memcmp(addr, sta_addr, ETH_ALEN) == 0)) { 343 /* Remove from HW Security CAM */ 344 memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN); 345 rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i); 346 pr_info("&&&&&&&&&del entry %d\n", i); 347 } 348 } 349 return; 350} 351EXPORT_SYMBOL(rtl_cam_del_entry); 352