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