blob: f4803fc054138b9b2740d48fd6249e789b4d677f [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
matthieu castet42a4cf92006-09-28 19:57:25 +0200134static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
135{
136 if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN))
137 return -EINVAL;
138 dev->mtu = new_mtu;
139 return 0;
140}
141
Daniel Drake718cc4c2006-11-22 03:15:46 +0000142static struct net_device_stats *ieee80211_generic_get_stats(
143 struct net_device *dev)
144{
145 struct ieee80211_device *ieee = netdev_priv(dev);
146 return &ieee->stats;
147}
148
Jeff Garzikb4538722005-05-12 22:48:20 -0400149struct net_device *alloc_ieee80211(int sizeof_priv)
150{
151 struct ieee80211_device *ieee;
152 struct net_device *dev;
153 int err;
154
155 IEEE80211_DEBUG_INFO("Initializing...\n");
156
157 dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
158 if (!dev) {
Akinobu Mitaa76193d2007-05-27 23:25:00 +0900159 IEEE80211_ERROR("Unable to allocate network device.\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400160 goto failed;
161 }
162 ieee = netdev_priv(dev);
163 dev->hard_start_xmit = ieee80211_xmit;
matthieu castet42a4cf92006-09-28 19:57:25 +0200164 dev->change_mtu = ieee80211_change_mtu;
Jeff Garzikb4538722005-05-12 22:48:20 -0400165
Daniel Drake718cc4c2006-11-22 03:15:46 +0000166 /* Drivers are free to override this if the generic implementation
167 * does not meet their needs. */
168 dev->get_stats = ieee80211_generic_get_stats;
169
Jeff Garzikb4538722005-05-12 22:48:20 -0400170 ieee->dev = dev;
171
172 err = ieee80211_networks_allocate(ieee);
173 if (err) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400174 IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
Julia Lawalld92a8e82008-07-16 16:34:54 +0200175 goto failed_free_netdev;
Jeff Garzikb4538722005-05-12 22:48:20 -0400176 }
177 ieee80211_networks_initialize(ieee);
178
179 /* Default fragmentation threshold is maximum payload size */
180 ieee->fts = DEFAULT_FTS;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500181 ieee->rts = DEFAULT_FTS;
Jeff Garzikb4538722005-05-12 22:48:20 -0400182 ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
183 ieee->open_wep = 1;
184
185 /* Default to enabling full open WEP with host based encrypt/decrypt */
186 ieee->host_encrypt = 1;
187 ieee->host_decrypt = 1;
James Ketrenosccd0fda2005-09-21 11:58:32 -0500188 ieee->host_mc_decrypt = 1;
189
James Ketrenos1264fc02005-09-21 11:54:53 -0500190 /* Host fragementation in Open mode. Default is enabled.
191 * Note: host fragmentation is always enabled if host encryption
192 * is enabled. For cards can do hardware encryption, they must do
193 * hardware fragmentation as well. So we don't need a variable
194 * like host_enc_frag. */
195 ieee->host_open_frag = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400196 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
Jeff Garzikb4538722005-05-12 22:48:20 -0400197
Jeff Garzikb4538722005-05-12 22:48:20 -0400198 spin_lock_init(&ieee->lock);
199
John W. Linville2ba4b322008-11-11 16:00:06 -0500200 lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
John W. Linville274bfb82008-10-29 11:35:05 -0400201
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400202 ieee->wpa_enabled = 0;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400203 ieee->drop_unencrypted = 0;
204 ieee->privacy_invoked = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400205
206 return dev;
207
Julia Lawalld92a8e82008-07-16 16:34:54 +0200208failed_free_netdev:
209 free_netdev(dev);
210failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400211 return NULL;
212}
213
Jeff Garzikb4538722005-05-12 22:48:20 -0400214void free_ieee80211(struct net_device *dev)
215{
216 struct ieee80211_device *ieee = netdev_priv(dev);
217
John W. Linville2ba4b322008-11-11 16:00:06 -0500218 lib80211_crypt_info_free(&ieee->crypt_info);
Jeff Garzikb4538722005-05-12 22:48:20 -0400219
220 ieee80211_networks_free(ieee);
221 free_netdev(dev);
222}
223
Helmut Schaa37561622009-03-06 12:02:25 +0100224#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400225
226static int debug = 0;
227u32 ieee80211_debug_level = 0;
Larry Finger2933d422007-04-17 10:28:47 -0500228EXPORT_SYMBOL_GPL(ieee80211_debug_level);
Johannes Bergb7cffb02006-01-04 20:58:10 +0100229static struct proc_dir_entry *ieee80211_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400230
231static int show_debug_level(char *page, char **start, off_t offset,
232 int count, int *eof, void *data)
233{
234 return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
235}
236
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400237static int store_debug_level(struct file *file, const char __user * buffer,
Jeff Garzikb4538722005-05-12 22:48:20 -0400238 unsigned long count, void *data)
239{
James Ketrenos262d8e42005-09-13 17:42:53 -0500240 char buf[] = "0x00000000\n";
241 unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
Jeff Garzikb4538722005-05-12 22:48:20 -0400242 unsigned long val;
243
James Ketrenos262d8e42005-09-13 17:42:53 -0500244 if (copy_from_user(buf, buffer, len))
Jeff Garzikb4538722005-05-12 22:48:20 -0400245 return count;
James Ketrenos262d8e42005-09-13 17:42:53 -0500246 buf[len] = 0;
247 if (sscanf(buf, "%li", &val) != 1)
Jeff Garzikb4538722005-05-12 22:48:20 -0400248 printk(KERN_INFO DRV_NAME
249 ": %s is not in hex or decimal form.\n", buf);
250 else
251 ieee80211_debug_level = val;
252
James Ketrenos262d8e42005-09-13 17:42:53 -0500253 return strnlen(buf, len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400254}
Helmut Schaa37561622009-03-06 12:02:25 +0100255#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400256
257static int __init ieee80211_init(void)
258{
Helmut Schaa37561622009-03-06 12:02:25 +0100259#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400260 struct proc_dir_entry *e;
261
262 ieee80211_debug_level = debug;
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200263 ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400264 if (ieee80211_proc == NULL) {
265 IEEE80211_ERROR("Unable to create " DRV_NAME
266 " proc directory\n");
267 return -EIO;
268 }
269 e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
270 ieee80211_proc);
271 if (!e) {
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200272 remove_proc_entry(DRV_NAME, init_net.proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400273 ieee80211_proc = NULL;
274 return -EIO;
275 }
276 e->read_proc = show_debug_level;
277 e->write_proc = store_debug_level;
278 e->data = NULL;
Helmut Schaa37561622009-03-06 12:02:25 +0100279#endif /* CONFIG_LIBIPW_DEBUG */
James Ketrenos31696162005-09-21 11:58:46 -0500280
281 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
282 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400283
284 return 0;
285}
286
287static void __exit ieee80211_exit(void)
288{
Helmut Schaa37561622009-03-06 12:02:25 +0100289#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400290 if (ieee80211_proc) {
291 remove_proc_entry("debug_level", ieee80211_proc);
Eric W. Biederman457c4cb2007-09-12 12:01:34 +0200292 remove_proc_entry(DRV_NAME, init_net.proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400293 ieee80211_proc = NULL;
294 }
Helmut Schaa37561622009-03-06 12:02:25 +0100295#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400296}
297
Helmut Schaa37561622009-03-06 12:02:25 +0100298#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400299#include <linux/moduleparam.h>
300module_param(debug, int, 0444);
301MODULE_PARM_DESC(debug, "debug output mask");
Helmut Schaa37561622009-03-06 12:02:25 +0100302#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400303
Jeff Garzikb4538722005-05-12 22:48:20 -0400304module_exit(ieee80211_exit);
305module_init(ieee80211_init);
Jeff Garzikb4538722005-05-12 22:48:20 -0400306
307EXPORT_SYMBOL(alloc_ieee80211);
308EXPORT_SYMBOL(free_ieee80211);