blob: 5f67c684afc24643e3d3eaee23482b05c9eabdb4 [file] [log] [blame]
Jeff Garzikb4538722005-05-12 22:48:20 -04001/*******************************************************************************
2
James Ketrenosebeaddc2005-09-21 11:58:43 -05003 Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
Jeff Garzikb4538722005-05-12 22:48:20 -04004
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>
Jeff Garzikb4538722005-05-12 22:48:20 -040043#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>
Jeff Garzikb4538722005-05-12 22:48:20 -040048#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
James Ketrenos31696162005-09-21 11:58:46 -050055#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>"
Jeff Garzikb4538722005-05-12 22:48:20 -040059
James Ketrenos31696162005-09-21 11:58:46 -050060MODULE_VERSION(DRV_VERSION);
61MODULE_DESCRIPTION(DRV_DESCRIPTION);
62MODULE_AUTHOR(DRV_COPYRIGHT);
63MODULE_LICENSE("GPL");
Jeff Garzikb4538722005-05-12 22:48:20 -040064
Arjan van de Ven858119e2006-01-14 13:20:43 -080065static int ieee80211_networks_allocate(struct ieee80211_device *ieee)
Jeff Garzikb4538722005-05-12 22:48:20 -040066{
67 if (ieee->networks)
68 return 0;
69
Jeff Garzik0edd5b42005-09-07 00:48:31 -040070 ieee->networks =
71 kmalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
72 GFP_KERNEL);
Jeff Garzikb4538722005-05-12 22:48:20 -040073 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
Zhu Yi15f38592006-01-19 16:21:35 +080085void ieee80211_network_reset(struct ieee80211_network *network)
86{
87 if (!network)
88 return;
89
90 if (network->ibss_dfs) {
91 kfree(network->ibss_dfs);
92 network->ibss_dfs = NULL;
93 }
94}
95
Jeff Garzikb4538722005-05-12 22:48:20 -040096static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
97{
Zhu Yi15f38592006-01-19 16:21:35 +080098 int i;
99
Jeff Garzikb4538722005-05-12 22:48:20 -0400100 if (!ieee->networks)
101 return;
Zhu Yi15f38592006-01-19 16:21:35 +0800102
103 for (i = 0; i < MAX_NETWORK_COUNT; i++)
104 if (ieee->networks[i].ibss_dfs)
105 kfree(ieee->networks[i].ibss_dfs);
106
Jeff Garzikb4538722005-05-12 22:48:20 -0400107 kfree(ieee->networks);
108 ieee->networks = NULL;
109}
110
Arjan van de Ven858119e2006-01-14 13:20:43 -0800111static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
Jeff Garzikb4538722005-05-12 22:48:20 -0400112{
113 int i;
114
115 INIT_LIST_HEAD(&ieee->network_free_list);
116 INIT_LIST_HEAD(&ieee->network_list);
117 for (i = 0; i < MAX_NETWORK_COUNT; i++)
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400118 list_add_tail(&ieee->networks[i].list,
119 &ieee->network_free_list);
Jeff Garzikb4538722005-05-12 22:48:20 -0400120}
121
Jeff Garzikb4538722005-05-12 22:48:20 -0400122struct net_device *alloc_ieee80211(int sizeof_priv)
123{
124 struct ieee80211_device *ieee;
125 struct net_device *dev;
126 int err;
127
128 IEEE80211_DEBUG_INFO("Initializing...\n");
129
130 dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
131 if (!dev) {
132 IEEE80211_ERROR("Unable to network device.\n");
133 goto failed;
134 }
135 ieee = netdev_priv(dev);
136 dev->hard_start_xmit = ieee80211_xmit;
137
138 ieee->dev = dev;
139
140 err = ieee80211_networks_allocate(ieee);
141 if (err) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400142 IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
Jeff Garzikb4538722005-05-12 22:48:20 -0400143 goto failed;
144 }
145 ieee80211_networks_initialize(ieee);
146
147 /* Default fragmentation threshold is maximum payload size */
148 ieee->fts = DEFAULT_FTS;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500149 ieee->rts = DEFAULT_FTS;
Jeff Garzikb4538722005-05-12 22:48:20 -0400150 ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
151 ieee->open_wep = 1;
152
153 /* Default to enabling full open WEP with host based encrypt/decrypt */
154 ieee->host_encrypt = 1;
155 ieee->host_decrypt = 1;
James Ketrenosccd0fda2005-09-21 11:58:32 -0500156 ieee->host_mc_decrypt = 1;
157
James Ketrenos1264fc02005-09-21 11:54:53 -0500158 /* Host fragementation in Open mode. Default is enabled.
159 * Note: host fragmentation is always enabled if host encryption
160 * is enabled. For cards can do hardware encryption, they must do
161 * hardware fragmentation as well. So we don't need a variable
162 * like host_enc_frag. */
163 ieee->host_open_frag = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400164 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
Jeff Garzikb4538722005-05-12 22:48:20 -0400165
166 INIT_LIST_HEAD(&ieee->crypt_deinit_list);
167 init_timer(&ieee->crypt_deinit_timer);
168 ieee->crypt_deinit_timer.data = (unsigned long)ieee;
169 ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
James Ketrenos0ad0c3c2005-09-21 11:54:15 -0500170 ieee->crypt_quiesced = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400171
172 spin_lock_init(&ieee->lock);
173
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400174 ieee->wpa_enabled = 0;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400175 ieee->drop_unencrypted = 0;
176 ieee->privacy_invoked = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400177
178 return dev;
179
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400180 failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400181 if (dev)
182 free_netdev(dev);
183 return NULL;
184}
185
Jeff Garzikb4538722005-05-12 22:48:20 -0400186void free_ieee80211(struct net_device *dev)
187{
188 struct ieee80211_device *ieee = netdev_priv(dev);
189
190 int i;
191
James Ketrenos0ad0c3c2005-09-21 11:54:15 -0500192 ieee80211_crypt_quiescing(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400193 del_timer_sync(&ieee->crypt_deinit_timer);
194 ieee80211_crypt_deinit_entries(ieee, 1);
195
196 for (i = 0; i < WEP_KEYS; i++) {
197 struct ieee80211_crypt_data *crypt = ieee->crypt[i];
198 if (crypt) {
199 if (crypt->ops) {
200 crypt->ops->deinit(crypt->priv);
201 module_put(crypt->ops->owner);
202 }
203 kfree(crypt);
204 ieee->crypt[i] = NULL;
205 }
206 }
207
208 ieee80211_networks_free(ieee);
209 free_netdev(dev);
210}
211
212#ifdef CONFIG_IEEE80211_DEBUG
213
214static int debug = 0;
215u32 ieee80211_debug_level = 0;
216struct proc_dir_entry *ieee80211_proc = NULL;
217
218static int show_debug_level(char *page, char **start, off_t offset,
219 int count, int *eof, void *data)
220{
221 return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
222}
223
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400224static int store_debug_level(struct file *file, const char __user * buffer,
Jeff Garzikb4538722005-05-12 22:48:20 -0400225 unsigned long count, void *data)
226{
James Ketrenos262d8e42005-09-13 17:42:53 -0500227 char buf[] = "0x00000000\n";
228 unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
Jeff Garzikb4538722005-05-12 22:48:20 -0400229 unsigned long val;
230
James Ketrenos262d8e42005-09-13 17:42:53 -0500231 if (copy_from_user(buf, buffer, len))
Jeff Garzikb4538722005-05-12 22:48:20 -0400232 return count;
James Ketrenos262d8e42005-09-13 17:42:53 -0500233 buf[len] = 0;
234 if (sscanf(buf, "%li", &val) != 1)
Jeff Garzikb4538722005-05-12 22:48:20 -0400235 printk(KERN_INFO DRV_NAME
236 ": %s is not in hex or decimal form.\n", buf);
237 else
238 ieee80211_debug_level = val;
239
James Ketrenos262d8e42005-09-13 17:42:53 -0500240 return strnlen(buf, len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400241}
James Ketrenos31696162005-09-21 11:58:46 -0500242#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400243
244static int __init ieee80211_init(void)
245{
James Ketrenos31696162005-09-21 11:58:46 -0500246#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400247 struct proc_dir_entry *e;
248
249 ieee80211_debug_level = debug;
Al Viro66600222005-09-28 22:32:57 +0100250 ieee80211_proc = proc_mkdir(DRV_NAME, proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400251 if (ieee80211_proc == NULL) {
252 IEEE80211_ERROR("Unable to create " DRV_NAME
253 " proc directory\n");
254 return -EIO;
255 }
256 e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
257 ieee80211_proc);
258 if (!e) {
259 remove_proc_entry(DRV_NAME, proc_net);
260 ieee80211_proc = NULL;
261 return -EIO;
262 }
263 e->read_proc = show_debug_level;
264 e->write_proc = store_debug_level;
265 e->data = NULL;
James Ketrenos31696162005-09-21 11:58:46 -0500266#endif /* CONFIG_IEEE80211_DEBUG */
267
268 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
269 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400270
271 return 0;
272}
273
274static void __exit ieee80211_exit(void)
275{
James Ketrenos31696162005-09-21 11:58:46 -0500276#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400277 if (ieee80211_proc) {
278 remove_proc_entry("debug_level", ieee80211_proc);
279 remove_proc_entry(DRV_NAME, proc_net);
280 ieee80211_proc = NULL;
281 }
James Ketrenos31696162005-09-21 11:58:46 -0500282#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400283}
284
James Ketrenos31696162005-09-21 11:58:46 -0500285#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400286#include <linux/moduleparam.h>
287module_param(debug, int, 0444);
288MODULE_PARM_DESC(debug, "debug output mask");
James Ketrenos31696162005-09-21 11:58:46 -0500289#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400290
Jeff Garzikb4538722005-05-12 22:48:20 -0400291module_exit(ieee80211_exit);
292module_init(ieee80211_init);
Jeff Garzikb4538722005-05-12 22:48:20 -0400293
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400294const char *escape_essid(const char *essid, u8 essid_len)
295{
Jiri Bence88187e2005-08-25 20:00:53 -0400296 static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
297 const char *s = essid;
298 char *d = escaped;
299
300 if (ieee80211_is_empty_essid(essid, essid_len)) {
301 memcpy(escaped, "<hidden>", sizeof("<hidden>"));
302 return escaped;
303 }
304
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400305 essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
Jiri Bence88187e2005-08-25 20:00:53 -0400306 while (essid_len--) {
307 if (*s == '\0') {
308 *d++ = '\\';
309 *d++ = '0';
310 s++;
311 } else {
312 *d++ = *s++;
313 }
314 }
315 *d = '\0';
316 return escaped;
317}
318
Jeff Garzikb4538722005-05-12 22:48:20 -0400319EXPORT_SYMBOL(alloc_ieee80211);
320EXPORT_SYMBOL(free_ieee80211);
Jiri Bence88187e2005-08-25 20:00:53 -0400321EXPORT_SYMBOL(escape_essid);