Merge branches 'amd-iommu/fixes' and 'dma-debug/fixes' into iommu/fixes
[linux-2.6-block.git] / drivers / staging / rtl8192e / ieee80211 / ieee80211_wx.c
CommitLineData
ecdfa446
GKH
1/******************************************************************************
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******************************************************************************/
32#include <linux/wireless.h>
33#include <linux/version.h>
34#include <linux/kmod.h>
35#include <linux/module.h>
36
37#include "ieee80211.h"
38#if 0
39static const char *ieee80211_modes[] = {
40 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
41};
42#endif
43struct modes_unit {
44 char *mode_string;
45 int mode_size;
46};
47struct modes_unit ieee80211_modes[] = {
48 {"a",1},
49 {"b",1},
50 {"g",1},
51 {"?",1},
52 {"N-24G",5},
53 {"N-5G",4},
54};
55
56#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
57static inline char *
58iwe_stream_add_event_rsl(char * stream, /* Stream of events */
59 char * ends, /* End of stream */
60 struct iw_event *iwe, /* Payload */
61 int event_len) /* Real size of payload */
62{
63 /* Check if it's possible */
64 if((stream + event_len) < ends) {
65 iwe->len = event_len;
66 ndelay(1); //new
67 memcpy(stream, (char *) iwe, event_len);
68 stream += event_len;
69 }
70 return stream;
71}
72#else
73#define iwe_stream_add_event_rsl iwe_stream_add_event
74#endif
75
76#define MAX_CUSTOM_LEN 64
77static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
78 char *start, char *stop,
79 struct ieee80211_network *network,
80 struct iw_request_info *info)
81{
82 char custom[MAX_CUSTOM_LEN];
83 char proto_name[IFNAMSIZ];
84 char *pname = proto_name;
85 char *p;
86 struct iw_event iwe;
87 int i, j;
88 u16 max_rate, rate;
89 static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
90
91 /* First entry *MUST* be the AP MAC address */
92 iwe.cmd = SIOCGIWAP;
93 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
94 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
95#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
96 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN);
97#else
98 start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_ADDR_LEN);
99#endif
100 /* Remaining entries will be displayed in the order we provide them */
101
102 /* Add the ESSID */
103 iwe.cmd = SIOCGIWESSID;
104 iwe.u.data.flags = 1;
105// if (network->flags & NETWORK_EMPTY_ESSID) {
106 if (network->ssid_len == 0) {
107 iwe.u.data.length = sizeof("<hidden>");
108#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
109 start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
110#else
111 start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
112#endif
113 } else {
114 iwe.u.data.length = min(network->ssid_len, (u8)32);
115#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
116 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
117#else
118 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
119#endif
120 }
121 /* Add the protocol name */
122 iwe.cmd = SIOCGIWNAME;
123 for(i=0; i<(sizeof(ieee80211_modes)/sizeof(ieee80211_modes[0])); i++) {
124 if(network->mode&(1<<i)) {
125 sprintf(pname,ieee80211_modes[i].mode_string,ieee80211_modes[i].mode_size);
126 pname +=ieee80211_modes[i].mode_size;
127 }
128 }
129 *pname = '\0';
130 snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
131#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
132 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN);
133#else
134 start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_CHAR_LEN);
135#endif
136 /* Add mode */
137 iwe.cmd = SIOCGIWMODE;
138 if (network->capability &
139 (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) {
140 if (network->capability & WLAN_CAPABILITY_BSS)
141 iwe.u.mode = IW_MODE_MASTER;
142 else
143 iwe.u.mode = IW_MODE_ADHOC;
144#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
145 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN);
146#else
147 start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_UINT_LEN);
148#endif
149 }
150
151 /* Add frequency/channel */
152 iwe.cmd = SIOCGIWFREQ;
153/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
154 iwe.u.freq.e = 3; */
155 iwe.u.freq.m = network->channel;
156 iwe.u.freq.e = 0;
157 iwe.u.freq.i = 0;
158#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
159 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN);
160#else
161 start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_FREQ_LEN);
162#endif
163 /* Add encryption capability */
164 iwe.cmd = SIOCGIWENCODE;
165 if (network->capability & WLAN_CAPABILITY_PRIVACY)
166 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
167 else
168 iwe.u.data.flags = IW_ENCODE_DISABLED;
169 iwe.u.data.length = 0;
170#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
171 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
172#else
173 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
174#endif
175 /* Add basic and extended rates */
176 max_rate = 0;
177 p = custom;
178 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
179 for (i = 0, j = 0; i < network->rates_len; ) {
180 if (j < network->rates_ex_len &&
181 ((network->rates_ex[j] & 0x7F) <
182 (network->rates[i] & 0x7F)))
183 rate = network->rates_ex[j++] & 0x7F;
184 else
185 rate = network->rates[i++] & 0x7F;
186 if (rate > max_rate)
187 max_rate = rate;
188 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
189 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
190 }
191 for (; j < network->rates_ex_len; j++) {
192 rate = network->rates_ex[j] & 0x7F;
193 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
194 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
195 if (rate > max_rate)
196 max_rate = rate;
197 }
198
199 if (network->mode >= IEEE_N_24G)//add N rate here;
200 {
201 PHT_CAPABILITY_ELE ht_cap = NULL;
202 bool is40M = false, isShortGI = false;
203 u8 max_mcs = 0;
204 if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
205 ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4];
206 else
207 ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0];
208 is40M = (ht_cap->ChlWidth)?1:0;
209 isShortGI = (ht_cap->ChlWidth)?
210 ((ht_cap->ShortGI40Mhz)?1:0):
211 ((ht_cap->ShortGI20Mhz)?1:0);
212
213 max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL);
214 rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f];
215 if (rate > max_rate)
216 max_rate = rate;
217 }
218#if 0
219 printk("max rate:%d ===basic rate:\n", max_rate);
220 for (i=0;i<network->rates_len;i++)
221 printk(" %x", network->rates[i]);
222 printk("\n=======extend rate\n");
223 for (i=0; i<network->rates_ex_len; i++)
224 printk(" %x", network->rates_ex[i]);
225 printk("\n");
226#endif
227 iwe.cmd = SIOCGIWRATE;
228 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
229 iwe.u.bitrate.value = max_rate * 500000;
230#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
231 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
232 IW_EV_PARAM_LEN);
233#else
234 start = iwe_stream_add_event_rsl(start, stop, &iwe,
235 IW_EV_PARAM_LEN);
236#endif
237 iwe.cmd = IWEVCUSTOM;
238 iwe.u.data.length = p - custom;
239 if (iwe.u.data.length)
240#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
241 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
242#else
243 start = iwe_stream_add_point(start, stop, &iwe, custom);
244#endif
245 /* Add quality statistics */
246 /* TODO: Fix these values... */
247 iwe.cmd = IWEVQUAL;
248 iwe.u.qual.qual = network->stats.signal;
249 iwe.u.qual.level = network->stats.rssi;
250 iwe.u.qual.noise = network->stats.noise;
251 iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
252 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
253 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
254 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
255 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
256 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
257 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
258 iwe.u.qual.updated = 7;
259#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
260 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN);
261#else
262 start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_QUAL_LEN);
263#endif
264 iwe.cmd = IWEVCUSTOM;
265 p = custom;
266
267 iwe.u.data.length = p - custom;
268 if (iwe.u.data.length)
269#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
270 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
271#else
272 start = iwe_stream_add_point(start, stop, &iwe, custom);
273#endif
274#if (WIRELESS_EXT < 18)
275 if (ieee->wpa_enabled && network->wpa_ie_len){
276 char buf[MAX_WPA_IE_LEN * 2 + 30];
277 // printk("WPA IE\n");
278 u8 *p = buf;
279 p += sprintf(p, "wpa_ie=");
280 for (i = 0; i < network->wpa_ie_len; i++) {
281 p += sprintf(p, "%02x", network->wpa_ie[i]);
282 }
283
284 memset(&iwe, 0, sizeof(iwe));
285 iwe.cmd = IWEVCUSTOM;
286 iwe.u.data.length = strlen(buf);
287#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
288 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
289#else
290 start = iwe_stream_add_point(start, stop, &iwe, buf);
291#endif
292 }
293
294 if (ieee->wpa_enabled && network->rsn_ie_len){
295 char buf[MAX_WPA_IE_LEN * 2 + 30];
296
297 u8 *p = buf;
298 p += sprintf(p, "rsn_ie=");
299 for (i = 0; i < network->rsn_ie_len; i++) {
300 p += sprintf(p, "%02x", network->rsn_ie[i]);
301 }
302
303 memset(&iwe, 0, sizeof(iwe));
304 iwe.cmd = IWEVCUSTOM;
305 iwe.u.data.length = strlen(buf);
306#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
307 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
308#else
309 start = iwe_stream_add_point(start, stop, &iwe, buf);
310#endif
311 }
312#else
313 memset(&iwe, 0, sizeof(iwe));
314 if (network->wpa_ie_len)
315 {
316 char buf[MAX_WPA_IE_LEN];
317 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
318 iwe.cmd = IWEVGENIE;
319 iwe.u.data.length = network->wpa_ie_len;
320#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
321 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
322#else
323 start = iwe_stream_add_point(start, stop, &iwe, buf);
324#endif
325 }
326 memset(&iwe, 0, sizeof(iwe));
327 if (network->rsn_ie_len)
328 {
329 char buf[MAX_WPA_IE_LEN];
330 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
331 iwe.cmd = IWEVGENIE;
332 iwe.u.data.length = network->rsn_ie_len;
333#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
334 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
335#else
336 start = iwe_stream_add_point(start, stop, &iwe, buf);
337#endif
338 }
339#endif
340
341
342 /* Add EXTRA: Age to display seconds since last beacon/probe response
343 * for given network. */
344 iwe.cmd = IWEVCUSTOM;
345 p = custom;
346 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
347 " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
348 iwe.u.data.length = p - custom;
349 if (iwe.u.data.length)
350#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
351 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
352#else
353 start = iwe_stream_add_point(start, stop, &iwe, custom);
354#endif
355
356 return start;
357}
358
359int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
360 struct iw_request_info *info,
361 union iwreq_data *wrqu, char *extra)
362{
363 struct ieee80211_network *network;
364 unsigned long flags;
365
366 char *ev = extra;
367// char *stop = ev + IW_SCAN_MAX_DATA;
368 char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
369 //char *stop = ev + IW_SCAN_MAX_DATA;
370 int i = 0;
371 int err = 0;
372 IEEE80211_DEBUG_WX("Getting scan\n");
373 down(&ieee->wx_sem);
374 spin_lock_irqsave(&ieee->lock, flags);
375
376 list_for_each_entry(network, &ieee->network_list, list) {
377 i++;
378 if((stop-ev)<200)
379 {
380 err = -E2BIG;
381 break;
382 }
383 if (ieee->scan_age == 0 ||
384 time_after(network->last_scanned + ieee->scan_age, jiffies))
385 ev = rtl819x_translate_scan(ieee, ev, stop, network, info);
386 else
387 IEEE80211_DEBUG_SCAN(
388 "Not showing network '%s ("
389 MAC_FMT ")' due to age (%lums).\n",
390 escape_essid(network->ssid,
391 network->ssid_len),
392 MAC_ARG(network->bssid),
393 (jiffies - network->last_scanned) / (HZ / 100));
394 }
395
396 spin_unlock_irqrestore(&ieee->lock, flags);
397 up(&ieee->wx_sem);
398 wrqu->data.length = ev - extra;
399 wrqu->data.flags = 0;
400
401 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
402
403 return err;
404}
405
406int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
407 struct iw_request_info *info,
408 union iwreq_data *wrqu, char *keybuf)
409{
410 struct iw_point *erq = &(wrqu->encoding);
411 struct net_device *dev = ieee->dev;
412 struct ieee80211_security sec = {
413 .flags = 0
414 };
415 int i, key, key_provided, len;
416 struct ieee80211_crypt_data **crypt;
417
418 IEEE80211_DEBUG_WX("SET_ENCODE\n");
419
420 key = erq->flags & IW_ENCODE_INDEX;
421 if (key) {
422 if (key > WEP_KEYS)
423 return -EINVAL;
424 key--;
425 key_provided = 1;
426 } else {
427 key_provided = 0;
428 key = ieee->tx_keyidx;
429 }
430
431 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
432 "provided" : "default");
433 crypt = &ieee->crypt[key];
434
435 if (erq->flags & IW_ENCODE_DISABLED) {
436 if (key_provided && *crypt) {
437 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
438 key);
439 ieee80211_crypt_delayed_deinit(ieee, crypt);
440 } else
441 IEEE80211_DEBUG_WX("Disabling encryption.\n");
442
443 /* Check all the keys to see if any are still configured,
444 * and if no key index was provided, de-init them all */
445 for (i = 0; i < WEP_KEYS; i++) {
446 if (ieee->crypt[i] != NULL) {
447 if (key_provided)
448 break;
449 ieee80211_crypt_delayed_deinit(
450 ieee, &ieee->crypt[i]);
451 }
452 }
453
454 if (i == WEP_KEYS) {
455 sec.enabled = 0;
456 sec.level = SEC_LEVEL_0;
457 sec.flags |= SEC_ENABLED | SEC_LEVEL;
458 }
459
460 goto done;
461 }
462
463
464
465 sec.enabled = 1;
466 sec.flags |= SEC_ENABLED;
467
468 if (*crypt != NULL && (*crypt)->ops != NULL &&
469 strcmp((*crypt)->ops->name, "WEP") != 0) {
470 /* changing to use WEP; deinit previously used algorithm
471 * on this key */
472 ieee80211_crypt_delayed_deinit(ieee, crypt);
473 }
474
475 if (*crypt == NULL) {
476 struct ieee80211_crypt_data *new_crypt;
477
478 /* take WEP into use */
479 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
480 GFP_KERNEL);
481 if (new_crypt == NULL)
482 return -ENOMEM;
483 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
484 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
a010a337 485 if (!new_crypt->ops)
ecdfa446 486 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
a010a337 487 if (new_crypt->ops)
ecdfa446
GKH
488 new_crypt->priv = new_crypt->ops->init(key);
489
490 if (!new_crypt->ops || !new_crypt->priv) {
491 kfree(new_crypt);
492 new_crypt = NULL;
493
494 printk(KERN_WARNING "%s: could not initialize WEP: "
495 "load module ieee80211_crypt_wep\n",
496 dev->name);
497 return -EOPNOTSUPP;
498 }
499 *crypt = new_crypt;
500 }
501
502 /* If a new key was provided, set it up */
503 if (erq->length > 0) {
504 len = erq->length <= 5 ? 5 : 13;
505 memcpy(sec.keys[key], keybuf, erq->length);
506 if (len > erq->length)
507 memset(sec.keys[key] + erq->length, 0,
508 len - erq->length);
509 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
510 key, escape_essid(sec.keys[key], len),
511 erq->length, len);
512 sec.key_sizes[key] = len;
513 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
514 (*crypt)->priv);
515 sec.flags |= (1 << key);
516 /* This ensures a key will be activated if no key is
517 * explicitely set */
518 if (key == sec.active_key)
519 sec.flags |= SEC_ACTIVE_KEY;
520 ieee->tx_keyidx = key;
521
522 } else {
523 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
524 NULL, (*crypt)->priv);
525 if (len == 0) {
526 /* Set a default key of all 0 */
527 printk("Setting key %d to all zero.\n",
528 key);
529
530 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
531 key);
532 memset(sec.keys[key], 0, 13);
533 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
534 (*crypt)->priv);
535 sec.key_sizes[key] = 13;
536 sec.flags |= (1 << key);
537 }
538
539 /* No key data - just set the default TX key index */
540 if (key_provided) {
541 IEEE80211_DEBUG_WX(
542 "Setting key %d to default Tx key.\n", key);
543 ieee->tx_keyidx = key;
544 sec.active_key = key;
545 sec.flags |= SEC_ACTIVE_KEY;
546 }
547 }
548
549 done:
550 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
551 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
552 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
553 sec.flags |= SEC_AUTH_MODE;
554 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
555 "OPEN" : "SHARED KEY");
556
557 /* For now we just support WEP, so only set that security level...
558 * TODO: When WPA is added this is one place that needs to change */
559 sec.flags |= SEC_LEVEL;
560 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
561
562 if (ieee->set_security)
563 ieee->set_security(dev, &sec);
564
565 /* Do not reset port if card is in Managed mode since resetting will
566 * generate new IEEE 802.11 authentication which may end up in looping
567 * with IEEE 802.1X. If your hardware requires a reset after WEP
568 * configuration (for example... Prism2), implement the reset_port in
569 * the callbacks structures used to initialize the 802.11 stack. */
570 if (ieee->reset_on_keychange &&
571 ieee->iw_mode != IW_MODE_INFRA &&
572 ieee->reset_port && ieee->reset_port(dev)) {
573 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
574 return -EINVAL;
575 }
576 return 0;
577}
578
579int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
580 struct iw_request_info *info,
581 union iwreq_data *wrqu, char *keybuf)
582{
583 struct iw_point *erq = &(wrqu->encoding);
584 int len, key;
585 struct ieee80211_crypt_data *crypt;
586
587 IEEE80211_DEBUG_WX("GET_ENCODE\n");
588
589 if(ieee->iw_mode == IW_MODE_MONITOR)
590 return -1;
591
592 key = erq->flags & IW_ENCODE_INDEX;
593 if (key) {
594 if (key > WEP_KEYS)
595 return -EINVAL;
596 key--;
597 } else
598 key = ieee->tx_keyidx;
599
600 crypt = ieee->crypt[key];
601 erq->flags = key + 1;
602
603 if (crypt == NULL || crypt->ops == NULL) {
604 erq->length = 0;
605 erq->flags |= IW_ENCODE_DISABLED;
606 return 0;
607 }
608#if 0
609 if (strcmp(crypt->ops->name, "WEP") != 0) {
610 /* only WEP is supported with wireless extensions, so just
611 * report that encryption is used */
612 erq->length = 0;
613 erq->flags |= IW_ENCODE_ENABLED;
614 return 0;
615 }
616#endif
617 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
618 erq->length = (len >= 0 ? len : 0);
619
620 erq->flags |= IW_ENCODE_ENABLED;
621
622 if (ieee->open_wep)
623 erq->flags |= IW_ENCODE_OPEN;
624 else
625 erq->flags |= IW_ENCODE_RESTRICTED;
626
627 return 0;
628}
629#if (WIRELESS_EXT >= 18)
630int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
631 struct iw_request_info *info,
632 union iwreq_data *wrqu, char *extra)
633{
634 int ret = 0;
635#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
636 struct net_device *dev = ieee->dev;
637 struct iw_point *encoding = &wrqu->encoding;
638 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
639 int i, idx;
640 int group_key = 0;
a010a337 641 const char *alg;
ecdfa446
GKH
642 struct ieee80211_crypto_ops *ops;
643 struct ieee80211_crypt_data **crypt;
644
645 struct ieee80211_security sec = {
646 .flags = 0,
647 };
648 //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
649 idx = encoding->flags & IW_ENCODE_INDEX;
650 if (idx) {
651 if (idx < 1 || idx > WEP_KEYS)
652 return -EINVAL;
653 idx--;
654 } else
655 idx = ieee->tx_keyidx;
656
657 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
658
659 crypt = &ieee->crypt[idx];
660
661 group_key = 1;
662 } else {
663 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
664 //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
665 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
666 return -EINVAL;
667 if (ieee->iw_mode == IW_MODE_INFRA)
668
669 crypt = &ieee->crypt[idx];
670
671 else
672 return -EINVAL;
673 }
674
675 sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
676 if ((encoding->flags & IW_ENCODE_DISABLED) ||
677 ext->alg == IW_ENCODE_ALG_NONE) {
678 if (*crypt)
679 ieee80211_crypt_delayed_deinit(ieee, crypt);
680
681 for (i = 0; i < WEP_KEYS; i++)
682
683 if (ieee->crypt[i] != NULL)
684
685 break;
686
687 if (i == WEP_KEYS) {
688 sec.enabled = 0;
689 // sec.encrypt = 0;
690 sec.level = SEC_LEVEL_0;
691 sec.flags |= SEC_LEVEL;
692 }
693 //printk("disabled: flag:%x\n", encoding->flags);
694 goto done;
695 }
696
697 sec.enabled = 1;
698 // sec.encrypt = 1;
699#if 0
700 if (group_key ? !ieee->host_mc_decrypt :
701 !(ieee->host_encrypt || ieee->host_decrypt ||
702 ieee->host_encrypt_msdu))
703 goto skip_host_crypt;
704#endif
705 switch (ext->alg) {
706 case IW_ENCODE_ALG_WEP:
707 alg = "WEP";
ecdfa446
GKH
708 break;
709 case IW_ENCODE_ALG_TKIP:
710 alg = "TKIP";
ecdfa446
GKH
711 break;
712 case IW_ENCODE_ALG_CCMP:
713 alg = "CCMP";
ecdfa446
GKH
714 break;
715 default:
716 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
717 dev->name, ext->alg);
718 ret = -EINVAL;
719 goto done;
720 }
721 printk("alg name:%s\n",alg);
722
723 ops = ieee80211_get_crypto_ops(alg);
a010a337 724 if (ops == NULL)
ecdfa446 725 ops = ieee80211_get_crypto_ops(alg);
ecdfa446
GKH
726 if (ops == NULL) {
727 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
728 dev->name, ext->alg);
729 printk("========>unknown crypto alg %d\n", ext->alg);
730 ret = -EINVAL;
731 goto done;
732 }
733
734 if (*crypt == NULL || (*crypt)->ops != ops) {
735 struct ieee80211_crypt_data *new_crypt;
736
737 ieee80211_crypt_delayed_deinit(ieee, crypt);
738
739#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
740 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
741#else
742 new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL);
743 memset(new_crypt,0,sizeof(*new_crypt));
744#endif
745 if (new_crypt == NULL) {
746 ret = -ENOMEM;
747 goto done;
748 }
749 new_crypt->ops = ops;
a010a337 750 if (new_crypt->ops)
ecdfa446
GKH
751 new_crypt->priv = new_crypt->ops->init(idx);
752 if (new_crypt->priv == NULL) {
753 kfree(new_crypt);
754 ret = -EINVAL;
755 goto done;
756 }
757 *crypt = new_crypt;
758
759 }
760
761 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
762 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
763 (*crypt)->priv) < 0) {
764 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
765 printk("key setting failed\n");
766 ret = -EINVAL;
767 goto done;
768 }
769#if 1
770 //skip_host_crypt:
771 //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
772 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
773 ieee->tx_keyidx = idx;
774 sec.active_key = idx;
775 sec.flags |= SEC_ACTIVE_KEY;
776 }
777
778 if (ext->alg != IW_ENCODE_ALG_NONE) {
779 //memcpy(sec.keys[idx], ext->key, ext->key_len);
780 sec.key_sizes[idx] = ext->key_len;
781 sec.flags |= (1 << idx);
782 if (ext->alg == IW_ENCODE_ALG_WEP) {
783 // sec.encode_alg[idx] = SEC_ALG_WEP;
784 sec.flags |= SEC_LEVEL;
785 sec.level = SEC_LEVEL_1;
786 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
787 // sec.encode_alg[idx] = SEC_ALG_TKIP;
788 sec.flags |= SEC_LEVEL;
789 sec.level = SEC_LEVEL_2;
790 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
791 // sec.encode_alg[idx] = SEC_ALG_CCMP;
792 sec.flags |= SEC_LEVEL;
793 sec.level = SEC_LEVEL_3;
794 }
795 /* Don't set sec level for group keys. */
796 if (group_key)
797 sec.flags &= ~SEC_LEVEL;
798 }
799#endif
800done:
801 if (ieee->set_security)
802 ieee->set_security(ieee->dev, &sec);
803
804 if (ieee->reset_on_keychange &&
805 ieee->iw_mode != IW_MODE_INFRA &&
806 ieee->reset_port && ieee->reset_port(dev)) {
807 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
808 return -EINVAL;
809 }
810#endif
811 return ret;
812}
813
814int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
815 struct iw_request_info *info,
816 union iwreq_data *wrqu, char *extra)
817{
818 struct iw_point *encoding = &wrqu->encoding;
819 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
820 struct ieee80211_crypt_data *crypt;
821 int idx, max_key_len;
822
823 max_key_len = encoding->length - sizeof(*ext);
824 if (max_key_len < 0)
825 return -EINVAL;
826
827 idx = encoding->flags & IW_ENCODE_INDEX;
828 if (idx) {
829 if (idx < 1 || idx > WEP_KEYS)
830 return -EINVAL;
831 idx--;
832 } else
833 idx = ieee->tx_keyidx;
834
3ef5a262 835 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
ecdfa446
GKH
836 ext->alg != IW_ENCODE_ALG_WEP)
837 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
838 return -EINVAL;
839
840 crypt = ieee->crypt[idx];
841 encoding->flags = idx + 1;
842 memset(ext, 0, sizeof(*ext));
843
844 if (crypt == NULL || crypt->ops == NULL ) {
845 ext->alg = IW_ENCODE_ALG_NONE;
846 ext->key_len = 0;
847 encoding->flags |= IW_ENCODE_DISABLED;
848 } else {
849 if (strcmp(crypt->ops->name, "WEP") == 0 )
850 ext->alg = IW_ENCODE_ALG_WEP;
851 else if (strcmp(crypt->ops->name, "TKIP"))
852 ext->alg = IW_ENCODE_ALG_TKIP;
853 else if (strcmp(crypt->ops->name, "CCMP"))
854 ext->alg = IW_ENCODE_ALG_CCMP;
855 else
856 return -EINVAL;
857 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
858 encoding->flags |= IW_ENCODE_ENABLED;
859 if (ext->key_len &&
860 (ext->alg == IW_ENCODE_ALG_TKIP ||
861 ext->alg == IW_ENCODE_ALG_CCMP))
862 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
863
864 }
865
866 return 0;
867}
868
869int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
870 struct iw_request_info *info,
871 union iwreq_data *wrqu, char *extra)
872{
873#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
874 struct iw_mlme *mlme = (struct iw_mlme *) extra;
875 switch (mlme->cmd) {
876 case IW_MLME_DEAUTH:
877 case IW_MLME_DISASSOC:
878 ieee80211_disassociate(ieee);
879 break;
880 default:
881 return -EOPNOTSUPP;
882 }
883#endif
884 return 0;
885}
886
887int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
888 struct iw_request_info *info,
889 struct iw_param *data, char *extra)
890{
891#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
892 switch (data->flags & IW_AUTH_INDEX) {
893 case IW_AUTH_WPA_VERSION:
894 /*need to support wpa2 here*/
895 //printk("wpa version:%x\n", data->value);
896 break;
897 case IW_AUTH_CIPHER_PAIRWISE:
898 case IW_AUTH_CIPHER_GROUP:
899 case IW_AUTH_KEY_MGMT:
900 /*
901 * * Host AP driver does not use these parameters and allows
902 * * wpa_supplicant to control them internally.
903 * */
904 break;
905 case IW_AUTH_TKIP_COUNTERMEASURES:
906 ieee->tkip_countermeasures = data->value;
907 break;
908 case IW_AUTH_DROP_UNENCRYPTED:
909 ieee->drop_unencrypted = data->value;
910 break;
911
912 case IW_AUTH_80211_AUTH_ALG:
913 //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
914 // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
915 if(data->value & IW_AUTH_ALG_SHARED_KEY){
916 ieee->open_wep = 0;
917 ieee->auth_mode = 1;
918 }
919 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
920 ieee->open_wep = 1;
921 ieee->auth_mode = 0;
922 }
923 else if(data->value & IW_AUTH_ALG_LEAP){
924 ieee->open_wep = 1;
925 ieee->auth_mode = 2;
926 //printk("hahahaa:LEAP\n");
927 }
928 else
929 return -EINVAL;
930 //printk("open_wep:%d\n", ieee->open_wep);
931 break;
932
933#if 1
934 case IW_AUTH_WPA_ENABLED:
935 ieee->wpa_enabled = (data->value)?1:0;
936 //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
937 break;
938
939#endif
940 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
941 ieee->ieee802_1x = data->value;
942 break;
943 case IW_AUTH_PRIVACY_INVOKED:
944 ieee->privacy_invoked = data->value;
945 break;
946 default:
947 return -EOPNOTSUPP;
948 }
949#endif
950 return 0;
951}
952#endif
953#if 1
954int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
955{
956#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
957#if 0
958 printk("====>%s()\n", __FUNCTION__);
959 {
960 int i;
961 for (i=0; i<len; i++)
962 printk("%2x ", ie[i]&0xff);
963 printk("\n");
964 }
965#endif
966 u8 *buf;
967
968 if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
969 {
970 // printk("return error out, len:%d\n", len);
971 return -EINVAL;
972 }
973
974
975 if (len)
976 {
977 if (len != ie[1]+2)
978 {
3d8affc0 979 printk("len:%zu, ie:%d\n", len, ie[1]);
ecdfa446
GKH
980 return -EINVAL;
981 }
982 buf = kmalloc(len, GFP_KERNEL);
983 if (buf == NULL)
984 return -ENOMEM;
985 memcpy(buf, ie, len);
986 kfree(ieee->wpa_ie);
987 ieee->wpa_ie = buf;
988 ieee->wpa_ie_len = len;
989 }
990 else{
991 if (ieee->wpa_ie)
992 kfree(ieee->wpa_ie);
993 ieee->wpa_ie = NULL;
994 ieee->wpa_ie_len = 0;
995 }
996#endif
997 return 0;
998
999}
1000#endif
1001
1002#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1003//EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
1004#if (WIRELESS_EXT >= 18)
1005//EXPORT_SYMBOL(ieee80211_wx_set_mlme);
1006//EXPORT_SYMBOL(ieee80211_wx_set_auth);
1007//EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
1008//EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
1009#endif
1010//EXPORT_SYMBOL(ieee80211_wx_get_scan);
1011//EXPORT_SYMBOL(ieee80211_wx_set_encode);
1012//EXPORT_SYMBOL(ieee80211_wx_get_encode);
1013#else
1014//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_gen_ie);
1015//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mlme);
1016//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_auth);
1017//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode_ext);
1018//EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_scan);
1019//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode);
1020//EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_encode);
1021#endif