Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/x86
[linux-2.6] / net / ieee80211 / ieee80211_wx.c
1 /******************************************************************************
2
3   Copyright(c) 2004-2005 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
33 #include <linux/kmod.h>
34 #include <linux/module.h>
35 #include <linux/jiffies.h>
36
37 #include <net/ieee80211.h>
38 #include <linux/wireless.h>
39
40 static const char *ieee80211_modes[] = {
41         "?", "a", "b", "ab", "g", "ag", "bg", "abg"
42 };
43
44 #define MAX_CUSTOM_LEN 64
45 static char *ipw2100_translate_scan(struct ieee80211_device *ieee,
46                                            char *start, char *stop,
47                                            struct ieee80211_network *network)
48 {
49         char custom[MAX_CUSTOM_LEN];
50         char *p;
51         struct iw_event iwe;
52         int i, j;
53         u8 max_rate, rate;
54
55         /* First entry *MUST* be the AP MAC address */
56         iwe.cmd = SIOCGIWAP;
57         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
58         memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
59         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
60
61         /* Remaining entries will be displayed in the order we provide them */
62
63         /* Add the ESSID */
64         iwe.cmd = SIOCGIWESSID;
65         iwe.u.data.flags = 1;
66         if (network->flags & NETWORK_EMPTY_ESSID) {
67                 iwe.u.data.length = sizeof("<hidden>");
68                 start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
69         } else {
70                 iwe.u.data.length = min(network->ssid_len, (u8) 32);
71                 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
72         }
73
74         /* Add the protocol name */
75         iwe.cmd = SIOCGIWNAME;
76         snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
77                  ieee80211_modes[network->mode]);
78         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
79
80         /* Add mode */
81         iwe.cmd = SIOCGIWMODE;
82         if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
83                 if (network->capability & WLAN_CAPABILITY_ESS)
84                         iwe.u.mode = IW_MODE_MASTER;
85                 else
86                         iwe.u.mode = IW_MODE_ADHOC;
87
88                 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
89         }
90
91         /* Add frequency/channel */
92         iwe.cmd = SIOCGIWFREQ;
93 /*      iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
94         iwe.u.freq.e = 3; */
95         iwe.u.freq.m = network->channel;
96         iwe.u.freq.e = 0;
97         iwe.u.freq.i = 0;
98         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
99
100         /* Add encryption capability */
101         iwe.cmd = SIOCGIWENCODE;
102         if (network->capability & WLAN_CAPABILITY_PRIVACY)
103                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
104         else
105                 iwe.u.data.flags = IW_ENCODE_DISABLED;
106         iwe.u.data.length = 0;
107         start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
108
109         /* Add basic and extended rates */
110         max_rate = 0;
111         p = custom;
112         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
113         for (i = 0, j = 0; i < network->rates_len;) {
114                 if (j < network->rates_ex_len &&
115                     ((network->rates_ex[j] & 0x7F) <
116                      (network->rates[i] & 0x7F)))
117                         rate = network->rates_ex[j++] & 0x7F;
118                 else
119                         rate = network->rates[i++] & 0x7F;
120                 if (rate > max_rate)
121                         max_rate = rate;
122                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
123                               "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
124         }
125         for (; j < network->rates_ex_len; j++) {
126                 rate = network->rates_ex[j] & 0x7F;
127                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
128                               "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
129                 if (rate > max_rate)
130                         max_rate = rate;
131         }
132
133         iwe.cmd = SIOCGIWRATE;
134         iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
135         iwe.u.bitrate.value = max_rate * 500000;
136         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN);
137
138         iwe.cmd = IWEVCUSTOM;
139         iwe.u.data.length = p - custom;
140         if (iwe.u.data.length)
141                 start = iwe_stream_add_point(start, stop, &iwe, custom);
142
143         /* Add quality statistics */
144         iwe.cmd = IWEVQUAL;
145         iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
146             IW_QUAL_NOISE_UPDATED;
147
148         if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
149                 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
150                     IW_QUAL_LEVEL_INVALID;
151                 iwe.u.qual.qual = 0;
152                 iwe.u.qual.level = 0;
153         } else {
154                 iwe.u.qual.level = network->stats.rssi;
155                 if (ieee->perfect_rssi == ieee->worst_rssi)
156                         iwe.u.qual.qual = 100;
157                 else
158                         iwe.u.qual.qual =
159                             (100 *
160                              (ieee->perfect_rssi - ieee->worst_rssi) *
161                              (ieee->perfect_rssi - ieee->worst_rssi) -
162                              (ieee->perfect_rssi - network->stats.rssi) *
163                              (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
164                               62 * (ieee->perfect_rssi -
165                                     network->stats.rssi))) /
166                             ((ieee->perfect_rssi -
167                               ieee->worst_rssi) * (ieee->perfect_rssi -
168                                                    ieee->worst_rssi));
169                 if (iwe.u.qual.qual > 100)
170                         iwe.u.qual.qual = 100;
171                 else if (iwe.u.qual.qual < 1)
172                         iwe.u.qual.qual = 0;
173         }
174
175         if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
176                 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
177                 iwe.u.qual.noise = 0;
178         } else {
179                 iwe.u.qual.noise = network->stats.noise;
180         }
181
182         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
183
184         iwe.cmd = IWEVCUSTOM;
185         p = custom;
186
187         iwe.u.data.length = p - custom;
188         if (iwe.u.data.length)
189                 start = iwe_stream_add_point(start, stop, &iwe, custom);
190
191         if (network->wpa_ie_len) {
192                 char buf[MAX_WPA_IE_LEN * 2 + 30];
193
194                 u8 *p = buf;
195                 p += sprintf(p, "wpa_ie=");
196                 for (i = 0; i < network->wpa_ie_len; i++) {
197                         p += sprintf(p, "%02x", network->wpa_ie[i]);
198                 }
199
200                 memset(&iwe, 0, sizeof(iwe));
201                 iwe.cmd = IWEVCUSTOM;
202                 iwe.u.data.length = strlen(buf);
203                 start = iwe_stream_add_point(start, stop, &iwe, buf);
204         }
205
206         if (network->rsn_ie_len) {
207                 char buf[MAX_WPA_IE_LEN * 2 + 30];
208
209                 u8 *p = buf;
210                 p += sprintf(p, "rsn_ie=");
211                 for (i = 0; i < network->rsn_ie_len; i++) {
212                         p += sprintf(p, "%02x", network->rsn_ie[i]);
213                 }
214
215                 memset(&iwe, 0, sizeof(iwe));
216                 iwe.cmd = IWEVCUSTOM;
217                 iwe.u.data.length = strlen(buf);
218                 start = iwe_stream_add_point(start, stop, &iwe, buf);
219         }
220
221         /* Add EXTRA: Age to display seconds since last beacon/probe response
222          * for given network. */
223         iwe.cmd = IWEVCUSTOM;
224         p = custom;
225         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
226                       " Last beacon: %dms ago",
227                       jiffies_to_msecs(jiffies - network->last_scanned));
228         iwe.u.data.length = p - custom;
229         if (iwe.u.data.length)
230                 start = iwe_stream_add_point(start, stop, &iwe, custom);
231
232         return start;
233 }
234
235 #define SCAN_ITEM_SIZE 128
236
237 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
238                           struct iw_request_info *info,
239                           union iwreq_data *wrqu, char *extra)
240 {
241         struct ieee80211_network *network;
242         unsigned long flags;
243         int err = 0;
244
245         char *ev = extra;
246         char *stop = ev + wrqu->data.length;
247         int i = 0;
248
249         IEEE80211_DEBUG_WX("Getting scan\n");
250
251         spin_lock_irqsave(&ieee->lock, flags);
252
253         list_for_each_entry(network, &ieee->network_list, list) {
254                 i++;
255                 if (stop - ev < SCAN_ITEM_SIZE) {
256                         err = -E2BIG;
257                         break;
258                 }
259
260                 if (ieee->scan_age == 0 ||
261                     time_after(network->last_scanned + ieee->scan_age, jiffies))
262                         ev = ipw2100_translate_scan(ieee, ev, stop, network);
263                 else
264                         IEEE80211_DEBUG_SCAN("Not showing network '%s ("
265                                              MAC_FMT ")' due to age (%dms).\n",
266                                              escape_essid(network->ssid,
267                                                           network->ssid_len),
268                                              MAC_ARG(network->bssid),
269                                              jiffies_to_msecs(jiffies -
270                                                               network->
271                                                               last_scanned));
272         }
273
274         spin_unlock_irqrestore(&ieee->lock, flags);
275
276         wrqu->data.length = ev - extra;
277         wrqu->data.flags = 0;
278
279         IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
280
281         return err;
282 }
283
284 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
285                             struct iw_request_info *info,
286                             union iwreq_data *wrqu, char *keybuf)
287 {
288         struct iw_point *erq = &(wrqu->encoding);
289         struct net_device *dev = ieee->dev;
290         struct ieee80211_security sec = {
291                 .flags = 0
292         };
293         int i, key, key_provided, len;
294         struct ieee80211_crypt_data **crypt;
295         int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
296
297         IEEE80211_DEBUG_WX("SET_ENCODE\n");
298
299         key = erq->flags & IW_ENCODE_INDEX;
300         if (key) {
301                 if (key > WEP_KEYS)
302                         return -EINVAL;
303                 key--;
304                 key_provided = 1;
305         } else {
306                 key_provided = 0;
307                 key = ieee->tx_keyidx;
308         }
309
310         IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
311                            "provided" : "default");
312
313         crypt = &ieee->crypt[key];
314
315         if (erq->flags & IW_ENCODE_DISABLED) {
316                 if (key_provided && *crypt) {
317                         IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
318                                            key);
319                         ieee80211_crypt_delayed_deinit(ieee, crypt);
320                 } else
321                         IEEE80211_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                                 ieee80211_crypt_delayed_deinit(ieee,
330                                                                &ieee->crypt[i]);
331                         }
332                 }
333
334                 if (i == WEP_KEYS) {
335                         sec.enabled = 0;
336                         sec.encrypt = 0;
337                         sec.level = SEC_LEVEL_0;
338                         sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
339                 }
340
341                 goto done;
342         }
343
344         sec.enabled = 1;
345         sec.encrypt = 1;
346         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
347
348         if (*crypt != NULL && (*crypt)->ops != NULL &&
349             strcmp((*crypt)->ops->name, "WEP") != 0) {
350                 /* changing to use WEP; deinit previously used algorithm
351                  * on this key */
352                 ieee80211_crypt_delayed_deinit(ieee, crypt);
353         }
354
355         if (*crypt == NULL && host_crypto) {
356                 struct ieee80211_crypt_data *new_crypt;
357
358                 /* take WEP into use */
359                 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
360                                     GFP_KERNEL);
361                 if (new_crypt == NULL)
362                         return -ENOMEM;
363                 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
364                 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
365                 if (!new_crypt->ops) {
366                         request_module("ieee80211_crypt_wep");
367                         new_crypt->ops = ieee80211_get_crypto_ops("WEP");
368                 }
369
370                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
371                         new_crypt->priv = new_crypt->ops->init(key);
372
373                 if (!new_crypt->ops || !new_crypt->priv) {
374                         kfree(new_crypt);
375                         new_crypt = NULL;
376
377                         printk(KERN_WARNING "%s: could not initialize WEP: "
378                                "load module ieee80211_crypt_wep\n", 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                 if (*crypt)
396                         (*crypt)->ops->set_key(sec.keys[key], len, NULL,
397                                                (*crypt)->priv);
398                 sec.flags |= (1 << key);
399                 /* This ensures a key will be activated if no key is
400                  * explicitely set */
401                 if (key == sec.active_key)
402                         sec.flags |= SEC_ACTIVE_KEY;
403
404         } else {
405                 if (host_crypto) {
406                         len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
407                                                      NULL, (*crypt)->priv);
408                         if (len == 0) {
409                                 /* Set a default key of all 0 */
410                                 IEEE80211_DEBUG_WX("Setting key %d to all "
411                                                    "zero.\n", key);
412                                 memset(sec.keys[key], 0, 13);
413                                 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
414                                                        (*crypt)->priv);
415                                 sec.key_sizes[key] = 13;
416                                 sec.flags |= (1 << key);
417                         }
418                 }
419                 /* No key data - just set the default TX key index */
420                 if (key_provided) {
421                         IEEE80211_DEBUG_WX("Setting key %d to default Tx "
422                                            "key.\n", key);
423                         ieee->tx_keyidx = key;
424                         sec.active_key = key;
425                         sec.flags |= SEC_ACTIVE_KEY;
426                 }
427         }
428         if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
429                 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
430                 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
431                     WLAN_AUTH_SHARED_KEY;
432                 sec.flags |= SEC_AUTH_MODE;
433                 IEEE80211_DEBUG_WX("Auth: %s\n",
434                                    sec.auth_mode == WLAN_AUTH_OPEN ?
435                                    "OPEN" : "SHARED KEY");
436         }
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         sec.encode_alg[key] = SEC_ALG_WEP;
443
444       done:
445         if (ieee->set_security)
446                 ieee->set_security(dev, &sec);
447
448         /* Do not reset port if card is in Managed mode since resetting will
449          * generate new IEEE 802.11 authentication which may end up in looping
450          * with IEEE 802.1X.  If your hardware requires a reset after WEP
451          * configuration (for example... Prism2), implement the reset_port in
452          * the callbacks structures used to initialize the 802.11 stack. */
453         if (ieee->reset_on_keychange &&
454             ieee->iw_mode != IW_MODE_INFRA &&
455             ieee->reset_port && ieee->reset_port(dev)) {
456                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
457                 return -EINVAL;
458         }
459         return 0;
460 }
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         struct ieee80211_security *sec = &ieee->sec;
470
471         IEEE80211_DEBUG_WX("GET_ENCODE\n");
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         erq->flags = key + 1;
483
484         if (!sec->enabled) {
485                 erq->length = 0;
486                 erq->flags |= IW_ENCODE_DISABLED;
487                 return 0;
488         }
489
490         len = sec->key_sizes[key];
491         memcpy(keybuf, sec->keys[key], len);
492
493         erq->length = (len >= 0 ? len : 0);
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
504 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
505                                struct iw_request_info *info,
506                                union iwreq_data *wrqu, char *extra)
507 {
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, ret = 0;
512         int group_key = 0;
513         const char *alg, *module;
514         struct ieee80211_crypto_ops *ops;
515         struct ieee80211_crypt_data **crypt;
516
517         struct ieee80211_security sec = {
518                 .flags = 0,
519         };
520
521         idx = encoding->flags & IW_ENCODE_INDEX;
522         if (idx) {
523                 if (idx < 1 || idx > WEP_KEYS)
524                         return -EINVAL;
525                 idx--;
526         } else
527                 idx = ieee->tx_keyidx;
528
529         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
530                 crypt = &ieee->crypt[idx];
531                 group_key = 1;
532         } else {
533                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
534                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
535                         return -EINVAL;
536                 if (ieee->iw_mode == IW_MODE_INFRA)
537                         crypt = &ieee->crypt[idx];
538                 else
539                         return -EINVAL;
540         }
541
542         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
543         if ((encoding->flags & IW_ENCODE_DISABLED) ||
544             ext->alg == IW_ENCODE_ALG_NONE) {
545                 if (*crypt)
546                         ieee80211_crypt_delayed_deinit(ieee, crypt);
547
548                 for (i = 0; i < WEP_KEYS; i++)
549                         if (ieee->crypt[i] != NULL)
550                                 break;
551
552                 if (i == WEP_KEYS) {
553                         sec.enabled = 0;
554                         sec.encrypt = 0;
555                         sec.level = SEC_LEVEL_0;
556                         sec.flags |= SEC_LEVEL;
557                 }
558                 goto done;
559         }
560
561         sec.enabled = 1;
562         sec.encrypt = 1;
563
564         if (group_key ? !ieee->host_mc_decrypt :
565             !(ieee->host_encrypt || ieee->host_decrypt ||
566               ieee->host_encrypt_msdu))
567                 goto skip_host_crypt;
568
569         switch (ext->alg) {
570         case IW_ENCODE_ALG_WEP:
571                 alg = "WEP";
572                 module = "ieee80211_crypt_wep";
573                 break;
574         case IW_ENCODE_ALG_TKIP:
575                 alg = "TKIP";
576                 module = "ieee80211_crypt_tkip";
577                 break;
578         case IW_ENCODE_ALG_CCMP:
579                 alg = "CCMP";
580                 module = "ieee80211_crypt_ccmp";
581                 break;
582         default:
583                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
584                                    dev->name, ext->alg);
585                 ret = -EINVAL;
586                 goto done;
587         }
588
589         ops = ieee80211_get_crypto_ops(alg);
590         if (ops == NULL) {
591                 request_module(module);
592                 ops = ieee80211_get_crypto_ops(alg);
593         }
594         if (ops == NULL) {
595                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
596                                    dev->name, ext->alg);
597                 ret = -EINVAL;
598                 goto done;
599         }
600
601         if (*crypt == NULL || (*crypt)->ops != ops) {
602                 struct ieee80211_crypt_data *new_crypt;
603
604                 ieee80211_crypt_delayed_deinit(ieee, crypt);
605
606                 new_crypt = (struct ieee80211_crypt_data *)
607                     kmalloc(sizeof(*new_crypt), GFP_KERNEL);
608                 if (new_crypt == NULL) {
609                         ret = -ENOMEM;
610                         goto done;
611                 }
612                 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
613                 new_crypt->ops = ops;
614                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
615                         new_crypt->priv = new_crypt->ops->init(idx);
616                 if (new_crypt->priv == NULL) {
617                         kfree(new_crypt);
618                         ret = -EINVAL;
619                         goto done;
620                 }
621                 *crypt = new_crypt;
622         }
623
624         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
625             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
626                                    (*crypt)->priv) < 0) {
627                 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
628                 ret = -EINVAL;
629                 goto done;
630         }
631
632       skip_host_crypt:
633         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
634                 ieee->tx_keyidx = idx;
635                 sec.active_key = idx;
636                 sec.flags |= SEC_ACTIVE_KEY;
637         }
638
639         if (ext->alg != IW_ENCODE_ALG_NONE) {
640                 memcpy(sec.keys[idx], ext->key, ext->key_len);
641                 sec.key_sizes[idx] = ext->key_len;
642                 sec.flags |= (1 << idx);
643                 if (ext->alg == IW_ENCODE_ALG_WEP) {
644                         sec.encode_alg[idx] = SEC_ALG_WEP;
645                         sec.flags |= SEC_LEVEL;
646                         sec.level = SEC_LEVEL_1;
647                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
648                         sec.encode_alg[idx] = SEC_ALG_TKIP;
649                         sec.flags |= SEC_LEVEL;
650                         sec.level = SEC_LEVEL_2;
651                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
652                         sec.encode_alg[idx] = SEC_ALG_CCMP;
653                         sec.flags |= SEC_LEVEL;
654                         sec.level = SEC_LEVEL_3;
655                 }
656                 /* Don't set sec level for group keys. */
657                 if (group_key)
658                         sec.flags &= ~SEC_LEVEL;
659         }
660       done:
661         if (ieee->set_security)
662                 ieee->set_security(ieee->dev, &sec);
663
664         /*
665          * Do not reset port if card is in Managed mode since resetting will
666          * generate new IEEE 802.11 authentication which may end up in looping
667          * with IEEE 802.1X. If your hardware requires a reset after WEP
668          * configuration (for example... Prism2), implement the reset_port in
669          * the callbacks structures used to initialize the 802.11 stack.
670          */
671         if (ieee->reset_on_keychange &&
672             ieee->iw_mode != IW_MODE_INFRA &&
673             ieee->reset_port && ieee->reset_port(dev)) {
674                 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
675                 return -EINVAL;
676         }
677
678         return ret;
679 }
680
681 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
682                                struct iw_request_info *info,
683                                union iwreq_data *wrqu, char *extra)
684 {
685         struct iw_point *encoding = &wrqu->encoding;
686         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
687         struct ieee80211_security *sec = &ieee->sec;
688         int idx, max_key_len;
689
690         max_key_len = encoding->length - sizeof(*ext);
691         if (max_key_len < 0)
692                 return -EINVAL;
693
694         idx = encoding->flags & IW_ENCODE_INDEX;
695         if (idx) {
696                 if (idx < 1 || idx > WEP_KEYS)
697                         return -EINVAL;
698                 idx--;
699         } else
700                 idx = ieee->tx_keyidx;
701
702         if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
703             ext->alg != IW_ENCODE_ALG_WEP)
704                 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
705                         return -EINVAL;
706
707         encoding->flags = idx + 1;
708         memset(ext, 0, sizeof(*ext));
709
710         if (!sec->enabled) {
711                 ext->alg = IW_ENCODE_ALG_NONE;
712                 ext->key_len = 0;
713                 encoding->flags |= IW_ENCODE_DISABLED;
714         } else {
715                 if (sec->encode_alg[idx] == SEC_ALG_WEP)
716                         ext->alg = IW_ENCODE_ALG_WEP;
717                 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
718                         ext->alg = IW_ENCODE_ALG_TKIP;
719                 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
720                         ext->alg = IW_ENCODE_ALG_CCMP;
721                 else
722                         return -EINVAL;
723
724                 ext->key_len = sec->key_sizes[idx];
725                 memcpy(ext->key, sec->keys[idx], ext->key_len);
726                 encoding->flags |= IW_ENCODE_ENABLED;
727                 if (ext->key_len &&
728                     (ext->alg == IW_ENCODE_ALG_TKIP ||
729                      ext->alg == IW_ENCODE_ALG_CCMP))
730                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
731
732         }
733
734         return 0;
735 }
736
737 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
738 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
739
740 EXPORT_SYMBOL(ieee80211_wx_get_scan);
741 EXPORT_SYMBOL(ieee80211_wx_set_encode);
742 EXPORT_SYMBOL(ieee80211_wx_get_encode);