Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.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_rtl_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; //default 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                         kfree(crypt);
248                         ieee->crypt[i] = NULL;
249                 }
250         }
251
252         ieee80211_networks_free(ieee);
253 #if 0
254         for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) {
255                 list_for_each_safe(p, q, &ieee->ibss_mac_hash[i]) {
256                         kfree(list_entry(p, struct ieee_ibss_seq, list));
257                         list_del(p);
258                 }
259         }
260
261 #endif
262 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
263         free_netdev(dev);
264 #else
265         kfree(dev);
266 #endif
267 }
268
269 #ifdef CONFIG_IEEE80211_DEBUG
270
271 u32 ieee80211_debug_level = 0;
272 static int debug = \
273         //                  IEEE80211_DL_INFO   |
274         //                  IEEE80211_DL_WX     |
275         //                  IEEE80211_DL_SCAN   |
276         //                  IEEE80211_DL_STATE  |
277         //                  IEEE80211_DL_MGMT   |
278         //                  IEEE80211_DL_FRAG   |
279         //                  IEEE80211_DL_EAP    |
280         //                  IEEE80211_DL_DROP   |
281         //                  IEEE80211_DL_TX     |
282         //                  IEEE80211_DL_RX     |
283                             //IEEE80211_DL_QOS    |
284         //                  IEEE80211_DL_HT     |
285         //                  IEEE80211_DL_TS     |
286 //                          IEEE80211_DL_BA     |
287         //                  IEEE80211_DL_REORDER|
288 //                          IEEE80211_DL_TRACE  |
289                             //IEEE80211_DL_DATA |
290                             IEEE80211_DL_ERR      //awayls open this flags to show error out
291                             ;
292 struct proc_dir_entry *ieee80211_proc = NULL;
293
294 static int show_debug_level(char *page, char **start, off_t offset,
295                             int count, int *eof, void *data)
296 {
297         return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
298 }
299
300 static int store_debug_level(struct file *file, const char *buffer,
301                              unsigned long count, void *data)
302 {
303         char buf[] = "0x00000000";
304         unsigned long len = min(sizeof(buf) - 1, (u32)count);
305         char *p = (char *)buf;
306         unsigned long val;
307
308         if (copy_from_user(buf, buffer, len))
309                 return count;
310         buf[len] = 0;
311         if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
312                 p++;
313                 if (p[0] == 'x' || p[0] == 'X')
314                         p++;
315                 val = simple_strtoul(p, &p, 16);
316         } else
317                 val = simple_strtoul(p, &p, 10);
318         if (p == buf)
319                 printk(KERN_INFO DRV_NAME
320                        ": %s is not in hex or decimal form.\n", buf);
321         else
322                 ieee80211_debug_level = val;
323
324         return strnlen(buf, count);
325 }
326
327 extern int ieee80211_crypto_init(void);
328 extern void ieee80211_crypto_deinit(void);
329 extern int ieee80211_crypto_tkip_init(void);
330 extern void ieee80211_crypto_tkip_exit(void);
331 extern int ieee80211_crypto_ccmp_init(void);
332 extern void ieee80211_crypto_ccmp_exit(void);
333 extern int ieee80211_crypto_wep_init(void);
334 extern void ieee80211_crypto_wep_exit(void);
335
336 int __init ieee80211_rtl_init(void)
337 {
338         struct proc_dir_entry *e;
339         int retval;
340
341         retval = ieee80211_crypto_init();
342         if (retval)
343                 return retval;
344         retval = ieee80211_crypto_tkip_init();
345         if (retval) {
346                 ieee80211_crypto_deinit();
347                 return retval;
348         }
349         retval = ieee80211_crypto_ccmp_init();
350         if (retval) {
351                 ieee80211_crypto_tkip_exit();
352                 ieee80211_crypto_deinit();
353                 return retval;
354         }
355         retval = ieee80211_crypto_wep_init();
356         if (retval) {
357                 ieee80211_crypto_ccmp_exit();
358                 ieee80211_crypto_tkip_exit();
359                 ieee80211_crypto_deinit();
360                 return retval;
361         }
362
363         ieee80211_debug_level = debug;
364 #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
365         ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net);
366 #else
367         ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, init_net.proc_net);
368 #endif
369         if (ieee80211_proc == NULL) {
370                 IEEE80211_ERROR("Unable to create " DRV_NAME
371                                 " proc directory\n");
372                 return -EIO;
373         }
374         e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
375                               ieee80211_proc);
376         if (!e) {
377 #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
378                 remove_proc_entry(DRV_NAME, proc_net);
379 #else
380                 remove_proc_entry(DRV_NAME, init_net.proc_net);
381 #endif
382                 ieee80211_proc = NULL;
383                 return -EIO;
384         }
385         e->read_proc = show_debug_level;
386         e->write_proc = store_debug_level;
387         e->data = NULL;
388
389         return 0;
390 }
391
392 void __exit ieee80211_rtl_exit(void)
393 {
394         if (ieee80211_proc) {
395                 remove_proc_entry("debug_level", ieee80211_proc);
396 #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
397                 remove_proc_entry(DRV_NAME, proc_net);
398 #else
399                 remove_proc_entry(DRV_NAME, init_net.proc_net);
400 #endif
401                 ieee80211_proc = NULL;
402         }
403         ieee80211_crypto_wep_exit();
404         ieee80211_crypto_ccmp_exit();
405         ieee80211_crypto_tkip_exit();
406         ieee80211_crypto_deinit();
407 }
408
409 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
410 #include <linux/moduleparam.h>
411 module_param(debug, int, 0444);
412 MODULE_PARM_DESC(debug, "debug output mask");
413
414
415 //module_exit(ieee80211_rtl_exit);
416 //module_init(ieee80211_rtl_init);
417 #endif
418 #endif
419
420 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
421 //EXPORT_SYMBOL(alloc_ieee80211);
422 //EXPORT_SYMBOL(free_ieee80211);
423 #else
424 EXPORT_SYMBOL_NOVERS(alloc_ieee80211);
425 EXPORT_SYMBOL_NOVERS(free_ieee80211);
426 #endif