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