[PATCH] softmac: deauthentication implies deassociation
[deliverable/linux.git] / net / ieee80211 / ieee80211_wx.c
CommitLineData
b453872c
JG
1/******************************************************************************
2
ebeaddcc 3 Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
b453872c
JG
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******************************************************************************/
bbeec90b 32
b453872c
JG
33#include <linux/kmod.h>
34#include <linux/module.h>
42e349fd 35#include <linux/jiffies.h>
b453872c
JG
36
37#include <net/ieee80211.h>
bbeec90b
JG
38#include <linux/wireless.h>
39
b453872c
JG
40static const char *ieee80211_modes[] = {
41 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
42};
43
44#define MAX_CUSTOM_LEN 64
d94606e0 45static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
0edd5b44 46 char *start, char *stop,
b453872c
JG
47 struct ieee80211_network *network)
48{
49 char custom[MAX_CUSTOM_LEN];
50 char *p;
51 struct iw_event iwe;
52 int i, j;
09593047
ZY
53 char *current_val; /* For rates */
54 u8 rate;
b453872c
JG
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 {
0edd5b44 71 iwe.u.data.length = min(network->ssid_len, (u8) 32);
b453872c
JG
72 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
73 }
74
75 /* Add the protocol name */
76 iwe.cmd = SIOCGIWNAME;
0edd5b44
JG
77 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
78 ieee80211_modes[network->mode]);
b453872c
JG
79 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
80
0edd5b44
JG
81 /* Add mode */
82 iwe.cmd = SIOCGIWMODE;
83 if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
1b5cca3a 84 if (network->capability & WLAN_CAPABILITY_ESS)
b453872c
JG
85 iwe.u.mode = IW_MODE_MASTER;
86 else
87 iwe.u.mode = IW_MODE_ADHOC;
88
0edd5b44 89 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
b453872c
JG
90 }
91
0edd5b44 92 /* Add frequency/channel */
b453872c
JG
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 */
09593047
ZY
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
0edd5b44 118 for (i = 0, j = 0; i < network->rates_len;) {
b453872c
JG
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;
09593047
ZY
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);
b453872c
JG
129 }
130 for (; j < network->rates_ex_len; j++) {
131 rate = network->rates_ex[j] & 0x7F;
09593047
ZY
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);
b453872c 136 }
09593047
ZY
137 /* Check if we added any rate */
138 if((current_val - start) > IW_EV_LCP_LEN)
139 start = current_val;
b453872c
JG
140
141 /* Add quality statistics */
b453872c 142 iwe.cmd = IWEVQUAL;
b1b508e1
JK
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;
b1b508e1 150 } else {
757d18fa
JB
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) +
81f87520
JK
160 62 * (ieee->perfect_rssi -
161 network->stats.rssi))) /
162 ((ieee->perfect_rssi -
163 ieee->worst_rssi) * (ieee->perfect_rssi -
164 ieee->worst_rssi));
b1b508e1
JK
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)) {
b453872c 172 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
b1b508e1
JK
173 iwe.u.qual.noise = 0;
174 } else {
175 iwe.u.qual.noise = network->stats.noise;
176 }
b453872c 177
7bd64366
ZY
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
b453872c
JG
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
47168082 194 memset(&iwe, 0, sizeof(iwe));
20d64713 195 if (network->wpa_ie_len) {
47168082
ZY
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;
b453872c
JG
200 start = iwe_stream_add_point(start, stop, &iwe, buf);
201 }
202
47168082 203 memset(&iwe, 0, sizeof(iwe));
20d64713 204 if (network->rsn_ie_len) {
47168082
ZY
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;
b453872c
JG
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),
42e349fd
JK
217 " Last beacon: %dms ago",
218 jiffies_to_msecs(jiffies - network->last_scanned));
b453872c
JG
219 iwe.u.data.length = p - custom;
220 if (iwe.u.data.length)
221 start = iwe_stream_add_point(start, stop, &iwe, custom);
222
7bd64366
ZY
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
b453872c
JG
245 return start;
246}
247
55cd94aa
ZY
248#define SCAN_ITEM_SIZE 128
249
b453872c
JG
250int 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;
55cd94aa 256 int err = 0;
b453872c
JG
257
258 char *ev = extra;
55cd94aa 259 char *stop = ev + wrqu->data.length;
b453872c
JG
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++;
55cd94aa
ZY
268 if (stop - ev < SCAN_ITEM_SIZE) {
269 err = -E2BIG;
270 break;
271 }
272
b453872c
JG
273 if (ieee->scan_age == 0 ||
274 time_after(network->last_scanned + ieee->scan_age, jiffies))
d94606e0 275 ev = ieee80211_translate_scan(ieee, ev, stop, network);
b453872c 276 else
0edd5b44 277 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
42e349fd 278 MAC_FMT ")' due to age (%dms).\n",
0edd5b44
JG
279 escape_essid(network->ssid,
280 network->ssid_len),
281 MAC_ARG(network->bssid),
42e349fd
JK
282 jiffies_to_msecs(jiffies -
283 network->
284 last_scanned));
b453872c
JG
285 }
286
287 spin_unlock_irqrestore(&ieee->lock, flags);
288
0edd5b44 289 wrqu->data.length = ev - extra;
b453872c
JG
290 wrqu->data.flags = 0;
291
292 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
293
55cd94aa 294 return err;
b453872c
JG
295}
296
297int 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;
a4bf26f3 308 int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
b453872c
JG
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;
0edd5b44
JG
342 ieee80211_crypt_delayed_deinit(ieee,
343 &ieee->crypt[i]);
b453872c
JG
344 }
345 }
346
347 if (i == WEP_KEYS) {
348 sec.enabled = 0;
f1bf6638 349 sec.encrypt = 0;
b453872c 350 sec.level = SEC_LEVEL_0;
259bf1fd 351 sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
b453872c
JG
352 }
353
354 goto done;
355 }
356
b453872c 357 sec.enabled = 1;
f1bf6638 358 sec.encrypt = 1;
259bf1fd 359 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
b453872c
JG
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
f1bf6638 368 if (*crypt == NULL && host_crypto) {
b453872c
JG
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))
6eb6edf0 384 new_crypt->priv = new_crypt->ops->init(key);
b453872c
JG
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: "
0edd5b44 391 "load module ieee80211_crypt_wep\n", dev->name);
b453872c
JG
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;
f1bf6638
JK
408 if (*crypt)
409 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
410 (*crypt)->priv);
b453872c
JG
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;
f1bf6638 416
b453872c 417 } else {
f1bf6638
JK
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 }
b453872c 431 }
b453872c
JG
432 /* No key data - just set the default TX key index */
433 if (key_provided) {
f1bf6638
JK
434 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
435 "key.\n", key);
b453872c
JG
436 ieee->tx_keyidx = key;
437 sec.active_key = key;
438 sec.flags |= SEC_ACTIVE_KEY;
439 }
440 }
7dc888fe
JK
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 }
b453872c
JG
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;
0edd5b44 454 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
e0d369d1 455 sec.encode_alg[key] = SEC_ALG_WEP;
b453872c 456
259bf1fd 457 done:
b453872c
JG
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
475int 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;
f1bf6638 482 struct ieee80211_security *sec = &ieee->sec;
b453872c
JG
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
f1bf6638 497 if (!sec->enabled) {
b453872c
JG
498 erq->length = 0;
499 erq->flags |= IW_ENCODE_DISABLED;
500 return 0;
501 }
502
f1bf6638
JK
503 len = sec->key_sizes[key];
504 memcpy(keybuf, sec->keys[key], len);
b453872c 505
f1bf6638 506 erq->length = (len >= 0 ? len : 0);
b453872c
JG
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
e0d369d1
JK
517int 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;
ccd0fda3 525 int group_key = 0;
e0d369d1
JK
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
ccd0fda3 542 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
e0d369d1 543 crypt = &ieee->crypt[idx];
ccd0fda3
JK
544 group_key = 1;
545 } else {
e189277a
VB
546 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
547 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
e0d369d1
JK
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
ccd0fda3
JK
577 if (group_key ? !ieee->host_mc_decrypt :
578 !(ieee->host_encrypt || ieee->host_decrypt ||
579 ieee->host_encrypt_msdu))
e0d369d1
JK
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))
6eb6edf0 628 new_crypt->priv = new_crypt->ops->init(idx);
e0d369d1
JK
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 }
ccd0fda3
JK
669 /* Don't set sec level for group keys. */
670 if (group_key)
671 sec.flags &= ~SEC_LEVEL;
e0d369d1
JK
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
694int 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
e189277a
VB
715 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
716 ext->alg != IW_ENCODE_ALG_WEP)
e0d369d1
JK
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
dd5eeb46
LF
750int 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
795int 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
e0d369d1
JK
836EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
837EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
e0d369d1 838
b453872c
JG
839EXPORT_SYMBOL(ieee80211_wx_get_scan);
840EXPORT_SYMBOL(ieee80211_wx_set_encode);
841EXPORT_SYMBOL(ieee80211_wx_get_encode);
dd5eeb46
LF
842
843EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth);
844EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth);
This page took 0.109987 seconds and 5 git commands to generate.