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