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