blob: d5ef696298eed37db811f55e60c0b7f3c0ded6f6 [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:
Reinette Chatrec1eb2c82009-08-21 13:34:26 -070028 Intel Linux Wireless <ilw@linux.intel.com>
Jeff Garzikb4538722005-05-12 22:48:20 -040029 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"
Pavel Roskin27ae60f2010-03-12 00:01:22 -050056#define DRV_NAME "libipw"
Linus Torvalds151f52f2010-11-05 18:57:04 -070057#define DRV_PROCNAME "ieee80211"
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040058#define DRV_VERSION LIBIPW_VERSION
James Ketrenos31696162005-09-21 11:58:46 -050059#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
Jeff Garzikb4538722005-05-12 22:48:20 -040060
James Ketrenos31696162005-09-21 11:58:46 -050061MODULE_VERSION(DRV_VERSION);
62MODULE_DESCRIPTION(DRV_DESCRIPTION);
63MODULE_AUTHOR(DRV_COPYRIGHT);
64MODULE_LICENSE("GPL");
Jeff Garzikb4538722005-05-12 22:48:20 -040065
John W. Linvillecc40cc52010-07-20 14:14:03 -040066static struct cfg80211_ops libipw_config_ops = { };
67static void *libipw_wiphy_privid = &libipw_wiphy_privid;
John W. Linvillea3caa992009-08-25 14:12:25 -040068
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040069static int libipw_networks_allocate(struct libipw_device *ieee)
Jeff Garzikb4538722005-05-12 22:48:20 -040070{
Zhu Yi8e593402010-03-08 13:18:03 +080071 int i, j;
Jeff Garzikb4538722005-05-12 22:48:20 -040072
Zhu Yi8e593402010-03-08 13:18:03 +080073 for (i = 0; i < MAX_NETWORK_COUNT; i++) {
74 ieee->networks[i] = kzalloc(sizeof(struct libipw_network),
75 GFP_KERNEL);
76 if (!ieee->networks[i]) {
77 LIBIPW_ERROR("Out of memory allocating beacons\n");
78 for (j = 0; j < i; j++)
79 kfree(ieee->networks[j]);
80 return -ENOMEM;
81 }
Jeff Garzikb4538722005-05-12 22:48:20 -040082 }
83
Jeff Garzikb4538722005-05-12 22:48:20 -040084 return 0;
85}
86
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040087void libipw_network_reset(struct libipw_network *network)
Zhu Yi15f38592006-01-19 16:21:35 +080088{
89 if (!network)
90 return;
91
92 if (network->ibss_dfs) {
93 kfree(network->ibss_dfs);
94 network->ibss_dfs = NULL;
95 }
96}
97
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040098static inline void libipw_networks_free(struct libipw_device *ieee)
Jeff Garzikb4538722005-05-12 22:48:20 -040099{
Zhu Yi15f38592006-01-19 16:21:35 +0800100 int i;
101
Zhu Yi8e593402010-03-08 13:18:03 +0800102 for (i = 0; i < MAX_NETWORK_COUNT; i++) {
103 if (ieee->networks[i]->ibss_dfs)
104 kfree(ieee->networks[i]->ibss_dfs);
105 kfree(ieee->networks[i]);
106 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400107}
108
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400109void libipw_networks_age(struct libipw_device *ieee,
Dan Williamsc3d72b92009-02-11 13:26:06 -0500110 unsigned long age_secs)
111{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400112 struct libipw_network *network = NULL;
Dan Williamsc3d72b92009-02-11 13:26:06 -0500113 unsigned long flags;
114 unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
115
116 spin_lock_irqsave(&ieee->lock, flags);
117 list_for_each_entry(network, &ieee->network_list, list) {
118 network->last_scanned -= age_jiffies;
119 }
120 spin_unlock_irqrestore(&ieee->lock, flags);
121}
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400122EXPORT_SYMBOL(libipw_networks_age);
Dan Williamsc3d72b92009-02-11 13:26:06 -0500123
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400124static void libipw_networks_initialize(struct libipw_device *ieee)
Jeff Garzikb4538722005-05-12 22:48:20 -0400125{
126 int i;
127
128 INIT_LIST_HEAD(&ieee->network_free_list);
129 INIT_LIST_HEAD(&ieee->network_list);
130 for (i = 0; i < MAX_NETWORK_COUNT; i++)
Zhu Yi8e593402010-03-08 13:18:03 +0800131 list_add_tail(&ieee->networks[i]->list,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400132 &ieee->network_free_list);
Jeff Garzikb4538722005-05-12 22:48:20 -0400133}
134
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400135int libipw_change_mtu(struct net_device *dev, int new_mtu)
matthieu castet42a4cf92006-09-28 19:57:25 +0200136{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400137 if ((new_mtu < 68) || (new_mtu > LIBIPW_DATA_LEN))
matthieu castet42a4cf92006-09-28 19:57:25 +0200138 return -EINVAL;
139 dev->mtu = new_mtu;
140 return 0;
141}
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400142EXPORT_SYMBOL(libipw_change_mtu);
matthieu castet42a4cf92006-09-28 19:57:25 +0200143
Pavel Roskin27ae60f2010-03-12 00:01:22 -0500144struct net_device *alloc_libipw(int sizeof_priv, int monitor)
Jeff Garzikb4538722005-05-12 22:48:20 -0400145{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400146 struct libipw_device *ieee;
Jeff Garzikb4538722005-05-12 22:48:20 -0400147 struct net_device *dev;
148 int err;
149
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400150 LIBIPW_DEBUG_INFO("Initializing...\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400151
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400152 dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv);
Jeff Garzikb4538722005-05-12 22:48:20 -0400153 if (!dev) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400154 LIBIPW_ERROR("Unable to allocate network device.\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400155 goto failed;
156 }
157 ieee = netdev_priv(dev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400158
159 ieee->dev = dev;
160
John W. Linvillea3caa992009-08-25 14:12:25 -0400161 if (!monitor) {
162 ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0);
163 if (!ieee->wdev.wiphy) {
164 LIBIPW_ERROR("Unable to allocate wiphy.\n");
165 goto failed_free_netdev;
166 }
167
168 ieee->dev->ieee80211_ptr = &ieee->wdev;
169 ieee->wdev.iftype = NL80211_IFTYPE_STATION;
170
171 /* Fill-out wiphy structure bits we know... Not enough info
172 here to call set_wiphy_dev or set MAC address or channel info
173 -- have to do that in ->ndo_init... */
174 ieee->wdev.wiphy->privid = libipw_wiphy_privid;
175
176 ieee->wdev.wiphy->max_scan_ssids = 1;
177 ieee->wdev.wiphy->max_scan_ie_len = 0;
178 ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
179 | BIT(NL80211_IFTYPE_ADHOC);
180 }
181
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400182 err = libipw_networks_allocate(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400183 if (err) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400184 LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
John W. Linvillea3caa992009-08-25 14:12:25 -0400185 goto failed_free_wiphy;
Jeff Garzikb4538722005-05-12 22:48:20 -0400186 }
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400187 libipw_networks_initialize(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400188
189 /* Default fragmentation threshold is maximum payload size */
190 ieee->fts = DEFAULT_FTS;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500191 ieee->rts = DEFAULT_FTS;
Jeff Garzikb4538722005-05-12 22:48:20 -0400192 ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
193 ieee->open_wep = 1;
194
195 /* Default to enabling full open WEP with host based encrypt/decrypt */
196 ieee->host_encrypt = 1;
197 ieee->host_decrypt = 1;
James Ketrenosccd0fda2005-09-21 11:58:32 -0500198 ieee->host_mc_decrypt = 1;
199
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200200 /* Host fragmentation in Open mode. Default is enabled.
James Ketrenos1264fc02005-09-21 11:54:53 -0500201 * Note: host fragmentation is always enabled if host encryption
202 * is enabled. For cards can do hardware encryption, they must do
203 * hardware fragmentation as well. So we don't need a variable
204 * like host_enc_frag. */
205 ieee->host_open_frag = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400206 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
Jeff Garzikb4538722005-05-12 22:48:20 -0400207
Jeff Garzikb4538722005-05-12 22:48:20 -0400208 spin_lock_init(&ieee->lock);
209
John W. Linville2ba4b322008-11-11 16:00:06 -0500210 lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
John W. Linville274bfb82008-10-29 11:35:05 -0400211
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400212 ieee->wpa_enabled = 0;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400213 ieee->drop_unencrypted = 0;
214 ieee->privacy_invoked = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400215
216 return dev;
217
John W. Linvillea3caa992009-08-25 14:12:25 -0400218failed_free_wiphy:
219 if (!monitor)
220 wiphy_free(ieee->wdev.wiphy);
Julia Lawalld92a8e82008-07-16 16:34:54 +0200221failed_free_netdev:
222 free_netdev(dev);
223failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400224 return NULL;
225}
Pavel Roskin27ae60f2010-03-12 00:01:22 -0500226EXPORT_SYMBOL(alloc_libipw);
Jeff Garzikb4538722005-05-12 22:48:20 -0400227
Pavel Roskin27ae60f2010-03-12 00:01:22 -0500228void free_libipw(struct net_device *dev, int monitor)
Jeff Garzikb4538722005-05-12 22:48:20 -0400229{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400230 struct libipw_device *ieee = netdev_priv(dev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400231
John W. Linville2ba4b322008-11-11 16:00:06 -0500232 lib80211_crypt_info_free(&ieee->crypt_info);
Jeff Garzikb4538722005-05-12 22:48:20 -0400233
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400234 libipw_networks_free(ieee);
John W. Linvillea3caa992009-08-25 14:12:25 -0400235
236 /* free cfg80211 resources */
237 if (!monitor)
238 wiphy_free(ieee->wdev.wiphy);
239
Jeff Garzikb4538722005-05-12 22:48:20 -0400240 free_netdev(dev);
241}
Pavel Roskin27ae60f2010-03-12 00:01:22 -0500242EXPORT_SYMBOL(free_libipw);
Jeff Garzikb4538722005-05-12 22:48:20 -0400243
Helmut Schaa37561622009-03-06 12:02:25 +0100244#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400245
246static int debug = 0;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400247u32 libipw_debug_level = 0;
248EXPORT_SYMBOL_GPL(libipw_debug_level);
249static struct proc_dir_entry *libipw_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400250
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300251static int debug_level_proc_show(struct seq_file *m, void *v)
Jeff Garzikb4538722005-05-12 22:48:20 -0400252{
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300253 seq_printf(m, "0x%08X\n", libipw_debug_level);
254 return 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400255}
256
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300257static int debug_level_proc_open(struct inode *inode, struct file *file)
258{
259 return single_open(file, debug_level_proc_show, NULL);
260}
261
262static ssize_t debug_level_proc_write(struct file *file,
263 const char __user *buffer, size_t count, loff_t *pos)
Jeff Garzikb4538722005-05-12 22:48:20 -0400264{
James Ketrenos262d8e42005-09-13 17:42:53 -0500265 char buf[] = "0x00000000\n";
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300266 size_t len = min(sizeof(buf) - 1, count);
Jeff Garzikb4538722005-05-12 22:48:20 -0400267 unsigned long val;
268
James Ketrenos262d8e42005-09-13 17:42:53 -0500269 if (copy_from_user(buf, buffer, len))
Jeff Garzikb4538722005-05-12 22:48:20 -0400270 return count;
James Ketrenos262d8e42005-09-13 17:42:53 -0500271 buf[len] = 0;
272 if (sscanf(buf, "%li", &val) != 1)
Jeff Garzikb4538722005-05-12 22:48:20 -0400273 printk(KERN_INFO DRV_NAME
274 ": %s is not in hex or decimal form.\n", buf);
275 else
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400276 libipw_debug_level = val;
Jeff Garzikb4538722005-05-12 22:48:20 -0400277
James Ketrenos262d8e42005-09-13 17:42:53 -0500278 return strnlen(buf, len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400279}
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300280
281static const struct file_operations debug_level_proc_fops = {
282 .owner = THIS_MODULE,
283 .open = debug_level_proc_open,
284 .read = seq_read,
285 .llseek = seq_lseek,
286 .release = single_release,
287 .write = debug_level_proc_write,
288};
Helmut Schaa37561622009-03-06 12:02:25 +0100289#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400290
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400291static int __init libipw_init(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400292{
Helmut Schaa37561622009-03-06 12:02:25 +0100293#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400294 struct proc_dir_entry *e;
295
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400296 libipw_debug_level = debug;
Linus Torvalds151f52f2010-11-05 18:57:04 -0700297 libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400298 if (libipw_proc == NULL) {
Linus Torvalds151f52f2010-11-05 18:57:04 -0700299 LIBIPW_ERROR("Unable to create " DRV_PROCNAME
Jeff Garzikb4538722005-05-12 22:48:20 -0400300 " proc directory\n");
301 return -EIO;
302 }
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300303 e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc,
304 &debug_level_proc_fops);
Jeff Garzikb4538722005-05-12 22:48:20 -0400305 if (!e) {
Linus Torvalds151f52f2010-11-05 18:57:04 -0700306 remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400307 libipw_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400308 return -EIO;
309 }
Helmut Schaa37561622009-03-06 12:02:25 +0100310#endif /* CONFIG_LIBIPW_DEBUG */
James Ketrenos31696162005-09-21 11:58:46 -0500311
312 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
313 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400314
315 return 0;
316}
317
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400318static void __exit libipw_exit(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400319{
Helmut Schaa37561622009-03-06 12:02:25 +0100320#ifdef CONFIG_LIBIPW_DEBUG
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400321 if (libipw_proc) {
322 remove_proc_entry("debug_level", libipw_proc);
Linus Torvalds151f52f2010-11-05 18:57:04 -0700323 remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400324 libipw_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400325 }
Helmut Schaa37561622009-03-06 12:02:25 +0100326#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400327}
328
Helmut Schaa37561622009-03-06 12:02:25 +0100329#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400330#include <linux/moduleparam.h>
331module_param(debug, int, 0444);
332MODULE_PARM_DESC(debug, "debug output mask");
Helmut Schaa37561622009-03-06 12:02:25 +0100333#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400334
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400335module_exit(libipw_exit);
336module_init(libipw_init);