]> Pileus Git - ~andy/linux/blob - drivers/staging/rtl8192e/rtllib_wx.c
0855ad8a0f6e703b84ac41229a348c2ae4753a4e
[~andy/linux] / 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/version.h>
34 #include <linux/kmod.h>
35 #include <linux/module.h>
36
37 #include "rtllib.h"
38 struct modes_unit {
39         char *mode_string;
40         int mode_size;
41 };
42 static struct modes_unit rtllib_modes[] = {
43         {"a",1},
44         {"b",1},
45         {"g",1},
46         {"?",1},
47         {"N-24G",5},
48         {"N-5G",4},
49 };
50
51 #define MAX_CUSTOM_LEN 64
52 static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
53                                            char *start, char *stop,
54                                            struct rtllib_network *network,
55                                            struct iw_request_info *info)
56 {
57         char custom[MAX_CUSTOM_LEN];
58         char proto_name[IFNAMSIZ];
59         char *pname = proto_name;
60         char *p;
61         struct iw_event iwe;
62         int i, j;
63         u16 max_rate, rate;
64         static u8       EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
65
66         /* First entry *MUST* be the AP MAC address */
67         iwe.cmd = SIOCGIWAP;
68         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
69         memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
70         start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN);
71         /* Remaining entries will be displayed in the order we provide them */
72
73         /* Add the ESSID */
74         iwe.cmd = SIOCGIWESSID;
75         iwe.u.data.flags = 1;
76         if (network->ssid_len > 0){
77                 iwe.u.data.length = min(network->ssid_len, (u8)32);
78                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, network->ssid);
79         }else if (network->hidden_ssid_len == 0){
80                 iwe.u.data.length = sizeof("<hidden>");
81                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, "<hidden>");
82         }else {
83                 iwe.u.data.length = min(network->hidden_ssid_len, (u8)32);
84                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, network->hidden_ssid);
85         }
86         /* Add the protocol name */
87         iwe.cmd = SIOCGIWNAME;
88         for (i=0; i<(sizeof(rtllib_modes)/sizeof(rtllib_modes[0])); i++) {
89                 if (network->mode&(1<<i)) {
90                         sprintf(pname,rtllib_modes[i].mode_string,rtllib_modes[i].mode_size);
91                         pname +=rtllib_modes[i].mode_size;
92                 }
93         }
94         *pname = '\0';
95         snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
96         start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN);
97         /* Add mode */
98         iwe.cmd = SIOCGIWMODE;
99         if (network->capability &
100             (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
101                 if (network->capability & WLAN_CAPABILITY_ESS)
102                         iwe.u.mode = IW_MODE_MASTER;
103                 else
104                         iwe.u.mode = IW_MODE_ADHOC;
105                 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN);
106         }
107
108         /* Add frequency/channel */
109         iwe.cmd = SIOCGIWFREQ;
110 /*      iwe.u.freq.m = rtllib_frequency(network->channel, network->mode);
111         iwe.u.freq.e = 3; */
112         iwe.u.freq.m = network->channel;
113         iwe.u.freq.e = 0;
114         iwe.u.freq.i = 0;
115         start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN);
116
117         /* Add encryption capability */
118         iwe.cmd = SIOCGIWENCODE;
119         if (network->capability & WLAN_CAPABILITY_PRIVACY)
120                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
121         else
122                 iwe.u.data.flags = IW_ENCODE_DISABLED;
123         iwe.u.data.length = 0;
124         start = iwe_stream_add_point_rsl(info, start, stop, &iwe, network->ssid);
125         /* Add basic and extended rates */
126         max_rate = 0;
127         p = custom;
128         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
129         for (i = 0, j = 0; i < network->rates_len; ) {
130                 if (j < network->rates_ex_len &&
131                     ((network->rates_ex[j] & 0x7F) <
132                      (network->rates[i] & 0x7F)))
133                         rate = network->rates_ex[j++] & 0x7F;
134                 else
135                         rate = network->rates[i++] & 0x7F;
136                 if (rate > max_rate)
137                         max_rate = rate;
138                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
139                               "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
140         }
141         for (; j < network->rates_ex_len; j++) {
142                 rate = network->rates_ex[j] & 0x7F;
143                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
144                               "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
145                 if (rate > max_rate)
146                         max_rate = rate;
147         }
148
149         if (network->mode >= IEEE_N_24G)
150         {
151                 PHT_CAPABILITY_ELE ht_cap = NULL;
152                 bool is40M = false, isShortGI = false;
153                 u8 max_mcs = 0;
154                 if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
155                         ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4];
156                 else
157                         ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0];
158                 is40M = (ht_cap->ChlWidth)?1:0;
159                 isShortGI = (ht_cap->ChlWidth)?
160                                                 ((ht_cap->ShortGI40Mhz)?1:0):
161                                                 ((ht_cap->ShortGI20Mhz)?1:0);
162
163                 max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL);
164                 rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f];
165                 if (rate > max_rate)
166                         max_rate = rate;
167         }
168         iwe.cmd = SIOCGIWRATE;
169         iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
170         iwe.u.bitrate.value = max_rate * 500000;
171         start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
172                                      IW_EV_PARAM_LEN);
173         iwe.cmd = IWEVCUSTOM;
174         iwe.u.data.length = p - custom;
175         if (iwe.u.data.length)
176                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, custom);
177         /* Add quality statistics */
178         /* TODO: Fix these values... */
179         iwe.cmd = IWEVQUAL;
180         iwe.u.qual.qual = network->stats.signal;
181         iwe.u.qual.level = network->stats.rssi;
182         iwe.u.qual.noise = network->stats.noise;
183         iwe.u.qual.updated = network->stats.mask & RTLLIB_STATMASK_WEMASK;
184         if (!(network->stats.mask & RTLLIB_STATMASK_RSSI))
185                 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
186         if (!(network->stats.mask & RTLLIB_STATMASK_NOISE))
187                 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
188         if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL))
189                 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
190         iwe.u.qual.updated = 7;
191         start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN);
192
193         iwe.cmd = IWEVCUSTOM;
194         p = custom;
195         iwe.u.data.length = p - custom;
196         if (iwe.u.data.length)
197                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, custom);
198
199         memset(&iwe, 0, sizeof(iwe));
200         if (network->wpa_ie_len)
201         {
202                 char buf[MAX_WPA_IE_LEN];
203                 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
204                 iwe.cmd = IWEVGENIE;
205                 iwe.u.data.length = network->wpa_ie_len;
206                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
207         }
208         memset(&iwe, 0, sizeof(iwe));
209         if (network->rsn_ie_len)
210         {
211                 char buf[MAX_WPA_IE_LEN];
212                 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
213                 iwe.cmd = IWEVGENIE;
214                 iwe.u.data.length = network->rsn_ie_len;
215                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
216         }
217
218 #ifndef CUSTOMER_ID_INTEL_CMPC
219         /* add info for WZC */
220         memset(&iwe, 0, sizeof(iwe));
221         if (network->wzc_ie_len)
222         {
223                 char buf[MAX_WZC_IE_LEN];
224                 memcpy(buf, network->wzc_ie, network->wzc_ie_len);
225                 iwe.cmd = IWEVGENIE;
226                 iwe.u.data.length = network->wzc_ie_len;
227                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
228         }
229 #endif
230
231         /* Add EXTRA: Age to display seconds since last beacon/probe response
232          * for given network. */
233         iwe.cmd = IWEVCUSTOM;
234         p = custom;
235         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
236                       " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
237         iwe.u.data.length = p - custom;
238         if (iwe.u.data.length)
239                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, custom);
240
241         return start;
242 }
243
244 int rtllib_wx_get_scan(struct rtllib_device *ieee,
245                           struct iw_request_info *info,
246                           union iwreq_data *wrqu, char *extra)
247 {
248         struct rtllib_network *network;
249         unsigned long flags;
250
251         char *ev = extra;
252         char *stop = ev + wrqu->data.length;
253         int i = 0;
254         int err = 0;
255         RTLLIB_DEBUG_WX("Getting scan\n");
256         down(&ieee->wx_sem);
257         spin_lock_irqsave(&ieee->lock, flags);
258
259         list_for_each_entry(network, &ieee->network_list, list) {
260                 i++;
261                 if ((stop-ev)<200)
262                 {
263                         err = -E2BIG;
264                         break;
265                                                                                                 }
266                 if (ieee->scan_age == 0 ||
267                     time_after(network->last_scanned + ieee->scan_age, jiffies))
268                         ev = rtl819x_translate_scan(ieee, ev, stop, network, info);
269                 else
270                         RTLLIB_DEBUG_SCAN(
271                                 "Not showing network '%s ("
272                                 MAC_FMT ")' due to age (%lums).\n",
273                                 escape_essid(network->ssid,
274                                              network->ssid_len),
275                                 MAC_ARG(network->bssid),
276                                 (jiffies - network->last_scanned) / (HZ / 100));
277         }
278
279         spin_unlock_irqrestore(&ieee->lock, flags);
280         up(&ieee->wx_sem);
281         wrqu->data.length = ev -  extra;
282         wrqu->data.flags = 0;
283
284         RTLLIB_DEBUG_WX("exit: %d networks returned.\n", i);
285
286         return err;
287 }
288
289 int rtllib_wx_set_encode(struct rtllib_device *ieee,
290                             struct iw_request_info *info,
291                             union iwreq_data *wrqu, char *keybuf)
292 {
293         struct iw_point *erq = &(wrqu->encoding);
294         struct net_device *dev = ieee->dev;
295         struct rtllib_security sec = {
296                 .flags = 0
297         };
298         int i, key, key_provided, len;
299         struct rtllib_crypt_data **crypt;
300
301         RTLLIB_DEBUG_WX("SET_ENCODE\n");
302
303         key = erq->flags & IW_ENCODE_INDEX;
304         if (key) {
305                 if (key > WEP_KEYS)
306                         return -EINVAL;
307                 key--;
308                 key_provided = 1;
309         } else {
310                 key_provided = 0;
311                 key = ieee->tx_keyidx;
312         }
313
314         RTLLIB_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
315                            "provided" : "default");
316         crypt = &ieee->crypt[key];
317         if (erq->flags & IW_ENCODE_DISABLED) {
318                 if (key_provided && *crypt) {
319                         RTLLIB_DEBUG_WX("Disabling encryption on key %d.\n",
320                                            key);
321                         rtllib_crypt_delayed_deinit(ieee, crypt);
322                 } else
323                         RTLLIB_DEBUG_WX("Disabling encryption.\n");
324
325                 /* Check all the keys to see if any are still configured,
326                  * and if no key index was provided, de-init them all */
327                 for (i = 0; i < WEP_KEYS; i++) {
328                         if (ieee->crypt[i] != NULL) {
329                                 if (key_provided)
330                                         break;
331                                 rtllib_crypt_delayed_deinit(ieee, &ieee->crypt[i]);
332                         }
333                 }
334
335                 if (i == WEP_KEYS) {
336                         sec.enabled = 0;
337                         sec.level = SEC_LEVEL_0;
338                         sec.flags |= SEC_ENABLED | SEC_LEVEL;
339                 }
340
341                 goto done;
342         }
343
344
345
346         sec.enabled = 1;
347         sec.flags |= SEC_ENABLED;
348
349         if (*crypt != NULL && (*crypt)->ops != NULL &&
350             strcmp((*crypt)->ops->name, "WEP") != 0) {
351                 /* changing to use WEP; deinit previously used algorithm
352                  * on this key */
353                 rtllib_crypt_delayed_deinit(ieee, crypt);
354         }
355
356         if (*crypt == NULL) {
357                 struct rtllib_crypt_data *new_crypt;
358
359                 /* take WEP into use */
360                 new_crypt = kmalloc(sizeof(struct rtllib_crypt_data),
361                                     GFP_KERNEL);
362                 if (new_crypt == NULL)
363                         return -ENOMEM;
364                 memset(new_crypt, 0, sizeof(struct rtllib_crypt_data));
365                 new_crypt->ops = rtllib_get_crypto_ops("WEP");
366                 if (!new_crypt->ops) {
367                         request_module("rtllib_crypt_wep");
368                         new_crypt->ops = rtllib_get_crypto_ops("WEP");
369                 }
370
371                 if (new_crypt->ops)
372                         new_crypt->priv = new_crypt->ops->init(key);
373
374                 if (!new_crypt->ops || !new_crypt->priv) {
375                         kfree(new_crypt);
376                         new_crypt = NULL;
377
378                         printk(KERN_WARNING "%s: could not initialize WEP: "
379                                "load module rtllib_crypt_wep\n",
380                                dev->name);
381                         return -EOPNOTSUPP;
382                 }
383                 *crypt = new_crypt;
384         }
385
386         /* If a new key was provided, set it up */
387         if (erq->length > 0) {
388                 len = erq->length <= 5 ? 5 : 13;
389                 memcpy(sec.keys[key], keybuf, erq->length);
390                 if (len > erq->length)
391                         memset(sec.keys[key] + erq->length, 0,
392                                len - erq->length);
393                 RTLLIB_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
394                                    key, escape_essid(sec.keys[key], len),
395                                    erq->length, len);
396                 sec.key_sizes[key] = len;
397                 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
398                                        (*crypt)->priv);
399                 sec.flags |= (1 << key);
400                 /* This ensures a key will be activated if no key is
401                  * explicitely set */
402                 if (key == sec.active_key)
403                         sec.flags |= SEC_ACTIVE_KEY;
404                 ieee->tx_keyidx = key;
405
406         } else {
407                 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
408                                              NULL, (*crypt)->priv);
409                 if (len == 0) {
410                         /* Set a default key of all 0 */
411                         printk("Setting key %d to all zero.\n",
412                                            key);
413
414                         RTLLIB_DEBUG_WX("Setting key %d to all zero.\n",
415                                            key);
416                         memset(sec.keys[key], 0, 13);
417                         (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
418                                                (*crypt)->priv);
419                         sec.key_sizes[key] = 13;
420                         sec.flags |= (1 << key);
421                 }
422
423                 /* No key data - just set the default TX key index */
424                 if (key_provided) {
425                         RTLLIB_DEBUG_WX(
426                                 "Setting key %d to default Tx key.\n", key);
427                         ieee->tx_keyidx = key;
428                         sec.active_key = key;
429                         sec.flags |= SEC_ACTIVE_KEY;
430                 }
431         }
432  done:
433         ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
434         ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
435         sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
436         sec.flags |= SEC_AUTH_MODE;
437         RTLLIB_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
438                            "OPEN" : "SHARED KEY");
439
440         /* For now we just support WEP, so only set that security level...
441          * TODO: When WPA is added this is one place that needs to change */
442         sec.flags |= SEC_LEVEL;
443         sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
444
445         if (ieee->set_security)
446                 ieee->set_security(dev, &sec);
447
448         /* Do not reset port if card is in Managed mode since resetting will
449          * generate new IEEE 802.11 authentication which may end up in looping
450          * with IEEE 802.1X.  If your hardware requires a reset after WEP
451          * configuration (for example... Prism2), implement the reset_port in
452          * the callbacks structures used to initialize the 802.11 stack. */
453         if (ieee->reset_on_keychange &&
454             ieee->iw_mode != IW_MODE_INFRA &&
455             ieee->reset_port && ieee->reset_port(dev)) {
456                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
457                 return -EINVAL;
458         }
459         return 0;
460 }
461
462 int rtllib_wx_get_encode(struct rtllib_device *ieee,
463                             struct iw_request_info *info,
464                             union iwreq_data *wrqu, char *keybuf)
465 {
466         struct iw_point *erq = &(wrqu->encoding);
467         int len, key;
468         struct rtllib_crypt_data *crypt;
469
470         RTLLIB_DEBUG_WX("GET_ENCODE\n");
471
472         if (ieee->iw_mode == IW_MODE_MONITOR)
473                 return -1;
474
475         key = erq->flags & IW_ENCODE_INDEX;
476         if (key) {
477                 if (key > WEP_KEYS)
478                         return -EINVAL;
479                 key--;
480         } else {
481                 key = ieee->tx_keyidx;
482         }
483         crypt = ieee->crypt[key];
484
485         erq->flags = key + 1;
486
487         if (crypt == NULL || crypt->ops == NULL) {
488                 erq->length = 0;
489                 erq->flags |= IW_ENCODE_DISABLED;
490                 return 0;
491         }
492         len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
493         erq->length = (len >= 0 ? len : 0);
494
495         erq->flags |= IW_ENCODE_ENABLED;
496
497         if (ieee->open_wep)
498                 erq->flags |= IW_ENCODE_OPEN;
499         else
500                 erq->flags |= IW_ENCODE_RESTRICTED;
501
502         return 0;
503 }
504
505 int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
506                                struct iw_request_info *info,
507                                union iwreq_data *wrqu, char *extra)
508 {
509         int ret = 0;
510         struct net_device *dev = ieee->dev;
511         struct iw_point *encoding = &wrqu->encoding;
512         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
513         int i, idx;
514         int group_key = 0;
515         const char *alg, *module;
516         struct rtllib_crypto_ops *ops;
517         struct rtllib_crypt_data **crypt;
518
519         struct rtllib_security sec = {
520                 .flags = 0,
521         };
522         idx = encoding->flags & IW_ENCODE_INDEX;
523         if (idx) {
524                 if (idx < 1 || idx > WEP_KEYS)
525                         return -EINVAL;
526                 idx--;
527         } else{
528                         idx = ieee->tx_keyidx;
529         }
530         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
531                 crypt = &ieee->crypt[idx];
532                 group_key = 1;
533         } else {
534                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
535                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
536                         return -EINVAL;
537                 if (ieee->iw_mode == IW_MODE_INFRA)
538                         crypt = &ieee->crypt[idx];
539                 else
540                         return -EINVAL;
541         }
542
543         sec.flags |= SEC_ENABLED;
544         if ((encoding->flags & IW_ENCODE_DISABLED) ||
545             ext->alg == IW_ENCODE_ALG_NONE) {
546                 if (*crypt)
547                         rtllib_crypt_delayed_deinit(ieee, crypt);
548
549                 for (i = 0; i < WEP_KEYS; i++) {
550                         if (ieee->crypt[i] != NULL)
551                                 break;
552                 }
553                 if (i == WEP_KEYS) {
554                         sec.enabled = 0;
555                         sec.level = SEC_LEVEL_0;
556                         sec.flags |= SEC_LEVEL;
557                 }
558                 goto done;
559         }
560
561         sec.enabled = 1;
562         switch (ext->alg) {
563         case IW_ENCODE_ALG_WEP:
564                 alg = "WEP";
565                 module = "rtllib_crypt_wep";
566                 break;
567         case IW_ENCODE_ALG_TKIP:
568                 alg = "TKIP";
569                 module = "rtllib_crypt_tkip";
570                 break;
571         case IW_ENCODE_ALG_CCMP:
572                 alg = "CCMP";
573                 module = "rtllib_crypt_ccmp";
574                 break;
575         default:
576                 RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
577                                    dev->name, ext->alg);
578                 ret = -EINVAL;
579                 goto done;
580         }
581         printk("alg name:%s\n",alg);
582
583          ops = rtllib_get_crypto_ops(alg);
584         if (ops == NULL) {
585                 char tempbuf[100];
586
587                 memset( tempbuf, 0x00, 100 );
588                 sprintf( tempbuf, "%s", module);
589                 request_module("%s",tempbuf);
590                 ops = rtllib_get_crypto_ops(alg);
591         }
592         if (ops == NULL) {
593                 RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
594                                    dev->name, ext->alg);
595                 printk("========>unknown crypto alg %d\n", ext->alg);
596                 ret = -EINVAL;
597                 goto done;
598         }
599
600         if (*crypt == NULL || (*crypt)->ops != ops) {
601                 struct rtllib_crypt_data *new_crypt;
602
603                 rtllib_crypt_delayed_deinit(ieee, crypt);
604
605                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
606                 if (new_crypt == NULL) {
607                         ret = -ENOMEM;
608                         goto done;
609                 }
610                 new_crypt->ops = ops;
611                 if (new_crypt->ops)
612                         new_crypt->priv = new_crypt->ops->init(idx);
613
614                 if (new_crypt->priv == NULL) {
615                         kfree(new_crypt);
616                         ret = -EINVAL;
617                         goto done;
618                 }
619                 *crypt = new_crypt;
620
621         }
622
623         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
624             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
625                                    (*crypt)->priv) < 0) {
626                 RTLLIB_DEBUG_WX("%s: key setting failed\n", dev->name);
627                 printk("key setting failed\n");
628                 ret = -EINVAL;
629                 goto done;
630         }
631         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
632                 ieee->tx_keyidx = idx;
633                 sec.active_key = idx;
634                 sec.flags |= SEC_ACTIVE_KEY;
635         }
636         if (ext->alg != IW_ENCODE_ALG_NONE) {
637                 sec.key_sizes[idx] = ext->key_len;
638                 sec.flags |= (1 << idx);
639                 if (ext->alg == IW_ENCODE_ALG_WEP) {
640                         sec.flags |= SEC_LEVEL;
641                         sec.level = SEC_LEVEL_1;
642                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
643                         sec.flags |= SEC_LEVEL;
644                         sec.level = SEC_LEVEL_2;
645                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
646                         sec.flags |= SEC_LEVEL;
647                         sec.level = SEC_LEVEL_3;
648                 }
649                 /* Don't set sec level for group keys. */
650                 if (group_key)
651                         sec.flags &= ~SEC_LEVEL;
652         }
653 done:
654         if (ieee->set_security)
655                 ieee->set_security(ieee->dev, &sec);
656
657          if (ieee->reset_on_keychange &&
658             ieee->iw_mode != IW_MODE_INFRA &&
659             ieee->reset_port && ieee->reset_port(dev)) {
660                 RTLLIB_DEBUG_WX("%s: reset_port failed\n", dev->name);
661                 return -EINVAL;
662         }
663         return ret;
664 }
665
666 int rtllib_wx_get_encode_ext(struct rtllib_device *ieee,
667                                struct iw_request_info *info,
668                                union iwreq_data *wrqu, char *extra)
669 {
670         struct iw_point *encoding = &wrqu->encoding;
671         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
672         struct rtllib_crypt_data *crypt;
673         int idx, max_key_len;
674
675         max_key_len = encoding->length - sizeof(*ext);
676         if (max_key_len < 0)
677                 return -EINVAL;
678
679         idx = encoding->flags & IW_ENCODE_INDEX;
680         if (idx) {
681                 if (idx < 1 || idx > WEP_KEYS)
682                         return -EINVAL;
683                 idx--;
684         } else {
685                 idx = ieee->tx_keyidx;
686         }
687         if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
688             (ext->alg != IW_ENCODE_ALG_WEP))
689                 if (idx != 0 || (ieee->iw_mode != IW_MODE_INFRA))
690                         return -EINVAL;
691
692         crypt = ieee->crypt[idx];
693
694         encoding->flags = idx + 1;
695         memset(ext, 0, sizeof(*ext));
696
697         if (crypt == NULL || crypt->ops == NULL ) {
698                 ext->alg = IW_ENCODE_ALG_NONE;
699                 ext->key_len = 0;
700                 encoding->flags |= IW_ENCODE_DISABLED;
701         } else {
702                 if (strcmp(crypt->ops->name, "WEP") == 0 )
703                         ext->alg = IW_ENCODE_ALG_WEP;
704                 else if (strcmp(crypt->ops->name, "TKIP"))
705                         ext->alg = IW_ENCODE_ALG_TKIP;
706                 else if (strcmp(crypt->ops->name, "CCMP"))
707                         ext->alg = IW_ENCODE_ALG_CCMP;
708                 else
709                         return -EINVAL;
710                 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
711                 encoding->flags |= IW_ENCODE_ENABLED;
712                 if (ext->key_len &&
713                     (ext->alg == IW_ENCODE_ALG_TKIP ||
714                      ext->alg == IW_ENCODE_ALG_CCMP))
715                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
716
717         }
718
719         return 0;
720 }
721
722 int rtllib_wx_set_mlme(struct rtllib_device *ieee,
723                                struct iw_request_info *info,
724                                union iwreq_data *wrqu, char *extra)
725 {
726         u8 i = 0;
727         bool deauth = false;
728         struct iw_mlme *mlme = (struct iw_mlme *) extra;
729
730         if (ieee->state != RTLLIB_LINKED)
731                 return -ENOLINK;
732
733         down(&ieee->wx_sem);
734
735         switch (mlme->cmd) {
736                 case IW_MLME_DEAUTH:
737                         deauth = true;
738                         /* leave break out intentionly */
739
740                 case IW_MLME_DISASSOC:
741                         if (deauth == true)
742                                 printk("disauth packet !\n");
743                         else
744                                 printk("dis associate packet!\n");
745
746                         ieee->cannot_notify = true;
747
748                         SendDisassociation(ieee,deauth,mlme->reason_code);
749                         rtllib_disassociate(ieee);
750
751                         ieee->wap_set = 0;
752                         for (i = 0; i < 6; i++)
753                                 ieee->current_network.bssid[i]= 0x55;
754
755                         ieee->ssid_set = 0;
756                         ieee->current_network.ssid[0] = '\0';
757                         ieee->current_network.ssid_len = 0;
758                 break;
759         default:
760                 up(&ieee->wx_sem);
761                 return -EOPNOTSUPP;
762         }
763
764         up(&ieee->wx_sem);
765
766         return 0;
767 }
768
769 int rtllib_wx_set_auth(struct rtllib_device *ieee,
770                                struct iw_request_info *info,
771                                struct iw_param *data, char *extra)
772 {
773         switch (data->flags & IW_AUTH_INDEX) {
774         case IW_AUTH_WPA_VERSION:
775                 break;
776         case IW_AUTH_CIPHER_PAIRWISE:
777         case IW_AUTH_CIPHER_GROUP:
778         case IW_AUTH_KEY_MGMT:
779                 /*
780                  * Host AP driver does not use these parameters and allows
781                  * wpa_supplicant to control them internally.
782                  */
783                 break;
784         case IW_AUTH_TKIP_COUNTERMEASURES:
785                 ieee->tkip_countermeasures = data->value;
786                 break;
787         case IW_AUTH_DROP_UNENCRYPTED:
788                 ieee->drop_unencrypted = data->value;
789                 break;
790
791         case IW_AUTH_80211_AUTH_ALG:
792                 if (data->value & IW_AUTH_ALG_SHARED_KEY){
793                         ieee->open_wep = 0;
794                         ieee->auth_mode = 1;
795                 }
796                 else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM){
797                         ieee->open_wep = 1;
798                         ieee->auth_mode = 0;
799                 }
800                 else if (data->value & IW_AUTH_ALG_LEAP){
801                         ieee->open_wep = 1;
802                         ieee->auth_mode = 2;
803                 }
804                 else
805                         return -EINVAL;
806                 break;
807
808         case IW_AUTH_WPA_ENABLED:
809                 ieee->wpa_enabled = (data->value)?1:0;
810                 break;
811
812         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
813                 ieee->ieee802_1x = data->value;
814                 break;
815         case IW_AUTH_PRIVACY_INVOKED:
816                 ieee->privacy_invoked = data->value;
817                 break;
818         default:
819                 return -EOPNOTSUPP;
820         }
821         return 0;
822 }
823
824 int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
825 {
826         u8 *buf;
827         u8 eid, wps_oui[4]={0x0,0x50,0xf2,0x04};
828
829         if (len > MAX_WPA_IE_LEN || (len && ie == NULL)) {
830                 return -EINVAL;
831         }
832
833         if (len) {
834                 eid = ie[0];
835                 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2], wps_oui, 4))) {
836
837                         ieee->wps_ie_len = (len < MAX_WZC_IE_LEN) ? (len):(MAX_WZC_IE_LEN);
838                         buf = kmalloc(ieee->wps_ie_len, GFP_KERNEL);
839                         if (buf == NULL)
840                                 return -ENOMEM;
841                         memcpy(buf, ie, ieee->wps_ie_len);
842                         ieee->wps_ie = buf;
843                         return 0;
844                 }
845         }
846         ieee->wps_ie_len = 0;
847         if (ieee->wps_ie)
848                 kfree(ieee->wps_ie);
849         ieee->wps_ie = NULL;
850         if (len) {
851                 if (len != ie[1]+2) {
852                         return -EINVAL;
853                 }
854                 buf = kmalloc(len, GFP_KERNEL);
855                 if (buf == NULL)
856                         return -ENOMEM;
857                 memcpy(buf, ie, len);
858                 kfree(ieee->wpa_ie);
859                 ieee->wpa_ie = buf;
860                 ieee->wpa_ie_len = len;
861         } else {
862                 if (ieee->wpa_ie)
863                 kfree(ieee->wpa_ie);
864                 ieee->wpa_ie = NULL;
865                 ieee->wpa_ie_len = 0;
866         }
867         return 0;
868 }