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