Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx...
[cascardo/linux.git] / drivers / staging / rtl8192e / ieee80211 / ieee80211_module.c
1 /*******************************************************************************
2
3   Copyright(c) 2004 Intel Corporation. All rights reserved.
4
5   Portions of this file are based on the WEP enablement code provided by the
6   Host AP project hostap-drivers v0.1.3
7   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
8   <jkmaline@cc.hut.fi>
9   Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
10
11   This program is free software; you can redistribute it and/or modify it
12   under the terms of version 2 of the GNU General Public License as
13   published by the Free Software Foundation.
14
15   This program is distributed in the hope that it will be useful, but WITHOUT
16   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18   more details.
19
20   You should have received a copy of the GNU General Public License along with
21   this program; if not, write to the Free Software Foundation, Inc., 59
22   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23
24   The full GNU General Public License is included in this distribution in the
25   file called LICENSE.
26
27   Contact Information:
28   James P. Ketrenos <ipw2100-admin@linux.intel.com>
29   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31 *******************************************************************************/
32
33 #include <linux/compiler.h>
34 //#include <linux/config.h>
35 #include <linux/errno.h>
36 #include <linux/if_arp.h>
37 #include <linux/in6.h>
38 #include <linux/in.h>
39 #include <linux/ip.h>
40 #include <linux/kernel.h>
41 #include <linux/module.h>
42 #include <linux/netdevice.h>
43 #include <linux/pci.h>
44 #include <linux/proc_fs.h>
45 #include <linux/skbuff.h>
46 #include <linux/slab.h>
47 #include <linux/tcp.h>
48 #include <linux/types.h>
49 #include <linux/version.h>
50 #include <linux/wireless.h>
51 #include <linux/etherdevice.h>
52 #include <asm/uaccess.h>
53 #include <net/arp.h>
54
55 #include "ieee80211.h"
56
57 MODULE_DESCRIPTION("802.11 data/management/control stack");
58 MODULE_AUTHOR("Copyright (C) 2004 Intel Corporation <jketreno@linux.intel.com>");
59 MODULE_LICENSE("GPL");
60
61 #define DRV_NAME "ieee80211"
62
63 static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
64 {
65         if (ieee->networks)
66                 return 0;
67
68         ieee->networks = kmalloc(
69                 MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
70                 GFP_KERNEL);
71         if (!ieee->networks) {
72                 printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
73                        ieee->dev->name);
74                 return -ENOMEM;
75         }
76
77         memset(ieee->networks, 0,
78                MAX_NETWORK_COUNT * sizeof(struct ieee80211_network));
79
80         return 0;
81 }
82
83 static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
84 {
85         if (!ieee->networks)
86                 return;
87         kfree(ieee->networks);
88         ieee->networks = NULL;
89 }
90
91 static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee)
92 {
93         int i;
94
95         INIT_LIST_HEAD(&ieee->network_free_list);
96         INIT_LIST_HEAD(&ieee->network_list);
97         for (i = 0; i < MAX_NETWORK_COUNT; i++)
98                 list_add_tail(&ieee->networks[i].list, &ieee->network_free_list);
99 }
100
101
102 struct net_device *alloc_ieee80211(int sizeof_priv)
103 {
104         struct ieee80211_device *ieee;
105         struct net_device *dev;
106         int i,err;
107
108         IEEE80211_DEBUG_INFO("Initializing...\n");
109
110         dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
111         if (!dev) {
112                 IEEE80211_ERROR("Unable to network device.\n");
113                 goto failed;
114         }
115
116 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
117         ieee = netdev_priv(dev);
118 #else
119         ieee = (struct ieee80211_device *)dev->priv;
120 #endif
121 #if 0
122         dev->hard_start_xmit = ieee80211_xmit;
123 #endif
124
125         memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv);
126         ieee->dev = dev;
127
128         err = ieee80211_networks_allocate(ieee);
129         if (err) {
130                 IEEE80211_ERROR("Unable to allocate beacon storage: %d\n",
131                                 err);
132                 goto failed;
133         }
134         ieee80211_networks_initialize(ieee);
135
136
137         /* Default fragmentation threshold is maximum payload size */
138         ieee->fts = DEFAULT_FTS;
139         ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
140         ieee->open_wep = 1;
141
142         /* Default to enabling full open WEP with host based encrypt/decrypt */
143         ieee->host_encrypt = 1;
144         ieee->host_decrypt = 1;
145         ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
146
147         INIT_LIST_HEAD(&ieee->crypt_deinit_list);
148         init_timer(&ieee->crypt_deinit_timer);
149         ieee->crypt_deinit_timer.data = (unsigned long)ieee;
150         ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
151
152         spin_lock_init(&ieee->lock);
153         spin_lock_init(&ieee->wpax_suitlist_lock);
154         spin_lock_init(&ieee->bw_spinlock);
155         spin_lock_init(&ieee->reorder_spinlock);
156         //added by WB
157         atomic_set(&(ieee->atm_chnlop), 0);
158         atomic_set(&(ieee->atm_swbw), 0);
159
160         ieee->wpax_type_set = 0;
161         ieee->wpa_enabled = 0;
162         ieee->tkip_countermeasures = 0;
163         ieee->drop_unencrypted = 0;
164         ieee->privacy_invoked = 0;
165         ieee->ieee802_1x = 1;
166         ieee->raw_tx = 0;
167         //ieee->hwsec_support = 1; //defalt support hw security. //use module_param instead.
168         ieee->hwsec_active = 0; //disable hwsec, switch it on when necessary.
169
170         ieee80211_softmac_init(ieee);
171
172 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
173         ieee->pHTInfo = (RT_HIGH_THROUGHPUT*)kzalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL);
174 #else
175         ieee->pHTInfo = (RT_HIGH_THROUGHPUT*)kmalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL);
176         memset(ieee->pHTInfo,0,sizeof(RT_HIGH_THROUGHPUT));
177 #endif
178         if (ieee->pHTInfo == NULL)
179         {
180                 IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n");
181                 return NULL;
182         }
183         HTUpdateDefaultSetting(ieee);
184         HTInitializeHTInfo(ieee); //may move to other place.
185         TSInitialize(ieee);
186 #if 0
187 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
188         INIT_WORK(&ieee->ht_onAssRsp, (void(*)(void*)) HTOnAssocRsp_wq);
189 #else
190         INIT_WORK(&ieee->ht_onAssRsp, (void(*)(void*)) HTOnAssocRsp_wq, ieee);
191 #endif
192 #endif
193         for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++)
194                 INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]);
195
196         for (i = 0; i < 17; i++) {
197           ieee->last_rxseq_num[i] = -1;
198           ieee->last_rxfrag_num[i] = -1;
199           ieee->last_packet_time[i] = 0;
200         }
201
202 //These function were added to load crypte module autoly
203         ieee80211_tkip_null();
204         ieee80211_wep_null();
205         ieee80211_ccmp_null();
206
207         return dev;
208
209  failed:
210         if (dev)
211 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
212                 free_netdev(dev);
213 #else
214                 kfree(dev);
215 #endif
216         return NULL;
217 }
218
219
220 void free_ieee80211(struct net_device *dev)
221 {
222 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
223         struct ieee80211_device *ieee = netdev_priv(dev);
224 #else
225         struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv;
226 #endif
227         int i;
228         //struct list_head *p, *q;
229 //      del_timer_sync(&ieee->SwBwTimer);
230 #if 1
231         if (ieee->pHTInfo != NULL)
232         {
233                 kfree(ieee->pHTInfo);
234                 ieee->pHTInfo = NULL;
235         }
236 #endif
237         RemoveAllTS(ieee);
238         ieee80211_softmac_free(ieee);
239         del_timer_sync(&ieee->crypt_deinit_timer);
240         ieee80211_crypt_deinit_entries(ieee, 1);
241
242         for (i = 0; i < WEP_KEYS; i++) {
243                 struct ieee80211_crypt_data *crypt = ieee->crypt[i];
244                 if (crypt) {
245                         if (crypt->ops) {
246                                 crypt->ops->deinit(crypt->priv);
247 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
248                                 module_put(crypt->ops->owner);
249 #else
250                                 __MOD_DEC_USE_COUNT(crypt->ops->owner);
251 #endif
252                         }
253                         kfree(crypt);
254                         ieee->crypt[i] = NULL;
255                 }
256         }
257
258         ieee80211_networks_free(ieee);
259 #if 0
260         for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) {
261                 list_for_each_safe(p, q, &ieee->ibss_mac_hash[i]) {
262                         kfree(list_entry(p, struct ieee_ibss_seq, list));
263                         list_del(p);
264                 }
265         }
266
267 #endif
268 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
269         free_netdev(dev);
270 #else
271         kfree(dev);
272 #endif
273 }
274
275 #ifdef CONFIG_IEEE80211_DEBUG
276
277 u32 ieee80211_debug_level = 0;
278 static int debug = \
279         //                  IEEE80211_DL_INFO   |
280         //                  IEEE80211_DL_WX     |
281         //                  IEEE80211_DL_SCAN   |
282         //                  IEEE80211_DL_STATE  |
283         //                  IEEE80211_DL_MGMT   |
284         //                  IEEE80211_DL_FRAG   |
285         //                  IEEE80211_DL_EAP    |
286         //                  IEEE80211_DL_DROP   |
287         //                  IEEE80211_DL_TX     |
288         //                  IEEE80211_DL_RX     |
289                             //IEEE80211_DL_QOS    |
290         //                  IEEE80211_DL_HT     |
291         //                  IEEE80211_DL_TS     |
292 //                          IEEE80211_DL_BA     |
293         //                  IEEE80211_DL_REORDER|
294 //                          IEEE80211_DL_TRACE  |
295                             //IEEE80211_DL_DATA |
296                             IEEE80211_DL_ERR      //awayls open this flags to show error out
297                             ;
298 struct proc_dir_entry *ieee80211_proc = NULL;
299
300 static int show_debug_level(char *page, char **start, off_t offset,
301                             int count, int *eof, void *data)
302 {
303         return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
304 }
305
306 static int store_debug_level(struct file *file, const char *buffer,
307                              unsigned long count, void *data)
308 {
309         char buf[] = "0x00000000";
310         unsigned long len = min(sizeof(buf) - 1, (u32)count);
311         char *p = (char *)buf;
312         unsigned long val;
313
314         if (copy_from_user(buf, buffer, len))
315                 return count;
316         buf[len] = 0;
317         if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
318                 p++;
319                 if (p[0] == 'x' || p[0] == 'X')
320                         p++;
321                 val = simple_strtoul(p, &p, 16);
322         } else
323                 val = simple_strtoul(p, &p, 10);
324         if (p == buf)
325                 printk(KERN_INFO DRV_NAME
326                        ": %s is not in hex or decimal form.\n", buf);
327         else
328                 ieee80211_debug_level = val;
329
330         return strnlen(buf, count);
331 }
332
333 extern int ieee80211_crypto_init(void);
334 extern void ieee80211_crypto_deinit(void);
335 extern int ieee80211_crypto_tkip_init(void);
336 extern void ieee80211_crypto_tkip_exit(void);
337 extern int ieee80211_crypto_ccmp_init(void);
338 extern void ieee80211_crypto_ccmp_exit(void);
339 extern int ieee80211_crypto_wep_init(void);
340 extern void ieee80211_crypto_wep_exit(void);
341
342 int __init ieee80211_init(void)
343 {
344         struct proc_dir_entry *e;
345         int retval;
346
347         retval = ieee80211_crypto_init();
348         if (retval)
349                 return retval;
350         retval = ieee80211_crypto_tkip_init();
351         if (retval) {
352                 ieee80211_crypto_deinit();
353                 return retval;
354         }
355         retval = ieee80211_crypto_ccmp_init();
356         if (retval) {
357                 ieee80211_crypto_tkip_exit();
358                 ieee80211_crypto_deinit();
359                 return retval;
360         }
361         retval = ieee80211_crypto_wep_init();
362         if (retval) {
363                 ieee80211_crypto_ccmp_exit();
364                 ieee80211_crypto_tkip_exit();
365                 ieee80211_crypto_deinit();
366                 return retval;
367         }
368
369         ieee80211_debug_level = debug;
370 #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
371         ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net);
372 #else
373         ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, init_net.proc_net);
374 #endif
375         if (ieee80211_proc == NULL) {
376                 IEEE80211_ERROR("Unable to create " DRV_NAME
377                                 " proc directory\n");
378                 return -EIO;
379         }
380         e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
381                               ieee80211_proc);
382         if (!e) {
383 #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
384                 remove_proc_entry(DRV_NAME, proc_net);
385 #else
386                 remove_proc_entry(DRV_NAME, init_net.proc_net);
387 #endif
388                 ieee80211_proc = NULL;
389                 return -EIO;
390         }
391         e->read_proc = show_debug_level;
392         e->write_proc = store_debug_level;
393         e->data = NULL;
394
395         return 0;
396 }
397
398 void __exit ieee80211_exit(void)
399 {
400         if (ieee80211_proc) {
401                 remove_proc_entry("debug_level", ieee80211_proc);
402 #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
403                 remove_proc_entry(DRV_NAME, proc_net);
404 #else
405                 remove_proc_entry(DRV_NAME, init_net.proc_net);
406 #endif
407                 ieee80211_proc = NULL;
408         }
409         ieee80211_crypto_wep_exit();
410         ieee80211_crypto_ccmp_exit();
411         ieee80211_crypto_tkip_exit();
412         ieee80211_crypto_deinit();
413 }
414
415 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
416 #include <linux/moduleparam.h>
417 module_param(debug, int, 0444);
418 MODULE_PARM_DESC(debug, "debug output mask");
419
420
421 //module_exit(ieee80211_exit);
422 //module_init(ieee80211_init);
423 #endif
424 #endif
425
426 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
427 //EXPORT_SYMBOL(alloc_ieee80211);
428 //EXPORT_SYMBOL(free_ieee80211);
429 #else
430 EXPORT_SYMBOL_NOVERS(alloc_ieee80211);
431 EXPORT_SYMBOL_NOVERS(free_ieee80211);
432 #endif