]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
c0b2c02b0ac458fbcf56ec727f252f74c876bce5
[net-next-2.6.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/version.h>
34 #include <linux/kmod.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 = kmalloc(sizeof(struct ieee80211_crypt_data),
383                                     GFP_KERNEL);
384                 if (new_crypt == NULL)
385                         return -ENOMEM;
386                 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
387                 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
388                 if (!new_crypt->ops) {
389                         request_module("ieee80211_crypt_wep");
390                         new_crypt->ops = ieee80211_get_crypto_ops("WEP");
391                 }
392                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
393                         new_crypt->priv = new_crypt->ops->init(key);
394
395                 if (!new_crypt->ops || !new_crypt->priv) {
396                         kfree(new_crypt);
397                         new_crypt = NULL;
398
399                         printk(KERN_WARNING "%s: could not initialize WEP: "
400                                "load module ieee80211_crypt_wep\n",
401                                dev->name);
402                         return -EOPNOTSUPP;
403                 }
404                 *crypt = new_crypt;
405         }
406
407         /* If a new key was provided, set it up */
408         if (erq->length > 0) {
409                 len = erq->length <= 5 ? 5 : 13;
410                 memcpy(sec.keys[key], keybuf, erq->length);
411                 if (len > erq->length)
412                         memset(sec.keys[key] + erq->length, 0,
413                                len - erq->length);
414                 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
415                                    key, escape_essid(sec.keys[key], len),
416                                    erq->length, len);
417                 sec.key_sizes[key] = len;
418                 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
419                                        (*crypt)->priv);
420                 sec.flags |= (1 << key);
421                 /* This ensures a key will be activated if no key is
422                  * explicitely set */
423                 if (key == sec.active_key)
424                         sec.flags |= SEC_ACTIVE_KEY;
425                 ieee->tx_keyidx = key;
426
427         } else {
428                 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
429                                              NULL, (*crypt)->priv);
430                 if (len == 0) {
431                         /* Set a default key of all 0 */
432                         printk("Setting key %d to all zero.\n",
433                                            key);
434
435                         IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
436                                            key);
437                         memset(sec.keys[key], 0, 13);
438                         (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
439                                                (*crypt)->priv);
440                         sec.key_sizes[key] = 13;
441                         sec.flags |= (1 << key);
442                 }
443
444                 /* No key data - just set the default TX key index */
445                 if (key_provided) {
446                         IEEE80211_DEBUG_WX(
447                                 "Setting key %d to default Tx key.\n", key);
448                         ieee->tx_keyidx = key;
449                         sec.active_key = key;
450                         sec.flags |= SEC_ACTIVE_KEY;
451                 }
452         }
453
454  done:
455         ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
456         ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
457         sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
458         sec.flags |= SEC_AUTH_MODE;
459         IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
460                            "OPEN" : "SHARED KEY");
461
462         /* For now we just support WEP, so only set that security level...
463          * TODO: When WPA is added this is one place that needs to change */
464         sec.flags |= SEC_LEVEL;
465         sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
466
467         if (ieee->set_security)
468                 ieee->set_security(dev, &sec);
469
470         /* Do not reset port if card is in Managed mode since resetting will
471          * generate new IEEE 802.11 authentication which may end up in looping
472          * with IEEE 802.1X.  If your hardware requires a reset after WEP
473          * configuration (for example... Prism2), implement the reset_port in
474          * the callbacks structures used to initialize the 802.11 stack. */
475         if (ieee->reset_on_keychange &&
476             ieee->iw_mode != IW_MODE_INFRA &&
477             ieee->reset_port && ieee->reset_port(dev)) {
478                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
479                 return -EINVAL;
480         }
481         return 0;
482 }
483
484 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
485                             struct iw_request_info *info,
486                             union iwreq_data *wrqu, char *keybuf)
487 {
488         struct iw_point *erq = &(wrqu->encoding);
489         int len, key;
490         struct ieee80211_crypt_data *crypt;
491
492         IEEE80211_DEBUG_WX("GET_ENCODE\n");
493
494         if(ieee->iw_mode == IW_MODE_MONITOR)
495                 return -1;
496
497         key = erq->flags & IW_ENCODE_INDEX;
498         if (key) {
499                 if (key > WEP_KEYS)
500                         return -EINVAL;
501                 key--;
502         } else
503                 key = ieee->tx_keyidx;
504
505         crypt = ieee->crypt[key];
506         erq->flags = key + 1;
507
508         if (crypt == NULL || crypt->ops == NULL) {
509                 erq->length = 0;
510                 erq->flags |= IW_ENCODE_DISABLED;
511                 return 0;
512         }
513         len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
514         erq->length = (len >= 0 ? len : 0);
515
516         erq->flags |= IW_ENCODE_ENABLED;
517
518         if (ieee->open_wep)
519                 erq->flags |= IW_ENCODE_OPEN;
520         else
521                 erq->flags |= IW_ENCODE_RESTRICTED;
522
523         return 0;
524 }
525 #if (WIRELESS_EXT >= 18)
526 int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
527                                struct iw_request_info *info,
528                                union iwreq_data *wrqu, char *extra)
529 {
530         int ret = 0;
531         struct net_device *dev = ieee->dev;
532         struct iw_point *encoding = &wrqu->encoding;
533         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
534         int i, idx;
535         int group_key = 0;
536         const char *alg, *module;
537         struct ieee80211_crypto_ops *ops;
538         struct ieee80211_crypt_data **crypt;
539
540         struct ieee80211_security sec = {
541                 .flags = 0,
542         };
543         //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
544         idx = encoding->flags & IW_ENCODE_INDEX;
545         if (idx) {
546                 if (idx < 1 || idx > WEP_KEYS)
547                         return -EINVAL;
548                 idx--;
549         } else
550                 idx = ieee->tx_keyidx;
551
552         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
553
554                 crypt = &ieee->crypt[idx];
555
556                 group_key = 1;
557         } else {
558                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
559                 //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
560                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
561                         return -EINVAL;
562                 if (ieee->iw_mode == IW_MODE_INFRA)
563
564                         crypt = &ieee->crypt[idx];
565
566                 else
567                         return -EINVAL;
568         }
569
570         sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
571         if ((encoding->flags & IW_ENCODE_DISABLED) ||
572             ext->alg == IW_ENCODE_ALG_NONE) {
573                 if (*crypt)
574                         ieee80211_crypt_delayed_deinit(ieee, crypt);
575
576                 for (i = 0; i < WEP_KEYS; i++)
577
578                         if (ieee->crypt[i] != NULL)
579
580                                 break;
581
582                 if (i == WEP_KEYS) {
583                         sec.enabled = 0;
584                       //  sec.encrypt = 0;
585                         sec.level = SEC_LEVEL_0;
586                         sec.flags |= SEC_LEVEL;
587                 }
588                 //printk("disabled: flag:%x\n", encoding->flags);
589                 goto done;
590         }
591
592         sec.enabled = 1;
593     //    sec.encrypt = 1;
594         switch (ext->alg) {
595         case IW_ENCODE_ALG_WEP:
596                 alg = "WEP";
597                 module = "ieee80211_crypt_wep";
598                 break;
599         case IW_ENCODE_ALG_TKIP:
600                 alg = "TKIP";
601                 module = "ieee80211_crypt_tkip";
602                 break;
603         case IW_ENCODE_ALG_CCMP:
604                 alg = "CCMP";
605                 module = "ieee80211_crypt_ccmp";
606                 break;
607         default:
608                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
609                                    dev->name, ext->alg);
610                 ret = -EINVAL;
611                 goto done;
612         }
613         printk("alg name:%s\n",alg);
614
615          ops = ieee80211_get_crypto_ops(alg);
616         if (ops == NULL) {
617                 request_module(module);
618                 ops = ieee80211_get_crypto_ops(alg);
619         }
620         if (ops == NULL) {
621                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
622                                    dev->name, ext->alg);
623                 printk("========>unknown crypto alg %d\n", ext->alg);
624                 ret = -EINVAL;
625                 goto done;
626         }
627
628         if (*crypt == NULL || (*crypt)->ops != ops) {
629                 struct ieee80211_crypt_data *new_crypt;
630
631                 ieee80211_crypt_delayed_deinit(ieee, crypt);
632
633                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
634                 if (new_crypt == NULL) {
635                         ret = -ENOMEM;
636                         goto done;
637                 }
638                 new_crypt->ops = ops;
639                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
640                         new_crypt->priv = new_crypt->ops->init(idx);
641                 if (new_crypt->priv == NULL) {
642                         kfree(new_crypt);
643                         ret = -EINVAL;
644                         goto done;
645                 }
646                 *crypt = new_crypt;
647
648         }
649
650         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
651             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
652                                    (*crypt)->priv) < 0) {
653                 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
654                 printk("key setting failed\n");
655                 ret = -EINVAL;
656                 goto done;
657         }
658  //skip_host_crypt:
659         //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
660         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
661                 ieee->tx_keyidx = idx;
662                 sec.active_key = idx;
663                 sec.flags |= SEC_ACTIVE_KEY;
664         }
665
666         if (ext->alg != IW_ENCODE_ALG_NONE) {
667                 //memcpy(sec.keys[idx], ext->key, ext->key_len);
668                 sec.key_sizes[idx] = ext->key_len;
669                 sec.flags |= (1 << idx);
670                 if (ext->alg == IW_ENCODE_ALG_WEP) {
671                       //  sec.encode_alg[idx] = SEC_ALG_WEP;
672                         sec.flags |= SEC_LEVEL;
673                         sec.level = SEC_LEVEL_1;
674                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
675                       //  sec.encode_alg[idx] = SEC_ALG_TKIP;
676                         sec.flags |= SEC_LEVEL;
677                         sec.level = SEC_LEVEL_2;
678                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
679                        // sec.encode_alg[idx] = SEC_ALG_CCMP;
680                         sec.flags |= SEC_LEVEL;
681                         sec.level = SEC_LEVEL_3;
682                 }
683                 /* Don't set sec level for group keys. */
684                 if (group_key)
685                         sec.flags &= ~SEC_LEVEL;
686         }
687 done:
688         if (ieee->set_security)
689                 ieee->set_security(ieee->dev, &sec);
690
691          if (ieee->reset_on_keychange &&
692             ieee->iw_mode != IW_MODE_INFRA &&
693             ieee->reset_port && ieee->reset_port(dev)) {
694                 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
695                 return -EINVAL;
696         }
697         return ret;
698 }
699
700 int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
701                                struct iw_request_info *info,
702                                union iwreq_data *wrqu, char *extra)
703 {
704         struct iw_point *encoding = &wrqu->encoding;
705         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
706         struct ieee80211_crypt_data *crypt;
707         int idx, max_key_len;
708
709         max_key_len = encoding->length - sizeof(*ext);
710         if (max_key_len < 0)
711                 return -EINVAL;
712
713         idx = encoding->flags & IW_ENCODE_INDEX;
714         if (idx) {
715                 if (idx < 1 || idx > WEP_KEYS)
716                         return -EINVAL;
717                 idx--;
718         } else
719                 idx = ieee->tx_keyidx;
720
721         if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
722             ext->alg != IW_ENCODE_ALG_WEP)
723                 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
724                         return -EINVAL;
725
726         crypt = ieee->crypt[idx];
727         encoding->flags = idx + 1;
728         memset(ext, 0, sizeof(*ext));
729
730         if (crypt == NULL || crypt->ops == NULL ) {
731                 ext->alg = IW_ENCODE_ALG_NONE;
732                 ext->key_len = 0;
733                 encoding->flags |= IW_ENCODE_DISABLED;
734         } else {
735                 if (strcmp(crypt->ops->name, "WEP") == 0 )
736                         ext->alg = IW_ENCODE_ALG_WEP;
737                 else if (strcmp(crypt->ops->name, "TKIP"))
738                         ext->alg = IW_ENCODE_ALG_TKIP;
739                 else if (strcmp(crypt->ops->name, "CCMP"))
740                         ext->alg = IW_ENCODE_ALG_CCMP;
741                 else
742                         return -EINVAL;
743                 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
744                 encoding->flags |= IW_ENCODE_ENABLED;
745                 if (ext->key_len &&
746                     (ext->alg == IW_ENCODE_ALG_TKIP ||
747                      ext->alg == IW_ENCODE_ALG_CCMP))
748                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
749
750         }
751
752         return 0;
753 }
754
755 int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
756                                struct iw_request_info *info,
757                                union iwreq_data *wrqu, char *extra)
758 {
759         struct iw_mlme *mlme = (struct iw_mlme *) extra;
760         switch (mlme->cmd) {
761         case IW_MLME_DEAUTH:
762         case IW_MLME_DISASSOC:
763                 ieee80211_disassociate(ieee);
764                 break;
765          default:
766                 return -EOPNOTSUPP;
767         }
768         return 0;
769 }
770
771 int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
772                                struct iw_request_info *info,
773                                struct iw_param *data, char *extra)
774 {
775         switch (data->flags & IW_AUTH_INDEX) {
776         case IW_AUTH_WPA_VERSION:
777              /*need to support wpa2 here*/
778                 //printk("wpa version:%x\n", data->value);
779                 break;
780         case IW_AUTH_CIPHER_PAIRWISE:
781         case IW_AUTH_CIPHER_GROUP:
782         case IW_AUTH_KEY_MGMT:
783                 /*
784  *                  * Host AP driver does not use these parameters and allows
785  *                                   * wpa_supplicant to control them internally.
786  *                                                    */
787                 break;
788         case IW_AUTH_TKIP_COUNTERMEASURES:
789                 ieee->tkip_countermeasures = data->value;
790                 break;
791         case IW_AUTH_DROP_UNENCRYPTED:
792                 ieee->drop_unencrypted = data->value;
793                 break;
794
795         case IW_AUTH_80211_AUTH_ALG:
796                 //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
797         //      ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
798                 if(data->value & IW_AUTH_ALG_SHARED_KEY){
799                         ieee->open_wep = 0;
800                         ieee->auth_mode = 1;
801                 }
802                 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
803                         ieee->open_wep = 1;
804                         ieee->auth_mode = 0;
805                 }
806                 else if(data->value & IW_AUTH_ALG_LEAP){
807                         ieee->open_wep = 1;
808                         ieee->auth_mode = 2;
809                         //printk("hahahaa:LEAP\n");
810                 }
811                 else
812                         return -EINVAL;
813                 //printk("open_wep:%d\n", ieee->open_wep);
814                 break;
815
816         case IW_AUTH_WPA_ENABLED:
817                 ieee->wpa_enabled = (data->value)?1:0;
818                 //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
819                 break;
820
821         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
822                 ieee->ieee802_1x = data->value;
823                 break;
824         case IW_AUTH_PRIVACY_INVOKED:
825                 ieee->privacy_invoked = data->value;
826                 break;
827         default:
828                 return -EOPNOTSUPP;
829         }
830         return 0;
831 }
832 #endif
833 int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
834 {
835         u8 *buf;
836
837         if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
838         {
839         //      printk("return error out, len:%d\n", len);
840         return -EINVAL;
841         }
842
843
844         if (len)
845         {
846                 if (len != ie[1]+2)
847                 {
848                         printk("len:%zu, ie:%d\n", len, ie[1]);
849                         return -EINVAL;
850                 }
851                 buf = kmalloc(len, GFP_KERNEL);
852                 if (buf == NULL)
853                         return -ENOMEM;
854                 memcpy(buf, ie, len);
855                 kfree(ieee->wpa_ie);
856                 ieee->wpa_ie = buf;
857                 ieee->wpa_ie_len = len;
858         }
859         else{
860                 if (ieee->wpa_ie)
861                 kfree(ieee->wpa_ie);
862                 ieee->wpa_ie = NULL;
863                 ieee->wpa_ie_len = 0;
864         }
865         return 0;
866
867 }
868
869 EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
870 #if (WIRELESS_EXT >= 18)
871 EXPORT_SYMBOL(ieee80211_wx_set_mlme);
872 EXPORT_SYMBOL(ieee80211_wx_set_auth);
873 EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
874 EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
875 #endif
876 EXPORT_SYMBOL(ieee80211_wx_get_scan);
877 EXPORT_SYMBOL(ieee80211_wx_set_encode);
878 EXPORT_SYMBOL(ieee80211_wx_get_encode);