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