OSDN Git Service

staging: rtl8192e: Replace ?: with min_t
[uclinux-h8/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         erq->length = (len >= 0 ? len : 0);
514
515         erq->flags |= IW_ENCODE_ENABLED;
516
517         if (ieee->open_wep)
518                 erq->flags |= IW_ENCODE_OPEN;
519         else
520                 erq->flags |= IW_ENCODE_RESTRICTED;
521
522         return 0;
523 }
524 EXPORT_SYMBOL(rtllib_wx_get_encode);
525
526 int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
527                                struct iw_request_info *info,
528                                union iwreq_data *wrqu, char *extra)
529 {
530         int ret = 0;
531         struct net_device *dev = ieee->dev;
532         struct iw_point *encoding = &wrqu->encoding;
533         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
534         int i, idx;
535         int group_key = 0;
536         const char *alg, *module;
537         struct lib80211_crypto_ops *ops;
538         struct lib80211_crypt_data **crypt;
539
540         struct rtllib_security sec = {
541                 .flags = 0,
542         };
543         idx = encoding->flags & IW_ENCODE_INDEX;
544         if (idx) {
545                 if (idx < 1 || idx > NUM_WEP_KEYS)
546                         return -EINVAL;
547                 idx--;
548         } else{
549                         idx = ieee->crypt_info.tx_keyidx;
550         }
551         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
552                 crypt = &ieee->crypt_info.crypt[idx];
553                 group_key = 1;
554         } else {
555                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
556                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
557                         return -EINVAL;
558                 if (ieee->iw_mode == IW_MODE_INFRA)
559                         crypt = &ieee->crypt_info.crypt[idx];
560                 else
561                         return -EINVAL;
562         }
563
564         sec.flags |= SEC_ENABLED;
565         if ((encoding->flags & IW_ENCODE_DISABLED) ||
566             ext->alg == IW_ENCODE_ALG_NONE) {
567                 if (*crypt)
568                         lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
569
570                 for (i = 0; i < NUM_WEP_KEYS; i++) {
571                         if (ieee->crypt_info.crypt[i] != NULL)
572                                 break;
573                 }
574                 if (i == NUM_WEP_KEYS) {
575                         sec.enabled = 0;
576                         sec.level = SEC_LEVEL_0;
577                         sec.flags |= SEC_LEVEL;
578                 }
579                 goto done;
580         }
581
582         sec.enabled = 1;
583         switch (ext->alg) {
584         case IW_ENCODE_ALG_WEP:
585                 alg = "R-WEP";
586                 module = "rtllib_crypt_wep";
587                 break;
588         case IW_ENCODE_ALG_TKIP:
589                 alg = "R-TKIP";
590                 module = "rtllib_crypt_tkip";
591                 break;
592         case IW_ENCODE_ALG_CCMP:
593                 alg = "R-CCMP";
594                 module = "rtllib_crypt_ccmp";
595                 break;
596         default:
597                 netdev_dbg(ieee->dev, "Unknown crypto alg %d\n", ext->alg);
598                 ret = -EINVAL;
599                 goto done;
600         }
601         netdev_info(dev, "alg name:%s\n", alg);
602
603         ops = lib80211_get_crypto_ops(alg);
604         if (ops == NULL) {
605                 char tempbuf[100];
606
607                 memset(tempbuf, 0x00, 100);
608                 sprintf(tempbuf, "%s", module);
609                 request_module("%s", tempbuf);
610                 ops = lib80211_get_crypto_ops(alg);
611         }
612         if (ops == NULL) {
613                 netdev_info(dev, "========>unknown crypto alg %d\n", ext->alg);
614                 ret = -EINVAL;
615                 goto done;
616         }
617
618         if (*crypt == NULL || (*crypt)->ops != ops) {
619                 struct lib80211_crypt_data *new_crypt;
620
621                 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
622
623                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
624                 if (new_crypt == NULL) {
625                         ret = -ENOMEM;
626                         goto done;
627                 }
628                 new_crypt->ops = ops;
629                 if (new_crypt->ops)
630                         new_crypt->priv = new_crypt->ops->init(idx);
631
632                 if (new_crypt->priv == NULL) {
633                         kfree(new_crypt);
634                         ret = -EINVAL;
635                         goto done;
636                 }
637                 *crypt = new_crypt;
638
639         }
640
641         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
642             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
643                                    (*crypt)->priv) < 0) {
644                 netdev_info(dev, "key setting failed\n");
645                 ret = -EINVAL;
646                 goto done;
647         }
648         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
649                 ieee->crypt_info.tx_keyidx = idx;
650                 sec.active_key = idx;
651                 sec.flags |= SEC_ACTIVE_KEY;
652         }
653         if (ext->alg != IW_ENCODE_ALG_NONE) {
654                 sec.key_sizes[idx] = ext->key_len;
655                 sec.flags |= (1 << idx);
656                 if (ext->alg == IW_ENCODE_ALG_WEP) {
657                         sec.flags |= SEC_LEVEL;
658                         sec.level = SEC_LEVEL_1;
659                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
660                         sec.flags |= SEC_LEVEL;
661                         sec.level = SEC_LEVEL_2;
662                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
663                         sec.flags |= SEC_LEVEL;
664                         sec.level = SEC_LEVEL_3;
665                 }
666                 /* Don't set sec level for group keys. */
667                 if (group_key)
668                         sec.flags &= ~SEC_LEVEL;
669         }
670 done:
671         if (ieee->set_security)
672                 ieee->set_security(ieee->dev, &sec);
673
674          if (ieee->reset_on_keychange &&
675             ieee->iw_mode != IW_MODE_INFRA &&
676             ieee->reset_port && ieee->reset_port(dev)) {
677                 netdev_dbg(ieee->dev, "Port reset failed\n");
678                 return -EINVAL;
679         }
680         return ret;
681 }
682 EXPORT_SYMBOL(rtllib_wx_set_encode_ext);
683
684 int rtllib_wx_get_encode_ext(struct rtllib_device *ieee,
685                                struct iw_request_info *info,
686                                union iwreq_data *wrqu, char *extra)
687 {
688         struct iw_point *encoding = &wrqu->encoding;
689         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
690         struct lib80211_crypt_data *crypt;
691         int idx, max_key_len;
692
693         max_key_len = encoding->length - sizeof(*ext);
694         if (max_key_len < 0)
695                 return -EINVAL;
696
697         idx = encoding->flags & IW_ENCODE_INDEX;
698         if (idx) {
699                 if (idx < 1 || idx > NUM_WEP_KEYS)
700                         return -EINVAL;
701                 idx--;
702         } else {
703                 idx = ieee->crypt_info.tx_keyidx;
704         }
705         if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
706             (ext->alg != IW_ENCODE_ALG_WEP))
707                 if (idx != 0 || (ieee->iw_mode != IW_MODE_INFRA))
708                         return -EINVAL;
709
710         crypt = ieee->crypt_info.crypt[idx];
711
712         encoding->flags = idx + 1;
713         memset(ext, 0, sizeof(*ext));
714
715         if (crypt == NULL || crypt->ops == NULL) {
716                 ext->alg = IW_ENCODE_ALG_NONE;
717                 ext->key_len = 0;
718                 encoding->flags |= IW_ENCODE_DISABLED;
719         } else {
720                 if (strcmp(crypt->ops->name, "R-WEP") == 0)
721                         ext->alg = IW_ENCODE_ALG_WEP;
722                 else if (strcmp(crypt->ops->name, "R-TKIP"))
723                         ext->alg = IW_ENCODE_ALG_TKIP;
724                 else if (strcmp(crypt->ops->name, "R-CCMP"))
725                         ext->alg = IW_ENCODE_ALG_CCMP;
726                 else
727                         return -EINVAL;
728                 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN,
729                                                    NULL, crypt->priv);
730                 encoding->flags |= IW_ENCODE_ENABLED;
731                 if (ext->key_len &&
732                     (ext->alg == IW_ENCODE_ALG_TKIP ||
733                      ext->alg == IW_ENCODE_ALG_CCMP))
734                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
735
736         }
737
738         return 0;
739 }
740
741 int rtllib_wx_set_mlme(struct rtllib_device *ieee,
742                                struct iw_request_info *info,
743                                union iwreq_data *wrqu, char *extra)
744 {
745         u8 i = 0;
746         bool deauth = false;
747         struct iw_mlme *mlme = (struct iw_mlme *) extra;
748
749         if (ieee->state != RTLLIB_LINKED)
750                 return -ENOLINK;
751
752         down(&ieee->wx_sem);
753
754         switch (mlme->cmd) {
755         case IW_MLME_DEAUTH:
756                 deauth = true;
757                 /* leave break out intentionly */
758
759         case IW_MLME_DISASSOC:
760                 if (deauth)
761                         netdev_info(ieee->dev, "disauth packet !\n");
762                 else
763                         netdev_info(ieee->dev, "dis associate packet!\n");
764
765                 ieee->cannot_notify = true;
766
767                 SendDisassociation(ieee, deauth, mlme->reason_code);
768                 rtllib_disassociate(ieee);
769
770                 ieee->wap_set = 0;
771                 for (i = 0; i < 6; i++)
772                         ieee->current_network.bssid[i] = 0x55;
773
774                 ieee->ssid_set = 0;
775                 ieee->current_network.ssid[0] = '\0';
776                 ieee->current_network.ssid_len = 0;
777                 break;
778         default:
779                 up(&ieee->wx_sem);
780                 return -EOPNOTSUPP;
781         }
782
783         up(&ieee->wx_sem);
784
785         return 0;
786 }
787 EXPORT_SYMBOL(rtllib_wx_set_mlme);
788
789 int rtllib_wx_set_auth(struct rtllib_device *ieee,
790                                struct iw_request_info *info,
791                                struct iw_param *data, char *extra)
792 {
793         switch (data->flags & IW_AUTH_INDEX) {
794         case IW_AUTH_WPA_VERSION:
795                 break;
796         case IW_AUTH_CIPHER_PAIRWISE:
797         case IW_AUTH_CIPHER_GROUP:
798         case IW_AUTH_KEY_MGMT:
799                 /* Host AP driver does not use these parameters and allows
800                  * wpa_supplicant to control them internally.
801                  */
802                 break;
803         case IW_AUTH_TKIP_COUNTERMEASURES:
804                 ieee->tkip_countermeasures = data->value;
805                 break;
806         case IW_AUTH_DROP_UNENCRYPTED:
807                 ieee->drop_unencrypted = data->value;
808                 break;
809
810         case IW_AUTH_80211_AUTH_ALG:
811                 if (data->value & IW_AUTH_ALG_SHARED_KEY) {
812                         ieee->open_wep = 0;
813                         ieee->auth_mode = 1;
814                 } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) {
815                         ieee->open_wep = 1;
816                         ieee->auth_mode = 0;
817                 } else if (data->value & IW_AUTH_ALG_LEAP) {
818                         ieee->open_wep = 1;
819                         ieee->auth_mode = 2;
820                 } else
821                         return -EINVAL;
822                 break;
823
824         case IW_AUTH_WPA_ENABLED:
825                 ieee->wpa_enabled = (data->value) ? 1 : 0;
826                 break;
827
828         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
829                 ieee->ieee802_1x = data->value;
830                 break;
831         case IW_AUTH_PRIVACY_INVOKED:
832                 ieee->privacy_invoked = data->value;
833                 break;
834         default:
835                 return -EOPNOTSUPP;
836         }
837         return 0;
838 }
839 EXPORT_SYMBOL(rtllib_wx_set_auth);
840
841 int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
842 {
843         u8 *buf;
844         u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
845
846         if (len > MAX_WPA_IE_LEN || (len && ie == NULL))
847                 return -EINVAL;
848
849         if (len) {
850                 eid = ie[0];
851                 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2],
852                      wps_oui, 4))) {
853
854                         ieee->wps_ie_len = min_t(size_t, len, MAX_WZC_IE_LEN);
855                         buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL);
856                         if (buf == NULL)
857                                 return -ENOMEM;
858                         ieee->wps_ie = buf;
859                         return 0;
860                 }
861         }
862         ieee->wps_ie_len = 0;
863         kfree(ieee->wps_ie);
864         ieee->wps_ie = NULL;
865         if (len) {
866                 if (len != ie[1]+2)
867                         return -EINVAL;
868                 buf = kmemdup(ie, len, GFP_KERNEL);
869                 if (buf == NULL)
870                         return -ENOMEM;
871                 kfree(ieee->wpa_ie);
872                 ieee->wpa_ie = buf;
873                 ieee->wpa_ie_len = len;
874         } else {
875                 kfree(ieee->wpa_ie);
876                 ieee->wpa_ie = NULL;
877                 ieee->wpa_ie_len = 0;
878         }
879         return 0;
880 }
881 EXPORT_SYMBOL(rtllib_wx_set_gen_ie);