blob: f66d792cd204b068976f7655e625cb4a21d99978 [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>
48#include <linux/version.h>
49#include <linux/wireless.h>
50#include <linux/etherdevice.h>
51#include <asm/uaccess.h>
52#include <net/arp.h>
53
54#include <net/ieee80211.h>
55
James Ketrenos31696162005-09-21 11:58:46 -050056#define DRV_DESCRIPTION "802.11 data/management/control stack"
57#define DRV_NAME "ieee80211"
58#define DRV_VERSION IEEE80211_VERSION
59#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
66static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
67{
68 if (ieee->networks)
69 return 0;
70
Jeff Garzik0edd5b42005-09-07 00:48:31 -040071 ieee->networks =
72 kmalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
73 GFP_KERNEL);
Jeff Garzikb4538722005-05-12 22:48:20 -040074 if (!ieee->networks) {
75 printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
76 ieee->dev->name);
77 return -ENOMEM;
78 }
79
80 memset(ieee->networks, 0,
81 MAX_NETWORK_COUNT * sizeof(struct ieee80211_network));
82
83 return 0;
84}
85
86static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
87{
88 if (!ieee->networks)
89 return;
90 kfree(ieee->networks);
91 ieee->networks = NULL;
92}
93
94static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee)
95{
96 int i;
97
98 INIT_LIST_HEAD(&ieee->network_free_list);
99 INIT_LIST_HEAD(&ieee->network_list);
100 for (i = 0; i < MAX_NETWORK_COUNT; i++)
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400101 list_add_tail(&ieee->networks[i].list,
102 &ieee->network_free_list);
Jeff Garzikb4538722005-05-12 22:48:20 -0400103}
104
Jeff Garzikb4538722005-05-12 22:48:20 -0400105struct net_device *alloc_ieee80211(int sizeof_priv)
106{
107 struct ieee80211_device *ieee;
108 struct net_device *dev;
109 int err;
110
111 IEEE80211_DEBUG_INFO("Initializing...\n");
112
113 dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
114 if (!dev) {
115 IEEE80211_ERROR("Unable to network device.\n");
116 goto failed;
117 }
118 ieee = netdev_priv(dev);
119 dev->hard_start_xmit = ieee80211_xmit;
120
121 ieee->dev = dev;
122
123 err = ieee80211_networks_allocate(ieee);
124 if (err) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400125 IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
Jeff Garzikb4538722005-05-12 22:48:20 -0400126 goto failed;
127 }
128 ieee80211_networks_initialize(ieee);
129
130 /* Default fragmentation threshold is maximum payload size */
131 ieee->fts = DEFAULT_FTS;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500132 ieee->rts = DEFAULT_FTS;
Jeff Garzikb4538722005-05-12 22:48:20 -0400133 ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
134 ieee->open_wep = 1;
135
136 /* Default to enabling full open WEP with host based encrypt/decrypt */
137 ieee->host_encrypt = 1;
138 ieee->host_decrypt = 1;
James Ketrenosccd0fda2005-09-21 11:58:32 -0500139 ieee->host_mc_decrypt = 1;
140
James Ketrenos1264fc02005-09-21 11:54:53 -0500141 /* Host fragementation in Open mode. Default is enabled.
142 * Note: host fragmentation is always enabled if host encryption
143 * is enabled. For cards can do hardware encryption, they must do
144 * hardware fragmentation as well. So we don't need a variable
145 * like host_enc_frag. */
146 ieee->host_open_frag = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400147 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
Jeff Garzikb4538722005-05-12 22:48:20 -0400148
149 INIT_LIST_HEAD(&ieee->crypt_deinit_list);
150 init_timer(&ieee->crypt_deinit_timer);
151 ieee->crypt_deinit_timer.data = (unsigned long)ieee;
152 ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
James Ketrenos0ad0c3c2005-09-21 11:54:15 -0500153 ieee->crypt_quiesced = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400154
155 spin_lock_init(&ieee->lock);
156
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400157 ieee->wpa_enabled = 0;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400158 ieee->drop_unencrypted = 0;
159 ieee->privacy_invoked = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400160
161 return dev;
162
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400163 failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400164 if (dev)
165 free_netdev(dev);
166 return NULL;
167}
168
Jeff Garzikb4538722005-05-12 22:48:20 -0400169void free_ieee80211(struct net_device *dev)
170{
171 struct ieee80211_device *ieee = netdev_priv(dev);
172
173 int i;
174
James Ketrenos0ad0c3c2005-09-21 11:54:15 -0500175 ieee80211_crypt_quiescing(ieee);
Jeff Garzikb4538722005-05-12 22:48:20 -0400176 del_timer_sync(&ieee->crypt_deinit_timer);
177 ieee80211_crypt_deinit_entries(ieee, 1);
178
179 for (i = 0; i < WEP_KEYS; i++) {
180 struct ieee80211_crypt_data *crypt = ieee->crypt[i];
181 if (crypt) {
182 if (crypt->ops) {
183 crypt->ops->deinit(crypt->priv);
184 module_put(crypt->ops->owner);
185 }
186 kfree(crypt);
187 ieee->crypt[i] = NULL;
188 }
189 }
190
191 ieee80211_networks_free(ieee);
192 free_netdev(dev);
193}
194
195#ifdef CONFIG_IEEE80211_DEBUG
196
197static int debug = 0;
198u32 ieee80211_debug_level = 0;
199struct proc_dir_entry *ieee80211_proc = NULL;
200
201static int show_debug_level(char *page, char **start, off_t offset,
202 int count, int *eof, void *data)
203{
204 return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
205}
206
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400207static int store_debug_level(struct file *file, const char __user * buffer,
Jeff Garzikb4538722005-05-12 22:48:20 -0400208 unsigned long count, void *data)
209{
James Ketrenos262d8e42005-09-13 17:42:53 -0500210 char buf[] = "0x00000000\n";
211 unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
Jeff Garzikb4538722005-05-12 22:48:20 -0400212 unsigned long val;
213
James Ketrenos262d8e42005-09-13 17:42:53 -0500214 if (copy_from_user(buf, buffer, len))
Jeff Garzikb4538722005-05-12 22:48:20 -0400215 return count;
James Ketrenos262d8e42005-09-13 17:42:53 -0500216 buf[len] = 0;
217 if (sscanf(buf, "%li", &val) != 1)
Jeff Garzikb4538722005-05-12 22:48:20 -0400218 printk(KERN_INFO DRV_NAME
219 ": %s is not in hex or decimal form.\n", buf);
220 else
221 ieee80211_debug_level = val;
222
James Ketrenos262d8e42005-09-13 17:42:53 -0500223 return strnlen(buf, len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400224}
James Ketrenos31696162005-09-21 11:58:46 -0500225#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400226
227static int __init ieee80211_init(void)
228{
James Ketrenos31696162005-09-21 11:58:46 -0500229#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400230 struct proc_dir_entry *e;
231
232 ieee80211_debug_level = debug;
Al Viro66600222005-09-28 22:32:57 +0100233 ieee80211_proc = proc_mkdir(DRV_NAME, proc_net);
Jeff Garzikb4538722005-05-12 22:48:20 -0400234 if (ieee80211_proc == NULL) {
235 IEEE80211_ERROR("Unable to create " DRV_NAME
236 " proc directory\n");
237 return -EIO;
238 }
239 e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
240 ieee80211_proc);
241 if (!e) {
242 remove_proc_entry(DRV_NAME, proc_net);
243 ieee80211_proc = NULL;
244 return -EIO;
245 }
246 e->read_proc = show_debug_level;
247 e->write_proc = store_debug_level;
248 e->data = NULL;
James Ketrenos31696162005-09-21 11:58:46 -0500249#endif /* CONFIG_IEEE80211_DEBUG */
250
251 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
252 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400253
254 return 0;
255}
256
257static void __exit ieee80211_exit(void)
258{
James Ketrenos31696162005-09-21 11:58:46 -0500259#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400260 if (ieee80211_proc) {
261 remove_proc_entry("debug_level", ieee80211_proc);
262 remove_proc_entry(DRV_NAME, proc_net);
263 ieee80211_proc = NULL;
264 }
James Ketrenos31696162005-09-21 11:58:46 -0500265#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400266}
267
James Ketrenos31696162005-09-21 11:58:46 -0500268#ifdef CONFIG_IEEE80211_DEBUG
Jeff Garzikb4538722005-05-12 22:48:20 -0400269#include <linux/moduleparam.h>
270module_param(debug, int, 0444);
271MODULE_PARM_DESC(debug, "debug output mask");
James Ketrenos31696162005-09-21 11:58:46 -0500272#endif /* CONFIG_IEEE80211_DEBUG */
Jeff Garzikb4538722005-05-12 22:48:20 -0400273
Jeff Garzikb4538722005-05-12 22:48:20 -0400274module_exit(ieee80211_exit);
275module_init(ieee80211_init);
Jeff Garzikb4538722005-05-12 22:48:20 -0400276
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400277const char *escape_essid(const char *essid, u8 essid_len)
278{
Jiri Bence88187e2005-08-25 20:00:53 -0400279 static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
280 const char *s = essid;
281 char *d = escaped;
282
283 if (ieee80211_is_empty_essid(essid, essid_len)) {
284 memcpy(escaped, "<hidden>", sizeof("<hidden>"));
285 return escaped;
286 }
287
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400288 essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
Jiri Bence88187e2005-08-25 20:00:53 -0400289 while (essid_len--) {
290 if (*s == '\0') {
291 *d++ = '\\';
292 *d++ = '0';
293 s++;
294 } else {
295 *d++ = *s++;
296 }
297 }
298 *d = '\0';
299 return escaped;
300}
301
Jeff Garzikb4538722005-05-12 22:48:20 -0400302EXPORT_SYMBOL(alloc_ieee80211);
303EXPORT_SYMBOL(free_ieee80211);
Jiri Bence88187e2005-08-25 20:00:53 -0400304EXPORT_SYMBOL(escape_essid);