Staging: rtl8192su: fix build warnings
[linux-2.6] / drivers / staging / rtl8192su / ieee80211 / ieee80211_wx.c
1 /******************************************************************************
2
3   Copyright(c) 2004 Intel Corporation. All rights reserved.
4
5   Portions of this file are based on the WEP enablement code provided by the
6   Host AP project hostap-drivers v0.1.3
7   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
8   <jkmaline@cc.hut.fi>
9   Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
10
11   This program is free software; you can redistribute it and/or modify it
12   under the terms of version 2 of the GNU General Public License as
13   published by the Free Software Foundation.
14
15   This program is distributed in the hope that it will be useful, but WITHOUT
16   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18   more details.
19
20   You should have received a copy of the GNU General Public License along with
21   this program; if not, write to the Free Software Foundation, Inc., 59
22   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23
24   The full GNU General Public License is included in this distribution in the
25   file called LICENSE.
26
27   Contact Information:
28   James P. Ketrenos <ipw2100-admin@linux.intel.com>
29   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31 ******************************************************************************/
32 #include <linux/wireless.h>
33 #include <linux/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                         request_module("ieee80211_crypt_wep");
487                         new_crypt->ops = ieee80211_get_crypto_ops("WEP");
488                 }
489 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
490                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
491 #else
492                 if (new_crypt->ops && try_inc_mod_count(new_crypt->ops->owner))
493 #endif
494                         new_crypt->priv = new_crypt->ops->init(key);
495
496                 if (!new_crypt->ops || !new_crypt->priv) {
497                         kfree(new_crypt);
498                         new_crypt = NULL;
499
500                         printk(KERN_WARNING "%s: could not initialize WEP: "
501                                "load module ieee80211_crypt_wep\n",
502                                dev->name);
503                         return -EOPNOTSUPP;
504                 }
505                 *crypt = new_crypt;
506         }
507
508         /* If a new key was provided, set it up */
509         if (erq->length > 0) {
510                 len = erq->length <= 5 ? 5 : 13;
511                 memcpy(sec.keys[key], keybuf, erq->length);
512                 if (len > erq->length)
513                         memset(sec.keys[key] + erq->length, 0,
514                                len - erq->length);
515                 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
516                                    key, escape_essid(sec.keys[key], len),
517                                    erq->length, len);
518                 sec.key_sizes[key] = len;
519                 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
520                                        (*crypt)->priv);
521                 sec.flags |= (1 << key);
522                 /* This ensures a key will be activated if no key is
523                  * explicitely set */
524                 if (key == sec.active_key)
525                         sec.flags |= SEC_ACTIVE_KEY;
526                 ieee->tx_keyidx = key;
527
528         } else {
529                 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
530                                              NULL, (*crypt)->priv);
531                 if (len == 0) {
532                         /* Set a default key of all 0 */
533                         printk("Setting key %d to all zero.\n",
534                                            key);
535
536                         IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
537                                            key);
538                         memset(sec.keys[key], 0, 13);
539                         (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
540                                                (*crypt)->priv);
541                         sec.key_sizes[key] = 13;
542                         sec.flags |= (1 << key);
543                 }
544
545                 /* No key data - just set the default TX key index */
546                 if (key_provided) {
547                         IEEE80211_DEBUG_WX(
548                                 "Setting key %d to default Tx key.\n", key);
549                         ieee->tx_keyidx = key;
550                         sec.active_key = key;
551                         sec.flags |= SEC_ACTIVE_KEY;
552                 }
553         }
554
555  done:
556         ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
557         ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
558         sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
559         sec.flags |= SEC_AUTH_MODE;
560         IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
561                            "OPEN" : "SHARED KEY");
562
563         /* For now we just support WEP, so only set that security level...
564          * TODO: When WPA is added this is one place that needs to change */
565         sec.flags |= SEC_LEVEL;
566         sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
567
568         if (ieee->set_security)
569                 ieee->set_security(dev, &sec);
570
571         /* Do not reset port if card is in Managed mode since resetting will
572          * generate new IEEE 802.11 authentication which may end up in looping
573          * with IEEE 802.1X.  If your hardware requires a reset after WEP
574          * configuration (for example... Prism2), implement the reset_port in
575          * the callbacks structures used to initialize the 802.11 stack. */
576         if (ieee->reset_on_keychange &&
577             ieee->iw_mode != IW_MODE_INFRA &&
578             ieee->reset_port && ieee->reset_port(dev)) {
579                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
580                 return -EINVAL;
581         }
582         return 0;
583 }
584
585 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
586                             struct iw_request_info *info,
587                             union iwreq_data *wrqu, char *keybuf)
588 {
589         struct iw_point *erq = &(wrqu->encoding);
590         int len, key;
591         struct ieee80211_crypt_data *crypt;
592
593         IEEE80211_DEBUG_WX("GET_ENCODE\n");
594
595         if(ieee->iw_mode == IW_MODE_MONITOR)
596                 return -1;
597
598         key = erq->flags & IW_ENCODE_INDEX;
599         if (key) {
600                 if (key > WEP_KEYS)
601                         return -EINVAL;
602                 key--;
603         } else
604                 key = ieee->tx_keyidx;
605
606         crypt = ieee->crypt[key];
607         erq->flags = key + 1;
608
609         if (crypt == NULL || crypt->ops == NULL) {
610                 erq->length = 0;
611                 erq->flags |= IW_ENCODE_DISABLED;
612                 return 0;
613         }
614 #if 0
615         if (strcmp(crypt->ops->name, "WEP") != 0) {
616                 /* only WEP is supported with wireless extensions, so just
617                  * report that encryption is used */
618                 erq->length = 0;
619                 erq->flags |= IW_ENCODE_ENABLED;
620                 return 0;
621         }
622 #endif
623         len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
624         erq->length = (len >= 0 ? len : 0);
625
626         erq->flags |= IW_ENCODE_ENABLED;
627
628         if (ieee->open_wep)
629                 erq->flags |= IW_ENCODE_OPEN;
630         else
631                 erq->flags |= IW_ENCODE_RESTRICTED;
632
633         return 0;
634 }
635 #if (WIRELESS_EXT >= 18)
636 int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
637                                struct iw_request_info *info,
638                                union iwreq_data *wrqu, char *extra)
639 {
640         int ret = 0;
641 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
642         struct net_device *dev = ieee->dev;
643         struct iw_point *encoding = &wrqu->encoding;
644         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
645         int i, idx;
646         int group_key = 0;
647         const char *alg, *module;
648         struct ieee80211_crypto_ops *ops;
649         struct ieee80211_crypt_data **crypt;
650
651         struct ieee80211_security sec = {
652                 .flags = 0,
653         };
654         //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
655         idx = encoding->flags & IW_ENCODE_INDEX;
656         if (idx) {
657                 if (idx < 1 || idx > WEP_KEYS)
658                         return -EINVAL;
659                 idx--;
660         } else
661                 idx = ieee->tx_keyidx;
662
663         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
664
665                 crypt = &ieee->crypt[idx];
666
667                 group_key = 1;
668         } else {
669                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
670                 //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
671                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
672                         return -EINVAL;
673                 if (ieee->iw_mode == IW_MODE_INFRA)
674
675                         crypt = &ieee->crypt[idx];
676
677                 else
678                         return -EINVAL;
679         }
680
681         sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
682         if ((encoding->flags & IW_ENCODE_DISABLED) ||
683             ext->alg == IW_ENCODE_ALG_NONE) {
684                 if (*crypt)
685                         ieee80211_crypt_delayed_deinit(ieee, crypt);
686
687                 for (i = 0; i < WEP_KEYS; i++)
688
689                         if (ieee->crypt[i] != NULL)
690
691                                 break;
692
693                 if (i == WEP_KEYS) {
694                         sec.enabled = 0;
695                       //  sec.encrypt = 0;
696                         sec.level = SEC_LEVEL_0;
697                         sec.flags |= SEC_LEVEL;
698                 }
699                 //printk("disabled: flag:%x\n", encoding->flags);
700                 goto done;
701         }
702
703         sec.enabled = 1;
704     //    sec.encrypt = 1;
705 #if 0
706         if (group_key ? !ieee->host_mc_decrypt :
707             !(ieee->host_encrypt || ieee->host_decrypt ||
708               ieee->host_encrypt_msdu))
709                 goto skip_host_crypt;
710 #endif
711         switch (ext->alg) {
712         case IW_ENCODE_ALG_WEP:
713                 alg = "WEP";
714                 module = "ieee80211_crypt_wep";
715                 break;
716         case IW_ENCODE_ALG_TKIP:
717                 alg = "TKIP";
718                 module = "ieee80211_crypt_tkip";
719                 break;
720         case IW_ENCODE_ALG_CCMP:
721                 alg = "CCMP";
722                 module = "ieee80211_crypt_ccmp";
723                 break;
724         default:
725                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
726                                    dev->name, ext->alg);
727                 ret = -EINVAL;
728                 goto done;
729         }
730         printk("alg name:%s\n",alg);
731
732          ops = ieee80211_get_crypto_ops(alg);
733         if (ops == NULL) {
734                 request_module("%s", module);
735                 ops = ieee80211_get_crypto_ops(alg);
736         }
737         if (ops == NULL) {
738                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
739                                    dev->name, ext->alg);
740                 printk("========>unknown crypto alg %d\n", ext->alg);
741                 ret = -EINVAL;
742                 goto done;
743         }
744
745         if (*crypt == NULL || (*crypt)->ops != ops) {
746                 struct ieee80211_crypt_data *new_crypt;
747
748                 ieee80211_crypt_delayed_deinit(ieee, crypt);
749
750 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
751                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
752 #else
753                 new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL);
754                 memset(new_crypt,0,sizeof(*new_crypt));
755 #endif
756                 if (new_crypt == NULL) {
757                         ret = -ENOMEM;
758                         goto done;
759                 }
760                 new_crypt->ops = ops;
761                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
762                         new_crypt->priv = new_crypt->ops->init(idx);
763                 if (new_crypt->priv == NULL) {
764                         kfree(new_crypt);
765                         ret = -EINVAL;
766                         goto done;
767                 }
768                 *crypt = new_crypt;
769
770         }
771
772         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
773             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
774                                    (*crypt)->priv) < 0) {
775                 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
776                 printk("key setting failed\n");
777                 ret = -EINVAL;
778                 goto done;
779         }
780 #if 1
781  //skip_host_crypt:
782         //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
783         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
784                 ieee->tx_keyidx = idx;
785                 sec.active_key = idx;
786                 sec.flags |= SEC_ACTIVE_KEY;
787         }
788
789         if (ext->alg != IW_ENCODE_ALG_NONE) {
790                 //memcpy(sec.keys[idx], ext->key, ext->key_len);
791                 sec.key_sizes[idx] = ext->key_len;
792                 sec.flags |= (1 << idx);
793                 if (ext->alg == IW_ENCODE_ALG_WEP) {
794                       //  sec.encode_alg[idx] = SEC_ALG_WEP;
795                         sec.flags |= SEC_LEVEL;
796                         sec.level = SEC_LEVEL_1;
797                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
798                       //  sec.encode_alg[idx] = SEC_ALG_TKIP;
799                         sec.flags |= SEC_LEVEL;
800                         sec.level = SEC_LEVEL_2;
801                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
802                        // sec.encode_alg[idx] = SEC_ALG_CCMP;
803                         sec.flags |= SEC_LEVEL;
804                         sec.level = SEC_LEVEL_3;
805                 }
806                 /* Don't set sec level for group keys. */
807                 if (group_key)
808                         sec.flags &= ~SEC_LEVEL;
809         }
810 #endif
811 done:
812         if (ieee->set_security)
813                 ieee->set_security(ieee->dev, &sec);
814
815          if (ieee->reset_on_keychange &&
816             ieee->iw_mode != IW_MODE_INFRA &&
817             ieee->reset_port && ieee->reset_port(dev)) {
818                 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
819                 return -EINVAL;
820         }
821 #endif
822         return ret;
823 }
824
825 int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
826                                struct iw_request_info *info,
827                                union iwreq_data *wrqu, char *extra)
828 {
829         struct iw_point *encoding = &wrqu->encoding;
830         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
831         struct ieee80211_crypt_data *crypt;
832         int idx, max_key_len;
833
834         max_key_len = encoding->length - sizeof(*ext);
835         if (max_key_len < 0)
836                 return -EINVAL;
837
838         idx = encoding->flags & IW_ENCODE_INDEX;
839         if (idx) {
840                 if (idx < 1 || idx > WEP_KEYS)
841                         return -EINVAL;
842                 idx--;
843         } else
844                 idx = ieee->tx_keyidx;
845
846         if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
847             ext->alg != IW_ENCODE_ALG_WEP)
848                 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
849                         return -EINVAL;
850
851         crypt = ieee->crypt[idx];
852         encoding->flags = idx + 1;
853         memset(ext, 0, sizeof(*ext));
854
855         if (crypt == NULL || crypt->ops == NULL ) {
856                 ext->alg = IW_ENCODE_ALG_NONE;
857                 ext->key_len = 0;
858                 encoding->flags |= IW_ENCODE_DISABLED;
859         } else {
860                 if (strcmp(crypt->ops->name, "WEP") == 0 )
861                         ext->alg = IW_ENCODE_ALG_WEP;
862                 else if (strcmp(crypt->ops->name, "TKIP"))
863                         ext->alg = IW_ENCODE_ALG_TKIP;
864                 else if (strcmp(crypt->ops->name, "CCMP"))
865                         ext->alg = IW_ENCODE_ALG_CCMP;
866                 else
867                         return -EINVAL;
868                 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
869                 encoding->flags |= IW_ENCODE_ENABLED;
870                 if (ext->key_len &&
871                     (ext->alg == IW_ENCODE_ALG_TKIP ||
872                      ext->alg == IW_ENCODE_ALG_CCMP))
873                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
874
875         }
876
877         return 0;
878 }
879
880 int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
881                                struct iw_request_info *info,
882                                union iwreq_data *wrqu, char *extra)
883 {
884 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
885         struct iw_mlme *mlme = (struct iw_mlme *) extra;
886         switch (mlme->cmd) {
887         case IW_MLME_DEAUTH:
888         case IW_MLME_DISASSOC:
889                 ieee80211_disassociate(ieee);
890                 break;
891          default:
892                 return -EOPNOTSUPP;
893         }
894 #endif
895         return 0;
896 }
897
898 int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
899                                struct iw_request_info *info,
900                                struct iw_param *data, char *extra)
901 {
902 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
903         switch (data->flags & IW_AUTH_INDEX) {
904         case IW_AUTH_WPA_VERSION:
905              /*need to support wpa2 here*/
906                 //printk("wpa version:%x\n", data->value);
907                 break;
908         case IW_AUTH_CIPHER_PAIRWISE:
909         case IW_AUTH_CIPHER_GROUP:
910         case IW_AUTH_KEY_MGMT:
911                 /*
912  *                  * Host AP driver does not use these parameters and allows
913  *                                   * wpa_supplicant to control them internally.
914  *                                                    */
915                 break;
916         case IW_AUTH_TKIP_COUNTERMEASURES:
917                 ieee->tkip_countermeasures = data->value;
918                 break;
919         case IW_AUTH_DROP_UNENCRYPTED:
920                 ieee->drop_unencrypted = data->value;
921                 break;
922
923         case IW_AUTH_80211_AUTH_ALG:
924                 //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
925         //      ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
926                 if(data->value & IW_AUTH_ALG_SHARED_KEY){
927                         ieee->open_wep = 0;
928                         ieee->auth_mode = 1;
929                 }
930                 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
931                         ieee->open_wep = 1;
932                         ieee->auth_mode = 0;
933                 }
934                 else if(data->value & IW_AUTH_ALG_LEAP){
935                         ieee->open_wep = 1;
936                         ieee->auth_mode = 2;
937                         //printk("hahahaa:LEAP\n");
938                 }
939                 else
940                         return -EINVAL;
941                 //printk("open_wep:%d\n", ieee->open_wep);
942                 break;
943
944 #if 1
945         case IW_AUTH_WPA_ENABLED:
946                 ieee->wpa_enabled = (data->value)?1:0;
947                 //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
948                 break;
949
950 #endif
951         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
952                 ieee->ieee802_1x = data->value;
953                 break;
954         case IW_AUTH_PRIVACY_INVOKED:
955                 ieee->privacy_invoked = data->value;
956                 break;
957         default:
958                 return -EOPNOTSUPP;
959         }
960 #endif
961         return 0;
962 }
963 #endif
964 #if 1
965 int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
966 {
967 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
968 #if 0
969         printk("====>%s()\n", __FUNCTION__);
970         {
971                 int i;
972                 for (i=0; i<len; i++)
973                 printk("%2x ", ie[i]&0xff);
974                 printk("\n");
975         }
976 #endif
977         u8 *buf;
978
979         if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
980         {
981         //      printk("return error out, len:%d\n", len);
982         return -EINVAL;
983         }
984
985
986         if (len)
987         {
988                 if (len != ie[1]+2)
989                 {
990                         printk("len:%d, ie:%d\n", len, ie[1]);
991                         return -EINVAL;
992                 }
993                 buf = kmalloc(len, GFP_KERNEL);
994                 if (buf == NULL)
995                         return -ENOMEM;
996                 memcpy(buf, ie, len);
997                 kfree(ieee->wpa_ie);
998                 ieee->wpa_ie = buf;
999                 ieee->wpa_ie_len = len;
1000         }
1001         else{
1002                 if (ieee->wpa_ie)
1003                 kfree(ieee->wpa_ie);
1004                 ieee->wpa_ie = NULL;
1005                 ieee->wpa_ie_len = 0;
1006         }
1007 #endif
1008         return 0;
1009
1010 }
1011 #endif
1012
1013 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1014 EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
1015 #if (WIRELESS_EXT >= 18)
1016 EXPORT_SYMBOL(ieee80211_wx_set_mlme);
1017 EXPORT_SYMBOL(ieee80211_wx_set_auth);
1018 EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
1019 EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
1020 #endif
1021 EXPORT_SYMBOL(ieee80211_wx_get_scan);
1022 EXPORT_SYMBOL(ieee80211_wx_set_encode);
1023 EXPORT_SYMBOL(ieee80211_wx_get_encode);
1024 #else
1025 EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_gen_ie);
1026 //EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mlme);
1027 //EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_auth);
1028 //EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode_ext);
1029 EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_scan);
1030 EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode);
1031 EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_encode);
1032 #endif