Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[cascardo/linux.git] / drivers / staging / rtl8192e / rtllib_wx.c
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/kmod.h>
34 #include <linux/module.h>
35
36 #include "rtllib.h"
37 struct modes_unit {
38         char *mode_string;
39         int mode_size;
40 };
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},
48 };
49
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)
55 {
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};
64
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 */
72
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);
88         }
89         /* Add the protocol name */
90         iwe.cmd = SIOCGIWNAME;
91         for (i = 0; i < ARRAY_SIZE(rtllib_modes); 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;
96                 }
97         }
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);
112         }
113
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);
123
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" : "");
148         }
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;
155         }
156
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
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);
172
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;
178         }
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);
205
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);
212
213         memset(&iwe, 0, sizeof(iwe));
214         if (network->wpa_ie_len) {
215                 char buf[MAX_WPA_IE_LEN];
216
217                 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
218                 iwe.cmd = IWEVGENIE;
219                 iwe.u.data.length = network->wpa_ie_len;
220                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
221         }
222         memset(&iwe, 0, sizeof(iwe));
223         if (network->rsn_ie_len) {
224                 char buf[MAX_WPA_IE_LEN];
225
226                 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
227                 iwe.cmd = IWEVGENIE;
228                 iwe.u.data.length = network->rsn_ie_len;
229                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
230         }
231
232         /* add info for WZC */
233         memset(&iwe, 0, sizeof(iwe));
234         if (network->wzc_ie_len) {
235                 char buf[MAX_WZC_IE_LEN];
236
237                 memcpy(buf, network->wzc_ie, network->wzc_ie_len);
238                 iwe.cmd = IWEVGENIE;
239                 iwe.u.data.length = network->wzc_ie_len;
240                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
241         }
242
243         /* Add EXTRA: Age to display seconds since last beacon/probe response
244          * for given network. */
245         iwe.cmd = IWEVCUSTOM;
246         p = custom;
247         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
248                       " Last beacon: %lums ago",
249                       (jiffies - network->last_scanned) / (HZ / 100));
250         iwe.u.data.length = p - custom;
251         if (iwe.u.data.length)
252                 start = iwe_stream_add_point_rsl(info, start, stop,
253                                                  &iwe, custom);
254
255         return start;
256 }
257
258 int rtllib_wx_get_scan(struct rtllib_device *ieee,
259                           struct iw_request_info *info,
260                           union iwreq_data *wrqu, char *extra)
261 {
262         struct rtllib_network *network;
263         unsigned long flags;
264
265         char *ev = extra;
266         char *stop = ev + wrqu->data.length;
267         int i = 0;
268         int err = 0;
269
270         RTLLIB_DEBUG_WX("Getting scan\n");
271         down(&ieee->wx_sem);
272         spin_lock_irqsave(&ieee->lock, flags);
273
274         list_for_each_entry(network, &ieee->network_list, list) {
275                 i++;
276                 if ((stop - ev) < 200) {
277                         err = -E2BIG;
278                         break;
279                 }
280                 if (ieee->scan_age == 0 ||
281                     time_after(network->last_scanned + ieee->scan_age, jiffies))
282                         ev = rtl819x_translate_scan(ieee, ev, stop, network,
283                                                     info);
284                 else
285                         RTLLIB_DEBUG_SCAN("Not showing network '%s ("
286                                 " %pM)' due to age (%lums).\n",
287                                 escape_essid(network->ssid,
288                                              network->ssid_len),
289                                 network->bssid,
290                                 (jiffies - network->last_scanned) / (HZ / 100));
291         }
292
293         spin_unlock_irqrestore(&ieee->lock, flags);
294         up(&ieee->wx_sem);
295         wrqu->data.length = ev -  extra;
296         wrqu->data.flags = 0;
297
298         RTLLIB_DEBUG_WX("exit: %d networks returned.\n", i);
299
300         return err;
301 }
302 EXPORT_SYMBOL(rtllib_wx_get_scan);
303
304 int rtllib_wx_set_encode(struct rtllib_device *ieee,
305                             struct iw_request_info *info,
306                             union iwreq_data *wrqu, char *keybuf)
307 {
308         struct iw_point *erq = &(wrqu->encoding);
309         struct net_device *dev = ieee->dev;
310         struct rtllib_security sec = {
311                 .flags = 0
312         };
313         int i, key, key_provided, len;
314         struct lib80211_crypt_data **crypt;
315
316         RTLLIB_DEBUG_WX("SET_ENCODE\n");
317
318         key = erq->flags & IW_ENCODE_INDEX;
319         if (key) {
320                 if (key > NUM_WEP_KEYS)
321                         return -EINVAL;
322                 key--;
323                 key_provided = 1;
324         } else {
325                 key_provided = 0;
326                 key = ieee->crypt_info.tx_keyidx;
327         }
328
329         RTLLIB_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
330                            "provided" : "default");
331         crypt = &ieee->crypt_info.crypt[key];
332         if (erq->flags & IW_ENCODE_DISABLED) {
333                 if (key_provided && *crypt) {
334                         RTLLIB_DEBUG_WX("Disabling encryption on key %d.\n",
335                                            key);
336                         lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
337                 } else
338                         RTLLIB_DEBUG_WX("Disabling encryption.\n");
339
340                 /* Check all the keys to see if any are still configured,
341                  * and if no key index was provided, de-init them all */
342                 for (i = 0; i < NUM_WEP_KEYS; i++) {
343                         if (ieee->crypt_info.crypt[i] != NULL) {
344                                 if (key_provided)
345                                         break;
346                                 lib80211_crypt_delayed_deinit(&ieee->crypt_info,
347                                                             &ieee->crypt_info.crypt[i]);
348                         }
349                 }
350
351                 if (i == NUM_WEP_KEYS) {
352                         sec.enabled = 0;
353                         sec.level = SEC_LEVEL_0;
354                         sec.flags |= SEC_ENABLED | SEC_LEVEL;
355                 }
356
357                 goto done;
358         }
359
360
361
362         sec.enabled = 1;
363         sec.flags |= SEC_ENABLED;
364
365         if (*crypt != NULL && (*crypt)->ops != NULL &&
366             strcmp((*crypt)->ops->name, "R-WEP") != 0) {
367                 /* changing to use WEP; deinit previously used algorithm
368                  * on this key */
369                 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
370         }
371
372         if (*crypt == NULL) {
373                 struct lib80211_crypt_data *new_crypt;
374
375                 /* take WEP into use */
376                 new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
377                                     GFP_KERNEL);
378                 if (new_crypt == NULL)
379                         return -ENOMEM;
380                 new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
381                 if (!new_crypt->ops) {
382                         request_module("rtllib_crypt_wep");
383                         new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
384                 }
385
386                 if (new_crypt->ops)
387                         new_crypt->priv = new_crypt->ops->init(key);
388
389                 if (!new_crypt->ops || !new_crypt->priv) {
390                         kfree(new_crypt);
391                         new_crypt = NULL;
392
393                         printk(KERN_WARNING "%s: could not initialize WEP: "
394                                "load module rtllib_crypt_wep\n",
395                                dev->name);
396                         return -EOPNOTSUPP;
397                 }
398                 *crypt = new_crypt;
399         }
400
401         /* If a new key was provided, set it up */
402         if (erq->length > 0) {
403                 len = erq->length <= 5 ? 5 : 13;
404                 memcpy(sec.keys[key], keybuf, erq->length);
405                 if (len > erq->length)
406                         memset(sec.keys[key] + erq->length, 0,
407                                len - erq->length);
408                 RTLLIB_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
409                                    key, escape_essid(sec.keys[key], len),
410                                    erq->length, len);
411                 sec.key_sizes[key] = len;
412                 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
413                                        (*crypt)->priv);
414                 sec.flags |= (1 << key);
415                 /* This ensures a key will be activated if no key is
416                  * explicitly set */
417                 if (key == sec.active_key)
418                         sec.flags |= SEC_ACTIVE_KEY;
419                 ieee->crypt_info.tx_keyidx = key;
420
421         } else {
422                 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
423                                              NULL, (*crypt)->priv);
424                 if (len == 0) {
425                         /* Set a default key of all 0 */
426                         printk(KERN_INFO "Setting key %d to all zero.\n",
427                                            key);
428
429                         RTLLIB_DEBUG_WX("Setting key %d to all zero.\n",
430                                            key);
431                         memset(sec.keys[key], 0, 13);
432                         (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
433                                                (*crypt)->priv);
434                         sec.key_sizes[key] = 13;
435                         sec.flags |= (1 << key);
436                 }
437
438                 /* No key data - just set the default TX key index */
439                 if (key_provided) {
440                         RTLLIB_DEBUG_WX(
441                                 "Setting key %d to default Tx key.\n", key);
442                         ieee->crypt_info.tx_keyidx = key;
443                         sec.active_key = key;
444                         sec.flags |= SEC_ACTIVE_KEY;
445                 }
446         }
447  done:
448         ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
449         ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
450                           WLAN_AUTH_SHARED_KEY;
451         sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
452         sec.flags |= SEC_AUTH_MODE;
453         RTLLIB_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
454                            "OPEN" : "SHARED KEY");
455
456         /* For now we just support WEP, so only set that security level...
457          * TODO: When WPA is added this is one place that needs to change */
458         sec.flags |= SEC_LEVEL;
459         sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
460
461         if (ieee->set_security)
462                 ieee->set_security(dev, &sec);
463
464         /* Do not reset port if card is in Managed mode since resetting will
465          * generate new IEEE 802.11 authentication which may end up in looping
466          * with IEEE 802.1X.  If your hardware requires a reset after WEP
467          * configuration (for example... Prism2), implement the reset_port in
468          * the callbacks structures used to initialize the 802.11 stack. */
469         if (ieee->reset_on_keychange &&
470             ieee->iw_mode != IW_MODE_INFRA &&
471             ieee->reset_port && ieee->reset_port(dev)) {
472                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
473                 return -EINVAL;
474         }
475         return 0;
476 }
477 EXPORT_SYMBOL(rtllib_wx_set_encode);
478
479 int rtllib_wx_get_encode(struct rtllib_device *ieee,
480                             struct iw_request_info *info,
481                             union iwreq_data *wrqu, char *keybuf)
482 {
483         struct iw_point *erq = &(wrqu->encoding);
484         int len, key;
485         struct lib80211_crypt_data *crypt;
486
487         RTLLIB_DEBUG_WX("GET_ENCODE\n");
488
489         if (ieee->iw_mode == IW_MODE_MONITOR)
490                 return -1;
491
492         key = erq->flags & IW_ENCODE_INDEX;
493         if (key) {
494                 if (key > NUM_WEP_KEYS)
495                         return -EINVAL;
496                 key--;
497         } else {
498                 key = ieee->crypt_info.tx_keyidx;
499         }
500         crypt = ieee->crypt_info.crypt[key];
501
502         erq->flags = key + 1;
503
504         if (crypt == NULL || crypt->ops == NULL) {
505                 erq->length = 0;
506                 erq->flags |= IW_ENCODE_DISABLED;
507                 return 0;
508         }
509         len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
510         erq->length = (len >= 0 ? len : 0);
511
512         erq->flags |= IW_ENCODE_ENABLED;
513
514         if (ieee->open_wep)
515                 erq->flags |= IW_ENCODE_OPEN;
516         else
517                 erq->flags |= IW_ENCODE_RESTRICTED;
518
519         return 0;
520 }
521 EXPORT_SYMBOL(rtllib_wx_get_encode);
522
523 int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
524                                struct iw_request_info *info,
525                                union iwreq_data *wrqu, char *extra)
526 {
527         int ret = 0;
528         struct net_device *dev = ieee->dev;
529         struct iw_point *encoding = &wrqu->encoding;
530         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
531         int i, idx;
532         int group_key = 0;
533         const char *alg, *module;
534         struct lib80211_crypto_ops *ops;
535         struct lib80211_crypt_data **crypt;
536
537         struct rtllib_security sec = {
538                 .flags = 0,
539         };
540         idx = encoding->flags & IW_ENCODE_INDEX;
541         if (idx) {
542                 if (idx < 1 || idx > NUM_WEP_KEYS)
543                         return -EINVAL;
544                 idx--;
545         } else{
546                         idx = ieee->crypt_info.tx_keyidx;
547         }
548         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
549                 crypt = &ieee->crypt_info.crypt[idx];
550                 group_key = 1;
551         } else {
552                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
553                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
554                         return -EINVAL;
555                 if (ieee->iw_mode == IW_MODE_INFRA)
556                         crypt = &ieee->crypt_info.crypt[idx];
557                 else
558                         return -EINVAL;
559         }
560
561         sec.flags |= SEC_ENABLED;
562         if ((encoding->flags & IW_ENCODE_DISABLED) ||
563             ext->alg == IW_ENCODE_ALG_NONE) {
564                 if (*crypt)
565                         lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
566
567                 for (i = 0; i < NUM_WEP_KEYS; i++) {
568                         if (ieee->crypt_info.crypt[i] != NULL)
569                                 break;
570                 }
571                 if (i == NUM_WEP_KEYS) {
572                         sec.enabled = 0;
573                         sec.level = SEC_LEVEL_0;
574                         sec.flags |= SEC_LEVEL;
575                 }
576                 goto done;
577         }
578
579         sec.enabled = 1;
580         switch (ext->alg) {
581         case IW_ENCODE_ALG_WEP:
582                 alg = "R-WEP";
583                 module = "rtllib_crypt_wep";
584                 break;
585         case IW_ENCODE_ALG_TKIP:
586                 alg = "R-TKIP";
587                 module = "rtllib_crypt_tkip";
588                 break;
589         case IW_ENCODE_ALG_CCMP:
590                 alg = "R-CCMP";
591                 module = "rtllib_crypt_ccmp";
592                 break;
593         default:
594                 RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
595                                    dev->name, ext->alg);
596                 ret = -EINVAL;
597                 goto done;
598         }
599         printk(KERN_INFO "alg name:%s\n", alg);
600
601         ops = lib80211_get_crypto_ops(alg);
602         if (ops == NULL) {
603                 char tempbuf[100];
604
605                 memset(tempbuf, 0x00, 100);
606                 sprintf(tempbuf, "%s", module);
607                 request_module("%s", tempbuf);
608                 ops = lib80211_get_crypto_ops(alg);
609         }
610         if (ops == NULL) {
611                 RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
612                                    dev->name, ext->alg);
613                 printk(KERN_INFO "========>unknown crypto alg %d\n", ext->alg);
614                 ret = -EINVAL;
615                 goto done;
616         }
617
618         if (*crypt == NULL || (*crypt)->ops != ops) {
619                 struct lib80211_crypt_data *new_crypt;
620
621                 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
622
623                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
624                 if (new_crypt == NULL) {
625                         ret = -ENOMEM;
626                         goto done;
627                 }
628                 new_crypt->ops = ops;
629                 if (new_crypt->ops)
630                         new_crypt->priv = new_crypt->ops->init(idx);
631
632                 if (new_crypt->priv == NULL) {
633                         kfree(new_crypt);
634                         ret = -EINVAL;
635                         goto done;
636                 }
637                 *crypt = new_crypt;
638
639         }
640
641         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
642             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
643                                    (*crypt)->priv) < 0) {
644                 RTLLIB_DEBUG_WX("%s: key setting failed\n", dev->name);
645                 printk(KERN_INFO "key setting failed\n");
646                 ret = -EINVAL;
647                 goto done;
648         }
649         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
650                 ieee->crypt_info.tx_keyidx = idx;
651                 sec.active_key = idx;
652                 sec.flags |= SEC_ACTIVE_KEY;
653         }
654         if (ext->alg != IW_ENCODE_ALG_NONE) {
655                 sec.key_sizes[idx] = ext->key_len;
656                 sec.flags |= (1 << idx);
657                 if (ext->alg == IW_ENCODE_ALG_WEP) {
658                         sec.flags |= SEC_LEVEL;
659                         sec.level = SEC_LEVEL_1;
660                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
661                         sec.flags |= SEC_LEVEL;
662                         sec.level = SEC_LEVEL_2;
663                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
664                         sec.flags |= SEC_LEVEL;
665                         sec.level = SEC_LEVEL_3;
666                 }
667                 /* Don't set sec level for group keys. */
668                 if (group_key)
669                         sec.flags &= ~SEC_LEVEL;
670         }
671 done:
672         if (ieee->set_security)
673                 ieee->set_security(ieee->dev, &sec);
674
675          if (ieee->reset_on_keychange &&
676             ieee->iw_mode != IW_MODE_INFRA &&
677             ieee->reset_port && ieee->reset_port(dev)) {
678                 RTLLIB_DEBUG_WX("%s: reset_port failed\n", dev->name);
679                 return -EINVAL;
680         }
681         return ret;
682 }
683 EXPORT_SYMBOL(rtllib_wx_set_encode_ext);
684
685 int rtllib_wx_get_encode_ext(struct rtllib_device *ieee,
686                                struct iw_request_info *info,
687                                union iwreq_data *wrqu, char *extra)
688 {
689         struct iw_point *encoding = &wrqu->encoding;
690         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
691         struct lib80211_crypt_data *crypt;
692         int idx, max_key_len;
693
694         max_key_len = encoding->length - sizeof(*ext);
695         if (max_key_len < 0)
696                 return -EINVAL;
697
698         idx = encoding->flags & IW_ENCODE_INDEX;
699         if (idx) {
700                 if (idx < 1 || idx > NUM_WEP_KEYS)
701                         return -EINVAL;
702                 idx--;
703         } else {
704                 idx = ieee->crypt_info.tx_keyidx;
705         }
706         if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
707             (ext->alg != IW_ENCODE_ALG_WEP))
708                 if (idx != 0 || (ieee->iw_mode != IW_MODE_INFRA))
709                         return -EINVAL;
710
711         crypt = ieee->crypt_info.crypt[idx];
712
713         encoding->flags = idx + 1;
714         memset(ext, 0, sizeof(*ext));
715
716         if (crypt == NULL || crypt->ops == NULL) {
717                 ext->alg = IW_ENCODE_ALG_NONE;
718                 ext->key_len = 0;
719                 encoding->flags |= IW_ENCODE_DISABLED;
720         } else {
721                 if (strcmp(crypt->ops->name, "R-WEP") == 0)
722                         ext->alg = IW_ENCODE_ALG_WEP;
723                 else if (strcmp(crypt->ops->name, "R-TKIP"))
724                         ext->alg = IW_ENCODE_ALG_TKIP;
725                 else if (strcmp(crypt->ops->name, "R-CCMP"))
726                         ext->alg = IW_ENCODE_ALG_CCMP;
727                 else
728                         return -EINVAL;
729                 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN,
730                                                    NULL, crypt->priv);
731                 encoding->flags |= IW_ENCODE_ENABLED;
732                 if (ext->key_len &&
733                     (ext->alg == IW_ENCODE_ALG_TKIP ||
734                      ext->alg == IW_ENCODE_ALG_CCMP))
735                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
736
737         }
738
739         return 0;
740 }
741
742 int rtllib_wx_set_mlme(struct rtllib_device *ieee,
743                                struct iw_request_info *info,
744                                union iwreq_data *wrqu, char *extra)
745 {
746         u8 i = 0;
747         bool deauth = false;
748         struct iw_mlme *mlme = (struct iw_mlme *) extra;
749
750         if (ieee->state != RTLLIB_LINKED)
751                 return -ENOLINK;
752
753         down(&ieee->wx_sem);
754
755         switch (mlme->cmd) {
756         case IW_MLME_DEAUTH:
757                 deauth = true;
758                 /* leave break out intentionly */
759
760         case IW_MLME_DISASSOC:
761                 if (deauth)
762                         printk(KERN_INFO "disauth packet !\n");
763                 else
764                         printk(KERN_INFO "dis associate packet!\n");
765
766                 ieee->cannot_notify = true;
767
768                 SendDisassociation(ieee, deauth, mlme->reason_code);
769                 rtllib_disassociate(ieee);
770
771                 ieee->wap_set = 0;
772                 for (i = 0; i < 6; i++)
773                         ieee->current_network.bssid[i] = 0x55;
774
775                 ieee->ssid_set = 0;
776                 ieee->current_network.ssid[0] = '\0';
777                 ieee->current_network.ssid_len = 0;
778                 break;
779         default:
780                 up(&ieee->wx_sem);
781                 return -EOPNOTSUPP;
782         }
783
784         up(&ieee->wx_sem);
785
786         return 0;
787 }
788 EXPORT_SYMBOL(rtllib_wx_set_mlme);
789
790 int rtllib_wx_set_auth(struct rtllib_device *ieee,
791                                struct iw_request_info *info,
792                                struct iw_param *data, char *extra)
793 {
794         switch (data->flags & IW_AUTH_INDEX) {
795         case IW_AUTH_WPA_VERSION:
796                 break;
797         case IW_AUTH_CIPHER_PAIRWISE:
798         case IW_AUTH_CIPHER_GROUP:
799         case IW_AUTH_KEY_MGMT:
800                 /*
801                  * Host AP driver does not use these parameters and allows
802                  * wpa_supplicant to control them internally.
803                  */
804                 break;
805         case IW_AUTH_TKIP_COUNTERMEASURES:
806                 ieee->tkip_countermeasures = data->value;
807                 break;
808         case IW_AUTH_DROP_UNENCRYPTED:
809                 ieee->drop_unencrypted = data->value;
810                 break;
811
812         case IW_AUTH_80211_AUTH_ALG:
813                 if (data->value & IW_AUTH_ALG_SHARED_KEY) {
814                         ieee->open_wep = 0;
815                         ieee->auth_mode = 1;
816                 } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) {
817                         ieee->open_wep = 1;
818                         ieee->auth_mode = 0;
819                 } else if (data->value & IW_AUTH_ALG_LEAP) {
820                         ieee->open_wep = 1;
821                         ieee->auth_mode = 2;
822                 } else
823                         return -EINVAL;
824                 break;
825
826         case IW_AUTH_WPA_ENABLED:
827                 ieee->wpa_enabled = (data->value) ? 1 : 0;
828                 break;
829
830         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
831                 ieee->ieee802_1x = data->value;
832                 break;
833         case IW_AUTH_PRIVACY_INVOKED:
834                 ieee->privacy_invoked = data->value;
835                 break;
836         default:
837                 return -EOPNOTSUPP;
838         }
839         return 0;
840 }
841 EXPORT_SYMBOL(rtllib_wx_set_auth);
842
843 int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
844 {
845         u8 *buf;
846         u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
847
848         if (len > MAX_WPA_IE_LEN || (len && ie == NULL))
849                 return -EINVAL;
850
851         if (len) {
852                 eid = ie[0];
853                 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2],
854                      wps_oui, 4))) {
855
856                         ieee->wps_ie_len = (len < MAX_WZC_IE_LEN) ? (len) :
857                                            (MAX_WZC_IE_LEN);
858                         buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL);
859                         if (buf == NULL)
860                                 return -ENOMEM;
861                         ieee->wps_ie = buf;
862                         return 0;
863                 }
864         }
865         ieee->wps_ie_len = 0;
866         kfree(ieee->wps_ie);
867         ieee->wps_ie = NULL;
868         if (len) {
869                 if (len != ie[1]+2)
870                         return -EINVAL;
871                 buf = kmemdup(ie, len, GFP_KERNEL);
872                 if (buf == NULL)
873                         return -ENOMEM;
874                 kfree(ieee->wpa_ie);
875                 ieee->wpa_ie = buf;
876                 ieee->wpa_ie_len = len;
877         } else {
878                 kfree(ieee->wpa_ie);
879                 ieee->wpa_ie = NULL;
880                 ieee->wpa_ie_len = 0;
881         }
882         return 0;
883 }
884 EXPORT_SYMBOL(rtllib_wx_set_gen_ie);