blob: 5f31b72a492181657f784408a3d33a11b418f221 [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++) {
Fabian Frederickf528f662014-06-28 14:18:52 +0200103 kfree(ieee->networks[i]->ibss_dfs);
Zhu Yi8e593402010-03-08 13:18:03 +0800104 kfree(ieee->networks[i]);
105 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400106}
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++)
Zhu Yi8e593402010-03-08 13:18:03 +0800130 list_add_tail(&ieee->networks[i]->list,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400131 &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
Pavel Roskin27ae60f2010-03-12 00:01:22 -0500143struct net_device *alloc_libipw(int sizeof_priv, int monitor)
Jeff Garzikb4538722005-05-12 22:48:20 -0400144{
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);
Joe Perches41de8d42012-01-29 13:47:52 +0000152 if (!dev)
Jeff Garzikb4538722005-05-12 22:48:20 -0400153 goto failed;
Joe Perches41de8d42012-01-29 13:47:52 +0000154
Jeff Garzikb4538722005-05-12 22:48:20 -0400155 ieee = netdev_priv(dev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400156
157 ieee->dev = dev;
158
John W. Linvillea3caa992009-08-25 14:12:25 -0400159 if (!monitor) {
160 ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0);
161 if (!ieee->wdev.wiphy) {
162 LIBIPW_ERROR("Unable to allocate wiphy.\n");
163 goto failed_free_netdev;
164 }
165
166 ieee->dev->ieee80211_ptr = &ieee->wdev;
167 ieee->wdev.iftype = NL80211_IFTYPE_STATION;
168
169 /* Fill-out wiphy structure bits we know... Not enough info
170 here to call set_wiphy_dev or set MAC address or channel info
171 -- have to do that in ->ndo_init... */
172 ieee->wdev.wiphy->privid = libipw_wiphy_privid;
173
174 ieee->wdev.wiphy->max_scan_ssids = 1;
175 ieee->wdev.wiphy->max_scan_ie_len = 0;
176 ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
177 | BIT(NL80211_IFTYPE_ADHOC);
178 }
179
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400180 err = libipw_networks_allocate(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400181 if (err) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400182 LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
John W. Linvillea3caa992009-08-25 14:12:25 -0400183 goto failed_free_wiphy;
Jeff Garzikb4538722005-05-12 22:48:20 -0400184 }
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400185 libipw_networks_initialize(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400186
187 /* Default fragmentation threshold is maximum payload size */
188 ieee->fts = DEFAULT_FTS;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500189 ieee->rts = DEFAULT_FTS;
Jeff Garzikb4538722005-05-12 22:48:20 -0400190 ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
191 ieee->open_wep = 1;
192
193 /* Default to enabling full open WEP with host based encrypt/decrypt */
194 ieee->host_encrypt = 1;
195 ieee->host_decrypt = 1;
James Ketrenosccd0fda2005-09-21 11:58:32 -0500196 ieee->host_mc_decrypt = 1;
197
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200198 /* Host fragmentation in Open mode. Default is enabled.
James Ketrenos1264fc02005-09-21 11:54:53 -0500199 * Note: host fragmentation is always enabled if host encryption
200 * is enabled. For cards can do hardware encryption, they must do
201 * hardware fragmentation as well. So we don't need a variable
202 * like host_enc_frag. */
203 ieee->host_open_frag = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400204 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
Jeff Garzikb4538722005-05-12 22:48:20 -0400205
Jeff Garzikb4538722005-05-12 22:48:20 -0400206 spin_lock_init(&ieee->lock);
207
John W. Linville2ba4b322008-11-11 16:00:06 -0500208 lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
John W. Linville274bfb82008-10-29 11:35:05 -0400209
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400210 ieee->wpa_enabled = 0;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400211 ieee->drop_unencrypted = 0;
212 ieee->privacy_invoked = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400213
214 return dev;
215
John W. Linvillea3caa992009-08-25 14:12:25 -0400216failed_free_wiphy:
217 if (!monitor)
218 wiphy_free(ieee->wdev.wiphy);
Julia Lawalld92a8e82008-07-16 16:34:54 +0200219failed_free_netdev:
220 free_netdev(dev);
221failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400222 return NULL;
223}
Pavel Roskin27ae60f2010-03-12 00:01:22 -0500224EXPORT_SYMBOL(alloc_libipw);
Jeff Garzikb4538722005-05-12 22:48:20 -0400225
Pavel Roskin27ae60f2010-03-12 00:01:22 -0500226void free_libipw(struct net_device *dev, int monitor)
Jeff Garzikb4538722005-05-12 22:48:20 -0400227{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400228 struct libipw_device *ieee = netdev_priv(dev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400229
John W. Linville2ba4b322008-11-11 16:00:06 -0500230 lib80211_crypt_info_free(&ieee->crypt_info);
Jeff Garzikb4538722005-05-12 22:48:20 -0400231
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400232 libipw_networks_free(ieee);
John W. Linvillea3caa992009-08-25 14:12:25 -0400233
234 /* free cfg80211 resources */
235 if (!monitor)
236 wiphy_free(ieee->wdev.wiphy);
237
Jeff Garzikb4538722005-05-12 22:48:20 -0400238 free_netdev(dev);
239}
Pavel Roskin27ae60f2010-03-12 00:01:22 -0500240EXPORT_SYMBOL(free_libipw);
Jeff Garzikb4538722005-05-12 22:48:20 -0400241
Helmut Schaa37561622009-03-06 12:02:25 +0100242#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400243
244static int debug = 0;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400245u32 libipw_debug_level = 0;
246EXPORT_SYMBOL_GPL(libipw_debug_level);
247static struct proc_dir_entry *libipw_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400248
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300249static int debug_level_proc_show(struct seq_file *m, void *v)
Jeff Garzikb4538722005-05-12 22:48:20 -0400250{
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300251 seq_printf(m, "0x%08X\n", libipw_debug_level);
252 return 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400253}
254
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300255static int debug_level_proc_open(struct inode *inode, struct file *file)
256{
257 return single_open(file, debug_level_proc_show, NULL);
258}
259
260static ssize_t debug_level_proc_write(struct file *file,
261 const char __user *buffer, size_t count, loff_t *pos)
Jeff Garzikb4538722005-05-12 22:48:20 -0400262{
James Ketrenos262d8e42005-09-13 17:42:53 -0500263 char buf[] = "0x00000000\n";
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300264 size_t len = min(sizeof(buf) - 1, count);
Jeff Garzikb4538722005-05-12 22:48:20 -0400265 unsigned long val;
266
James Ketrenos262d8e42005-09-13 17:42:53 -0500267 if (copy_from_user(buf, buffer, len))
Jeff Garzikb4538722005-05-12 22:48:20 -0400268 return count;
James Ketrenos262d8e42005-09-13 17:42:53 -0500269 buf[len] = 0;
270 if (sscanf(buf, "%li", &val) != 1)
Jeff Garzikb4538722005-05-12 22:48:20 -0400271 printk(KERN_INFO DRV_NAME
272 ": %s is not in hex or decimal form.\n", buf);
273 else
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400274 libipw_debug_level = val;
Jeff Garzikb4538722005-05-12 22:48:20 -0400275
James Ketrenos262d8e42005-09-13 17:42:53 -0500276 return strnlen(buf, len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400277}
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300278
279static const struct file_operations debug_level_proc_fops = {
280 .owner = THIS_MODULE,
281 .open = debug_level_proc_open,
282 .read = seq_read,
283 .llseek = seq_lseek,
284 .release = single_release,
285 .write = debug_level_proc_write,
286};
Helmut Schaa37561622009-03-06 12:02:25 +0100287#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400288
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400289static int __init libipw_init(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400290{
Helmut Schaa37561622009-03-06 12:02:25 +0100291#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400292 struct proc_dir_entry *e;
293
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400294 libipw_debug_level = debug;
Linus Torvalds151f52f2010-11-05 18:57:04 -0700295 libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400296 if (libipw_proc == NULL) {
Linus Torvalds151f52f2010-11-05 18:57:04 -0700297 LIBIPW_ERROR("Unable to create " DRV_PROCNAME
Jeff Garzikb4538722005-05-12 22:48:20 -0400298 " proc directory\n");
299 return -EIO;
300 }
Alexey Dobriyanb8d83392009-11-25 10:14:12 +0300301 e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc,
302 &debug_level_proc_fops);
Jeff Garzikb4538722005-05-12 22:48:20 -0400303 if (!e) {
Linus Torvalds151f52f2010-11-05 18:57:04 -0700304 remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400305 libipw_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400306 return -EIO;
307 }
Helmut Schaa37561622009-03-06 12:02:25 +0100308#endif /* CONFIG_LIBIPW_DEBUG */
James Ketrenos31696162005-09-21 11:58:46 -0500309
310 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
311 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400312
313 return 0;
314}
315
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400316static void __exit libipw_exit(void)
Jeff Garzikb4538722005-05-12 22:48:20 -0400317{
Helmut Schaa37561622009-03-06 12:02:25 +0100318#ifdef CONFIG_LIBIPW_DEBUG
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400319 if (libipw_proc) {
320 remove_proc_entry("debug_level", libipw_proc);
Linus Torvalds151f52f2010-11-05 18:57:04 -0700321 remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400322 libipw_proc = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400323 }
Helmut Schaa37561622009-03-06 12:02:25 +0100324#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400325}
326
Helmut Schaa37561622009-03-06 12:02:25 +0100327#ifdef CONFIG_LIBIPW_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400328#include <linux/moduleparam.h>
329module_param(debug, int, 0444);
330MODULE_PARM_DESC(debug, "debug output mask");
Helmut Schaa37561622009-03-06 12:02:25 +0100331#endif /* CONFIG_LIBIPW_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400332
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400333module_exit(libipw_exit);
334module_init(libipw_init);