Merge tag 'fbdev-3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/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                 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);
171
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;
177         }
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);
204
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);
211
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);
219         }
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);
227         }
228
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);
237         }
238
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);
250
251         return start;
252 }
253
254 int rtllib_wx_get_scan(struct rtllib_device *ieee,
255                           struct iw_request_info *info,
256                           union iwreq_data *wrqu, char *extra)
257 {
258         struct rtllib_network *network;
259         unsigned long flags;
260
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);
268
269         list_for_each_entry(network, &ieee->network_list, list) {
270                 i++;
271                 if ((stop - ev) < 200) {
272                         err = -E2BIG;
273                         break;
274                 }
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));
286         }
287
288         spin_unlock_irqrestore(&ieee->lock, flags);
289         up(&ieee->wx_sem);
290         wrqu->data.length = ev -  extra;
291         wrqu->data.flags = 0;
292
293         RTLLIB_DEBUG_WX("exit: %d networks returned.\n", i);
294
295         return err;
296 }
297 EXPORT_SYMBOL(rtllib_wx_get_scan);
298
299 int rtllib_wx_set_encode(struct rtllib_device *ieee,
300                             struct iw_request_info *info,
301                             union iwreq_data *wrqu, char *keybuf)
302 {
303         struct iw_point *erq = &(wrqu->encoding);
304         struct net_device *dev = ieee->dev;
305         struct rtllib_security sec = {
306                 .flags = 0
307         };
308         int i, key, key_provided, len;
309         struct lib80211_crypt_data **crypt;
310
311         RTLLIB_DEBUG_WX("SET_ENCODE\n");
312
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;
322         }
323
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");
334
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]);
343                         }
344                 }
345
346                 if (i == NUM_WEP_KEYS) {
347                         sec.enabled = 0;
348                         sec.level = SEC_LEVEL_0;
349                         sec.flags |= SEC_ENABLED | SEC_LEVEL;
350                 }
351
352                 goto done;
353         }
354
355
356
357         sec.enabled = 1;
358         sec.flags |= SEC_ENABLED;
359
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);
365         }
366
367         if (*crypt == NULL) {
368                 struct lib80211_crypt_data *new_crypt;
369
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");
379                 }
380
381                 if (new_crypt->ops)
382                         new_crypt->priv = new_crypt->ops->init(key);
383
384                 if (!new_crypt->ops || !new_crypt->priv) {
385                         kfree(new_crypt);
386                         new_crypt = NULL;
387
388                         printk(KERN_WARNING "%s: could not initialize WEP: "
389                                "load module rtllib_crypt_wep\n",
390                                dev->name);
391                         return -EOPNOTSUPP;
392                 }
393                 *crypt = new_crypt;
394         }
395
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                  * explicitly set */
412                 if (key == sec.active_key)
413                         sec.flags |= SEC_ACTIVE_KEY;
414                 ieee->crypt_info.tx_keyidx = key;
415
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);
423
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);
431                 }
432
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;
440                 }
441         }
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");
450
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 */
455
456         if (ieee->set_security)
457                 ieee->set_security(dev, &sec);
458
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;
469         }
470         return 0;
471 }
472 EXPORT_SYMBOL(rtllib_wx_set_encode);
473
474 int rtllib_wx_get_encode(struct rtllib_device *ieee,
475                             struct iw_request_info *info,
476                             union iwreq_data *wrqu, char *keybuf)
477 {
478         struct iw_point *erq = &(wrqu->encoding);
479         int len, key;
480         struct lib80211_crypt_data *crypt;
481
482         RTLLIB_DEBUG_WX("GET_ENCODE\n");
483
484         if (ieee->iw_mode == IW_MODE_MONITOR)
485                 return -1;
486
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;
494         }
495         crypt = ieee->crypt_info.crypt[key];
496
497         erq->flags = key + 1;
498
499         if (crypt == NULL || crypt->ops == NULL) {
500                 erq->length = 0;
501                 erq->flags |= IW_ENCODE_DISABLED;
502                 return 0;
503         }
504         len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
505         erq->length = (len >= 0 ? len : 0);
506
507         erq->flags |= IW_ENCODE_ENABLED;
508
509         if (ieee->open_wep)
510                 erq->flags |= IW_ENCODE_OPEN;
511         else
512                 erq->flags |= IW_ENCODE_RESTRICTED;
513
514         return 0;
515 }
516 EXPORT_SYMBOL(rtllib_wx_get_encode);
517
518 int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
519                                struct iw_request_info *info,
520                                union iwreq_data *wrqu, char *extra)
521 {
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;
531
532         struct rtllib_security sec = {
533                 .flags = 0,
534         };
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;
542         }
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;
554         }
555
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);
561
562                 for (i = 0; i < NUM_WEP_KEYS; i++) {
563                         if (ieee->crypt_info.crypt[i] != NULL)
564                                 break;
565                 }
566                 if (i == NUM_WEP_KEYS) {
567                         sec.enabled = 0;
568                         sec.level = SEC_LEVEL_0;
569                         sec.flags |= SEC_LEVEL;
570                 }
571                 goto done;
572         }
573
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;
593         }
594         printk(KERN_INFO "alg name:%s\n", alg);
595
596         ops = lib80211_get_crypto_ops(alg);
597         if (ops == NULL) {
598                 char tempbuf[100];
599
600                 memset(tempbuf, 0x00, 100);
601                 sprintf(tempbuf, "%s", module);
602                 request_module("%s", tempbuf);
603                 ops = lib80211_get_crypto_ops(alg);
604         }
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;
611         }
612
613         if (*crypt == NULL || (*crypt)->ops != ops) {
614                 struct lib80211_crypt_data *new_crypt;
615
616                 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
617
618                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
619                 if (new_crypt == NULL) {
620                         ret = -ENOMEM;
621                         goto done;
622                 }
623                 new_crypt->ops = ops;
624                 if (new_crypt->ops)
625                         new_crypt->priv = new_crypt->ops->init(idx);
626
627                 if (new_crypt->priv == NULL) {
628                         kfree(new_crypt);
629                         ret = -EINVAL;
630                         goto done;
631                 }
632                 *crypt = new_crypt;
633
634         }
635
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;
643         }
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;
648         }
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;
661                 }
662                 /* Don't set sec level for group keys. */
663                 if (group_key)
664                         sec.flags &= ~SEC_LEVEL;
665         }
666 done:
667         if (ieee->set_security)
668                 ieee->set_security(ieee->dev, &sec);
669
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;
675         }
676         return ret;
677 }
678 EXPORT_SYMBOL(rtllib_wx_set_encode_ext);
679
680 int rtllib_wx_get_encode_ext(struct rtllib_device *ieee,
681                                struct iw_request_info *info,
682                                union iwreq_data *wrqu, char *extra)
683 {
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;
688
689         max_key_len = encoding->length - sizeof(*ext);
690         if (max_key_len < 0)
691                 return -EINVAL;
692
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;
700         }
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;
705
706         crypt = ieee->crypt_info.crypt[idx];
707
708         encoding->flags = idx + 1;
709         memset(ext, 0, sizeof(*ext));
710
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;
731
732         }
733
734         return 0;
735 }
736
737 int rtllib_wx_set_mlme(struct rtllib_device *ieee,
738                                struct iw_request_info *info,
739                                union iwreq_data *wrqu, char *extra)
740 {
741         u8 i = 0;
742         bool deauth = false;
743         struct iw_mlme *mlme = (struct iw_mlme *) extra;
744
745         if (ieee->state != RTLLIB_LINKED)
746                 return -ENOLINK;
747
748         down(&ieee->wx_sem);
749
750         switch (mlme->cmd) {
751         case IW_MLME_DEAUTH:
752                 deauth = true;
753                 /* leave break out intentionly */
754
755         case IW_MLME_DISASSOC:
756                 if (deauth)
757                         printk(KERN_INFO "disauth packet !\n");
758                 else
759                         printk(KERN_INFO "dis associate packet!\n");
760
761                 ieee->cannot_notify = true;
762
763                 SendDisassociation(ieee, deauth, mlme->reason_code);
764                 rtllib_disassociate(ieee);
765
766                 ieee->wap_set = 0;
767                 for (i = 0; i < 6; i++)
768                         ieee->current_network.bssid[i] = 0x55;
769
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;
777         }
778
779         up(&ieee->wx_sem);
780
781         return 0;
782 }
783 EXPORT_SYMBOL(rtllib_wx_set_mlme);
784
785 int rtllib_wx_set_auth(struct rtllib_device *ieee,
786                                struct iw_request_info *info,
787                                struct iw_param *data, char *extra)
788 {
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:
795                 /*
796                  * Host AP driver does not use these parameters and allows
797                  * wpa_supplicant to control them internally.
798                  */
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;
806
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;
820
821         case IW_AUTH_WPA_ENABLED:
822                 ieee->wpa_enabled = (data->value) ? 1 : 0;
823                 break;
824
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;
833         }
834         return 0;
835 }
836 EXPORT_SYMBOL(rtllib_wx_set_auth);
837
838 int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
839 {
840         u8 *buf;
841         u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
842
843         if (len > MAX_WPA_IE_LEN || (len && ie == NULL))
844                 return -EINVAL;
845
846         if (len) {
847                 eid = ie[0];
848                 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2],
849                      wps_oui, 4))) {
850
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;
858                 }
859         }
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;
876         }
877         return 0;
878 }
879 EXPORT_SYMBOL(rtllib_wx_set_gen_ie);