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