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