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