1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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,
59 char * ends,
60 struct iw_event *iwe,
61 int event_len)
62{
63
64 if((stream + event_len) < ends) {
65 iwe->len = event_len;
66 ndelay(1);
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
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
101
102
103 iwe.cmd = SIOCGIWESSID;
104 iwe.u.data.flags = 1;
105
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
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
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
152 iwe.cmd = SIOCGIWFREQ;
153
154
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
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
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)
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
246
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
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
343
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
368 char *stop = ev + wrqu->data.length;
369
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
444
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
471
472 ieee80211_crypt_delayed_deinit(ieee, crypt);
473 }
474
475 if (*crypt == NULL) {
476 struct ieee80211_crypt_data *new_crypt;
477
478
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");
485 if (!new_crypt->ops)
486 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
487 if (new_crypt->ops)
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
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
517
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
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
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
558
559 sec.flags |= SEC_LEVEL;
560 sec.level = SEC_LEVEL_1;
561
562 if (ieee->set_security)
563 ieee->set_security(dev, &sec);
564
565
566
567
568
569
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
611
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;
641 const char *alg;
642 struct ieee80211_crypto_ops *ops;
643 struct ieee80211_crypt_data **crypt;
644
645 struct ieee80211_security sec = {
646 .flags = 0,
647 };
648
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
664
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;
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
690 sec.level = SEC_LEVEL_0;
691 sec.flags |= SEC_LEVEL;
692 }
693
694 goto done;
695 }
696
697 sec.enabled = 1;
698
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";
708 break;
709 case IW_ENCODE_ALG_TKIP:
710 alg = "TKIP";
711 break;
712 case IW_ENCODE_ALG_CCMP:
713 alg = "CCMP";
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);
724 if (ops == NULL)
725 ops = ieee80211_get_crypto_ops(alg);
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;
750 if (new_crypt->ops)
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
771
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
780 sec.key_sizes[idx] = ext->key_len;
781 sec.flags |= (1 << idx);
782 if (ext->alg == IW_ENCODE_ALG_WEP) {
783
784 sec.flags |= SEC_LEVEL;
785 sec.level = SEC_LEVEL_1;
786 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
787
788 sec.flags |= SEC_LEVEL;
789 sec.level = SEC_LEVEL_2;
790 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
791
792 sec.flags |= SEC_LEVEL;
793 sec.level = SEC_LEVEL_3;
794 }
795
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
835 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
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
895
896 break;
897 case IW_AUTH_CIPHER_PAIRWISE:
898 case IW_AUTH_CIPHER_GROUP:
899 case IW_AUTH_KEY_MGMT:
900
901
902
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
914
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
927 }
928 else
929 return -EINVAL;
930
931 break;
932
933#if 1
934 case IW_AUTH_WPA_ENABLED:
935 ieee->wpa_enabled = (data->value)?1:0;
936
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
971 return -EINVAL;
972 }
973
974
975 if (len)
976 {
977 if (len != ie[1]+2)
978 {
979 printk("len:%d, ie:%d\n", len, ie[1]);
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
1004#if (WIRELESS_EXT >= 18)
1005
1006
1007
1008
1009#endif
1010
1011
1012
1013#else
1014
1015
1016
1017
1018
1019
1020
1021#endif
1022