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