39c6644f11b513f2f5c78241e12b20c2540090e6
[pandora-kernel.git] / drivers / staging / rtl8192e / rtllib_wx.c
1 /******************************************************************************
2
3   Copyright(c) 2004 Intel Corporation. All rights reserved.
4
5   Portions of this file are based on the WEP enablement code provided by the
6   Host AP project hostap-drivers v0.1.3
7   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
8   <jkmaline@cc.hut.fi>
9   Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
10
11   This program is free software; you can redistribute it and/or modify it
12   under the terms of version 2 of the GNU General Public License as
13   published by the Free Software Foundation.
14
15   This program is distributed in the hope that it will be useful, but WITHOUT
16   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18   more details.
19
20   You should have received a copy of the GNU General Public License along with
21   this program; if not, write to the Free Software Foundation, Inc., 59
22   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23
24   The full GNU General Public License is included in this distribution in the
25   file called LICENSE.
26
27   Contact Information:
28   James P. Ketrenos <ipw2100-admin@linux.intel.com>
29   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31 ******************************************************************************/
32 #include <linux/wireless.h>
33 #include <linux/version.h>
34 #include <linux/kmod.h>
35 #include <linux/module.h>
36
37 #include "rtllib.h"
38 struct modes_unit {
39         char *mode_string;
40         int mode_size;
41 };
42 static struct modes_unit rtllib_modes[] = {
43         {"a",1},
44         {"b",1},
45         {"g",1},
46         {"?",1},
47         {"N-24G",5},
48         {"N-5G",4},
49 };
50
51 #define MAX_CUSTOM_LEN 64
52 static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
53                                            char *start, char *stop,
54                                            struct rtllib_network *network,
55                                            struct iw_request_info *info)
56 {
57         char custom[MAX_CUSTOM_LEN];
58         char proto_name[IFNAMSIZ];
59         char *pname = proto_name;
60         char *p;
61         struct iw_event iwe;
62         int i, j;
63         u16 max_rate, rate;
64         static u8       EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
65
66         /* First entry *MUST* be the AP MAC address */
67         iwe.cmd = SIOCGIWAP;
68         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
69         memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
70         start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN);
71         /* Remaining entries will be displayed in the order we provide them */
72
73         /* Add the ESSID */
74         iwe.cmd = SIOCGIWESSID;
75         iwe.u.data.flags = 1;
76         if (network->ssid_len > 0){
77                 iwe.u.data.length = min(network->ssid_len, (u8)32);
78                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, network->ssid);
79         }else if (network->hidden_ssid_len == 0){
80                 iwe.u.data.length = sizeof("<hidden>");
81                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, "<hidden>");
82         }else {
83                 iwe.u.data.length = min(network->hidden_ssid_len, (u8)32);
84                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, network->hidden_ssid);
85         }
86         /* Add the protocol name */
87         iwe.cmd = SIOCGIWNAME;
88         for (i=0; i<(sizeof(rtllib_modes)/sizeof(rtllib_modes[0])); i++) {
89                 if (network->mode&(1<<i)) {
90                         sprintf(pname,rtllib_modes[i].mode_string,rtllib_modes[i].mode_size);
91                         pname +=rtllib_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_ESS | WLAN_CAPABILITY_IBSS)) {
101                 if (network->capability & WLAN_CAPABILITY_ESS)
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 = rtllib_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
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_rsl(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)
150         {
151                 struct ht_capab_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 = (struct ht_capab_ele *)&network->bssht.bdHTCapBuf[4];
156                 else
157                         ht_cap = (struct ht_capab_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_rsl(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 & RTLLIB_STATMASK_WEMASK;
184         if (!(network->stats.mask & RTLLIB_STATMASK_RSSI))
185                 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
186         if (!(network->stats.mask & RTLLIB_STATMASK_NOISE))
187                 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
188         if (!(network->stats.mask & RTLLIB_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
193         iwe.cmd = IWEVCUSTOM;
194         p = custom;
195         iwe.u.data.length = p - custom;
196         if (iwe.u.data.length)
197                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, custom);
198
199         memset(&iwe, 0, sizeof(iwe));
200         if (network->wpa_ie_len)
201         {
202                 char buf[MAX_WPA_IE_LEN];
203                 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
204                 iwe.cmd = IWEVGENIE;
205                 iwe.u.data.length = network->wpa_ie_len;
206                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
207         }
208         memset(&iwe, 0, sizeof(iwe));
209         if (network->rsn_ie_len)
210         {
211                 char buf[MAX_WPA_IE_LEN];
212                 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
213                 iwe.cmd = IWEVGENIE;
214                 iwe.u.data.length = network->rsn_ie_len;
215                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
216         }
217
218         /* add info for WZC */
219         memset(&iwe, 0, sizeof(iwe));
220         if (network->wzc_ie_len)
221         {
222                 char buf[MAX_WZC_IE_LEN];
223                 memcpy(buf, network->wzc_ie, network->wzc_ie_len);
224                 iwe.cmd = IWEVGENIE;
225                 iwe.u.data.length = network->wzc_ie_len;
226                 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
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_rsl(info, start, stop, &iwe, custom);
238
239         return start;
240 }
241
242 int rtllib_wx_get_scan(struct rtllib_device *ieee,
243                           struct iw_request_info *info,
244                           union iwreq_data *wrqu, char *extra)
245 {
246         struct rtllib_network *network;
247         unsigned long flags;
248
249         char *ev = extra;
250         char *stop = ev + wrqu->data.length;
251         int i = 0;
252         int err = 0;
253         RTLLIB_DEBUG_WX("Getting scan\n");
254         down(&ieee->wx_sem);
255         spin_lock_irqsave(&ieee->lock, flags);
256
257         list_for_each_entry(network, &ieee->network_list, list) {
258                 i++;
259                 if ((stop-ev)<200)
260                 {
261                         err = -E2BIG;
262                         break;
263                                                                                                 }
264                 if (ieee->scan_age == 0 ||
265                     time_after(network->last_scanned + ieee->scan_age, jiffies))
266                         ev = rtl819x_translate_scan(ieee, ev, stop, network, info);
267                 else
268                         RTLLIB_DEBUG_SCAN(
269                                 "Not showing network '%s ("
270                                 MAC_FMT ")' due to age (%lums).\n",
271                                 escape_essid(network->ssid,
272                                              network->ssid_len),
273                                 MAC_ARG(network->bssid),
274                                 (jiffies - network->last_scanned) / (HZ / 100));
275         }
276
277         spin_unlock_irqrestore(&ieee->lock, flags);
278         up(&ieee->wx_sem);
279         wrqu->data.length = ev -  extra;
280         wrqu->data.flags = 0;
281
282         RTLLIB_DEBUG_WX("exit: %d networks returned.\n", i);
283
284         return err;
285 }
286
287 int rtllib_wx_set_encode(struct rtllib_device *ieee,
288                             struct iw_request_info *info,
289                             union iwreq_data *wrqu, char *keybuf)
290 {
291         struct iw_point *erq = &(wrqu->encoding);
292         struct net_device *dev = ieee->dev;
293         struct rtllib_security sec = {
294                 .flags = 0
295         };
296         int i, key, key_provided, len;
297         struct rtllib_crypt_data **crypt;
298
299         RTLLIB_DEBUG_WX("SET_ENCODE\n");
300
301         key = erq->flags & IW_ENCODE_INDEX;
302         if (key) {
303                 if (key > WEP_KEYS)
304                         return -EINVAL;
305                 key--;
306                 key_provided = 1;
307         } else {
308                 key_provided = 0;
309                 key = ieee->tx_keyidx;
310         }
311
312         RTLLIB_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
313                            "provided" : "default");
314         crypt = &ieee->crypt[key];
315         if (erq->flags & IW_ENCODE_DISABLED) {
316                 if (key_provided && *crypt) {
317                         RTLLIB_DEBUG_WX("Disabling encryption on key %d.\n",
318                                            key);
319                         rtllib_crypt_delayed_deinit(ieee, crypt);
320                 } else
321                         RTLLIB_DEBUG_WX("Disabling encryption.\n");
322
323                 /* Check all the keys to see if any are still configured,
324                  * and if no key index was provided, de-init them all */
325                 for (i = 0; i < WEP_KEYS; i++) {
326                         if (ieee->crypt[i] != NULL) {
327                                 if (key_provided)
328                                         break;
329                                 rtllib_crypt_delayed_deinit(ieee, &ieee->crypt[i]);
330                         }
331                 }
332
333                 if (i == WEP_KEYS) {
334                         sec.enabled = 0;
335                         sec.level = SEC_LEVEL_0;
336                         sec.flags |= SEC_ENABLED | SEC_LEVEL;
337                 }
338
339                 goto done;
340         }
341
342
343
344         sec.enabled = 1;
345         sec.flags |= SEC_ENABLED;
346
347         if (*crypt != NULL && (*crypt)->ops != NULL &&
348             strcmp((*crypt)->ops->name, "WEP") != 0) {
349                 /* changing to use WEP; deinit previously used algorithm
350                  * on this key */
351                 rtllib_crypt_delayed_deinit(ieee, crypt);
352         }
353
354         if (*crypt == NULL) {
355                 struct rtllib_crypt_data *new_crypt;
356
357                 /* take WEP into use */
358                 new_crypt = kmalloc(sizeof(struct rtllib_crypt_data),
359                                     GFP_KERNEL);
360                 if (new_crypt == NULL)
361                         return -ENOMEM;
362                 memset(new_crypt, 0, sizeof(struct rtllib_crypt_data));
363                 new_crypt->ops = rtllib_get_crypto_ops("WEP");
364                 if (!new_crypt->ops) {
365                         request_module("rtllib_crypt_wep");
366                         new_crypt->ops = rtllib_get_crypto_ops("WEP");
367                 }
368
369                 if (new_crypt->ops)
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 rtllib_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                 RTLLIB_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                         RTLLIB_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                         RTLLIB_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  done:
431         ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
432         ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
433         sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
434         sec.flags |= SEC_AUTH_MODE;
435         RTLLIB_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
436                            "OPEN" : "SHARED KEY");
437
438         /* For now we just support WEP, so only set that security level...
439          * TODO: When WPA is added this is one place that needs to change */
440         sec.flags |= SEC_LEVEL;
441         sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
442
443         if (ieee->set_security)
444                 ieee->set_security(dev, &sec);
445
446         /* Do not reset port if card is in Managed mode since resetting will
447          * generate new IEEE 802.11 authentication which may end up in looping
448          * with IEEE 802.1X.  If your hardware requires a reset after WEP
449          * configuration (for example... Prism2), implement the reset_port in
450          * the callbacks structures used to initialize the 802.11 stack. */
451         if (ieee->reset_on_keychange &&
452             ieee->iw_mode != IW_MODE_INFRA &&
453             ieee->reset_port && ieee->reset_port(dev)) {
454                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
455                 return -EINVAL;
456         }
457         return 0;
458 }
459
460 int rtllib_wx_get_encode(struct rtllib_device *ieee,
461                             struct iw_request_info *info,
462                             union iwreq_data *wrqu, char *keybuf)
463 {
464         struct iw_point *erq = &(wrqu->encoding);
465         int len, key;
466         struct rtllib_crypt_data *crypt;
467
468         RTLLIB_DEBUG_WX("GET_ENCODE\n");
469
470         if (ieee->iw_mode == IW_MODE_MONITOR)
471                 return -1;
472
473         key = erq->flags & IW_ENCODE_INDEX;
474         if (key) {
475                 if (key > WEP_KEYS)
476                         return -EINVAL;
477                 key--;
478         } else {
479                 key = ieee->tx_keyidx;
480         }
481         crypt = ieee->crypt[key];
482
483         erq->flags = key + 1;
484
485         if (crypt == NULL || crypt->ops == NULL) {
486                 erq->length = 0;
487                 erq->flags |= IW_ENCODE_DISABLED;
488                 return 0;
489         }
490         len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
491         erq->length = (len >= 0 ? len : 0);
492
493         erq->flags |= IW_ENCODE_ENABLED;
494
495         if (ieee->open_wep)
496                 erq->flags |= IW_ENCODE_OPEN;
497         else
498                 erq->flags |= IW_ENCODE_RESTRICTED;
499
500         return 0;
501 }
502
503 int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
504                                struct iw_request_info *info,
505                                union iwreq_data *wrqu, char *extra)
506 {
507         int ret = 0;
508         struct net_device *dev = ieee->dev;
509         struct iw_point *encoding = &wrqu->encoding;
510         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
511         int i, idx;
512         int group_key = 0;
513         const char *alg, *module;
514         struct rtllib_crypto_ops *ops;
515         struct rtllib_crypt_data **crypt;
516
517         struct rtllib_security sec = {
518                 .flags = 0,
519         };
520         idx = encoding->flags & IW_ENCODE_INDEX;
521         if (idx) {
522                 if (idx < 1 || idx > WEP_KEYS)
523                         return -EINVAL;
524                 idx--;
525         } else{
526                         idx = ieee->tx_keyidx;
527         }
528         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
529                 crypt = &ieee->crypt[idx];
530                 group_key = 1;
531         } else {
532                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
533                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
534                         return -EINVAL;
535                 if (ieee->iw_mode == IW_MODE_INFRA)
536                         crypt = &ieee->crypt[idx];
537                 else
538                         return -EINVAL;
539         }
540
541         sec.flags |= SEC_ENABLED;
542         if ((encoding->flags & IW_ENCODE_DISABLED) ||
543             ext->alg == IW_ENCODE_ALG_NONE) {
544                 if (*crypt)
545                         rtllib_crypt_delayed_deinit(ieee, crypt);
546
547                 for (i = 0; i < WEP_KEYS; i++) {
548                         if (ieee->crypt[i] != NULL)
549                                 break;
550                 }
551                 if (i == WEP_KEYS) {
552                         sec.enabled = 0;
553                         sec.level = SEC_LEVEL_0;
554                         sec.flags |= SEC_LEVEL;
555                 }
556                 goto done;
557         }
558
559         sec.enabled = 1;
560         switch (ext->alg) {
561         case IW_ENCODE_ALG_WEP:
562                 alg = "WEP";
563                 module = "rtllib_crypt_wep";
564                 break;
565         case IW_ENCODE_ALG_TKIP:
566                 alg = "TKIP";
567                 module = "rtllib_crypt_tkip";
568                 break;
569         case IW_ENCODE_ALG_CCMP:
570                 alg = "CCMP";
571                 module = "rtllib_crypt_ccmp";
572                 break;
573         default:
574                 RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
575                                    dev->name, ext->alg);
576                 ret = -EINVAL;
577                 goto done;
578         }
579         printk("alg name:%s\n",alg);
580
581          ops = rtllib_get_crypto_ops(alg);
582         if (ops == NULL) {
583                 char tempbuf[100];
584
585                 memset( tempbuf, 0x00, 100 );
586                 sprintf( tempbuf, "%s", module);
587                 request_module("%s",tempbuf);
588                 ops = rtllib_get_crypto_ops(alg);
589         }
590         if (ops == NULL) {
591                 RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
592                                    dev->name, ext->alg);
593                 printk("========>unknown crypto alg %d\n", ext->alg);
594                 ret = -EINVAL;
595                 goto done;
596         }
597
598         if (*crypt == NULL || (*crypt)->ops != ops) {
599                 struct rtllib_crypt_data *new_crypt;
600
601                 rtllib_crypt_delayed_deinit(ieee, crypt);
602
603                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
604                 if (new_crypt == NULL) {
605                         ret = -ENOMEM;
606                         goto done;
607                 }
608                 new_crypt->ops = ops;
609                 if (new_crypt->ops)
610                         new_crypt->priv = new_crypt->ops->init(idx);
611
612                 if (new_crypt->priv == NULL) {
613                         kfree(new_crypt);
614                         ret = -EINVAL;
615                         goto done;
616                 }
617                 *crypt = new_crypt;
618
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                 RTLLIB_DEBUG_WX("%s: key setting failed\n", dev->name);
625                 printk("key setting failed\n");
626                 ret = -EINVAL;
627                 goto done;
628         }
629         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
630                 ieee->tx_keyidx = idx;
631                 sec.active_key = idx;
632                 sec.flags |= SEC_ACTIVE_KEY;
633         }
634         if (ext->alg != IW_ENCODE_ALG_NONE) {
635                 sec.key_sizes[idx] = ext->key_len;
636                 sec.flags |= (1 << idx);
637                 if (ext->alg == IW_ENCODE_ALG_WEP) {
638                         sec.flags |= SEC_LEVEL;
639                         sec.level = SEC_LEVEL_1;
640                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
641                         sec.flags |= SEC_LEVEL;
642                         sec.level = SEC_LEVEL_2;
643                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
644                         sec.flags |= SEC_LEVEL;
645                         sec.level = SEC_LEVEL_3;
646                 }
647                 /* Don't set sec level for group keys. */
648                 if (group_key)
649                         sec.flags &= ~SEC_LEVEL;
650         }
651 done:
652         if (ieee->set_security)
653                 ieee->set_security(ieee->dev, &sec);
654
655          if (ieee->reset_on_keychange &&
656             ieee->iw_mode != IW_MODE_INFRA &&
657             ieee->reset_port && ieee->reset_port(dev)) {
658                 RTLLIB_DEBUG_WX("%s: reset_port failed\n", dev->name);
659                 return -EINVAL;
660         }
661         return ret;
662 }
663
664 int rtllib_wx_get_encode_ext(struct rtllib_device *ieee,
665                                struct iw_request_info *info,
666                                union iwreq_data *wrqu, char *extra)
667 {
668         struct iw_point *encoding = &wrqu->encoding;
669         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
670         struct rtllib_crypt_data *crypt;
671         int idx, max_key_len;
672
673         max_key_len = encoding->length - sizeof(*ext);
674         if (max_key_len < 0)
675                 return -EINVAL;
676
677         idx = encoding->flags & IW_ENCODE_INDEX;
678         if (idx) {
679                 if (idx < 1 || idx > WEP_KEYS)
680                         return -EINVAL;
681                 idx--;
682         } else {
683                 idx = ieee->tx_keyidx;
684         }
685         if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
686             (ext->alg != IW_ENCODE_ALG_WEP))
687                 if (idx != 0 || (ieee->iw_mode != IW_MODE_INFRA))
688                         return -EINVAL;
689
690         crypt = ieee->crypt[idx];
691
692         encoding->flags = idx + 1;
693         memset(ext, 0, sizeof(*ext));
694
695         if (crypt == NULL || crypt->ops == NULL ) {
696                 ext->alg = IW_ENCODE_ALG_NONE;
697                 ext->key_len = 0;
698                 encoding->flags |= IW_ENCODE_DISABLED;
699         } else {
700                 if (strcmp(crypt->ops->name, "WEP") == 0 )
701                         ext->alg = IW_ENCODE_ALG_WEP;
702                 else if (strcmp(crypt->ops->name, "TKIP"))
703                         ext->alg = IW_ENCODE_ALG_TKIP;
704                 else if (strcmp(crypt->ops->name, "CCMP"))
705                         ext->alg = IW_ENCODE_ALG_CCMP;
706                 else
707                         return -EINVAL;
708                 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
709                 encoding->flags |= IW_ENCODE_ENABLED;
710                 if (ext->key_len &&
711                     (ext->alg == IW_ENCODE_ALG_TKIP ||
712                      ext->alg == IW_ENCODE_ALG_CCMP))
713                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
714
715         }
716
717         return 0;
718 }
719
720 int rtllib_wx_set_mlme(struct rtllib_device *ieee,
721                                struct iw_request_info *info,
722                                union iwreq_data *wrqu, char *extra)
723 {
724         u8 i = 0;
725         bool deauth = false;
726         struct iw_mlme *mlme = (struct iw_mlme *) extra;
727
728         if (ieee->state != RTLLIB_LINKED)
729                 return -ENOLINK;
730
731         down(&ieee->wx_sem);
732
733         switch (mlme->cmd) {
734                 case IW_MLME_DEAUTH:
735                         deauth = true;
736                         /* leave break out intentionly */
737
738                 case IW_MLME_DISASSOC:
739                         if (deauth == true)
740                                 printk("disauth packet !\n");
741                         else
742                                 printk("dis associate packet!\n");
743
744                         ieee->cannot_notify = true;
745
746                         SendDisassociation(ieee,deauth,mlme->reason_code);
747                         rtllib_disassociate(ieee);
748
749                         ieee->wap_set = 0;
750                         for (i = 0; i < 6; i++)
751                                 ieee->current_network.bssid[i]= 0x55;
752
753                         ieee->ssid_set = 0;
754                         ieee->current_network.ssid[0] = '\0';
755                         ieee->current_network.ssid_len = 0;
756                 break;
757         default:
758                 up(&ieee->wx_sem);
759                 return -EOPNOTSUPP;
760         }
761
762         up(&ieee->wx_sem);
763
764         return 0;
765 }
766
767 int rtllib_wx_set_auth(struct rtllib_device *ieee,
768                                struct iw_request_info *info,
769                                struct iw_param *data, char *extra)
770 {
771         switch (data->flags & IW_AUTH_INDEX) {
772         case IW_AUTH_WPA_VERSION:
773                 break;
774         case IW_AUTH_CIPHER_PAIRWISE:
775         case IW_AUTH_CIPHER_GROUP:
776         case IW_AUTH_KEY_MGMT:
777                 /*
778                  * Host AP driver does not use these parameters and allows
779                  * wpa_supplicant to control them internally.
780                  */
781                 break;
782         case IW_AUTH_TKIP_COUNTERMEASURES:
783                 ieee->tkip_countermeasures = data->value;
784                 break;
785         case IW_AUTH_DROP_UNENCRYPTED:
786                 ieee->drop_unencrypted = data->value;
787                 break;
788
789         case IW_AUTH_80211_AUTH_ALG:
790                 if (data->value & IW_AUTH_ALG_SHARED_KEY){
791                         ieee->open_wep = 0;
792                         ieee->auth_mode = 1;
793                 }
794                 else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM){
795                         ieee->open_wep = 1;
796                         ieee->auth_mode = 0;
797                 }
798                 else if (data->value & IW_AUTH_ALG_LEAP){
799                         ieee->open_wep = 1;
800                         ieee->auth_mode = 2;
801                 }
802                 else
803                         return -EINVAL;
804                 break;
805
806         case IW_AUTH_WPA_ENABLED:
807                 ieee->wpa_enabled = (data->value)?1:0;
808                 break;
809
810         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
811                 ieee->ieee802_1x = data->value;
812                 break;
813         case IW_AUTH_PRIVACY_INVOKED:
814                 ieee->privacy_invoked = data->value;
815                 break;
816         default:
817                 return -EOPNOTSUPP;
818         }
819         return 0;
820 }
821
822 int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
823 {
824         u8 *buf;
825         u8 eid, wps_oui[4]={0x0,0x50,0xf2,0x04};
826
827         if (len > MAX_WPA_IE_LEN || (len && ie == NULL)) {
828                 return -EINVAL;
829         }
830
831         if (len) {
832                 eid = ie[0];
833                 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2], wps_oui, 4))) {
834
835                         ieee->wps_ie_len = (len < MAX_WZC_IE_LEN) ? (len):(MAX_WZC_IE_LEN);
836                         buf = kmalloc(ieee->wps_ie_len, GFP_KERNEL);
837                         if (buf == NULL)
838                                 return -ENOMEM;
839                         memcpy(buf, ie, ieee->wps_ie_len);
840                         ieee->wps_ie = buf;
841                         return 0;
842                 }
843         }
844         ieee->wps_ie_len = 0;
845         if (ieee->wps_ie)
846                 kfree(ieee->wps_ie);
847         ieee->wps_ie = NULL;
848         if (len) {
849                 if (len != ie[1]+2) {
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         } else {
860                 if (ieee->wpa_ie)
861                 kfree(ieee->wpa_ie);
862                 ieee->wpa_ie = NULL;
863                 ieee->wpa_ie_len = 0;
864         }
865         return 0;
866 }