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