staging: rtl8192e: Replace ?: with max
[pandora-kernel.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_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                         netdev_info(ieee->dev, "disauth packet !\n");
763                 else
764                         netdev_info(ieee->dev, "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                 /* Host AP driver does not use these parameters and allows
801                  * wpa_supplicant to control them internally.
802                  */
803                 break;
804         case IW_AUTH_TKIP_COUNTERMEASURES:
805                 ieee->tkip_countermeasures = data->value;
806                 break;
807         case IW_AUTH_DROP_UNENCRYPTED:
808                 ieee->drop_unencrypted = data->value;
809                 break;
810
811         case IW_AUTH_80211_AUTH_ALG:
812                 if (data->value & IW_AUTH_ALG_SHARED_KEY) {
813                         ieee->open_wep = 0;
814                         ieee->auth_mode = 1;
815                 } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) {
816                         ieee->open_wep = 1;
817                         ieee->auth_mode = 0;
818                 } else if (data->value & IW_AUTH_ALG_LEAP) {
819                         ieee->open_wep = 1;
820                         ieee->auth_mode = 2;
821                 } else
822                         return -EINVAL;
823                 break;
824
825         case IW_AUTH_WPA_ENABLED:
826                 ieee->wpa_enabled = (data->value) ? 1 : 0;
827                 break;
828
829         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
830                 ieee->ieee802_1x = data->value;
831                 break;
832         case IW_AUTH_PRIVACY_INVOKED:
833                 ieee->privacy_invoked = data->value;
834                 break;
835         default:
836                 return -EOPNOTSUPP;
837         }
838         return 0;
839 }
840 EXPORT_SYMBOL(rtllib_wx_set_auth);
841
842 int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
843 {
844         u8 *buf;
845         u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
846
847         if (len > MAX_WPA_IE_LEN || (len && ie == NULL))
848                 return -EINVAL;
849
850         if (len) {
851                 eid = ie[0];
852                 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2],
853                      wps_oui, 4))) {
854
855                         ieee->wps_ie_len = min_t(size_t, len, MAX_WZC_IE_LEN);
856                         buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL);
857                         if (buf == NULL)
858                                 return -ENOMEM;
859                         ieee->wps_ie = buf;
860                         return 0;
861                 }
862         }
863         ieee->wps_ie_len = 0;
864         kfree(ieee->wps_ie);
865         ieee->wps_ie = NULL;
866         if (len) {
867                 if (len != ie[1]+2)
868                         return -EINVAL;
869                 buf = kmemdup(ie, len, GFP_KERNEL);
870                 if (buf == NULL)
871                         return -ENOMEM;
872                 kfree(ieee->wpa_ie);
873                 ieee->wpa_ie = buf;
874                 ieee->wpa_ie_len = len;
875         } else {
876                 kfree(ieee->wpa_ie);
877                 ieee->wpa_ie = NULL;
878                 ieee->wpa_ie_len = 0;
879         }
880         return 0;
881 }
882 EXPORT_SYMBOL(rtllib_wx_set_gen_ie);