Merge tag 'v3.3.7' into 3.3/master
[zen-stable.git] / drivers / staging / rtl8192e / rtllib_wx.c
blobc27ff7edbaf285d9b1d3889c82428db189009100
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/kmod.h>
34 #include <linux/module.h>
36 #include "rtllib.h"
37 struct modes_unit {
38 char *mode_string;
39 int mode_size;
41 static struct modes_unit rtllib_modes[] = {
42 {"a", 1},
43 {"b", 1},
44 {"g", 1},
45 {"?", 1},
46 {"N-24G", 5},
47 {"N-5G", 4},
50 #define MAX_CUSTOM_LEN 64
51 static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
52 char *start, char *stop,
53 struct rtllib_network *network,
54 struct iw_request_info *info)
56 char custom[MAX_CUSTOM_LEN];
57 char proto_name[IFNAMSIZ];
58 char *pname = proto_name;
59 char *p;
60 struct iw_event iwe;
61 int i, j;
62 u16 max_rate, rate;
63 static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
65 /* First entry *MUST* be the AP MAC address */
66 iwe.cmd = SIOCGIWAP;
67 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
68 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
69 start = iwe_stream_add_event_rsl(info, start, stop,
70 &iwe, IW_EV_ADDR_LEN);
71 /* Remaining entries will be displayed in the order we provide them */
73 /* Add the ESSID */
74 iwe.cmd = SIOCGIWESSID;
75 iwe.u.data.flags = 1;
76 if (network->ssid_len > 0) {
77 iwe.u.data.length = min(network->ssid_len, (u8)32);
78 start = iwe_stream_add_point_rsl(info, start, stop, &iwe,
79 network->ssid);
80 } else if (network->hidden_ssid_len == 0) {
81 iwe.u.data.length = sizeof("<hidden>");
82 start = iwe_stream_add_point_rsl(info, start, stop,
83 &iwe, "<hidden>");
84 } else {
85 iwe.u.data.length = min(network->hidden_ssid_len, (u8)32);
86 start = iwe_stream_add_point_rsl(info, start, stop, &iwe,
87 network->hidden_ssid);
89 /* Add the protocol name */
90 iwe.cmd = SIOCGIWNAME;
91 for (i = 0; i < (sizeof(rtllib_modes)/sizeof(rtllib_modes[0])); i++) {
92 if (network->mode&(1<<i)) {
93 sprintf(pname, rtllib_modes[i].mode_string,
94 rtllib_modes[i].mode_size);
95 pname += rtllib_modes[i].mode_size;
98 *pname = '\0';
99 snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
100 start = iwe_stream_add_event_rsl(info, start, stop,
101 &iwe, IW_EV_CHAR_LEN);
102 /* Add mode */
103 iwe.cmd = SIOCGIWMODE;
104 if (network->capability &
105 (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
106 if (network->capability & WLAN_CAPABILITY_ESS)
107 iwe.u.mode = IW_MODE_MASTER;
108 else
109 iwe.u.mode = IW_MODE_ADHOC;
110 start = iwe_stream_add_event_rsl(info, start, stop,
111 &iwe, IW_EV_UINT_LEN);
114 /* Add frequency/channel */
115 iwe.cmd = SIOCGIWFREQ;
116 /* iwe.u.freq.m = rtllib_frequency(network->channel, network->mode);
117 iwe.u.freq.e = 3; */
118 iwe.u.freq.m = network->channel;
119 iwe.u.freq.e = 0;
120 iwe.u.freq.i = 0;
121 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
122 IW_EV_FREQ_LEN);
124 /* Add encryption capability */
125 iwe.cmd = SIOCGIWENCODE;
126 if (network->capability & WLAN_CAPABILITY_PRIVACY)
127 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
128 else
129 iwe.u.data.flags = IW_ENCODE_DISABLED;
130 iwe.u.data.length = 0;
131 start = iwe_stream_add_point_rsl(info, start, stop,
132 &iwe, network->ssid);
133 /* Add basic and extended rates */
134 max_rate = 0;
135 p = custom;
136 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
137 for (i = 0, j = 0; i < network->rates_len;) {
138 if (j < network->rates_ex_len &&
139 ((network->rates_ex[j] & 0x7F) <
140 (network->rates[i] & 0x7F)))
141 rate = network->rates_ex[j++] & 0x7F;
142 else
143 rate = network->rates[i++] & 0x7F;
144 if (rate > max_rate)
145 max_rate = rate;
146 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
147 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
149 for (; j < network->rates_ex_len; j++) {
150 rate = network->rates_ex[j] & 0x7F;
151 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
152 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
153 if (rate > max_rate)
154 max_rate = rate;
157 if (network->mode >= IEEE_N_24G) {
158 struct ht_capab_ele *ht_cap = NULL;
159 bool is40M = false, isShortGI = false;
160 u8 max_mcs = 0;
161 if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
162 ht_cap = (struct ht_capab_ele *)
163 &network->bssht.bdHTCapBuf[4];
164 else
165 ht_cap = (struct ht_capab_ele *)
166 &network->bssht.bdHTCapBuf[0];
167 is40M = (ht_cap->ChlWidth) ? 1 : 0;
168 isShortGI = (ht_cap->ChlWidth) ?
169 ((ht_cap->ShortGI40Mhz) ? 1 : 0) :
170 ((ht_cap->ShortGI20Mhz) ? 1 : 0);
172 max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS,
173 MCS_FILTER_ALL);
174 rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f];
175 if (rate > max_rate)
176 max_rate = rate;
178 iwe.cmd = SIOCGIWRATE;
179 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
180 iwe.u.bitrate.value = max_rate * 500000;
181 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
182 IW_EV_PARAM_LEN);
183 iwe.cmd = IWEVCUSTOM;
184 iwe.u.data.length = p - custom;
185 if (iwe.u.data.length)
186 start = iwe_stream_add_point_rsl(info, start, stop,
187 &iwe, custom);
188 /* Add quality statistics */
189 /* TODO: Fix these values... */
190 iwe.cmd = IWEVQUAL;
191 iwe.u.qual.qual = network->stats.signal;
192 iwe.u.qual.level = network->stats.rssi;
193 iwe.u.qual.noise = network->stats.noise;
194 iwe.u.qual.updated = network->stats.mask & RTLLIB_STATMASK_WEMASK;
195 if (!(network->stats.mask & RTLLIB_STATMASK_RSSI))
196 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
197 if (!(network->stats.mask & RTLLIB_STATMASK_NOISE))
198 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
199 if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL))
200 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
201 iwe.u.qual.updated = 7;
202 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
203 IW_EV_QUAL_LEN);
205 iwe.cmd = IWEVCUSTOM;
206 p = custom;
207 iwe.u.data.length = p - custom;
208 if (iwe.u.data.length)
209 start = iwe_stream_add_point_rsl(info, start, stop,
210 &iwe, custom);
212 memset(&iwe, 0, sizeof(iwe));
213 if (network->wpa_ie_len) {
214 char buf[MAX_WPA_IE_LEN];
215 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
216 iwe.cmd = IWEVGENIE;
217 iwe.u.data.length = network->wpa_ie_len;
218 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
220 memset(&iwe, 0, sizeof(iwe));
221 if (network->rsn_ie_len) {
222 char buf[MAX_WPA_IE_LEN];
223 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
224 iwe.cmd = IWEVGENIE;
225 iwe.u.data.length = network->rsn_ie_len;
226 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
229 /* add info for WZC */
230 memset(&iwe, 0, sizeof(iwe));
231 if (network->wzc_ie_len) {
232 char buf[MAX_WZC_IE_LEN];
233 memcpy(buf, network->wzc_ie, network->wzc_ie_len);
234 iwe.cmd = IWEVGENIE;
235 iwe.u.data.length = network->wzc_ie_len;
236 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
239 /* Add EXTRA: Age to display seconds since last beacon/probe response
240 * for given network. */
241 iwe.cmd = IWEVCUSTOM;
242 p = custom;
243 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
244 " Last beacon: %lums ago",
245 (jiffies - network->last_scanned) / (HZ / 100));
246 iwe.u.data.length = p - custom;
247 if (iwe.u.data.length)
248 start = iwe_stream_add_point_rsl(info, start, stop,
249 &iwe, custom);
251 return start;
254 int rtllib_wx_get_scan(struct rtllib_device *ieee,
255 struct iw_request_info *info,
256 union iwreq_data *wrqu, char *extra)
258 struct rtllib_network *network;
259 unsigned long flags;
261 char *ev = extra;
262 char *stop = ev + wrqu->data.length;
263 int i = 0;
264 int err = 0;
265 RTLLIB_DEBUG_WX("Getting scan\n");
266 down(&ieee->wx_sem);
267 spin_lock_irqsave(&ieee->lock, flags);
269 list_for_each_entry(network, &ieee->network_list, list) {
270 i++;
271 if ((stop - ev) < 200) {
272 err = -E2BIG;
273 break;
275 if (ieee->scan_age == 0 ||
276 time_after(network->last_scanned + ieee->scan_age, jiffies))
277 ev = rtl819x_translate_scan(ieee, ev, stop, network,
278 info);
279 else
280 RTLLIB_DEBUG_SCAN("Not showing network '%s ("
281 " %pM)' due to age (%lums).\n",
282 escape_essid(network->ssid,
283 network->ssid_len),
284 network->bssid,
285 (jiffies - network->last_scanned) / (HZ / 100));
288 spin_unlock_irqrestore(&ieee->lock, flags);
289 up(&ieee->wx_sem);
290 wrqu->data.length = ev - extra;
291 wrqu->data.flags = 0;
293 RTLLIB_DEBUG_WX("exit: %d networks returned.\n", i);
295 return err;
297 EXPORT_SYMBOL(rtllib_wx_get_scan);
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 lib80211_crypt_data **crypt;
311 RTLLIB_DEBUG_WX("SET_ENCODE\n");
313 key = erq->flags & IW_ENCODE_INDEX;
314 if (key) {
315 if (key > NUM_WEP_KEYS)
316 return -EINVAL;
317 key--;
318 key_provided = 1;
319 } else {
320 key_provided = 0;
321 key = ieee->crypt_info.tx_keyidx;
324 RTLLIB_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
325 "provided" : "default");
326 crypt = &ieee->crypt_info.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 lib80211_crypt_delayed_deinit(&ieee->crypt_info, 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 < NUM_WEP_KEYS; i++) {
338 if (ieee->crypt_info.crypt[i] != NULL) {
339 if (key_provided)
340 break;
341 lib80211_crypt_delayed_deinit(&ieee->crypt_info,
342 &ieee->crypt_info.crypt[i]);
346 if (i == NUM_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, "R-WEP") != 0) {
362 /* changing to use WEP; deinit previously used algorithm
363 * on this key */
364 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
367 if (*crypt == NULL) {
368 struct lib80211_crypt_data *new_crypt;
370 /* take WEP into use */
371 new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
372 GFP_KERNEL);
373 if (new_crypt == NULL)
374 return -ENOMEM;
375 new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
376 if (!new_crypt->ops) {
377 request_module("rtllib_crypt_wep");
378 new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
381 if (new_crypt->ops)
382 new_crypt->priv = new_crypt->ops->init(key);
384 if (!new_crypt->ops || !new_crypt->priv) {
385 kfree(new_crypt);
386 new_crypt = NULL;
388 printk(KERN_WARNING "%s: could not initialize WEP: "
389 "load module rtllib_crypt_wep\n",
390 dev->name);
391 return -EOPNOTSUPP;
393 *crypt = new_crypt;
396 /* If a new key was provided, set it up */
397 if (erq->length > 0) {
398 len = erq->length <= 5 ? 5 : 13;
399 memcpy(sec.keys[key], keybuf, erq->length);
400 if (len > erq->length)
401 memset(sec.keys[key] + erq->length, 0,
402 len - erq->length);
403 RTLLIB_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
404 key, escape_essid(sec.keys[key], len),
405 erq->length, len);
406 sec.key_sizes[key] = len;
407 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
408 (*crypt)->priv);
409 sec.flags |= (1 << key);
410 /* This ensures a key will be activated if no key is
411 * explicitely set */
412 if (key == sec.active_key)
413 sec.flags |= SEC_ACTIVE_KEY;
414 ieee->crypt_info.tx_keyidx = key;
416 } else {
417 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
418 NULL, (*crypt)->priv);
419 if (len == 0) {
420 /* Set a default key of all 0 */
421 printk(KERN_INFO "Setting key %d to all zero.\n",
422 key);
424 RTLLIB_DEBUG_WX("Setting key %d to all zero.\n",
425 key);
426 memset(sec.keys[key], 0, 13);
427 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
428 (*crypt)->priv);
429 sec.key_sizes[key] = 13;
430 sec.flags |= (1 << key);
433 /* No key data - just set the default TX key index */
434 if (key_provided) {
435 RTLLIB_DEBUG_WX(
436 "Setting key %d to default Tx key.\n", key);
437 ieee->crypt_info.tx_keyidx = key;
438 sec.active_key = key;
439 sec.flags |= SEC_ACTIVE_KEY;
442 done:
443 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
444 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
445 WLAN_AUTH_SHARED_KEY;
446 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
447 sec.flags |= SEC_AUTH_MODE;
448 RTLLIB_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
449 "OPEN" : "SHARED KEY");
451 /* For now we just support WEP, so only set that security level...
452 * TODO: When WPA is added this is one place that needs to change */
453 sec.flags |= SEC_LEVEL;
454 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
456 if (ieee->set_security)
457 ieee->set_security(dev, &sec);
459 /* Do not reset port if card is in Managed mode since resetting will
460 * generate new IEEE 802.11 authentication which may end up in looping
461 * with IEEE 802.1X. If your hardware requires a reset after WEP
462 * configuration (for example... Prism2), implement the reset_port in
463 * the callbacks structures used to initialize the 802.11 stack. */
464 if (ieee->reset_on_keychange &&
465 ieee->iw_mode != IW_MODE_INFRA &&
466 ieee->reset_port && ieee->reset_port(dev)) {
467 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
468 return -EINVAL;
470 return 0;
472 EXPORT_SYMBOL(rtllib_wx_set_encode);
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 lib80211_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 > NUM_WEP_KEYS)
490 return -EINVAL;
491 key--;
492 } else {
493 key = ieee->crypt_info.tx_keyidx;
495 crypt = ieee->crypt_info.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;
516 EXPORT_SYMBOL(rtllib_wx_get_encode);
518 int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
519 struct iw_request_info *info,
520 union iwreq_data *wrqu, char *extra)
522 int ret = 0;
523 struct net_device *dev = ieee->dev;
524 struct iw_point *encoding = &wrqu->encoding;
525 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
526 int i, idx;
527 int group_key = 0;
528 const char *alg, *module;
529 struct lib80211_crypto_ops *ops;
530 struct lib80211_crypt_data **crypt;
532 struct rtllib_security sec = {
533 .flags = 0,
535 idx = encoding->flags & IW_ENCODE_INDEX;
536 if (idx) {
537 if (idx < 1 || idx > NUM_WEP_KEYS)
538 return -EINVAL;
539 idx--;
540 } else{
541 idx = ieee->crypt_info.tx_keyidx;
543 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
544 crypt = &ieee->crypt_info.crypt[idx];
545 group_key = 1;
546 } else {
547 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
548 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
549 return -EINVAL;
550 if (ieee->iw_mode == IW_MODE_INFRA)
551 crypt = &ieee->crypt_info.crypt[idx];
552 else
553 return -EINVAL;
556 sec.flags |= SEC_ENABLED;
557 if ((encoding->flags & IW_ENCODE_DISABLED) ||
558 ext->alg == IW_ENCODE_ALG_NONE) {
559 if (*crypt)
560 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
562 for (i = 0; i < NUM_WEP_KEYS; i++) {
563 if (ieee->crypt_info.crypt[i] != NULL)
564 break;
566 if (i == NUM_WEP_KEYS) {
567 sec.enabled = 0;
568 sec.level = SEC_LEVEL_0;
569 sec.flags |= SEC_LEVEL;
571 goto done;
574 sec.enabled = 1;
575 switch (ext->alg) {
576 case IW_ENCODE_ALG_WEP:
577 alg = "R-WEP";
578 module = "rtllib_crypt_wep";
579 break;
580 case IW_ENCODE_ALG_TKIP:
581 alg = "R-TKIP";
582 module = "rtllib_crypt_tkip";
583 break;
584 case IW_ENCODE_ALG_CCMP:
585 alg = "R-CCMP";
586 module = "rtllib_crypt_ccmp";
587 break;
588 default:
589 RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
590 dev->name, ext->alg);
591 ret = -EINVAL;
592 goto done;
594 printk(KERN_INFO "alg name:%s\n", alg);
596 ops = lib80211_get_crypto_ops(alg);
597 if (ops == NULL) {
598 char tempbuf[100];
600 memset(tempbuf, 0x00, 100);
601 sprintf(tempbuf, "%s", module);
602 request_module("%s", tempbuf);
603 ops = lib80211_get_crypto_ops(alg);
605 if (ops == NULL) {
606 RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
607 dev->name, ext->alg);
608 printk(KERN_INFO "========>unknown crypto alg %d\n", ext->alg);
609 ret = -EINVAL;
610 goto done;
613 if (*crypt == NULL || (*crypt)->ops != ops) {
614 struct lib80211_crypt_data *new_crypt;
616 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
618 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
619 if (new_crypt == NULL) {
620 ret = -ENOMEM;
621 goto done;
623 new_crypt->ops = ops;
624 if (new_crypt->ops)
625 new_crypt->priv = new_crypt->ops->init(idx);
627 if (new_crypt->priv == NULL) {
628 kfree(new_crypt);
629 ret = -EINVAL;
630 goto done;
632 *crypt = new_crypt;
636 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
637 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
638 (*crypt)->priv) < 0) {
639 RTLLIB_DEBUG_WX("%s: key setting failed\n", dev->name);
640 printk(KERN_INFO "key setting failed\n");
641 ret = -EINVAL;
642 goto done;
644 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
645 ieee->crypt_info.tx_keyidx = idx;
646 sec.active_key = idx;
647 sec.flags |= SEC_ACTIVE_KEY;
649 if (ext->alg != IW_ENCODE_ALG_NONE) {
650 sec.key_sizes[idx] = ext->key_len;
651 sec.flags |= (1 << idx);
652 if (ext->alg == IW_ENCODE_ALG_WEP) {
653 sec.flags |= SEC_LEVEL;
654 sec.level = SEC_LEVEL_1;
655 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
656 sec.flags |= SEC_LEVEL;
657 sec.level = SEC_LEVEL_2;
658 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
659 sec.flags |= SEC_LEVEL;
660 sec.level = SEC_LEVEL_3;
662 /* Don't set sec level for group keys. */
663 if (group_key)
664 sec.flags &= ~SEC_LEVEL;
666 done:
667 if (ieee->set_security)
668 ieee->set_security(ieee->dev, &sec);
670 if (ieee->reset_on_keychange &&
671 ieee->iw_mode != IW_MODE_INFRA &&
672 ieee->reset_port && ieee->reset_port(dev)) {
673 RTLLIB_DEBUG_WX("%s: reset_port failed\n", dev->name);
674 return -EINVAL;
676 return ret;
678 EXPORT_SYMBOL(rtllib_wx_set_encode_ext);
680 int rtllib_wx_get_encode_ext(struct rtllib_device *ieee,
681 struct iw_request_info *info,
682 union iwreq_data *wrqu, char *extra)
684 struct iw_point *encoding = &wrqu->encoding;
685 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
686 struct lib80211_crypt_data *crypt;
687 int idx, max_key_len;
689 max_key_len = encoding->length - sizeof(*ext);
690 if (max_key_len < 0)
691 return -EINVAL;
693 idx = encoding->flags & IW_ENCODE_INDEX;
694 if (idx) {
695 if (idx < 1 || idx > NUM_WEP_KEYS)
696 return -EINVAL;
697 idx--;
698 } else {
699 idx = ieee->crypt_info.tx_keyidx;
701 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
702 (ext->alg != IW_ENCODE_ALG_WEP))
703 if (idx != 0 || (ieee->iw_mode != IW_MODE_INFRA))
704 return -EINVAL;
706 crypt = ieee->crypt_info.crypt[idx];
708 encoding->flags = idx + 1;
709 memset(ext, 0, sizeof(*ext));
711 if (crypt == NULL || crypt->ops == NULL) {
712 ext->alg = IW_ENCODE_ALG_NONE;
713 ext->key_len = 0;
714 encoding->flags |= IW_ENCODE_DISABLED;
715 } else {
716 if (strcmp(crypt->ops->name, "R-WEP") == 0)
717 ext->alg = IW_ENCODE_ALG_WEP;
718 else if (strcmp(crypt->ops->name, "R-TKIP"))
719 ext->alg = IW_ENCODE_ALG_TKIP;
720 else if (strcmp(crypt->ops->name, "R-CCMP"))
721 ext->alg = IW_ENCODE_ALG_CCMP;
722 else
723 return -EINVAL;
724 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN,
725 NULL, crypt->priv);
726 encoding->flags |= IW_ENCODE_ENABLED;
727 if (ext->key_len &&
728 (ext->alg == IW_ENCODE_ALG_TKIP ||
729 ext->alg == IW_ENCODE_ALG_CCMP))
730 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
734 return 0;
737 int rtllib_wx_set_mlme(struct rtllib_device *ieee,
738 struct iw_request_info *info,
739 union iwreq_data *wrqu, char *extra)
741 u8 i = 0;
742 bool deauth = false;
743 struct iw_mlme *mlme = (struct iw_mlme *) extra;
745 if (ieee->state != RTLLIB_LINKED)
746 return -ENOLINK;
748 down(&ieee->wx_sem);
750 switch (mlme->cmd) {
751 case IW_MLME_DEAUTH:
752 deauth = true;
753 /* leave break out intentionly */
755 case IW_MLME_DISASSOC:
756 if (deauth == true)
757 printk(KERN_INFO "disauth packet !\n");
758 else
759 printk(KERN_INFO "dis associate packet!\n");
761 ieee->cannot_notify = true;
763 SendDisassociation(ieee, deauth, mlme->reason_code);
764 rtllib_disassociate(ieee);
766 ieee->wap_set = 0;
767 for (i = 0; i < 6; i++)
768 ieee->current_network.bssid[i] = 0x55;
770 ieee->ssid_set = 0;
771 ieee->current_network.ssid[0] = '\0';
772 ieee->current_network.ssid_len = 0;
773 break;
774 default:
775 up(&ieee->wx_sem);
776 return -EOPNOTSUPP;
779 up(&ieee->wx_sem);
781 return 0;
783 EXPORT_SYMBOL(rtllib_wx_set_mlme);
785 int rtllib_wx_set_auth(struct rtllib_device *ieee,
786 struct iw_request_info *info,
787 struct iw_param *data, char *extra)
789 switch (data->flags & IW_AUTH_INDEX) {
790 case IW_AUTH_WPA_VERSION:
791 break;
792 case IW_AUTH_CIPHER_PAIRWISE:
793 case IW_AUTH_CIPHER_GROUP:
794 case IW_AUTH_KEY_MGMT:
796 * Host AP driver does not use these parameters and allows
797 * wpa_supplicant to control them internally.
799 break;
800 case IW_AUTH_TKIP_COUNTERMEASURES:
801 ieee->tkip_countermeasures = data->value;
802 break;
803 case IW_AUTH_DROP_UNENCRYPTED:
804 ieee->drop_unencrypted = data->value;
805 break;
807 case IW_AUTH_80211_AUTH_ALG:
808 if (data->value & IW_AUTH_ALG_SHARED_KEY) {
809 ieee->open_wep = 0;
810 ieee->auth_mode = 1;
811 } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) {
812 ieee->open_wep = 1;
813 ieee->auth_mode = 0;
814 } else if (data->value & IW_AUTH_ALG_LEAP) {
815 ieee->open_wep = 1;
816 ieee->auth_mode = 2;
817 } else
818 return -EINVAL;
819 break;
821 case IW_AUTH_WPA_ENABLED:
822 ieee->wpa_enabled = (data->value) ? 1 : 0;
823 break;
825 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
826 ieee->ieee802_1x = data->value;
827 break;
828 case IW_AUTH_PRIVACY_INVOKED:
829 ieee->privacy_invoked = data->value;
830 break;
831 default:
832 return -EOPNOTSUPP;
834 return 0;
836 EXPORT_SYMBOL(rtllib_wx_set_auth);
838 int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
840 u8 *buf;
841 u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
843 if (len > MAX_WPA_IE_LEN || (len && ie == NULL))
844 return -EINVAL;
846 if (len) {
847 eid = ie[0];
848 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2],
849 wps_oui, 4))) {
851 ieee->wps_ie_len = (len < MAX_WZC_IE_LEN) ? (len) :
852 (MAX_WZC_IE_LEN);
853 buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL);
854 if (buf == NULL)
855 return -ENOMEM;
856 ieee->wps_ie = buf;
857 return 0;
860 ieee->wps_ie_len = 0;
861 kfree(ieee->wps_ie);
862 ieee->wps_ie = NULL;
863 if (len) {
864 if (len != ie[1]+2)
865 return -EINVAL;
866 buf = kmemdup(ie, len, GFP_KERNEL);
867 if (buf == NULL)
868 return -ENOMEM;
869 kfree(ieee->wpa_ie);
870 ieee->wpa_ie = buf;
871 ieee->wpa_ie_len = len;
872 } else {
873 kfree(ieee->wpa_ie);
874 ieee->wpa_ie = NULL;
875 ieee->wpa_ie_len = 0;
877 return 0;
879 EXPORT_SYMBOL(rtllib_wx_set_gen_ie);