GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / staging / rtlwifi / cam.c
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2009-2012  Realtek Corporation.
5  *
6  * Contact Information:
7  * wlanfae <wlanfae@realtek.com>
8  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
9  * Hsinchu 300, Taiwan.
10  *
11  * Larry Finger <Larry.Finger@lwfinger.net>
12  *
13  *****************************************************************************/
14 #include "wifi.h"
15 #include "cam.h"
16 #include <linux/export.h>
17
18 void rtl_cam_reset_sec_info(struct ieee80211_hw *hw)
19 {
20         struct rtl_priv *rtlpriv = rtl_priv(hw);
21
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;
28 }
29
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)
32 {
33         struct rtl_priv *rtlpriv = rtl_priv(hw);
34
35         u32 target_command;
36         u32 target_content = 0;
37         int entry_i;
38
39         RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_DMESG, "Key content :",
40                       key_cont_128, 16);
41
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);
46
47                 if (entry_i == 0) {
48                         target_content = (u32)(*(mac_addr + 0)) << 16 |
49                                          (u32)(*(mac_addr + 1)) << 24 |
50                                          (u32)us_config;
51
52                         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
53                                         target_content);
54                         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
55                                         target_command);
56
57                         RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
58                                  "WRITE %x: %x\n",
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,
63                                  "WRITE %x: %x\n",
64                                  rtlpriv->cfg->maps[RWCAM], target_command);
65
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));
71
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
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);
81                 } else {
82                         target_content =
83                             (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 3)) <<
84                             24 | (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 2))
85                             << 16 |
86                             (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 8
87                             | (u32)(*(key_cont_128 + (entry_i * 4 - 8) + 0));
88
89                         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
90                                         target_content);
91                         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
92                                         target_command);
93
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);
98                 }
99         }
100
101         RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
102                  "after set key, usconfig:%x\n", us_config);
103 }
104
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)
108 {
109         u32 us_config;
110         struct rtl_priv *rtlpriv = rtl_priv(hw);
111
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);
116
117         if (ul_key_id == TOTAL_CAM_ENTRY) {
118                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
119                          "ulKeyId exceed!\n");
120                 return 0;
121         }
122
123         if (ul_default_key == 1)
124                 us_config = CFG_VALID | ((u16)(ul_enc_alg) << 2);
125         else
126                 us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id;
127
128         rtl_cam_program_entry(hw, ul_entry_idx, mac_addr,
129                               (u8 *)key_content, us_config);
130
131         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "end\n");
132
133         return 1;
134 }
135
136 int rtl_cam_delete_one_entry(struct ieee80211_hw *hw,
137                              u8 *mac_addr, u32 ul_key_id)
138 {
139         u32 ul_command;
140         struct rtl_priv *rtlpriv = rtl_priv(hw);
141
142         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "key_idx:%d\n", ul_key_id);
143
144         ul_command = ul_key_id * CAM_CONTENT_COUNT;
145         ul_command = ul_command | BIT(31) | BIT(16);
146
147         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0);
148         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
149
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);
154
155         return 0;
156 }
157
158 void rtl_cam_reset_all_entry(struct ieee80211_hw *hw)
159 {
160         u32 ul_command;
161         struct rtl_priv *rtlpriv = rtl_priv(hw);
162
163         ul_command = BIT(31) | BIT(30);
164         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
165 }
166
167 void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index)
168 {
169         struct rtl_priv *rtlpriv = rtl_priv(hw);
170
171         u32 ul_command;
172         u32 ul_content;
173         u32 ul_enc_algo;
174
175         switch (rtlpriv->sec.pairwise_enc_algorithm) {
176         case WEP40_ENCRYPTION:
177                 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
178                 break;
179         case WEP104_ENCRYPTION:
180                 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
181                 break;
182         case TKIP_ENCRYPTION:
183                 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
184                 break;
185         case AESCCMP_ENCRYPTION:
186                 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
187                 break;
188         default:
189                 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
190         }
191
192         ul_content = (uc_index & 3) | ((u16)(ul_enc_algo) << 2);
193
194         ul_content |= BIT(15);
195         ul_command = CAM_CONTENT_COUNT * uc_index;
196         ul_command = ul_command | BIT(31) | BIT(16);
197
198         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
199         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
200
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);
205 }
206
207 void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index)
208 {
209         struct rtl_priv *rtlpriv = rtl_priv(hw);
210
211         u32 ul_command;
212         u32 ul_content;
213         u32 ul_encalgo;
214         u8 entry_i;
215
216         switch (rtlpriv->sec.pairwise_enc_algorithm) {
217         case WEP40_ENCRYPTION:
218                 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
219                 break;
220         case WEP104_ENCRYPTION:
221                 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
222                 break;
223         case TKIP_ENCRYPTION:
224                 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
225                 break;
226         case AESCCMP_ENCRYPTION:
227                 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
228                 break;
229         default:
230                 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
231         }
232
233         for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
234                 if (entry_i == 0) {
235                         ul_content =
236                             (uc_index & 0x03) | ((u16)(ul_encalgo) << 2);
237                         ul_content |= BIT(15);
238                 } else {
239                         ul_content = 0;
240                 }
241
242                 ul_command = CAM_CONTENT_COUNT * uc_index + entry_i;
243                 ul_command = ul_command | BIT(31) | BIT(16);
244
245                 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
246                 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
247
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);
252         }
253 }
254
255 u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr)
256 {
257         struct rtl_priv *rtlpriv = rtl_priv(hw);
258         u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4;
259         u8 entry_idx = 0;
260         u8 i, *addr;
261
262         if (!sta_addr) {
263                 pr_err("sta_addr is NULL.\n");
264                 return TOTAL_CAM_ENTRY;
265         }
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))
270                         return i;
271         }
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],
279                                sta_addr, ETH_ALEN);
280                         return entry_idx;
281                 }
282                 bitmap = bitmap >> 1;
283         }
284         return TOTAL_CAM_ENTRY;
285 }
286
287 void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr)
288 {
289         struct rtl_priv *rtlpriv = rtl_priv(hw);
290         u32 bitmap;
291         u8 i, *addr;
292
293         if (!sta_addr) {
294                 pr_err("sta_addr is NULL.\n");
295                 return;
296         }
297
298         if (is_zero_ether_addr(sta_addr)) {
299                 pr_err("sta_addr is %pM\n", sta_addr);
300                 return;
301         }
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);
313                 }
314         }
315 }