wireless: escape_ssid should handle non-printables
[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
85d32e7b
JM
8 <j@w1.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
b453872c
JG
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,
ccc58057
DM
46 char *start, char *stop,
47 struct ieee80211_network *network,
48 struct iw_request_info *info)
b453872c
JG
49{
50 char custom[MAX_CUSTOM_LEN];
51 char *p;
52 struct iw_event iwe;
53 int i, j;
09593047
ZY
54 char *current_val; /* For rates */
55 u8 rate;
b453872c
JG
56
57 /* First entry *MUST* be the AP MAC address */
58 iwe.cmd = SIOCGIWAP;
59 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
60 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
ccc58057 61 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
b453872c
JG
62
63 /* Remaining entries will be displayed in the order we provide them */
64
65 /* Add the ESSID */
66 iwe.cmd = SIOCGIWESSID;
67 iwe.u.data.flags = 1;
c5d3dce8
JL
68 iwe.u.data.length = min(network->ssid_len, (u8) 32);
69 start = iwe_stream_add_point(info, start, stop,
70 &iwe, network->ssid);
b453872c
JG
71
72 /* Add the protocol name */
73 iwe.cmd = SIOCGIWNAME;
0edd5b44
JG
74 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
75 ieee80211_modes[network->mode]);
ccc58057 76 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
b453872c 77
0edd5b44
JG
78 /* Add mode */
79 iwe.cmd = SIOCGIWMODE;
80 if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
1b5cca3a 81 if (network->capability & WLAN_CAPABILITY_ESS)
b453872c
JG
82 iwe.u.mode = IW_MODE_MASTER;
83 else
84 iwe.u.mode = IW_MODE_ADHOC;
85
ccc58057
DM
86 start = iwe_stream_add_event(info, start, stop,
87 &iwe, IW_EV_UINT_LEN);
b453872c
JG
88 }
89
93afe3da 90 /* Add channel and frequency */
90869b24 91 /* Note : userspace automatically computes channel using iwrange */
b453872c 92 iwe.cmd = SIOCGIWFREQ;
93afe3da
LF
93 iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
94 iwe.u.freq.e = 6;
90869b24 95 iwe.u.freq.i = 0;
ccc58057 96 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
93afe3da 97
b453872c
JG
98 /* Add encryption capability */
99 iwe.cmd = SIOCGIWENCODE;
100 if (network->capability & WLAN_CAPABILITY_PRIVACY)
101 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
102 else
103 iwe.u.data.flags = IW_ENCODE_DISABLED;
104 iwe.u.data.length = 0;
ccc58057
DM
105 start = iwe_stream_add_point(info, start, stop,
106 &iwe, network->ssid);
b453872c
JG
107
108 /* Add basic and extended rates */
09593047
ZY
109 /* Rate : stuffing multiple values in a single event require a bit
110 * more of magic - Jean II */
ccc58057 111 current_val = start + iwe_stream_lcp_len(info);
09593047
ZY
112 iwe.cmd = SIOCGIWRATE;
113 /* Those two flags are ignored... */
114 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
115
0edd5b44 116 for (i = 0, j = 0; i < network->rates_len;) {
b453872c
JG
117 if (j < network->rates_ex_len &&
118 ((network->rates_ex[j] & 0x7F) <
119 (network->rates[i] & 0x7F)))
120 rate = network->rates_ex[j++] & 0x7F;
121 else
122 rate = network->rates[i++] & 0x7F;
09593047
ZY
123 /* Bit rate given in 500 kb/s units (+ 0x80) */
124 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
125 /* Add new value to event */
ccc58057
DM
126 current_val = iwe_stream_add_value(info, start, current_val,
127 stop, &iwe, IW_EV_PARAM_LEN);
b453872c
JG
128 }
129 for (; j < network->rates_ex_len; j++) {
130 rate = network->rates_ex[j] & 0x7F;
09593047
ZY
131 /* Bit rate given in 500 kb/s units (+ 0x80) */
132 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
133 /* Add new value to event */
ccc58057
DM
134 current_val = iwe_stream_add_value(info, start, current_val,
135 stop, &iwe, IW_EV_PARAM_LEN);
b453872c 136 }
09593047 137 /* Check if we added any rate */
ccc58057 138 if ((current_val - start) > iwe_stream_lcp_len(info))
09593047 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
ccc58057 185 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
b453872c
JG
186
187 iwe.cmd = IWEVCUSTOM;
188 p = custom;
189
190 iwe.u.data.length = p - custom;
191 if (iwe.u.data.length)
ccc58057 192 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
b453872c 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;
ccc58057 200 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
b453872c
JG
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;
ccc58057 209 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
b453872c
JG
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)
ccc58057 221 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
b453872c 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;
ccc58057 242 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
7bd64366
ZY
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))
ccc58057
DM
275 ev = ieee80211_translate_scan(ieee, ev, stop, network,
276 info);
b453872c 277 else
0edd5b44 278 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
e174961c 279 "%pM)' due to age (%dms).\n",
7e272fcf
JL
280 escape_ssid(network->ssid,
281 network->ssid_len),
e174961c 282 network->bssid,
42e349fd
JK
283 jiffies_to_msecs(jiffies -
284 network->
285 last_scanned));
b453872c
JG
286 }
287
288 spin_unlock_irqrestore(&ieee->lock, flags);
289
0edd5b44 290 wrqu->data.length = ev - extra;
b453872c
JG
291 wrqu->data.flags = 0;
292
293 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
294
55cd94aa 295 return err;
b453872c
JG
296}
297
298int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
299 struct iw_request_info *info,
300 union iwreq_data *wrqu, char *keybuf)
301{
302 struct iw_point *erq = &(wrqu->encoding);
303 struct net_device *dev = ieee->dev;
304 struct ieee80211_security sec = {
305 .flags = 0
306 };
307 int i, key, key_provided, len;
308 struct ieee80211_crypt_data **crypt;
a4bf26f3 309 int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
b453872c
JG
310
311 IEEE80211_DEBUG_WX("SET_ENCODE\n");
312
313 key = erq->flags & IW_ENCODE_INDEX;
314 if (key) {
315 if (key > WEP_KEYS)
316 return -EINVAL;
317 key--;
318 key_provided = 1;
319 } else {
320 key_provided = 0;
321 key = ieee->tx_keyidx;
322 }
323
324 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
325 "provided" : "default");
326
327 crypt = &ieee->crypt[key];
328
329 if (erq->flags & IW_ENCODE_DISABLED) {
330 if (key_provided && *crypt) {
331 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
332 key);
333 ieee80211_crypt_delayed_deinit(ieee, crypt);
334 } else
335 IEEE80211_DEBUG_WX("Disabling encryption.\n");
336
337 /* Check all the keys to see if any are still configured,
338 * and if no key index was provided, de-init them all */
339 for (i = 0; i < WEP_KEYS; i++) {
340 if (ieee->crypt[i] != NULL) {
341 if (key_provided)
342 break;
0edd5b44
JG
343 ieee80211_crypt_delayed_deinit(ieee,
344 &ieee->crypt[i]);
b453872c
JG
345 }
346 }
347
348 if (i == WEP_KEYS) {
349 sec.enabled = 0;
f1bf6638 350 sec.encrypt = 0;
b453872c 351 sec.level = SEC_LEVEL_0;
259bf1fd 352 sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
b453872c
JG
353 }
354
355 goto done;
356 }
357
b453872c 358 sec.enabled = 1;
f1bf6638 359 sec.encrypt = 1;
259bf1fd 360 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
b453872c
JG
361
362 if (*crypt != NULL && (*crypt)->ops != NULL &&
363 strcmp((*crypt)->ops->name, "WEP") != 0) {
364 /* changing to use WEP; deinit previously used algorithm
365 * on this key */
366 ieee80211_crypt_delayed_deinit(ieee, crypt);
367 }
368
f1bf6638 369 if (*crypt == NULL && host_crypto) {
b453872c
JG
370 struct ieee80211_crypt_data *new_crypt;
371
372 /* take WEP into use */
0da974f4 373 new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
b453872c
JG
374 GFP_KERNEL);
375 if (new_crypt == NULL)
376 return -ENOMEM;
b453872c
JG
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",
7e272fcf 405 key, escape_ssid(sec.keys[key], len),
b453872c
JG
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
c03983ac 413 * explicitly set */
b453872c
JG
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
6274115c 506 erq->length = len;
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
0da974f4 619 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
e0d369d1
JK
620 if (new_crypt == NULL) {
621 ret = -ENOMEM;
622 goto done;
623 }
e0d369d1
JK
624 new_crypt->ops = ops;
625 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
6eb6edf0 626 new_crypt->priv = new_crypt->ops->init(idx);
e0d369d1
JK
627 if (new_crypt->priv == NULL) {
628 kfree(new_crypt);
629 ret = -EINVAL;
630 goto done;
631 }
632 *crypt = new_crypt;
633 }
634
635 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
636 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
637 (*crypt)->priv) < 0) {
638 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
639 ret = -EINVAL;
640 goto done;
641 }
642
643 skip_host_crypt:
644 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
645 ieee->tx_keyidx = idx;
646 sec.active_key = idx;
647 sec.flags |= SEC_ACTIVE_KEY;
648 }
649
650 if (ext->alg != IW_ENCODE_ALG_NONE) {
651 memcpy(sec.keys[idx], ext->key, ext->key_len);
652 sec.key_sizes[idx] = ext->key_len;
653 sec.flags |= (1 << idx);
654 if (ext->alg == IW_ENCODE_ALG_WEP) {
655 sec.encode_alg[idx] = SEC_ALG_WEP;
656 sec.flags |= SEC_LEVEL;
657 sec.level = SEC_LEVEL_1;
658 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
659 sec.encode_alg[idx] = SEC_ALG_TKIP;
660 sec.flags |= SEC_LEVEL;
661 sec.level = SEC_LEVEL_2;
662 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
663 sec.encode_alg[idx] = SEC_ALG_CCMP;
664 sec.flags |= SEC_LEVEL;
665 sec.level = SEC_LEVEL_3;
666 }
ccd0fda3
JK
667 /* Don't set sec level for group keys. */
668 if (group_key)
669 sec.flags &= ~SEC_LEVEL;
e0d369d1
JK
670 }
671 done:
672 if (ieee->set_security)
673 ieee->set_security(ieee->dev, &sec);
674
675 /*
676 * Do not reset port if card is in Managed mode since resetting will
677 * generate new IEEE 802.11 authentication which may end up in looping
678 * with IEEE 802.1X. If your hardware requires a reset after WEP
679 * configuration (for example... Prism2), implement the reset_port in
680 * the callbacks structures used to initialize the 802.11 stack.
681 */
682 if (ieee->reset_on_keychange &&
683 ieee->iw_mode != IW_MODE_INFRA &&
684 ieee->reset_port && ieee->reset_port(dev)) {
685 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
686 return -EINVAL;
687 }
688
689 return ret;
690}
691
692int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
693 struct iw_request_info *info,
694 union iwreq_data *wrqu, char *extra)
695{
696 struct iw_point *encoding = &wrqu->encoding;
697 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
698 struct ieee80211_security *sec = &ieee->sec;
699 int idx, max_key_len;
700
701 max_key_len = encoding->length - sizeof(*ext);
702 if (max_key_len < 0)
703 return -EINVAL;
704
705 idx = encoding->flags & IW_ENCODE_INDEX;
706 if (idx) {
707 if (idx < 1 || idx > WEP_KEYS)
708 return -EINVAL;
709 idx--;
710 } else
711 idx = ieee->tx_keyidx;
712
f59d9782 713 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
e189277a 714 ext->alg != IW_ENCODE_ALG_WEP)
e0d369d1
JK
715 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
716 return -EINVAL;
717
718 encoding->flags = idx + 1;
719 memset(ext, 0, sizeof(*ext));
720
721 if (!sec->enabled) {
722 ext->alg = IW_ENCODE_ALG_NONE;
723 ext->key_len = 0;
724 encoding->flags |= IW_ENCODE_DISABLED;
725 } else {
726 if (sec->encode_alg[idx] == SEC_ALG_WEP)
727 ext->alg = IW_ENCODE_ALG_WEP;
728 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
729 ext->alg = IW_ENCODE_ALG_TKIP;
730 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
731 ext->alg = IW_ENCODE_ALG_CCMP;
732 else
733 return -EINVAL;
734
735 ext->key_len = sec->key_sizes[idx];
736 memcpy(ext->key, sec->keys[idx], ext->key_len);
737 encoding->flags |= IW_ENCODE_ENABLED;
738 if (ext->key_len &&
739 (ext->alg == IW_ENCODE_ALG_TKIP ||
740 ext->alg == IW_ENCODE_ALG_CCMP))
741 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
742
743 }
744
745 return 0;
746}
747
748EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
749EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
e0d369d1 750
b453872c
JG
751EXPORT_SYMBOL(ieee80211_wx_get_scan);
752EXPORT_SYMBOL(ieee80211_wx_set_encode);
753EXPORT_SYMBOL(ieee80211_wx_get_encode);
This page took 0.341441 seconds and 5 git commands to generate.