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