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