ipw2x00: relocate ipw2100/ipw2200 to common directory
[linux-2.6.git] / net / ieee80211 / ieee80211_wx.c
1 /******************************************************************************
2
3   Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
4
5   Portions of this file are based on the WEP enablement code provided by the
6   Host AP project hostap-drivers v0.1.3
7   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
8   <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/lib80211.h>
38 #include <net/ieee80211.h>
39 #include <linux/wireless.h>
40
41 static const char *ieee80211_modes[] = {
42         "?", "a", "b", "ab", "g", "ag", "bg", "abg"
43 };
44
45 #define MAX_CUSTOM_LEN 64
46 static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
47                                       char *start, char *stop,
48                                       struct ieee80211_network *network,
49                                       struct iw_request_info *info)
50 {
51         char custom[MAX_CUSTOM_LEN];
52         char *p;
53         struct iw_event iwe;
54         int i, j;
55         char *current_val;      /* For rates */
56         u8 rate;
57
58         /* First entry *MUST* be the AP MAC address */
59         iwe.cmd = SIOCGIWAP;
60         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
61         memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
62         start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
63
64         /* Remaining entries will be displayed in the order we provide them */
65
66         /* Add the ESSID */
67         iwe.cmd = SIOCGIWESSID;
68         iwe.u.data.flags = 1;
69         iwe.u.data.length = min(network->ssid_len, (u8) 32);
70         start = iwe_stream_add_point(info, start, stop,
71                                      &iwe, network->ssid);
72
73         /* Add the protocol name */
74         iwe.cmd = SIOCGIWNAME;
75         snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
76                  ieee80211_modes[network->mode]);
77         start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
78
79         /* Add mode */
80         iwe.cmd = SIOCGIWMODE;
81         if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
82                 if (network->capability & WLAN_CAPABILITY_ESS)
83                         iwe.u.mode = IW_MODE_MASTER;
84                 else
85                         iwe.u.mode = IW_MODE_ADHOC;
86
87                 start = iwe_stream_add_event(info, start, stop,
88                                              &iwe, IW_EV_UINT_LEN);
89         }
90
91         /* Add channel and frequency */
92         /* Note : userspace automatically computes channel using iwrange */
93         iwe.cmd = SIOCGIWFREQ;
94         iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
95         iwe.u.freq.e = 6;
96         iwe.u.freq.i = 0;
97         start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
98
99         /* Add encryption capability */
100         iwe.cmd = SIOCGIWENCODE;
101         if (network->capability & WLAN_CAPABILITY_PRIVACY)
102                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
103         else
104                 iwe.u.data.flags = IW_ENCODE_DISABLED;
105         iwe.u.data.length = 0;
106         start = iwe_stream_add_point(info, start, stop,
107                                      &iwe, network->ssid);
108
109         /* Add basic and extended rates */
110         /* Rate : stuffing multiple values in a single event require a bit
111          * more of magic - Jean II */
112         current_val = start + iwe_stream_lcp_len(info);
113         iwe.cmd = SIOCGIWRATE;
114         /* Those two flags are ignored... */
115         iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
116
117         for (i = 0, j = 0; i < network->rates_len;) {
118                 if (j < network->rates_ex_len &&
119                     ((network->rates_ex[j] & 0x7F) <
120                      (network->rates[i] & 0x7F)))
121                         rate = network->rates_ex[j++] & 0x7F;
122                 else
123                         rate = network->rates[i++] & 0x7F;
124                 /* Bit rate given in 500 kb/s units (+ 0x80) */
125                 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
126                 /* Add new value to event */
127                 current_val = iwe_stream_add_value(info, start, current_val,
128                                                    stop, &iwe, IW_EV_PARAM_LEN);
129         }
130         for (; j < network->rates_ex_len; j++) {
131                 rate = network->rates_ex[j] & 0x7F;
132                 /* Bit rate given in 500 kb/s units (+ 0x80) */
133                 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
134                 /* Add new value to event */
135                 current_val = iwe_stream_add_value(info, start, current_val,
136                                                    stop, &iwe, IW_EV_PARAM_LEN);
137         }
138         /* Check if we added any rate */
139         if ((current_val - start) > iwe_stream_lcp_len(info))
140                 start = current_val;
141
142         /* Add quality statistics */
143         iwe.cmd = IWEVQUAL;
144         iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
145             IW_QUAL_NOISE_UPDATED;
146
147         if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
148                 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
149                     IW_QUAL_LEVEL_INVALID;
150                 iwe.u.qual.qual = 0;
151         } else {
152                 if (ieee->perfect_rssi == ieee->worst_rssi)
153                         iwe.u.qual.qual = 100;
154                 else
155                         iwe.u.qual.qual =
156                             (100 *
157                              (ieee->perfect_rssi - ieee->worst_rssi) *
158                              (ieee->perfect_rssi - ieee->worst_rssi) -
159                              (ieee->perfect_rssi - network->stats.rssi) *
160                              (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
161                               62 * (ieee->perfect_rssi -
162                                     network->stats.rssi))) /
163                             ((ieee->perfect_rssi -
164                               ieee->worst_rssi) * (ieee->perfect_rssi -
165                                                    ieee->worst_rssi));
166                 if (iwe.u.qual.qual > 100)
167                         iwe.u.qual.qual = 100;
168                 else if (iwe.u.qual.qual < 1)
169                         iwe.u.qual.qual = 0;
170         }
171
172         if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
173                 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
174                 iwe.u.qual.noise = 0;
175         } else {
176                 iwe.u.qual.noise = network->stats.noise;
177         }
178
179         if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
180                 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
181                 iwe.u.qual.level = 0;
182         } else {
183                 iwe.u.qual.level = network->stats.signal;
184         }
185
186         start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
187
188         iwe.cmd = IWEVCUSTOM;
189         p = custom;
190
191         iwe.u.data.length = p - custom;
192         if (iwe.u.data.length)
193                 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
194
195         memset(&iwe, 0, sizeof(iwe));
196         if (network->wpa_ie_len) {
197                 char buf[MAX_WPA_IE_LEN];
198                 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
199                 iwe.cmd = IWEVGENIE;
200                 iwe.u.data.length = network->wpa_ie_len;
201                 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
202         }
203
204         memset(&iwe, 0, sizeof(iwe));
205         if (network->rsn_ie_len) {
206                 char buf[MAX_WPA_IE_LEN];
207                 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
208                 iwe.cmd = IWEVGENIE;
209                 iwe.u.data.length = network->rsn_ie_len;
210                 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
211         }
212
213         /* Add EXTRA: Age to display seconds since last beacon/probe response
214          * for given network. */
215         iwe.cmd = IWEVCUSTOM;
216         p = custom;
217         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
218                       " Last beacon: %dms ago",
219                       jiffies_to_msecs(jiffies - network->last_scanned));
220         iwe.u.data.length = p - custom;
221         if (iwe.u.data.length)
222                 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
223
224         /* Add spectrum management information */
225         iwe.cmd = -1;
226         p = custom;
227         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
228
229         if (ieee80211_get_channel_flags(ieee, network->channel) &
230             IEEE80211_CH_INVALID) {
231                 iwe.cmd = IWEVCUSTOM;
232                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
233         }
234
235         if (ieee80211_get_channel_flags(ieee, network->channel) &
236             IEEE80211_CH_RADAR_DETECT) {
237                 iwe.cmd = IWEVCUSTOM;
238                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
239         }
240
241         if (iwe.cmd == IWEVCUSTOM) {
242                 iwe.u.data.length = p - custom;
243                 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
244         }
245
246         return start;
247 }
248
249 #define SCAN_ITEM_SIZE 128
250
251 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
252                           struct iw_request_info *info,
253                           union iwreq_data *wrqu, char *extra)
254 {
255         struct ieee80211_network *network;
256         unsigned long flags;
257         int err = 0;
258
259         char *ev = extra;
260         char *stop = ev + wrqu->data.length;
261         int i = 0;
262         DECLARE_SSID_BUF(ssid);
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                                                       info);
279                 else
280                         IEEE80211_DEBUG_SCAN("Not showing network '%s ("
281                                              "%pM)' due to age (%dms).\n",
282                                              print_ssid(ssid, network->ssid,
283                                                          network->ssid_len),
284                                              network->bssid,
285                                              jiffies_to_msecs(jiffies -
286                                                               network->
287                                                               last_scanned));
288         }
289
290         spin_unlock_irqrestore(&ieee->lock, flags);
291
292         wrqu->data.length = ev - extra;
293         wrqu->data.flags = 0;
294
295         IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
296
297         return err;
298 }
299
300 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
301                             struct iw_request_info *info,
302                             union iwreq_data *wrqu, char *keybuf)
303 {
304         struct iw_point *erq = &(wrqu->encoding);
305         struct net_device *dev = ieee->dev;
306         struct ieee80211_security sec = {
307                 .flags = 0
308         };
309         int i, key, key_provided, len;
310         struct lib80211_crypt_data **crypt;
311         int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
312         DECLARE_SSID_BUF(ssid);
313
314         IEEE80211_DEBUG_WX("SET_ENCODE\n");
315
316         key = erq->flags & IW_ENCODE_INDEX;
317         if (key) {
318                 if (key > WEP_KEYS)
319                         return -EINVAL;
320                 key--;
321                 key_provided = 1;
322         } else {
323                 key_provided = 0;
324                 key = ieee->crypt_info.tx_keyidx;
325         }
326
327         IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
328                            "provided" : "default");
329
330         crypt = &ieee->crypt_info.crypt[key];
331
332         if (erq->flags & IW_ENCODE_DISABLED) {
333                 if (key_provided && *crypt) {
334                         IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
335                                            key);
336                         lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
337                 } else
338                         IEEE80211_DEBUG_WX("Disabling encryption.\n");
339
340                 /* Check all the keys to see if any are still configured,
341                  * and if no key index was provided, de-init them all */
342                 for (i = 0; i < WEP_KEYS; i++) {
343                         if (ieee->crypt_info.crypt[i] != NULL) {
344                                 if (key_provided)
345                                         break;
346                                 lib80211_crypt_delayed_deinit(&ieee->crypt_info,
347                                                                &ieee->crypt_info.crypt[i]);
348                         }
349                 }
350
351                 if (i == WEP_KEYS) {
352                         sec.enabled = 0;
353                         sec.encrypt = 0;
354                         sec.level = SEC_LEVEL_0;
355                         sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
356                 }
357
358                 goto done;
359         }
360
361         sec.enabled = 1;
362         sec.encrypt = 1;
363         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
364
365         if (*crypt != NULL && (*crypt)->ops != NULL &&
366             strcmp((*crypt)->ops->name, "WEP") != 0) {
367                 /* changing to use WEP; deinit previously used algorithm
368                  * on this key */
369                 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
370         }
371
372         if (*crypt == NULL && host_crypto) {
373                 struct lib80211_crypt_data *new_crypt;
374
375                 /* take WEP into use */
376                 new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
377                                     GFP_KERNEL);
378                 if (new_crypt == NULL)
379                         return -ENOMEM;
380                 new_crypt->ops = lib80211_get_crypto_ops("WEP");
381                 if (!new_crypt->ops) {
382                         request_module("lib80211_crypt_wep");
383                         new_crypt->ops = lib80211_get_crypto_ops("WEP");
384                 }
385
386                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
387                         new_crypt->priv = new_crypt->ops->init(key);
388
389                 if (!new_crypt->ops || !new_crypt->priv) {
390                         kfree(new_crypt);
391                         new_crypt = NULL;
392
393                         printk(KERN_WARNING "%s: could not initialize WEP: "
394                                "load module lib80211_crypt_wep\n", dev->name);
395                         return -EOPNOTSUPP;
396                 }
397                 *crypt = new_crypt;
398         }
399
400         /* If a new key was provided, set it up */
401         if (erq->length > 0) {
402 #ifdef CONFIG_IEEE80211_DEBUG
403                 DECLARE_SSID_BUF(ssid);
404 #endif
405
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, print_ssid(ssid, 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->crypt_info.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 lib80211_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->crypt_info.tx_keyidx;
500
501         crypt = ieee->crypt_info.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 lib80211_crypto_ops *ops;
535         struct lib80211_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->crypt_info.tx_keyidx;
548
549         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
550                 crypt = &ieee->crypt_info.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_info.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                         lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
567
568                 for (i = 0; i < WEP_KEYS; i++)
569                         if (ieee->crypt_info.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 = "lib80211_crypt_wep";
593                 break;
594         case IW_ENCODE_ALG_TKIP:
595                 alg = "TKIP";
596                 module = "lib80211_crypt_tkip";
597                 break;
598         case IW_ENCODE_ALG_CCMP:
599                 alg = "CCMP";
600                 module = "lib80211_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 = lib80211_get_crypto_ops(alg);
610         if (ops == NULL) {
611                 request_module(module);
612                 ops = lib80211_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 lib80211_crypt_data *new_crypt;
623
624                 lib80211_crypt_delayed_deinit(&ieee->crypt_info, 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->crypt_info.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->crypt_info.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);