blob: 8ce6e961c5da08396a1805f5b46d428865b84924 [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
Dan Williamsf3734ee2009-02-12 12:32:55 -050053#include "ieee80211.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"
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 =
Arnaldo Carvalho de Melo571d6ee2006-11-21 01:26:49 -020071 kzalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_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
Zhu Yi15f38592006-01-19 16:21:35 +080082void ieee80211_network_reset(struct ieee80211_network *network)
83{
84 if (!network)
85 return;
86
87 if (network->ibss_dfs) {
88 kfree(network->ibss_dfs);
89 network->ibss_dfs = NULL;
90 }
91}
92
Jeff Garzikb4538722005-05-12 22:48:20 -040093static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
94{
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
Dan Williamsc3d72b92009-02-11 13:26:06 -0500108void ieee80211_networks_age(struct ieee80211_device *ieee,
109 unsigned long age_secs)
110{
111 struct ieee80211_network *network = NULL;
112 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}
121EXPORT_SYMBOL(ieee80211_networks_age);
122
Arjan van de Ven858119e2006-01-14 13:20:43 -0800123static void ieee80211_networks_initialize(struct ieee80211_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
Stephen Hemmingerd5b3b9a2009-03-20 19:36:39 +0000134int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
matthieu castet42a4cf92006-09-28 19:57:25 +0200135{
136 if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN))
137 return -EINVAL;
138 dev->mtu = new_mtu;
139 return 0;
140}
Stephen Hemmingerd5b3b9a2009-03-20 19:36:39 +0000141EXPORT_SYMBOL(ieee80211_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{
145 struct ieee80211_device *ieee;
146 struct net_device *dev;
147 int err;
148
149 IEEE80211_DEBUG_INFO("Initializing...\n");
150
151 dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
152 if (!dev) {
Akinobu Mitaa76193d2007-05-27 23:25:00 +0900153 IEEE80211_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
160 err = ieee80211_networks_allocate(ieee);
161 if (err) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400162 IEEE80211_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 }
165 ieee80211_networks_initialize(ieee);
166
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{
204 struct ieee80211_device *ieee = netdev_priv(dev);
205
John W. Linville2ba4b322008-11-11 16:00:06 -0500206 lib80211_crypt_info_free(&ieee->crypt_info);
Jeff Garzikb4538722005-05-12 22:48:20 -0400207
208 ieee80211_networks_free(ieee);
209 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;
215u32 ieee80211_debug_level = 0;
Larry Finger2933d422007-04-17 10:28:47 -0500216EXPORT_SYMBOL_GPL(ieee80211_debug_level);
Johannes Bergb7cffb02006-01-04 20:58:10 +0100217static struct proc_dir_entry *ieee80211_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{
222 return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
223}
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
239 ieee80211_debug_level = val;
240
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
245static int __init ieee80211_init(void)
246{
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
250 ieee80211_debug_level = debug;
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200251 ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400252 if (ieee80211_proc == NULL) {
253 IEEE80211_ERROR("Unable to create " DRV_NAME
254 " proc directory\n");
255 return -EIO;
256 }
257 e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
258 ieee80211_proc);
259 if (!e) {
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200260 remove_proc_entry(DRV_NAME, init_net.proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400261 ieee80211_proc = NULL;
262 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
275static void __exit ieee80211_exit(void)
276{
Helmut Schaa37561622009-03-06 12:02:25 +0100277#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400278 if (ieee80211_proc) {
279 remove_proc_entry("debug_level", ieee80211_proc);
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200280 remove_proc_entry(DRV_NAME, init_net.proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400281 ieee80211_proc = NULL;
282 }
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
Jeff Garzikb4538722005-05-12 22:48:20 -0400292module_exit(ieee80211_exit);
293module_init(ieee80211_init);
Jeff Garzikb4538722005-05-12 22:48:20 -0400294
295EXPORT_SYMBOL(alloc_ieee80211);
296EXPORT_SYMBOL(free_ieee80211);