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