Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
[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 = kzalloc(sizeof(struct ieee80211_crypt_data),
373                                     GFP_KERNEL);
374                 if (new_crypt == NULL)
375                         return -ENOMEM;
376                 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
377                 if (!new_crypt->ops) {
378                         request_module("ieee80211_crypt_wep");
379                         new_crypt->ops = ieee80211_get_crypto_ops("WEP");
380                 }
381
382                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
383                         new_crypt->priv = new_crypt->ops->init(key);
384
385                 if (!new_crypt->ops || !new_crypt->priv) {
386                         kfree(new_crypt);
387                         new_crypt = NULL;
388
389                         printk(KERN_WARNING "%s: could not initialize WEP: "
390                                "load module ieee80211_crypt_wep\n", dev->name);
391                         return -EOPNOTSUPP;
392                 }
393                 *crypt = new_crypt;
394         }
395
396         /* If a new key was provided, set it up */
397         if (erq->length > 0) {
398                 len = erq->length <= 5 ? 5 : 13;
399                 memcpy(sec.keys[key], keybuf, erq->length);
400                 if (len > erq->length)
401                         memset(sec.keys[key] + erq->length, 0,
402                                len - erq->length);
403                 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
404                                    key, escape_essid(sec.keys[key], len),
405                                    erq->length, len);
406                 sec.key_sizes[key] = len;
407                 if (*crypt)
408                         (*crypt)->ops->set_key(sec.keys[key], len, NULL,
409                                                (*crypt)->priv);
410                 sec.flags |= (1 << key);
411                 /* This ensures a key will be activated if no key is
412                  * explicitely set */
413                 if (key == sec.active_key)
414                         sec.flags |= SEC_ACTIVE_KEY;
415
416         } else {
417                 if (host_crypto) {
418                         len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
419                                                      NULL, (*crypt)->priv);
420                         if (len == 0) {
421                                 /* Set a default key of all 0 */
422                                 IEEE80211_DEBUG_WX("Setting key %d to all "
423                                                    "zero.\n", key);
424                                 memset(sec.keys[key], 0, 13);
425                                 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
426                                                        (*crypt)->priv);
427                                 sec.key_sizes[key] = 13;
428                                 sec.flags |= (1 << key);
429                         }
430                 }
431                 /* No key data - just set the default TX key index */
432                 if (key_provided) {
433                         IEEE80211_DEBUG_WX("Setting key %d to default Tx "
434                                            "key.\n", key);
435                         ieee->tx_keyidx = key;
436                         sec.active_key = key;
437                         sec.flags |= SEC_ACTIVE_KEY;
438                 }
439         }
440         if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
441                 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
442                 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
443                     WLAN_AUTH_SHARED_KEY;
444                 sec.flags |= SEC_AUTH_MODE;
445                 IEEE80211_DEBUG_WX("Auth: %s\n",
446                                    sec.auth_mode == WLAN_AUTH_OPEN ?
447                                    "OPEN" : "SHARED KEY");
448         }
449
450         /* For now we just support WEP, so only set that security level...
451          * TODO: When WPA is added this is one place that needs to change */
452         sec.flags |= SEC_LEVEL;
453         sec.level = SEC_LEVEL_1;        /* 40 and 104 bit WEP */
454         sec.encode_alg[key] = SEC_ALG_WEP;
455
456       done:
457         if (ieee->set_security)
458                 ieee->set_security(dev, &sec);
459
460         /* Do not reset port if card is in Managed mode since resetting will
461          * generate new IEEE 802.11 authentication which may end up in looping
462          * with IEEE 802.1X.  If your hardware requires a reset after WEP
463          * configuration (for example... Prism2), implement the reset_port in
464          * the callbacks structures used to initialize the 802.11 stack. */
465         if (ieee->reset_on_keychange &&
466             ieee->iw_mode != IW_MODE_INFRA &&
467             ieee->reset_port && ieee->reset_port(dev)) {
468                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
469                 return -EINVAL;
470         }
471         return 0;
472 }
473
474 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
475                             struct iw_request_info *info,
476                             union iwreq_data *wrqu, char *keybuf)
477 {
478         struct iw_point *erq = &(wrqu->encoding);
479         int len, key;
480         struct ieee80211_crypt_data *crypt;
481         struct ieee80211_security *sec = &ieee->sec;
482
483         IEEE80211_DEBUG_WX("GET_ENCODE\n");
484
485         key = erq->flags & IW_ENCODE_INDEX;
486         if (key) {
487                 if (key > WEP_KEYS)
488                         return -EINVAL;
489                 key--;
490         } else
491                 key = ieee->tx_keyidx;
492
493         crypt = ieee->crypt[key];
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 ieee80211_wx_set_encodeext(struct ieee80211_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 ieee80211_crypto_ops *ops;
527         struct ieee80211_crypt_data **crypt;
528
529         struct ieee80211_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->tx_keyidx;
540
541         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
542                 crypt = &ieee->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[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                         ieee80211_crypt_delayed_deinit(ieee, crypt);
559
560                 for (i = 0; i < WEP_KEYS; i++)
561                         if (ieee->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 = "ieee80211_crypt_wep";
585                 break;
586         case IW_ENCODE_ALG_TKIP:
587                 alg = "TKIP";
588                 module = "ieee80211_crypt_tkip";
589                 break;
590         case IW_ENCODE_ALG_CCMP:
591                 alg = "CCMP";
592                 module = "ieee80211_crypt_ccmp";
593                 break;
594         default:
595                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
596                                    dev->name, ext->alg);
597                 ret = -EINVAL;
598                 goto done;
599         }
600
601         ops = ieee80211_get_crypto_ops(alg);
602         if (ops == NULL) {
603                 request_module(module);
604                 ops = ieee80211_get_crypto_ops(alg);
605         }
606         if (ops == NULL) {
607                 IEEE80211_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 ieee80211_crypt_data *new_crypt;
615
616                 ieee80211_crypt_delayed_deinit(ieee, 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                 IEEE80211_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->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(ieee->dev, &sec);
673
674         /*
675          * Do not reset port if card is in Managed mode since resetting will
676          * generate new IEEE 802.11 authentication which may end up in looping
677          * with IEEE 802.1X. If your hardware requires a reset after WEP
678          * configuration (for example... Prism2), implement the reset_port in
679          * the callbacks structures used to initialize the 802.11 stack.
680          */
681         if (ieee->reset_on_keychange &&
682             ieee->iw_mode != IW_MODE_INFRA &&
683             ieee->reset_port && ieee->reset_port(dev)) {
684                 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
685                 return -EINVAL;
686         }
687
688         return ret;
689 }
690
691 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
692                                struct iw_request_info *info,
693                                union iwreq_data *wrqu, char *extra)
694 {
695         struct iw_point *encoding = &wrqu->encoding;
696         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
697         struct ieee80211_security *sec = &ieee->sec;
698         int idx, max_key_len;
699
700         max_key_len = encoding->length - sizeof(*ext);
701         if (max_key_len < 0)
702                 return -EINVAL;
703
704         idx = encoding->flags & IW_ENCODE_INDEX;
705         if (idx) {
706                 if (idx < 1 || idx > WEP_KEYS)
707                         return -EINVAL;
708                 idx--;
709         } else
710                 idx = ieee->tx_keyidx;
711
712         if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
713             ext->alg != IW_ENCODE_ALG_WEP)
714                 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
715                         return -EINVAL;
716
717         encoding->flags = idx + 1;
718         memset(ext, 0, sizeof(*ext));
719
720         if (!sec->enabled) {
721                 ext->alg = IW_ENCODE_ALG_NONE;
722                 ext->key_len = 0;
723                 encoding->flags |= IW_ENCODE_DISABLED;
724         } else {
725                 if (sec->encode_alg[idx] == SEC_ALG_WEP)
726                         ext->alg = IW_ENCODE_ALG_WEP;
727                 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
728                         ext->alg = IW_ENCODE_ALG_TKIP;
729                 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
730                         ext->alg = IW_ENCODE_ALG_CCMP;
731                 else
732                         return -EINVAL;
733
734                 ext->key_len = sec->key_sizes[idx];
735                 memcpy(ext->key, sec->keys[idx], ext->key_len);
736                 encoding->flags |= IW_ENCODE_ENABLED;
737                 if (ext->key_len &&
738                     (ext->alg == IW_ENCODE_ALG_TKIP ||
739                      ext->alg == IW_ENCODE_ALG_CCMP))
740                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
741
742         }
743
744         return 0;
745 }
746
747 int ieee80211_wx_set_auth(struct net_device *dev,
748                           struct iw_request_info *info,
749                           union iwreq_data *wrqu,
750                           char *extra)
751 {
752         struct ieee80211_device *ieee = netdev_priv(dev);
753         unsigned long flags;
754         int err = 0;
755
756         spin_lock_irqsave(&ieee->lock, flags);
757
758         switch (wrqu->param.flags & IW_AUTH_INDEX) {
759         case IW_AUTH_WPA_VERSION:
760         case IW_AUTH_CIPHER_PAIRWISE:
761         case IW_AUTH_CIPHER_GROUP:
762         case IW_AUTH_KEY_MGMT:
763                 /*
764                  * Host AP driver does not use these parameters and allows
765                  * wpa_supplicant to control them internally.
766                  */
767                 break;
768         case IW_AUTH_TKIP_COUNTERMEASURES:
769                 break;          /* FIXME */
770         case IW_AUTH_DROP_UNENCRYPTED:
771                 ieee->drop_unencrypted = !!wrqu->param.value;
772                 break;
773         case IW_AUTH_80211_AUTH_ALG:
774                 break;          /* FIXME */
775         case IW_AUTH_WPA_ENABLED:
776                 ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value;
777                 break;
778         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
779                 ieee->ieee802_1x = !!wrqu->param.value;
780                 break;
781         case IW_AUTH_PRIVACY_INVOKED:
782                 ieee->privacy_invoked = !!wrqu->param.value;
783                 break;
784         default:
785                 err = -EOPNOTSUPP;
786                 break;
787         }
788         spin_unlock_irqrestore(&ieee->lock, flags);
789         return err;
790 }
791
792 int ieee80211_wx_get_auth(struct net_device *dev,
793                           struct iw_request_info *info,
794                           union iwreq_data *wrqu,
795                           char *extra)
796 {
797         struct ieee80211_device *ieee = netdev_priv(dev);
798         unsigned long flags;
799         int err = 0;
800
801         spin_lock_irqsave(&ieee->lock, flags);
802
803         switch (wrqu->param.flags & IW_AUTH_INDEX) {
804         case IW_AUTH_WPA_VERSION:
805         case IW_AUTH_CIPHER_PAIRWISE:
806         case IW_AUTH_CIPHER_GROUP:
807         case IW_AUTH_KEY_MGMT:
808         case IW_AUTH_TKIP_COUNTERMEASURES:              /* FIXME */
809         case IW_AUTH_80211_AUTH_ALG:                    /* FIXME */
810                 /*
811                  * Host AP driver does not use these parameters and allows
812                  * wpa_supplicant to control them internally.
813                  */
814                 err = -EOPNOTSUPP;
815                 break;
816         case IW_AUTH_DROP_UNENCRYPTED:
817                 wrqu->param.value = ieee->drop_unencrypted;
818                 break;
819         case IW_AUTH_WPA_ENABLED:
820                 wrqu->param.value = ieee->wpa_enabled;
821                 break;
822         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
823                 wrqu->param.value = ieee->ieee802_1x;
824                 break;
825         default:
826                 err = -EOPNOTSUPP;
827                 break;
828         }
829         spin_unlock_irqrestore(&ieee->lock, flags);
830         return err;
831 }
832
833 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
834 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
835
836 EXPORT_SYMBOL(ieee80211_wx_get_scan);
837 EXPORT_SYMBOL(ieee80211_wx_set_encode);
838 EXPORT_SYMBOL(ieee80211_wx_get_encode);
839
840 EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth);
841 EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth);