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