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