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