Merge branch 'atmel'
[linux-2.6] / net / ieee80211 / ieee80211_module.c
1 /*******************************************************************************
2
3   Copyright(c) 2004-2005 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/proc_fs.h>
44 #include <linux/skbuff.h>
45 #include <linux/slab.h>
46 #include <linux/tcp.h>
47 #include <linux/types.h>
48 #include <linux/wireless.h>
49 #include <linux/etherdevice.h>
50 #include <asm/uaccess.h>
51 #include <net/arp.h>
52
53 #include <net/ieee80211.h>
54
55 #define DRV_DESCRIPTION "802.11 data/management/control stack"
56 #define DRV_NAME        "ieee80211"
57 #define DRV_VERSION     IEEE80211_VERSION
58 #define DRV_COPYRIGHT   "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
59
60 MODULE_VERSION(DRV_VERSION);
61 MODULE_DESCRIPTION(DRV_DESCRIPTION);
62 MODULE_AUTHOR(DRV_COPYRIGHT);
63 MODULE_LICENSE("GPL");
64
65 static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
66 {
67         if (ieee->networks)
68                 return 0;
69
70         ieee->networks =
71             kmalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
72                     GFP_KERNEL);
73         if (!ieee->networks) {
74                 printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
75                        ieee->dev->name);
76                 return -ENOMEM;
77         }
78
79         memset(ieee->networks, 0,
80                MAX_NETWORK_COUNT * sizeof(struct ieee80211_network));
81
82         return 0;
83 }
84
85 static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
86 {
87         if (!ieee->networks)
88                 return;
89         kfree(ieee->networks);
90         ieee->networks = NULL;
91 }
92
93 static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee)
94 {
95         int i;
96
97         INIT_LIST_HEAD(&ieee->network_free_list);
98         INIT_LIST_HEAD(&ieee->network_list);
99         for (i = 0; i < MAX_NETWORK_COUNT; i++)
100                 list_add_tail(&ieee->networks[i].list,
101                               &ieee->network_free_list);
102 }
103
104 struct net_device *alloc_ieee80211(int sizeof_priv)
105 {
106         struct ieee80211_device *ieee;
107         struct net_device *dev;
108         int err;
109
110         IEEE80211_DEBUG_INFO("Initializing...\n");
111
112         dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
113         if (!dev) {
114                 IEEE80211_ERROR("Unable to network device.\n");
115                 goto failed;
116         }
117         ieee = netdev_priv(dev);
118         dev->hard_start_xmit = ieee80211_xmit;
119
120         ieee->dev = dev;
121
122         err = ieee80211_networks_allocate(ieee);
123         if (err) {
124                 IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
125                 goto failed;
126         }
127         ieee80211_networks_initialize(ieee);
128
129         /* Default fragmentation threshold is maximum payload size */
130         ieee->fts = DEFAULT_FTS;
131         ieee->rts = DEFAULT_FTS;
132         ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
133         ieee->open_wep = 1;
134
135         /* Default to enabling full open WEP with host based encrypt/decrypt */
136         ieee->host_encrypt = 1;
137         ieee->host_decrypt = 1;
138         ieee->host_mc_decrypt = 1;
139
140         /* Host fragementation in Open mode. Default is enabled.
141          * Note: host fragmentation is always enabled if host encryption
142          * is enabled. For cards can do hardware encryption, they must do
143          * hardware fragmentation as well. So we don't need a variable
144          * like host_enc_frag. */
145         ieee->host_open_frag = 1;
146         ieee->ieee802_1x = 1;   /* Default to supporting 802.1x */
147
148         INIT_LIST_HEAD(&ieee->crypt_deinit_list);
149         init_timer(&ieee->crypt_deinit_timer);
150         ieee->crypt_deinit_timer.data = (unsigned long)ieee;
151         ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
152         ieee->crypt_quiesced = 0;
153
154         spin_lock_init(&ieee->lock);
155
156         ieee->wpa_enabled = 0;
157         ieee->drop_unencrypted = 0;
158         ieee->privacy_invoked = 0;
159
160         return dev;
161
162       failed:
163         if (dev)
164                 free_netdev(dev);
165         return NULL;
166 }
167
168 void free_ieee80211(struct net_device *dev)
169 {
170         struct ieee80211_device *ieee = netdev_priv(dev);
171
172         int i;
173
174         ieee80211_crypt_quiescing(ieee);
175         del_timer_sync(&ieee->crypt_deinit_timer);
176         ieee80211_crypt_deinit_entries(ieee, 1);
177
178         for (i = 0; i < WEP_KEYS; i++) {
179                 struct ieee80211_crypt_data *crypt = ieee->crypt[i];
180                 if (crypt) {
181                         if (crypt->ops) {
182                                 crypt->ops->deinit(crypt->priv);
183                                 module_put(crypt->ops->owner);
184                         }
185                         kfree(crypt);
186                         ieee->crypt[i] = NULL;
187                 }
188         }
189
190         ieee80211_networks_free(ieee);
191         free_netdev(dev);
192 }
193
194 #ifdef CONFIG_IEEE80211_DEBUG
195
196 static int debug = 0;
197 u32 ieee80211_debug_level = 0;
198 struct proc_dir_entry *ieee80211_proc = NULL;
199
200 static int show_debug_level(char *page, char **start, off_t offset,
201                             int count, int *eof, void *data)
202 {
203         return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
204 }
205
206 static int store_debug_level(struct file *file, const char __user * buffer,
207                              unsigned long count, void *data)
208 {
209         char buf[] = "0x00000000\n";
210         unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
211         unsigned long val;
212
213         if (copy_from_user(buf, buffer, len))
214                 return count;
215         buf[len] = 0;
216         if (sscanf(buf, "%li", &val) != 1)
217                 printk(KERN_INFO DRV_NAME
218                        ": %s is not in hex or decimal form.\n", buf);
219         else
220                 ieee80211_debug_level = val;
221
222         return strnlen(buf, len);
223 }
224 #endif                          /* CONFIG_IEEE80211_DEBUG */
225
226 static int __init ieee80211_init(void)
227 {
228 #ifdef CONFIG_IEEE80211_DEBUG
229         struct proc_dir_entry *e;
230
231         ieee80211_debug_level = debug;
232         ieee80211_proc = proc_mkdir(DRV_NAME, proc_net);
233         if (ieee80211_proc == NULL) {
234                 IEEE80211_ERROR("Unable to create " DRV_NAME
235                                 " proc directory\n");
236                 return -EIO;
237         }
238         e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
239                               ieee80211_proc);
240         if (!e) {
241                 remove_proc_entry(DRV_NAME, proc_net);
242                 ieee80211_proc = NULL;
243                 return -EIO;
244         }
245         e->read_proc = show_debug_level;
246         e->write_proc = store_debug_level;
247         e->data = NULL;
248 #endif                          /* CONFIG_IEEE80211_DEBUG */
249
250         printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
251         printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
252
253         return 0;
254 }
255
256 static void __exit ieee80211_exit(void)
257 {
258 #ifdef CONFIG_IEEE80211_DEBUG
259         if (ieee80211_proc) {
260                 remove_proc_entry("debug_level", ieee80211_proc);
261                 remove_proc_entry(DRV_NAME, proc_net);
262                 ieee80211_proc = NULL;
263         }
264 #endif                          /* CONFIG_IEEE80211_DEBUG */
265 }
266
267 #ifdef CONFIG_IEEE80211_DEBUG
268 #include <linux/moduleparam.h>
269 module_param(debug, int, 0444);
270 MODULE_PARM_DESC(debug, "debug output mask");
271 #endif                          /* CONFIG_IEEE80211_DEBUG */
272
273 module_exit(ieee80211_exit);
274 module_init(ieee80211_init);
275
276 const char *escape_essid(const char *essid, u8 essid_len)
277 {
278         static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
279         const char *s = essid;
280         char *d = escaped;
281
282         if (ieee80211_is_empty_essid(essid, essid_len)) {
283                 memcpy(escaped, "<hidden>", sizeof("<hidden>"));
284                 return escaped;
285         }
286
287         essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
288         while (essid_len--) {
289                 if (*s == '\0') {
290                         *d++ = '\\';
291                         *d++ = '0';
292                         s++;
293                 } else {
294                         *d++ = *s++;
295                 }
296         }
297         *d = '\0';
298         return escaped;
299 }
300
301 EXPORT_SYMBOL(alloc_ieee80211);
302 EXPORT_SYMBOL(free_ieee80211);
303 EXPORT_SYMBOL(escape_essid);