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