]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/net/wireless/ipw2x00/libipw_module.c
Merge branch 'upstream/core' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen
[net-next-2.6.git] / drivers / net / wireless / ipw2x00 / libipw_module.c
CommitLineData
b453872c
JG
1/*******************************************************************************
2
ebeaddcc 3 Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
b453872c
JG
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
85d32e7b
JM
8 <j@w1.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
b453872c
JG
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:
c1eb2c82 28 Intel Linux Wireless <ilw@linux.intel.com>
b453872c
JG
29 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31*******************************************************************************/
32
33#include <linux/compiler.h>
b453872c
JG
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>
b453872c
JG
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>
b453872c
JG
47#include <linux/wireless.h>
48#include <linux/etherdevice.h>
49#include <asm/uaccess.h>
457c4cbc 50#include <net/net_namespace.h>
b453872c
JG
51#include <net/arp.h>
52
b0a4e7d8 53#include "libipw.h"
b453872c 54
31696160 55#define DRV_DESCRIPTION "802.11 data/management/control stack"
27ae60f8 56#define DRV_NAME "libipw"
151f52f0 57#define DRV_PROCNAME "ieee80211"
b0a4e7d8 58#define DRV_VERSION LIBIPW_VERSION
31696160
JK
59#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
60
61MODULE_VERSION(DRV_VERSION);
62MODULE_DESCRIPTION(DRV_DESCRIPTION);
63MODULE_AUTHOR(DRV_COPYRIGHT);
b453872c
JG
64MODULE_LICENSE("GPL");
65
cc40cc56
JL
66static struct cfg80211_ops libipw_config_ops = { };
67static void *libipw_wiphy_privid = &libipw_wiphy_privid;
a3caa99e 68
b0a4e7d8 69static int libipw_networks_allocate(struct libipw_device *ieee)
b453872c 70{
8e59340e
ZY
71 int i, j;
72
73 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 }
b453872c
JG
82 }
83
b453872c
JG
84 return 0;
85}
86
b0a4e7d8 87void libipw_network_reset(struct libipw_network *network)
15f38598
ZY
88{
89 if (!network)
90 return;
91
92 if (network->ibss_dfs) {
93 kfree(network->ibss_dfs);
94 network->ibss_dfs = NULL;
95 }
96}
97
b0a4e7d8 98static inline void libipw_networks_free(struct libipw_device *ieee)
b453872c 99{
15f38598
ZY
100 int i;
101
8e59340e
ZY
102 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 }
b453872c
JG
107}
108
b0a4e7d8 109void libipw_networks_age(struct libipw_device *ieee,
c3d72b96
DW
110 unsigned long age_secs)
111{
b0a4e7d8 112 struct libipw_network *network = NULL;
c3d72b96
DW
113 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}
b0a4e7d8 122EXPORT_SYMBOL(libipw_networks_age);
c3d72b96 123
b0a4e7d8 124static void libipw_networks_initialize(struct libipw_device *ieee)
b453872c
JG
125{
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++)
8e59340e 131 list_add_tail(&ieee->networks[i]->list,
0edd5b44 132 &ieee->network_free_list);
b453872c
JG
133}
134
b0a4e7d8 135int libipw_change_mtu(struct net_device *dev, int new_mtu)
42a4cf95 136{
b0a4e7d8 137 if ((new_mtu < 68) || (new_mtu > LIBIPW_DATA_LEN))
42a4cf95
MC
138 return -EINVAL;
139 dev->mtu = new_mtu;
140 return 0;
141}
b0a4e7d8 142EXPORT_SYMBOL(libipw_change_mtu);
42a4cf95 143
27ae60f8 144struct net_device *alloc_libipw(int sizeof_priv, int monitor)
b453872c 145{
b0a4e7d8 146 struct libipw_device *ieee;
b453872c
JG
147 struct net_device *dev;
148 int err;
149
b0a4e7d8 150 LIBIPW_DEBUG_INFO("Initializing...\n");
b453872c 151
b0a4e7d8 152 dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv);
b453872c 153 if (!dev) {
b0a4e7d8 154 LIBIPW_ERROR("Unable to allocate network device.\n");
b453872c
JG
155 goto failed;
156 }
157 ieee = netdev_priv(dev);
b453872c
JG
158
159 ieee->dev = dev;
160
a3caa99e
JL
161 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
b0a4e7d8 182 err = libipw_networks_allocate(ieee);
b453872c 183 if (err) {
b0a4e7d8 184 LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
a3caa99e 185 goto failed_free_wiphy;
b453872c 186 }
b0a4e7d8 187 libipw_networks_initialize(ieee);
b453872c
JG
188
189 /* Default fragmentation threshold is maximum payload size */
190 ieee->fts = DEFAULT_FTS;
3cdd00c5 191 ieee->rts = DEFAULT_FTS;
b453872c
JG
192 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;
ccd0fda3
JK
198 ieee->host_mc_decrypt = 1;
199
af901ca1 200 /* Host fragmentation in Open mode. Default is enabled.
1264fc04
JK
201 * 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;
0edd5b44 206 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
b453872c 207
b453872c
JG
208 spin_lock_init(&ieee->lock);
209
2ba4b32e 210 lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
274bfb8d 211
0edd5b44 212 ieee->wpa_enabled = 0;
0edd5b44
JG
213 ieee->drop_unencrypted = 0;
214 ieee->privacy_invoked = 0;
b453872c
JG
215
216 return dev;
217
a3caa99e
JL
218failed_free_wiphy:
219 if (!monitor)
220 wiphy_free(ieee->wdev.wiphy);
d92a8e81
JL
221failed_free_netdev:
222 free_netdev(dev);
223failed:
b453872c
JG
224 return NULL;
225}
27ae60f8 226EXPORT_SYMBOL(alloc_libipw);
b453872c 227
27ae60f8 228void free_libipw(struct net_device *dev, int monitor)
b453872c 229{
b0a4e7d8 230 struct libipw_device *ieee = netdev_priv(dev);
b453872c 231
2ba4b32e 232 lib80211_crypt_info_free(&ieee->crypt_info);
b453872c 233
b0a4e7d8 234 libipw_networks_free(ieee);
a3caa99e
JL
235
236 /* free cfg80211 resources */
237 if (!monitor)
238 wiphy_free(ieee->wdev.wiphy);
239
b453872c
JG
240 free_netdev(dev);
241}
27ae60f8 242EXPORT_SYMBOL(free_libipw);
b453872c 243
3756162b 244#ifdef CONFIG_LIBIPW_DEBUG
b453872c
JG
245
246static int debug = 0;
b0a4e7d8
JL
247u32 libipw_debug_level = 0;
248EXPORT_SYMBOL_GPL(libipw_debug_level);
249static struct proc_dir_entry *libipw_proc = NULL;
b453872c 250
b8d83392 251static int debug_level_proc_show(struct seq_file *m, void *v)
b453872c 252{
b8d83392
AD
253 seq_printf(m, "0x%08X\n", libipw_debug_level);
254 return 0;
b453872c
JG
255}
256
b8d83392
AD
257static 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)
b453872c 264{
262d8e46 265 char buf[] = "0x00000000\n";
b8d83392 266 size_t len = min(sizeof(buf) - 1, count);
b453872c
JG
267 unsigned long val;
268
262d8e46 269 if (copy_from_user(buf, buffer, len))
b453872c 270 return count;
262d8e46
JK
271 buf[len] = 0;
272 if (sscanf(buf, "%li", &val) != 1)
b453872c
JG
273 printk(KERN_INFO DRV_NAME
274 ": %s is not in hex or decimal form.\n", buf);
275 else
b0a4e7d8 276 libipw_debug_level = val;
b453872c 277
262d8e46 278 return strnlen(buf, len);
b453872c 279}
b8d83392
AD
280
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};
3756162b 289#endif /* CONFIG_LIBIPW_DEBUG */
b453872c 290
b0a4e7d8 291static int __init libipw_init(void)
b453872c 292{
3756162b 293#ifdef CONFIG_LIBIPW_DEBUG
b453872c
JG
294 struct proc_dir_entry *e;
295
b0a4e7d8 296 libipw_debug_level = debug;
151f52f0 297 libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
b0a4e7d8 298 if (libipw_proc == NULL) {
151f52f0 299 LIBIPW_ERROR("Unable to create " DRV_PROCNAME
b453872c
JG
300 " proc directory\n");
301 return -EIO;
302 }
b8d83392
AD
303 e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc,
304 &debug_level_proc_fops);
b453872c 305 if (!e) {
151f52f0 306 remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
b0a4e7d8 307 libipw_proc = NULL;
b453872c
JG
308 return -EIO;
309 }
3756162b 310#endif /* CONFIG_LIBIPW_DEBUG */
31696160
JK
311
312 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
313 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
b453872c
JG
314
315 return 0;
316}
317
b0a4e7d8 318static void __exit libipw_exit(void)
b453872c 319{
3756162b 320#ifdef CONFIG_LIBIPW_DEBUG
b0a4e7d8
JL
321 if (libipw_proc) {
322 remove_proc_entry("debug_level", libipw_proc);
151f52f0 323 remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
b0a4e7d8 324 libipw_proc = NULL;
b453872c 325 }
3756162b 326#endif /* CONFIG_LIBIPW_DEBUG */
b453872c
JG
327}
328
3756162b 329#ifdef CONFIG_LIBIPW_DEBUG
b453872c
JG
330#include <linux/moduleparam.h>
331module_param(debug, int, 0444);
332MODULE_PARM_DESC(debug, "debug output mask");
3756162b 333#endif /* CONFIG_LIBIPW_DEBUG */
b453872c 334
b0a4e7d8
JL
335module_exit(libipw_exit);
336module_init(libipw_init);