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