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