libipw_module.c revision c3d72b968129ad4aec86c5fc8d2380f01ebebc53
1/*******************************************************************************
2
3  Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
4
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
8  <j@w1.fi>
9  Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
10
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>
34#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>
42#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>
47#include <linux/wireless.h>
48#include <linux/etherdevice.h>
49#include <asm/uaccess.h>
50#include <net/net_namespace.h>
51#include <net/arp.h>
52
53#include "ieee80211.h"
54
55#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>"
59
60MODULE_VERSION(DRV_VERSION);
61MODULE_DESCRIPTION(DRV_DESCRIPTION);
62MODULE_AUTHOR(DRV_COPYRIGHT);
63MODULE_LICENSE("GPL");
64
65static int ieee80211_networks_allocate(struct ieee80211_device *ieee)
66{
67	if (ieee->networks)
68		return 0;
69
70	ieee->networks =
71	    kzalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
72		    GFP_KERNEL);
73	if (!ieee->networks) {
74		printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
75		       ieee->dev->name);
76		return -ENOMEM;
77	}
78
79	return 0;
80}
81
82void 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
93static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
94{
95	int i;
96
97	if (!ieee->networks)
98		return;
99
100	for (i = 0; i < MAX_NETWORK_COUNT; i++)
101		if (ieee->networks[i].ibss_dfs)
102			kfree(ieee->networks[i].ibss_dfs);
103
104	kfree(ieee->networks);
105	ieee->networks = NULL;
106}
107
108void 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
123static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
124{
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++)
130		list_add_tail(&ieee->networks[i].list,
131			      &ieee->network_free_list);
132}
133
134static 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
142static 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
149struct 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) {
159		IEEE80211_ERROR("Unable to allocate network device.\n");
160		goto failed;
161	}
162	ieee = netdev_priv(dev);
163	dev->hard_start_xmit = ieee80211_xmit;
164	dev->change_mtu = ieee80211_change_mtu;
165
166	/* 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
170	ieee->dev = dev;
171
172	err = ieee80211_networks_allocate(ieee);
173	if (err) {
174		IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
175		goto failed_free_netdev;
176	}
177	ieee80211_networks_initialize(ieee);
178
179	/* Default fragmentation threshold is maximum payload size */
180	ieee->fts = DEFAULT_FTS;
181	ieee->rts = DEFAULT_FTS;
182	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;
188	ieee->host_mc_decrypt = 1;
189
190	/* 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;
196	ieee->ieee802_1x = 1;	/* Default to supporting 802.1x */
197
198	spin_lock_init(&ieee->lock);
199
200	lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
201
202	ieee->wpa_enabled = 0;
203	ieee->drop_unencrypted = 0;
204	ieee->privacy_invoked = 0;
205
206	return dev;
207
208failed_free_netdev:
209	free_netdev(dev);
210failed:
211	return NULL;
212}
213
214void free_ieee80211(struct net_device *dev)
215{
216	struct ieee80211_device *ieee = netdev_priv(dev);
217
218	lib80211_crypt_info_free(&ieee->crypt_info);
219
220	ieee80211_networks_free(ieee);
221	free_netdev(dev);
222}
223
224#ifdef CONFIG_IEEE80211_DEBUG
225
226static int debug = 0;
227u32 ieee80211_debug_level = 0;
228EXPORT_SYMBOL_GPL(ieee80211_debug_level);
229static struct proc_dir_entry *ieee80211_proc = NULL;
230
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
237static int store_debug_level(struct file *file, const char __user * buffer,
238			     unsigned long count, void *data)
239{
240	char buf[] = "0x00000000\n";
241	unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
242	unsigned long val;
243
244	if (copy_from_user(buf, buffer, len))
245		return count;
246	buf[len] = 0;
247	if (sscanf(buf, "%li", &val) != 1)
248		printk(KERN_INFO DRV_NAME
249		       ": %s is not in hex or decimal form.\n", buf);
250	else
251		ieee80211_debug_level = val;
252
253	return strnlen(buf, len);
254}
255#endif				/* CONFIG_IEEE80211_DEBUG */
256
257static int __init ieee80211_init(void)
258{
259#ifdef CONFIG_IEEE80211_DEBUG
260	struct proc_dir_entry *e;
261
262	ieee80211_debug_level = debug;
263	ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
264	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) {
272		remove_proc_entry(DRV_NAME, init_net.proc_net);
273		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;
279#endif				/* CONFIG_IEEE80211_DEBUG */
280
281	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
282	printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
283
284	return 0;
285}
286
287static void __exit ieee80211_exit(void)
288{
289#ifdef CONFIG_IEEE80211_DEBUG
290	if (ieee80211_proc) {
291		remove_proc_entry("debug_level", ieee80211_proc);
292		remove_proc_entry(DRV_NAME, init_net.proc_net);
293		ieee80211_proc = NULL;
294	}
295#endif				/* CONFIG_IEEE80211_DEBUG */
296}
297
298#ifdef CONFIG_IEEE80211_DEBUG
299#include <linux/moduleparam.h>
300module_param(debug, int, 0444);
301MODULE_PARM_DESC(debug, "debug output mask");
302#endif				/* CONFIG_IEEE80211_DEBUG */
303
304module_exit(ieee80211_exit);
305module_init(ieee80211_init);
306
307EXPORT_SYMBOL(alloc_ieee80211);
308EXPORT_SYMBOL(free_ieee80211);
309