blob: 321287bc887f2808438af09f9e955d78828063bd [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
8 <jkmaline@cc.hut.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.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/config.h>
35#include <linux/errno.h>
36#include <linux/if_arp.h>
37#include <linux/in6.h>
38#include <linux/in.h>
39#include <linux/ip.h>
40#include <linux/kernel.h>
41#include <linux/module.h>
42#include <linux/netdevice.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040043#include <linux/proc_fs.h>
44#include <linux/skbuff.h>
45#include <linux/slab.h>
46#include <linux/tcp.h>
47#include <linux/types.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040048#include <linux/wireless.h>
49#include <linux/etherdevice.h>
50#include <asm/uaccess.h>
51#include <net/arp.h>
52
53#include <net/ieee80211.h>
54
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
65static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
66{
67 if (ieee->networks)
68 return 0;
69
Jeff Garzik0edd5b42005-09-07 00:48:31 -040070 ieee->networks =
71 kmalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
72 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
79 memset(ieee->networks, 0,
80 MAX_NETWORK_COUNT * sizeof(struct ieee80211_network));
81
82 return 0;
83}
84
85static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
86{
87 if (!ieee->networks)
88 return;
89 kfree(ieee->networks);
90 ieee->networks = NULL;
91}
92
93static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee)
94{
95 int i;
96
97 INIT_LIST_HEAD(&ieee->network_free_list);
98 INIT_LIST_HEAD(&ieee->network_list);
99 for (i = 0; i < MAX_NETWORK_COUNT; i++)
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400100 list_add_tail(&ieee->networks[i].list,
101 &ieee->network_free_list);
Jeff Garzikb4538722005-05-12 22:48:20 -0400102}
103
Jeff Garzikb4538722005-05-12 22:48:20 -0400104struct net_device *alloc_ieee80211(int sizeof_priv)
105{
106 struct ieee80211_device *ieee;
107 struct net_device *dev;
108 int err;
109
110 IEEE80211_DEBUG_INFO("Initializing...\n");
111
112 dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
113 if (!dev) {
114 IEEE80211_ERROR("Unable to network device.\n");
115 goto failed;
116 }
117 ieee = netdev_priv(dev);
118 dev->hard_start_xmit = ieee80211_xmit;
119
120 ieee->dev = dev;
121
122 err = ieee80211_networks_allocate(ieee);
123 if (err) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400124 IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
Jeff Garzikb4538722005-05-12 22:48:20 -0400125 goto failed;
126 }
127 ieee80211_networks_initialize(ieee);
128
129 /* Default fragmentation threshold is maximum payload size */
130 ieee->fts = DEFAULT_FTS;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500131 ieee->rts = DEFAULT_FTS;
Jeff Garzikb4538722005-05-12 22:48:20 -0400132 ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
133 ieee->open_wep = 1;
134
135 /* Default to enabling full open WEP with host based encrypt/decrypt */
136 ieee->host_encrypt = 1;
137 ieee->host_decrypt = 1;
James Ketrenosccd0fda2005-09-21 11:58:32 -0500138 ieee->host_mc_decrypt = 1;
139
James Ketrenos1264fc02005-09-21 11:54:53 -0500140 /* Host fragementation in Open mode. Default is enabled.
141 * Note: host fragmentation is always enabled if host encryption
142 * is enabled. For cards can do hardware encryption, they must do
143 * hardware fragmentation as well. So we don't need a variable
144 * like host_enc_frag. */
145 ieee->host_open_frag = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400146 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
Jeff Garzikb4538722005-05-12 22:48:20 -0400147
148 INIT_LIST_HEAD(&ieee->crypt_deinit_list);
149 init_timer(&ieee->crypt_deinit_timer);
150 ieee->crypt_deinit_timer.data = (unsigned long)ieee;
151 ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
James Ketrenos0ad0c3c2005-09-21 11:54:15 -0500152 ieee->crypt_quiesced = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400153
154 spin_lock_init(&ieee->lock);
155
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400156 ieee->wpa_enabled = 0;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400157 ieee->drop_unencrypted = 0;
158 ieee->privacy_invoked = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400159
160 return dev;
161
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400162 failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400163 if (dev)
164 free_netdev(dev);
165 return NULL;
166}
167
Jeff Garzikb4538722005-05-12 22:48:20 -0400168void free_ieee80211(struct net_device *dev)
169{
170 struct ieee80211_device *ieee = netdev_priv(dev);
171
172 int i;
173
James Ketrenos0ad0c3c2005-09-21 11:54:15 -0500174 ieee80211_crypt_quiescing(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400175 del_timer_sync(&ieee->crypt_deinit_timer);
176 ieee80211_crypt_deinit_entries(ieee, 1);
177
178 for (i = 0; i < WEP_KEYS; i++) {
179 struct ieee80211_crypt_data *crypt = ieee->crypt[i];
180 if (crypt) {
181 if (crypt->ops) {
182 crypt->ops->deinit(crypt->priv);
183 module_put(crypt->ops->owner);
184 }
185 kfree(crypt);
186 ieee->crypt[i] = NULL;
187 }
188 }
189
190 ieee80211_networks_free(ieee);
191 free_netdev(dev);
192}
193
194#ifdef CONFIG_IEEE80211_DEBUG
195
196static int debug = 0;
197u32 ieee80211_debug_level = 0;
198struct proc_dir_entry *ieee80211_proc = NULL;
199
200static int show_debug_level(char *page, char **start, off_t offset,
201 int count, int *eof, void *data)
202{
203 return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
204}
205
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400206static int store_debug_level(struct file *file, const char __user * buffer,
Jeff Garzikb4538722005-05-12 22:48:20 -0400207 unsigned long count, void *data)
208{
James Ketrenos262d8e42005-09-13 17:42:53 -0500209 char buf[] = "0x00000000\n";
210 unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
Jeff Garzikb4538722005-05-12 22:48:20 -0400211 unsigned long val;
212
James Ketrenos262d8e42005-09-13 17:42:53 -0500213 if (copy_from_user(buf, buffer, len))
Jeff Garzikb4538722005-05-12 22:48:20 -0400214 return count;
James Ketrenos262d8e42005-09-13 17:42:53 -0500215 buf[len] = 0;
216 if (sscanf(buf, "%li", &val) != 1)
Jeff Garzikb4538722005-05-12 22:48:20 -0400217 printk(KERN_INFO DRV_NAME
218 ": %s is not in hex or decimal form.\n", buf);
219 else
220 ieee80211_debug_level = val;
221
James Ketrenos262d8e42005-09-13 17:42:53 -0500222 return strnlen(buf, len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400223}
James Ketrenos31696162005-09-21 11:58:46 -0500224#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400225
226static int __init ieee80211_init(void)
227{
James Ketrenos31696162005-09-21 11:58:46 -0500228#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400229 struct proc_dir_entry *e;
230
231 ieee80211_debug_level = debug;
Al Viro66600222005-09-28 22:32:57 +0100232 ieee80211_proc = proc_mkdir(DRV_NAME, proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400233 if (ieee80211_proc == NULL) {
234 IEEE80211_ERROR("Unable to create " DRV_NAME
235 " proc directory\n");
236 return -EIO;
237 }
238 e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
239 ieee80211_proc);
240 if (!e) {
241 remove_proc_entry(DRV_NAME, proc_net);
242 ieee80211_proc = NULL;
243 return -EIO;
244 }
245 e->read_proc = show_debug_level;
246 e->write_proc = store_debug_level;
247 e->data = NULL;
James Ketrenos31696162005-09-21 11:58:46 -0500248#endif /* CONFIG_IEEE80211_DEBUG */
249
250 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
251 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400252
253 return 0;
254}
255
256static void __exit ieee80211_exit(void)
257{
James Ketrenos31696162005-09-21 11:58:46 -0500258#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400259 if (ieee80211_proc) {
260 remove_proc_entry("debug_level", ieee80211_proc);
261 remove_proc_entry(DRV_NAME, proc_net);
262 ieee80211_proc = NULL;
263 }
James Ketrenos31696162005-09-21 11:58:46 -0500264#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400265}
266
James Ketrenos31696162005-09-21 11:58:46 -0500267#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400268#include <linux/moduleparam.h>
269module_param(debug, int, 0444);
270MODULE_PARM_DESC(debug, "debug output mask");
James Ketrenos31696162005-09-21 11:58:46 -0500271#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400272
Jeff Garzikb4538722005-05-12 22:48:20 -0400273module_exit(ieee80211_exit);
274module_init(ieee80211_init);
Jeff Garzikb4538722005-05-12 22:48:20 -0400275
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400276const char *escape_essid(const char *essid, u8 essid_len)
277{
Jiri Bence88187e2005-08-25 20:00:53 -0400278 static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
279 const char *s = essid;
280 char *d = escaped;
281
282 if (ieee80211_is_empty_essid(essid, essid_len)) {
283 memcpy(escaped, "<hidden>", sizeof("<hidden>"));
284 return escaped;
285 }
286
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400287 essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
Jiri Bence88187e2005-08-25 20:00:53 -0400288 while (essid_len--) {
289 if (*s == '\0') {
290 *d++ = '\\';
291 *d++ = '0';
292 s++;
293 } else {
294 *d++ = *s++;
295 }
296 }
297 *d = '\0';
298 return escaped;
299}
300
Jeff Garzikb4538722005-05-12 22:48:20 -0400301EXPORT_SYMBOL(alloc_ieee80211);
302EXPORT_SYMBOL(free_ieee80211);
Jiri Bence88187e2005-08-25 20:00:53 -0400303EXPORT_SYMBOL(escape_essid);