blob: 00c3640b0f8af02a8bea21e0435ce4c616cc69e1 [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
Jouni Malinen85d32e72007-03-24 17:15:30 -07008 <j@w1.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
Jeff Garzikb4538722005-05-12 22:48:20 -040010
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>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020050#include <net/net_namespace.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040051#include <net/arp.h>
52
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040053#include "libipw.h"
Jeff Garzikb4538722005-05-12 22:48:20 -040054
James Ketrenos31696162005-09-21 11:58:46 -050055#define DRV_DESCRIPTION "802.11 data/management/control stack"
56#define DRV_NAME "ieee80211"
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040057#define DRV_VERSION LIBIPW_VERSION
James Ketrenos31696162005-09-21 11:58:46 -050058#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
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040065static int libipw_networks_allocate(struct libipw_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 =
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040071 kzalloc(MAX_NETWORK_COUNT * sizeof(struct libipw_network),
Jeff Garzik0edd5b42005-09-07 00:48:31 -040072 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
Jeff Garzikb4538722005-05-12 22:48:20 -040079 return 0;
80}
81
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040082void libipw_network_reset(struct libipw_network *network)
Zhu Yi15f38592006-01-19 16:21:35 +080083{
84 if (!network)
85 return;
86
87 if (network->ibss_dfs) {
88 kfree(network->ibss_dfs);
89 network->ibss_dfs = NULL;
90 }
91}
92
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040093static inline void libipw_networks_free(struct libipw_device *ieee)
Jeff Garzikb4538722005-05-12 22:48:20 -040094{
Zhu Yi15f38592006-01-19 16:21:35 +080095 int i;
96
Jeff Garzikb4538722005-05-12 22:48:20 -040097 if (!ieee->networks)
98 return;
Zhu Yi15f38592006-01-19 16:21:35 +080099
100 for (i = 0; i < MAX_NETWORK_COUNT; i++)
101 if (ieee->networks[i].ibss_dfs)
102 kfree(ieee->networks[i].ibss_dfs);
103
Jeff Garzikb4538722005-05-12 22:48:20 -0400104 kfree(ieee->networks);
105 ieee->networks = NULL;
106}
107
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400108void libipw_networks_age(struct libipw_device *ieee,
Dan Williamsc3d72b92009-02-11 13:26:06 -0500109 unsigned long age_secs)
110{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400111 struct libipw_network *network = NULL;
Dan Williamsc3d72b92009-02-11 13:26:06 -0500112 unsigned long flags;
113 unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
114
115 spin_lock_irqsave(&ieee->lock, flags);
116 list_for_each_entry(network, &ieee->network_list, list) {
117 network->last_scanned -= age_jiffies;
118 }
119 spin_unlock_irqrestore(&ieee->lock, flags);
120}
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400121EXPORT_SYMBOL(libipw_networks_age);
Dan Williamsc3d72b92009-02-11 13:26:06 -0500122
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400123static void libipw_networks_initialize(struct libipw_device *ieee)
Jeff Garzikb4538722005-05-12 22:48:20 -0400124{
125 int i;
126
127 INIT_LIST_HEAD(&ieee->network_free_list);
128 INIT_LIST_HEAD(&ieee->network_list);
129 for (i = 0; i < MAX_NETWORK_COUNT; i++)
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400130 list_add_tail(&ieee->networks[i].list,
131 &ieee->network_free_list);
Jeff Garzikb4538722005-05-12 22:48:20 -0400132}
133
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400134int libipw_change_mtu(struct net_device *dev, int new_mtu)
matthieu castet42a4cf92006-09-28 19:57:25 +0200135{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400136 if ((new_mtu < 68) || (new_mtu > LIBIPW_DATA_LEN))
matthieu castet42a4cf92006-09-28 19:57:25 +0200137 return -EINVAL;
138 dev->mtu = new_mtu;
139 return 0;
140}
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400141EXPORT_SYMBOL(libipw_change_mtu);
matthieu castet42a4cf92006-09-28 19:57:25 +0200142
Jeff Garzikb4538722005-05-12 22:48:20 -0400143struct net_device *alloc_ieee80211(int sizeof_priv)
144{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400145 struct libipw_device *ieee;
Jeff Garzikb4538722005-05-12 22:48:20 -0400146 struct net_device *dev;
147 int err;
148
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400149 LIBIPW_DEBUG_INFO("Initializing...\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400150
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400151 dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv);
Jeff Garzikb4538722005-05-12 22:48:20 -0400152 if (!dev) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400153 LIBIPW_ERROR("Unable to allocate network device.\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400154 goto failed;
155 }
156 ieee = netdev_priv(dev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400157
158 ieee->dev = dev;
159
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400160 err = libipw_networks_allocate(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400161 if (err) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400162 LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
Julia Lawalld92a8e82008-07-16 16:34:54 +0200163 goto failed_free_netdev;
Jeff Garzikb4538722005-05-12 22:48:20 -0400164 }
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400165 libipw_networks_initialize(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400166
167 /* Default fragmentation threshold is maximum payload size */
168 ieee->fts = DEFAULT_FTS;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500169 ieee->rts = DEFAULT_FTS;
Jeff Garzikb4538722005-05-12 22:48:20 -0400170 ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
171 ieee->open_wep = 1;
172
173 /* Default to enabling full open WEP with host based encrypt/decrypt */
174 ieee->host_encrypt = 1;
175 ieee->host_decrypt = 1;
James Ketrenosccd0fda2005-09-21 11:58:32 -0500176 ieee->host_mc_decrypt = 1;
177
James Ketrenos1264fc02005-09-21 11:54:53 -0500178 /* Host fragementation in Open mode. Default is enabled.
179 * Note: host fragmentation is always enabled if host encryption
180 * is enabled. For cards can do hardware encryption, they must do
181 * hardware fragmentation as well. So we don't need a variable
182 * like host_enc_frag. */
183 ieee->host_open_frag = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400184 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
Jeff Garzikb4538722005-05-12 22:48:20 -0400185
Jeff Garzikb4538722005-05-12 22:48:20 -0400186 spin_lock_init(&ieee->lock);
187
John W. Linville2ba4b322008-11-11 16:00:06 -0500188 lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
John W. Linville274bfb82008-10-29 11:35:05 -0400189
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400190 ieee->wpa_enabled = 0;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400191 ieee->drop_unencrypted = 0;
192 ieee->privacy_invoked = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400193
194 return dev;
195
Julia Lawalld92a8e82008-07-16 16:34:54 +0200196failed_free_netdev:
197 free_netdev(dev);
198failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400199 return NULL;
200}
201
Jeff Garzikb4538722005-05-12 22:48:20 -0400202void free_ieee80211(struct net_device *dev)
203{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400204 struct libipw_device *ieee = netdev_priv(dev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400205
John W. Linville2ba4b322008-11-11 16:00:06 -0500206 lib80211_crypt_info_free(&ieee->crypt_info);
Jeff Garzikb4538722005-05-12 22:48:20 -0400207
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400208 libipw_networks_free(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400209 free_netdev(dev);
210}
211
Helmut Schaa37561622009-03-06 12:02:25 +0100212#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400213
214static int debug = 0;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400215u32 libipw_debug_level = 0;
216EXPORT_SYMBOL_GPL(libipw_debug_level);
217static struct proc_dir_entry *libipw_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400218
219static int show_debug_level(char *page, char **start, off_t offset,
220 int count, int *eof, void *data)
221{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400222 return snprintf(page, count, "0x%08X\n", libipw_debug_level);
Jeff Garzikb4538722005-05-12 22:48:20 -0400223}
224
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400225static int store_debug_level(struct file *file, const char __user * buffer,
Jeff Garzikb4538722005-05-12 22:48:20 -0400226 unsigned long count, void *data)
227{
James Ketrenos262d8e42005-09-13 17:42:53 -0500228 char buf[] = "0x00000000\n";
229 unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
Jeff Garzikb4538722005-05-12 22:48:20 -0400230 unsigned long val;
231
James Ketrenos262d8e42005-09-13 17:42:53 -0500232 if (copy_from_user(buf, buffer, len))
Jeff Garzikb4538722005-05-12 22:48:20 -0400233 return count;
James Ketrenos262d8e42005-09-13 17:42:53 -0500234 buf[len] = 0;
235 if (sscanf(buf, "%li", &val) != 1)
Jeff Garzikb4538722005-05-12 22:48:20 -0400236 printk(KERN_INFO DRV_NAME
237 ": %s is not in hex or decimal form.\n", buf);
238 else
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400239 libipw_debug_level = val;
Jeff Garzikb4538722005-05-12 22:48:20 -0400240
James Ketrenos262d8e42005-09-13 17:42:53 -0500241 return strnlen(buf, len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400242}
Helmut Schaa37561622009-03-06 12:02:25 +0100243#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400244
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400245static int __init libipw_init(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400246{
Helmut Schaa37561622009-03-06 12:02:25 +0100247#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400248 struct proc_dir_entry *e;
249
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400250 libipw_debug_level = debug;
251 libipw_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
252 if (libipw_proc == NULL) {
253 LIBIPW_ERROR("Unable to create " DRV_NAME
Jeff Garzikb4538722005-05-12 22:48:20 -0400254 " proc directory\n");
255 return -EIO;
256 }
257 e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400258 libipw_proc);
Jeff Garzikb4538722005-05-12 22:48:20 -0400259 if (!e) {
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200260 remove_proc_entry(DRV_NAME, init_net.proc_net);
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400261 libipw_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400262 return -EIO;
263 }
264 e->read_proc = show_debug_level;
265 e->write_proc = store_debug_level;
266 e->data = NULL;
Helmut Schaa37561622009-03-06 12:02:25 +0100267#endif /* CONFIG_LIBIPW_DEBUG */
James Ketrenos31696162005-09-21 11:58:46 -0500268
269 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
270 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400271
272 return 0;
273}
274
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400275static void __exit libipw_exit(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400276{
Helmut Schaa37561622009-03-06 12:02:25 +0100277#ifdef CONFIG_LIBIPW_DEBUG
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400278 if (libipw_proc) {
279 remove_proc_entry("debug_level", libipw_proc);
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200280 remove_proc_entry(DRV_NAME, init_net.proc_net);
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400281 libipw_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400282 }
Helmut Schaa37561622009-03-06 12:02:25 +0100283#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400284}
285
Helmut Schaa37561622009-03-06 12:02:25 +0100286#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400287#include <linux/moduleparam.h>
288module_param(debug, int, 0444);
289MODULE_PARM_DESC(debug, "debug output mask");
Helmut Schaa37561622009-03-06 12:02:25 +0100290#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400291
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400292module_exit(libipw_exit);
293module_init(libipw_init);
Jeff Garzikb4538722005-05-12 22:48:20 -0400294
295EXPORT_SYMBOL(alloc_ieee80211);
296EXPORT_SYMBOL(free_ieee80211);