Staging: add Realtek 8192 PCI wireless driver
[deliverable/linux.git] / drivers / staging / rtl8192e / ieee80211 / ieee80211_wx.c
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
39 static const char *ieee80211_modes[] = {
40 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
41 };
42 #endif
43 struct modes_unit {
44 char *mode_string;
45 int mode_size;
46 };
47 struct 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))
57 static inline char *
58 iwe_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
77 static 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
359 int 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
406 int 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");
485 if (!new_crypt->ops) {
486 request_module("ieee80211_crypt_wep");
487 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
488 }
489 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
490 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
491 #else
492 if (new_crypt->ops && try_inc_mod_count(new_crypt->ops->owner))
493 #endif
494 new_crypt->priv = new_crypt->ops->init(key);
495
496 if (!new_crypt->ops || !new_crypt->priv) {
497 kfree(new_crypt);
498 new_crypt = NULL;
499
500 printk(KERN_WARNING "%s: could not initialize WEP: "
501 "load module ieee80211_crypt_wep\n",
502 dev->name);
503 return -EOPNOTSUPP;
504 }
505 *crypt = new_crypt;
506 }
507
508 /* If a new key was provided, set it up */
509 if (erq->length > 0) {
510 len = erq->length <= 5 ? 5 : 13;
511 memcpy(sec.keys[key], keybuf, erq->length);
512 if (len > erq->length)
513 memset(sec.keys[key] + erq->length, 0,
514 len - erq->length);
515 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
516 key, escape_essid(sec.keys[key], len),
517 erq->length, len);
518 sec.key_sizes[key] = len;
519 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
520 (*crypt)->priv);
521 sec.flags |= (1 << key);
522 /* This ensures a key will be activated if no key is
523 * explicitely set */
524 if (key == sec.active_key)
525 sec.flags |= SEC_ACTIVE_KEY;
526 ieee->tx_keyidx = key;
527
528 } else {
529 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
530 NULL, (*crypt)->priv);
531 if (len == 0) {
532 /* Set a default key of all 0 */
533 printk("Setting key %d to all zero.\n",
534 key);
535
536 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
537 key);
538 memset(sec.keys[key], 0, 13);
539 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
540 (*crypt)->priv);
541 sec.key_sizes[key] = 13;
542 sec.flags |= (1 << key);
543 }
544
545 /* No key data - just set the default TX key index */
546 if (key_provided) {
547 IEEE80211_DEBUG_WX(
548 "Setting key %d to default Tx key.\n", key);
549 ieee->tx_keyidx = key;
550 sec.active_key = key;
551 sec.flags |= SEC_ACTIVE_KEY;
552 }
553 }
554
555 done:
556 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
557 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
558 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
559 sec.flags |= SEC_AUTH_MODE;
560 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
561 "OPEN" : "SHARED KEY");
562
563 /* For now we just support WEP, so only set that security level...
564 * TODO: When WPA is added this is one place that needs to change */
565 sec.flags |= SEC_LEVEL;
566 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
567
568 if (ieee->set_security)
569 ieee->set_security(dev, &sec);
570
571 /* Do not reset port if card is in Managed mode since resetting will
572 * generate new IEEE 802.11 authentication which may end up in looping
573 * with IEEE 802.1X. If your hardware requires a reset after WEP
574 * configuration (for example... Prism2), implement the reset_port in
575 * the callbacks structures used to initialize the 802.11 stack. */
576 if (ieee->reset_on_keychange &&
577 ieee->iw_mode != IW_MODE_INFRA &&
578 ieee->reset_port && ieee->reset_port(dev)) {
579 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
580 return -EINVAL;
581 }
582 return 0;
583 }
584
585 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
586 struct iw_request_info *info,
587 union iwreq_data *wrqu, char *keybuf)
588 {
589 struct iw_point *erq = &(wrqu->encoding);
590 int len, key;
591 struct ieee80211_crypt_data *crypt;
592
593 IEEE80211_DEBUG_WX("GET_ENCODE\n");
594
595 if(ieee->iw_mode == IW_MODE_MONITOR)
596 return -1;
597
598 key = erq->flags & IW_ENCODE_INDEX;
599 if (key) {
600 if (key > WEP_KEYS)
601 return -EINVAL;
602 key--;
603 } else
604 key = ieee->tx_keyidx;
605
606 crypt = ieee->crypt[key];
607 erq->flags = key + 1;
608
609 if (crypt == NULL || crypt->ops == NULL) {
610 erq->length = 0;
611 erq->flags |= IW_ENCODE_DISABLED;
612 return 0;
613 }
614 #if 0
615 if (strcmp(crypt->ops->name, "WEP") != 0) {
616 /* only WEP is supported with wireless extensions, so just
617 * report that encryption is used */
618 erq->length = 0;
619 erq->flags |= IW_ENCODE_ENABLED;
620 return 0;
621 }
622 #endif
623 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
624 erq->length = (len >= 0 ? len : 0);
625
626 erq->flags |= IW_ENCODE_ENABLED;
627
628 if (ieee->open_wep)
629 erq->flags |= IW_ENCODE_OPEN;
630 else
631 erq->flags |= IW_ENCODE_RESTRICTED;
632
633 return 0;
634 }
635 #if (WIRELESS_EXT >= 18)
636 int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
637 struct iw_request_info *info,
638 union iwreq_data *wrqu, char *extra)
639 {
640 int ret = 0;
641 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
642 struct net_device *dev = ieee->dev;
643 struct iw_point *encoding = &wrqu->encoding;
644 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
645 int i, idx;
646 int group_key = 0;
647 const char *alg, *module;
648 struct ieee80211_crypto_ops *ops;
649 struct ieee80211_crypt_data **crypt;
650
651 struct ieee80211_security sec = {
652 .flags = 0,
653 };
654 //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
655 idx = encoding->flags & IW_ENCODE_INDEX;
656 if (idx) {
657 if (idx < 1 || idx > WEP_KEYS)
658 return -EINVAL;
659 idx--;
660 } else
661 idx = ieee->tx_keyidx;
662
663 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
664
665 crypt = &ieee->crypt[idx];
666
667 group_key = 1;
668 } else {
669 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
670 //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
671 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
672 return -EINVAL;
673 if (ieee->iw_mode == IW_MODE_INFRA)
674
675 crypt = &ieee->crypt[idx];
676
677 else
678 return -EINVAL;
679 }
680
681 sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
682 if ((encoding->flags & IW_ENCODE_DISABLED) ||
683 ext->alg == IW_ENCODE_ALG_NONE) {
684 if (*crypt)
685 ieee80211_crypt_delayed_deinit(ieee, crypt);
686
687 for (i = 0; i < WEP_KEYS; i++)
688
689 if (ieee->crypt[i] != NULL)
690
691 break;
692
693 if (i == WEP_KEYS) {
694 sec.enabled = 0;
695 // sec.encrypt = 0;
696 sec.level = SEC_LEVEL_0;
697 sec.flags |= SEC_LEVEL;
698 }
699 //printk("disabled: flag:%x\n", encoding->flags);
700 goto done;
701 }
702
703 sec.enabled = 1;
704 // sec.encrypt = 1;
705 #if 0
706 if (group_key ? !ieee->host_mc_decrypt :
707 !(ieee->host_encrypt || ieee->host_decrypt ||
708 ieee->host_encrypt_msdu))
709 goto skip_host_crypt;
710 #endif
711 switch (ext->alg) {
712 case IW_ENCODE_ALG_WEP:
713 alg = "WEP";
714 module = "ieee80211_crypt_wep";
715 break;
716 case IW_ENCODE_ALG_TKIP:
717 alg = "TKIP";
718 module = "ieee80211_crypt_tkip";
719 break;
720 case IW_ENCODE_ALG_CCMP:
721 alg = "CCMP";
722 module = "ieee80211_crypt_ccmp";
723 break;
724 default:
725 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
726 dev->name, ext->alg);
727 ret = -EINVAL;
728 goto done;
729 }
730 printk("alg name:%s\n",alg);
731
732 ops = ieee80211_get_crypto_ops(alg);
733 if (ops == NULL) {
734 request_module(module);
735 ops = ieee80211_get_crypto_ops(alg);
736 }
737 if (ops == NULL) {
738 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
739 dev->name, ext->alg);
740 printk("========>unknown crypto alg %d\n", ext->alg);
741 ret = -EINVAL;
742 goto done;
743 }
744
745 if (*crypt == NULL || (*crypt)->ops != ops) {
746 struct ieee80211_crypt_data *new_crypt;
747
748 ieee80211_crypt_delayed_deinit(ieee, crypt);
749
750 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
751 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
752 #else
753 new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL);
754 memset(new_crypt,0,sizeof(*new_crypt));
755 #endif
756 if (new_crypt == NULL) {
757 ret = -ENOMEM;
758 goto done;
759 }
760 new_crypt->ops = ops;
761 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
762 new_crypt->priv = new_crypt->ops->init(idx);
763 if (new_crypt->priv == NULL) {
764 kfree(new_crypt);
765 ret = -EINVAL;
766 goto done;
767 }
768 *crypt = new_crypt;
769
770 }
771
772 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
773 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
774 (*crypt)->priv) < 0) {
775 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
776 printk("key setting failed\n");
777 ret = -EINVAL;
778 goto done;
779 }
780 #if 1
781 //skip_host_crypt:
782 //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
783 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
784 ieee->tx_keyidx = idx;
785 sec.active_key = idx;
786 sec.flags |= SEC_ACTIVE_KEY;
787 }
788
789 if (ext->alg != IW_ENCODE_ALG_NONE) {
790 //memcpy(sec.keys[idx], ext->key, ext->key_len);
791 sec.key_sizes[idx] = ext->key_len;
792 sec.flags |= (1 << idx);
793 if (ext->alg == IW_ENCODE_ALG_WEP) {
794 // sec.encode_alg[idx] = SEC_ALG_WEP;
795 sec.flags |= SEC_LEVEL;
796 sec.level = SEC_LEVEL_1;
797 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
798 // sec.encode_alg[idx] = SEC_ALG_TKIP;
799 sec.flags |= SEC_LEVEL;
800 sec.level = SEC_LEVEL_2;
801 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
802 // sec.encode_alg[idx] = SEC_ALG_CCMP;
803 sec.flags |= SEC_LEVEL;
804 sec.level = SEC_LEVEL_3;
805 }
806 /* Don't set sec level for group keys. */
807 if (group_key)
808 sec.flags &= ~SEC_LEVEL;
809 }
810 #endif
811 done:
812 if (ieee->set_security)
813 ieee->set_security(ieee->dev, &sec);
814
815 if (ieee->reset_on_keychange &&
816 ieee->iw_mode != IW_MODE_INFRA &&
817 ieee->reset_port && ieee->reset_port(dev)) {
818 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
819 return -EINVAL;
820 }
821 #endif
822 return ret;
823 }
824
825 int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
826 struct iw_request_info *info,
827 union iwreq_data *wrqu, char *extra)
828 {
829 struct iw_point *encoding = &wrqu->encoding;
830 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
831 struct ieee80211_crypt_data *crypt;
832 int idx, max_key_len;
833
834 max_key_len = encoding->length - sizeof(*ext);
835 if (max_key_len < 0)
836 return -EINVAL;
837
838 idx = encoding->flags & IW_ENCODE_INDEX;
839 if (idx) {
840 if (idx < 1 || idx > WEP_KEYS)
841 return -EINVAL;
842 idx--;
843 } else
844 idx = ieee->tx_keyidx;
845
846 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
847 ext->alg != IW_ENCODE_ALG_WEP)
848 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
849 return -EINVAL;
850
851 crypt = ieee->crypt[idx];
852 encoding->flags = idx + 1;
853 memset(ext, 0, sizeof(*ext));
854
855 if (crypt == NULL || crypt->ops == NULL ) {
856 ext->alg = IW_ENCODE_ALG_NONE;
857 ext->key_len = 0;
858 encoding->flags |= IW_ENCODE_DISABLED;
859 } else {
860 if (strcmp(crypt->ops->name, "WEP") == 0 )
861 ext->alg = IW_ENCODE_ALG_WEP;
862 else if (strcmp(crypt->ops->name, "TKIP"))
863 ext->alg = IW_ENCODE_ALG_TKIP;
864 else if (strcmp(crypt->ops->name, "CCMP"))
865 ext->alg = IW_ENCODE_ALG_CCMP;
866 else
867 return -EINVAL;
868 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
869 encoding->flags |= IW_ENCODE_ENABLED;
870 if (ext->key_len &&
871 (ext->alg == IW_ENCODE_ALG_TKIP ||
872 ext->alg == IW_ENCODE_ALG_CCMP))
873 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
874
875 }
876
877 return 0;
878 }
879
880 int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
881 struct iw_request_info *info,
882 union iwreq_data *wrqu, char *extra)
883 {
884 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
885 struct iw_mlme *mlme = (struct iw_mlme *) extra;
886 switch (mlme->cmd) {
887 case IW_MLME_DEAUTH:
888 case IW_MLME_DISASSOC:
889 ieee80211_disassociate(ieee);
890 break;
891 default:
892 return -EOPNOTSUPP;
893 }
894 #endif
895 return 0;
896 }
897
898 int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
899 struct iw_request_info *info,
900 struct iw_param *data, char *extra)
901 {
902 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
903 switch (data->flags & IW_AUTH_INDEX) {
904 case IW_AUTH_WPA_VERSION:
905 /*need to support wpa2 here*/
906 //printk("wpa version:%x\n", data->value);
907 break;
908 case IW_AUTH_CIPHER_PAIRWISE:
909 case IW_AUTH_CIPHER_GROUP:
910 case IW_AUTH_KEY_MGMT:
911 /*
912 * * Host AP driver does not use these parameters and allows
913 * * wpa_supplicant to control them internally.
914 * */
915 break;
916 case IW_AUTH_TKIP_COUNTERMEASURES:
917 ieee->tkip_countermeasures = data->value;
918 break;
919 case IW_AUTH_DROP_UNENCRYPTED:
920 ieee->drop_unencrypted = data->value;
921 break;
922
923 case IW_AUTH_80211_AUTH_ALG:
924 //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
925 // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
926 if(data->value & IW_AUTH_ALG_SHARED_KEY){
927 ieee->open_wep = 0;
928 ieee->auth_mode = 1;
929 }
930 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
931 ieee->open_wep = 1;
932 ieee->auth_mode = 0;
933 }
934 else if(data->value & IW_AUTH_ALG_LEAP){
935 ieee->open_wep = 1;
936 ieee->auth_mode = 2;
937 //printk("hahahaa:LEAP\n");
938 }
939 else
940 return -EINVAL;
941 //printk("open_wep:%d\n", ieee->open_wep);
942 break;
943
944 #if 1
945 case IW_AUTH_WPA_ENABLED:
946 ieee->wpa_enabled = (data->value)?1:0;
947 //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
948 break;
949
950 #endif
951 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
952 ieee->ieee802_1x = data->value;
953 break;
954 case IW_AUTH_PRIVACY_INVOKED:
955 ieee->privacy_invoked = data->value;
956 break;
957 default:
958 return -EOPNOTSUPP;
959 }
960 #endif
961 return 0;
962 }
963 #endif
964 #if 1
965 int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
966 {
967 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
968 #if 0
969 printk("====>%s()\n", __FUNCTION__);
970 {
971 int i;
972 for (i=0; i<len; i++)
973 printk("%2x ", ie[i]&0xff);
974 printk("\n");
975 }
976 #endif
977 u8 *buf;
978
979 if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
980 {
981 // printk("return error out, len:%d\n", len);
982 return -EINVAL;
983 }
984
985
986 if (len)
987 {
988 if (len != ie[1]+2)
989 {
990 printk("len:%d, ie:%d\n", len, ie[1]);
991 return -EINVAL;
992 }
993 buf = kmalloc(len, GFP_KERNEL);
994 if (buf == NULL)
995 return -ENOMEM;
996 memcpy(buf, ie, len);
997 kfree(ieee->wpa_ie);
998 ieee->wpa_ie = buf;
999 ieee->wpa_ie_len = len;
1000 }
1001 else{
1002 if (ieee->wpa_ie)
1003 kfree(ieee->wpa_ie);
1004 ieee->wpa_ie = NULL;
1005 ieee->wpa_ie_len = 0;
1006 }
1007 #endif
1008 return 0;
1009
1010 }
1011 #endif
1012
1013 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1014 //EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
1015 #if (WIRELESS_EXT >= 18)
1016 //EXPORT_SYMBOL(ieee80211_wx_set_mlme);
1017 //EXPORT_SYMBOL(ieee80211_wx_set_auth);
1018 //EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
1019 //EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
1020 #endif
1021 //EXPORT_SYMBOL(ieee80211_wx_get_scan);
1022 //EXPORT_SYMBOL(ieee80211_wx_set_encode);
1023 //EXPORT_SYMBOL(ieee80211_wx_get_encode);
1024 #else
1025 //EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_gen_ie);
1026 //EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mlme);
1027 //EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_auth);
1028 //EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode_ext);
1029 //EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_scan);
1030 //EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode);
1031 //EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_encode);
1032 #endif
This page took 0.052476 seconds and 5 git commands to generate.