cam.c 9.9 KB

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