3b031c2910acff581904f5148e0f4f2715d1a540
[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                                       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
268         IEEE80211_DEBUG_WX("Getting scan\n");
269
270         spin_lock_irqsave(&ieee->lock, flags);
271
272         list_for_each_entry(network, &ieee->network_list, list) {
273                 i++;
274                 if (stop - ev < SCAN_ITEM_SIZE) {
275                         err = -E2BIG;
276                         break;
277                 }
278
279                 if (ieee->scan_age == 0 ||
280                     time_after(network->last_scanned + ieee->scan_age, jiffies))
281                         ev = ieee80211_translate_scan(ieee, ev, stop, network,
282                                                       info);
283                 else
284                         IEEE80211_DEBUG_SCAN("Not showing network '%s ("
285                                              "%pM)' due to age (%dms).\n",
286                                              escape_ssid(network->ssid,
287                                                          network->ssid_len),
288                                              network->bssid,
289                                              jiffies_to_msecs(jiffies -
290                                                               network->
291                                                               last_scanned));
292         }
293
294         spin_unlock_irqrestore(&ieee->lock, flags);
295
296         wrqu->data.length = ev - extra;
297         wrqu->data.flags = 0;
298
299         IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
300
301         return err;
302 }
303
304 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
305                             struct iw_request_info *info,
306                             union iwreq_data *wrqu, char *keybuf)
307 {
308         struct iw_point *erq = &(wrqu->encoding);
309         struct net_device *dev = ieee->dev;
310         struct ieee80211_security sec = {
311                 .flags = 0
312         };
313         int i, key, key_provided, len;
314         struct ieee80211_crypt_data **crypt;
315         int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
316
317         IEEE80211_DEBUG_WX("SET_ENCODE\n");
318
319         key = erq->flags & IW_ENCODE_INDEX;
320         if (key) {
321                 if (key > WEP_KEYS)
322                         return -EINVAL;
323                 key--;
324                 key_provided = 1;
325         } else {
326                 key_provided = 0;
327                 key = ieee->tx_keyidx;
328         }
329
330         IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
331                            "provided" : "default");
332
333         crypt = &ieee->crypt[key];
334
335         if (erq->flags & IW_ENCODE_DISABLED) {
336                 if (key_provided && *crypt) {
337                         IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
338                                            key);
339                         ieee80211_crypt_delayed_deinit(ieee, crypt);
340                 } else
341                         IEEE80211_DEBUG_WX("Disabling encryption.\n");
342
343                 /* Check all the keys to see if any are still configured,
344                  * and if no key index was provided, de-init them all */
345                 for (i = 0; i < WEP_KEYS; i++) {
346                         if (ieee->crypt[i] != NULL) {
347                                 if (key_provided)
348                                         break;
349                                 ieee80211_crypt_delayed_deinit(ieee,
350                                                                &ieee->crypt[i]);
351                         }
352                 }
353
354                 if (i == WEP_KEYS) {
355                         sec.enabled = 0;
356                         sec.encrypt = 0;
357                         sec.level = SEC_LEVEL_0;
358                         sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
359                 }
360
361                 goto done;
362         }
363
364         sec.enabled = 1;
365         sec.encrypt = 1;
366         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
367
368         if (*crypt != NULL && (*crypt)->ops != NULL &&
369             strcmp((*crypt)->ops->name, "WEP") != 0) {
370                 /* changing to use WEP; deinit previously used algorithm
371                  * on this key */
372                 ieee80211_crypt_delayed_deinit(ieee, crypt);
373         }
374
375         if (*crypt == NULL && host_crypto) {
376                 struct ieee80211_crypt_data *new_crypt;
377
378                 /* take WEP into use */
379                 new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
380                                     GFP_KERNEL);
381                 if (new_crypt == NULL)
382                         return -ENOMEM;
383                 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
384                 if (!new_crypt->ops) {
385                         request_module("ieee80211_crypt_wep");
386                         new_crypt->ops = ieee80211_get_crypto_ops("WEP");
387                 }
388
389                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
390                         new_crypt->priv = new_crypt->ops->init(key);
391
392                 if (!new_crypt->ops || !new_crypt->priv) {
393                         kfree(new_crypt);
394                         new_crypt = NULL;
395
396                         printk(KERN_WARNING "%s: could not initialize WEP: "
397                                "load module ieee80211_crypt_wep\n", dev->name);
398                         return -EOPNOTSUPP;
399                 }
400                 *crypt = new_crypt;
401         }
402
403         /* If a new key was provided, set it up */
404         if (erq->length > 0) {
405                 len = erq->length <= 5 ? 5 : 13;
406                 memcpy(sec.keys[key], keybuf, erq->length);
407                 if (len > erq->length)
408                         memset(sec.keys[key] + erq->length, 0,
409                                len - erq->length);
410                 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
411                                    key, escape_ssid(sec.keys[key], len),
412                                    erq->length, len);
413                 sec.key_sizes[key] = len;
414                 if (*crypt)
415                         (*crypt)->ops->set_key(sec.keys[key], len, NULL,
416                                                (*crypt)->priv);
417                 sec.flags |= (1 << key);
418                 /* This ensures a key will be activated if no key is
419                  * explicitly set */
420                 if (key == sec.active_key)
421                         sec.flags |= SEC_ACTIVE_KEY;
422
423         } else {
424                 if (host_crypto) {
425                         len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
426                                                      NULL, (*crypt)->priv);
427                         if (len == 0) {
428                                 /* Set a default key of all 0 */
429                                 IEEE80211_DEBUG_WX("Setting key %d to all "
430                                                    "zero.\n", key);
431                                 memset(sec.keys[key], 0, 13);
432                                 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
433                                                        (*crypt)->priv);
434                                 sec.key_sizes[key] = 13;
435                                 sec.flags |= (1 << key);
436                         }
437                 }
438                 /* No key data - just set the default TX key index */
439                 if (key_provided) {
440                         IEEE80211_DEBUG_WX("Setting key %d to default Tx "
441                                            "key.\n", key);
442                         ieee->tx_keyidx = key;
443                         sec.active_key = key;
444                         sec.flags |= SEC_ACTIVE_KEY;
445                 }
446         }
447         if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
448                 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
449                 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
450                     WLAN_AUTH_SHARED_KEY;
451                 sec.flags |= SEC_AUTH_MODE;
452                 IEEE80211_DEBUG_WX("Auth: %s\n",
453                                    sec.auth_mode == WLAN_AUTH_OPEN ?
454                                    "OPEN" : "SHARED KEY");
455         }
456
457         /* For now we just support WEP, so only set that security level...
458          * TODO: When WPA is added this is one place that needs to change */
459         sec.flags |= SEC_LEVEL;
460         sec.level = SEC_LEVEL_1;        /* 40 and 104 bit WEP */
461         sec.encode_alg[key] = SEC_ALG_WEP;
462
463       done:
464         if (ieee->set_security)
465                 ieee->set_security(dev, &sec);
466
467         /* Do not reset port if card is in Managed mode since resetting will
468          * generate new IEEE 802.11 authentication which may end up in looping
469          * with IEEE 802.1X.  If your hardware requires a reset after WEP
470          * configuration (for example... Prism2), implement the reset_port in
471          * the callbacks structures used to initialize the 802.11 stack. */
472         if (ieee->reset_on_keychange &&
473             ieee->iw_mode != IW_MODE_INFRA &&
474             ieee->reset_port && ieee->reset_port(dev)) {
475                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
476                 return -EINVAL;
477         }
478         return 0;
479 }
480
481 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
482                             struct iw_request_info *info,
483                             union iwreq_data *wrqu, char *keybuf)
484 {
485         struct iw_point *erq = &(wrqu->encoding);
486         int len, key;
487         struct ieee80211_crypt_data *crypt;
488         struct ieee80211_security *sec = &ieee->sec;
489
490         IEEE80211_DEBUG_WX("GET_ENCODE\n");
491
492         key = erq->flags & IW_ENCODE_INDEX;
493         if (key) {
494                 if (key > WEP_KEYS)
495                         return -EINVAL;
496                 key--;
497         } else
498                 key = ieee->tx_keyidx;
499
500         crypt = ieee->crypt[key];
501         erq->flags = key + 1;
502
503         if (!sec->enabled) {
504                 erq->length = 0;
505                 erq->flags |= IW_ENCODE_DISABLED;
506                 return 0;
507         }
508
509         len = sec->key_sizes[key];
510         memcpy(keybuf, sec->keys[key], len);
511
512         erq->length = len;
513         erq->flags |= IW_ENCODE_ENABLED;
514
515         if (ieee->open_wep)
516                 erq->flags |= IW_ENCODE_OPEN;
517         else
518                 erq->flags |= IW_ENCODE_RESTRICTED;
519
520         return 0;
521 }
522
523 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
524                                struct iw_request_info *info,
525                                union iwreq_data *wrqu, char *extra)
526 {
527         struct net_device *dev = ieee->dev;
528         struct iw_point *encoding = &wrqu->encoding;
529         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
530         int i, idx, ret = 0;
531         int group_key = 0;
532         const char *alg, *module;
533         struct ieee80211_crypto_ops *ops;
534         struct ieee80211_crypt_data **crypt;
535
536         struct ieee80211_security sec = {
537                 .flags = 0,
538         };
539
540         idx = encoding->flags & IW_ENCODE_INDEX;
541         if (idx) {
542                 if (idx < 1 || idx > WEP_KEYS)
543                         return -EINVAL;
544                 idx--;
545         } else
546                 idx = ieee->tx_keyidx;
547
548         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
549                 crypt = &ieee->crypt[idx];
550                 group_key = 1;
551         } else {
552                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
553                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
554                         return -EINVAL;
555                 if (ieee->iw_mode == IW_MODE_INFRA)
556                         crypt = &ieee->crypt[idx];
557                 else
558                         return -EINVAL;
559         }
560
561         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
562         if ((encoding->flags & IW_ENCODE_DISABLED) ||
563             ext->alg == IW_ENCODE_ALG_NONE) {
564                 if (*crypt)
565                         ieee80211_crypt_delayed_deinit(ieee, crypt);
566
567                 for (i = 0; i < WEP_KEYS; i++)
568                         if (ieee->crypt[i] != NULL)
569                                 break;
570
571                 if (i == WEP_KEYS) {
572                         sec.enabled = 0;
573                         sec.encrypt = 0;
574                         sec.level = SEC_LEVEL_0;
575                         sec.flags |= SEC_LEVEL;
576                 }
577                 goto done;
578         }
579
580         sec.enabled = 1;
581         sec.encrypt = 1;
582
583         if (group_key ? !ieee->host_mc_decrypt :
584             !(ieee->host_encrypt || ieee->host_decrypt ||
585               ieee->host_encrypt_msdu))
586                 goto skip_host_crypt;
587
588         switch (ext->alg) {
589         case IW_ENCODE_ALG_WEP:
590                 alg = "WEP";
591                 module = "ieee80211_crypt_wep";
592                 break;
593         case IW_ENCODE_ALG_TKIP:
594                 alg = "TKIP";
595                 module = "ieee80211_crypt_tkip";
596                 break;
597         case IW_ENCODE_ALG_CCMP:
598                 alg = "CCMP";
599                 module = "ieee80211_crypt_ccmp";
600                 break;
601         default:
602                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
603                                    dev->name, ext->alg);
604                 ret = -EINVAL;
605                 goto done;
606         }
607
608         ops = ieee80211_get_crypto_ops(alg);
609         if (ops == NULL) {
610                 request_module(module);
611                 ops = ieee80211_get_crypto_ops(alg);
612         }
613         if (ops == NULL) {
614                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
615                                    dev->name, ext->alg);
616                 ret = -EINVAL;
617                 goto done;
618         }
619
620         if (*crypt == NULL || (*crypt)->ops != ops) {
621                 struct ieee80211_crypt_data *new_crypt;
622
623                 ieee80211_crypt_delayed_deinit(ieee, crypt);
624
625                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
626                 if (new_crypt == NULL) {
627                         ret = -ENOMEM;
628                         goto done;
629                 }
630                 new_crypt->ops = ops;
631                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
632                         new_crypt->priv = new_crypt->ops->init(idx);
633                 if (new_crypt->priv == NULL) {
634                         kfree(new_crypt);
635                         ret = -EINVAL;
636                         goto done;
637                 }
638                 *crypt = new_crypt;
639         }
640
641         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
642             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
643                                    (*crypt)->priv) < 0) {
644                 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
645                 ret = -EINVAL;
646                 goto done;
647         }
648
649       skip_host_crypt:
650         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
651                 ieee->tx_keyidx = idx;
652                 sec.active_key = idx;
653                 sec.flags |= SEC_ACTIVE_KEY;
654         }
655
656         if (ext->alg != IW_ENCODE_ALG_NONE) {
657                 memcpy(sec.keys[idx], ext->key, ext->key_len);
658                 sec.key_sizes[idx] = ext->key_len;
659                 sec.flags |= (1 << idx);
660                 if (ext->alg == IW_ENCODE_ALG_WEP) {
661                         sec.encode_alg[idx] = SEC_ALG_WEP;
662                         sec.flags |= SEC_LEVEL;
663                         sec.level = SEC_LEVEL_1;
664                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
665                         sec.encode_alg[idx] = SEC_ALG_TKIP;
666                         sec.flags |= SEC_LEVEL;
667                         sec.level = SEC_LEVEL_2;
668                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
669                         sec.encode_alg[idx] = SEC_ALG_CCMP;
670                         sec.flags |= SEC_LEVEL;
671                         sec.level = SEC_LEVEL_3;
672                 }
673                 /* Don't set sec level for group keys. */
674                 if (group_key)
675                         sec.flags &= ~SEC_LEVEL;
676         }
677       done:
678         if (ieee->set_security)
679                 ieee->set_security(ieee->dev, &sec);
680
681         /*
682          * Do not reset port if card is in Managed mode since resetting will
683          * generate new IEEE 802.11 authentication which may end up in looping
684          * with IEEE 802.1X. If your hardware requires a reset after WEP
685          * configuration (for example... Prism2), implement the reset_port in
686          * the callbacks structures used to initialize the 802.11 stack.
687          */
688         if (ieee->reset_on_keychange &&
689             ieee->iw_mode != IW_MODE_INFRA &&
690             ieee->reset_port && ieee->reset_port(dev)) {
691                 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
692                 return -EINVAL;
693         }
694
695         return ret;
696 }
697
698 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
699                                struct iw_request_info *info,
700                                union iwreq_data *wrqu, char *extra)
701 {
702         struct iw_point *encoding = &wrqu->encoding;
703         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
704         struct ieee80211_security *sec = &ieee->sec;
705         int idx, max_key_len;
706
707         max_key_len = encoding->length - sizeof(*ext);
708         if (max_key_len < 0)
709                 return -EINVAL;
710
711         idx = encoding->flags & IW_ENCODE_INDEX;
712         if (idx) {
713                 if (idx < 1 || idx > WEP_KEYS)
714                         return -EINVAL;
715                 idx--;
716         } else
717                 idx = ieee->tx_keyidx;
718
719         if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
720             ext->alg != IW_ENCODE_ALG_WEP)
721                 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
722                         return -EINVAL;
723
724         encoding->flags = idx + 1;
725         memset(ext, 0, sizeof(*ext));
726
727         if (!sec->enabled) {
728                 ext->alg = IW_ENCODE_ALG_NONE;
729                 ext->key_len = 0;
730                 encoding->flags |= IW_ENCODE_DISABLED;
731         } else {
732                 if (sec->encode_alg[idx] == SEC_ALG_WEP)
733                         ext->alg = IW_ENCODE_ALG_WEP;
734                 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
735                         ext->alg = IW_ENCODE_ALG_TKIP;
736                 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
737                         ext->alg = IW_ENCODE_ALG_CCMP;
738                 else
739                         return -EINVAL;
740
741                 ext->key_len = sec->key_sizes[idx];
742                 memcpy(ext->key, sec->keys[idx], ext->key_len);
743                 encoding->flags |= IW_ENCODE_ENABLED;
744                 if (ext->key_len &&
745                     (ext->alg == IW_ENCODE_ALG_TKIP ||
746                      ext->alg == IW_ENCODE_ALG_CCMP))
747                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
748
749         }
750
751         return 0;
752 }
753
754 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
755 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
756
757 EXPORT_SYMBOL(ieee80211_wx_get_scan);
758 EXPORT_SYMBOL(ieee80211_wx_set_encode);
759 EXPORT_SYMBOL(ieee80211_wx_get_encode);