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