Fix common misspellings
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / rtl8192e / ieee80211 / ieee80211_wx.c
CommitLineData
ecdfa446
GKH
1/******************************************************************************
2
3 Copyright(c) 2004 Intel Corporation. All rights reserved.
4
5 Portions of this file are based on the WEP enablement code provided by the
6 Host AP project hostap-drivers v0.1.3
7 Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
8 <jkmaline@cc.hut.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
10
11 This program is free software; you can redistribute it and/or modify it
12 under the terms of version 2 of the GNU General Public License as
13 published by the Free Software Foundation.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 more details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59
22 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 The full GNU General Public License is included in this distribution in the
25 file called LICENSE.
26
27 Contact Information:
28 James P. Ketrenos <ipw2100-admin@linux.intel.com>
29 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31******************************************************************************/
32#include <linux/wireless.h>
33#include <linux/version.h>
34#include <linux/kmod.h>
5a0e3ad6 35#include <linux/slab.h>
ecdfa446
GKH
36#include <linux/module.h>
37
38#include "ieee80211.h"
85c876e4 39
ecdfa446
GKH
40struct modes_unit {
41 char *mode_string;
42 int mode_size;
43};
44struct modes_unit ieee80211_modes[] = {
45 {"a",1},
46 {"b",1},
47 {"g",1},
48 {"?",1},
49 {"N-24G",5},
50 {"N-5G",4},
51};
52
ecdfa446 53#define iwe_stream_add_event_rsl iwe_stream_add_event
ecdfa446
GKH
54
55#define MAX_CUSTOM_LEN 64
56static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
57 char *start, char *stop,
58 struct ieee80211_network *network,
59 struct iw_request_info *info)
60{
61 char custom[MAX_CUSTOM_LEN];
62 char proto_name[IFNAMSIZ];
63 char *pname = proto_name;
64 char *p;
65 struct iw_event iwe;
66 int i, j;
67 u16 max_rate, rate;
68 static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
69
70 /* First entry *MUST* be the AP MAC address */
71 iwe.cmd = SIOCGIWAP;
72 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
73 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
ecdfa446 74 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN);
ecdfa446
GKH
75 /* Remaining entries will be displayed in the order we provide them */
76
77 /* Add the ESSID */
78 iwe.cmd = SIOCGIWESSID;
79 iwe.u.data.flags = 1;
80// if (network->flags & NETWORK_EMPTY_ESSID) {
81 if (network->ssid_len == 0) {
82 iwe.u.data.length = sizeof("<hidden>");
ecdfa446 83 start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
ecdfa446
GKH
84 } else {
85 iwe.u.data.length = min(network->ssid_len, (u8)32);
ecdfa446 86 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
ecdfa446
GKH
87 }
88 /* Add the protocol name */
89 iwe.cmd = SIOCGIWNAME;
7e1d794f 90 for(i=0; i<ARRAY_SIZE(ieee80211_modes); i++) {
ecdfa446
GKH
91 if(network->mode&(1<<i)) {
92 sprintf(pname,ieee80211_modes[i].mode_string,ieee80211_modes[i].mode_size);
93 pname +=ieee80211_modes[i].mode_size;
94 }
95 }
96 *pname = '\0';
97 snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
ecdfa446 98 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN);
ecdfa446
GKH
99 /* Add mode */
100 iwe.cmd = SIOCGIWMODE;
101 if (network->capability &
102 (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) {
103 if (network->capability & WLAN_CAPABILITY_BSS)
104 iwe.u.mode = IW_MODE_MASTER;
105 else
106 iwe.u.mode = IW_MODE_ADHOC;
ecdfa446 107 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN);
ecdfa446
GKH
108 }
109
110 /* Add frequency/channel */
111 iwe.cmd = SIOCGIWFREQ;
112/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
113 iwe.u.freq.e = 3; */
114 iwe.u.freq.m = network->channel;
115 iwe.u.freq.e = 0;
116 iwe.u.freq.i = 0;
ecdfa446 117 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN);
ecdfa446
GKH
118 /* Add encryption capability */
119 iwe.cmd = SIOCGIWENCODE;
120 if (network->capability & WLAN_CAPABILITY_PRIVACY)
121 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
122 else
123 iwe.u.data.flags = IW_ENCODE_DISABLED;
124 iwe.u.data.length = 0;
ecdfa446 125 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
ecdfa446
GKH
126 /* Add basic and extended rates */
127 max_rate = 0;
128 p = custom;
129 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
130 for (i = 0, j = 0; i < network->rates_len; ) {
131 if (j < network->rates_ex_len &&
132 ((network->rates_ex[j] & 0x7F) <
133 (network->rates[i] & 0x7F)))
134 rate = network->rates_ex[j++] & 0x7F;
135 else
136 rate = network->rates[i++] & 0x7F;
137 if (rate > max_rate)
138 max_rate = rate;
139 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
140 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
141 }
142 for (; j < network->rates_ex_len; j++) {
143 rate = network->rates_ex[j] & 0x7F;
144 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
145 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
146 if (rate > max_rate)
147 max_rate = rate;
148 }
149
150 if (network->mode >= IEEE_N_24G)//add N rate here;
151 {
152 PHT_CAPABILITY_ELE ht_cap = NULL;
153 bool is40M = false, isShortGI = false;
154 u8 max_mcs = 0;
155 if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
156 ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4];
157 else
158 ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0];
159 is40M = (ht_cap->ChlWidth)?1:0;
160 isShortGI = (ht_cap->ChlWidth)?
161 ((ht_cap->ShortGI40Mhz)?1:0):
162 ((ht_cap->ShortGI20Mhz)?1:0);
163
164 max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL);
165 rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f];
166 if (rate > max_rate)
167 max_rate = rate;
168 }
ecdfa446
GKH
169 iwe.cmd = SIOCGIWRATE;
170 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
171 iwe.u.bitrate.value = max_rate * 500000;
ecdfa446
GKH
172 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
173 IW_EV_PARAM_LEN);
ecdfa446
GKH
174 iwe.cmd = IWEVCUSTOM;
175 iwe.u.data.length = p - custom;
176 if (iwe.u.data.length)
ecdfa446 177 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
ecdfa446
GKH
178 /* Add quality statistics */
179 /* TODO: Fix these values... */
180 iwe.cmd = IWEVQUAL;
181 iwe.u.qual.qual = network->stats.signal;
182 iwe.u.qual.level = network->stats.rssi;
183 iwe.u.qual.noise = network->stats.noise;
184 iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
185 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
186 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
187 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
188 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
189 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
190 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
191 iwe.u.qual.updated = 7;
ecdfa446 192 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN);
ecdfa446
GKH
193 iwe.cmd = IWEVCUSTOM;
194 p = custom;
195
196 iwe.u.data.length = p - custom;
197 if (iwe.u.data.length)
ecdfa446 198 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
ecdfa446
GKH
199#if (WIRELESS_EXT < 18)
200 if (ieee->wpa_enabled && network->wpa_ie_len){
201 char buf[MAX_WPA_IE_LEN * 2 + 30];
ecdfa446
GKH
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);
ecdfa446 211 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
ecdfa446
GKH
212 }
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);
ecdfa446 226 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
ecdfa446
GKH
227 }
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;
ecdfa446 236 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
ecdfa446
GKH
237 }
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;
ecdfa446 245 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
ecdfa446
GKH
246 }
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)
ecdfa446 258 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
ecdfa446
GKH
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",
ecdfa446
GKH
294 escape_essid(network->ssid,
295 network->ssid_len),
0ee9f67c 296 network->bssid,
ecdfa446
GKH
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 */
7a6cb0d5 383 new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
ecdfa446
GKH
384 GFP_KERNEL);
385 if (new_crypt == NULL)
386 return -ENOMEM;
ecdfa446 387 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
a010a337 388 if (!new_crypt->ops)
ecdfa446 389 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
a010a337 390 if (new_crypt->ops)
ecdfa446
GKH
391 new_crypt->priv = new_crypt->ops->init(key);
392
393 if (!new_crypt->ops || !new_crypt->priv) {
394 kfree(new_crypt);
395 new_crypt = NULL;
396
397 printk(KERN_WARNING "%s: could not initialize WEP: "
398 "load module ieee80211_crypt_wep\n",
399 dev->name);
400 return -EOPNOTSUPP;
401 }
402 *crypt = new_crypt;
403 }
404
405 /* If a new key was provided, set it up */
406 if (erq->length > 0) {
407 len = erq->length <= 5 ? 5 : 13;
408 memcpy(sec.keys[key], keybuf, erq->length);
409 if (len > erq->length)
410 memset(sec.keys[key] + erq->length, 0,
411 len - erq->length);
412 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
413 key, escape_essid(sec.keys[key], len),
414 erq->length, len);
415 sec.key_sizes[key] = len;
416 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
417 (*crypt)->priv);
418 sec.flags |= (1 << key);
419 /* This ensures a key will be activated if no key is
420 * explicitely set */
421 if (key == sec.active_key)
422 sec.flags |= SEC_ACTIVE_KEY;
423 ieee->tx_keyidx = key;
424
425 } else {
426 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
427 NULL, (*crypt)->priv);
428 if (len == 0) {
429 /* Set a default key of all 0 */
430 printk("Setting key %d to all zero.\n",
431 key);
432
433 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
434 key);
435 memset(sec.keys[key], 0, 13);
436 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
437 (*crypt)->priv);
438 sec.key_sizes[key] = 13;
439 sec.flags |= (1 << key);
440 }
441
442 /* No key data - just set the default TX key index */
443 if (key_provided) {
444 IEEE80211_DEBUG_WX(
445 "Setting key %d to default Tx key.\n", key);
446 ieee->tx_keyidx = key;
447 sec.active_key = key;
448 sec.flags |= SEC_ACTIVE_KEY;
449 }
450 }
451
452 done:
453 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
454 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
455 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
456 sec.flags |= SEC_AUTH_MODE;
457 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
458 "OPEN" : "SHARED KEY");
459
460 /* For now we just support WEP, so only set that security level...
461 * TODO: When WPA is added this is one place that needs to change */
462 sec.flags |= SEC_LEVEL;
463 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
464
465 if (ieee->set_security)
d1c580aa 466 ieee->set_security(ieee, &sec);
ecdfa446
GKH
467
468 /* Do not reset port if card is in Managed mode since resetting will
469 * generate new IEEE 802.11 authentication which may end up in looping
470 * with IEEE 802.1X. If your hardware requires a reset after WEP
471 * configuration (for example... Prism2), implement the reset_port in
472 * the callbacks structures used to initialize the 802.11 stack. */
473 if (ieee->reset_on_keychange &&
474 ieee->iw_mode != IW_MODE_INFRA &&
7c186cff 475 ieee->reset_port && ieee->reset_port(ieee)) {
ecdfa446
GKH
476 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
477 return -EINVAL;
478 }
479 return 0;
480}
481
482int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
483 struct iw_request_info *info,
484 union iwreq_data *wrqu, char *keybuf)
485{
486 struct iw_point *erq = &(wrqu->encoding);
487 int len, key;
488 struct ieee80211_crypt_data *crypt;
489
490 IEEE80211_DEBUG_WX("GET_ENCODE\n");
491
492 if(ieee->iw_mode == IW_MODE_MONITOR)
493 return -1;
494
495 key = erq->flags & IW_ENCODE_INDEX;
496 if (key) {
497 if (key > WEP_KEYS)
498 return -EINVAL;
499 key--;
500 } else
501 key = ieee->tx_keyidx;
502
503 crypt = ieee->crypt[key];
504 erq->flags = key + 1;
505
506 if (crypt == NULL || crypt->ops == NULL) {
507 erq->length = 0;
508 erq->flags |= IW_ENCODE_DISABLED;
509 return 0;
510 }
511#if 0
512 if (strcmp(crypt->ops->name, "WEP") != 0) {
513 /* only WEP is supported with wireless extensions, so just
514 * report that encryption is used */
515 erq->length = 0;
516 erq->flags |= IW_ENCODE_ENABLED;
517 return 0;
518 }
519#endif
520 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
521 erq->length = (len >= 0 ? len : 0);
522
523 erq->flags |= IW_ENCODE_ENABLED;
524
525 if (ieee->open_wep)
526 erq->flags |= IW_ENCODE_OPEN;
527 else
528 erq->flags |= IW_ENCODE_RESTRICTED;
529
530 return 0;
531}
532#if (WIRELESS_EXT >= 18)
533int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
534 struct iw_request_info *info,
535 union iwreq_data *wrqu, char *extra)
536{
537 int ret = 0;
ecdfa446
GKH
538 struct net_device *dev = ieee->dev;
539 struct iw_point *encoding = &wrqu->encoding;
540 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
541 int i, idx;
542 int group_key = 0;
a010a337 543 const char *alg;
ecdfa446
GKH
544 struct ieee80211_crypto_ops *ops;
545 struct ieee80211_crypt_data **crypt;
546
547 struct ieee80211_security sec = {
548 .flags = 0,
549 };
ecdfa446
GKH
550 idx = encoding->flags & IW_ENCODE_INDEX;
551 if (idx) {
552 if (idx < 1 || idx > WEP_KEYS)
553 return -EINVAL;
554 idx--;
555 } else
556 idx = ieee->tx_keyidx;
557
558 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
559
560 crypt = &ieee->crypt[idx];
561
562 group_key = 1;
563 } else {
564 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
ecdfa446
GKH
565 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
566 return -EINVAL;
567 if (ieee->iw_mode == IW_MODE_INFRA)
568
569 crypt = &ieee->crypt[idx];
570
571 else
572 return -EINVAL;
573 }
574
575 sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
576 if ((encoding->flags & IW_ENCODE_DISABLED) ||
577 ext->alg == IW_ENCODE_ALG_NONE) {
578 if (*crypt)
579 ieee80211_crypt_delayed_deinit(ieee, crypt);
580
581 for (i = 0; i < WEP_KEYS; i++)
582
583 if (ieee->crypt[i] != NULL)
584
585 break;
586
587 if (i == WEP_KEYS) {
588 sec.enabled = 0;
589 // sec.encrypt = 0;
590 sec.level = SEC_LEVEL_0;
591 sec.flags |= SEC_LEVEL;
592 }
ecdfa446
GKH
593 goto done;
594 }
595
596 sec.enabled = 1;
597 // sec.encrypt = 1;
598#if 0
599 if (group_key ? !ieee->host_mc_decrypt :
600 !(ieee->host_encrypt || ieee->host_decrypt ||
601 ieee->host_encrypt_msdu))
602 goto skip_host_crypt;
603#endif
604 switch (ext->alg) {
605 case IW_ENCODE_ALG_WEP:
606 alg = "WEP";
ecdfa446
GKH
607 break;
608 case IW_ENCODE_ALG_TKIP:
609 alg = "TKIP";
ecdfa446
GKH
610 break;
611 case IW_ENCODE_ALG_CCMP:
612 alg = "CCMP";
ecdfa446
GKH
613 break;
614 default:
615 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
616 dev->name, ext->alg);
617 ret = -EINVAL;
618 goto done;
619 }
620 printk("alg name:%s\n",alg);
621
622 ops = ieee80211_get_crypto_ops(alg);
a010a337 623 if (ops == NULL)
ecdfa446 624 ops = ieee80211_get_crypto_ops(alg);
ecdfa446
GKH
625 if (ops == NULL) {
626 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
627 dev->name, ext->alg);
628 printk("========>unknown crypto alg %d\n", ext->alg);
629 ret = -EINVAL;
630 goto done;
631 }
632
633 if (*crypt == NULL || (*crypt)->ops != ops) {
634 struct ieee80211_crypt_data *new_crypt;
635
636 ieee80211_crypt_delayed_deinit(ieee, crypt);
637
638#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
639 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
640#else
641 new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL);
642 memset(new_crypt,0,sizeof(*new_crypt));
643#endif
644 if (new_crypt == NULL) {
645 ret = -ENOMEM;
646 goto done;
647 }
648 new_crypt->ops = ops;
a010a337 649 if (new_crypt->ops)
ecdfa446
GKH
650 new_crypt->priv = new_crypt->ops->init(idx);
651 if (new_crypt->priv == NULL) {
652 kfree(new_crypt);
653 ret = -EINVAL;
654 goto done;
655 }
656 *crypt = new_crypt;
657
658 }
659
660 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
661 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
662 (*crypt)->priv) < 0) {
663 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
664 printk("key setting failed\n");
665 ret = -EINVAL;
666 goto done;
667 }
668#if 1
ecdfa446
GKH
669 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
670 ieee->tx_keyidx = idx;
671 sec.active_key = idx;
672 sec.flags |= SEC_ACTIVE_KEY;
673 }
674
675 if (ext->alg != IW_ENCODE_ALG_NONE) {
676 //memcpy(sec.keys[idx], ext->key, ext->key_len);
677 sec.key_sizes[idx] = ext->key_len;
678 sec.flags |= (1 << idx);
679 if (ext->alg == IW_ENCODE_ALG_WEP) {
680 // sec.encode_alg[idx] = SEC_ALG_WEP;
681 sec.flags |= SEC_LEVEL;
682 sec.level = SEC_LEVEL_1;
683 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
684 // sec.encode_alg[idx] = SEC_ALG_TKIP;
685 sec.flags |= SEC_LEVEL;
686 sec.level = SEC_LEVEL_2;
687 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
688 // sec.encode_alg[idx] = SEC_ALG_CCMP;
689 sec.flags |= SEC_LEVEL;
690 sec.level = SEC_LEVEL_3;
691 }
692 /* Don't set sec level for group keys. */
693 if (group_key)
694 sec.flags &= ~SEC_LEVEL;
695 }
696#endif
697done:
698 if (ieee->set_security)
d1c580aa 699 ieee->set_security(ieee, &sec);
ecdfa446
GKH
700
701 if (ieee->reset_on_keychange &&
702 ieee->iw_mode != IW_MODE_INFRA &&
7c186cff 703 ieee->reset_port && ieee->reset_port(ieee)) {
ecdfa446
GKH
704 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
705 return -EINVAL;
706 }
ecdfa446
GKH
707 return ret;
708}
709
710int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
711 struct iw_request_info *info,
712 union iwreq_data *wrqu, char *extra)
713{
714 struct iw_point *encoding = &wrqu->encoding;
715 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
716 struct ieee80211_crypt_data *crypt;
717 int idx, max_key_len;
718
719 max_key_len = encoding->length - sizeof(*ext);
720 if (max_key_len < 0)
721 return -EINVAL;
722
723 idx = encoding->flags & IW_ENCODE_INDEX;
724 if (idx) {
725 if (idx < 1 || idx > WEP_KEYS)
726 return -EINVAL;
727 idx--;
728 } else
729 idx = ieee->tx_keyidx;
730
3ef5a262 731 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
ecdfa446
GKH
732 ext->alg != IW_ENCODE_ALG_WEP)
733 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
734 return -EINVAL;
735
736 crypt = ieee->crypt[idx];
737 encoding->flags = idx + 1;
738 memset(ext, 0, sizeof(*ext));
739
740 if (crypt == NULL || crypt->ops == NULL ) {
741 ext->alg = IW_ENCODE_ALG_NONE;
742 ext->key_len = 0;
743 encoding->flags |= IW_ENCODE_DISABLED;
744 } else {
745 if (strcmp(crypt->ops->name, "WEP") == 0 )
746 ext->alg = IW_ENCODE_ALG_WEP;
747 else if (strcmp(crypt->ops->name, "TKIP"))
748 ext->alg = IW_ENCODE_ALG_TKIP;
749 else if (strcmp(crypt->ops->name, "CCMP"))
750 ext->alg = IW_ENCODE_ALG_CCMP;
751 else
752 return -EINVAL;
753 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
754 encoding->flags |= IW_ENCODE_ENABLED;
755 if (ext->key_len &&
756 (ext->alg == IW_ENCODE_ALG_TKIP ||
757 ext->alg == IW_ENCODE_ALG_CCMP))
758 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
759
760 }
761
762 return 0;
763}
764
765int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
766 struct iw_request_info *info,
767 union iwreq_data *wrqu, char *extra)
768{
ecdfa446
GKH
769 struct iw_mlme *mlme = (struct iw_mlme *) extra;
770 switch (mlme->cmd) {
771 case IW_MLME_DEAUTH:
772 case IW_MLME_DISASSOC:
773 ieee80211_disassociate(ieee);
774 break;
775 default:
776 return -EOPNOTSUPP;
777 }
ecdfa446
GKH
778 return 0;
779}
780
781int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
782 struct iw_request_info *info,
783 struct iw_param *data, char *extra)
784{
ecdfa446
GKH
785 switch (data->flags & IW_AUTH_INDEX) {
786 case IW_AUTH_WPA_VERSION:
787 /*need to support wpa2 here*/
ecdfa446
GKH
788 break;
789 case IW_AUTH_CIPHER_PAIRWISE:
790 case IW_AUTH_CIPHER_GROUP:
791 case IW_AUTH_KEY_MGMT:
792 /*
793 * * Host AP driver does not use these parameters and allows
794 * * wpa_supplicant to control them internally.
795 * */
796 break;
797 case IW_AUTH_TKIP_COUNTERMEASURES:
798 ieee->tkip_countermeasures = data->value;
799 break;
800 case IW_AUTH_DROP_UNENCRYPTED:
801 ieee->drop_unencrypted = data->value;
802 break;
803
804 case IW_AUTH_80211_AUTH_ALG:
ecdfa446
GKH
805 if(data->value & IW_AUTH_ALG_SHARED_KEY){
806 ieee->open_wep = 0;
807 ieee->auth_mode = 1;
808 }
809 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
810 ieee->open_wep = 1;
811 ieee->auth_mode = 0;
812 }
813 else if(data->value & IW_AUTH_ALG_LEAP){
814 ieee->open_wep = 1;
815 ieee->auth_mode = 2;
ecdfa446
GKH
816 }
817 else
818 return -EINVAL;
ecdfa446
GKH
819 break;
820
821#if 1
822 case IW_AUTH_WPA_ENABLED:
823 ieee->wpa_enabled = (data->value)?1:0;
ecdfa446
GKH
824 break;
825
826#endif
827 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
828 ieee->ieee802_1x = data->value;
829 break;
830 case IW_AUTH_PRIVACY_INVOKED:
831 ieee->privacy_invoked = data->value;
832 break;
833 default:
834 return -EOPNOTSUPP;
835 }
ecdfa446
GKH
836 return 0;
837}
838#endif
839#if 1
840int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
841{
ecdfa446
GKH
842 u8 *buf;
843
844 if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
845 {
ecdfa446
GKH
846 return -EINVAL;
847 }
848
849
850 if (len)
851 {
852 if (len != ie[1]+2)
853 {
3d8affc0 854 printk("len:%zu, ie:%d\n", len, ie[1]);
ecdfa446
GKH
855 return -EINVAL;
856 }
94002c07 857 buf = kmemdup(ie, len, GFP_KERNEL);
ecdfa446
GKH
858 if (buf == NULL)
859 return -ENOMEM;
ecdfa446
GKH
860 kfree(ieee->wpa_ie);
861 ieee->wpa_ie = buf;
862 ieee->wpa_ie_len = len;
863 }
864 else{
ecdfa446
GKH
865 kfree(ieee->wpa_ie);
866 ieee->wpa_ie = NULL;
867 ieee->wpa_ie_len = 0;
868 }
ecdfa446
GKH
869 return 0;
870
871}
872#endif