blob: f88c8116a23c34185c3d1e99dd803686f23be76a [file] [log] [blame]
Jeff Garzikb4538722005-05-12 22:48:20 -04001/******************************************************************************
2
3 Copyright(c) 2004 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 <jkmaline@cc.hut.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
10
11 This program is free software; you can redistribute it and/or modify it
12 under the terms of version 2 of the GNU General Public License as
13 published by the Free Software Foundation.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 more details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59
22 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 The full GNU General Public License is included in this distribution in the
25 file called LICENSE.
26
27 Contact Information:
28 James P. Ketrenos <ipw2100-admin@linux.intel.com>
29 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31******************************************************************************/
Jeff Garzikbbeec902005-09-07 00:27:54 -040032
Jeff Garzikb4538722005-05-12 22:48:20 -040033#include <linux/kmod.h>
34#include <linux/module.h>
35
36#include <net/ieee80211.h>
Jeff Garzikbbeec902005-09-07 00:27:54 -040037#include <linux/wireless.h>
38
Jeff Garzikb4538722005-05-12 22:48:20 -040039static const char *ieee80211_modes[] = {
40 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
41};
42
43#define MAX_CUSTOM_LEN 64
44static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
Jeff Garzik0edd5b42005-09-07 00:48:31 -040045 char *start, char *stop,
Jeff Garzikb4538722005-05-12 22:48:20 -040046 struct ieee80211_network *network)
47{
48 char custom[MAX_CUSTOM_LEN];
49 char *p;
50 struct iw_event iwe;
51 int i, j;
52 u8 max_rate, rate;
53
54 /* First entry *MUST* be the AP MAC address */
55 iwe.cmd = SIOCGIWAP;
56 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
57 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
58 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
59
60 /* Remaining entries will be displayed in the order we provide them */
61
62 /* Add the ESSID */
63 iwe.cmd = SIOCGIWESSID;
64 iwe.u.data.flags = 1;
65 if (network->flags & NETWORK_EMPTY_ESSID) {
66 iwe.u.data.length = sizeof("<hidden>");
67 start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
68 } else {
Jeff Garzik0edd5b42005-09-07 00:48:31 -040069 iwe.u.data.length = min(network->ssid_len, (u8) 32);
Jeff Garzikb4538722005-05-12 22:48:20 -040070 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
71 }
72
73 /* Add the protocol name */
74 iwe.cmd = SIOCGIWNAME;
Jeff Garzik0edd5b42005-09-07 00:48:31 -040075 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
76 ieee80211_modes[network->mode]);
Jeff Garzikb4538722005-05-12 22:48:20 -040077 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
78
Jeff Garzik0edd5b42005-09-07 00:48:31 -040079 /* Add mode */
80 iwe.cmd = SIOCGIWMODE;
81 if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
Jeff Garzik1b5cca32005-08-15 00:32:15 -040082 if (network->capability & WLAN_CAPABILITY_ESS)
Jeff Garzikb4538722005-05-12 22:48:20 -040083 iwe.u.mode = IW_MODE_MASTER;
84 else
85 iwe.u.mode = IW_MODE_ADHOC;
86
Jeff Garzik0edd5b42005-09-07 00:48:31 -040087 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -040088 }
89
Jeff Garzik0edd5b42005-09-07 00:48:31 -040090 /* Add frequency/channel */
Jeff Garzikb4538722005-05-12 22:48:20 -040091 iwe.cmd = SIOCGIWFREQ;
92/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
93 iwe.u.freq.e = 3; */
94 iwe.u.freq.m = network->channel;
95 iwe.u.freq.e = 0;
96 iwe.u.freq.i = 0;
97 start = iwe_stream_add_event(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(start, stop, &iwe, network->ssid);
107
108 /* Add basic and extended rates */
109 max_rate = 0;
110 p = custom;
111 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400112 for (i = 0, j = 0; i < network->rates_len;) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400113 if (j < network->rates_ex_len &&
114 ((network->rates_ex[j] & 0x7F) <
115 (network->rates[i] & 0x7F)))
116 rate = network->rates_ex[j++] & 0x7F;
117 else
118 rate = network->rates[i++] & 0x7F;
119 if (rate > max_rate)
120 max_rate = rate;
121 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
122 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
123 }
124 for (; j < network->rates_ex_len; j++) {
125 rate = network->rates_ex[j] & 0x7F;
126 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
127 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
128 if (rate > max_rate)
129 max_rate = rate;
130 }
131
132 iwe.cmd = SIOCGIWRATE;
133 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
134 iwe.u.bitrate.value = max_rate * 500000;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400135 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400136
137 iwe.cmd = IWEVCUSTOM;
138 iwe.u.data.length = p - custom;
139 if (iwe.u.data.length)
140 start = iwe_stream_add_point(start, stop, &iwe, custom);
141
142 /* Add quality statistics */
Jeff Garzikb4538722005-05-12 22:48:20 -0400143 iwe.cmd = IWEVQUAL;
James Ketrenosb1b508e2005-09-13 17:27:19 -0500144 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 iwe.u.qual.level = 0;
152 } else {
153 iwe.u.qual.level = network->stats.rssi;
154 iwe.u.qual.qual =
155 (100 *
156 (ieee->perfect_rssi - ieee->worst_rssi) *
157 (ieee->perfect_rssi - ieee->worst_rssi) -
158 (ieee->perfect_rssi - network->stats.rssi) *
159 (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
160 62 * (ieee->perfect_rssi - network->stats.rssi))) /
161 ((ieee->perfect_rssi - ieee->worst_rssi) *
162 (ieee->perfect_rssi - ieee->worst_rssi));
163 if (iwe.u.qual.qual > 100)
164 iwe.u.qual.qual = 100;
165 else if (iwe.u.qual.qual < 1)
166 iwe.u.qual.qual = 0;
167 }
168
169 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400170 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
James Ketrenosb1b508e2005-09-13 17:27:19 -0500171 iwe.u.qual.noise = 0;
172 } else {
173 iwe.u.qual.noise = network->stats.noise;
174 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400175
176 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
177
178 iwe.cmd = IWEVCUSTOM;
179 p = custom;
180
181 iwe.u.data.length = p - custom;
182 if (iwe.u.data.length)
183 start = iwe_stream_add_point(start, stop, &iwe, custom);
184
James Ketrenos20d64712005-09-21 11:53:43 -0500185 if (network->wpa_ie_len) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400186 char buf[MAX_WPA_IE_LEN * 2 + 30];
187
188 u8 *p = buf;
189 p += sprintf(p, "wpa_ie=");
190 for (i = 0; i < network->wpa_ie_len; i++) {
191 p += sprintf(p, "%02x", network->wpa_ie[i]);
192 }
193
194 memset(&iwe, 0, sizeof(iwe));
195 iwe.cmd = IWEVCUSTOM;
196 iwe.u.data.length = strlen(buf);
197 start = iwe_stream_add_point(start, stop, &iwe, buf);
198 }
199
James Ketrenos20d64712005-09-21 11:53:43 -0500200 if (network->rsn_ie_len) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400201 char buf[MAX_WPA_IE_LEN * 2 + 30];
202
203 u8 *p = buf;
204 p += sprintf(p, "rsn_ie=");
205 for (i = 0; i < network->rsn_ie_len; i++) {
206 p += sprintf(p, "%02x", network->rsn_ie[i]);
207 }
208
209 memset(&iwe, 0, sizeof(iwe));
210 iwe.cmd = IWEVCUSTOM;
211 iwe.u.data.length = strlen(buf);
212 start = iwe_stream_add_point(start, stop, &iwe, buf);
213 }
214
215 /* Add EXTRA: Age to display seconds since last beacon/probe response
216 * for given network. */
217 iwe.cmd = IWEVCUSTOM;
218 p = custom;
219 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400220 " Last beacon: %lums ago",
221 (jiffies - network->last_scanned) / (HZ / 100));
Jeff Garzikb4538722005-05-12 22:48:20 -0400222 iwe.u.data.length = p - custom;
223 if (iwe.u.data.length)
224 start = iwe_stream_add_point(start, stop, &iwe, custom);
225
Jeff Garzikb4538722005-05-12 22:48:20 -0400226 return start;
227}
228
229int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
230 struct iw_request_info *info,
231 union iwreq_data *wrqu, char *extra)
232{
233 struct ieee80211_network *network;
234 unsigned long flags;
235
236 char *ev = extra;
237 char *stop = ev + IW_SCAN_MAX_DATA;
238 int i = 0;
239
240 IEEE80211_DEBUG_WX("Getting scan\n");
241
242 spin_lock_irqsave(&ieee->lock, flags);
243
244 list_for_each_entry(network, &ieee->network_list, list) {
245 i++;
246 if (ieee->scan_age == 0 ||
247 time_after(network->last_scanned + ieee->scan_age, jiffies))
248 ev = ipw2100_translate_scan(ieee, ev, stop, network);
249 else
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400250 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
251 MAC_FMT ")' due to age (%lums).\n",
252 escape_essid(network->ssid,
253 network->ssid_len),
254 MAC_ARG(network->bssid),
255 (jiffies -
256 network->last_scanned) / (HZ /
257 100));
Jeff Garzikb4538722005-05-12 22:48:20 -0400258 }
259
260 spin_unlock_irqrestore(&ieee->lock, flags);
261
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400262 wrqu->data.length = ev - extra;
Jeff Garzikb4538722005-05-12 22:48:20 -0400263 wrqu->data.flags = 0;
264
265 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
266
267 return 0;
268}
269
270int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
271 struct iw_request_info *info,
272 union iwreq_data *wrqu, char *keybuf)
273{
274 struct iw_point *erq = &(wrqu->encoding);
275 struct net_device *dev = ieee->dev;
276 struct ieee80211_security sec = {
277 .flags = 0
278 };
279 int i, key, key_provided, len;
280 struct ieee80211_crypt_data **crypt;
James Ketrenosf1bf6632005-09-21 11:53:54 -0500281 int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
Jeff Garzikb4538722005-05-12 22:48:20 -0400282
283 IEEE80211_DEBUG_WX("SET_ENCODE\n");
284
285 key = erq->flags & IW_ENCODE_INDEX;
286 if (key) {
287 if (key > WEP_KEYS)
288 return -EINVAL;
289 key--;
290 key_provided = 1;
291 } else {
292 key_provided = 0;
293 key = ieee->tx_keyidx;
294 }
295
296 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
297 "provided" : "default");
298
299 crypt = &ieee->crypt[key];
300
301 if (erq->flags & IW_ENCODE_DISABLED) {
302 if (key_provided && *crypt) {
303 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
304 key);
305 ieee80211_crypt_delayed_deinit(ieee, crypt);
306 } else
307 IEEE80211_DEBUG_WX("Disabling encryption.\n");
308
309 /* Check all the keys to see if any are still configured,
310 * and if no key index was provided, de-init them all */
311 for (i = 0; i < WEP_KEYS; i++) {
312 if (ieee->crypt[i] != NULL) {
313 if (key_provided)
314 break;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400315 ieee80211_crypt_delayed_deinit(ieee,
316 &ieee->crypt[i]);
Jeff Garzikb4538722005-05-12 22:48:20 -0400317 }
318 }
319
320 if (i == WEP_KEYS) {
321 sec.enabled = 0;
James Ketrenosf1bf6632005-09-21 11:53:54 -0500322 sec.encrypt = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400323 sec.level = SEC_LEVEL_0;
324 sec.flags |= SEC_ENABLED | SEC_LEVEL;
325 }
326
327 goto done;
328 }
329
Jeff Garzikb4538722005-05-12 22:48:20 -0400330 sec.enabled = 1;
James Ketrenosf1bf6632005-09-21 11:53:54 -0500331 sec.encrypt = 1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400332 sec.flags |= SEC_ENABLED;
333
334 if (*crypt != NULL && (*crypt)->ops != NULL &&
335 strcmp((*crypt)->ops->name, "WEP") != 0) {
336 /* changing to use WEP; deinit previously used algorithm
337 * on this key */
338 ieee80211_crypt_delayed_deinit(ieee, crypt);
339 }
340
James Ketrenosf1bf6632005-09-21 11:53:54 -0500341 if (*crypt == NULL && host_crypto) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400342 struct ieee80211_crypt_data *new_crypt;
343
344 /* take WEP into use */
345 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
346 GFP_KERNEL);
347 if (new_crypt == NULL)
348 return -ENOMEM;
349 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
350 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
351 if (!new_crypt->ops) {
352 request_module("ieee80211_crypt_wep");
353 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
354 }
355
356 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
James Ketrenos20d64712005-09-21 11:53:43 -0500357 new_crypt->priv = new_crypt->ops->init(ieee, key);
Jeff Garzikb4538722005-05-12 22:48:20 -0400358
359 if (!new_crypt->ops || !new_crypt->priv) {
360 kfree(new_crypt);
361 new_crypt = NULL;
362
363 printk(KERN_WARNING "%s: could not initialize WEP: "
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400364 "load module ieee80211_crypt_wep\n", dev->name);
Jeff Garzikb4538722005-05-12 22:48:20 -0400365 return -EOPNOTSUPP;
366 }
367 *crypt = new_crypt;
368 }
369
370 /* If a new key was provided, set it up */
371 if (erq->length > 0) {
372 len = erq->length <= 5 ? 5 : 13;
373 memcpy(sec.keys[key], keybuf, erq->length);
374 if (len > erq->length)
375 memset(sec.keys[key] + erq->length, 0,
376 len - erq->length);
377 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
378 key, escape_essid(sec.keys[key], len),
379 erq->length, len);
380 sec.key_sizes[key] = len;
James Ketrenosf1bf6632005-09-21 11:53:54 -0500381 if (*crypt)
382 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
383 (*crypt)->priv);
Jeff Garzikb4538722005-05-12 22:48:20 -0400384 sec.flags |= (1 << key);
385 /* This ensures a key will be activated if no key is
386 * explicitely set */
387 if (key == sec.active_key)
388 sec.flags |= SEC_ACTIVE_KEY;
Jeff Garzikb4538722005-05-12 22:48:20 -0400389
James Ketrenosf1bf6632005-09-21 11:53:54 -0500390 } else {
391 if (host_crypto) {
392 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
393 NULL, (*crypt)->priv);
394 if (len == 0) {
395 /* Set a default key of all 0 */
396 IEEE80211_DEBUG_WX("Setting key %d to all "
397 "zero.\n", key);
398 memset(sec.keys[key], 0, 13);
399 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
400 (*crypt)->priv);
401 sec.key_sizes[key] = 13;
402 sec.flags |= (1 << key);
403 }
404 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400405 /* No key data - just set the default TX key index */
406 if (key_provided) {
James Ketrenosf1bf6632005-09-21 11:53:54 -0500407 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
408 "key.\n", key);
Jeff Garzikb4538722005-05-12 22:48:20 -0400409 ieee->tx_keyidx = key;
410 sec.active_key = key;
411 sec.flags |= SEC_ACTIVE_KEY;
412 }
413 }
414
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400415 done:
Jeff Garzikb4538722005-05-12 22:48:20 -0400416 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
417 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
418 sec.flags |= SEC_AUTH_MODE;
419 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
420 "OPEN" : "SHARED KEY");
421
422 /* For now we just support WEP, so only set that security level...
423 * TODO: When WPA is added this is one place that needs to change */
424 sec.flags |= SEC_LEVEL;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400425 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
Jeff Garzikb4538722005-05-12 22:48:20 -0400426
427 if (ieee->set_security)
428 ieee->set_security(dev, &sec);
429
430 /* Do not reset port if card is in Managed mode since resetting will
431 * generate new IEEE 802.11 authentication which may end up in looping
432 * with IEEE 802.1X. If your hardware requires a reset after WEP
433 * configuration (for example... Prism2), implement the reset_port in
434 * the callbacks structures used to initialize the 802.11 stack. */
435 if (ieee->reset_on_keychange &&
436 ieee->iw_mode != IW_MODE_INFRA &&
437 ieee->reset_port && ieee->reset_port(dev)) {
438 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
439 return -EINVAL;
440 }
441 return 0;
442}
443
444int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
445 struct iw_request_info *info,
446 union iwreq_data *wrqu, char *keybuf)
447{
448 struct iw_point *erq = &(wrqu->encoding);
449 int len, key;
450 struct ieee80211_crypt_data *crypt;
James Ketrenosf1bf6632005-09-21 11:53:54 -0500451 struct ieee80211_security *sec = &ieee->sec;
Jeff Garzikb4538722005-05-12 22:48:20 -0400452
453 IEEE80211_DEBUG_WX("GET_ENCODE\n");
454
455 key = erq->flags & IW_ENCODE_INDEX;
456 if (key) {
457 if (key > WEP_KEYS)
458 return -EINVAL;
459 key--;
460 } else
461 key = ieee->tx_keyidx;
462
463 crypt = ieee->crypt[key];
464 erq->flags = key + 1;
465
James Ketrenosf1bf6632005-09-21 11:53:54 -0500466 if (!sec->enabled) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400467 erq->length = 0;
468 erq->flags |= IW_ENCODE_DISABLED;
469 return 0;
470 }
471
James Ketrenosf1bf6632005-09-21 11:53:54 -0500472 if (sec->level != SEC_LEVEL_1) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400473 /* only WEP is supported with wireless extensions, so just
474 * report that encryption is used */
475 erq->length = 0;
476 erq->flags |= IW_ENCODE_ENABLED;
477 return 0;
478 }
479
James Ketrenosf1bf6632005-09-21 11:53:54 -0500480 len = sec->key_sizes[key];
481 memcpy(keybuf, sec->keys[key], len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400482
James Ketrenosf1bf6632005-09-21 11:53:54 -0500483 erq->length = (len >= 0 ? len : 0);
Jeff Garzikb4538722005-05-12 22:48:20 -0400484 erq->flags |= IW_ENCODE_ENABLED;
485
486 if (ieee->open_wep)
487 erq->flags |= IW_ENCODE_OPEN;
488 else
489 erq->flags |= IW_ENCODE_RESTRICTED;
490
491 return 0;
492}
493
494EXPORT_SYMBOL(ieee80211_wx_get_scan);
495EXPORT_SYMBOL(ieee80211_wx_set_encode);
496EXPORT_SYMBOL(ieee80211_wx_get_encode);