]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/ieee80211/ieee80211_module.c
[PATCH] ieee80211: Added subsystem version string and reporting via MODULE_VERSION
[karo-tx-linux.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->tkip_countermeasures = 0;
159         ieee->drop_unencrypted = 0;
160         ieee->privacy_invoked = 0;
161
162         return dev;
163
164       failed:
165         if (dev)
166                 free_netdev(dev);
167         return NULL;
168 }
169
170 void free_ieee80211(struct net_device *dev)
171 {
172         struct ieee80211_device *ieee = netdev_priv(dev);
173
174         int i;
175
176         ieee80211_crypt_quiescing(ieee);
177         del_timer_sync(&ieee->crypt_deinit_timer);
178         ieee80211_crypt_deinit_entries(ieee, 1);
179
180         for (i = 0; i < WEP_KEYS; i++) {
181                 struct ieee80211_crypt_data *crypt = ieee->crypt[i];
182                 if (crypt) {
183                         if (crypt->ops) {
184                                 crypt->ops->deinit(crypt->priv);
185                                 module_put(crypt->ops->owner);
186                         }
187                         kfree(crypt);
188                         ieee->crypt[i] = NULL;
189                 }
190         }
191
192         ieee80211_networks_free(ieee);
193         free_netdev(dev);
194 }
195
196 #ifdef CONFIG_IEEE80211_DEBUG
197
198 static int debug = 0;
199 u32 ieee80211_debug_level = 0;
200 struct proc_dir_entry *ieee80211_proc = NULL;
201
202 static int show_debug_level(char *page, char **start, off_t offset,
203                             int count, int *eof, void *data)
204 {
205         return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
206 }
207
208 static int store_debug_level(struct file *file, const char __user * buffer,
209                              unsigned long count, void *data)
210 {
211         char buf[] = "0x00000000\n";
212         unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
213         unsigned long val;
214
215         if (copy_from_user(buf, buffer, len))
216                 return count;
217         buf[len] = 0;
218         if (sscanf(buf, "%li", &val) != 1)
219                 printk(KERN_INFO DRV_NAME
220                        ": %s is not in hex or decimal form.\n", buf);
221         else
222                 ieee80211_debug_level = val;
223
224         return strnlen(buf, len);
225 }
226 #endif                          /* CONFIG_IEEE80211_DEBUG */
227
228 static int __init ieee80211_init(void)
229 {
230 #ifdef CONFIG_IEEE80211_DEBUG
231         struct proc_dir_entry *e;
232
233         ieee80211_debug_level = debug;
234         ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net);
235         if (ieee80211_proc == NULL) {
236                 IEEE80211_ERROR("Unable to create " DRV_NAME
237                                 " proc directory\n");
238                 return -EIO;
239         }
240         e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
241                               ieee80211_proc);
242         if (!e) {
243                 remove_proc_entry(DRV_NAME, proc_net);
244                 ieee80211_proc = NULL;
245                 return -EIO;
246         }
247         e->read_proc = show_debug_level;
248         e->write_proc = store_debug_level;
249         e->data = NULL;
250 #endif                          /* CONFIG_IEEE80211_DEBUG */
251
252         printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
253         printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
254
255         return 0;
256 }
257
258 static void __exit ieee80211_exit(void)
259 {
260 #ifdef CONFIG_IEEE80211_DEBUG
261         if (ieee80211_proc) {
262                 remove_proc_entry("debug_level", ieee80211_proc);
263                 remove_proc_entry(DRV_NAME, proc_net);
264                 ieee80211_proc = NULL;
265         }
266 #endif                          /* CONFIG_IEEE80211_DEBUG */
267 }
268
269 #ifdef CONFIG_IEEE80211_DEBUG
270 #include <linux/moduleparam.h>
271 module_param(debug, int, 0444);
272 MODULE_PARM_DESC(debug, "debug output mask");
273 #endif                          /* CONFIG_IEEE80211_DEBUG */
274
275 module_exit(ieee80211_exit);
276 module_init(ieee80211_init);
277
278 const char *escape_essid(const char *essid, u8 essid_len)
279 {
280         static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
281         const char *s = essid;
282         char *d = escaped;
283
284         if (ieee80211_is_empty_essid(essid, essid_len)) {
285                 memcpy(escaped, "<hidden>", sizeof("<hidden>"));
286                 return escaped;
287         }
288
289         essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
290         while (essid_len--) {
291                 if (*s == '\0') {
292                         *d++ = '\\';
293                         *d++ = '0';
294                         s++;
295                 } else {
296                         *d++ = *s++;
297                 }
298         }
299         *d = '\0';
300         return escaped;
301 }
302
303 EXPORT_SYMBOL(alloc_ieee80211);
304 EXPORT_SYMBOL(free_ieee80211);
305 EXPORT_SYMBOL(escape_essid);