1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
4 * Copyright(c) 2009-2012 Realtek Corporation.
7 * wlanfae <wlanfae@realtek.com>
8 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
11 * Larry Finger <Larry.Finger@lwfinger.net>
13 *****************************************************************************/
16 #include <linux/export.h>
18 void rtl_cam_reset_sec_info(struct ieee80211_hw
*hw
)
20 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
22 rtlpriv
->sec
.use_defaultkey
= false;
23 rtlpriv
->sec
.pairwise_enc_algorithm
= NO_ENCRYPTION
;
24 rtlpriv
->sec
.group_enc_algorithm
= NO_ENCRYPTION
;
25 memset(rtlpriv
->sec
.key_buf
, 0, KEY_BUF_SIZE
* MAX_KEY_LEN
);
26 memset(rtlpriv
->sec
.key_len
, 0, KEY_BUF_SIZE
);
27 rtlpriv
->sec
.pairwise_key
= NULL
;
30 static void rtl_cam_program_entry(struct ieee80211_hw
*hw
, u32 entry_no
,
31 u8
*mac_addr
, u8
*key_cont_128
, u16 us_config
)
33 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
36 u32 target_content
= 0;
39 RT_PRINT_DATA(rtlpriv
, COMP_SEC
, DBG_DMESG
, "Key content :",
42 /* 0-1 config + mac, 2-5 fill 128key,6-7 are reserved */
43 for (entry_i
= CAM_CONTENT_COUNT
- 1; entry_i
>= 0; entry_i
--) {
44 target_command
= entry_i
+ CAM_CONTENT_COUNT
* entry_no
;
45 target_command
= target_command
| BIT(31) | BIT(16);
48 target_content
= (u32
)(*(mac_addr
+ 0)) << 16 |
49 (u32
)(*(mac_addr
+ 1)) << 24 |
52 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[WCAMI
],
54 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[RWCAM
],
57 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_LOUD
,
59 rtlpriv
->cfg
->maps
[WCAMI
], target_content
);
60 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_LOUD
,
61 "The Key ID is %d\n", entry_no
);
62 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_LOUD
,
64 rtlpriv
->cfg
->maps
[RWCAM
], target_command
);
66 } else if (entry_i
== 1) {
67 target_content
= (u32
)(*(mac_addr
+ 5)) << 24 |
68 (u32
)(*(mac_addr
+ 4)) << 16 |
69 (u32
)(*(mac_addr
+ 3)) << 8 |
70 (u32
)(*(mac_addr
+ 2));
72 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[WCAMI
],
74 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[RWCAM
],
77 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_LOUD
,
78 "WRITE A4: %x\n", target_content
);
79 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_LOUD
,
80 "WRITE A0: %x\n", target_command
);
83 (u32
)(*(key_cont_128
+ (entry_i
* 4 - 8) + 3)) <<
84 24 | (u32
)(*(key_cont_128
+ (entry_i
* 4 - 8) + 2))
86 (u32
)(*(key_cont_128
+ (entry_i
* 4 - 8) + 1)) << 8
87 | (u32
)(*(key_cont_128
+ (entry_i
* 4 - 8) + 0));
89 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[WCAMI
],
91 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[RWCAM
],
94 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_LOUD
,
95 "WRITE A4: %x\n", target_content
);
96 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_LOUD
,
97 "WRITE A0: %x\n", target_command
);
101 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_LOUD
,
102 "after set key, usconfig:%x\n", us_config
);
105 u8
rtl_cam_add_one_entry(struct ieee80211_hw
*hw
, u8
*mac_addr
,
106 u32 ul_key_id
, u32 ul_entry_idx
, u32 ul_enc_alg
,
107 u32 ul_default_key
, u8
*key_content
)
110 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
112 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_DMESG
,
113 "EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n",
114 ul_entry_idx
, ul_key_id
, ul_enc_alg
,
115 ul_default_key
, mac_addr
);
117 if (ul_key_id
== TOTAL_CAM_ENTRY
) {
118 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_WARNING
,
119 "ulKeyId exceed!\n");
123 if (ul_default_key
== 1)
124 us_config
= CFG_VALID
| ((u16
)(ul_enc_alg
) << 2);
126 us_config
= CFG_VALID
| ((ul_enc_alg
) << 2) | ul_key_id
;
128 rtl_cam_program_entry(hw
, ul_entry_idx
, mac_addr
,
129 (u8
*)key_content
, us_config
);
131 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_DMESG
, "end\n");
136 int rtl_cam_delete_one_entry(struct ieee80211_hw
*hw
,
137 u8
*mac_addr
, u32 ul_key_id
)
140 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
142 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_DMESG
, "key_idx:%d\n", ul_key_id
);
144 ul_command
= ul_key_id
* CAM_CONTENT_COUNT
;
145 ul_command
= ul_command
| BIT(31) | BIT(16);
147 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[WCAMI
], 0);
148 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[RWCAM
], ul_command
);
150 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_DMESG
,
151 "%s(): WRITE A4: %x\n", __func__
, 0);
152 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_DMESG
,
153 "%s(): WRITE A0: %x\n", __func__
, ul_command
);
158 void rtl_cam_reset_all_entry(struct ieee80211_hw
*hw
)
161 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
163 ul_command
= BIT(31) | BIT(30);
164 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[RWCAM
], ul_command
);
167 void rtl_cam_mark_invalid(struct ieee80211_hw
*hw
, u8 uc_index
)
169 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
175 switch (rtlpriv
->sec
.pairwise_enc_algorithm
) {
176 case WEP40_ENCRYPTION
:
177 ul_enc_algo
= rtlpriv
->cfg
->maps
[SEC_CAM_WEP40
];
179 case WEP104_ENCRYPTION
:
180 ul_enc_algo
= rtlpriv
->cfg
->maps
[SEC_CAM_WEP104
];
182 case TKIP_ENCRYPTION
:
183 ul_enc_algo
= rtlpriv
->cfg
->maps
[SEC_CAM_TKIP
];
185 case AESCCMP_ENCRYPTION
:
186 ul_enc_algo
= rtlpriv
->cfg
->maps
[SEC_CAM_AES
];
189 ul_enc_algo
= rtlpriv
->cfg
->maps
[SEC_CAM_AES
];
192 ul_content
= (uc_index
& 3) | ((u16
)(ul_enc_algo
) << 2);
194 ul_content
|= BIT(15);
195 ul_command
= CAM_CONTENT_COUNT
* uc_index
;
196 ul_command
= ul_command
| BIT(31) | BIT(16);
198 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[WCAMI
], ul_content
);
199 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[RWCAM
], ul_command
);
201 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_DMESG
,
202 "%s(): WRITE A4: %x\n", __func__
, ul_content
);
203 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_DMESG
,
204 "%s(): WRITE A0: %x\n", __func__
, ul_command
);
207 void rtl_cam_empty_entry(struct ieee80211_hw
*hw
, u8 uc_index
)
209 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
216 switch (rtlpriv
->sec
.pairwise_enc_algorithm
) {
217 case WEP40_ENCRYPTION
:
218 ul_encalgo
= rtlpriv
->cfg
->maps
[SEC_CAM_WEP40
];
220 case WEP104_ENCRYPTION
:
221 ul_encalgo
= rtlpriv
->cfg
->maps
[SEC_CAM_WEP104
];
223 case TKIP_ENCRYPTION
:
224 ul_encalgo
= rtlpriv
->cfg
->maps
[SEC_CAM_TKIP
];
226 case AESCCMP_ENCRYPTION
:
227 ul_encalgo
= rtlpriv
->cfg
->maps
[SEC_CAM_AES
];
230 ul_encalgo
= rtlpriv
->cfg
->maps
[SEC_CAM_AES
];
233 for (entry_i
= 0; entry_i
< CAM_CONTENT_COUNT
; entry_i
++) {
236 (uc_index
& 0x03) | ((u16
)(ul_encalgo
) << 2);
237 ul_content
|= BIT(15);
242 ul_command
= CAM_CONTENT_COUNT
* uc_index
+ entry_i
;
243 ul_command
= ul_command
| BIT(31) | BIT(16);
245 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[WCAMI
], ul_content
);
246 rtl_write_dword(rtlpriv
, rtlpriv
->cfg
->maps
[RWCAM
], ul_command
);
248 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_LOUD
,
249 "%s(): WRITE A4: %x\n", __func__
, ul_content
);
250 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_LOUD
,
251 "%s(): WRITE A0: %x\n", __func__
, ul_command
);
255 u8
rtl_cam_get_free_entry(struct ieee80211_hw
*hw
, u8
*sta_addr
)
257 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
258 u32 bitmap
= (rtlpriv
->sec
.hwsec_cam_bitmap
) >> 4;
263 pr_err("sta_addr is NULL.\n");
264 return TOTAL_CAM_ENTRY
;
266 /* Does STA already exist? */
267 for (i
= 4; i
< TOTAL_CAM_ENTRY
; i
++) {
268 addr
= rtlpriv
->sec
.hwsec_cam_sta_addr
[i
];
269 if (ether_addr_equal_unaligned(addr
, sta_addr
))
272 /* Get a free CAM entry. */
273 for (entry_idx
= 4; entry_idx
< TOTAL_CAM_ENTRY
; entry_idx
++) {
274 if ((bitmap
& BIT(0)) == 0) {
275 pr_err("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n",
276 rtlpriv
->sec
.hwsec_cam_bitmap
, entry_idx
);
277 rtlpriv
->sec
.hwsec_cam_bitmap
|= BIT(0) << entry_idx
;
278 memcpy(rtlpriv
->sec
.hwsec_cam_sta_addr
[entry_idx
],
282 bitmap
= bitmap
>> 1;
284 return TOTAL_CAM_ENTRY
;
287 void rtl_cam_del_entry(struct ieee80211_hw
*hw
, u8
*sta_addr
)
289 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
294 pr_err("sta_addr is NULL.\n");
298 if (is_zero_ether_addr(sta_addr
)) {
299 pr_err("sta_addr is %pM\n", sta_addr
);
302 /* Does STA already exist? */
303 for (i
= 4; i
< TOTAL_CAM_ENTRY
; i
++) {
304 addr
= rtlpriv
->sec
.hwsec_cam_sta_addr
[i
];
305 bitmap
= (rtlpriv
->sec
.hwsec_cam_bitmap
) >> i
;
306 if (((bitmap
& BIT(0)) == BIT(0)) &&
307 (ether_addr_equal_unaligned(addr
, sta_addr
))) {
308 /* Remove from HW Security CAM */
309 eth_zero_addr(rtlpriv
->sec
.hwsec_cam_sta_addr
[i
]);
310 rtlpriv
->sec
.hwsec_cam_bitmap
&= ~(BIT(0) << i
);
311 RT_TRACE(rtlpriv
, COMP_SEC
, DBG_DMESG
,
312 "&&&&&&&&&del entry %d\n", i
);