blob: 2b14c2f3e21d89330a36d45dffc51f9358e3a949 [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>
Jeff Garzikb4538722005-05-12 22:48:20 -040034#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>
Jeff Garzikb4538722005-05-12 22:48:20 -040042#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>
Jeff Garzikb4538722005-05-12 22:48:20 -040047#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
James Ketrenos31696162005-09-21 11:58:46 -050054#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>"
Jeff Garzikb4538722005-05-12 22:48:20 -040058
James Ketrenos31696162005-09-21 11:58:46 -050059MODULE_VERSION(DRV_VERSION);
60MODULE_DESCRIPTION(DRV_DESCRIPTION);
61MODULE_AUTHOR(DRV_COPYRIGHT);
62MODULE_LICENSE("GPL");
Jeff Garzikb4538722005-05-12 22:48:20 -040063
Arjan van de Ven858119e2006-01-14 13:20:43 -080064static int ieee80211_networks_allocate(struct ieee80211_device *ieee)
Jeff Garzikb4538722005-05-12 22:48:20 -040065{
66 if (ieee->networks)
67 return 0;
68
Jeff Garzik0edd5b42005-09-07 00:48:31 -040069 ieee->networks =
70 kmalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
71 GFP_KERNEL);
Jeff Garzikb4538722005-05-12 22:48:20 -040072 if (!ieee->networks) {
73 printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
74 ieee->dev->name);
75 return -ENOMEM;
76 }
77
78 memset(ieee->networks, 0,
79 MAX_NETWORK_COUNT * sizeof(struct ieee80211_network));
80
81 return 0;
82}
83
Zhu Yi15f38592006-01-19 16:21:35 +080084void ieee80211_network_reset(struct ieee80211_network *network)
85{
86 if (!network)
87 return;
88
89 if (network->ibss_dfs) {
90 kfree(network->ibss_dfs);
91 network->ibss_dfs = NULL;
92 }
93}
94
Jeff Garzikb4538722005-05-12 22:48:20 -040095static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
96{
Zhu Yi15f38592006-01-19 16:21:35 +080097 int i;
98
Jeff Garzikb4538722005-05-12 22:48:20 -040099 if (!ieee->networks)
100 return;
Zhu Yi15f38592006-01-19 16:21:35 +0800101
102 for (i = 0; i < MAX_NETWORK_COUNT; i++)
103 if (ieee->networks[i].ibss_dfs)
104 kfree(ieee->networks[i].ibss_dfs);
105
Jeff Garzikb4538722005-05-12 22:48:20 -0400106 kfree(ieee->networks);
107 ieee->networks = NULL;
108}
109
Arjan van de Ven858119e2006-01-14 13:20:43 -0800110static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
Jeff Garzikb4538722005-05-12 22:48:20 -0400111{
112 int i;
113
114 INIT_LIST_HEAD(&ieee->network_free_list);
115 INIT_LIST_HEAD(&ieee->network_list);
116 for (i = 0; i < MAX_NETWORK_COUNT; i++)
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400117 list_add_tail(&ieee->networks[i].list,
118 &ieee->network_free_list);
Jeff Garzikb4538722005-05-12 22:48:20 -0400119}
120
matthieu castet42a4cf92006-09-28 19:57:25 +0200121static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
122{
123 if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN))
124 return -EINVAL;
125 dev->mtu = new_mtu;
126 return 0;
127}
128
Jeff Garzikb4538722005-05-12 22:48:20 -0400129struct net_device *alloc_ieee80211(int sizeof_priv)
130{
131 struct ieee80211_device *ieee;
132 struct net_device *dev;
133 int err;
134
135 IEEE80211_DEBUG_INFO("Initializing...\n");
136
137 dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
138 if (!dev) {
139 IEEE80211_ERROR("Unable to network device.\n");
140 goto failed;
141 }
142 ieee = netdev_priv(dev);
143 dev->hard_start_xmit = ieee80211_xmit;
matthieu castet42a4cf92006-09-28 19:57:25 +0200144 dev->change_mtu = ieee80211_change_mtu;
Jeff Garzikb4538722005-05-12 22:48:20 -0400145
146 ieee->dev = dev;
147
148 err = ieee80211_networks_allocate(ieee);
149 if (err) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400150 IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
Jeff Garzikb4538722005-05-12 22:48:20 -0400151 goto failed;
152 }
153 ieee80211_networks_initialize(ieee);
154
155 /* Default fragmentation threshold is maximum payload size */
156 ieee->fts = DEFAULT_FTS;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500157 ieee->rts = DEFAULT_FTS;
Jeff Garzikb4538722005-05-12 22:48:20 -0400158 ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
159 ieee->open_wep = 1;
160
161 /* Default to enabling full open WEP with host based encrypt/decrypt */
162 ieee->host_encrypt = 1;
163 ieee->host_decrypt = 1;
James Ketrenosccd0fda2005-09-21 11:58:32 -0500164 ieee->host_mc_decrypt = 1;
165
James Ketrenos1264fc02005-09-21 11:54:53 -0500166 /* Host fragementation in Open mode. Default is enabled.
167 * Note: host fragmentation is always enabled if host encryption
168 * is enabled. For cards can do hardware encryption, they must do
169 * hardware fragmentation as well. So we don't need a variable
170 * like host_enc_frag. */
171 ieee->host_open_frag = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400172 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
Jeff Garzikb4538722005-05-12 22:48:20 -0400173
174 INIT_LIST_HEAD(&ieee->crypt_deinit_list);
175 init_timer(&ieee->crypt_deinit_timer);
176 ieee->crypt_deinit_timer.data = (unsigned long)ieee;
177 ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
James Ketrenos0ad0c3c2005-09-21 11:54:15 -0500178 ieee->crypt_quiesced = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400179
180 spin_lock_init(&ieee->lock);
181
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400182 ieee->wpa_enabled = 0;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400183 ieee->drop_unencrypted = 0;
184 ieee->privacy_invoked = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400185
186 return dev;
187
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400188 failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400189 if (dev)
190 free_netdev(dev);
191 return NULL;
192}
193
Jeff Garzikb4538722005-05-12 22:48:20 -0400194void free_ieee80211(struct net_device *dev)
195{
196 struct ieee80211_device *ieee = netdev_priv(dev);
197
198 int i;
199
James Ketrenos0ad0c3c2005-09-21 11:54:15 -0500200 ieee80211_crypt_quiescing(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400201 del_timer_sync(&ieee->crypt_deinit_timer);
202 ieee80211_crypt_deinit_entries(ieee, 1);
203
204 for (i = 0; i < WEP_KEYS; i++) {
205 struct ieee80211_crypt_data *crypt = ieee->crypt[i];
206 if (crypt) {
207 if (crypt->ops) {
208 crypt->ops->deinit(crypt->priv);
209 module_put(crypt->ops->owner);
210 }
211 kfree(crypt);
212 ieee->crypt[i] = NULL;
213 }
214 }
215
216 ieee80211_networks_free(ieee);
217 free_netdev(dev);
218}
219
220#ifdef CONFIG_IEEE80211_DEBUG
221
222static int debug = 0;
223u32 ieee80211_debug_level = 0;
Johannes Bergb7cffb02006-01-04 20:58:10 +0100224static struct proc_dir_entry *ieee80211_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400225
226static int show_debug_level(char *page, char **start, off_t offset,
227 int count, int *eof, void *data)
228{
229 return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
230}
231
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400232static int store_debug_level(struct file *file, const char __user * buffer,
Jeff Garzikb4538722005-05-12 22:48:20 -0400233 unsigned long count, void *data)
234{
James Ketrenos262d8e42005-09-13 17:42:53 -0500235 char buf[] = "0x00000000\n";
236 unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
Jeff Garzikb4538722005-05-12 22:48:20 -0400237 unsigned long val;
238
James Ketrenos262d8e42005-09-13 17:42:53 -0500239 if (copy_from_user(buf, buffer, len))
Jeff Garzikb4538722005-05-12 22:48:20 -0400240 return count;
James Ketrenos262d8e42005-09-13 17:42:53 -0500241 buf[len] = 0;
242 if (sscanf(buf, "%li", &val) != 1)
Jeff Garzikb4538722005-05-12 22:48:20 -0400243 printk(KERN_INFO DRV_NAME
244 ": %s is not in hex or decimal form.\n", buf);
245 else
246 ieee80211_debug_level = val;
247
James Ketrenos262d8e42005-09-13 17:42:53 -0500248 return strnlen(buf, len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400249}
James Ketrenos31696162005-09-21 11:58:46 -0500250#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400251
252static int __init ieee80211_init(void)
253{
James Ketrenos31696162005-09-21 11:58:46 -0500254#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400255 struct proc_dir_entry *e;
256
257 ieee80211_debug_level = debug;
Al Viro66600222005-09-28 22:32:57 +0100258 ieee80211_proc = proc_mkdir(DRV_NAME, proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400259 if (ieee80211_proc == NULL) {
260 IEEE80211_ERROR("Unable to create " DRV_NAME
261 " proc directory\n");
262 return -EIO;
263 }
264 e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
265 ieee80211_proc);
266 if (!e) {
267 remove_proc_entry(DRV_NAME, proc_net);
268 ieee80211_proc = NULL;
269 return -EIO;
270 }
271 e->read_proc = show_debug_level;
272 e->write_proc = store_debug_level;
273 e->data = NULL;
James Ketrenos31696162005-09-21 11:58:46 -0500274#endif /* CONFIG_IEEE80211_DEBUG */
275
276 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
277 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400278
279 return 0;
280}
281
282static void __exit ieee80211_exit(void)
283{
James Ketrenos31696162005-09-21 11:58:46 -0500284#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400285 if (ieee80211_proc) {
286 remove_proc_entry("debug_level", ieee80211_proc);
287 remove_proc_entry(DRV_NAME, proc_net);
288 ieee80211_proc = NULL;
289 }
James Ketrenos31696162005-09-21 11:58:46 -0500290#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400291}
292
James Ketrenos31696162005-09-21 11:58:46 -0500293#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400294#include <linux/moduleparam.h>
295module_param(debug, int, 0444);
296MODULE_PARM_DESC(debug, "debug output mask");
James Ketrenos31696162005-09-21 11:58:46 -0500297#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400298
Jeff Garzikb4538722005-05-12 22:48:20 -0400299module_exit(ieee80211_exit);
300module_init(ieee80211_init);
Jeff Garzikb4538722005-05-12 22:48:20 -0400301
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400302const char *escape_essid(const char *essid, u8 essid_len)
303{
Jiri Bence88187e2005-08-25 20:00:53 -0400304 static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
305 const char *s = essid;
306 char *d = escaped;
307
308 if (ieee80211_is_empty_essid(essid, essid_len)) {
309 memcpy(escaped, "<hidden>", sizeof("<hidden>"));
310 return escaped;
311 }
312
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400313 essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
Jiri Bence88187e2005-08-25 20:00:53 -0400314 while (essid_len--) {
315 if (*s == '\0') {
316 *d++ = '\\';
317 *d++ = '0';
318 s++;
319 } else {
320 *d++ = *s++;
321 }
322 }
323 *d = '\0';
324 return escaped;
325}
326
Jeff Garzikb4538722005-05-12 22:48:20 -0400327EXPORT_SYMBOL(alloc_ieee80211);
328EXPORT_SYMBOL(free_ieee80211);
Jiri Bence88187e2005-08-25 20:00:53 -0400329EXPORT_SYMBOL(escape_essid);