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