Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-btrfs-devel.git] / drivers / staging / rtl8192e / rtllib_wx.c
blob8cea4a60e1b3f64619f06beb0e37b04ab857c720
1 /******************************************************************************
3 Copyright(c) 2004 Intel Corporation. All rights reserved.
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>
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.
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.
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.
24 The full GNU General Public License is included in this distribution in the
25 file called LICENSE.
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
31 ******************************************************************************/
32 #include <linux/wireless.h>
33 #include <linux/version.h>
34 #include <linux/kmod.h>
35 #include <linux/module.h>
37 #include "rtllib.h"
38 struct modes_unit {
39 char *mode_string;
40 int mode_size;
42 static struct modes_unit rtllib_modes[] = {
43 {"a", 1},
44 {"b", 1},
45 {"g", 1},
46 {"?", 1},
47 {"N-24G", 5},
48 {"N-5G", 4},
51 #define MAX_CUSTOM_LEN 64
52 static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
53 char *start, char *stop,
54 struct rtllib_network *network,
55 struct iw_request_info *info)
57 char custom[MAX_CUSTOM_LEN];
58 char proto_name[IFNAMSIZ];
59 char *pname = proto_name;
60 char *p;
61 struct iw_event iwe;
62 int i, j;
63 u16 max_rate, rate;
64 static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
66 /* First entry *MUST* be the AP MAC address */
67 iwe.cmd = SIOCGIWAP;
68 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
69 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
70 start = iwe_stream_add_event_rsl(info, start, stop,
71 &iwe, IW_EV_ADDR_LEN);
72 /* Remaining entries will be displayed in the order we provide them */
74 /* Add the ESSID */
75 iwe.cmd = SIOCGIWESSID;
76 iwe.u.data.flags = 1;
77 if (network->ssid_len > 0) {
78 iwe.u.data.length = min(network->ssid_len, (u8)32);
79 start = iwe_stream_add_point_rsl(info, start, stop, &iwe,
80 network->ssid);
81 } else if (network->hidden_ssid_len == 0) {
82 iwe.u.data.length = sizeof("<hidden>");
83 start = iwe_stream_add_point_rsl(info, start, stop,
84 &iwe, "<hidden>");
85 } else {
86 iwe.u.data.length = min(network->hidden_ssid_len, (u8)32);
87 start = iwe_stream_add_point_rsl(info, start, stop, &iwe,
88 network->hidden_ssid);
90 /* Add the protocol name */
91 iwe.cmd = SIOCGIWNAME;
92 for (i = 0; i < (sizeof(rtllib_modes)/sizeof(rtllib_modes[0])); i++) {
93 if (network->mode&(1<<i)) {
94 sprintf(pname, rtllib_modes[i].mode_string,
95 rtllib_modes[i].mode_size);
96 pname += rtllib_modes[i].mode_size;
99 *pname = '\0';
100 snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
101 start = iwe_stream_add_event_rsl(info, start, stop,
102 &iwe, IW_EV_CHAR_LEN);
103 /* Add mode */
104 iwe.cmd = SIOCGIWMODE;
105 if (network->capability &
106 (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
107 if (network->capability & WLAN_CAPABILITY_ESS)
108 iwe.u.mode = IW_MODE_MASTER;
109 else
110 iwe.u.mode = IW_MODE_ADHOC;
111 start = iwe_stream_add_event_rsl(info, start, stop,
112 &iwe, IW_EV_UINT_LEN);
115 /* Add frequency/channel */
116 iwe.cmd = SIOCGIWFREQ;
117 /* iwe.u.freq.m = rtllib_frequency(network->channel, network->mode);
118 iwe.u.freq.e = 3; */
119 iwe.u.freq.m = network->channel;
120 iwe.u.freq.e = 0;
121 iwe.u.freq.i = 0;
122 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
123 IW_EV_FREQ_LEN);
125 /* Add encryption capability */
126 iwe.cmd = SIOCGIWENCODE;
127 if (network->capability & WLAN_CAPABILITY_PRIVACY)
128 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
129 else
130 iwe.u.data.flags = IW_ENCODE_DISABLED;
131 iwe.u.data.length = 0;
132 start = iwe_stream_add_point_rsl(info, start, stop,
133 &iwe, network->ssid);
134 /* Add basic and extended rates */
135 max_rate = 0;
136 p = custom;
137 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
138 for (i = 0, j = 0; i < network->rates_len;) {
139 if (j < network->rates_ex_len &&
140 ((network->rates_ex[j] & 0x7F) <
141 (network->rates[i] & 0x7F)))
142 rate = network->rates_ex[j++] & 0x7F;
143 else
144 rate = network->rates[i++] & 0x7F;
145 if (rate > max_rate)
146 max_rate = rate;
147 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
148 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
150 for (; j < network->rates_ex_len; j++) {
151 rate = network->rates_ex[j] & 0x7F;
152 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
153 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
154 if (rate > max_rate)
155 max_rate = rate;
158 if (network->mode >= IEEE_N_24G) {
159 struct ht_capab_ele *ht_cap = NULL;
160 bool is40M = false, isShortGI = false;
161 u8 max_mcs = 0;
162 if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
163 ht_cap = (struct ht_capab_ele *)
164 &network->bssht.bdHTCapBuf[4];
165 else
166 ht_cap = (struct ht_capab_ele *)
167 &network->bssht.bdHTCapBuf[0];
168 is40M = (ht_cap->ChlWidth) ? 1 : 0;
169 isShortGI = (ht_cap->ChlWidth) ?
170 ((ht_cap->ShortGI40Mhz) ? 1 : 0) :
171 ((ht_cap->ShortGI20Mhz) ? 1 : 0);
173 max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS,
174 MCS_FILTER_ALL);
175 rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f];
176 if (rate > max_rate)
177 max_rate = rate;
179 iwe.cmd = SIOCGIWRATE;
180 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
181 iwe.u.bitrate.value = max_rate * 500000;
182 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
183 IW_EV_PARAM_LEN);
184 iwe.cmd = IWEVCUSTOM;
185 iwe.u.data.length = p - custom;
186 if (iwe.u.data.length)
187 start = iwe_stream_add_point_rsl(info, start, stop,
188 &iwe, custom);
189 /* Add quality statistics */
190 /* TODO: Fix these values... */
191 iwe.cmd = IWEVQUAL;
192 iwe.u.qual.qual = network->stats.signal;
193 iwe.u.qual.level = network->stats.rssi;
194 iwe.u.qual.noise = network->stats.noise;
195 iwe.u.qual.updated = network->stats.mask & RTLLIB_STATMASK_WEMASK;
196 if (!(network->stats.mask & RTLLIB_STATMASK_RSSI))
197 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
198 if (!(network->stats.mask & RTLLIB_STATMASK_NOISE))
199 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
200 if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL))
201 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
202 iwe.u.qual.updated = 7;
203 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
204 IW_EV_QUAL_LEN);
206 iwe.cmd = IWEVCUSTOM;
207 p = custom;
208 iwe.u.data.length = p - custom;
209 if (iwe.u.data.length)
210 start = iwe_stream_add_point_rsl(info, start, stop,
211 &iwe, custom);
213 memset(&iwe, 0, sizeof(iwe));
214 if (network->wpa_ie_len) {
215 char buf[MAX_WPA_IE_LEN];
216 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
217 iwe.cmd = IWEVGENIE;
218 iwe.u.data.length = network->wpa_ie_len;
219 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
221 memset(&iwe, 0, sizeof(iwe));
222 if (network->rsn_ie_len) {
223 char buf[MAX_WPA_IE_LEN];
224 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
225 iwe.cmd = IWEVGENIE;
226 iwe.u.data.length = network->rsn_ie_len;
227 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
230 /* add info for WZC */
231 memset(&iwe, 0, sizeof(iwe));
232 if (network->wzc_ie_len) {
233 char buf[MAX_WZC_IE_LEN];
234 memcpy(buf, network->wzc_ie, network->wzc_ie_len);
235 iwe.cmd = IWEVGENIE;
236 iwe.u.data.length = network->wzc_ie_len;
237 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
240 /* Add EXTRA: Age to display seconds since last beacon/probe response
241 * for given network. */
242 iwe.cmd = IWEVCUSTOM;
243 p = custom;
244 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
245 " Last beacon: %lums ago",
246 (jiffies - network->last_scanned) / (HZ / 100));
247 iwe.u.data.length = p - custom;
248 if (iwe.u.data.length)
249 start = iwe_stream_add_point_rsl(info, start, stop,
250 &iwe, custom);
252 return start;
255 int rtllib_wx_get_scan(struct rtllib_device *ieee,
256 struct iw_request_info *info,
257 union iwreq_data *wrqu, char *extra)
259 struct rtllib_network *network;
260 unsigned long flags;
262 char *ev = extra;
263 char *stop = ev + wrqu->data.length;
264 int i = 0;
265 int err = 0;
266 RTLLIB_DEBUG_WX("Getting scan\n");
267 down(&ieee->wx_sem);
268 spin_lock_irqsave(&ieee->lock, flags);
270 list_for_each_entry(network, &ieee->network_list, list) {
271 i++;
272 if ((stop - ev) < 200) {
273 err = -E2BIG;
274 break;
276 if (ieee->scan_age == 0 ||
277 time_after(network->last_scanned + ieee->scan_age, jiffies))
278 ev = rtl819x_translate_scan(ieee, ev, stop, network,
279 info);
280 else
281 RTLLIB_DEBUG_SCAN("Not showing network '%s ("
282 " %pM)' due to age (%lums).\n",
283 escape_essid(network->ssid,
284 network->ssid_len),
285 network->bssid,
286 (jiffies - network->last_scanned) / (HZ / 100));
289 spin_unlock_irqrestore(&ieee->lock, flags);
290 up(&ieee->wx_sem);
291 wrqu->data.length = ev - extra;
292 wrqu->data.flags = 0;
294 RTLLIB_DEBUG_WX("exit: %d networks returned.\n", i);
296 return err;
299 int rtllib_wx_set_encode(struct rtllib_device *ieee,
300 struct iw_request_info *info,
301 union iwreq_data *wrqu, char *keybuf)
303 struct iw_point *erq = &(wrqu->encoding);
304 struct net_device *dev = ieee->dev;
305 struct rtllib_security sec = {
306 .flags = 0
308 int i, key, key_provided, len;
309 struct rtllib_crypt_data **crypt;
311 RTLLIB_DEBUG_WX("SET_ENCODE\n");
313 key = erq->flags & IW_ENCODE_INDEX;
314 if (key) {
315 if (key > WEP_KEYS)
316 return -EINVAL;
317 key--;
318 key_provided = 1;
319 } else {
320 key_provided = 0;
321 key = ieee->tx_keyidx;
324 RTLLIB_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
325 "provided" : "default");
326 crypt = &ieee->crypt[key];
327 if (erq->flags & IW_ENCODE_DISABLED) {
328 if (key_provided && *crypt) {
329 RTLLIB_DEBUG_WX("Disabling encryption on key %d.\n",
330 key);
331 rtllib_crypt_delayed_deinit(ieee, crypt);
332 } else
333 RTLLIB_DEBUG_WX("Disabling encryption.\n");
335 /* Check all the keys to see if any are still configured,
336 * and if no key index was provided, de-init them all */
337 for (i = 0; i < WEP_KEYS; i++) {
338 if (ieee->crypt[i] != NULL) {
339 if (key_provided)
340 break;
341 rtllib_crypt_delayed_deinit(ieee,
342 &ieee->crypt[i]);
346 if (i == WEP_KEYS) {
347 sec.enabled = 0;
348 sec.level = SEC_LEVEL_0;
349 sec.flags |= SEC_ENABLED | SEC_LEVEL;
352 goto done;
357 sec.enabled = 1;
358 sec.flags |= SEC_ENABLED;
360 if (*crypt != NULL && (*crypt)->ops != NULL &&
361 strcmp((*crypt)->ops->name, "WEP") != 0) {
362 /* changing to use WEP; deinit previously used algorithm
363 * on this key */
364 rtllib_crypt_delayed_deinit(ieee, crypt);
367 if (*crypt == NULL) {
368 struct rtllib_crypt_data *new_crypt;
370 /* take WEP into use */
371 new_crypt = kmalloc(sizeof(struct rtllib_crypt_data),
372 GFP_KERNEL);
373 if (new_crypt == NULL)
374 return -ENOMEM;
375 memset(new_crypt, 0, sizeof(struct rtllib_crypt_data));
376 new_crypt->ops = rtllib_get_crypto_ops("WEP");
377 if (!new_crypt->ops) {
378 request_module("rtllib_crypt_wep");
379 new_crypt->ops = rtllib_get_crypto_ops("WEP");
382 if (new_crypt->ops)
383 new_crypt->priv = new_crypt->ops->init(key);
385 if (!new_crypt->ops || !new_crypt->priv) {
386 kfree(new_crypt);
387 new_crypt = NULL;
389 printk(KERN_WARNING "%s: could not initialize WEP: "
390 "load module rtllib_crypt_wep\n",
391 dev->name);
392 return -EOPNOTSUPP;
394 *crypt = new_crypt;
397 /* If a new key was provided, set it up */
398 if (erq->length > 0) {
399 len = erq->length <= 5 ? 5 : 13;
400 memcpy(sec.keys[key], keybuf, erq->length);
401 if (len > erq->length)
402 memset(sec.keys[key] + erq->length, 0,
403 len - erq->length);
404 RTLLIB_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
405 key, escape_essid(sec.keys[key], len),
406 erq->length, len);
407 sec.key_sizes[key] = len;
408 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
409 (*crypt)->priv);
410 sec.flags |= (1 << key);
411 /* This ensures a key will be activated if no key is
412 * explicitely set */
413 if (key == sec.active_key)
414 sec.flags |= SEC_ACTIVE_KEY;
415 ieee->tx_keyidx = key;
417 } else {
418 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
419 NULL, (*crypt)->priv);
420 if (len == 0) {
421 /* Set a default key of all 0 */
422 printk(KERN_INFO "Setting key %d to all zero.\n",
423 key);
425 RTLLIB_DEBUG_WX("Setting key %d to all zero.\n",
426 key);
427 memset(sec.keys[key], 0, 13);
428 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
429 (*crypt)->priv);
430 sec.key_sizes[key] = 13;
431 sec.flags |= (1 << key);
434 /* No key data - just set the default TX key index */
435 if (key_provided) {
436 RTLLIB_DEBUG_WX(
437 "Setting key %d to default Tx key.\n", key);
438 ieee->tx_keyidx = key;
439 sec.active_key = key;
440 sec.flags |= SEC_ACTIVE_KEY;
443 done:
444 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
445 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
446 WLAN_AUTH_SHARED_KEY;
447 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
448 sec.flags |= SEC_AUTH_MODE;
449 RTLLIB_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
450 "OPEN" : "SHARED KEY");
452 /* For now we just support WEP, so only set that security level...
453 * TODO: When WPA is added this is one place that needs to change */
454 sec.flags |= SEC_LEVEL;
455 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
457 if (ieee->set_security)
458 ieee->set_security(dev, &sec);
460 /* Do not reset port if card is in Managed mode since resetting will
461 * generate new IEEE 802.11 authentication which may end up in looping
462 * with IEEE 802.1X. If your hardware requires a reset after WEP
463 * configuration (for example... Prism2), implement the reset_port in
464 * the callbacks structures used to initialize the 802.11 stack. */
465 if (ieee->reset_on_keychange &&
466 ieee->iw_mode != IW_MODE_INFRA &&
467 ieee->reset_port && ieee->reset_port(dev)) {
468 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
469 return -EINVAL;
471 return 0;
474 int rtllib_wx_get_encode(struct rtllib_device *ieee,
475 struct iw_request_info *info,
476 union iwreq_data *wrqu, char *keybuf)
478 struct iw_point *erq = &(wrqu->encoding);
479 int len, key;
480 struct rtllib_crypt_data *crypt;
482 RTLLIB_DEBUG_WX("GET_ENCODE\n");
484 if (ieee->iw_mode == IW_MODE_MONITOR)
485 return -1;
487 key = erq->flags & IW_ENCODE_INDEX;
488 if (key) {
489 if (key > WEP_KEYS)
490 return -EINVAL;
491 key--;
492 } else {
493 key = ieee->tx_keyidx;
495 crypt = ieee->crypt[key];
497 erq->flags = key + 1;
499 if (crypt == NULL || crypt->ops == NULL) {
500 erq->length = 0;
501 erq->flags |= IW_ENCODE_DISABLED;
502 return 0;
504 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
505 erq->length = (len >= 0 ? len : 0);
507 erq->flags |= IW_ENCODE_ENABLED;
509 if (ieee->open_wep)
510 erq->flags |= IW_ENCODE_OPEN;
511 else
512 erq->flags |= IW_ENCODE_RESTRICTED;
514 return 0;
517 int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
518 struct iw_request_info *info,
519 union iwreq_data *wrqu, char *extra)
521 int ret = 0;
522 struct net_device *dev = ieee->dev;
523 struct iw_point *encoding = &wrqu->encoding;
524 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
525 int i, idx;
526 int group_key = 0;
527 const char *alg, *module;
528 struct rtllib_crypto_ops *ops;
529 struct rtllib_crypt_data **crypt;
531 struct rtllib_security sec = {
532 .flags = 0,
534 idx = encoding->flags & IW_ENCODE_INDEX;
535 if (idx) {
536 if (idx < 1 || idx > WEP_KEYS)
537 return -EINVAL;
538 idx--;
539 } else{
540 idx = ieee->tx_keyidx;
542 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
543 crypt = &ieee->crypt[idx];
544 group_key = 1;
545 } else {
546 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
547 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
548 return -EINVAL;
549 if (ieee->iw_mode == IW_MODE_INFRA)
550 crypt = &ieee->crypt[idx];
551 else
552 return -EINVAL;
555 sec.flags |= SEC_ENABLED;
556 if ((encoding->flags & IW_ENCODE_DISABLED) ||
557 ext->alg == IW_ENCODE_ALG_NONE) {
558 if (*crypt)
559 rtllib_crypt_delayed_deinit(ieee, crypt);
561 for (i = 0; i < WEP_KEYS; i++) {
562 if (ieee->crypt[i] != NULL)
563 break;
565 if (i == WEP_KEYS) {
566 sec.enabled = 0;
567 sec.level = SEC_LEVEL_0;
568 sec.flags |= SEC_LEVEL;
570 goto done;
573 sec.enabled = 1;
574 switch (ext->alg) {
575 case IW_ENCODE_ALG_WEP:
576 alg = "WEP";
577 module = "rtllib_crypt_wep";
578 break;
579 case IW_ENCODE_ALG_TKIP:
580 alg = "TKIP";
581 module = "rtllib_crypt_tkip";
582 break;
583 case IW_ENCODE_ALG_CCMP:
584 alg = "CCMP";
585 module = "rtllib_crypt_ccmp";
586 break;
587 default:
588 RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
589 dev->name, ext->alg);
590 ret = -EINVAL;
591 goto done;
593 printk(KERN_INFO "alg name:%s\n", alg);
595 ops = rtllib_get_crypto_ops(alg);
596 if (ops == NULL) {
597 char tempbuf[100];
599 memset(tempbuf, 0x00, 100);
600 sprintf(tempbuf, "%s", module);
601 request_module("%s", tempbuf);
602 ops = rtllib_get_crypto_ops(alg);
604 if (ops == NULL) {
605 RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
606 dev->name, ext->alg);
607 printk(KERN_INFO "========>unknown crypto alg %d\n", ext->alg);
608 ret = -EINVAL;
609 goto done;
612 if (*crypt == NULL || (*crypt)->ops != ops) {
613 struct rtllib_crypt_data *new_crypt;
615 rtllib_crypt_delayed_deinit(ieee, crypt);
617 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
618 if (new_crypt == NULL) {
619 ret = -ENOMEM;
620 goto done;
622 new_crypt->ops = ops;
623 if (new_crypt->ops)
624 new_crypt->priv = new_crypt->ops->init(idx);
626 if (new_crypt->priv == NULL) {
627 kfree(new_crypt);
628 ret = -EINVAL;
629 goto done;
631 *crypt = new_crypt;
635 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
636 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
637 (*crypt)->priv) < 0) {
638 RTLLIB_DEBUG_WX("%s: key setting failed\n", dev->name);
639 printk(KERN_INFO "key setting failed\n");
640 ret = -EINVAL;
641 goto done;
643 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
644 ieee->tx_keyidx = idx;
645 sec.active_key = idx;
646 sec.flags |= SEC_ACTIVE_KEY;
648 if (ext->alg != IW_ENCODE_ALG_NONE) {
649 sec.key_sizes[idx] = ext->key_len;
650 sec.flags |= (1 << idx);
651 if (ext->alg == IW_ENCODE_ALG_WEP) {
652 sec.flags |= SEC_LEVEL;
653 sec.level = SEC_LEVEL_1;
654 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
655 sec.flags |= SEC_LEVEL;
656 sec.level = SEC_LEVEL_2;
657 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
658 sec.flags |= SEC_LEVEL;
659 sec.level = SEC_LEVEL_3;
661 /* Don't set sec level for group keys. */
662 if (group_key)
663 sec.flags &= ~SEC_LEVEL;
665 done:
666 if (ieee->set_security)
667 ieee->set_security(ieee->dev, &sec);
669 if (ieee->reset_on_keychange &&
670 ieee->iw_mode != IW_MODE_INFRA &&
671 ieee->reset_port && ieee->reset_port(dev)) {
672 RTLLIB_DEBUG_WX("%s: reset_port failed\n", dev->name);
673 return -EINVAL;
675 return ret;
678 int rtllib_wx_get_encode_ext(struct rtllib_device *ieee,
679 struct iw_request_info *info,
680 union iwreq_data *wrqu, char *extra)
682 struct iw_point *encoding = &wrqu->encoding;
683 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
684 struct rtllib_crypt_data *crypt;
685 int idx, max_key_len;
687 max_key_len = encoding->length - sizeof(*ext);
688 if (max_key_len < 0)
689 return -EINVAL;
691 idx = encoding->flags & IW_ENCODE_INDEX;
692 if (idx) {
693 if (idx < 1 || idx > WEP_KEYS)
694 return -EINVAL;
695 idx--;
696 } else {
697 idx = ieee->tx_keyidx;
699 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
700 (ext->alg != IW_ENCODE_ALG_WEP))
701 if (idx != 0 || (ieee->iw_mode != IW_MODE_INFRA))
702 return -EINVAL;
704 crypt = ieee->crypt[idx];
706 encoding->flags = idx + 1;
707 memset(ext, 0, sizeof(*ext));
709 if (crypt == NULL || crypt->ops == NULL) {
710 ext->alg = IW_ENCODE_ALG_NONE;
711 ext->key_len = 0;
712 encoding->flags |= IW_ENCODE_DISABLED;
713 } else {
714 if (strcmp(crypt->ops->name, "WEP") == 0)
715 ext->alg = IW_ENCODE_ALG_WEP;
716 else if (strcmp(crypt->ops->name, "TKIP"))
717 ext->alg = IW_ENCODE_ALG_TKIP;
718 else if (strcmp(crypt->ops->name, "CCMP"))
719 ext->alg = IW_ENCODE_ALG_CCMP;
720 else
721 return -EINVAL;
722 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN,
723 NULL, crypt->priv);
724 encoding->flags |= IW_ENCODE_ENABLED;
725 if (ext->key_len &&
726 (ext->alg == IW_ENCODE_ALG_TKIP ||
727 ext->alg == IW_ENCODE_ALG_CCMP))
728 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
732 return 0;
735 int rtllib_wx_set_mlme(struct rtllib_device *ieee,
736 struct iw_request_info *info,
737 union iwreq_data *wrqu, char *extra)
739 u8 i = 0;
740 bool deauth = false;
741 struct iw_mlme *mlme = (struct iw_mlme *) extra;
743 if (ieee->state != RTLLIB_LINKED)
744 return -ENOLINK;
746 down(&ieee->wx_sem);
748 switch (mlme->cmd) {
749 case IW_MLME_DEAUTH:
750 deauth = true;
751 /* leave break out intentionly */
753 case IW_MLME_DISASSOC:
754 if (deauth == true)
755 printk(KERN_INFO "disauth packet !\n");
756 else
757 printk(KERN_INFO "dis associate packet!\n");
759 ieee->cannot_notify = true;
761 SendDisassociation(ieee, deauth, mlme->reason_code);
762 rtllib_disassociate(ieee);
764 ieee->wap_set = 0;
765 for (i = 0; i < 6; i++)
766 ieee->current_network.bssid[i] = 0x55;
768 ieee->ssid_set = 0;
769 ieee->current_network.ssid[0] = '\0';
770 ieee->current_network.ssid_len = 0;
771 break;
772 default:
773 up(&ieee->wx_sem);
774 return -EOPNOTSUPP;
777 up(&ieee->wx_sem);
779 return 0;
782 int rtllib_wx_set_auth(struct rtllib_device *ieee,
783 struct iw_request_info *info,
784 struct iw_param *data, char *extra)
786 switch (data->flags & IW_AUTH_INDEX) {
787 case IW_AUTH_WPA_VERSION:
788 break;
789 case IW_AUTH_CIPHER_PAIRWISE:
790 case IW_AUTH_CIPHER_GROUP:
791 case IW_AUTH_KEY_MGMT:
793 * Host AP driver does not use these parameters and allows
794 * wpa_supplicant to control them internally.
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;
804 case IW_AUTH_80211_AUTH_ALG:
805 if (data->value & IW_AUTH_ALG_SHARED_KEY) {
806 ieee->open_wep = 0;
807 ieee->auth_mode = 1;
808 } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) {
809 ieee->open_wep = 1;
810 ieee->auth_mode = 0;
811 } else if (data->value & IW_AUTH_ALG_LEAP) {
812 ieee->open_wep = 1;
813 ieee->auth_mode = 2;
814 } else
815 return -EINVAL;
816 break;
818 case IW_AUTH_WPA_ENABLED:
819 ieee->wpa_enabled = (data->value) ? 1 : 0;
820 break;
822 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
823 ieee->ieee802_1x = data->value;
824 break;
825 case IW_AUTH_PRIVACY_INVOKED:
826 ieee->privacy_invoked = data->value;
827 break;
828 default:
829 return -EOPNOTSUPP;
831 return 0;
834 int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
836 u8 *buf;
837 u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
839 if (len > MAX_WPA_IE_LEN || (len && ie == NULL))
840 return -EINVAL;
842 if (len) {
843 eid = ie[0];
844 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2],
845 wps_oui, 4))) {
847 ieee->wps_ie_len = (len < MAX_WZC_IE_LEN) ? (len) :
848 (MAX_WZC_IE_LEN);
849 buf = kmalloc(ieee->wps_ie_len, GFP_KERNEL);
850 if (buf == NULL)
851 return -ENOMEM;
852 memcpy(buf, ie, ieee->wps_ie_len);
853 ieee->wps_ie = buf;
854 return 0;
857 ieee->wps_ie_len = 0;
858 kfree(ieee->wps_ie);
859 ieee->wps_ie = NULL;
860 if (len) {
861 if (len != ie[1]+2)
862 return -EINVAL;
863 buf = kmalloc(len, GFP_KERNEL);
864 if (buf == NULL)
865 return -ENOMEM;
866 memcpy(buf, ie, len);
867 kfree(ieee->wpa_ie);
868 ieee->wpa_ie = buf;
869 ieee->wpa_ie_len = len;
870 } else {
871 kfree(ieee->wpa_ie);
872 ieee->wpa_ie = NULL;
873 ieee->wpa_ie_len = 0;
875 return 0;