blob: 92a26922e792d73721a2e4ca0ed3c2c3a125fcb5 [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);
Stephen Hemmingerd5b3b9a2009-03-20 19:36:39 +0000157#ifdef CONFIG_COMPAT_NET_DEV_OPS
Jeff Garzikb4538722005-05-12 22:48:20 -0400158 dev->hard_start_xmit = ieee80211_xmit;
matthieu castet42a4cf92006-09-28 19:57:25 +0200159 dev->change_mtu = ieee80211_change_mtu;
Stephen Hemmingerd5b3b9a2009-03-20 19:36:39 +0000160#endif
Jeff Garzikb4538722005-05-12 22:48:20 -0400161
162 ieee->dev = dev;
163
164 err = ieee80211_networks_allocate(ieee);
165 if (err) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400166 IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
Julia Lawalld92a8e82008-07-16 16:34:54 +0200167 goto failed_free_netdev;
Jeff Garzikb4538722005-05-12 22:48:20 -0400168 }
169 ieee80211_networks_initialize(ieee);
170
171 /* Default fragmentation threshold is maximum payload size */
172 ieee->fts = DEFAULT_FTS;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500173 ieee->rts = DEFAULT_FTS;
Jeff Garzikb4538722005-05-12 22:48:20 -0400174 ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
175 ieee->open_wep = 1;
176
177 /* Default to enabling full open WEP with host based encrypt/decrypt */
178 ieee->host_encrypt = 1;
179 ieee->host_decrypt = 1;
James Ketrenosccd0fda2005-09-21 11:58:32 -0500180 ieee->host_mc_decrypt = 1;
181
James Ketrenos1264fc02005-09-21 11:54:53 -0500182 /* Host fragementation in Open mode. Default is enabled.
183 * Note: host fragmentation is always enabled if host encryption
184 * is enabled. For cards can do hardware encryption, they must do
185 * hardware fragmentation as well. So we don't need a variable
186 * like host_enc_frag. */
187 ieee->host_open_frag = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400188 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
Jeff Garzikb4538722005-05-12 22:48:20 -0400189
Jeff Garzikb4538722005-05-12 22:48:20 -0400190 spin_lock_init(&ieee->lock);
191
John W. Linville2ba4b322008-11-11 16:00:06 -0500192 lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
John W. Linville274bfb82008-10-29 11:35:05 -0400193
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400194 ieee->wpa_enabled = 0;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400195 ieee->drop_unencrypted = 0;
196 ieee->privacy_invoked = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400197
198 return dev;
199
Julia Lawalld92a8e82008-07-16 16:34:54 +0200200failed_free_netdev:
201 free_netdev(dev);
202failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400203 return NULL;
204}
205
Jeff Garzikb4538722005-05-12 22:48:20 -0400206void free_ieee80211(struct net_device *dev)
207{
208 struct ieee80211_device *ieee = netdev_priv(dev);
209
John W. Linville2ba4b322008-11-11 16:00:06 -0500210 lib80211_crypt_info_free(&ieee->crypt_info);
Jeff Garzikb4538722005-05-12 22:48:20 -0400211
212 ieee80211_networks_free(ieee);
213 free_netdev(dev);
214}
215
Helmut Schaa37561622009-03-06 12:02:25 +0100216#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400217
218static int debug = 0;
219u32 ieee80211_debug_level = 0;
Larry Finger2933d422007-04-17 10:28:47 -0500220EXPORT_SYMBOL_GPL(ieee80211_debug_level);
Johannes Bergb7cffb02006-01-04 20:58:10 +0100221static struct proc_dir_entry *ieee80211_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400222
223static int show_debug_level(char *page, char **start, off_t offset,
224 int count, int *eof, void *data)
225{
226 return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
227}
228
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400229static int store_debug_level(struct file *file, const char __user * buffer,
Jeff Garzikb4538722005-05-12 22:48:20 -0400230 unsigned long count, void *data)
231{
James Ketrenos262d8e42005-09-13 17:42:53 -0500232 char buf[] = "0x00000000\n";
233 unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
Jeff Garzikb4538722005-05-12 22:48:20 -0400234 unsigned long val;
235
James Ketrenos262d8e42005-09-13 17:42:53 -0500236 if (copy_from_user(buf, buffer, len))
Jeff Garzikb4538722005-05-12 22:48:20 -0400237 return count;
James Ketrenos262d8e42005-09-13 17:42:53 -0500238 buf[len] = 0;
239 if (sscanf(buf, "%li", &val) != 1)
Jeff Garzikb4538722005-05-12 22:48:20 -0400240 printk(KERN_INFO DRV_NAME
241 ": %s is not in hex or decimal form.\n", buf);
242 else
243 ieee80211_debug_level = val;
244
James Ketrenos262d8e42005-09-13 17:42:53 -0500245 return strnlen(buf, len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400246}
Helmut Schaa37561622009-03-06 12:02:25 +0100247#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400248
249static int __init ieee80211_init(void)
250{
Helmut Schaa37561622009-03-06 12:02:25 +0100251#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400252 struct proc_dir_entry *e;
253
254 ieee80211_debug_level = debug;
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200255 ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400256 if (ieee80211_proc == NULL) {
257 IEEE80211_ERROR("Unable to create " DRV_NAME
258 " proc directory\n");
259 return -EIO;
260 }
261 e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
262 ieee80211_proc);
263 if (!e) {
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200264 remove_proc_entry(DRV_NAME, init_net.proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400265 ieee80211_proc = NULL;
266 return -EIO;
267 }
268 e->read_proc = show_debug_level;
269 e->write_proc = store_debug_level;
270 e->data = NULL;
Helmut Schaa37561622009-03-06 12:02:25 +0100271#endif /* CONFIG_LIBIPW_DEBUG */
James Ketrenos31696162005-09-21 11:58:46 -0500272
273 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
274 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400275
276 return 0;
277}
278
279static void __exit ieee80211_exit(void)
280{
Helmut Schaa37561622009-03-06 12:02:25 +0100281#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400282 if (ieee80211_proc) {
283 remove_proc_entry("debug_level", ieee80211_proc);
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200284 remove_proc_entry(DRV_NAME, init_net.proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400285 ieee80211_proc = NULL;
286 }
Helmut Schaa37561622009-03-06 12:02:25 +0100287#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400288}
289
Helmut Schaa37561622009-03-06 12:02:25 +0100290#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400291#include <linux/moduleparam.h>
292module_param(debug, int, 0444);
293MODULE_PARM_DESC(debug, "debug output mask");
Helmut Schaa37561622009-03-06 12:02:25 +0100294#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400295
Jeff Garzikb4538722005-05-12 22:48:20 -0400296module_exit(ieee80211_exit);
297module_init(ieee80211_init);
Jeff Garzikb4538722005-05-12 22:48:20 -0400298
299EXPORT_SYMBOL(alloc_ieee80211);
300EXPORT_SYMBOL(free_ieee80211);