Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband
[pandora-kernel.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   <j@w1.fi>
9   Copyright (c) 2002-2003, Jouni Malinen <j@w1.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         char *current_val;      /* For rates */
54         u8 rate;
55
56         /* First entry *MUST* be the AP MAC address */
57         iwe.cmd = SIOCGIWAP;
58         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
59         memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
60         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
61
62         /* Remaining entries will be displayed in the order we provide them */
63
64         /* Add the ESSID */
65         iwe.cmd = SIOCGIWESSID;
66         iwe.u.data.flags = 1;
67         if (network->flags & NETWORK_EMPTY_ESSID) {
68                 iwe.u.data.length = sizeof("<hidden>");
69                 start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
70         } else {
71                 iwe.u.data.length = min(network->ssid_len, (u8) 32);
72                 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
73         }
74
75         /* Add the protocol name */
76         iwe.cmd = SIOCGIWNAME;
77         snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
78                  ieee80211_modes[network->mode]);
79         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
80
81         /* Add mode */
82         iwe.cmd = SIOCGIWMODE;
83         if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
84                 if (network->capability & WLAN_CAPABILITY_ESS)
85                         iwe.u.mode = IW_MODE_MASTER;
86                 else
87                         iwe.u.mode = IW_MODE_ADHOC;
88
89                 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
90         }
91
92         /* Add channel and frequency */
93         iwe.cmd = SIOCGIWFREQ;
94         iwe.u.freq.m = network->channel;
95         iwe.u.freq.e = 0;
96         iwe.u.freq.i = 0;
97         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
98
99         iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
100         iwe.u.freq.e = 6;
101         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
102
103         /* Add encryption capability */
104         iwe.cmd = SIOCGIWENCODE;
105         if (network->capability & WLAN_CAPABILITY_PRIVACY)
106                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
107         else
108                 iwe.u.data.flags = IW_ENCODE_DISABLED;
109         iwe.u.data.length = 0;
110         start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
111
112         /* Add basic and extended rates */
113         /* Rate : stuffing multiple values in a single event require a bit
114          * more of magic - Jean II */
115         current_val = start + IW_EV_LCP_LEN;
116         iwe.cmd = SIOCGIWRATE;
117         /* Those two flags are ignored... */
118         iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
119
120         for (i = 0, j = 0; i < network->rates_len;) {
121                 if (j < network->rates_ex_len &&
122                     ((network->rates_ex[j] & 0x7F) <
123                      (network->rates[i] & 0x7F)))
124                         rate = network->rates_ex[j++] & 0x7F;
125                 else
126                         rate = network->rates[i++] & 0x7F;
127                 /* Bit rate given in 500 kb/s units (+ 0x80) */
128                 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
129                 /* Add new value to event */
130                 current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
131         }
132         for (; j < network->rates_ex_len; j++) {
133                 rate = network->rates_ex[j] & 0x7F;
134                 /* Bit rate given in 500 kb/s units (+ 0x80) */
135                 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
136                 /* Add new value to event */
137                 current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
138         }
139         /* Check if we added any rate */
140         if((current_val - start) > IW_EV_LCP_LEN)
141                 start = current_val;
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 = kzalloc(sizeof(struct ieee80211_crypt_data),
375                                     GFP_KERNEL);
376                 if (new_crypt == NULL)
377                         return -ENOMEM;
378                 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
379                 if (!new_crypt->ops) {
380                         request_module("ieee80211_crypt_wep");
381                         new_crypt->ops = ieee80211_get_crypto_ops("WEP");
382                 }
383
384                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
385                         new_crypt->priv = new_crypt->ops->init(key);
386
387                 if (!new_crypt->ops || !new_crypt->priv) {
388                         kfree(new_crypt);
389                         new_crypt = NULL;
390
391                         printk(KERN_WARNING "%s: could not initialize WEP: "
392                                "load module ieee80211_crypt_wep\n", dev->name);
393                         return -EOPNOTSUPP;
394                 }
395                 *crypt = new_crypt;
396         }
397
398         /* If a new key was provided, set it up */
399         if (erq->length > 0) {
400                 len = erq->length <= 5 ? 5 : 13;
401                 memcpy(sec.keys[key], keybuf, erq->length);
402                 if (len > erq->length)
403                         memset(sec.keys[key] + erq->length, 0,
404                                len - erq->length);
405                 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
406                                    key, escape_essid(sec.keys[key], len),
407                                    erq->length, len);
408                 sec.key_sizes[key] = len;
409                 if (*crypt)
410                         (*crypt)->ops->set_key(sec.keys[key], len, NULL,
411                                                (*crypt)->priv);
412                 sec.flags |= (1 << key);
413                 /* This ensures a key will be activated if no key is
414                  * explicitely set */
415                 if (key == sec.active_key)
416                         sec.flags |= SEC_ACTIVE_KEY;
417
418         } else {
419                 if (host_crypto) {
420                         len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
421                                                      NULL, (*crypt)->priv);
422                         if (len == 0) {
423                                 /* Set a default key of all 0 */
424                                 IEEE80211_DEBUG_WX("Setting key %d to all "
425                                                    "zero.\n", key);
426                                 memset(sec.keys[key], 0, 13);
427                                 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
428                                                        (*crypt)->priv);
429                                 sec.key_sizes[key] = 13;
430                                 sec.flags |= (1 << key);
431                         }
432                 }
433                 /* No key data - just set the default TX key index */
434                 if (key_provided) {
435                         IEEE80211_DEBUG_WX("Setting key %d to default Tx "
436                                            "key.\n", key);
437                         ieee->tx_keyidx = key;
438                         sec.active_key = key;
439                         sec.flags |= SEC_ACTIVE_KEY;
440                 }
441         }
442         if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
443                 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
444                 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
445                     WLAN_AUTH_SHARED_KEY;
446                 sec.flags |= SEC_AUTH_MODE;
447                 IEEE80211_DEBUG_WX("Auth: %s\n",
448                                    sec.auth_mode == WLAN_AUTH_OPEN ?
449                                    "OPEN" : "SHARED KEY");
450         }
451
452         /* For now we just support WEP, so only set that security level...
453          * TODO: When WPA is added this is one place that needs to change */
454         sec.flags |= SEC_LEVEL;
455         sec.level = SEC_LEVEL_1;        /* 40 and 104 bit WEP */
456         sec.encode_alg[key] = SEC_ALG_WEP;
457
458       done:
459         if (ieee->set_security)
460                 ieee->set_security(dev, &sec);
461
462         /* Do not reset port if card is in Managed mode since resetting will
463          * generate new IEEE 802.11 authentication which may end up in looping
464          * with IEEE 802.1X.  If your hardware requires a reset after WEP
465          * configuration (for example... Prism2), implement the reset_port in
466          * the callbacks structures used to initialize the 802.11 stack. */
467         if (ieee->reset_on_keychange &&
468             ieee->iw_mode != IW_MODE_INFRA &&
469             ieee->reset_port && ieee->reset_port(dev)) {
470                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
471                 return -EINVAL;
472         }
473         return 0;
474 }
475
476 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
477                             struct iw_request_info *info,
478                             union iwreq_data *wrqu, char *keybuf)
479 {
480         struct iw_point *erq = &(wrqu->encoding);
481         int len, key;
482         struct ieee80211_crypt_data *crypt;
483         struct ieee80211_security *sec = &ieee->sec;
484
485         IEEE80211_DEBUG_WX("GET_ENCODE\n");
486
487         key = erq->flags & IW_ENCODE_INDEX;
488         if (key) {
489                 if (key > WEP_KEYS)
490                         return -EINVAL;
491                 key--;
492         } else
493                 key = ieee->tx_keyidx;
494
495         crypt = ieee->crypt[key];
496         erq->flags = key + 1;
497
498         if (!sec->enabled) {
499                 erq->length = 0;
500                 erq->flags |= IW_ENCODE_DISABLED;
501                 return 0;
502         }
503
504         len = sec->key_sizes[key];
505         memcpy(keybuf, sec->keys[key], len);
506
507         erq->length = len;
508         erq->flags |= IW_ENCODE_ENABLED;
509
510         if (ieee->open_wep)
511                 erq->flags |= IW_ENCODE_OPEN;
512         else
513                 erq->flags |= IW_ENCODE_RESTRICTED;
514
515         return 0;
516 }
517
518 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
519                                struct iw_request_info *info,
520                                union iwreq_data *wrqu, char *extra)
521 {
522         struct net_device *dev = ieee->dev;
523         struct iw_point *encoding = &wrqu->encoding;
524         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
525         int i, idx, ret = 0;
526         int group_key = 0;
527         const char *alg, *module;
528         struct ieee80211_crypto_ops *ops;
529         struct ieee80211_crypt_data **crypt;
530
531         struct ieee80211_security sec = {
532                 .flags = 0,
533         };
534
535         idx = encoding->flags & IW_ENCODE_INDEX;
536         if (idx) {
537                 if (idx < 1 || idx > WEP_KEYS)
538                         return -EINVAL;
539                 idx--;
540         } else
541                 idx = ieee->tx_keyidx;
542
543         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
544                 crypt = &ieee->crypt[idx];
545                 group_key = 1;
546         } else {
547                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
548                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
549                         return -EINVAL;
550                 if (ieee->iw_mode == IW_MODE_INFRA)
551                         crypt = &ieee->crypt[idx];
552                 else
553                         return -EINVAL;
554         }
555
556         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
557         if ((encoding->flags & IW_ENCODE_DISABLED) ||
558             ext->alg == IW_ENCODE_ALG_NONE) {
559                 if (*crypt)
560                         ieee80211_crypt_delayed_deinit(ieee, crypt);
561
562                 for (i = 0; i < WEP_KEYS; i++)
563                         if (ieee->crypt[i] != NULL)
564                                 break;
565
566                 if (i == WEP_KEYS) {
567                         sec.enabled = 0;
568                         sec.encrypt = 0;
569                         sec.level = SEC_LEVEL_0;
570                         sec.flags |= SEC_LEVEL;
571                 }
572                 goto done;
573         }
574
575         sec.enabled = 1;
576         sec.encrypt = 1;
577
578         if (group_key ? !ieee->host_mc_decrypt :
579             !(ieee->host_encrypt || ieee->host_decrypt ||
580               ieee->host_encrypt_msdu))
581                 goto skip_host_crypt;
582
583         switch (ext->alg) {
584         case IW_ENCODE_ALG_WEP:
585                 alg = "WEP";
586                 module = "ieee80211_crypt_wep";
587                 break;
588         case IW_ENCODE_ALG_TKIP:
589                 alg = "TKIP";
590                 module = "ieee80211_crypt_tkip";
591                 break;
592         case IW_ENCODE_ALG_CCMP:
593                 alg = "CCMP";
594                 module = "ieee80211_crypt_ccmp";
595                 break;
596         default:
597                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
598                                    dev->name, ext->alg);
599                 ret = -EINVAL;
600                 goto done;
601         }
602
603         ops = ieee80211_get_crypto_ops(alg);
604         if (ops == NULL) {
605                 request_module(module);
606                 ops = ieee80211_get_crypto_ops(alg);
607         }
608         if (ops == NULL) {
609                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
610                                    dev->name, ext->alg);
611                 ret = -EINVAL;
612                 goto done;
613         }
614
615         if (*crypt == NULL || (*crypt)->ops != ops) {
616                 struct ieee80211_crypt_data *new_crypt;
617
618                 ieee80211_crypt_delayed_deinit(ieee, crypt);
619
620                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
621                 if (new_crypt == NULL) {
622                         ret = -ENOMEM;
623                         goto done;
624                 }
625                 new_crypt->ops = ops;
626                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
627                         new_crypt->priv = new_crypt->ops->init(idx);
628                 if (new_crypt->priv == NULL) {
629                         kfree(new_crypt);
630                         ret = -EINVAL;
631                         goto done;
632                 }
633                 *crypt = new_crypt;
634         }
635
636         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
637             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
638                                    (*crypt)->priv) < 0) {
639                 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
640                 ret = -EINVAL;
641                 goto done;
642         }
643
644       skip_host_crypt:
645         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
646                 ieee->tx_keyidx = idx;
647                 sec.active_key = idx;
648                 sec.flags |= SEC_ACTIVE_KEY;
649         }
650
651         if (ext->alg != IW_ENCODE_ALG_NONE) {
652                 memcpy(sec.keys[idx], ext->key, ext->key_len);
653                 sec.key_sizes[idx] = ext->key_len;
654                 sec.flags |= (1 << idx);
655                 if (ext->alg == IW_ENCODE_ALG_WEP) {
656                         sec.encode_alg[idx] = SEC_ALG_WEP;
657                         sec.flags |= SEC_LEVEL;
658                         sec.level = SEC_LEVEL_1;
659                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
660                         sec.encode_alg[idx] = SEC_ALG_TKIP;
661                         sec.flags |= SEC_LEVEL;
662                         sec.level = SEC_LEVEL_2;
663                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
664                         sec.encode_alg[idx] = SEC_ALG_CCMP;
665                         sec.flags |= SEC_LEVEL;
666                         sec.level = SEC_LEVEL_3;
667                 }
668                 /* Don't set sec level for group keys. */
669                 if (group_key)
670                         sec.flags &= ~SEC_LEVEL;
671         }
672       done:
673         if (ieee->set_security)
674                 ieee->set_security(ieee->dev, &sec);
675
676         /*
677          * Do not reset port if card is in Managed mode since resetting will
678          * generate new IEEE 802.11 authentication which may end up in looping
679          * with IEEE 802.1X. If your hardware requires a reset after WEP
680          * configuration (for example... Prism2), implement the reset_port in
681          * the callbacks structures used to initialize the 802.11 stack.
682          */
683         if (ieee->reset_on_keychange &&
684             ieee->iw_mode != IW_MODE_INFRA &&
685             ieee->reset_port && ieee->reset_port(dev)) {
686                 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
687                 return -EINVAL;
688         }
689
690         return ret;
691 }
692
693 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
694                                struct iw_request_info *info,
695                                union iwreq_data *wrqu, char *extra)
696 {
697         struct iw_point *encoding = &wrqu->encoding;
698         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
699         struct ieee80211_security *sec = &ieee->sec;
700         int idx, max_key_len;
701
702         max_key_len = encoding->length - sizeof(*ext);
703         if (max_key_len < 0)
704                 return -EINVAL;
705
706         idx = encoding->flags & IW_ENCODE_INDEX;
707         if (idx) {
708                 if (idx < 1 || idx > WEP_KEYS)
709                         return -EINVAL;
710                 idx--;
711         } else
712                 idx = ieee->tx_keyidx;
713
714         if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
715             ext->alg != IW_ENCODE_ALG_WEP)
716                 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
717                         return -EINVAL;
718
719         encoding->flags = idx + 1;
720         memset(ext, 0, sizeof(*ext));
721
722         if (!sec->enabled) {
723                 ext->alg = IW_ENCODE_ALG_NONE;
724                 ext->key_len = 0;
725                 encoding->flags |= IW_ENCODE_DISABLED;
726         } else {
727                 if (sec->encode_alg[idx] == SEC_ALG_WEP)
728                         ext->alg = IW_ENCODE_ALG_WEP;
729                 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
730                         ext->alg = IW_ENCODE_ALG_TKIP;
731                 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
732                         ext->alg = IW_ENCODE_ALG_CCMP;
733                 else
734                         return -EINVAL;
735
736                 ext->key_len = sec->key_sizes[idx];
737                 memcpy(ext->key, sec->keys[idx], ext->key_len);
738                 encoding->flags |= IW_ENCODE_ENABLED;
739                 if (ext->key_len &&
740                     (ext->alg == IW_ENCODE_ALG_TKIP ||
741                      ext->alg == IW_ENCODE_ALG_CCMP))
742                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
743
744         }
745
746         return 0;
747 }
748
749 int ieee80211_wx_set_auth(struct net_device *dev,
750                           struct iw_request_info *info,
751                           union iwreq_data *wrqu,
752                           char *extra)
753 {
754         struct ieee80211_device *ieee = netdev_priv(dev);
755         unsigned long flags;
756         int err = 0;
757
758         spin_lock_irqsave(&ieee->lock, flags);
759
760         switch (wrqu->param.flags & IW_AUTH_INDEX) {
761         case IW_AUTH_WPA_VERSION:
762         case IW_AUTH_CIPHER_PAIRWISE:
763         case IW_AUTH_CIPHER_GROUP:
764         case IW_AUTH_KEY_MGMT:
765                 /*
766                  * Host AP driver does not use these parameters and allows
767                  * wpa_supplicant to control them internally.
768                  */
769                 break;
770         case IW_AUTH_TKIP_COUNTERMEASURES:
771                 break;          /* FIXME */
772         case IW_AUTH_DROP_UNENCRYPTED:
773                 ieee->drop_unencrypted = !!wrqu->param.value;
774                 break;
775         case IW_AUTH_80211_AUTH_ALG:
776                 break;          /* FIXME */
777         case IW_AUTH_WPA_ENABLED:
778                 ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value;
779                 break;
780         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
781                 ieee->ieee802_1x = !!wrqu->param.value;
782                 break;
783         case IW_AUTH_PRIVACY_INVOKED:
784                 ieee->privacy_invoked = !!wrqu->param.value;
785                 break;
786         default:
787                 err = -EOPNOTSUPP;
788                 break;
789         }
790         spin_unlock_irqrestore(&ieee->lock, flags);
791         return err;
792 }
793
794 int ieee80211_wx_get_auth(struct net_device *dev,
795                           struct iw_request_info *info,
796                           union iwreq_data *wrqu,
797                           char *extra)
798 {
799         struct ieee80211_device *ieee = netdev_priv(dev);
800         unsigned long flags;
801         int err = 0;
802
803         spin_lock_irqsave(&ieee->lock, flags);
804
805         switch (wrqu->param.flags & IW_AUTH_INDEX) {
806         case IW_AUTH_WPA_VERSION:
807         case IW_AUTH_CIPHER_PAIRWISE:
808         case IW_AUTH_CIPHER_GROUP:
809         case IW_AUTH_KEY_MGMT:
810         case IW_AUTH_TKIP_COUNTERMEASURES:              /* FIXME */
811         case IW_AUTH_80211_AUTH_ALG:                    /* FIXME */
812                 /*
813                  * Host AP driver does not use these parameters and allows
814                  * wpa_supplicant to control them internally.
815                  */
816                 err = -EOPNOTSUPP;
817                 break;
818         case IW_AUTH_DROP_UNENCRYPTED:
819                 wrqu->param.value = ieee->drop_unencrypted;
820                 break;
821         case IW_AUTH_WPA_ENABLED:
822                 wrqu->param.value = ieee->wpa_enabled;
823                 break;
824         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
825                 wrqu->param.value = ieee->ieee802_1x;
826                 break;
827         default:
828                 err = -EOPNOTSUPP;
829                 break;
830         }
831         spin_unlock_irqrestore(&ieee->lock, flags);
832         return err;
833 }
834
835 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
836 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
837
838 EXPORT_SYMBOL(ieee80211_wx_get_scan);
839 EXPORT_SYMBOL(ieee80211_wx_set_encode);
840 EXPORT_SYMBOL(ieee80211_wx_get_encode);
841
842 EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth);
843 EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth);