]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/rtl8192e/rtllib_wx.c
Merge linux-block/for-4.3/core into md/for-linux
[karo-tx-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 #include <linux/etherdevice.h>
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         ether_addr_copy(iwe.u.ap_addr.sa_data, network->bssid);
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_t(u8, network->ssid_len, 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_t(u8, network->hidden_ssid_len, 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 = network->channel;
117         iwe.u.freq.e = 0;
118         iwe.u.freq.i = 0;
119         start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
120                                          IW_EV_FREQ_LEN);
121
122         /* Add encryption capability */
123         iwe.cmd = SIOCGIWENCODE;
124         if (network->capability & WLAN_CAPABILITY_PRIVACY)
125                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
126         else
127                 iwe.u.data.flags = IW_ENCODE_DISABLED;
128         iwe.u.data.length = 0;
129         start = iwe_stream_add_point_rsl(info, start, stop,
130                                          &iwe, network->ssid);
131         /* Add basic and extended rates */
132         max_rate = 0;
133         p = custom;
134         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
135         for (i = 0, j = 0; i < network->rates_len;) {
136                 if (j < network->rates_ex_len &&
137                     ((network->rates_ex[j] & 0x7F) <
138                      (network->rates[i] & 0x7F)))
139                         rate = network->rates_ex[j++] & 0x7F;
140                 else
141                         rate = network->rates[i++] & 0x7F;
142                 if (rate > max_rate)
143                         max_rate = rate;
144                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
145                               "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
146         }
147         for (; j < network->rates_ex_len; j++) {
148                 rate = network->rates_ex[j] & 0x7F;
149                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
150                               "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
151                 if (rate > max_rate)
152                         max_rate = rate;
153         }
154
155         if (network->mode >= IEEE_N_24G) {
156                 struct ht_capab_ele *ht_cap = NULL;
157                 bool is40M = false, isShortGI = false;
158                 u8 max_mcs = 0;
159
160                 if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
161                         ht_cap = (struct ht_capab_ele *)
162                                  &network->bssht.bdHTCapBuf[4];
163                 else
164                         ht_cap = (struct ht_capab_ele *)
165                                  &network->bssht.bdHTCapBuf[0];
166                 is40M = (ht_cap->ChlWidth) ? 1 : 0;
167                 isShortGI = (ht_cap->ChlWidth) ?
168                                 ((ht_cap->ShortGI40Mhz) ? 1 : 0) :
169                                 ((ht_cap->ShortGI20Mhz) ? 1 : 0);
170
171                 max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS,
172                                               MCS_FILTER_ALL);
173                 rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f];
174                 if (rate > max_rate)
175                         max_rate = rate;
176         }
177         iwe.cmd = SIOCGIWRATE;
178         iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
179         iwe.u.bitrate.value = max_rate * 500000;
180         start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
181                                      IW_EV_PARAM_LEN);
182         iwe.cmd = IWEVCUSTOM;
183         iwe.u.data.length = p - custom;
184         if (iwe.u.data.length)
185                 start = iwe_stream_add_point_rsl(info, start, stop,
186                                                  &iwe, custom);
187         /* Add quality statistics */
188         /* TODO: Fix these values... */
189         iwe.cmd = IWEVQUAL;
190         iwe.u.qual.qual = network->stats.signal;
191         iwe.u.qual.level = network->stats.rssi;
192         iwe.u.qual.noise = network->stats.noise;
193         iwe.u.qual.updated = network->stats.mask & RTLLIB_STATMASK_WEMASK;
194         if (!(network->stats.mask & RTLLIB_STATMASK_RSSI))
195                 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
196         if (!(network->stats.mask & RTLLIB_STATMASK_NOISE))
197                 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
198         if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL))
199                 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
200         iwe.u.qual.updated = 7;
201         start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
202                                          IW_EV_QUAL_LEN);
203
204         iwe.cmd = IWEVCUSTOM;
205         p = custom;
206         iwe.u.data.length = p - custom;
207         if (iwe.u.data.length)
208                 start = iwe_stream_add_point_rsl(info, start, stop,
209                                                  &iwe, custom);
210
211         memset(&iwe, 0, sizeof(iwe));
212         if (network->wpa_ie_len) {
213                 char buf[MAX_WPA_IE_LEN];
214
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
224                 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
225                 iwe.cmd = IWEVGENIE;
226                 iwe.u.data.length = network->rsn_ie_len;
227                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
228         }
229
230         /* add info for WZC */
231         memset(&iwe, 0, sizeof(iwe));
232         if (network->wzc_ie_len) {
233                 char buf[MAX_WZC_IE_LEN];
234
235                 memcpy(buf, network->wzc_ie, network->wzc_ie_len);
236                 iwe.cmd = IWEVGENIE;
237                 iwe.u.data.length = network->wzc_ie_len;
238                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
239         }
240
241         /* Add EXTRA: Age to display seconds since last beacon/probe response
242          * for given network.
243          */
244         iwe.cmd = IWEVCUSTOM;
245         p = custom;
246         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
247                       " Last beacon: %lums ago",
248                       (jiffies - network->last_scanned) / (HZ / 100));
249         iwe.u.data.length = p - custom;
250         if (iwe.u.data.length)
251                 start = iwe_stream_add_point_rsl(info, start, stop,
252                                                  &iwe, custom);
253
254         return start;
255 }
256
257 int rtllib_wx_get_scan(struct rtllib_device *ieee,
258                           struct iw_request_info *info,
259                           union iwreq_data *wrqu, char *extra)
260 {
261         struct rtllib_network *network;
262         unsigned long flags;
263
264         char *ev = extra;
265         char *stop = ev + wrqu->data.length;
266         int i = 0;
267         int err = 0;
268
269         netdev_dbg(ieee->dev, "Getting scan\n");
270         down(&ieee->wx_sem);
271         spin_lock_irqsave(&ieee->lock, flags);
272
273         list_for_each_entry(network, &ieee->network_list, list) {
274                 i++;
275                 if ((stop - ev) < 200) {
276                         err = -E2BIG;
277                         break;
278                 }
279                 if (ieee->scan_age == 0 ||
280                     time_after(network->last_scanned + ieee->scan_age, jiffies))
281                         ev = rtl819x_translate_scan(ieee, ev, stop, network,
282                                                     info);
283                 else
284                         netdev_dbg(ieee->dev,
285                                    "Network '%s ( %pM)' hidden due to age (%lums).\n",
286                                    escape_essid(network->ssid,
287                                                 network->ssid_len),
288                                    network->bssid,
289                                    (jiffies - network->last_scanned) /
290                                    (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         netdev_dbg(ieee->dev, "%s(): %d networks returned.\n", __func__, 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         netdev_dbg(ieee->dev, "%s()\n", __func__);
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         netdev_dbg(ieee->dev, "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                         netdev_dbg(ieee->dev,
335                                    "Disabling encryption on key %d.\n", key);
336                         lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
337                 } else
338                         netdev_dbg(ieee->dev, "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                  */
343                 for (i = 0; i < NUM_WEP_KEYS; i++) {
344                         if (ieee->crypt_info.crypt[i] != NULL) {
345                                 if (key_provided)
346                                         break;
347                                 lib80211_crypt_delayed_deinit(&ieee->crypt_info,
348                                                     &ieee->crypt_info.crypt[i]);
349                         }
350                 }
351
352                 if (i == NUM_WEP_KEYS) {
353                         sec.enabled = 0;
354                         sec.level = SEC_LEVEL_0;
355                         sec.flags |= SEC_ENABLED | SEC_LEVEL;
356                 }
357
358                 goto done;
359         }
360
361
362
363         sec.enabled = 1;
364         sec.flags |= SEC_ENABLED;
365
366         if (*crypt != NULL && (*crypt)->ops != NULL &&
367             strcmp((*crypt)->ops->name, "R-WEP") != 0) {
368                 /* changing to use WEP; deinit previously used algorithm
369                  * on this key
370                  */
371                 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
372         }
373
374         if (*crypt == NULL) {
375                 struct lib80211_crypt_data *new_crypt;
376
377                 /* take WEP into use */
378                 new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
379                                     GFP_KERNEL);
380                 if (new_crypt == NULL)
381                         return -ENOMEM;
382                 new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
383                 if (!new_crypt->ops) {
384                         request_module("rtllib_crypt_wep");
385                         new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
386                 }
387
388                 if (new_crypt->ops)
389                         new_crypt->priv = new_crypt->ops->init(key);
390
391                 if (!new_crypt->ops || !new_crypt->priv) {
392                         kfree(new_crypt);
393                         new_crypt = NULL;
394
395                         netdev_warn(dev,
396                                     "%s: could not initialize WEP: load module rtllib_crypt_wep\n",
397                                     dev->name);
398                         return -EOPNOTSUPP;
399                 }
400                 *crypt = new_crypt;
401         }
402
403         /* If a new key was provided, set it up */
404         if (erq->length > 0) {
405                 len = erq->length <= 5 ? 5 : 13;
406                 memcpy(sec.keys[key], keybuf, erq->length);
407                 if (len > erq->length)
408                         memset(sec.keys[key] + erq->length, 0,
409                                len - erq->length);
410                 netdev_dbg(ieee->dev, "Setting key %d to '%s' (%d:%d bytes)\n",
411                            key, escape_essid(sec.keys[key], len), erq->length,
412                            len);
413                 sec.key_sizes[key] = len;
414                 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
415                                        (*crypt)->priv);
416                 sec.flags |= (1 << key);
417                 /* This ensures a key will be activated if no key is
418                  * explicitly set
419                  */
420                 if (key == sec.active_key)
421                         sec.flags |= SEC_ACTIVE_KEY;
422                 ieee->crypt_info.tx_keyidx = key;
423
424         } else {
425                 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
426                                              NULL, (*crypt)->priv);
427                 if (len == 0) {
428                         /* Set a default key of all 0 */
429                         netdev_info(ieee->dev, "Setting key %d to all zero.\n",
430                                            key);
431
432                         memset(sec.keys[key], 0, 13);
433                         (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
434                                                (*crypt)->priv);
435                         sec.key_sizes[key] = 13;
436                         sec.flags |= (1 << key);
437                 }
438
439                 /* No key data - just set the default TX key index */
440                 if (key_provided) {
441                         netdev_dbg(ieee->dev,
442                                    "Setting key %d as default Tx key.\n", key);
443                         ieee->crypt_info.tx_keyidx = key;
444                         sec.active_key = key;
445                         sec.flags |= SEC_ACTIVE_KEY;
446                 }
447         }
448  done:
449         ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
450         ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
451                           WLAN_AUTH_SHARED_KEY;
452         sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
453         sec.flags |= SEC_AUTH_MODE;
454         netdev_dbg(ieee->dev, "Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
455                            "OPEN" : "SHARED KEY");
456
457         /* For now we just support WEP, so only set that security level...
458          * TODO: When WPA is added this is one place that needs to change
459          */
460         sec.flags |= SEC_LEVEL;
461         sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
462
463         if (ieee->set_security)
464                 ieee->set_security(dev, &sec);
465
466         /* Do not reset port if card is in Managed mode since resetting will
467          * generate new IEEE 802.11 authentication which may end up in looping
468          * with IEEE 802.1X.  If your hardware requires a reset after WEP
469          * configuration (for example... Prism2), implement the reset_port in
470          * the callbacks structures used to initialize the 802.11 stack.
471          */
472         if (ieee->reset_on_keychange &&
473             ieee->iw_mode != IW_MODE_INFRA &&
474             ieee->reset_port && ieee->reset_port(dev)) {
475                 netdev_dbg(dev, "%s: reset_port failed\n", dev->name);
476                 return -EINVAL;
477         }
478         return 0;
479 }
480 EXPORT_SYMBOL(rtllib_wx_set_encode);
481
482 int rtllib_wx_get_encode(struct rtllib_device *ieee,
483                             struct iw_request_info *info,
484                             union iwreq_data *wrqu, char *keybuf)
485 {
486         struct iw_point *erq = &(wrqu->encoding);
487         int len, key;
488         struct lib80211_crypt_data *crypt;
489
490         netdev_dbg(ieee->dev, "%s()\n", __func__);
491
492         if (ieee->iw_mode == IW_MODE_MONITOR)
493                 return -1;
494
495         key = erq->flags & IW_ENCODE_INDEX;
496         if (key) {
497                 if (key > NUM_WEP_KEYS)
498                         return -EINVAL;
499                 key--;
500         } else {
501                 key = ieee->crypt_info.tx_keyidx;
502         }
503         crypt = ieee->crypt_info.crypt[key];
504
505         erq->flags = key + 1;
506
507         if (crypt == NULL || crypt->ops == NULL) {
508                 erq->length = 0;
509                 erq->flags |= IW_ENCODE_DISABLED;
510                 return 0;
511         }
512         len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
513
514         erq->length = max(len, 0);
515
516         erq->flags |= IW_ENCODE_ENABLED;
517
518         if (ieee->open_wep)
519                 erq->flags |= IW_ENCODE_OPEN;
520         else
521                 erq->flags |= IW_ENCODE_RESTRICTED;
522
523         return 0;
524 }
525 EXPORT_SYMBOL(rtllib_wx_get_encode);
526
527 int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
528                                struct iw_request_info *info,
529                                union iwreq_data *wrqu, char *extra)
530 {
531         int ret = 0;
532         struct net_device *dev = ieee->dev;
533         struct iw_point *encoding = &wrqu->encoding;
534         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
535         int i, idx;
536         int group_key = 0;
537         const char *alg, *module;
538         struct lib80211_crypto_ops *ops;
539         struct lib80211_crypt_data **crypt;
540
541         struct rtllib_security sec = {
542                 .flags = 0,
543         };
544         idx = encoding->flags & IW_ENCODE_INDEX;
545         if (idx) {
546                 if (idx < 1 || idx > NUM_WEP_KEYS)
547                         return -EINVAL;
548                 idx--;
549         } else{
550                         idx = ieee->crypt_info.tx_keyidx;
551         }
552         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
553                 crypt = &ieee->crypt_info.crypt[idx];
554                 group_key = 1;
555         } else {
556                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
557                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
558                         return -EINVAL;
559                 if (ieee->iw_mode == IW_MODE_INFRA)
560                         crypt = &ieee->crypt_info.crypt[idx];
561                 else
562                         return -EINVAL;
563         }
564
565         sec.flags |= SEC_ENABLED;
566         if ((encoding->flags & IW_ENCODE_DISABLED) ||
567             ext->alg == IW_ENCODE_ALG_NONE) {
568                 if (*crypt)
569                         lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
570
571                 for (i = 0; i < NUM_WEP_KEYS; i++) {
572                         if (ieee->crypt_info.crypt[i] != NULL)
573                                 break;
574                 }
575                 if (i == NUM_WEP_KEYS) {
576                         sec.enabled = 0;
577                         sec.level = SEC_LEVEL_0;
578                         sec.flags |= SEC_LEVEL;
579                 }
580                 goto done;
581         }
582
583         sec.enabled = 1;
584         switch (ext->alg) {
585         case IW_ENCODE_ALG_WEP:
586                 alg = "R-WEP";
587                 module = "rtllib_crypt_wep";
588                 break;
589         case IW_ENCODE_ALG_TKIP:
590                 alg = "R-TKIP";
591                 module = "rtllib_crypt_tkip";
592                 break;
593         case IW_ENCODE_ALG_CCMP:
594                 alg = "R-CCMP";
595                 module = "rtllib_crypt_ccmp";
596                 break;
597         default:
598                 netdev_dbg(ieee->dev, "Unknown crypto alg %d\n", ext->alg);
599                 ret = -EINVAL;
600                 goto done;
601         }
602         netdev_info(dev, "alg name:%s\n", alg);
603
604         ops = lib80211_get_crypto_ops(alg);
605         if (ops == NULL) {
606                 char tempbuf[100];
607
608                 memset(tempbuf, 0x00, 100);
609                 sprintf(tempbuf, "%s", module);
610                 request_module("%s", tempbuf);
611                 ops = lib80211_get_crypto_ops(alg);
612         }
613         if (ops == NULL) {
614                 netdev_info(dev, "========>unknown crypto alg %d\n", ext->alg);
615                 ret = -EINVAL;
616                 goto done;
617         }
618
619         if (*crypt == NULL || (*crypt)->ops != ops) {
620                 struct lib80211_crypt_data *new_crypt;
621
622                 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
623
624                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
625                 if (new_crypt == NULL) {
626                         ret = -ENOMEM;
627                         goto done;
628                 }
629                 new_crypt->ops = ops;
630                 if (new_crypt->ops)
631                         new_crypt->priv = new_crypt->ops->init(idx);
632
633                 if (new_crypt->priv == NULL) {
634                         kfree(new_crypt);
635                         ret = -EINVAL;
636                         goto done;
637                 }
638                 *crypt = new_crypt;
639
640         }
641
642         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
643             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
644                                    (*crypt)->priv) < 0) {
645                 netdev_info(dev, "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                 netdev_dbg(ieee->dev, "Port reset failed\n");
679                 return -EINVAL;
680         }
681         return ret;
682 }
683 EXPORT_SYMBOL(rtllib_wx_set_encode_ext);
684
685 int rtllib_wx_set_mlme(struct rtllib_device *ieee,
686                                struct iw_request_info *info,
687                                union iwreq_data *wrqu, char *extra)
688 {
689         u8 i = 0;
690         bool deauth = false;
691         struct iw_mlme *mlme = (struct iw_mlme *) extra;
692
693         if (ieee->state != RTLLIB_LINKED)
694                 return -ENOLINK;
695
696         down(&ieee->wx_sem);
697
698         switch (mlme->cmd) {
699         case IW_MLME_DEAUTH:
700                 deauth = true;
701                 /* leave break out intentionly */
702
703         case IW_MLME_DISASSOC:
704                 if (deauth)
705                         netdev_info(ieee->dev, "disauth packet !\n");
706                 else
707                         netdev_info(ieee->dev, "dis associate packet!\n");
708
709                 ieee->cannot_notify = true;
710
711                 SendDisassociation(ieee, deauth, mlme->reason_code);
712                 rtllib_disassociate(ieee);
713
714                 ieee->wap_set = 0;
715                 for (i = 0; i < 6; i++)
716                         ieee->current_network.bssid[i] = 0x55;
717
718                 ieee->ssid_set = 0;
719                 ieee->current_network.ssid[0] = '\0';
720                 ieee->current_network.ssid_len = 0;
721                 break;
722         default:
723                 up(&ieee->wx_sem);
724                 return -EOPNOTSUPP;
725         }
726
727         up(&ieee->wx_sem);
728
729         return 0;
730 }
731 EXPORT_SYMBOL(rtllib_wx_set_mlme);
732
733 int rtllib_wx_set_auth(struct rtllib_device *ieee,
734                                struct iw_request_info *info,
735                                struct iw_param *data, char *extra)
736 {
737         switch (data->flags & IW_AUTH_INDEX) {
738         case IW_AUTH_WPA_VERSION:
739                 break;
740         case IW_AUTH_CIPHER_PAIRWISE:
741         case IW_AUTH_CIPHER_GROUP:
742         case IW_AUTH_KEY_MGMT:
743                 /* Host AP driver does not use these parameters and allows
744                  * wpa_supplicant to control them internally.
745                  */
746                 break;
747         case IW_AUTH_TKIP_COUNTERMEASURES:
748                 ieee->tkip_countermeasures = data->value;
749                 break;
750         case IW_AUTH_DROP_UNENCRYPTED:
751                 ieee->drop_unencrypted = data->value;
752                 break;
753
754         case IW_AUTH_80211_AUTH_ALG:
755                 if (data->value & IW_AUTH_ALG_SHARED_KEY) {
756                         ieee->open_wep = 0;
757                         ieee->auth_mode = 1;
758                 } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) {
759                         ieee->open_wep = 1;
760                         ieee->auth_mode = 0;
761                 } else if (data->value & IW_AUTH_ALG_LEAP) {
762                         ieee->open_wep = 1;
763                         ieee->auth_mode = 2;
764                 } else
765                         return -EINVAL;
766                 break;
767
768         case IW_AUTH_WPA_ENABLED:
769                 ieee->wpa_enabled = (data->value) ? 1 : 0;
770                 break;
771
772         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
773                 ieee->ieee802_1x = data->value;
774                 break;
775         case IW_AUTH_PRIVACY_INVOKED:
776                 ieee->privacy_invoked = data->value;
777                 break;
778         default:
779                 return -EOPNOTSUPP;
780         }
781         return 0;
782 }
783 EXPORT_SYMBOL(rtllib_wx_set_auth);
784
785 int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
786 {
787         u8 *buf;
788         u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
789
790         if (len > MAX_WPA_IE_LEN || (len && ie == NULL))
791                 return -EINVAL;
792
793         if (len) {
794                 eid = ie[0];
795                 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2],
796                      wps_oui, 4))) {
797
798                         ieee->wps_ie_len = min_t(size_t, len, MAX_WZC_IE_LEN);
799                         buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL);
800                         if (buf == NULL)
801                                 return -ENOMEM;
802                         ieee->wps_ie = buf;
803                         return 0;
804                 }
805         }
806         ieee->wps_ie_len = 0;
807         kfree(ieee->wps_ie);
808         ieee->wps_ie = NULL;
809         if (len) {
810                 if (len != ie[1]+2)
811                         return -EINVAL;
812                 buf = kmemdup(ie, len, GFP_KERNEL);
813                 if (buf == NULL)
814                         return -ENOMEM;
815                 kfree(ieee->wpa_ie);
816                 ieee->wpa_ie = buf;
817                 ieee->wpa_ie_len = len;
818         } else {
819                 kfree(ieee->wpa_ie);
820                 ieee->wpa_ie = NULL;
821                 ieee->wpa_ie_len = 0;
822         }
823         return 0;
824 }
825 EXPORT_SYMBOL(rtllib_wx_set_gen_ie);