aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2008-11-11 16:45:38 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-11-21 11:08:18 -0500
commitbeb2a7f331361bfe81e71acdb0739eae570475a2 (patch)
treede7ee004296ae3bd5aeb85c19c82d419074f4f29 /net
parent0795cd29b6fe05107b40080cb1fccadb96320c96 (diff)
net/ieee80211 -> drivers/net/ipw2x00/libipw_* rename
The old ieee80211 code only remains as a support library for the ipw2100 and ipw2200 drivers. So, move the code and rename it appropriately to reflects it's true purpose and status. Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/Kconfig1
-rw-r--r--net/Makefile1
-rw-r--r--net/ieee80211/Kconfig41
-rw-r--r--net/ieee80211/Makefile8
-rw-r--r--net/ieee80211/ieee80211_geo.c195
-rw-r--r--net/ieee80211/ieee80211_module.c293
-rw-r--r--net/ieee80211/ieee80211_rx.c1799
-rw-r--r--net/ieee80211/ieee80211_tx.c546
-rw-r--r--net/ieee80211/ieee80211_wx.c760
9 files changed, 0 insertions, 3644 deletions
diff --git a/net/Kconfig b/net/Kconfig
index c7d01c3a23c..6ec2cce7c16 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -251,7 +251,6 @@ if WIRELESS
251 251
252source "net/wireless/Kconfig" 252source "net/wireless/Kconfig"
253source "net/mac80211/Kconfig" 253source "net/mac80211/Kconfig"
254source "net/ieee80211/Kconfig"
255 254
256endif # WIRELESS 255endif # WIRELESS
257 256
diff --git a/net/Makefile b/net/Makefile
index 83b064651f1..e5af3dc3a03 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -51,7 +51,6 @@ obj-$(CONFIG_IP_DCCP) += dccp/
51obj-$(CONFIG_IP_SCTP) += sctp/ 51obj-$(CONFIG_IP_SCTP) += sctp/
52obj-y += wireless/ 52obj-y += wireless/
53obj-$(CONFIG_MAC80211) += mac80211/ 53obj-$(CONFIG_MAC80211) += mac80211/
54obj-$(CONFIG_IEEE80211) += ieee80211/
55obj-$(CONFIG_TIPC) += tipc/ 54obj-$(CONFIG_TIPC) += tipc/
56obj-$(CONFIG_NETLABEL) += netlabel/ 55obj-$(CONFIG_NETLABEL) += netlabel/
57obj-$(CONFIG_IUCV) += iucv/ 56obj-$(CONFIG_IUCV) += iucv/
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
deleted file mode 100644
index 46f24f4c9dc..00000000000
--- a/net/ieee80211/Kconfig
+++ /dev/null
@@ -1,41 +0,0 @@
1config IEEE80211
2 tristate
3 select WIRELESS_EXT
4 select CRYPTO
5 select CRYPTO_ARC4
6 select CRYPTO_ECB
7 select CRYPTO_AES
8 select CRYPTO_MICHAEL_MIC
9 select CRYPTO_ECB
10 select CRC32
11 select LIB80211
12 select LIB80211_CRYPT_WEP
13 select LIB80211_CRYPT_TKIP
14 select LIB80211_CRYPT_CCMP
15 ---help---
16 This option enables the hardware independent IEEE 802.11
17 networking stack. This component is deprecated in favor of the
18 mac80211 component.
19
20config IEEE80211_DEBUG
21 bool "Full debugging output for the old IEEE80211 stack"
22 depends on IEEE80211
23 ---help---
24 This option will enable debug tracing output for the
25 ieee80211 network stack.
26
27 This will result in the kernel module being ~70k larger. You
28 can control which debug output is sent to the kernel log by
29 setting the value in
30
31 /proc/net/ieee80211/debug_level
32
33 For example:
34
35 % echo 0x00000FFO > /proc/net/ieee80211/debug_level
36
37 For a list of values you can assign to debug_level, you
38 can look at the bit mask values in <net/ieee80211.h>
39
40 If you are not trying to debug or develop the ieee80211
41 subsystem, you most likely want to say N here.
diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile
deleted file mode 100644
index 158963ff18d..00000000000
--- a/net/ieee80211/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
1obj-$(CONFIG_IEEE80211) += ieee80211.o
2ieee80211-objs := \
3 ieee80211_module.o \
4 ieee80211_tx.o \
5 ieee80211_rx.o \
6 ieee80211_wx.o \
7 ieee80211_geo.o
8
diff --git a/net/ieee80211/ieee80211_geo.c b/net/ieee80211/ieee80211_geo.c
deleted file mode 100644
index 960ad13f5e9..00000000000
--- a/net/ieee80211/ieee80211_geo.c
+++ /dev/null
@@ -1,195 +0,0 @@
1/******************************************************************************
2
3 Copyright(c) 2005 Intel Corporation. All rights reserved.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of version 2 of the GNU General Public License as
7 published by the Free Software Foundation.
8
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 59
16 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 The full GNU General Public License is included in this distribution in the
19 file called LICENSE.
20
21 Contact Information:
22 James P. Ketrenos <ipw2100-admin@linux.intel.com>
23 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24
25******************************************************************************/
26#include <linux/compiler.h>
27#include <linux/errno.h>
28#include <linux/if_arp.h>
29#include <linux/in6.h>
30#include <linux/in.h>
31#include <linux/ip.h>
32#include <linux/kernel.h>
33#include <linux/module.h>
34#include <linux/netdevice.h>
35#include <linux/proc_fs.h>
36#include <linux/skbuff.h>
37#include <linux/slab.h>
38#include <linux/tcp.h>
39#include <linux/types.h>
40#include <linux/wireless.h>
41#include <linux/etherdevice.h>
42#include <asm/uaccess.h>
43
44#include <net/ieee80211.h>
45
46int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel)
47{
48 int i;
49
50 /* Driver needs to initialize the geography map before using
51 * these helper functions */
52 if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
53 return 0;
54
55 if (ieee->freq_band & IEEE80211_24GHZ_BAND)
56 for (i = 0; i < ieee->geo.bg_channels; i++)
57 /* NOTE: If G mode is currently supported but
58 * this is a B only channel, we don't see it
59 * as valid. */
60 if ((ieee->geo.bg[i].channel == channel) &&
61 !(ieee->geo.bg[i].flags & IEEE80211_CH_INVALID) &&
62 (!(ieee->mode & IEEE_G) ||
63 !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY)))
64 return IEEE80211_24GHZ_BAND;
65
66 if (ieee->freq_band & IEEE80211_52GHZ_BAND)
67 for (i = 0; i < ieee->geo.a_channels; i++)
68 if ((ieee->geo.a[i].channel == channel) &&
69 !(ieee->geo.a[i].flags & IEEE80211_CH_INVALID))
70 return IEEE80211_52GHZ_BAND;
71
72 return 0;
73}
74
75int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
76{
77 int i;
78
79 /* Driver needs to initialize the geography map before using
80 * these helper functions */
81 if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
82 return -1;
83
84 if (ieee->freq_band & IEEE80211_24GHZ_BAND)
85 for (i = 0; i < ieee->geo.bg_channels; i++)
86 if (ieee->geo.bg[i].channel == channel)
87 return i;
88
89 if (ieee->freq_band & IEEE80211_52GHZ_BAND)
90 for (i = 0; i < ieee->geo.a_channels; i++)
91 if (ieee->geo.a[i].channel == channel)
92 return i;
93
94 return -1;
95}
96
97u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel)
98{
99 const struct ieee80211_channel * ch;
100
101 /* Driver needs to initialize the geography map before using
102 * these helper functions */
103 if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
104 return 0;
105
106 ch = ieee80211_get_channel(ieee, channel);
107 if (!ch->channel)
108 return 0;
109 return ch->freq;
110}
111
112u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
113{
114 int i;
115
116 /* Driver needs to initialize the geography map before using
117 * these helper functions */
118 if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
119 return 0;
120
121 freq /= 100000;
122
123 if (ieee->freq_band & IEEE80211_24GHZ_BAND)
124 for (i = 0; i < ieee->geo.bg_channels; i++)
125 if (ieee->geo.bg[i].freq == freq)
126 return ieee->geo.bg[i].channel;
127
128 if (ieee->freq_band & IEEE80211_52GHZ_BAND)
129 for (i = 0; i < ieee->geo.a_channels; i++)
130 if (ieee->geo.a[i].freq == freq)
131 return ieee->geo.a[i].channel;
132
133 return 0;
134}
135
136int ieee80211_set_geo(struct ieee80211_device *ieee,
137 const struct ieee80211_geo *geo)
138{
139 memcpy(ieee->geo.name, geo->name, 3);
140 ieee->geo.name[3] = '\0';
141 ieee->geo.bg_channels = geo->bg_channels;
142 ieee->geo.a_channels = geo->a_channels;
143 memcpy(ieee->geo.bg, geo->bg, geo->bg_channels *
144 sizeof(struct ieee80211_channel));
145 memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
146 sizeof(struct ieee80211_channel));
147 return 0;
148}
149
150const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device *ieee)
151{
152 return &ieee->geo;
153}
154
155u8 ieee80211_get_channel_flags(struct ieee80211_device * ieee, u8 channel)
156{
157 int index = ieee80211_channel_to_index(ieee, channel);
158
159 if (index == -1)
160 return IEEE80211_CH_INVALID;
161
162 if (channel <= IEEE80211_24GHZ_CHANNELS)
163 return ieee->geo.bg[index].flags;
164
165 return ieee->geo.a[index].flags;
166}
167
168static const struct ieee80211_channel bad_channel = {
169 .channel = 0,
170 .flags = IEEE80211_CH_INVALID,
171 .max_power = 0,
172};
173
174const struct ieee80211_channel *ieee80211_get_channel(struct ieee80211_device
175 *ieee, u8 channel)
176{
177 int index = ieee80211_channel_to_index(ieee, channel);
178
179 if (index == -1)
180 return &bad_channel;
181
182 if (channel <= IEEE80211_24GHZ_CHANNELS)
183 return &ieee->geo.bg[index];
184
185 return &ieee->geo.a[index];
186}
187
188EXPORT_SYMBOL(ieee80211_get_channel);
189EXPORT_SYMBOL(ieee80211_get_channel_flags);
190EXPORT_SYMBOL(ieee80211_is_valid_channel);
191EXPORT_SYMBOL(ieee80211_freq_to_channel);
192EXPORT_SYMBOL(ieee80211_channel_to_freq);
193EXPORT_SYMBOL(ieee80211_channel_to_index);
194EXPORT_SYMBOL(ieee80211_set_geo);
195EXPORT_SYMBOL(ieee80211_get_geo);
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
deleted file mode 100644
index a2f5616d5b0..00000000000
--- a/net/ieee80211/ieee80211_module.c
+++ /dev/null
@@ -1,293 +0,0 @@
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 <net/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
108static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
109{
110 int i;
111
112 INIT_LIST_HEAD(&ieee->network_free_list);
113 INIT_LIST_HEAD(&ieee->network_list);
114 for (i = 0; i < MAX_NETWORK_COUNT; i++)
115 list_add_tail(&ieee->networks[i].list,
116 &ieee->network_free_list);
117}
118
119static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
120{
121 if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN))
122 return -EINVAL;
123 dev->mtu = new_mtu;
124 return 0;
125}
126
127static struct net_device_stats *ieee80211_generic_get_stats(
128 struct net_device *dev)
129{
130 struct ieee80211_device *ieee = netdev_priv(dev);
131 return &ieee->stats;
132}
133
134struct net_device *alloc_ieee80211(int sizeof_priv)
135{
136 struct ieee80211_device *ieee;
137 struct net_device *dev;
138 int err;
139
140 IEEE80211_DEBUG_INFO("Initializing...\n");
141
142 dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
143 if (!dev) {
144 IEEE80211_ERROR("Unable to allocate network device.\n");
145 goto failed;
146 }
147 ieee = netdev_priv(dev);
148 dev->hard_start_xmit = ieee80211_xmit;
149 dev->change_mtu = ieee80211_change_mtu;
150
151 /* Drivers are free to override this if the generic implementation
152 * does not meet their needs. */
153 dev->get_stats = ieee80211_generic_get_stats;
154
155 ieee->dev = dev;
156
157 err = ieee80211_networks_allocate(ieee);
158 if (err) {
159 IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
160 goto failed_free_netdev;
161 }
162 ieee80211_networks_initialize(ieee);
163
164 /* Default fragmentation threshold is maximum payload size */
165 ieee->fts = DEFAULT_FTS;
166 ieee->rts = DEFAULT_FTS;
167 ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
168 ieee->open_wep = 1;
169
170 /* Default to enabling full open WEP with host based encrypt/decrypt */
171 ieee->host_encrypt = 1;
172 ieee->host_decrypt = 1;
173 ieee->host_mc_decrypt = 1;
174
175 /* Host fragementation in Open mode. Default is enabled.
176 * Note: host fragmentation is always enabled if host encryption
177 * is enabled. For cards can do hardware encryption, they must do
178 * hardware fragmentation as well. So we don't need a variable
179 * like host_enc_frag. */
180 ieee->host_open_frag = 1;
181 ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
182
183 spin_lock_init(&ieee->lock);
184
185 lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
186
187 ieee->wpa_enabled = 0;
188 ieee->drop_unencrypted = 0;
189 ieee->privacy_invoked = 0;
190
191 return dev;
192
193failed_free_netdev:
194 free_netdev(dev);
195failed:
196 return NULL;
197}
198
199void free_ieee80211(struct net_device *dev)
200{
201 struct ieee80211_device *ieee = netdev_priv(dev);
202
203 lib80211_crypt_info_free(&ieee->crypt_info);
204
205 ieee80211_networks_free(ieee);
206 free_netdev(dev);
207}
208
209#ifdef CONFIG_IEEE80211_DEBUG
210
211static int debug = 0;
212u32 ieee80211_debug_level = 0;
213EXPORT_SYMBOL_GPL(ieee80211_debug_level);
214static struct proc_dir_entry *ieee80211_proc = NULL;
215
216static int show_debug_level(char *page, char **start, off_t offset,
217 int count, int *eof, void *data)
218{
219 return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
220}
221
222static int store_debug_level(struct file *file, const char __user * buffer,
223 unsigned long count, void *data)
224{
225 char buf[] = "0x00000000\n";
226 unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
227 unsigned long val;
228
229 if (copy_from_user(buf, buffer, len))
230 return count;
231 buf[len] = 0;
232 if (sscanf(buf, "%li", &val) != 1)
233 printk(KERN_INFO DRV_NAME
234 ": %s is not in hex or decimal form.\n", buf);
235 else
236 ieee80211_debug_level = val;
237
238 return strnlen(buf, len);
239}
240#endif /* CONFIG_IEEE80211_DEBUG */
241
242static int __init ieee80211_init(void)
243{
244#ifdef CONFIG_IEEE80211_DEBUG
245 struct proc_dir_entry *e;
246
247 ieee80211_debug_level = debug;
248 ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
249 if (ieee80211_proc == NULL) {
250 IEEE80211_ERROR("Unable to create " DRV_NAME
251 " proc directory\n");
252 return -EIO;
253 }
254 e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
255 ieee80211_proc);
256 if (!e) {
257 remove_proc_entry(DRV_NAME, init_net.proc_net);
258 ieee80211_proc = NULL;
259 return -EIO;
260 }
261 e->read_proc = show_debug_level;
262 e->write_proc = store_debug_level;
263 e->data = NULL;
264#endif /* CONFIG_IEEE80211_DEBUG */
265
266 printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
267 printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
268
269 return 0;
270}
271
272static void __exit ieee80211_exit(void)
273{
274#ifdef CONFIG_IEEE80211_DEBUG
275 if (ieee80211_proc) {
276 remove_proc_entry("debug_level", ieee80211_proc);
277 remove_proc_entry(DRV_NAME, init_net.proc_net);
278 ieee80211_proc = NULL;
279 }
280#endif /* CONFIG_IEEE80211_DEBUG */
281}
282
283#ifdef CONFIG_IEEE80211_DEBUG
284#include <linux/moduleparam.h>
285module_param(debug, int, 0444);
286MODULE_PARM_DESC(debug, "debug output mask");
287#endif /* CONFIG_IEEE80211_DEBUG */
288
289module_exit(ieee80211_exit);
290module_init(ieee80211_init);
291
292EXPORT_SYMBOL(alloc_ieee80211);
293EXPORT_SYMBOL(free_ieee80211);
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
deleted file mode 100644
index 9c67dfae432..00000000000
--- a/net/ieee80211/ieee80211_rx.c
+++ /dev/null
@@ -1,1799 +0,0 @@
1/*
2 * Original code based Host AP (software wireless LAN access point) driver
3 * for Intersil Prism2/2.5/3 - hostap.o module, common routines
4 *
5 * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
6 * <j@w1.fi>
7 * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
8 * Copyright (c) 2004-2005, Intel Corporation
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation. See README and COPYING for
13 * more details.
14 */
15
16#include <linux/compiler.h>
17#include <linux/errno.h>
18#include <linux/if_arp.h>
19#include <linux/in6.h>
20#include <linux/in.h>
21#include <linux/ip.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/netdevice.h>
25#include <linux/proc_fs.h>
26#include <linux/skbuff.h>
27#include <linux/slab.h>
28#include <linux/tcp.h>
29#include <linux/types.h>
30#include <linux/wireless.h>
31#include <linux/etherdevice.h>
32#include <asm/uaccess.h>
33#include <linux/ctype.h>
34
35#include <net/lib80211.h>
36#include <net/ieee80211.h>
37
38static void ieee80211_monitor_rx(struct ieee80211_device *ieee,
39 struct sk_buff *skb,
40 struct ieee80211_rx_stats *rx_stats)
41{
42 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
43 u16 fc = le16_to_cpu(hdr->frame_control);
44
45 skb->dev = ieee->dev;
46 skb_reset_mac_header(skb);
47 skb_pull(skb, ieee80211_get_hdrlen(fc));
48 skb->pkt_type = PACKET_OTHERHOST;
49 skb->protocol = htons(ETH_P_80211_RAW);
50 memset(skb->cb, 0, sizeof(skb->cb));
51 netif_rx(skb);
52}
53
54/* Called only as a tasklet (software IRQ) */
55static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct
56 ieee80211_device
57 *ieee,
58 unsigned int seq,
59 unsigned int frag,
60 u8 * src,
61 u8 * dst)
62{
63 struct ieee80211_frag_entry *entry;
64 int i;
65
66 for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) {
67 entry = &ieee->frag_cache[i];
68 if (entry->skb != NULL &&
69 time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
70 IEEE80211_DEBUG_FRAG("expiring fragment cache entry "
71 "seq=%u last_frag=%u\n",
72 entry->seq, entry->last_frag);
73 dev_kfree_skb_any(entry->skb);
74 entry->skb = NULL;
75 }
76
77 if (entry->skb != NULL && entry->seq == seq &&
78 (entry->last_frag + 1 == frag || frag == -1) &&
79 !compare_ether_addr(entry->src_addr, src) &&
80 !compare_ether_addr(entry->dst_addr, dst))
81 return entry;
82 }
83
84 return NULL;
85}
86
87/* Called only as a tasklet (software IRQ) */
88static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee,
89 struct ieee80211_hdr_4addr *hdr)
90{
91 struct sk_buff *skb = NULL;
92 u16 sc;
93 unsigned int frag, seq;
94 struct ieee80211_frag_entry *entry;
95
96 sc = le16_to_cpu(hdr->seq_ctl);
97 frag = WLAN_GET_SEQ_FRAG(sc);
98 seq = WLAN_GET_SEQ_SEQ(sc);
99
100 if (frag == 0) {
101 /* Reserve enough space to fit maximum frame length */
102 skb = dev_alloc_skb(ieee->dev->mtu +
103 sizeof(struct ieee80211_hdr_4addr) +
104 8 /* LLC */ +
105 2 /* alignment */ +
106 8 /* WEP */ + ETH_ALEN /* WDS */ );
107 if (skb == NULL)
108 return NULL;
109
110 entry = &ieee->frag_cache[ieee->frag_next_idx];
111 ieee->frag_next_idx++;
112 if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN)
113 ieee->frag_next_idx = 0;
114
115 if (entry->skb != NULL)
116 dev_kfree_skb_any(entry->skb);
117
118 entry->first_frag_time = jiffies;
119 entry->seq = seq;
120 entry->last_frag = frag;
121 entry->skb = skb;
122 memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
123 memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
124 } else {
125 /* received a fragment of a frame for which the head fragment
126 * should have already been received */
127 entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2,
128 hdr->addr1);
129 if (entry != NULL) {
130 entry->last_frag = frag;
131 skb = entry->skb;
132 }
133 }
134
135 return skb;
136}
137
138/* Called only as a tasklet (software IRQ) */
139static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
140 struct ieee80211_hdr_4addr *hdr)
141{
142 u16 sc;
143 unsigned int seq;
144 struct ieee80211_frag_entry *entry;
145
146 sc = le16_to_cpu(hdr->seq_ctl);
147 seq = WLAN_GET_SEQ_SEQ(sc);
148
149 entry = ieee80211_frag_cache_find(ieee, seq, -1, hdr->addr2,
150 hdr->addr1);
151
152 if (entry == NULL) {
153 IEEE80211_DEBUG_FRAG("could not invalidate fragment cache "
154 "entry (seq=%u)\n", seq);
155 return -1;
156 }
157
158 entry->skb = NULL;
159 return 0;
160}
161
162#ifdef NOT_YET
163/* ieee80211_rx_frame_mgtmt
164 *
165 * Responsible for handling management control frames
166 *
167 * Called by ieee80211_rx */
168static int
169ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
170 struct ieee80211_rx_stats *rx_stats, u16 type,
171 u16 stype)
172{
173 if (ieee->iw_mode == IW_MODE_MASTER) {
174 printk(KERN_DEBUG "%s: Master mode not yet suppported.\n",
175 ieee->dev->name);
176 return 0;
177/*
178 hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr_4addr *)
179 skb->data);*/
180 }
181
182 if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) {
183 if (stype == WLAN_FC_STYPE_BEACON &&
184 ieee->iw_mode == IW_MODE_MASTER) {
185 struct sk_buff *skb2;
186 /* Process beacon frames also in kernel driver to
187 * update STA(AP) table statistics */
188 skb2 = skb_clone(skb, GFP_ATOMIC);
189 if (skb2)
190 hostap_rx(skb2->dev, skb2, rx_stats);
191 }
192
193 /* send management frames to the user space daemon for
194 * processing */
195 ieee->apdevstats.rx_packets++;
196 ieee->apdevstats.rx_bytes += skb->len;
197 prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT);
198 return 0;
199 }
200
201 if (ieee->iw_mode == IW_MODE_MASTER) {
202 if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) {
203 printk(KERN_DEBUG "%s: unknown management frame "
204 "(type=0x%02x, stype=0x%02x) dropped\n",
205 skb->dev->name, type, stype);
206 return -1;
207 }
208
209 hostap_rx(skb->dev, skb, rx_stats);
210 return 0;
211 }
212
213 printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame "
214 "received in non-Host AP mode\n", skb->dev->name);
215 return -1;
216}
217#endif
218
219/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
220/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
221static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
222
223/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
224static unsigned char bridge_tunnel_header[] =
225 { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
226/* No encapsulation header if EtherType < 0x600 (=length) */
227
228/* Called by ieee80211_rx_frame_decrypt */
229static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
230 struct sk_buff *skb)
231{
232 struct net_device *dev = ieee->dev;
233 u16 fc, ethertype;
234 struct ieee80211_hdr_3addr *hdr;
235 u8 *pos;
236
237 if (skb->len < 24)
238 return 0;
239
240 hdr = (struct ieee80211_hdr_3addr *)skb->data;
241 fc = le16_to_cpu(hdr->frame_ctl);
242
243 /* check that the frame is unicast frame to us */
244 if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
245 IEEE80211_FCTL_TODS &&
246 !compare_ether_addr(hdr->addr1, dev->dev_addr) &&
247 !compare_ether_addr(hdr->addr3, dev->dev_addr)) {
248 /* ToDS frame with own addr BSSID and DA */
249 } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
250 IEEE80211_FCTL_FROMDS &&
251 !compare_ether_addr(hdr->addr1, dev->dev_addr)) {
252 /* FromDS frame with own addr as DA */
253 } else
254 return 0;
255
256 if (skb->len < 24 + 8)
257 return 0;
258
259 /* check for port access entity Ethernet type */
260 pos = skb->data + 24;
261 ethertype = (pos[6] << 8) | pos[7];
262 if (ethertype == ETH_P_PAE)
263 return 1;
264
265 return 0;
266}
267
268/* Called only as a tasklet (software IRQ), by ieee80211_rx */
269static int
270ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
271 struct lib80211_crypt_data *crypt)
272{
273 struct ieee80211_hdr_3addr *hdr;
274 int res, hdrlen;
275
276 if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
277 return 0;
278
279 hdr = (struct ieee80211_hdr_3addr *)skb->data;
280 hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
281
282 atomic_inc(&crypt->refcnt);
283 res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
284 atomic_dec(&crypt->refcnt);
285 if (res < 0) {
286 IEEE80211_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n",
287 hdr->addr2, res);
288 if (res == -2)
289 IEEE80211_DEBUG_DROP("Decryption failed ICV "
290 "mismatch (key %d)\n",
291 skb->data[hdrlen + 3] >> 6);
292 ieee->ieee_stats.rx_discards_undecryptable++;
293 return -1;
294 }
295
296 return res;
297}
298
299/* Called only as a tasklet (software IRQ), by ieee80211_rx */
300static int
301ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
302 struct sk_buff *skb, int keyidx,
303 struct lib80211_crypt_data *crypt)
304{
305 struct ieee80211_hdr_3addr *hdr;
306 int res, hdrlen;
307
308 if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
309 return 0;
310
311 hdr = (struct ieee80211_hdr_3addr *)skb->data;
312 hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
313
314 atomic_inc(&crypt->refcnt);
315 res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
316 atomic_dec(&crypt->refcnt);
317 if (res < 0) {
318 printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
319 " (SA=%pM keyidx=%d)\n", ieee->dev->name, hdr->addr2,
320 keyidx);
321 return -1;
322 }
323
324 return 0;
325}
326
327/* All received frames are sent to this function. @skb contains the frame in
328 * IEEE 802.11 format, i.e., in the format it was sent over air.
329 * This function is called only as a tasklet (software IRQ). */
330int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
331 struct ieee80211_rx_stats *rx_stats)
332{
333 struct net_device *dev = ieee->dev;
334 struct ieee80211_hdr_4addr *hdr;
335 size_t hdrlen;
336 u16 fc, type, stype, sc;
337 struct net_device_stats *stats;
338 unsigned int frag;
339 u8 *payload;
340 u16 ethertype;
341#ifdef NOT_YET
342 struct net_device *wds = NULL;
343 struct sk_buff *skb2 = NULL;
344 struct net_device *wds = NULL;
345 int frame_authorized = 0;
346 int from_assoc_ap = 0;
347 void *sta = NULL;
348#endif
349 u8 dst[ETH_ALEN];
350 u8 src[ETH_ALEN];
351 struct lib80211_crypt_data *crypt = NULL;
352 int keyidx = 0;
353 int can_be_decrypted = 0;
354
355 hdr = (struct ieee80211_hdr_4addr *)skb->data;
356 stats = &ieee->stats;
357
358 if (skb->len < 10) {
359 printk(KERN_INFO "%s: SKB length < 10\n", dev->name);
360 goto rx_dropped;
361 }
362
363 fc = le16_to_cpu(hdr->frame_ctl);
364 type = WLAN_FC_GET_TYPE(fc);
365 stype = WLAN_FC_GET_STYPE(fc);
366 sc = le16_to_cpu(hdr->seq_ctl);
367 frag = WLAN_GET_SEQ_FRAG(sc);
368 hdrlen = ieee80211_get_hdrlen(fc);
369
370 if (skb->len < hdrlen) {
371 printk(KERN_INFO "%s: invalid SKB length %d\n",
372 dev->name, skb->len);
373 goto rx_dropped;
374 }
375
376 /* Put this code here so that we avoid duplicating it in all
377 * Rx paths. - Jean II */
378#ifdef CONFIG_WIRELESS_EXT
379#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
380 /* If spy monitoring on */
381 if (ieee->spy_data.spy_number > 0) {
382 struct iw_quality wstats;
383
384 wstats.updated = 0;
385 if (rx_stats->mask & IEEE80211_STATMASK_RSSI) {
386 wstats.level = rx_stats->signal;
387 wstats.updated |= IW_QUAL_LEVEL_UPDATED;
388 } else
389 wstats.updated |= IW_QUAL_LEVEL_INVALID;
390
391 if (rx_stats->mask & IEEE80211_STATMASK_NOISE) {
392 wstats.noise = rx_stats->noise;
393 wstats.updated |= IW_QUAL_NOISE_UPDATED;
394 } else
395 wstats.updated |= IW_QUAL_NOISE_INVALID;
396
397 if (rx_stats->mask & IEEE80211_STATMASK_SIGNAL) {
398 wstats.qual = rx_stats->signal;
399 wstats.updated |= IW_QUAL_QUAL_UPDATED;
400 } else
401 wstats.updated |= IW_QUAL_QUAL_INVALID;
402
403 /* Update spy records */
404 wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
405 }
406#endif /* IW_WIRELESS_SPY */
407#endif /* CONFIG_WIRELESS_EXT */
408
409#ifdef NOT_YET
410 hostap_update_rx_stats(local->ap, hdr, rx_stats);
411#endif
412
413 if (ieee->iw_mode == IW_MODE_MONITOR) {
414 stats->rx_packets++;
415 stats->rx_bytes += skb->len;
416 ieee80211_monitor_rx(ieee, skb, rx_stats);
417 return 1;
418 }
419
420 can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) ||
421 is_broadcast_ether_addr(hdr->addr2)) ?
422 ieee->host_mc_decrypt : ieee->host_decrypt;
423
424 if (can_be_decrypted) {
425 if (skb->len >= hdrlen + 3) {
426 /* Top two-bits of byte 3 are the key index */
427 keyidx = skb->data[hdrlen + 3] >> 6;
428 }
429
430 /* ieee->crypt[] is WEP_KEY (4) in length. Given that keyidx
431 * is only allowed 2-bits of storage, no value of keyidx can
432 * be provided via above code that would result in keyidx
433 * being out of range */
434 crypt = ieee->crypt_info.crypt[keyidx];
435
436#ifdef NOT_YET
437 sta = NULL;
438
439 /* Use station specific key to override default keys if the
440 * receiver address is a unicast address ("individual RA"). If
441 * bcrx_sta_key parameter is set, station specific key is used
442 * even with broad/multicast targets (this is against IEEE
443 * 802.11, but makes it easier to use different keys with
444 * stations that do not support WEP key mapping). */
445
446 if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)
447 (void)hostap_handle_sta_crypto(local, hdr, &crypt,
448 &sta);
449#endif
450
451 /* allow NULL decrypt to indicate an station specific override
452 * for default encryption */
453 if (crypt && (crypt->ops == NULL ||
454 crypt->ops->decrypt_mpdu == NULL))
455 crypt = NULL;
456
457 if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
458 /* This seems to be triggered by some (multicast?)
459 * frames from other than current BSS, so just drop the
460 * frames silently instead of filling system log with
461 * these reports. */
462 IEEE80211_DEBUG_DROP("Decryption failed (not set)"
463 " (SA=%pM)\n", hdr->addr2);
464 ieee->ieee_stats.rx_discards_undecryptable++;
465 goto rx_dropped;
466 }
467 }
468#ifdef NOT_YET
469 if (type != WLAN_FC_TYPE_DATA) {
470 if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH &&
471 fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt &&
472 (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
473 printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
474 "from %pM\n", dev->name, hdr->addr2);
475 /* TODO: could inform hostapd about this so that it
476 * could send auth failure report */
477 goto rx_dropped;
478 }
479
480 if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
481 goto rx_dropped;
482 else
483 goto rx_exit;
484 }
485#endif
486 /* drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.29) */
487 if (sc == ieee->prev_seq_ctl)
488 goto rx_dropped;
489 else
490 ieee->prev_seq_ctl = sc;
491
492 /* Data frame - extract src/dst addresses */
493 if (skb->len < IEEE80211_3ADDR_LEN)
494 goto rx_dropped;
495
496 switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
497 case IEEE80211_FCTL_FROMDS:
498 memcpy(dst, hdr->addr1, ETH_ALEN);
499 memcpy(src, hdr->addr3, ETH_ALEN);
500 break;
501 case IEEE80211_FCTL_TODS:
502 memcpy(dst, hdr->addr3, ETH_ALEN);
503 memcpy(src, hdr->addr2, ETH_ALEN);
504 break;
505 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
506 if (skb->len < IEEE80211_4ADDR_LEN)
507 goto rx_dropped;
508 memcpy(dst, hdr->addr3, ETH_ALEN);
509 memcpy(src, hdr->addr4, ETH_ALEN);
510 break;
511 case 0:
512 memcpy(dst, hdr->addr1, ETH_ALEN);
513 memcpy(src, hdr->addr2, ETH_ALEN);
514 break;
515 }
516
517#ifdef NOT_YET
518 if (hostap_rx_frame_wds(ieee, hdr, fc, &wds))
519 goto rx_dropped;
520 if (wds) {
521 skb->dev = dev = wds;
522 stats = hostap_get_stats(dev);
523 }
524
525 if (ieee->iw_mode == IW_MODE_MASTER && !wds &&
526 (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
527 IEEE80211_FCTL_FROMDS && ieee->stadev
528 && !compare_ether_addr(hdr->addr2, ieee->assoc_ap_addr)) {
529 /* Frame from BSSID of the AP for which we are a client */
530 skb->dev = dev = ieee->stadev;
531 stats = hostap_get_stats(dev);
532 from_assoc_ap = 1;
533 }
534#endif
535
536#ifdef NOT_YET
537 if ((ieee->iw_mode == IW_MODE_MASTER ||
538 ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) {
539 switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
540 wds != NULL)) {
541 case AP_RX_CONTINUE_NOT_AUTHORIZED:
542 frame_authorized = 0;
543 break;
544 case AP_RX_CONTINUE:
545 frame_authorized = 1;
546 break;
547 case AP_RX_DROP:
548 goto rx_dropped;
549 case AP_RX_EXIT:
550 goto rx_exit;
551 }
552 }
553#endif
554
555 /* Nullfunc frames may have PS-bit set, so they must be passed to
556 * hostap_handle_sta_rx() before being dropped here. */
557
558 stype &= ~IEEE80211_STYPE_QOS_DATA;
559
560 if (stype != IEEE80211_STYPE_DATA &&
561 stype != IEEE80211_STYPE_DATA_CFACK &&
562 stype != IEEE80211_STYPE_DATA_CFPOLL &&
563 stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
564 if (stype != IEEE80211_STYPE_NULLFUNC)
565 IEEE80211_DEBUG_DROP("RX: dropped data frame "
566 "with no data (type=0x%02x, "
567 "subtype=0x%02x, len=%d)\n",
568 type, stype, skb->len);
569 goto rx_dropped;
570 }
571
572 /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
573
574 if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
575 (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0)
576 goto rx_dropped;
577
578 hdr = (struct ieee80211_hdr_4addr *)skb->data;
579
580 /* skb: hdr + (possibly fragmented) plaintext payload */
581 // PR: FIXME: hostap has additional conditions in the "if" below:
582 // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
583 if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) {
584 int flen;
585 struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr);
586 IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
587
588 if (!frag_skb) {
589 IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG,
590 "Rx cannot get skb from fragment "
591 "cache (morefrag=%d seq=%u frag=%u)\n",
592 (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
593 WLAN_GET_SEQ_SEQ(sc), frag);
594 goto rx_dropped;
595 }
596
597 flen = skb->len;
598 if (frag != 0)
599 flen -= hdrlen;
600
601 if (frag_skb->tail + flen > frag_skb->end) {
602 printk(KERN_WARNING "%s: host decrypted and "
603 "reassembled frame did not fit skb\n",
604 dev->name);
605 ieee80211_frag_cache_invalidate(ieee, hdr);
606 goto rx_dropped;
607 }
608
609 if (frag == 0) {
610 /* copy first fragment (including full headers) into
611 * beginning of the fragment cache skb */
612 skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), flen);
613 } else {
614 /* append frame payload to the end of the fragment
615 * cache skb */
616 skb_copy_from_linear_data_offset(skb, hdrlen,
617 skb_put(frag_skb, flen), flen);
618 }
619 dev_kfree_skb_any(skb);
620 skb = NULL;
621
622 if (fc & IEEE80211_FCTL_MOREFRAGS) {
623 /* more fragments expected - leave the skb in fragment
624 * cache for now; it will be delivered to upper layers
625 * after all fragments have been received */
626 goto rx_exit;
627 }
628
629 /* this was the last fragment and the frame will be
630 * delivered, so remove skb from fragment cache */
631 skb = frag_skb;
632 hdr = (struct ieee80211_hdr_4addr *)skb->data;
633 ieee80211_frag_cache_invalidate(ieee, hdr);
634 }
635
636 /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
637 * encrypted/authenticated */
638 if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
639 ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
640 goto rx_dropped;
641
642 hdr = (struct ieee80211_hdr_4addr *)skb->data;
643 if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) {
644 if ( /*ieee->ieee802_1x && */
645 ieee80211_is_eapol_frame(ieee, skb)) {
646 /* pass unencrypted EAPOL frames even if encryption is
647 * configured */
648 } else {
649 IEEE80211_DEBUG_DROP("encryption configured, but RX "
650 "frame not encrypted (SA=%pM)\n",
651 hdr->addr2);
652 goto rx_dropped;
653 }
654 }
655
656 if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
657 !ieee80211_is_eapol_frame(ieee, skb)) {
658 IEEE80211_DEBUG_DROP("dropped unencrypted RX data "
659 "frame from %pM (drop_unencrypted=1)\n",
660 hdr->addr2);
661 goto rx_dropped;
662 }
663
664 /* If the frame was decrypted in hardware, we may need to strip off
665 * any security data (IV, ICV, etc) that was left behind */
666 if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) &&
667 ieee->host_strip_iv_icv) {
668 int trimlen = 0;
669
670 /* Top two-bits of byte 3 are the key index */
671 if (skb->len >= hdrlen + 3)
672 keyidx = skb->data[hdrlen + 3] >> 6;
673
674 /* To strip off any security data which appears before the
675 * payload, we simply increase hdrlen (as the header gets
676 * chopped off immediately below). For the security data which
677 * appears after the payload, we use skb_trim. */
678
679 switch (ieee->sec.encode_alg[keyidx]) {
680 case SEC_ALG_WEP:
681 /* 4 byte IV */
682 hdrlen += 4;
683 /* 4 byte ICV */
684 trimlen = 4;
685 break;
686 case SEC_ALG_TKIP:
687 /* 4 byte IV, 4 byte ExtIV */
688 hdrlen += 8;
689 /* 8 byte MIC, 4 byte ICV */
690 trimlen = 12;
691 break;
692 case SEC_ALG_CCMP:
693 /* 8 byte CCMP header */
694 hdrlen += 8;
695 /* 8 byte MIC */
696 trimlen = 8;
697 break;
698 }
699
700 if (skb->len < trimlen)
701 goto rx_dropped;
702
703 __skb_trim(skb, skb->len - trimlen);
704
705 if (skb->len < hdrlen)
706 goto rx_dropped;
707 }
708
709 /* skb: hdr + (possible reassembled) full plaintext payload */
710
711 payload = skb->data + hdrlen;
712 ethertype = (payload[6] << 8) | payload[7];
713
714#ifdef NOT_YET
715 /* If IEEE 802.1X is used, check whether the port is authorized to send
716 * the received frame. */
717 if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) {
718 if (ethertype == ETH_P_PAE) {
719 printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n",
720 dev->name);
721 if (ieee->hostapd && ieee->apdev) {
722 /* Send IEEE 802.1X frames to the user
723 * space daemon for processing */
724 prism2_rx_80211(ieee->apdev, skb, rx_stats,
725 PRISM2_RX_MGMT);
726 ieee->apdevstats.rx_packets++;
727 ieee->apdevstats.rx_bytes += skb->len;
728 goto rx_exit;
729 }
730 } else if (!frame_authorized) {
731 printk(KERN_DEBUG "%s: dropped frame from "
732 "unauthorized port (IEEE 802.1X): "
733 "ethertype=0x%04x\n", dev->name, ethertype);
734 goto rx_dropped;
735 }
736 }
737#endif
738
739 /* convert hdr + possible LLC headers into Ethernet header */
740 if (skb->len - hdrlen >= 8 &&
741 ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 &&
742 ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
743 memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) {
744 /* remove RFC1042 or Bridge-Tunnel encapsulation and
745 * replace EtherType */
746 skb_pull(skb, hdrlen + SNAP_SIZE);
747 memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
748 memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
749 } else {
750 __be16 len;
751 /* Leave Ethernet header part of hdr and full payload */
752 skb_pull(skb, hdrlen);
753 len = htons(skb->len);
754 memcpy(skb_push(skb, 2), &len, 2);
755 memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
756 memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
757 }
758
759#ifdef NOT_YET
760 if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
761 IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) {
762 /* Non-standard frame: get addr4 from its bogus location after
763 * the payload */
764 skb_copy_to_linear_data_offset(skb, ETH_ALEN,
765 skb->data + skb->len - ETH_ALEN,
766 ETH_ALEN);
767 skb_trim(skb, skb->len - ETH_ALEN);
768 }
769#endif
770
771 stats->rx_packets++;
772 stats->rx_bytes += skb->len;
773
774#ifdef NOT_YET
775 if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) {
776 if (dst[0] & 0x01) {
777 /* copy multicast frame both to the higher layers and
778 * to the wireless media */
779 ieee->ap->bridged_multicast++;
780 skb2 = skb_clone(skb, GFP_ATOMIC);
781 if (skb2 == NULL)
782 printk(KERN_DEBUG "%s: skb_clone failed for "
783 "multicast frame\n", dev->name);
784 } else if (hostap_is_sta_assoc(ieee->ap, dst)) {
785 /* send frame directly to the associated STA using
786 * wireless media and not passing to higher layers */
787 ieee->ap->bridged_unicast++;
788 skb2 = skb;
789 skb = NULL;
790 }
791 }
792
793 if (skb2 != NULL) {
794 /* send to wireless media */
795 skb2->dev = dev;
796 skb2->protocol = htons(ETH_P_802_3);
797 skb_reset_mac_header(skb2);
798 skb_reset_network_header(skb2);
799 /* skb2->network_header += ETH_HLEN; */
800 dev_queue_xmit(skb2);
801 }
802#endif
803
804 if (skb) {
805 skb->protocol = eth_type_trans(skb, dev);
806 memset(skb->cb, 0, sizeof(skb->cb));
807 skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */
808 if (netif_rx(skb) == NET_RX_DROP) {
809 /* netif_rx always succeeds, but it might drop
810 * the packet. If it drops the packet, we log that
811 * in our stats. */
812 IEEE80211_DEBUG_DROP
813 ("RX: netif_rx dropped the packet\n");
814 stats->rx_dropped++;
815 }
816 }
817
818 rx_exit:
819#ifdef NOT_YET
820 if (sta)
821 hostap_handle_sta_release(sta);
822#endif
823 return 1;
824
825 rx_dropped:
826 stats->rx_dropped++;
827
828 /* Returning 0 indicates to caller that we have not handled the SKB--
829 * so it is still allocated and can be used again by underlying
830 * hardware as a DMA target */
831 return 0;
832}
833
834/* Filter out unrelated packets, call ieee80211_rx[_mgt]
835 * This function takes over the skb, it should not be used again after calling
836 * this function. */
837void ieee80211_rx_any(struct ieee80211_device *ieee,
838 struct sk_buff *skb, struct ieee80211_rx_stats *stats)
839{
840 struct ieee80211_hdr_4addr *hdr;
841 int is_packet_for_us;
842 u16 fc;
843
844 if (ieee->iw_mode == IW_MODE_MONITOR) {
845 if (!ieee80211_rx(ieee, skb, stats))
846 dev_kfree_skb_irq(skb);
847 return;
848 }
849
850 if (skb->len < sizeof(struct ieee80211_hdr))
851 goto drop_free;
852
853 hdr = (struct ieee80211_hdr_4addr *)skb->data;
854 fc = le16_to_cpu(hdr->frame_ctl);
855
856 if ((fc & IEEE80211_FCTL_VERS) != 0)
857 goto drop_free;
858
859 switch (fc & IEEE80211_FCTL_FTYPE) {
860 case IEEE80211_FTYPE_MGMT:
861 if (skb->len < sizeof(struct ieee80211_hdr_3addr))
862 goto drop_free;
863 ieee80211_rx_mgt(ieee, hdr, stats);
864 dev_kfree_skb_irq(skb);
865 return;
866 case IEEE80211_FTYPE_DATA:
867 break;
868 case IEEE80211_FTYPE_CTL:
869 return;
870 default:
871 return;
872 }
873
874 is_packet_for_us = 0;
875 switch (ieee->iw_mode) {
876 case IW_MODE_ADHOC:
877 /* our BSS and not from/to DS */
878 if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0)
879 if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
880 /* promisc: get all */
881 if (ieee->dev->flags & IFF_PROMISC)
882 is_packet_for_us = 1;
883 /* to us */
884 else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
885 is_packet_for_us = 1;
886 /* mcast */
887 else if (is_multicast_ether_addr(hdr->addr1))
888 is_packet_for_us = 1;
889 }
890 break;
891 case IW_MODE_INFRA:
892 /* our BSS (== from our AP) and from DS */
893 if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0)
894 if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
895 /* promisc: get all */
896 if (ieee->dev->flags & IFF_PROMISC)
897 is_packet_for_us = 1;
898 /* to us */
899 else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
900 is_packet_for_us = 1;
901 /* mcast */
902 else if (is_multicast_ether_addr(hdr->addr1)) {
903 /* not our own packet bcasted from AP */
904 if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN))
905 is_packet_for_us = 1;
906 }
907 }
908 break;
909 default:
910 /* ? */
911 break;
912 }
913
914 if (is_packet_for_us)
915 if (!ieee80211_rx(ieee, skb, stats))
916 dev_kfree_skb_irq(skb);
917 return;
918
919drop_free:
920 dev_kfree_skb_irq(skb);
921 ieee->stats.rx_dropped++;
922 return;
923}
924
925#define MGMT_FRAME_FIXED_PART_LENGTH 0x24
926
927static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
928
929/*
930* Make ther structure we read from the beacon packet has
931* the right values
932*/
933static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element
934 *info_element, int sub_type)
935{
936
937 if (info_element->qui_subtype != sub_type)
938 return -1;
939 if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN))
940 return -1;
941 if (info_element->qui_type != QOS_OUI_TYPE)
942 return -1;
943 if (info_element->version != QOS_VERSION_1)
944 return -1;
945
946 return 0;
947}
948
949/*
950 * Parse a QoS parameter element
951 */
952static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info
953 *element_param, struct ieee80211_info_element
954 *info_element)
955{
956 int ret = 0;
957 u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2;
958
959 if ((info_element == NULL) || (element_param == NULL))
960 return -1;
961
962 if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) {
963 memcpy(element_param->info_element.qui, info_element->data,
964 info_element->len);
965 element_param->info_element.elementID = info_element->id;
966 element_param->info_element.length = info_element->len;
967 } else
968 ret = -1;
969 if (ret == 0)
970 ret = ieee80211_verify_qos_info(&element_param->info_element,
971 QOS_OUI_PARAM_SUB_TYPE);
972 return ret;
973}
974
975/*
976 * Parse a QoS information element
977 */
978static int ieee80211_read_qos_info_element(struct
979 ieee80211_qos_information_element
980 *element_info, struct ieee80211_info_element
981 *info_element)
982{
983 int ret = 0;
984 u16 size = sizeof(struct ieee80211_qos_information_element) - 2;
985
986 if (element_info == NULL)
987 return -1;
988 if (info_element == NULL)
989 return -1;
990
991 if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) {
992 memcpy(element_info->qui, info_element->data,
993 info_element->len);
994 element_info->elementID = info_element->id;
995 element_info->length = info_element->len;
996 } else
997 ret = -1;
998
999 if (ret == 0)
1000 ret = ieee80211_verify_qos_info(element_info,
1001 QOS_OUI_INFO_SUB_TYPE);
1002 return ret;
1003}
1004
1005/*
1006 * Write QoS parameters from the ac parameters.
1007 */
1008static int ieee80211_qos_convert_ac_to_parameters(struct
1009 ieee80211_qos_parameter_info
1010 *param_elm, struct
1011 ieee80211_qos_parameters
1012 *qos_param)
1013{
1014 int rc = 0;
1015 int i;
1016 struct ieee80211_qos_ac_parameter *ac_params;
1017 u32 txop;
1018 u8 cw_min;
1019 u8 cw_max;
1020
1021 for (i = 0; i < QOS_QUEUE_NUM; i++) {
1022 ac_params = &(param_elm->ac_params_record[i]);
1023
1024 qos_param->aifs[i] = (ac_params->aci_aifsn) & 0x0F;
1025 qos_param->aifs[i] -= (qos_param->aifs[i] < 2) ? 0 : 2;
1026
1027 cw_min = ac_params->ecw_min_max & 0x0F;
1028 qos_param->cw_min[i] = cpu_to_le16((1 << cw_min) - 1);
1029
1030 cw_max = (ac_params->ecw_min_max & 0xF0) >> 4;
1031 qos_param->cw_max[i] = cpu_to_le16((1 << cw_max) - 1);
1032
1033 qos_param->flag[i] =
1034 (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00;
1035
1036 txop = le16_to_cpu(ac_params->tx_op_limit) * 32;
1037 qos_param->tx_op_limit[i] = cpu_to_le16(txop);
1038 }
1039 return rc;
1040}
1041
1042/*
1043 * we have a generic data element which it may contain QoS information or
1044 * parameters element. check the information element length to decide
1045 * which type to read
1046 */
1047static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element
1048 *info_element,
1049 struct ieee80211_network *network)
1050{
1051 int rc = 0;
1052 struct ieee80211_qos_parameters *qos_param = NULL;
1053 struct ieee80211_qos_information_element qos_info_element;
1054
1055 rc = ieee80211_read_qos_info_element(&qos_info_element, info_element);
1056
1057 if (rc == 0) {
1058 network->qos_data.param_count = qos_info_element.ac_info & 0x0F;
1059 network->flags |= NETWORK_HAS_QOS_INFORMATION;
1060 } else {
1061 struct ieee80211_qos_parameter_info param_element;
1062
1063 rc = ieee80211_read_qos_param_element(&param_element,
1064 info_element);
1065 if (rc == 0) {
1066 qos_param = &(network->qos_data.parameters);
1067 ieee80211_qos_convert_ac_to_parameters(&param_element,
1068 qos_param);
1069 network->flags |= NETWORK_HAS_QOS_PARAMETERS;
1070 network->qos_data.param_count =
1071 param_element.info_element.ac_info & 0x0F;
1072 }
1073 }
1074
1075 if (rc == 0) {
1076 IEEE80211_DEBUG_QOS("QoS is supported\n");
1077 network->qos_data.supported = 1;
1078 }
1079 return rc;
1080}
1081
1082#ifdef CONFIG_IEEE80211_DEBUG
1083#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x
1084
1085static const char *get_info_element_string(u16 id)
1086{
1087 switch (id) {
1088 MFIE_STRING(SSID);
1089 MFIE_STRING(RATES);
1090 MFIE_STRING(FH_SET);
1091 MFIE_STRING(DS_SET);
1092 MFIE_STRING(CF_SET);
1093 MFIE_STRING(TIM);
1094 MFIE_STRING(IBSS_SET);
1095 MFIE_STRING(COUNTRY);
1096 MFIE_STRING(HOP_PARAMS);
1097 MFIE_STRING(HOP_TABLE);
1098 MFIE_STRING(REQUEST);
1099 MFIE_STRING(CHALLENGE);
1100 MFIE_STRING(POWER_CONSTRAINT);
1101 MFIE_STRING(POWER_CAPABILITY);
1102 MFIE_STRING(TPC_REQUEST);
1103 MFIE_STRING(TPC_REPORT);
1104 MFIE_STRING(SUPP_CHANNELS);
1105 MFIE_STRING(CSA);
1106 MFIE_STRING(MEASURE_REQUEST);
1107 MFIE_STRING(MEASURE_REPORT);
1108 MFIE_STRING(QUIET);
1109 MFIE_STRING(IBSS_DFS);
1110 MFIE_STRING(ERP_INFO);
1111 MFIE_STRING(RSN);
1112 MFIE_STRING(RATES_EX);
1113 MFIE_STRING(GENERIC);
1114 MFIE_STRING(QOS_PARAMETER);
1115 default:
1116 return "UNKNOWN";
1117 }
1118}
1119#endif
1120
1121static int ieee80211_parse_info_param(struct ieee80211_info_element
1122 *info_element, u16 length,
1123 struct ieee80211_network *network)
1124{
1125 DECLARE_SSID_BUF(ssid);
1126 u8 i;
1127#ifdef CONFIG_IEEE80211_DEBUG
1128 char rates_str[64];
1129 char *p;
1130#endif
1131
1132 while (length >= sizeof(*info_element)) {
1133 if (sizeof(*info_element) + info_element->len > length) {
1134 IEEE80211_DEBUG_MGMT("Info elem: parse failed: "
1135 "info_element->len + 2 > left : "
1136 "info_element->len+2=%zd left=%d, id=%d.\n",
1137 info_element->len +
1138 sizeof(*info_element),
1139 length, info_element->id);
1140 /* We stop processing but don't return an error here
1141 * because some misbehaviour APs break this rule. ie.
1142 * Orinoco AP1000. */
1143 break;
1144 }
1145
1146 switch (info_element->id) {
1147 case MFIE_TYPE_SSID:
1148 network->ssid_len = min(info_element->len,
1149 (u8) IW_ESSID_MAX_SIZE);
1150 memcpy(network->ssid, info_element->data,
1151 network->ssid_len);
1152 if (network->ssid_len < IW_ESSID_MAX_SIZE)
1153 memset(network->ssid + network->ssid_len, 0,
1154 IW_ESSID_MAX_SIZE - network->ssid_len);
1155
1156 IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n",
1157 print_ssid(ssid, network->ssid,
1158 network->ssid_len),
1159 network->ssid_len);
1160 break;
1161
1162 case MFIE_TYPE_RATES:
1163#ifdef CONFIG_IEEE80211_DEBUG
1164 p = rates_str;
1165#endif
1166 network->rates_len = min(info_element->len,
1167 MAX_RATES_LENGTH);
1168 for (i = 0; i < network->rates_len; i++) {
1169 network->rates[i] = info_element->data[i];
1170#ifdef CONFIG_IEEE80211_DEBUG
1171 p += snprintf(p, sizeof(rates_str) -
1172 (p - rates_str), "%02X ",
1173 network->rates[i]);
1174#endif
1175 if (ieee80211_is_ofdm_rate
1176 (info_element->data[i])) {
1177 network->flags |= NETWORK_HAS_OFDM;
1178 if (info_element->data[i] &
1179 IEEE80211_BASIC_RATE_MASK)
1180 network->flags &=
1181 ~NETWORK_HAS_CCK;
1182 }
1183 }
1184
1185 IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES: '%s' (%d)\n",
1186 rates_str, network->rates_len);
1187 break;
1188
1189 case MFIE_TYPE_RATES_EX:
1190#ifdef CONFIG_IEEE80211_DEBUG
1191 p = rates_str;
1192#endif
1193 network->rates_ex_len = min(info_element->len,
1194 MAX_RATES_EX_LENGTH);
1195 for (i = 0; i < network->rates_ex_len; i++) {
1196 network->rates_ex[i] = info_element->data[i];
1197#ifdef CONFIG_IEEE80211_DEBUG
1198 p += snprintf(p, sizeof(rates_str) -
1199 (p - rates_str), "%02X ",
1200 network->rates[i]);
1201#endif
1202 if (ieee80211_is_ofdm_rate
1203 (info_element->data[i])) {
1204 network->flags |= NETWORK_HAS_OFDM;
1205 if (info_element->data[i] &
1206 IEEE80211_BASIC_RATE_MASK)
1207 network->flags &=
1208 ~NETWORK_HAS_CCK;
1209 }
1210 }
1211
1212 IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES_EX: '%s' (%d)\n",
1213 rates_str, network->rates_ex_len);
1214 break;
1215
1216 case MFIE_TYPE_DS_SET:
1217 IEEE80211_DEBUG_MGMT("MFIE_TYPE_DS_SET: %d\n",
1218 info_element->data[0]);
1219 network->channel = info_element->data[0];
1220 break;
1221
1222 case MFIE_TYPE_FH_SET:
1223 IEEE80211_DEBUG_MGMT("MFIE_TYPE_FH_SET: ignored\n");
1224 break;
1225
1226 case MFIE_TYPE_CF_SET:
1227 IEEE80211_DEBUG_MGMT("MFIE_TYPE_CF_SET: ignored\n");
1228 break;
1229
1230 case MFIE_TYPE_TIM:
1231 network->tim.tim_count = info_element->data[0];
1232 network->tim.tim_period = info_element->data[1];
1233 IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n");
1234 break;
1235
1236 case MFIE_TYPE_ERP_INFO:
1237 network->erp_value = info_element->data[0];
1238 network->flags |= NETWORK_HAS_ERP_VALUE;
1239 IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
1240 network->erp_value);
1241 break;
1242
1243 case MFIE_TYPE_IBSS_SET:
1244 network->atim_window = info_element->data[0];
1245 IEEE80211_DEBUG_MGMT("MFIE_TYPE_IBSS_SET: %d\n",
1246 network->atim_window);
1247 break;
1248
1249 case MFIE_TYPE_CHALLENGE:
1250 IEEE80211_DEBUG_MGMT("MFIE_TYPE_CHALLENGE: ignored\n");
1251 break;
1252
1253 case MFIE_TYPE_GENERIC:
1254 IEEE80211_DEBUG_MGMT("MFIE_TYPE_GENERIC: %d bytes\n",
1255 info_element->len);
1256 if (!ieee80211_parse_qos_info_param_IE(info_element,
1257 network))
1258 break;
1259
1260 if (info_element->len >= 4 &&
1261 info_element->data[0] == 0x00 &&
1262 info_element->data[1] == 0x50 &&
1263 info_element->data[2] == 0xf2 &&
1264 info_element->data[3] == 0x01) {
1265 network->wpa_ie_len = min(info_element->len + 2,
1266 MAX_WPA_IE_LEN);
1267 memcpy(network->wpa_ie, info_element,
1268 network->wpa_ie_len);
1269 }
1270 break;
1271
1272 case MFIE_TYPE_RSN:
1273 IEEE80211_DEBUG_MGMT("MFIE_TYPE_RSN: %d bytes\n",
1274 info_element->len);
1275 network->rsn_ie_len = min(info_element->len + 2,
1276 MAX_WPA_IE_LEN);
1277 memcpy(network->rsn_ie, info_element,
1278 network->rsn_ie_len);
1279 break;
1280
1281 case MFIE_TYPE_QOS_PARAMETER:
1282 printk(KERN_ERR
1283 "QoS Error need to parse QOS_PARAMETER IE\n");
1284 break;
1285 /* 802.11h */
1286 case MFIE_TYPE_POWER_CONSTRAINT:
1287 network->power_constraint = info_element->data[0];
1288 network->flags |= NETWORK_HAS_POWER_CONSTRAINT;
1289 break;
1290
1291 case MFIE_TYPE_CSA:
1292 network->power_constraint = info_element->data[0];
1293 network->flags |= NETWORK_HAS_CSA;
1294 break;
1295
1296 case MFIE_TYPE_QUIET:
1297 network->quiet.count = info_element->data[0];
1298 network->quiet.period = info_element->data[1];
1299 network->quiet.duration = info_element->data[2];
1300 network->quiet.offset = info_element->data[3];
1301 network->flags |= NETWORK_HAS_QUIET;
1302 break;
1303
1304 case MFIE_TYPE_IBSS_DFS:
1305 if (network->ibss_dfs)
1306 break;
1307 network->ibss_dfs = kmemdup(info_element->data,
1308 info_element->len,
1309 GFP_ATOMIC);
1310 if (!network->ibss_dfs)
1311 return 1;
1312 network->flags |= NETWORK_HAS_IBSS_DFS;
1313 break;
1314
1315 case MFIE_TYPE_TPC_REPORT:
1316 network->tpc_report.transmit_power =
1317 info_element->data[0];
1318 network->tpc_report.link_margin = info_element->data[1];
1319 network->flags |= NETWORK_HAS_TPC_REPORT;
1320 break;
1321
1322 default:
1323 IEEE80211_DEBUG_MGMT
1324 ("Unsupported info element: %s (%d)\n",
1325 get_info_element_string(info_element->id),
1326 info_element->id);
1327 break;
1328 }
1329
1330 length -= sizeof(*info_element) + info_element->len;
1331 info_element =
1332 (struct ieee80211_info_element *)&info_element->
1333 data[info_element->len];
1334 }
1335
1336 return 0;
1337}
1338
1339static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response
1340 *frame, struct ieee80211_rx_stats *stats)
1341{
1342 struct ieee80211_network network_resp = {
1343 .ibss_dfs = NULL,
1344 };
1345 struct ieee80211_network *network = &network_resp;
1346 struct net_device *dev = ieee->dev;
1347
1348 network->flags = 0;
1349 network->qos_data.active = 0;
1350 network->qos_data.supported = 0;
1351 network->qos_data.param_count = 0;
1352 network->qos_data.old_param_count = 0;
1353
1354 //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF);
1355 network->atim_window = le16_to_cpu(frame->aid);
1356 network->listen_interval = le16_to_cpu(frame->status);
1357 memcpy(network->bssid, frame->header.addr3, ETH_ALEN);
1358 network->capability = le16_to_cpu(frame->capability);
1359 network->last_scanned = jiffies;
1360 network->rates_len = network->rates_ex_len = 0;
1361 network->last_associate = 0;
1362 network->ssid_len = 0;
1363 network->erp_value =
1364 (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0;
1365
1366 if (stats->freq == IEEE80211_52GHZ_BAND) {
1367 /* for A band (No DS info) */
1368 network->channel = stats->received_channel;
1369 } else
1370 network->flags |= NETWORK_HAS_CCK;
1371
1372 network->wpa_ie_len = 0;
1373 network->rsn_ie_len = 0;
1374
1375 if (ieee80211_parse_info_param
1376 (frame->info_element, stats->len - sizeof(*frame), network))
1377 return 1;
1378
1379 network->mode = 0;
1380 if (stats->freq == IEEE80211_52GHZ_BAND)
1381 network->mode = IEEE_A;
1382 else {
1383 if (network->flags & NETWORK_HAS_OFDM)
1384 network->mode |= IEEE_G;
1385 if (network->flags & NETWORK_HAS_CCK)
1386 network->mode |= IEEE_B;
1387 }
1388
1389 memcpy(&network->stats, stats, sizeof(network->stats));
1390
1391 if (ieee->handle_assoc_response != NULL)
1392 ieee->handle_assoc_response(dev, frame, network);
1393
1394 return 0;
1395}
1396
1397/***************************************************/
1398
1399static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response
1400 *beacon,
1401 struct ieee80211_network *network,
1402 struct ieee80211_rx_stats *stats)
1403{
1404 DECLARE_SSID_BUF(ssid);
1405
1406 network->qos_data.active = 0;
1407 network->qos_data.supported = 0;
1408 network->qos_data.param_count = 0;
1409 network->qos_data.old_param_count = 0;
1410
1411 /* Pull out fixed field data */
1412 memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
1413 network->capability = le16_to_cpu(beacon->capability);
1414 network->last_scanned = jiffies;
1415 network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]);
1416 network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]);
1417 network->beacon_interval = le16_to_cpu(beacon->beacon_interval);
1418 /* Where to pull this? beacon->listen_interval; */
1419 network->listen_interval = 0x0A;
1420 network->rates_len = network->rates_ex_len = 0;
1421 network->last_associate = 0;
1422 network->ssid_len = 0;
1423 network->flags = 0;
1424 network->atim_window = 0;
1425 network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ?
1426 0x3 : 0x0;
1427
1428 if (stats->freq == IEEE80211_52GHZ_BAND) {
1429 /* for A band (No DS info) */
1430 network->channel = stats->received_channel;
1431 } else
1432 network->flags |= NETWORK_HAS_CCK;
1433
1434 network->wpa_ie_len = 0;
1435 network->rsn_ie_len = 0;
1436
1437 if (ieee80211_parse_info_param
1438 (beacon->info_element, stats->len - sizeof(*beacon), network))
1439 return 1;
1440
1441 network->mode = 0;
1442 if (stats->freq == IEEE80211_52GHZ_BAND)
1443 network->mode = IEEE_A;
1444 else {
1445 if (network->flags & NETWORK_HAS_OFDM)
1446 network->mode |= IEEE_G;
1447 if (network->flags & NETWORK_HAS_CCK)
1448 network->mode |= IEEE_B;
1449 }
1450
1451 if (network->mode == 0) {
1452 IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' "
1453 "network.\n",
1454 print_ssid(ssid, network->ssid,
1455 network->ssid_len),
1456 network->bssid);
1457 return 1;
1458 }
1459
1460 memcpy(&network->stats, stats, sizeof(network->stats));
1461
1462 return 0;
1463}
1464
1465static inline int is_same_network(struct ieee80211_network *src,
1466 struct ieee80211_network *dst)
1467{
1468 /* A network is only a duplicate if the channel, BSSID, and ESSID
1469 * all match. We treat all <hidden> with the same BSSID and channel
1470 * as one network */
1471 return ((src->ssid_len == dst->ssid_len) &&
1472 (src->channel == dst->channel) &&
1473 !compare_ether_addr(src->bssid, dst->bssid) &&
1474 !memcmp(src->ssid, dst->ssid, src->ssid_len));
1475}
1476
1477static void update_network(struct ieee80211_network *dst,
1478 struct ieee80211_network *src)
1479{
1480 int qos_active;
1481 u8 old_param;
1482
1483 ieee80211_network_reset(dst);
1484 dst->ibss_dfs = src->ibss_dfs;
1485
1486 /* We only update the statistics if they were created by receiving
1487 * the network information on the actual channel the network is on.
1488 *
1489 * This keeps beacons received on neighbor channels from bringing
1490 * down the signal level of an AP. */
1491 if (dst->channel == src->stats.received_channel)
1492 memcpy(&dst->stats, &src->stats,
1493 sizeof(struct ieee80211_rx_stats));
1494 else
1495 IEEE80211_DEBUG_SCAN("Network %pM info received "
1496 "off channel (%d vs. %d)\n", src->bssid,
1497 dst->channel, src->stats.received_channel);
1498
1499 dst->capability = src->capability;
1500 memcpy(dst->rates, src->rates, src->rates_len);
1501 dst->rates_len = src->rates_len;
1502 memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
1503 dst->rates_ex_len = src->rates_ex_len;
1504
1505 dst->mode = src->mode;
1506 dst->flags = src->flags;
1507 dst->time_stamp[0] = src->time_stamp[0];
1508 dst->time_stamp[1] = src->time_stamp[1];
1509
1510 dst->beacon_interval = src->beacon_interval;
1511 dst->listen_interval = src->listen_interval;
1512 dst->atim_window = src->atim_window;
1513 dst->erp_value = src->erp_value;
1514 dst->tim = src->tim;
1515
1516 memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
1517 dst->wpa_ie_len = src->wpa_ie_len;
1518 memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len);
1519 dst->rsn_ie_len = src->rsn_ie_len;
1520
1521 dst->last_scanned = jiffies;
1522 qos_active = src->qos_data.active;
1523 old_param = dst->qos_data.old_param_count;
1524 if (dst->flags & NETWORK_HAS_QOS_MASK)
1525 memcpy(&dst->qos_data, &src->qos_data,
1526 sizeof(struct ieee80211_qos_data));
1527 else {
1528 dst->qos_data.supported = src->qos_data.supported;
1529 dst->qos_data.param_count = src->qos_data.param_count;
1530 }
1531
1532 if (dst->qos_data.supported == 1) {
1533 if (dst->ssid_len)
1534 IEEE80211_DEBUG_QOS
1535 ("QoS the network %s is QoS supported\n",
1536 dst->ssid);
1537 else
1538 IEEE80211_DEBUG_QOS
1539 ("QoS the network is QoS supported\n");
1540 }
1541 dst->qos_data.active = qos_active;
1542 dst->qos_data.old_param_count = old_param;
1543
1544 /* dst->last_associate is not overwritten */
1545}
1546
1547static inline int is_beacon(__le16 fc)
1548{
1549 return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
1550}
1551
1552static void ieee80211_process_probe_response(struct ieee80211_device
1553 *ieee, struct
1554 ieee80211_probe_response
1555 *beacon, struct ieee80211_rx_stats
1556 *stats)
1557{
1558 struct net_device *dev = ieee->dev;
1559 struct ieee80211_network network = {
1560 .ibss_dfs = NULL,
1561 };
1562 struct ieee80211_network *target;
1563 struct ieee80211_network *oldest = NULL;
1564#ifdef CONFIG_IEEE80211_DEBUG
1565 struct ieee80211_info_element *info_element = beacon->info_element;
1566#endif
1567 unsigned long flags;
1568 DECLARE_SSID_BUF(ssid);
1569
1570 IEEE80211_DEBUG_SCAN("'%s' (%pM"
1571 "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
1572 print_ssid(ssid, info_element->data, info_element->len),
1573 beacon->header.addr3,
1574 (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
1575 (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
1576 (beacon->capability & cpu_to_le16(1 << 0xd)) ? '1' : '0',
1577 (beacon->capability & cpu_to_le16(1 << 0xc)) ? '1' : '0',
1578 (beacon->capability & cpu_to_le16(1 << 0xb)) ? '1' : '0',
1579 (beacon->capability & cpu_to_le16(1 << 0xa)) ? '1' : '0',
1580 (beacon->capability & cpu_to_le16(1 << 0x9)) ? '1' : '0',
1581 (beacon->capability & cpu_to_le16(1 << 0x8)) ? '1' : '0',
1582 (beacon->capability & cpu_to_le16(1 << 0x7)) ? '1' : '0',
1583 (beacon->capability & cpu_to_le16(1 << 0x6)) ? '1' : '0',
1584 (beacon->capability & cpu_to_le16(1 << 0x5)) ? '1' : '0',
1585 (beacon->capability & cpu_to_le16(1 << 0x4)) ? '1' : '0',
1586 (beacon->capability & cpu_to_le16(1 << 0x3)) ? '1' : '0',
1587 (beacon->capability & cpu_to_le16(1 << 0x2)) ? '1' : '0',
1588 (beacon->capability & cpu_to_le16(1 << 0x1)) ? '1' : '0',
1589 (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
1590
1591 if (ieee80211_network_init(ieee, beacon, &network, stats)) {
1592 IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
1593 print_ssid(ssid, info_element->data,
1594 info_element->len),
1595 beacon->header.addr3,
1596 is_beacon(beacon->header.frame_ctl) ?
1597 "BEACON" : "PROBE RESPONSE");
1598 return;
1599 }
1600
1601 /* The network parsed correctly -- so now we scan our known networks
1602 * to see if we can find it in our list.
1603 *
1604 * NOTE: This search is definitely not optimized. Once its doing
1605 * the "right thing" we'll optimize it for efficiency if
1606 * necessary */
1607
1608 /* Search for this entry in the list and update it if it is
1609 * already there. */
1610
1611 spin_lock_irqsave(&ieee->lock, flags);
1612
1613 list_for_each_entry(target, &ieee->network_list, list) {
1614 if (is_same_network(target, &network))
1615 break;
1616
1617 if ((oldest == NULL) ||
1618 (target->last_scanned < oldest->last_scanned))
1619 oldest = target;
1620 }
1621
1622 /* If we didn't find a match, then get a new network slot to initialize
1623 * with this beacon's information */
1624 if (&target->list == &ieee->network_list) {
1625 if (list_empty(&ieee->network_free_list)) {
1626 /* If there are no more slots, expire the oldest */
1627 list_del(&oldest->list);
1628 target = oldest;
1629 IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from "
1630 "network list.\n",
1631 print_ssid(ssid, target->ssid,
1632 target->ssid_len),
1633 target->bssid);
1634 ieee80211_network_reset(target);
1635 } else {
1636 /* Otherwise just pull from the free list */
1637 target = list_entry(ieee->network_free_list.next,
1638 struct ieee80211_network, list);
1639 list_del(ieee->network_free_list.next);
1640 }
1641
1642#ifdef CONFIG_IEEE80211_DEBUG
1643 IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
1644 print_ssid(ssid, network.ssid,
1645 network.ssid_len),
1646 network.bssid,
1647 is_beacon(beacon->header.frame_ctl) ?
1648 "BEACON" : "PROBE RESPONSE");
1649#endif
1650 memcpy(target, &network, sizeof(*target));
1651 network.ibss_dfs = NULL;
1652 list_add_tail(&target->list, &ieee->network_list);
1653 } else {
1654 IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
1655 print_ssid(ssid, target->ssid,
1656 target->ssid_len),
1657 target->bssid,
1658 is_beacon(beacon->header.frame_ctl) ?
1659 "BEACON" : "PROBE RESPONSE");
1660 update_network(target, &network);
1661 network.ibss_dfs = NULL;
1662 }
1663
1664 spin_unlock_irqrestore(&ieee->lock, flags);
1665
1666 if (is_beacon(beacon->header.frame_ctl)) {
1667 if (ieee->handle_beacon != NULL)
1668 ieee->handle_beacon(dev, beacon, target);
1669 } else {
1670 if (ieee->handle_probe_response != NULL)
1671 ieee->handle_probe_response(dev, beacon, target);
1672 }
1673}
1674
1675void ieee80211_rx_mgt(struct ieee80211_device *ieee,
1676 struct ieee80211_hdr_4addr *header,
1677 struct ieee80211_rx_stats *stats)
1678{
1679 switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) {
1680 case IEEE80211_STYPE_ASSOC_RESP:
1681 IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n",
1682 WLAN_FC_GET_STYPE(le16_to_cpu
1683 (header->frame_ctl)));
1684 ieee80211_handle_assoc_resp(ieee,
1685 (struct ieee80211_assoc_response *)
1686 header, stats);
1687 break;
1688
1689 case IEEE80211_STYPE_REASSOC_RESP:
1690 IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n",
1691 WLAN_FC_GET_STYPE(le16_to_cpu
1692 (header->frame_ctl)));
1693 break;
1694
1695 case IEEE80211_STYPE_PROBE_REQ:
1696 IEEE80211_DEBUG_MGMT("received auth (%d)\n",
1697 WLAN_FC_GET_STYPE(le16_to_cpu
1698 (header->frame_ctl)));
1699
1700 if (ieee->handle_probe_request != NULL)
1701 ieee->handle_probe_request(ieee->dev,
1702 (struct
1703 ieee80211_probe_request *)
1704 header, stats);
1705 break;
1706
1707 case IEEE80211_STYPE_PROBE_RESP:
1708 IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n",
1709 WLAN_FC_GET_STYPE(le16_to_cpu
1710 (header->frame_ctl)));
1711 IEEE80211_DEBUG_SCAN("Probe response\n");
1712 ieee80211_process_probe_response(ieee,
1713 (struct
1714 ieee80211_probe_response *)
1715 header, stats);
1716 break;
1717
1718 case IEEE80211_STYPE_BEACON:
1719 IEEE80211_DEBUG_MGMT("received BEACON (%d)\n",
1720 WLAN_FC_GET_STYPE(le16_to_cpu
1721 (header->frame_ctl)));
1722 IEEE80211_DEBUG_SCAN("Beacon\n");
1723 ieee80211_process_probe_response(ieee,
1724 (struct
1725 ieee80211_probe_response *)
1726 header, stats);
1727 break;
1728 case IEEE80211_STYPE_AUTH:
1729
1730 IEEE80211_DEBUG_MGMT("received auth (%d)\n",
1731 WLAN_FC_GET_STYPE(le16_to_cpu
1732 (header->frame_ctl)));
1733
1734 if (ieee->handle_auth != NULL)
1735 ieee->handle_auth(ieee->dev,
1736 (struct ieee80211_auth *)header);
1737 break;
1738
1739 case IEEE80211_STYPE_DISASSOC:
1740 if (ieee->handle_disassoc != NULL)
1741 ieee->handle_disassoc(ieee->dev,
1742 (struct ieee80211_disassoc *)
1743 header);
1744 break;
1745
1746 case IEEE80211_STYPE_ACTION:
1747 IEEE80211_DEBUG_MGMT("ACTION\n");
1748 if (ieee->handle_action)
1749 ieee->handle_action(ieee->dev,
1750 (struct ieee80211_action *)
1751 header, stats);
1752 break;
1753
1754 case IEEE80211_STYPE_REASSOC_REQ:
1755 IEEE80211_DEBUG_MGMT("received reassoc (%d)\n",
1756 WLAN_FC_GET_STYPE(le16_to_cpu
1757 (header->frame_ctl)));
1758
1759 IEEE80211_DEBUG_MGMT("%s: IEEE80211_REASSOC_REQ received\n",
1760 ieee->dev->name);
1761 if (ieee->handle_reassoc_request != NULL)
1762 ieee->handle_reassoc_request(ieee->dev,
1763 (struct ieee80211_reassoc_request *)
1764 header);
1765 break;
1766
1767 case IEEE80211_STYPE_ASSOC_REQ:
1768 IEEE80211_DEBUG_MGMT("received assoc (%d)\n",
1769 WLAN_FC_GET_STYPE(le16_to_cpu
1770 (header->frame_ctl)));
1771
1772 IEEE80211_DEBUG_MGMT("%s: IEEE80211_ASSOC_REQ received\n",
1773 ieee->dev->name);
1774 if (ieee->handle_assoc_request != NULL)
1775 ieee->handle_assoc_request(ieee->dev);
1776 break;
1777
1778 case IEEE80211_STYPE_DEAUTH:
1779 IEEE80211_DEBUG_MGMT("DEAUTH\n");
1780 if (ieee->handle_deauth != NULL)
1781 ieee->handle_deauth(ieee->dev,
1782 (struct ieee80211_deauth *)
1783 header);
1784 break;
1785 default:
1786 IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
1787 WLAN_FC_GET_STYPE(le16_to_cpu
1788 (header->frame_ctl)));
1789 IEEE80211_DEBUG_MGMT("%s: Unknown management packet: %d\n",
1790 ieee->dev->name,
1791 WLAN_FC_GET_STYPE(le16_to_cpu
1792 (header->frame_ctl)));
1793 break;
1794 }
1795}
1796
1797EXPORT_SYMBOL_GPL(ieee80211_rx_any);
1798EXPORT_SYMBOL(ieee80211_rx_mgt);
1799EXPORT_SYMBOL(ieee80211_rx);
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
deleted file mode 100644
index f78f57e8844..00000000000
--- a/net/ieee80211/ieee80211_tx.c
+++ /dev/null
@@ -1,546 +0,0 @@
1/******************************************************************************
2
3 Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of version 2 of the GNU General Public License as
7 published by the Free Software Foundation.
8
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 59
16 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 The full GNU General Public License is included in this distribution in the
19 file called LICENSE.
20
21 Contact Information:
22 James P. Ketrenos <ipw2100-admin@linux.intel.com>
23 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24
25******************************************************************************/
26#include <linux/compiler.h>
27#include <linux/errno.h>
28#include <linux/if_arp.h>
29#include <linux/in6.h>
30#include <linux/in.h>
31#include <linux/ip.h>
32#include <linux/kernel.h>
33#include <linux/module.h>
34#include <linux/netdevice.h>
35#include <linux/proc_fs.h>
36#include <linux/skbuff.h>
37#include <linux/slab.h>
38#include <linux/tcp.h>
39#include <linux/types.h>
40#include <linux/wireless.h>
41#include <linux/etherdevice.h>
42#include <asm/uaccess.h>
43
44#include <net/ieee80211.h>
45
46/*
47
48802.11 Data Frame
49
50 ,-------------------------------------------------------------------.
51Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
52 |------|------|---------|---------|---------|------|---------|------|
53Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs |
54 | | tion | (BSSID) | | | ence | data | |
55 `--------------------------------------------------| |------'
56Total: 28 non-data bytes `----.----'
57 |
58 .- 'Frame data' expands, if WEP enabled, to <----------'
59 |
60 V
61 ,-----------------------.
62Bytes | 4 | 0-2296 | 4 |
63 |-----|-----------|-----|
64Desc. | IV | Encrypted | ICV |
65 | | Packet | |
66 `-----| |-----'
67 `-----.-----'
68 |
69 .- 'Encrypted Packet' expands to
70 |
71 V
72 ,---------------------------------------------------.
73Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 |
74 |------|------|---------|----------|------|---------|
75Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP |
76 | DSAP | SSAP | | | | Packet |
77 | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | |
78 `----------------------------------------------------
79Total: 8 non-data bytes
80
81802.3 Ethernet Data Frame
82
83 ,-----------------------------------------.
84Bytes | 6 | 6 | 2 | Variable | 4 |
85 |-------|-------|------|-----------|------|
86Desc. | Dest. | Source| Type | IP Packet | fcs |
87 | MAC | MAC | | | |
88 `-----------------------------------------'
89Total: 18 non-data bytes
90
91In the event that fragmentation is required, the incoming payload is split into
92N parts of size ieee->fts. The first fragment contains the SNAP header and the
93remaining packets are just data.
94
95If encryption is enabled, each fragment payload size is reduced by enough space
96to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP)
97So if you have 1500 bytes of payload with ieee->fts set to 500 without
98encryption it will take 3 frames. With WEP it will take 4 frames as the
99payload of each frame is reduced to 492 bytes.
100
101* SKB visualization
102*
103* ,- skb->data
104* |
105* | ETHERNET HEADER ,-<-- PAYLOAD
106* | | 14 bytes from skb->data
107* | 2 bytes for Type --> ,T. | (sizeof ethhdr)
108* | | | |
109* |,-Dest.--. ,--Src.---. | | |
110* | 6 bytes| | 6 bytes | | | |
111* v | | | | | |
112* 0 | v 1 | v | v 2
113* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
114* ^ | ^ | ^ |
115* | | | | | |
116* | | | | `T' <---- 2 bytes for Type
117* | | | |
118* | | '---SNAP--' <-------- 6 bytes for SNAP
119* | |
120* `-IV--' <-------------------- 4 bytes for IV (WEP)
121*
122* SNAP HEADER
123*
124*/
125
126static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
127static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
128
129static int ieee80211_copy_snap(u8 * data, __be16 h_proto)
130{
131 struct ieee80211_snap_hdr *snap;
132 u8 *oui;
133
134 snap = (struct ieee80211_snap_hdr *)data;
135 snap->dsap = 0xaa;
136 snap->ssap = 0xaa;
137 snap->ctrl = 0x03;
138
139 if (h_proto == htons(ETH_P_AARP) || h_proto == htons(ETH_P_IPX))
140 oui = P802_1H_OUI;
141 else
142 oui = RFC1042_OUI;
143 snap->oui[0] = oui[0];
144 snap->oui[1] = oui[1];
145 snap->oui[2] = oui[2];
146
147 memcpy(data + SNAP_SIZE, &h_proto, sizeof(u16));
148
149 return SNAP_SIZE + sizeof(u16);
150}
151
152static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
153 struct sk_buff *frag, int hdr_len)
154{
155 struct lib80211_crypt_data *crypt =
156 ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
157 int res;
158
159 if (crypt == NULL)
160 return -1;
161
162 /* To encrypt, frame format is:
163 * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
164 atomic_inc(&crypt->refcnt);
165 res = 0;
166 if (crypt->ops && crypt->ops->encrypt_mpdu)
167 res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
168
169 atomic_dec(&crypt->refcnt);
170 if (res < 0) {
171 printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
172 ieee->dev->name, frag->len);
173 ieee->ieee_stats.tx_discards++;
174 return -1;
175 }
176
177 return 0;
178}
179
180void ieee80211_txb_free(struct ieee80211_txb *txb)
181{
182 int i;
183 if (unlikely(!txb))
184 return;
185 for (i = 0; i < txb->nr_frags; i++)
186 if (txb->fragments[i])
187 dev_kfree_skb_any(txb->fragments[i]);
188 kfree(txb);
189}
190
191static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
192 int headroom, gfp_t gfp_mask)
193{
194 struct ieee80211_txb *txb;
195 int i;
196 txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags),
197 gfp_mask);
198 if (!txb)
199 return NULL;
200
201 memset(txb, 0, sizeof(struct ieee80211_txb));
202 txb->nr_frags = nr_frags;
203 txb->frag_size = txb_size;
204
205 for (i = 0; i < nr_frags; i++) {
206 txb->fragments[i] = __dev_alloc_skb(txb_size + headroom,
207 gfp_mask);
208 if (unlikely(!txb->fragments[i])) {
209 i--;
210 break;
211 }
212 skb_reserve(txb->fragments[i], headroom);
213 }
214 if (unlikely(i != nr_frags)) {
215 while (i >= 0)
216 dev_kfree_skb_any(txb->fragments[i--]);
217 kfree(txb);
218 return NULL;
219 }
220 return txb;
221}
222
223static int ieee80211_classify(struct sk_buff *skb)
224{
225 struct ethhdr *eth;
226 struct iphdr *ip;
227
228 eth = (struct ethhdr *)skb->data;
229 if (eth->h_proto != htons(ETH_P_IP))
230 return 0;
231
232 ip = ip_hdr(skb);
233 switch (ip->tos & 0xfc) {
234 case 0x20:
235 return 2;
236 case 0x40:
237 return 1;
238 case 0x60:
239 return 3;
240 case 0x80:
241 return 4;
242 case 0xa0:
243 return 5;
244 case 0xc0:
245 return 6;
246 case 0xe0:
247 return 7;
248 default:
249 return 0;
250 }
251}
252
253/* Incoming skb is converted to a txb which consists of
254 * a block of 802.11 fragment packets (stored as skbs) */
255int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
256{
257 struct ieee80211_device *ieee = netdev_priv(dev);
258 struct ieee80211_txb *txb = NULL;
259 struct ieee80211_hdr_3addrqos *frag_hdr;
260 int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
261 rts_required;
262 unsigned long flags;
263 struct net_device_stats *stats = &ieee->stats;
264 int encrypt, host_encrypt, host_encrypt_msdu, host_build_iv;
265 __be16 ether_type;
266 int bytes, fc, hdr_len;
267 struct sk_buff *skb_frag;
268 struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */
269 .duration_id = 0,
270 .seq_ctl = 0,
271 .qos_ctl = 0
272 };
273 u8 dest[ETH_ALEN], src[ETH_ALEN];
274 struct lib80211_crypt_data *crypt;
275 int priority = skb->priority;
276 int snapped = 0;
277
278 if (ieee->is_queue_full && (*ieee->is_queue_full) (dev, priority))
279 return NETDEV_TX_BUSY;
280
281 spin_lock_irqsave(&ieee->lock, flags);
282
283 /* If there is no driver handler to take the TXB, dont' bother
284 * creating it... */
285 if (!ieee->hard_start_xmit) {
286 printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
287 goto success;
288 }
289
290 if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
291 printk(KERN_WARNING "%s: skb too small (%d).\n",
292 ieee->dev->name, skb->len);
293 goto success;
294 }
295
296 ether_type = ((struct ethhdr *)skb->data)->h_proto;
297
298 crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
299
300 encrypt = !(ether_type == htons(ETH_P_PAE) && ieee->ieee802_1x) &&
301 ieee->sec.encrypt;
302
303 host_encrypt = ieee->host_encrypt && encrypt && crypt;
304 host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt && crypt;
305 host_build_iv = ieee->host_build_iv && encrypt && crypt;
306
307 if (!encrypt && ieee->ieee802_1x &&
308 ieee->drop_unencrypted && ether_type != htons(ETH_P_PAE)) {
309 stats->tx_dropped++;
310 goto success;
311 }
312
313 /* Save source and destination addresses */
314 skb_copy_from_linear_data(skb, dest, ETH_ALEN);
315 skb_copy_from_linear_data_offset(skb, ETH_ALEN, src, ETH_ALEN);
316
317 if (host_encrypt || host_build_iv)
318 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
319 IEEE80211_FCTL_PROTECTED;
320 else
321 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
322
323 if (ieee->iw_mode == IW_MODE_INFRA) {
324 fc |= IEEE80211_FCTL_TODS;
325 /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
326 memcpy(header.addr1, ieee->bssid, ETH_ALEN);
327 memcpy(header.addr2, src, ETH_ALEN);
328 memcpy(header.addr3, dest, ETH_ALEN);
329 } else if (ieee->iw_mode == IW_MODE_ADHOC) {
330 /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
331 memcpy(header.addr1, dest, ETH_ALEN);
332 memcpy(header.addr2, src, ETH_ALEN);
333 memcpy(header.addr3, ieee->bssid, ETH_ALEN);
334 }
335 hdr_len = IEEE80211_3ADDR_LEN;
336
337 if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) {
338 fc |= IEEE80211_STYPE_QOS_DATA;
339 hdr_len += 2;
340
341 skb->priority = ieee80211_classify(skb);
342 header.qos_ctl |= cpu_to_le16(skb->priority & IEEE80211_QCTL_TID);
343 }
344 header.frame_ctl = cpu_to_le16(fc);
345
346 /* Advance the SKB to the start of the payload */
347 skb_pull(skb, sizeof(struct ethhdr));
348
349 /* Determine total amount of storage required for TXB packets */
350 bytes = skb->len + SNAP_SIZE + sizeof(u16);
351
352 /* Encrypt msdu first on the whole data packet. */
353 if ((host_encrypt || host_encrypt_msdu) &&
354 crypt && crypt->ops && crypt->ops->encrypt_msdu) {
355 int res = 0;
356 int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
357 crypt->ops->extra_msdu_postfix_len;
358 struct sk_buff *skb_new = dev_alloc_skb(len);
359
360 if (unlikely(!skb_new))
361 goto failed;
362
363 skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
364 memcpy(skb_put(skb_new, hdr_len), &header, hdr_len);
365 snapped = 1;
366 ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
367 ether_type);
368 skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len);
369 res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
370 if (res < 0) {
371 IEEE80211_ERROR("msdu encryption failed\n");
372 dev_kfree_skb_any(skb_new);
373 goto failed;
374 }
375 dev_kfree_skb_any(skb);
376 skb = skb_new;
377 bytes += crypt->ops->extra_msdu_prefix_len +
378 crypt->ops->extra_msdu_postfix_len;
379 skb_pull(skb, hdr_len);
380 }
381
382 if (host_encrypt || ieee->host_open_frag) {
383 /* Determine fragmentation size based on destination (multicast
384 * and broadcast are not fragmented) */
385 if (is_multicast_ether_addr(dest) ||
386 is_broadcast_ether_addr(dest))
387 frag_size = MAX_FRAG_THRESHOLD;
388 else
389 frag_size = ieee->fts;
390
391 /* Determine amount of payload per fragment. Regardless of if
392 * this stack is providing the full 802.11 header, one will
393 * eventually be affixed to this fragment -- so we must account
394 * for it when determining the amount of payload space. */
395 bytes_per_frag = frag_size - hdr_len;
396 if (ieee->config &
397 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
398 bytes_per_frag -= IEEE80211_FCS_LEN;
399
400 /* Each fragment may need to have room for encryptiong
401 * pre/postfix */
402 if (host_encrypt)
403 bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
404 crypt->ops->extra_mpdu_postfix_len;
405
406 /* Number of fragments is the total
407 * bytes_per_frag / payload_per_fragment */
408 nr_frags = bytes / bytes_per_frag;
409 bytes_last_frag = bytes % bytes_per_frag;
410 if (bytes_last_frag)
411 nr_frags++;
412 else
413 bytes_last_frag = bytes_per_frag;
414 } else {
415 nr_frags = 1;
416 bytes_per_frag = bytes_last_frag = bytes;
417 frag_size = bytes + hdr_len;
418 }
419
420 rts_required = (frag_size > ieee->rts
421 && ieee->config & CFG_IEEE80211_RTS);
422 if (rts_required)
423 nr_frags++;
424
425 /* When we allocate the TXB we allocate enough space for the reserve
426 * and full fragment bytes (bytes_per_frag doesn't include prefix,
427 * postfix, header, FCS, etc.) */
428 txb = ieee80211_alloc_txb(nr_frags, frag_size,
429 ieee->tx_headroom, GFP_ATOMIC);
430 if (unlikely(!txb)) {
431 printk(KERN_WARNING "%s: Could not allocate TXB\n",
432 ieee->dev->name);
433 goto failed;
434 }
435 txb->encrypted = encrypt;
436 if (host_encrypt)
437 txb->payload_size = frag_size * (nr_frags - 1) +
438 bytes_last_frag;
439 else
440 txb->payload_size = bytes;
441
442 if (rts_required) {
443 skb_frag = txb->fragments[0];
444 frag_hdr =
445 (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
446
447 /*
448 * Set header frame_ctl to the RTS.
449 */
450 header.frame_ctl =
451 cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
452 memcpy(frag_hdr, &header, hdr_len);
453
454 /*
455 * Restore header frame_ctl to the original data setting.
456 */
457 header.frame_ctl = cpu_to_le16(fc);
458
459 if (ieee->config &
460 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
461 skb_put(skb_frag, 4);
462
463 txb->rts_included = 1;
464 i = 1;
465 } else
466 i = 0;
467
468 for (; i < nr_frags; i++) {
469 skb_frag = txb->fragments[i];
470
471 if (host_encrypt || host_build_iv)
472 skb_reserve(skb_frag,
473 crypt->ops->extra_mpdu_prefix_len);
474
475 frag_hdr =
476 (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
477 memcpy(frag_hdr, &header, hdr_len);
478
479 /* If this is not the last fragment, then add the MOREFRAGS
480 * bit to the frame control */
481 if (i != nr_frags - 1) {
482 frag_hdr->frame_ctl =
483 cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS);
484 bytes = bytes_per_frag;
485 } else {
486 /* The last fragment takes the remaining length */
487 bytes = bytes_last_frag;
488 }
489
490 if (i == 0 && !snapped) {
491 ieee80211_copy_snap(skb_put
492 (skb_frag, SNAP_SIZE + sizeof(u16)),
493 ether_type);
494 bytes -= SNAP_SIZE + sizeof(u16);
495 }
496
497 skb_copy_from_linear_data(skb, skb_put(skb_frag, bytes), bytes);
498
499 /* Advance the SKB... */
500 skb_pull(skb, bytes);
501
502 /* Encryption routine will move the header forward in order
503 * to insert the IV between the header and the payload */
504 if (host_encrypt)
505 ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
506 else if (host_build_iv) {
507 atomic_inc(&crypt->refcnt);
508 if (crypt->ops->build_iv)
509 crypt->ops->build_iv(skb_frag, hdr_len,
510 ieee->sec.keys[ieee->sec.active_key],
511 ieee->sec.key_sizes[ieee->sec.active_key],
512 crypt->priv);
513 atomic_dec(&crypt->refcnt);
514 }
515
516 if (ieee->config &
517 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
518 skb_put(skb_frag, 4);
519 }
520
521 success:
522 spin_unlock_irqrestore(&ieee->lock, flags);
523
524 dev_kfree_skb_any(skb);
525
526 if (txb) {
527 int ret = (*ieee->hard_start_xmit) (txb, dev, priority);
528 if (ret == 0) {
529 stats->tx_packets++;
530 stats->tx_bytes += txb->payload_size;
531 return 0;
532 }
533
534 ieee80211_txb_free(txb);
535 }
536
537 return 0;
538
539 failed:
540 spin_unlock_irqrestore(&ieee->lock, flags);
541 netif_stop_queue(dev);
542 stats->tx_errors++;
543 return 1;
544}
545
546EXPORT_SYMBOL(ieee80211_txb_free);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
deleted file mode 100644
index 31ea3abfc32..00000000000
--- a/net/ieee80211/ieee80211_wx.c
+++ /dev/null
@@ -1,760 +0,0 @@
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/kmod.h>
34#include <linux/module.h>
35#include <linux/jiffies.h>
36
37#include <net/lib80211.h>
38#include <net/ieee80211.h>
39#include <linux/wireless.h>
40
41static const char *ieee80211_modes[] = {
42 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
43};
44
45#define MAX_CUSTOM_LEN 64
46static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
47 char *start, char *stop,
48 struct ieee80211_network *network,
49 struct iw_request_info *info)
50{
51 char custom[MAX_CUSTOM_LEN];
52 char *p;
53 struct iw_event iwe;
54 int i, j;
55 char *current_val; /* For rates */
56 u8 rate;
57
58 /* First entry *MUST* be the AP MAC address */
59 iwe.cmd = SIOCGIWAP;
60 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
61 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
62 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
63
64 /* Remaining entries will be displayed in the order we provide them */
65
66 /* Add the ESSID */
67 iwe.cmd = SIOCGIWESSID;
68 iwe.u.data.flags = 1;
69 iwe.u.data.length = min(network->ssid_len, (u8) 32);
70 start = iwe_stream_add_point(info, start, stop,
71 &iwe, network->ssid);
72
73 /* Add the protocol name */
74 iwe.cmd = SIOCGIWNAME;
75 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
76 ieee80211_modes[network->mode]);
77 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
78
79 /* Add mode */
80 iwe.cmd = SIOCGIWMODE;
81 if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
82 if (network->capability & WLAN_CAPABILITY_ESS)
83 iwe.u.mode = IW_MODE_MASTER;
84 else
85 iwe.u.mode = IW_MODE_ADHOC;
86
87 start = iwe_stream_add_event(info, start, stop,
88 &iwe, IW_EV_UINT_LEN);
89 }
90
91 /* Add channel and frequency */
92 /* Note : userspace automatically computes channel using iwrange */
93 iwe.cmd = SIOCGIWFREQ;
94 iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
95 iwe.u.freq.e = 6;
96 iwe.u.freq.i = 0;
97 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
98
99 /* Add encryption capability */
100 iwe.cmd = SIOCGIWENCODE;
101 if (network->capability & WLAN_CAPABILITY_PRIVACY)
102 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
103 else
104 iwe.u.data.flags = IW_ENCODE_DISABLED;
105 iwe.u.data.length = 0;
106 start = iwe_stream_add_point(info, start, stop,
107 &iwe, network->ssid);
108
109 /* Add basic and extended rates */
110 /* Rate : stuffing multiple values in a single event require a bit
111 * more of magic - Jean II */
112 current_val = start + iwe_stream_lcp_len(info);
113 iwe.cmd = SIOCGIWRATE;
114 /* Those two flags are ignored... */
115 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
116
117 for (i = 0, j = 0; i < network->rates_len;) {
118 if (j < network->rates_ex_len &&
119 ((network->rates_ex[j] & 0x7F) <
120 (network->rates[i] & 0x7F)))
121 rate = network->rates_ex[j++] & 0x7F;
122 else
123 rate = network->rates[i++] & 0x7F;
124 /* Bit rate given in 500 kb/s units (+ 0x80) */
125 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
126 /* Add new value to event */
127 current_val = iwe_stream_add_value(info, start, current_val,
128 stop, &iwe, IW_EV_PARAM_LEN);
129 }
130 for (; j < network->rates_ex_len; j++) {
131 rate = network->rates_ex[j] & 0x7F;
132 /* Bit rate given in 500 kb/s units (+ 0x80) */
133 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
134 /* Add new value to event */
135 current_val = iwe_stream_add_value(info, start, current_val,
136 stop, &iwe, IW_EV_PARAM_LEN);
137 }
138 /* Check if we added any rate */
139 if ((current_val - start) > iwe_stream_lcp_len(info))
140 start = current_val;
141
142 /* Add quality statistics */
143 iwe.cmd = IWEVQUAL;
144 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
145 IW_QUAL_NOISE_UPDATED;
146
147 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
148 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
149 IW_QUAL_LEVEL_INVALID;
150 iwe.u.qual.qual = 0;
151 } else {
152 if (ieee->perfect_rssi == ieee->worst_rssi)
153 iwe.u.qual.qual = 100;
154 else
155 iwe.u.qual.qual =
156 (100 *
157 (ieee->perfect_rssi - ieee->worst_rssi) *
158 (ieee->perfect_rssi - ieee->worst_rssi) -
159 (ieee->perfect_rssi - network->stats.rssi) *
160 (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
161 62 * (ieee->perfect_rssi -
162 network->stats.rssi))) /
163 ((ieee->perfect_rssi -
164 ieee->worst_rssi) * (ieee->perfect_rssi -
165 ieee->worst_rssi));
166 if (iwe.u.qual.qual > 100)
167 iwe.u.qual.qual = 100;
168 else if (iwe.u.qual.qual < 1)
169 iwe.u.qual.qual = 0;
170 }
171
172 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
173 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
174 iwe.u.qual.noise = 0;
175 } else {
176 iwe.u.qual.noise = network->stats.noise;
177 }
178
179 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
180 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
181 iwe.u.qual.level = 0;
182 } else {
183 iwe.u.qual.level = network->stats.signal;
184 }
185
186 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
187
188 iwe.cmd = IWEVCUSTOM;
189 p = custom;
190
191 iwe.u.data.length = p - custom;
192 if (iwe.u.data.length)
193 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
194
195 memset(&iwe, 0, sizeof(iwe));
196 if (network->wpa_ie_len) {
197 char buf[MAX_WPA_IE_LEN];
198 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
199 iwe.cmd = IWEVGENIE;
200 iwe.u.data.length = network->wpa_ie_len;
201 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
202 }
203
204 memset(&iwe, 0, sizeof(iwe));
205 if (network->rsn_ie_len) {
206 char buf[MAX_WPA_IE_LEN];
207 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
208 iwe.cmd = IWEVGENIE;
209 iwe.u.data.length = network->rsn_ie_len;
210 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
211 }
212
213 /* Add EXTRA: Age to display seconds since last beacon/probe response
214 * for given network. */
215 iwe.cmd = IWEVCUSTOM;
216 p = custom;
217 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
218 " Last beacon: %dms ago",
219 jiffies_to_msecs(jiffies - network->last_scanned));
220 iwe.u.data.length = p - custom;
221 if (iwe.u.data.length)
222 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
223
224 /* Add spectrum management information */
225 iwe.cmd = -1;
226 p = custom;
227 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
228
229 if (ieee80211_get_channel_flags(ieee, network->channel) &
230 IEEE80211_CH_INVALID) {
231 iwe.cmd = IWEVCUSTOM;
232 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
233 }
234
235 if (ieee80211_get_channel_flags(ieee, network->channel) &
236 IEEE80211_CH_RADAR_DETECT) {
237 iwe.cmd = IWEVCUSTOM;
238 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
239 }
240
241 if (iwe.cmd == IWEVCUSTOM) {
242 iwe.u.data.length = p - custom;
243 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
244 }
245
246 return start;
247}
248
249#define SCAN_ITEM_SIZE 128
250
251int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
252 struct iw_request_info *info,
253 union iwreq_data *wrqu, char *extra)
254{
255 struct ieee80211_network *network;
256 unsigned long flags;
257 int err = 0;
258
259 char *ev = extra;
260 char *stop = ev + wrqu->data.length;
261 int i = 0;
262 DECLARE_SSID_BUF(ssid);
263
264 IEEE80211_DEBUG_WX("Getting scan\n");
265
266 spin_lock_irqsave(&ieee->lock, flags);
267
268 list_for_each_entry(network, &ieee->network_list, list) {
269 i++;
270 if (stop - ev < SCAN_ITEM_SIZE) {
271 err = -E2BIG;
272 break;
273 }
274
275 if (ieee->scan_age == 0 ||
276 time_after(network->last_scanned + ieee->scan_age, jiffies))
277 ev = ieee80211_translate_scan(ieee, ev, stop, network,
278 info);
279 else
280 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
281 "%pM)' due to age (%dms).\n",
282 print_ssid(ssid, network->ssid,
283 network->ssid_len),
284 network->bssid,
285 jiffies_to_msecs(jiffies -
286 network->
287 last_scanned));
288 }
289
290 spin_unlock_irqrestore(&ieee->lock, flags);
291
292 wrqu->data.length = ev - extra;
293 wrqu->data.flags = 0;
294
295 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
296
297 return err;
298}
299
300int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
301 struct iw_request_info *info,
302 union iwreq_data *wrqu, char *keybuf)
303{
304 struct iw_point *erq = &(wrqu->encoding);
305 struct net_device *dev = ieee->dev;
306 struct ieee80211_security sec = {
307 .flags = 0
308 };
309 int i, key, key_provided, len;
310 struct lib80211_crypt_data **crypt;
311 int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
312 DECLARE_SSID_BUF(ssid);
313
314 IEEE80211_DEBUG_WX("SET_ENCODE\n");
315
316 key = erq->flags & IW_ENCODE_INDEX;
317 if (key) {
318 if (key > WEP_KEYS)
319 return -EINVAL;
320 key--;
321 key_provided = 1;
322 } else {
323 key_provided = 0;
324 key = ieee->crypt_info.tx_keyidx;
325 }
326
327 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
328 "provided" : "default");
329
330 crypt = &ieee->crypt_info.crypt[key];
331
332 if (erq->flags & IW_ENCODE_DISABLED) {
333 if (key_provided && *crypt) {
334 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
335 key);
336 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
337 } else
338 IEEE80211_DEBUG_WX("Disabling encryption.\n");
339
340 /* Check all the keys to see if any are still configured,
341 * and if no key index was provided, de-init them all */
342 for (i = 0; i < WEP_KEYS; i++) {
343 if (ieee->crypt_info.crypt[i] != NULL) {
344 if (key_provided)
345 break;
346 lib80211_crypt_delayed_deinit(&ieee->crypt_info,
347 &ieee->crypt_info.crypt[i]);
348 }
349 }
350
351 if (i == WEP_KEYS) {
352 sec.enabled = 0;
353 sec.encrypt = 0;
354 sec.level = SEC_LEVEL_0;
355 sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
356 }
357
358 goto done;
359 }
360
361 sec.enabled = 1;
362 sec.encrypt = 1;
363 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
364
365 if (*crypt != NULL && (*crypt)->ops != NULL &&
366 strcmp((*crypt)->ops->name, "WEP") != 0) {
367 /* changing to use WEP; deinit previously used algorithm
368 * on this key */
369 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
370 }
371
372 if (*crypt == NULL && host_crypto) {
373 struct lib80211_crypt_data *new_crypt;
374
375 /* take WEP into use */
376 new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
377 GFP_KERNEL);
378 if (new_crypt == NULL)
379 return -ENOMEM;
380 new_crypt->ops = lib80211_get_crypto_ops("WEP");
381 if (!new_crypt->ops) {
382 request_module("lib80211_crypt_wep");
383 new_crypt->ops = lib80211_get_crypto_ops("WEP");
384 }
385
386 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
387 new_crypt->priv = new_crypt->ops->init(key);
388
389 if (!new_crypt->ops || !new_crypt->priv) {
390 kfree(new_crypt);
391 new_crypt = NULL;
392
393 printk(KERN_WARNING "%s: could not initialize WEP: "
394 "load module lib80211_crypt_wep\n", dev->name);
395 return -EOPNOTSUPP;
396 }
397 *crypt = new_crypt;
398 }
399
400 /* If a new key was provided, set it up */
401 if (erq->length > 0) {
402#ifdef CONFIG_IEEE80211_DEBUG
403 DECLARE_SSID_BUF(ssid);
404#endif
405
406 len = erq->length <= 5 ? 5 : 13;
407 memcpy(sec.keys[key], keybuf, erq->length);
408 if (len > erq->length)
409 memset(sec.keys[key] + erq->length, 0,
410 len - erq->length);
411 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
412 key, print_ssid(ssid, sec.keys[key], len),
413 erq->length, len);
414 sec.key_sizes[key] = len;
415 if (*crypt)
416 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
417 (*crypt)->priv);
418 sec.flags |= (1 << key);
419 /* This ensures a key will be activated if no key is
420 * explicitly set */
421 if (key == sec.active_key)
422 sec.flags |= SEC_ACTIVE_KEY;
423
424 } else {
425 if (host_crypto) {
426 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
427 NULL, (*crypt)->priv);
428 if (len == 0) {
429 /* Set a default key of all 0 */
430 IEEE80211_DEBUG_WX("Setting key %d to all "
431 "zero.\n", key);
432 memset(sec.keys[key], 0, 13);
433 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
434 (*crypt)->priv);
435 sec.key_sizes[key] = 13;
436 sec.flags |= (1 << key);
437 }
438 }
439 /* No key data - just set the default TX key index */
440 if (key_provided) {
441 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
442 "key.\n", key);
443 ieee->crypt_info.tx_keyidx = key;
444 sec.active_key = key;
445 sec.flags |= SEC_ACTIVE_KEY;
446 }
447 }
448 if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
449 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
450 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
451 WLAN_AUTH_SHARED_KEY;
452 sec.flags |= SEC_AUTH_MODE;
453 IEEE80211_DEBUG_WX("Auth: %s\n",
454 sec.auth_mode == WLAN_AUTH_OPEN ?
455 "OPEN" : "SHARED KEY");
456 }
457
458 /* For now we just support WEP, so only set that security level...
459 * TODO: When WPA is added this is one place that needs to change */
460 sec.flags |= SEC_LEVEL;
461 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
462 sec.encode_alg[key] = SEC_ALG_WEP;
463
464 done:
465 if (ieee->set_security)
466 ieee->set_security(dev, &sec);
467
468 /* Do not reset port if card is in Managed mode since resetting will
469 * generate new IEEE 802.11 authentication which may end up in looping
470 * with IEEE 802.1X. If your hardware requires a reset after WEP
471 * configuration (for example... Prism2), implement the reset_port in
472 * the callbacks structures used to initialize the 802.11 stack. */
473 if (ieee->reset_on_keychange &&
474 ieee->iw_mode != IW_MODE_INFRA &&
475 ieee->reset_port && ieee->reset_port(dev)) {
476 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
477 return -EINVAL;
478 }
479 return 0;
480}
481
482int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
483 struct iw_request_info *info,
484 union iwreq_data *wrqu, char *keybuf)
485{
486 struct iw_point *erq = &(wrqu->encoding);
487 int len, key;
488 struct lib80211_crypt_data *crypt;
489 struct ieee80211_security *sec = &ieee->sec;
490
491 IEEE80211_DEBUG_WX("GET_ENCODE\n");
492
493 key = erq->flags & IW_ENCODE_INDEX;
494 if (key) {
495 if (key > WEP_KEYS)
496 return -EINVAL;
497 key--;
498 } else
499 key = ieee->crypt_info.tx_keyidx;
500
501 crypt = ieee->crypt_info.crypt[key];
502 erq->flags = key + 1;
503
504 if (!sec->enabled) {
505 erq->length = 0;
506 erq->flags |= IW_ENCODE_DISABLED;
507 return 0;
508 }
509
510 len = sec->key_sizes[key];
511 memcpy(keybuf, sec->keys[key], len);
512
513 erq->length = len;
514 erq->flags |= IW_ENCODE_ENABLED;
515
516 if (ieee->open_wep)
517 erq->flags |= IW_ENCODE_OPEN;
518 else
519 erq->flags |= IW_ENCODE_RESTRICTED;
520
521 return 0;
522}
523
524int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
525 struct iw_request_info *info,
526 union iwreq_data *wrqu, char *extra)
527{
528 struct net_device *dev = ieee->dev;
529 struct iw_point *encoding = &wrqu->encoding;
530 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
531 int i, idx, ret = 0;
532 int group_key = 0;
533 const char *alg, *module;
534 struct lib80211_crypto_ops *ops;
535 struct lib80211_crypt_data **crypt;
536
537 struct ieee80211_security sec = {
538 .flags = 0,
539 };
540
541 idx = encoding->flags & IW_ENCODE_INDEX;
542 if (idx) {
543 if (idx < 1 || idx > WEP_KEYS)
544 return -EINVAL;
545 idx--;
546 } else
547 idx = ieee->crypt_info.tx_keyidx;
548
549 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
550 crypt = &ieee->crypt_info.crypt[idx];
551 group_key = 1;
552 } else {
553 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
554 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
555 return -EINVAL;
556 if (ieee->iw_mode == IW_MODE_INFRA)
557 crypt = &ieee->crypt_info.crypt[idx];
558 else
559 return -EINVAL;
560 }
561
562 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
563 if ((encoding->flags & IW_ENCODE_DISABLED) ||
564 ext->alg == IW_ENCODE_ALG_NONE) {
565 if (*crypt)
566 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
567
568 for (i = 0; i < WEP_KEYS; i++)
569 if (ieee->crypt_info.crypt[i] != NULL)
570 break;
571
572 if (i == WEP_KEYS) {
573 sec.enabled = 0;
574 sec.encrypt = 0;
575 sec.level = SEC_LEVEL_0;
576 sec.flags |= SEC_LEVEL;
577 }
578 goto done;
579 }
580
581 sec.enabled = 1;
582 sec.encrypt = 1;
583
584 if (group_key ? !ieee->host_mc_decrypt :
585 !(ieee->host_encrypt || ieee->host_decrypt ||
586 ieee->host_encrypt_msdu))
587 goto skip_host_crypt;
588
589 switch (ext->alg) {
590 case IW_ENCODE_ALG_WEP:
591 alg = "WEP";
592 module = "lib80211_crypt_wep";
593 break;
594 case IW_ENCODE_ALG_TKIP:
595 alg = "TKIP";
596 module = "lib80211_crypt_tkip";
597 break;
598 case IW_ENCODE_ALG_CCMP:
599 alg = "CCMP";
600 module = "lib80211_crypt_ccmp";
601 break;
602 default:
603 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
604 dev->name, ext->alg);
605 ret = -EINVAL;
606 goto done;
607 }
608
609 ops = lib80211_get_crypto_ops(alg);
610 if (ops == NULL) {
611 request_module(module);
612 ops = lib80211_get_crypto_ops(alg);
613 }
614 if (ops == NULL) {
615 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
616 dev->name, ext->alg);
617 ret = -EINVAL;
618 goto done;
619 }
620
621 if (*crypt == NULL || (*crypt)->ops != ops) {
622 struct lib80211_crypt_data *new_crypt;
623
624 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
625
626 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
627 if (new_crypt == NULL) {
628 ret = -ENOMEM;
629 goto done;
630 }
631 new_crypt->ops = ops;
632 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
633 new_crypt->priv = new_crypt->ops->init(idx);
634 if (new_crypt->priv == NULL) {
635 kfree(new_crypt);
636 ret = -EINVAL;
637 goto done;
638 }
639 *crypt = new_crypt;
640 }
641
642 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
643 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
644 (*crypt)->priv) < 0) {
645 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
646 ret = -EINVAL;
647 goto done;
648 }
649
650 skip_host_crypt:
651 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
652 ieee->crypt_info.tx_keyidx = idx;
653 sec.active_key = idx;
654 sec.flags |= SEC_ACTIVE_KEY;
655 }
656
657 if (ext->alg != IW_ENCODE_ALG_NONE) {
658 memcpy(sec.keys[idx], ext->key, ext->key_len);
659 sec.key_sizes[idx] = ext->key_len;
660 sec.flags |= (1 << idx);
661 if (ext->alg == IW_ENCODE_ALG_WEP) {
662 sec.encode_alg[idx] = SEC_ALG_WEP;
663 sec.flags |= SEC_LEVEL;
664 sec.level = SEC_LEVEL_1;
665 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
666 sec.encode_alg[idx] = SEC_ALG_TKIP;
667 sec.flags |= SEC_LEVEL;
668 sec.level = SEC_LEVEL_2;
669 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
670 sec.encode_alg[idx] = SEC_ALG_CCMP;
671 sec.flags |= SEC_LEVEL;
672 sec.level = SEC_LEVEL_3;
673 }
674 /* Don't set sec level for group keys. */
675 if (group_key)
676 sec.flags &= ~SEC_LEVEL;
677 }
678 done:
679 if (ieee->set_security)
680 ieee->set_security(ieee->dev, &sec);
681
682 /*
683 * Do not reset port if card is in Managed mode since resetting will
684 * generate new IEEE 802.11 authentication which may end up in looping
685 * with IEEE 802.1X. If your hardware requires a reset after WEP
686 * configuration (for example... Prism2), implement the reset_port in
687 * the callbacks structures used to initialize the 802.11 stack.
688 */
689 if (ieee->reset_on_keychange &&
690 ieee->iw_mode != IW_MODE_INFRA &&
691 ieee->reset_port && ieee->reset_port(dev)) {
692 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
693 return -EINVAL;
694 }
695
696 return ret;
697}
698
699int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
700 struct iw_request_info *info,
701 union iwreq_data *wrqu, char *extra)
702{
703 struct iw_point *encoding = &wrqu->encoding;
704 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
705 struct ieee80211_security *sec = &ieee->sec;
706 int idx, max_key_len;
707
708 max_key_len = encoding->length - sizeof(*ext);
709 if (max_key_len < 0)
710 return -EINVAL;
711
712 idx = encoding->flags & IW_ENCODE_INDEX;
713 if (idx) {
714 if (idx < 1 || idx > WEP_KEYS)
715 return -EINVAL;
716 idx--;
717 } else
718 idx = ieee->crypt_info.tx_keyidx;
719
720 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
721 ext->alg != IW_ENCODE_ALG_WEP)
722 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
723 return -EINVAL;
724
725 encoding->flags = idx + 1;
726 memset(ext, 0, sizeof(*ext));
727
728 if (!sec->enabled) {
729 ext->alg = IW_ENCODE_ALG_NONE;
730 ext->key_len = 0;
731 encoding->flags |= IW_ENCODE_DISABLED;
732 } else {
733 if (sec->encode_alg[idx] == SEC_ALG_WEP)
734 ext->alg = IW_ENCODE_ALG_WEP;
735 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
736 ext->alg = IW_ENCODE_ALG_TKIP;
737 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
738 ext->alg = IW_ENCODE_ALG_CCMP;
739 else
740 return -EINVAL;
741
742 ext->key_len = sec->key_sizes[idx];
743 memcpy(ext->key, sec->keys[idx], ext->key_len);
744 encoding->flags |= IW_ENCODE_ENABLED;
745 if (ext->key_len &&
746 (ext->alg == IW_ENCODE_ALG_TKIP ||
747 ext->alg == IW_ENCODE_ALG_CCMP))
748 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
749
750 }
751
752 return 0;
753}
754
755EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
756EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
757
758EXPORT_SYMBOL(ieee80211_wx_get_scan);
759EXPORT_SYMBOL(ieee80211_wx_set_encode);
760EXPORT_SYMBOL(ieee80211_wx_get_encode);