This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / 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 *ieee80211_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         } else {
153                 if (ieee->perfect_rssi == ieee->worst_rssi)
154                         iwe.u.qual.qual = 100;
155                 else
156                         iwe.u.qual.qual =
157                             (100 *
158                              (ieee->perfect_rssi - ieee->worst_rssi) *
159                              (ieee->perfect_rssi - ieee->worst_rssi) -
160                              (ieee->perfect_rssi - network->stats.rssi) *
161                              (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
162                               62 * (ieee->perfect_rssi -
163                                     network->stats.rssi))) /
164                             ((ieee->perfect_rssi -
165                               ieee->worst_rssi) * (ieee->perfect_rssi -
166                                                    ieee->worst_rssi));
167                 if (iwe.u.qual.qual > 100)
168                         iwe.u.qual.qual = 100;
169                 else if (iwe.u.qual.qual < 1)
170                         iwe.u.qual.qual = 0;
171         }
172
173         if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
174                 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
175                 iwe.u.qual.noise = 0;
176         } else {
177                 iwe.u.qual.noise = network->stats.noise;
178         }
179
180         if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
181                 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
182                 iwe.u.qual.level = 0;
183         } else {
184                 iwe.u.qual.level = network->stats.signal;
185         }
186
187         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
188
189         iwe.cmd = IWEVCUSTOM;
190         p = custom;
191
192         iwe.u.data.length = p - custom;
193         if (iwe.u.data.length)
194                 start = iwe_stream_add_point(start, stop, &iwe, custom);
195
196         memset(&iwe, 0, sizeof(iwe));
197         if (network->wpa_ie_len) {
198                 char buf[MAX_WPA_IE_LEN];
199                 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
200                 iwe.cmd = IWEVGENIE;
201                 iwe.u.data.length = network->wpa_ie_len;
202                 start = iwe_stream_add_point(start, stop, &iwe, buf);
203         }
204
205         memset(&iwe, 0, sizeof(iwe));
206         if (network->rsn_ie_len) {
207                 char buf[MAX_WPA_IE_LEN];
208                 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
209                 iwe.cmd = IWEVGENIE;
210                 iwe.u.data.length = network->rsn_ie_len;
211                 start = iwe_stream_add_point(start, stop, &iwe, buf);
212         }
213
214         /* Add EXTRA: Age to display seconds since last beacon/probe response
215          * for given network. */
216         iwe.cmd = IWEVCUSTOM;
217         p = custom;
218         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
219                       " Last beacon: %dms ago",
220                       jiffies_to_msecs(jiffies - network->last_scanned));
221         iwe.u.data.length = p - custom;
222         if (iwe.u.data.length)
223                 start = iwe_stream_add_point(start, stop, &iwe, custom);
224
225         /* Add spectrum management information */
226         iwe.cmd = -1;
227         p = custom;
228         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
229
230         if (ieee80211_get_channel_flags(ieee, network->channel) &
231             IEEE80211_CH_INVALID) {
232                 iwe.cmd = IWEVCUSTOM;
233                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
234         }
235
236         if (ieee80211_get_channel_flags(ieee, network->channel) &
237             IEEE80211_CH_RADAR_DETECT) {
238                 iwe.cmd = IWEVCUSTOM;
239                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
240         }
241
242         if (iwe.cmd == IWEVCUSTOM) {
243                 iwe.u.data.length = p - custom;
244                 start = iwe_stream_add_point(start, stop, &iwe, custom);
245         }
246
247         return start;
248 }
249
250 #define SCAN_ITEM_SIZE 128
251
252 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
253                           struct iw_request_info *info,
254                           union iwreq_data *wrqu, char *extra)
255 {
256         struct ieee80211_network *network;
257         unsigned long flags;
258         int err = 0;
259
260         char *ev = extra;
261         char *stop = ev + wrqu->data.length;
262         int i = 0;
263
264         IEEE80211_DEBUG_WX("Getting scan\n");
265
266         spin_lock_irqsave(&ieee->lock, flags);
267
268         list_for_each_entry(network, &ieee->network_list, list) {
269                 i++;
270                 if (stop - ev < SCAN_ITEM_SIZE) {
271                         err = -E2BIG;
272                         break;
273                 }
274
275                 if (ieee->scan_age == 0 ||
276                     time_after(network->last_scanned + ieee->scan_age, jiffies))
277                         ev = ieee80211_translate_scan(ieee, ev, stop, network);
278                 else
279                         IEEE80211_DEBUG_SCAN("Not showing network '%s ("
280                                              MAC_FMT ")' due to age (%dms).\n",
281                                              escape_essid(network->ssid,
282                                                           network->ssid_len),
283                                              MAC_ARG(network->bssid),
284                                              jiffies_to_msecs(jiffies -
285                                                               network->
286                                                               last_scanned));
287         }
288
289         spin_unlock_irqrestore(&ieee->lock, flags);
290
291         wrqu->data.length = ev - extra;
292         wrqu->data.flags = 0;
293
294         IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
295
296         return err;
297 }
298
299 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
300                             struct iw_request_info *info,
301                             union iwreq_data *wrqu, char *keybuf)
302 {
303         struct iw_point *erq = &(wrqu->encoding);
304         struct net_device *dev = ieee->dev;
305         struct ieee80211_security sec = {
306                 .flags = 0
307         };
308         int i, key, key_provided, len;
309         struct ieee80211_crypt_data **crypt;
310         int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
311
312         IEEE80211_DEBUG_WX("SET_ENCODE\n");
313
314         key = erq->flags & IW_ENCODE_INDEX;
315         if (key) {
316                 if (key > WEP_KEYS)
317                         return -EINVAL;
318                 key--;
319                 key_provided = 1;
320         } else {
321                 key_provided = 0;
322                 key = ieee->tx_keyidx;
323         }
324
325         IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
326                            "provided" : "default");
327
328         crypt = &ieee->crypt[key];
329
330         if (erq->flags & IW_ENCODE_DISABLED) {
331                 if (key_provided && *crypt) {
332                         IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
333                                            key);
334                         ieee80211_crypt_delayed_deinit(ieee, crypt);
335                 } else
336                         IEEE80211_DEBUG_WX("Disabling encryption.\n");
337
338                 /* Check all the keys to see if any are still configured,
339                  * and if no key index was provided, de-init them all */
340                 for (i = 0; i < WEP_KEYS; i++) {
341                         if (ieee->crypt[i] != NULL) {
342                                 if (key_provided)
343                                         break;
344                                 ieee80211_crypt_delayed_deinit(ieee,
345                                                                &ieee->crypt[i]);
346                         }
347                 }
348
349                 if (i == WEP_KEYS) {
350                         sec.enabled = 0;
351                         sec.encrypt = 0;
352                         sec.level = SEC_LEVEL_0;
353                         sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
354                 }
355
356                 goto done;
357         }
358
359         sec.enabled = 1;
360         sec.encrypt = 1;
361         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
362
363         if (*crypt != NULL && (*crypt)->ops != NULL &&
364             strcmp((*crypt)->ops->name, "WEP") != 0) {
365                 /* changing to use WEP; deinit previously used algorithm
366                  * on this key */
367                 ieee80211_crypt_delayed_deinit(ieee, crypt);
368         }
369
370         if (*crypt == NULL && host_crypto) {
371                 struct ieee80211_crypt_data *new_crypt;
372
373                 /* take WEP into use */
374                 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
375                                     GFP_KERNEL);
376                 if (new_crypt == NULL)
377                         return -ENOMEM;
378                 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
379                 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
380                 if (!new_crypt->ops) {
381                         request_module("ieee80211_crypt_wep");
382                         new_crypt->ops = ieee80211_get_crypto_ops("WEP");
383                 }
384
385                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
386                         new_crypt->priv = new_crypt->ops->init(key);
387
388                 if (!new_crypt->ops || !new_crypt->priv) {
389                         kfree(new_crypt);
390                         new_crypt = NULL;
391
392                         printk(KERN_WARNING "%s: could not initialize WEP: "
393                                "load module ieee80211_crypt_wep\n", dev->name);
394                         return -EOPNOTSUPP;
395                 }
396                 *crypt = new_crypt;
397         }
398
399         /* If a new key was provided, set it up */
400         if (erq->length > 0) {
401                 len = erq->length <= 5 ? 5 : 13;
402                 memcpy(sec.keys[key], keybuf, erq->length);
403                 if (len > erq->length)
404                         memset(sec.keys[key] + erq->length, 0,
405                                len - erq->length);
406                 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
407                                    key, escape_essid(sec.keys[key], len),
408                                    erq->length, len);
409                 sec.key_sizes[key] = len;
410                 if (*crypt)
411                         (*crypt)->ops->set_key(sec.keys[key], len, NULL,
412                                                (*crypt)->priv);
413                 sec.flags |= (1 << key);
414                 /* This ensures a key will be activated if no key is
415                  * explicitely set */
416                 if (key == sec.active_key)
417                         sec.flags |= SEC_ACTIVE_KEY;
418
419         } else {
420                 if (host_crypto) {
421                         len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
422                                                      NULL, (*crypt)->priv);
423                         if (len == 0) {
424                                 /* Set a default key of all 0 */
425                                 IEEE80211_DEBUG_WX("Setting key %d to all "
426                                                    "zero.\n", key);
427                                 memset(sec.keys[key], 0, 13);
428                                 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
429                                                        (*crypt)->priv);
430                                 sec.key_sizes[key] = 13;
431                                 sec.flags |= (1 << key);
432                         }
433                 }
434                 /* No key data - just set the default TX key index */
435                 if (key_provided) {
436                         IEEE80211_DEBUG_WX("Setting key %d to default Tx "
437                                            "key.\n", key);
438                         ieee->tx_keyidx = key;
439                         sec.active_key = key;
440                         sec.flags |= SEC_ACTIVE_KEY;
441                 }
442         }
443         if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
444                 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
445                 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
446                     WLAN_AUTH_SHARED_KEY;
447                 sec.flags |= SEC_AUTH_MODE;
448                 IEEE80211_DEBUG_WX("Auth: %s\n",
449                                    sec.auth_mode == WLAN_AUTH_OPEN ?
450                                    "OPEN" : "SHARED KEY");
451         }
452
453         /* For now we just support WEP, so only set that security level...
454          * TODO: When WPA is added this is one place that needs to change */
455         sec.flags |= SEC_LEVEL;
456         sec.level = SEC_LEVEL_1;        /* 40 and 104 bit WEP */
457         sec.encode_alg[key] = SEC_ALG_WEP;
458
459       done:
460         if (ieee->set_security)
461                 ieee->set_security(dev, &sec);
462
463         /* Do not reset port if card is in Managed mode since resetting will
464          * generate new IEEE 802.11 authentication which may end up in looping
465          * with IEEE 802.1X.  If your hardware requires a reset after WEP
466          * configuration (for example... Prism2), implement the reset_port in
467          * the callbacks structures used to initialize the 802.11 stack. */
468         if (ieee->reset_on_keychange &&
469             ieee->iw_mode != IW_MODE_INFRA &&
470             ieee->reset_port && ieee->reset_port(dev)) {
471                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
472                 return -EINVAL;
473         }
474         return 0;
475 }
476
477 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
478                             struct iw_request_info *info,
479                             union iwreq_data *wrqu, char *keybuf)
480 {
481         struct iw_point *erq = &(wrqu->encoding);
482         int len, key;
483         struct ieee80211_crypt_data *crypt;
484         struct ieee80211_security *sec = &ieee->sec;
485
486         IEEE80211_DEBUG_WX("GET_ENCODE\n");
487
488         key = erq->flags & IW_ENCODE_INDEX;
489         if (key) {
490                 if (key > WEP_KEYS)
491                         return -EINVAL;
492                 key--;
493         } else
494                 key = ieee->tx_keyidx;
495
496         crypt = ieee->crypt[key];
497         erq->flags = key + 1;
498
499         if (!sec->enabled) {
500                 erq->length = 0;
501                 erq->flags |= IW_ENCODE_DISABLED;
502                 return 0;
503         }
504
505         len = sec->key_sizes[key];
506         memcpy(keybuf, sec->keys[key], len);
507
508         erq->length = (len >= 0 ? len : 0);
509         erq->flags |= IW_ENCODE_ENABLED;
510
511         if (ieee->open_wep)
512                 erq->flags |= IW_ENCODE_OPEN;
513         else
514                 erq->flags |= IW_ENCODE_RESTRICTED;
515
516         return 0;
517 }
518
519 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
520                                struct iw_request_info *info,
521                                union iwreq_data *wrqu, char *extra)
522 {
523         struct net_device *dev = ieee->dev;
524         struct iw_point *encoding = &wrqu->encoding;
525         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
526         int i, idx, ret = 0;
527         int group_key = 0;
528         const char *alg, *module;
529         struct ieee80211_crypto_ops *ops;
530         struct ieee80211_crypt_data **crypt;
531
532         struct ieee80211_security sec = {
533                 .flags = 0,
534         };
535
536         idx = encoding->flags & IW_ENCODE_INDEX;
537         if (idx) {
538                 if (idx < 1 || idx > WEP_KEYS)
539                         return -EINVAL;
540                 idx--;
541         } else
542                 idx = ieee->tx_keyidx;
543
544         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
545                 crypt = &ieee->crypt[idx];
546                 group_key = 1;
547         } else {
548                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
549                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
550                         return -EINVAL;
551                 if (ieee->iw_mode == IW_MODE_INFRA)
552                         crypt = &ieee->crypt[idx];
553                 else
554                         return -EINVAL;
555         }
556
557         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
558         if ((encoding->flags & IW_ENCODE_DISABLED) ||
559             ext->alg == IW_ENCODE_ALG_NONE) {
560                 if (*crypt)
561                         ieee80211_crypt_delayed_deinit(ieee, crypt);
562
563                 for (i = 0; i < WEP_KEYS; i++)
564                         if (ieee->crypt[i] != NULL)
565                                 break;
566
567                 if (i == WEP_KEYS) {
568                         sec.enabled = 0;
569                         sec.encrypt = 0;
570                         sec.level = SEC_LEVEL_0;
571                         sec.flags |= SEC_LEVEL;
572                 }
573                 goto done;
574         }
575
576         sec.enabled = 1;
577         sec.encrypt = 1;
578
579         if (group_key ? !ieee->host_mc_decrypt :
580             !(ieee->host_encrypt || ieee->host_decrypt ||
581               ieee->host_encrypt_msdu))
582                 goto skip_host_crypt;
583
584         switch (ext->alg) {
585         case IW_ENCODE_ALG_WEP:
586                 alg = "WEP";
587                 module = "ieee80211_crypt_wep";
588                 break;
589         case IW_ENCODE_ALG_TKIP:
590                 alg = "TKIP";
591                 module = "ieee80211_crypt_tkip";
592                 break;
593         case IW_ENCODE_ALG_CCMP:
594                 alg = "CCMP";
595                 module = "ieee80211_crypt_ccmp";
596                 break;
597         default:
598                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
599                                    dev->name, ext->alg);
600                 ret = -EINVAL;
601                 goto done;
602         }
603
604         ops = ieee80211_get_crypto_ops(alg);
605         if (ops == NULL) {
606                 request_module(module);
607                 ops = ieee80211_get_crypto_ops(alg);
608         }
609         if (ops == NULL) {
610                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
611                                    dev->name, ext->alg);
612                 ret = -EINVAL;
613                 goto done;
614         }
615
616         if (*crypt == NULL || (*crypt)->ops != ops) {
617                 struct ieee80211_crypt_data *new_crypt;
618
619                 ieee80211_crypt_delayed_deinit(ieee, crypt);
620
621                 new_crypt = (struct ieee80211_crypt_data *)
622                     kmalloc(sizeof(*new_crypt), GFP_KERNEL);
623                 if (new_crypt == NULL) {
624                         ret = -ENOMEM;
625                         goto done;
626                 }
627                 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
628                 new_crypt->ops = ops;
629                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
630                         new_crypt->priv = new_crypt->ops->init(idx);
631                 if (new_crypt->priv == NULL) {
632                         kfree(new_crypt);
633                         ret = -EINVAL;
634                         goto done;
635                 }
636                 *crypt = new_crypt;
637         }
638
639         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
640             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
641                                    (*crypt)->priv) < 0) {
642                 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
643                 ret = -EINVAL;
644                 goto done;
645         }
646
647       skip_host_crypt:
648         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
649                 ieee->tx_keyidx = idx;
650                 sec.active_key = idx;
651                 sec.flags |= SEC_ACTIVE_KEY;
652         }
653
654         if (ext->alg != IW_ENCODE_ALG_NONE) {
655                 memcpy(sec.keys[idx], ext->key, ext->key_len);
656                 sec.key_sizes[idx] = ext->key_len;
657                 sec.flags |= (1 << idx);
658                 if (ext->alg == IW_ENCODE_ALG_WEP) {
659                         sec.encode_alg[idx] = SEC_ALG_WEP;
660                         sec.flags |= SEC_LEVEL;
661                         sec.level = SEC_LEVEL_1;
662                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
663                         sec.encode_alg[idx] = SEC_ALG_TKIP;
664                         sec.flags |= SEC_LEVEL;
665                         sec.level = SEC_LEVEL_2;
666                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
667                         sec.encode_alg[idx] = SEC_ALG_CCMP;
668                         sec.flags |= SEC_LEVEL;
669                         sec.level = SEC_LEVEL_3;
670                 }
671                 /* Don't set sec level for group keys. */
672                 if (group_key)
673                         sec.flags &= ~SEC_LEVEL;
674         }
675       done:
676         if (ieee->set_security)
677                 ieee->set_security(ieee->dev, &sec);
678
679         /*
680          * Do not reset port if card is in Managed mode since resetting will
681          * generate new IEEE 802.11 authentication which may end up in looping
682          * with IEEE 802.1X. If your hardware requires a reset after WEP
683          * configuration (for example... Prism2), implement the reset_port in
684          * the callbacks structures used to initialize the 802.11 stack.
685          */
686         if (ieee->reset_on_keychange &&
687             ieee->iw_mode != IW_MODE_INFRA &&
688             ieee->reset_port && ieee->reset_port(dev)) {
689                 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
690                 return -EINVAL;
691         }
692
693         return ret;
694 }
695
696 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
697                                struct iw_request_info *info,
698                                union iwreq_data *wrqu, char *extra)
699 {
700         struct iw_point *encoding = &wrqu->encoding;
701         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
702         struct ieee80211_security *sec = &ieee->sec;
703         int idx, max_key_len;
704
705         max_key_len = encoding->length - sizeof(*ext);
706         if (max_key_len < 0)
707                 return -EINVAL;
708
709         idx = encoding->flags & IW_ENCODE_INDEX;
710         if (idx) {
711                 if (idx < 1 || idx > WEP_KEYS)
712                         return -EINVAL;
713                 idx--;
714         } else
715                 idx = ieee->tx_keyidx;
716
717         if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
718             ext->alg != IW_ENCODE_ALG_WEP)
719                 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
720                         return -EINVAL;
721
722         encoding->flags = idx + 1;
723         memset(ext, 0, sizeof(*ext));
724
725         if (!sec->enabled) {
726                 ext->alg = IW_ENCODE_ALG_NONE;
727                 ext->key_len = 0;
728                 encoding->flags |= IW_ENCODE_DISABLED;
729         } else {
730                 if (sec->encode_alg[idx] == SEC_ALG_WEP)
731                         ext->alg = IW_ENCODE_ALG_WEP;
732                 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
733                         ext->alg = IW_ENCODE_ALG_TKIP;
734                 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
735                         ext->alg = IW_ENCODE_ALG_CCMP;
736                 else
737                         return -EINVAL;
738
739                 ext->key_len = sec->key_sizes[idx];
740                 memcpy(ext->key, sec->keys[idx], ext->key_len);
741                 encoding->flags |= IW_ENCODE_ENABLED;
742                 if (ext->key_len &&
743                     (ext->alg == IW_ENCODE_ALG_TKIP ||
744                      ext->alg == IW_ENCODE_ALG_CCMP))
745                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
746
747         }
748
749         return 0;
750 }
751
752 int ieee80211_wx_set_auth(struct net_device *dev,
753                           struct iw_request_info *info,
754                           union iwreq_data *wrqu,
755                           char *extra)
756 {
757         struct ieee80211_device *ieee = netdev_priv(dev);
758         unsigned long flags;
759         int err = 0;
760
761         spin_lock_irqsave(&ieee->lock, flags);
762         
763         switch (wrqu->param.flags & IW_AUTH_INDEX) {
764         case IW_AUTH_WPA_VERSION:
765         case IW_AUTH_CIPHER_PAIRWISE:
766         case IW_AUTH_CIPHER_GROUP:
767         case IW_AUTH_KEY_MGMT:
768                 /*
769                  * Host AP driver does not use these parameters and allows
770                  * wpa_supplicant to control them internally.
771                  */
772                 break;
773         case IW_AUTH_TKIP_COUNTERMEASURES:
774                 break;          /* FIXME */
775         case IW_AUTH_DROP_UNENCRYPTED:
776                 ieee->drop_unencrypted = !!wrqu->param.value;
777                 break;
778         case IW_AUTH_80211_AUTH_ALG:
779                 break;          /* FIXME */
780         case IW_AUTH_WPA_ENABLED:
781                 ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value;
782                 break;
783         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
784                 ieee->ieee802_1x = !!wrqu->param.value;
785                 break;
786         case IW_AUTH_PRIVACY_INVOKED:
787                 ieee->privacy_invoked = !!wrqu->param.value;
788                 break;
789         default:
790                 err = -EOPNOTSUPP;
791                 break;
792         }
793         spin_unlock_irqrestore(&ieee->lock, flags);
794         return err;
795 }
796
797 int ieee80211_wx_get_auth(struct net_device *dev,
798                           struct iw_request_info *info,
799                           union iwreq_data *wrqu,
800                           char *extra)
801 {
802         struct ieee80211_device *ieee = netdev_priv(dev);
803         unsigned long flags;
804         int err = 0;
805
806         spin_lock_irqsave(&ieee->lock, flags);
807         
808         switch (wrqu->param.flags & IW_AUTH_INDEX) {
809         case IW_AUTH_WPA_VERSION:
810         case IW_AUTH_CIPHER_PAIRWISE:
811         case IW_AUTH_CIPHER_GROUP:
812         case IW_AUTH_KEY_MGMT:
813         case IW_AUTH_TKIP_COUNTERMEASURES:              /* FIXME */
814         case IW_AUTH_80211_AUTH_ALG:                    /* FIXME */
815                 /*
816                  * Host AP driver does not use these parameters and allows
817                  * wpa_supplicant to control them internally.
818                  */
819                 err = -EOPNOTSUPP;
820                 break;
821         case IW_AUTH_DROP_UNENCRYPTED:
822                 wrqu->param.value = ieee->drop_unencrypted;
823                 break;
824         case IW_AUTH_WPA_ENABLED:
825                 wrqu->param.value = ieee->wpa_enabled;
826                 break;
827         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
828                 wrqu->param.value = ieee->ieee802_1x;
829                 break;
830         default:
831                 err = -EOPNOTSUPP;
832                 break;
833         }
834         spin_unlock_irqrestore(&ieee->lock, flags);
835         return err;
836 }
837
838 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
839 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
840
841 EXPORT_SYMBOL(ieee80211_wx_get_scan);
842 EXPORT_SYMBOL(ieee80211_wx_set_encode);
843 EXPORT_SYMBOL(ieee80211_wx_get_encode);
844
845 EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth);
846 EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth);