Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight
[pandora-kernel.git] / net / ieee80211 / ieee80211_wx.c
1 /******************************************************************************
2
3   Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
4
5   Portions of this file are based on the WEP enablement code provided by the
6   Host AP project hostap-drivers v0.1.3
7   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
8   <j@w1.fi>
9   Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
10
11   This program is free software; you can redistribute it and/or modify it
12   under the terms of version 2 of the GNU General Public License as
13   published by the Free Software Foundation.
14
15   This program is distributed in the hope that it will be useful, but WITHOUT
16   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18   more details.
19
20   You should have received a copy of the GNU General Public License along with
21   this program; if not, write to the Free Software Foundation, Inc., 59
22   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23
24   The full GNU General Public License is included in this distribution in the
25   file called LICENSE.
26
27   Contact Information:
28   James P. Ketrenos <ipw2100-admin@linux.intel.com>
29   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31 ******************************************************************************/
32
33 #include <linux/kmod.h>
34 #include <linux/module.h>
35 #include <linux/jiffies.h>
36
37 #include <net/ieee80211.h>
38 #include <linux/wireless.h>
39
40 static const char *ieee80211_modes[] = {
41         "?", "a", "b", "ab", "g", "ag", "bg", "abg"
42 };
43
44 #define MAX_CUSTOM_LEN 64
45 static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
46                                            char *start, char *stop,
47                                            struct ieee80211_network *network)
48 {
49         char custom[MAX_CUSTOM_LEN];
50         char *p;
51         struct iw_event iwe;
52         int i, j;
53         char *current_val;      /* For rates */
54         u8 rate;
55
56         /* First entry *MUST* be the AP MAC address */
57         iwe.cmd = SIOCGIWAP;
58         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
59         memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
60         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
61
62         /* Remaining entries will be displayed in the order we provide them */
63
64         /* Add the ESSID */
65         iwe.cmd = SIOCGIWESSID;
66         iwe.u.data.flags = 1;
67         if (network->flags & NETWORK_EMPTY_ESSID) {
68                 iwe.u.data.length = sizeof("<hidden>");
69                 start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
70         } else {
71                 iwe.u.data.length = min(network->ssid_len, (u8) 32);
72                 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
73         }
74
75         /* Add the protocol name */
76         iwe.cmd = SIOCGIWNAME;
77         snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
78                  ieee80211_modes[network->mode]);
79         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
80
81         /* Add mode */
82         iwe.cmd = SIOCGIWMODE;
83         if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
84                 if (network->capability & WLAN_CAPABILITY_ESS)
85                         iwe.u.mode = IW_MODE_MASTER;
86                 else
87                         iwe.u.mode = IW_MODE_ADHOC;
88
89                 start = iwe_stream_add_event(start, stop, &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(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(start, stop, &iwe, network->ssid);
108
109         /* Add basic and extended rates */
110         /* Rate : stuffing multiple values in a single event require a bit
111          * more of magic - Jean II */
112         current_val = start + IW_EV_LCP_LEN;
113         iwe.cmd = SIOCGIWRATE;
114         /* Those two flags are ignored... */
115         iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
116
117         for (i = 0, j = 0; i < network->rates_len;) {
118                 if (j < network->rates_ex_len &&
119                     ((network->rates_ex[j] & 0x7F) <
120                      (network->rates[i] & 0x7F)))
121                         rate = network->rates_ex[j++] & 0x7F;
122                 else
123                         rate = network->rates[i++] & 0x7F;
124                 /* Bit rate given in 500 kb/s units (+ 0x80) */
125                 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
126                 /* Add new value to event */
127                 current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
128         }
129         for (; j < network->rates_ex_len; j++) {
130                 rate = network->rates_ex[j] & 0x7F;
131                 /* Bit rate given in 500 kb/s units (+ 0x80) */
132                 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
133                 /* Add new value to event */
134                 current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
135         }
136         /* Check if we added any rate */
137         if((current_val - start) > IW_EV_LCP_LEN)
138                 start = current_val;
139
140         /* Add quality statistics */
141         iwe.cmd = IWEVQUAL;
142         iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
143             IW_QUAL_NOISE_UPDATED;
144
145         if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
146                 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
147                     IW_QUAL_LEVEL_INVALID;
148                 iwe.u.qual.qual = 0;
149         } else {
150                 if (ieee->perfect_rssi == ieee->worst_rssi)
151                         iwe.u.qual.qual = 100;
152                 else
153                         iwe.u.qual.qual =
154                             (100 *
155                              (ieee->perfect_rssi - ieee->worst_rssi) *
156                              (ieee->perfect_rssi - ieee->worst_rssi) -
157                              (ieee->perfect_rssi - network->stats.rssi) *
158                              (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
159                               62 * (ieee->perfect_rssi -
160                                     network->stats.rssi))) /
161                             ((ieee->perfect_rssi -
162                               ieee->worst_rssi) * (ieee->perfect_rssi -
163                                                    ieee->worst_rssi));
164                 if (iwe.u.qual.qual > 100)
165                         iwe.u.qual.qual = 100;
166                 else if (iwe.u.qual.qual < 1)
167                         iwe.u.qual.qual = 0;
168         }
169
170         if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
171                 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
172                 iwe.u.qual.noise = 0;
173         } else {
174                 iwe.u.qual.noise = network->stats.noise;
175         }
176
177         if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
178                 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
179                 iwe.u.qual.level = 0;
180         } else {
181                 iwe.u.qual.level = network->stats.signal;
182         }
183
184         start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
185
186         iwe.cmd = IWEVCUSTOM;
187         p = custom;
188
189         iwe.u.data.length = p - custom;
190         if (iwe.u.data.length)
191                 start = iwe_stream_add_point(start, stop, &iwe, custom);
192
193         memset(&iwe, 0, sizeof(iwe));
194         if (network->wpa_ie_len) {
195                 char buf[MAX_WPA_IE_LEN];
196                 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
197                 iwe.cmd = IWEVGENIE;
198                 iwe.u.data.length = network->wpa_ie_len;
199                 start = iwe_stream_add_point(start, stop, &iwe, buf);
200         }
201
202         memset(&iwe, 0, sizeof(iwe));
203         if (network->rsn_ie_len) {
204                 char buf[MAX_WPA_IE_LEN];
205                 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
206                 iwe.cmd = IWEVGENIE;
207                 iwe.u.data.length = network->rsn_ie_len;
208                 start = iwe_stream_add_point(start, stop, &iwe, buf);
209         }
210
211         /* Add EXTRA: Age to display seconds since last beacon/probe response
212          * for given network. */
213         iwe.cmd = IWEVCUSTOM;
214         p = custom;
215         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
216                       " Last beacon: %dms ago",
217                       jiffies_to_msecs(jiffies - network->last_scanned));
218         iwe.u.data.length = p - custom;
219         if (iwe.u.data.length)
220                 start = iwe_stream_add_point(start, stop, &iwe, custom);
221
222         /* Add spectrum management information */
223         iwe.cmd = -1;
224         p = custom;
225         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
226
227         if (ieee80211_get_channel_flags(ieee, network->channel) &
228             IEEE80211_CH_INVALID) {
229                 iwe.cmd = IWEVCUSTOM;
230                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
231         }
232
233         if (ieee80211_get_channel_flags(ieee, network->channel) &
234             IEEE80211_CH_RADAR_DETECT) {
235                 iwe.cmd = IWEVCUSTOM;
236                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
237         }
238
239         if (iwe.cmd == IWEVCUSTOM) {
240                 iwe.u.data.length = p - custom;
241                 start = iwe_stream_add_point(start, stop, &iwe, custom);
242         }
243
244         return start;
245 }
246
247 #define SCAN_ITEM_SIZE 128
248
249 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
250                           struct iw_request_info *info,
251                           union iwreq_data *wrqu, char *extra)
252 {
253         struct ieee80211_network *network;
254         unsigned long flags;
255         int err = 0;
256
257         char *ev = extra;
258         char *stop = ev + wrqu->data.length;
259         int i = 0;
260
261         IEEE80211_DEBUG_WX("Getting scan\n");
262
263         spin_lock_irqsave(&ieee->lock, flags);
264
265         list_for_each_entry(network, &ieee->network_list, list) {
266                 i++;
267                 if (stop - ev < SCAN_ITEM_SIZE) {
268                         err = -E2BIG;
269                         break;
270                 }
271
272                 if (ieee->scan_age == 0 ||
273                     time_after(network->last_scanned + ieee->scan_age, jiffies))
274                         ev = ieee80211_translate_scan(ieee, ev, stop, network);
275                 else
276                         IEEE80211_DEBUG_SCAN("Not showing network '%s ("
277                                              MAC_FMT ")' due to age (%dms).\n",
278                                              escape_essid(network->ssid,
279                                                           network->ssid_len),
280                                              MAC_ARG(network->bssid),
281                                              jiffies_to_msecs(jiffies -
282                                                               network->
283                                                               last_scanned));
284         }
285
286         spin_unlock_irqrestore(&ieee->lock, flags);
287
288         wrqu->data.length = ev - extra;
289         wrqu->data.flags = 0;
290
291         IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
292
293         return err;
294 }
295
296 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
297                             struct iw_request_info *info,
298                             union iwreq_data *wrqu, char *keybuf)
299 {
300         struct iw_point *erq = &(wrqu->encoding);
301         struct net_device *dev = ieee->dev;
302         struct ieee80211_security sec = {
303                 .flags = 0
304         };
305         int i, key, key_provided, len;
306         struct ieee80211_crypt_data **crypt;
307         int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
308
309         IEEE80211_DEBUG_WX("SET_ENCODE\n");
310
311         key = erq->flags & IW_ENCODE_INDEX;
312         if (key) {
313                 if (key > WEP_KEYS)
314                         return -EINVAL;
315                 key--;
316                 key_provided = 1;
317         } else {
318                 key_provided = 0;
319                 key = ieee->tx_keyidx;
320         }
321
322         IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
323                            "provided" : "default");
324
325         crypt = &ieee->crypt[key];
326
327         if (erq->flags & IW_ENCODE_DISABLED) {
328                 if (key_provided && *crypt) {
329                         IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
330                                            key);
331                         ieee80211_crypt_delayed_deinit(ieee, crypt);
332                 } else
333                         IEEE80211_DEBUG_WX("Disabling encryption.\n");
334
335                 /* Check all the keys to see if any are still configured,
336                  * and if no key index was provided, de-init them all */
337                 for (i = 0; i < WEP_KEYS; i++) {
338                         if (ieee->crypt[i] != NULL) {
339                                 if (key_provided)
340                                         break;
341                                 ieee80211_crypt_delayed_deinit(ieee,
342                                                                &ieee->crypt[i]);
343                         }
344                 }
345
346                 if (i == WEP_KEYS) {
347                         sec.enabled = 0;
348                         sec.encrypt = 0;
349                         sec.level = SEC_LEVEL_0;
350                         sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
351                 }
352
353                 goto done;
354         }
355
356         sec.enabled = 1;
357         sec.encrypt = 1;
358         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
359
360         if (*crypt != NULL && (*crypt)->ops != NULL &&
361             strcmp((*crypt)->ops->name, "WEP") != 0) {
362                 /* changing to use WEP; deinit previously used algorithm
363                  * on this key */
364                 ieee80211_crypt_delayed_deinit(ieee, crypt);
365         }
366
367         if (*crypt == NULL && host_crypto) {
368                 struct ieee80211_crypt_data *new_crypt;
369
370                 /* take WEP into use */
371                 new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
372                                     GFP_KERNEL);
373                 if (new_crypt == NULL)
374                         return -ENOMEM;
375                 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
376                 if (!new_crypt->ops) {
377                         request_module("ieee80211_crypt_wep");
378                         new_crypt->ops = ieee80211_get_crypto_ops("WEP");
379                 }
380
381                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
382                         new_crypt->priv = new_crypt->ops->init(key);
383
384                 if (!new_crypt->ops || !new_crypt->priv) {
385                         kfree(new_crypt);
386                         new_crypt = NULL;
387
388                         printk(KERN_WARNING "%s: could not initialize WEP: "
389                                "load module ieee80211_crypt_wep\n", dev->name);
390                         return -EOPNOTSUPP;
391                 }
392                 *crypt = new_crypt;
393         }
394
395         /* If a new key was provided, set it up */
396         if (erq->length > 0) {
397                 len = erq->length <= 5 ? 5 : 13;
398                 memcpy(sec.keys[key], keybuf, erq->length);
399                 if (len > erq->length)
400                         memset(sec.keys[key] + erq->length, 0,
401                                len - erq->length);
402                 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
403                                    key, escape_essid(sec.keys[key], len),
404                                    erq->length, len);
405                 sec.key_sizes[key] = len;
406                 if (*crypt)
407                         (*crypt)->ops->set_key(sec.keys[key], len, NULL,
408                                                (*crypt)->priv);
409                 sec.flags |= (1 << key);
410                 /* This ensures a key will be activated if no key is
411                  * explicitely set */
412                 if (key == sec.active_key)
413                         sec.flags |= SEC_ACTIVE_KEY;
414
415         } else {
416                 if (host_crypto) {
417                         len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
418                                                      NULL, (*crypt)->priv);
419                         if (len == 0) {
420                                 /* Set a default key of all 0 */
421                                 IEEE80211_DEBUG_WX("Setting key %d to all "
422                                                    "zero.\n", key);
423                                 memset(sec.keys[key], 0, 13);
424                                 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
425                                                        (*crypt)->priv);
426                                 sec.key_sizes[key] = 13;
427                                 sec.flags |= (1 << key);
428                         }
429                 }
430                 /* No key data - just set the default TX key index */
431                 if (key_provided) {
432                         IEEE80211_DEBUG_WX("Setting key %d to default Tx "
433                                            "key.\n", key);
434                         ieee->tx_keyidx = key;
435                         sec.active_key = key;
436                         sec.flags |= SEC_ACTIVE_KEY;
437                 }
438         }
439         if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
440                 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
441                 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
442                     WLAN_AUTH_SHARED_KEY;
443                 sec.flags |= SEC_AUTH_MODE;
444                 IEEE80211_DEBUG_WX("Auth: %s\n",
445                                    sec.auth_mode == WLAN_AUTH_OPEN ?
446                                    "OPEN" : "SHARED KEY");
447         }
448
449         /* For now we just support WEP, so only set that security level...
450          * TODO: When WPA is added this is one place that needs to change */
451         sec.flags |= SEC_LEVEL;
452         sec.level = SEC_LEVEL_1;        /* 40 and 104 bit WEP */
453         sec.encode_alg[key] = SEC_ALG_WEP;
454
455       done:
456         if (ieee->set_security)
457                 ieee->set_security(dev, &sec);
458
459         /* Do not reset port if card is in Managed mode since resetting will
460          * generate new IEEE 802.11 authentication which may end up in looping
461          * with IEEE 802.1X.  If your hardware requires a reset after WEP
462          * configuration (for example... Prism2), implement the reset_port in
463          * the callbacks structures used to initialize the 802.11 stack. */
464         if (ieee->reset_on_keychange &&
465             ieee->iw_mode != IW_MODE_INFRA &&
466             ieee->reset_port && ieee->reset_port(dev)) {
467                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
468                 return -EINVAL;
469         }
470         return 0;
471 }
472
473 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
474                             struct iw_request_info *info,
475                             union iwreq_data *wrqu, char *keybuf)
476 {
477         struct iw_point *erq = &(wrqu->encoding);
478         int len, key;
479         struct ieee80211_crypt_data *crypt;
480         struct ieee80211_security *sec = &ieee->sec;
481
482         IEEE80211_DEBUG_WX("GET_ENCODE\n");
483
484         key = erq->flags & IW_ENCODE_INDEX;
485         if (key) {
486                 if (key > WEP_KEYS)
487                         return -EINVAL;
488                 key--;
489         } else
490                 key = ieee->tx_keyidx;
491
492         crypt = ieee->crypt[key];
493         erq->flags = key + 1;
494
495         if (!sec->enabled) {
496                 erq->length = 0;
497                 erq->flags |= IW_ENCODE_DISABLED;
498                 return 0;
499         }
500
501         len = sec->key_sizes[key];
502         memcpy(keybuf, sec->keys[key], len);
503
504         erq->length = len;
505         erq->flags |= IW_ENCODE_ENABLED;
506
507         if (ieee->open_wep)
508                 erq->flags |= IW_ENCODE_OPEN;
509         else
510                 erq->flags |= IW_ENCODE_RESTRICTED;
511
512         return 0;
513 }
514
515 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
516                                struct iw_request_info *info,
517                                union iwreq_data *wrqu, char *extra)
518 {
519         struct net_device *dev = ieee->dev;
520         struct iw_point *encoding = &wrqu->encoding;
521         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
522         int i, idx, ret = 0;
523         int group_key = 0;
524         const char *alg, *module;
525         struct ieee80211_crypto_ops *ops;
526         struct ieee80211_crypt_data **crypt;
527
528         struct ieee80211_security sec = {
529                 .flags = 0,
530         };
531
532         idx = encoding->flags & IW_ENCODE_INDEX;
533         if (idx) {
534                 if (idx < 1 || idx > WEP_KEYS)
535                         return -EINVAL;
536                 idx--;
537         } else
538                 idx = ieee->tx_keyidx;
539
540         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
541                 crypt = &ieee->crypt[idx];
542                 group_key = 1;
543         } else {
544                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
545                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
546                         return -EINVAL;
547                 if (ieee->iw_mode == IW_MODE_INFRA)
548                         crypt = &ieee->crypt[idx];
549                 else
550                         return -EINVAL;
551         }
552
553         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
554         if ((encoding->flags & IW_ENCODE_DISABLED) ||
555             ext->alg == IW_ENCODE_ALG_NONE) {
556                 if (*crypt)
557                         ieee80211_crypt_delayed_deinit(ieee, crypt);
558
559                 for (i = 0; i < WEP_KEYS; i++)
560                         if (ieee->crypt[i] != NULL)
561                                 break;
562
563                 if (i == WEP_KEYS) {
564                         sec.enabled = 0;
565                         sec.encrypt = 0;
566                         sec.level = SEC_LEVEL_0;
567                         sec.flags |= SEC_LEVEL;
568                 }
569                 goto done;
570         }
571
572         sec.enabled = 1;
573         sec.encrypt = 1;
574
575         if (group_key ? !ieee->host_mc_decrypt :
576             !(ieee->host_encrypt || ieee->host_decrypt ||
577               ieee->host_encrypt_msdu))
578                 goto skip_host_crypt;
579
580         switch (ext->alg) {
581         case IW_ENCODE_ALG_WEP:
582                 alg = "WEP";
583                 module = "ieee80211_crypt_wep";
584                 break;
585         case IW_ENCODE_ALG_TKIP:
586                 alg = "TKIP";
587                 module = "ieee80211_crypt_tkip";
588                 break;
589         case IW_ENCODE_ALG_CCMP:
590                 alg = "CCMP";
591                 module = "ieee80211_crypt_ccmp";
592                 break;
593         default:
594                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
595                                    dev->name, ext->alg);
596                 ret = -EINVAL;
597                 goto done;
598         }
599
600         ops = ieee80211_get_crypto_ops(alg);
601         if (ops == NULL) {
602                 request_module(module);
603                 ops = ieee80211_get_crypto_ops(alg);
604         }
605         if (ops == NULL) {
606                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
607                                    dev->name, ext->alg);
608                 ret = -EINVAL;
609                 goto done;
610         }
611
612         if (*crypt == NULL || (*crypt)->ops != ops) {
613                 struct ieee80211_crypt_data *new_crypt;
614
615                 ieee80211_crypt_delayed_deinit(ieee, crypt);
616
617                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
618                 if (new_crypt == NULL) {
619                         ret = -ENOMEM;
620                         goto done;
621                 }
622                 new_crypt->ops = ops;
623                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
624                         new_crypt->priv = new_crypt->ops->init(idx);
625                 if (new_crypt->priv == NULL) {
626                         kfree(new_crypt);
627                         ret = -EINVAL;
628                         goto done;
629                 }
630                 *crypt = new_crypt;
631         }
632
633         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
634             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
635                                    (*crypt)->priv) < 0) {
636                 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
637                 ret = -EINVAL;
638                 goto done;
639         }
640
641       skip_host_crypt:
642         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
643                 ieee->tx_keyidx = idx;
644                 sec.active_key = idx;
645                 sec.flags |= SEC_ACTIVE_KEY;
646         }
647
648         if (ext->alg != IW_ENCODE_ALG_NONE) {
649                 memcpy(sec.keys[idx], ext->key, ext->key_len);
650                 sec.key_sizes[idx] = ext->key_len;
651                 sec.flags |= (1 << idx);
652                 if (ext->alg == IW_ENCODE_ALG_WEP) {
653                         sec.encode_alg[idx] = SEC_ALG_WEP;
654                         sec.flags |= SEC_LEVEL;
655                         sec.level = SEC_LEVEL_1;
656                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
657                         sec.encode_alg[idx] = SEC_ALG_TKIP;
658                         sec.flags |= SEC_LEVEL;
659                         sec.level = SEC_LEVEL_2;
660                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
661                         sec.encode_alg[idx] = SEC_ALG_CCMP;
662                         sec.flags |= SEC_LEVEL;
663                         sec.level = SEC_LEVEL_3;
664                 }
665                 /* Don't set sec level for group keys. */
666                 if (group_key)
667                         sec.flags &= ~SEC_LEVEL;
668         }
669       done:
670         if (ieee->set_security)
671                 ieee->set_security(ieee->dev, &sec);
672
673         /*
674          * Do not reset port if card is in Managed mode since resetting will
675          * generate new IEEE 802.11 authentication which may end up in looping
676          * with IEEE 802.1X. If your hardware requires a reset after WEP
677          * configuration (for example... Prism2), implement the reset_port in
678          * the callbacks structures used to initialize the 802.11 stack.
679          */
680         if (ieee->reset_on_keychange &&
681             ieee->iw_mode != IW_MODE_INFRA &&
682             ieee->reset_port && ieee->reset_port(dev)) {
683                 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
684                 return -EINVAL;
685         }
686
687         return ret;
688 }
689
690 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
691                                struct iw_request_info *info,
692                                union iwreq_data *wrqu, char *extra)
693 {
694         struct iw_point *encoding = &wrqu->encoding;
695         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
696         struct ieee80211_security *sec = &ieee->sec;
697         int idx, max_key_len;
698
699         max_key_len = encoding->length - sizeof(*ext);
700         if (max_key_len < 0)
701                 return -EINVAL;
702
703         idx = encoding->flags & IW_ENCODE_INDEX;
704         if (idx) {
705                 if (idx < 1 || idx > WEP_KEYS)
706                         return -EINVAL;
707                 idx--;
708         } else
709                 idx = ieee->tx_keyidx;
710
711         if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
712             ext->alg != IW_ENCODE_ALG_WEP)
713                 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
714                         return -EINVAL;
715
716         encoding->flags = idx + 1;
717         memset(ext, 0, sizeof(*ext));
718
719         if (!sec->enabled) {
720                 ext->alg = IW_ENCODE_ALG_NONE;
721                 ext->key_len = 0;
722                 encoding->flags |= IW_ENCODE_DISABLED;
723         } else {
724                 if (sec->encode_alg[idx] == SEC_ALG_WEP)
725                         ext->alg = IW_ENCODE_ALG_WEP;
726                 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
727                         ext->alg = IW_ENCODE_ALG_TKIP;
728                 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
729                         ext->alg = IW_ENCODE_ALG_CCMP;
730                 else
731                         return -EINVAL;
732
733                 ext->key_len = sec->key_sizes[idx];
734                 memcpy(ext->key, sec->keys[idx], ext->key_len);
735                 encoding->flags |= IW_ENCODE_ENABLED;
736                 if (ext->key_len &&
737                     (ext->alg == IW_ENCODE_ALG_TKIP ||
738                      ext->alg == IW_ENCODE_ALG_CCMP))
739                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
740
741         }
742
743         return 0;
744 }
745
746 int ieee80211_wx_set_auth(struct net_device *dev,
747                           struct iw_request_info *info,
748                           union iwreq_data *wrqu,
749                           char *extra)
750 {
751         struct ieee80211_device *ieee = netdev_priv(dev);
752         unsigned long flags;
753         int err = 0;
754
755         spin_lock_irqsave(&ieee->lock, flags);
756
757         switch (wrqu->param.flags & IW_AUTH_INDEX) {
758         case IW_AUTH_WPA_VERSION:
759         case IW_AUTH_CIPHER_PAIRWISE:
760         case IW_AUTH_CIPHER_GROUP:
761         case IW_AUTH_KEY_MGMT:
762                 /*
763                  * Host AP driver does not use these parameters and allows
764                  * wpa_supplicant to control them internally.
765                  */
766                 break;
767         case IW_AUTH_TKIP_COUNTERMEASURES:
768                 break;          /* FIXME */
769         case IW_AUTH_DROP_UNENCRYPTED:
770                 ieee->drop_unencrypted = !!wrqu->param.value;
771                 break;
772         case IW_AUTH_80211_AUTH_ALG:
773                 break;          /* FIXME */
774         case IW_AUTH_WPA_ENABLED:
775                 ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value;
776                 break;
777         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
778                 ieee->ieee802_1x = !!wrqu->param.value;
779                 break;
780         case IW_AUTH_PRIVACY_INVOKED:
781                 ieee->privacy_invoked = !!wrqu->param.value;
782                 break;
783         default:
784                 err = -EOPNOTSUPP;
785                 break;
786         }
787         spin_unlock_irqrestore(&ieee->lock, flags);
788         return err;
789 }
790
791 int ieee80211_wx_get_auth(struct net_device *dev,
792                           struct iw_request_info *info,
793                           union iwreq_data *wrqu,
794                           char *extra)
795 {
796         struct ieee80211_device *ieee = netdev_priv(dev);
797         unsigned long flags;
798         int err = 0;
799
800         spin_lock_irqsave(&ieee->lock, flags);
801
802         switch (wrqu->param.flags & IW_AUTH_INDEX) {
803         case IW_AUTH_WPA_VERSION:
804         case IW_AUTH_CIPHER_PAIRWISE:
805         case IW_AUTH_CIPHER_GROUP:
806         case IW_AUTH_KEY_MGMT:
807         case IW_AUTH_TKIP_COUNTERMEASURES:              /* FIXME */
808         case IW_AUTH_80211_AUTH_ALG:                    /* FIXME */
809                 /*
810                  * Host AP driver does not use these parameters and allows
811                  * wpa_supplicant to control them internally.
812                  */
813                 err = -EOPNOTSUPP;
814                 break;
815         case IW_AUTH_DROP_UNENCRYPTED:
816                 wrqu->param.value = ieee->drop_unencrypted;
817                 break;
818         case IW_AUTH_WPA_ENABLED:
819                 wrqu->param.value = ieee->wpa_enabled;
820                 break;
821         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
822                 wrqu->param.value = ieee->ieee802_1x;
823                 break;
824         default:
825                 err = -EOPNOTSUPP;
826                 break;
827         }
828         spin_unlock_irqrestore(&ieee->lock, flags);
829         return err;
830 }
831
832 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
833 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
834
835 EXPORT_SYMBOL(ieee80211_wx_get_scan);
836 EXPORT_SYMBOL(ieee80211_wx_set_encode);
837 EXPORT_SYMBOL(ieee80211_wx_get_encode);
838
839 EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth);
840 EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth);