airo: correct improper initialization of local variable
[deliverable/linux.git] / drivers / net / wireless / ipw2x00 / libipw_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 36
9387b7ca 37#include <net/lib80211.h>
bbeec90b
JG
38#include <linux/wireless.h>
39
f3734ee6
DW
40#include "ieee80211.h"
41
b453872c
JG
42static const char *ieee80211_modes[] = {
43 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
44};
45
46#define MAX_CUSTOM_LEN 64
d94606e0 47static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
ccc58057
DM
48 char *start, char *stop,
49 struct ieee80211_network *network,
50 struct iw_request_info *info)
b453872c
JG
51{
52 char custom[MAX_CUSTOM_LEN];
53 char *p;
54 struct iw_event iwe;
55 int i, j;
09593047
ZY
56 char *current_val; /* For rates */
57 u8 rate;
b453872c
JG
58
59 /* First entry *MUST* be the AP MAC address */
60 iwe.cmd = SIOCGIWAP;
61 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
62 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
ccc58057 63 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
b453872c
JG
64
65 /* Remaining entries will be displayed in the order we provide them */
66
67 /* Add the ESSID */
68 iwe.cmd = SIOCGIWESSID;
69 iwe.u.data.flags = 1;
c5d3dce8
JL
70 iwe.u.data.length = min(network->ssid_len, (u8) 32);
71 start = iwe_stream_add_point(info, start, stop,
72 &iwe, network->ssid);
b453872c
JG
73
74 /* Add the protocol name */
75 iwe.cmd = SIOCGIWNAME;
0edd5b44
JG
76 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
77 ieee80211_modes[network->mode]);
ccc58057 78 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
b453872c 79
0edd5b44
JG
80 /* Add mode */
81 iwe.cmd = SIOCGIWMODE;
82 if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
1b5cca3a 83 if (network->capability & WLAN_CAPABILITY_ESS)
b453872c
JG
84 iwe.u.mode = IW_MODE_MASTER;
85 else
86 iwe.u.mode = IW_MODE_ADHOC;
87
ccc58057
DM
88 start = iwe_stream_add_event(info, start, stop,
89 &iwe, IW_EV_UINT_LEN);
b453872c
JG
90 }
91
93afe3da 92 /* Add channel and frequency */
90869b24 93 /* Note : userspace automatically computes channel using iwrange */
b453872c 94 iwe.cmd = SIOCGIWFREQ;
93afe3da
LF
95 iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
96 iwe.u.freq.e = 6;
90869b24 97 iwe.u.freq.i = 0;
ccc58057 98 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
93afe3da 99
b453872c
JG
100 /* Add encryption capability */
101 iwe.cmd = SIOCGIWENCODE;
102 if (network->capability & WLAN_CAPABILITY_PRIVACY)
103 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
104 else
105 iwe.u.data.flags = IW_ENCODE_DISABLED;
106 iwe.u.data.length = 0;
ccc58057
DM
107 start = iwe_stream_add_point(info, start, stop,
108 &iwe, network->ssid);
b453872c
JG
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 */
ccc58057 113 current_val = start + iwe_stream_lcp_len(info);
09593047
ZY
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 */
ccc58057
DM
128 current_val = iwe_stream_add_value(info, start, current_val,
129 stop, &iwe, IW_EV_PARAM_LEN);
b453872c
JG
130 }
131 for (; j < network->rates_ex_len; j++) {
132 rate = network->rates_ex[j] & 0x7F;
09593047
ZY
133 /* Bit rate given in 500 kb/s units (+ 0x80) */
134 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
135 /* Add new value to event */
ccc58057
DM
136 current_val = iwe_stream_add_value(info, start, current_val,
137 stop, &iwe, IW_EV_PARAM_LEN);
b453872c 138 }
09593047 139 /* Check if we added any rate */
ccc58057 140 if ((current_val - start) > iwe_stream_lcp_len(info))
09593047 141 start = current_val;
b453872c
JG
142
143 /* Add quality statistics */
b453872c 144 iwe.cmd = IWEVQUAL;
b1b508e1
JK
145 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
146 IW_QUAL_NOISE_UPDATED;
147
148 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
149 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
150 IW_QUAL_LEVEL_INVALID;
151 iwe.u.qual.qual = 0;
b1b508e1 152 } else {
757d18fa
JB
153 if (ieee->perfect_rssi == ieee->worst_rssi)
154 iwe.u.qual.qual = 100;
155 else
156 iwe.u.qual.qual =
157 (100 *
158 (ieee->perfect_rssi - ieee->worst_rssi) *
159 (ieee->perfect_rssi - ieee->worst_rssi) -
160 (ieee->perfect_rssi - network->stats.rssi) *
161 (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
81f87520
JK
162 62 * (ieee->perfect_rssi -
163 network->stats.rssi))) /
164 ((ieee->perfect_rssi -
165 ieee->worst_rssi) * (ieee->perfect_rssi -
166 ieee->worst_rssi));
b1b508e1
JK
167 if (iwe.u.qual.qual > 100)
168 iwe.u.qual.qual = 100;
169 else if (iwe.u.qual.qual < 1)
170 iwe.u.qual.qual = 0;
171 }
172
173 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
b453872c 174 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
b1b508e1
JK
175 iwe.u.qual.noise = 0;
176 } else {
177 iwe.u.qual.noise = network->stats.noise;
178 }
b453872c 179
7bd64366
ZY
180 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
181 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
182 iwe.u.qual.level = 0;
183 } else {
184 iwe.u.qual.level = network->stats.signal;
185 }
186
ccc58057 187 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
b453872c
JG
188
189 iwe.cmd = IWEVCUSTOM;
190 p = custom;
191
192 iwe.u.data.length = p - custom;
193 if (iwe.u.data.length)
ccc58057 194 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
b453872c 195
47168082 196 memset(&iwe, 0, sizeof(iwe));
20d64713 197 if (network->wpa_ie_len) {
47168082
ZY
198 char buf[MAX_WPA_IE_LEN];
199 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
200 iwe.cmd = IWEVGENIE;
201 iwe.u.data.length = network->wpa_ie_len;
ccc58057 202 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
b453872c
JG
203 }
204
47168082 205 memset(&iwe, 0, sizeof(iwe));
20d64713 206 if (network->rsn_ie_len) {
47168082
ZY
207 char buf[MAX_WPA_IE_LEN];
208 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
209 iwe.cmd = IWEVGENIE;
210 iwe.u.data.length = network->rsn_ie_len;
ccc58057 211 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
b453872c
JG
212 }
213
214 /* Add EXTRA: Age to display seconds since last beacon/probe response
215 * for given network. */
216 iwe.cmd = IWEVCUSTOM;
217 p = custom;
218 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
42e349fd
JK
219 " Last beacon: %dms ago",
220 jiffies_to_msecs(jiffies - network->last_scanned));
b453872c
JG
221 iwe.u.data.length = p - custom;
222 if (iwe.u.data.length)
ccc58057 223 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
b453872c 224
7bd64366
ZY
225 /* Add spectrum management information */
226 iwe.cmd = -1;
227 p = custom;
228 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
229
230 if (ieee80211_get_channel_flags(ieee, network->channel) &
231 IEEE80211_CH_INVALID) {
232 iwe.cmd = IWEVCUSTOM;
233 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
234 }
235
236 if (ieee80211_get_channel_flags(ieee, network->channel) &
237 IEEE80211_CH_RADAR_DETECT) {
238 iwe.cmd = IWEVCUSTOM;
239 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
240 }
241
242 if (iwe.cmd == IWEVCUSTOM) {
243 iwe.u.data.length = p - custom;
ccc58057 244 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
7bd64366
ZY
245 }
246
b453872c
JG
247 return start;
248}
249
55cd94aa
ZY
250#define SCAN_ITEM_SIZE 128
251
b453872c
JG
252int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
253 struct iw_request_info *info,
254 union iwreq_data *wrqu, char *extra)
255{
256 struct ieee80211_network *network;
257 unsigned long flags;
55cd94aa 258 int err = 0;
b453872c
JG
259
260 char *ev = extra;
55cd94aa 261 char *stop = ev + wrqu->data.length;
b453872c 262 int i = 0;
9387b7ca 263 DECLARE_SSID_BUF(ssid);
b453872c
JG
264
265 IEEE80211_DEBUG_WX("Getting scan\n");
266
267 spin_lock_irqsave(&ieee->lock, flags);
268
269 list_for_each_entry(network, &ieee->network_list, list) {
270 i++;
55cd94aa
ZY
271 if (stop - ev < SCAN_ITEM_SIZE) {
272 err = -E2BIG;
273 break;
274 }
275
b453872c
JG
276 if (ieee->scan_age == 0 ||
277 time_after(network->last_scanned + ieee->scan_age, jiffies))
ccc58057
DM
278 ev = ieee80211_translate_scan(ieee, ev, stop, network,
279 info);
b453872c 280 else
0edd5b44 281 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
e174961c 282 "%pM)' due to age (%dms).\n",
9387b7ca 283 print_ssid(ssid, network->ssid,
7e272fcf 284 network->ssid_len),
e174961c 285 network->bssid,
42e349fd
JK
286 jiffies_to_msecs(jiffies -
287 network->
288 last_scanned));
b453872c
JG
289 }
290
291 spin_unlock_irqrestore(&ieee->lock, flags);
292
0edd5b44 293 wrqu->data.length = ev - extra;
b453872c
JG
294 wrqu->data.flags = 0;
295
296 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
297
55cd94aa 298 return err;
b453872c
JG
299}
300
301int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
302 struct iw_request_info *info,
303 union iwreq_data *wrqu, char *keybuf)
304{
305 struct iw_point *erq = &(wrqu->encoding);
306 struct net_device *dev = ieee->dev;
307 struct ieee80211_security sec = {
308 .flags = 0
309 };
310 int i, key, key_provided, len;
274bfb8d 311 struct lib80211_crypt_data **crypt;
a4bf26f3 312 int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
9387b7ca 313 DECLARE_SSID_BUF(ssid);
b453872c
JG
314
315 IEEE80211_DEBUG_WX("SET_ENCODE\n");
316
317 key = erq->flags & IW_ENCODE_INDEX;
318 if (key) {
319 if (key > WEP_KEYS)
320 return -EINVAL;
321 key--;
322 key_provided = 1;
323 } else {
324 key_provided = 0;
274bfb8d 325 key = ieee->crypt_info.tx_keyidx;
b453872c
JG
326 }
327
328 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
329 "provided" : "default");
330
274bfb8d 331 crypt = &ieee->crypt_info.crypt[key];
b453872c
JG
332
333 if (erq->flags & IW_ENCODE_DISABLED) {
334 if (key_provided && *crypt) {
335 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
336 key);
274bfb8d 337 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
b453872c
JG
338 } else
339 IEEE80211_DEBUG_WX("Disabling encryption.\n");
340
341 /* Check all the keys to see if any are still configured,
342 * and if no key index was provided, de-init them all */
343 for (i = 0; i < WEP_KEYS; i++) {
274bfb8d 344 if (ieee->crypt_info.crypt[i] != NULL) {
b453872c
JG
345 if (key_provided)
346 break;
274bfb8d
JL
347 lib80211_crypt_delayed_deinit(&ieee->crypt_info,
348 &ieee->crypt_info.crypt[i]);
b453872c
JG
349 }
350 }
351
352 if (i == WEP_KEYS) {
353 sec.enabled = 0;
f1bf6638 354 sec.encrypt = 0;
b453872c 355 sec.level = SEC_LEVEL_0;
259bf1fd 356 sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
b453872c
JG
357 }
358
359 goto done;
360 }
361
b453872c 362 sec.enabled = 1;
f1bf6638 363 sec.encrypt = 1;
259bf1fd 364 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
b453872c
JG
365
366 if (*crypt != NULL && (*crypt)->ops != NULL &&
367 strcmp((*crypt)->ops->name, "WEP") != 0) {
368 /* changing to use WEP; deinit previously used algorithm
369 * on this key */
274bfb8d 370 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
b453872c
JG
371 }
372
f1bf6638 373 if (*crypt == NULL && host_crypto) {
274bfb8d 374 struct lib80211_crypt_data *new_crypt;
b453872c
JG
375
376 /* take WEP into use */
274bfb8d 377 new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
b453872c
JG
378 GFP_KERNEL);
379 if (new_crypt == NULL)
380 return -ENOMEM;
274bfb8d 381 new_crypt->ops = lib80211_get_crypto_ops("WEP");
b453872c 382 if (!new_crypt->ops) {
274bfb8d
JL
383 request_module("lib80211_crypt_wep");
384 new_crypt->ops = lib80211_get_crypto_ops("WEP");
b453872c
JG
385 }
386
387 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
6eb6edf0 388 new_crypt->priv = new_crypt->ops->init(key);
b453872c
JG
389
390 if (!new_crypt->ops || !new_crypt->priv) {
391 kfree(new_crypt);
392 new_crypt = NULL;
393
394 printk(KERN_WARNING "%s: could not initialize WEP: "
274bfb8d 395 "load module lib80211_crypt_wep\n", dev->name);
b453872c
JG
396 return -EOPNOTSUPP;
397 }
398 *crypt = new_crypt;
399 }
400
401 /* If a new key was provided, set it up */
402 if (erq->length > 0) {
2a941ecb
HS
403#ifdef CONFIG_IEEE80211_DEBUG
404 DECLARE_SSID_BUF(ssid);
405#endif
406
b453872c
JG
407 len = erq->length <= 5 ? 5 : 13;
408 memcpy(sec.keys[key], keybuf, erq->length);
409 if (len > erq->length)
410 memset(sec.keys[key] + erq->length, 0,
411 len - erq->length);
412 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
9387b7ca 413 key, print_ssid(ssid, sec.keys[key], len),
b453872c
JG
414 erq->length, len);
415 sec.key_sizes[key] = len;
f1bf6638
JK
416 if (*crypt)
417 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
418 (*crypt)->priv);
b453872c
JG
419 sec.flags |= (1 << key);
420 /* This ensures a key will be activated if no key is
c03983ac 421 * explicitly set */
b453872c
JG
422 if (key == sec.active_key)
423 sec.flags |= SEC_ACTIVE_KEY;
f1bf6638 424
b453872c 425 } else {
f1bf6638
JK
426 if (host_crypto) {
427 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
428 NULL, (*crypt)->priv);
429 if (len == 0) {
430 /* Set a default key of all 0 */
431 IEEE80211_DEBUG_WX("Setting key %d to all "
432 "zero.\n", key);
433 memset(sec.keys[key], 0, 13);
434 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
435 (*crypt)->priv);
436 sec.key_sizes[key] = 13;
437 sec.flags |= (1 << key);
438 }
b453872c 439 }
b453872c
JG
440 /* No key data - just set the default TX key index */
441 if (key_provided) {
f1bf6638
JK
442 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
443 "key.\n", key);
274bfb8d 444 ieee->crypt_info.tx_keyidx = key;
b453872c
JG
445 sec.active_key = key;
446 sec.flags |= SEC_ACTIVE_KEY;
447 }
448 }
7dc888fe
JK
449 if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
450 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
451 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
452 WLAN_AUTH_SHARED_KEY;
453 sec.flags |= SEC_AUTH_MODE;
454 IEEE80211_DEBUG_WX("Auth: %s\n",
455 sec.auth_mode == WLAN_AUTH_OPEN ?
456 "OPEN" : "SHARED KEY");
457 }
b453872c
JG
458
459 /* For now we just support WEP, so only set that security level...
460 * TODO: When WPA is added this is one place that needs to change */
461 sec.flags |= SEC_LEVEL;
0edd5b44 462 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
e0d369d1 463 sec.encode_alg[key] = SEC_ALG_WEP;
b453872c 464
259bf1fd 465 done:
b453872c
JG
466 if (ieee->set_security)
467 ieee->set_security(dev, &sec);
468
469 /* Do not reset port if card is in Managed mode since resetting will
470 * generate new IEEE 802.11 authentication which may end up in looping
471 * with IEEE 802.1X. If your hardware requires a reset after WEP
472 * configuration (for example... Prism2), implement the reset_port in
473 * the callbacks structures used to initialize the 802.11 stack. */
474 if (ieee->reset_on_keychange &&
475 ieee->iw_mode != IW_MODE_INFRA &&
476 ieee->reset_port && ieee->reset_port(dev)) {
477 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
478 return -EINVAL;
479 }
480 return 0;
481}
482
483int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
484 struct iw_request_info *info,
485 union iwreq_data *wrqu, char *keybuf)
486{
487 struct iw_point *erq = &(wrqu->encoding);
488 int len, key;
274bfb8d 489 struct lib80211_crypt_data *crypt;
f1bf6638 490 struct ieee80211_security *sec = &ieee->sec;
b453872c
JG
491
492 IEEE80211_DEBUG_WX("GET_ENCODE\n");
493
494 key = erq->flags & IW_ENCODE_INDEX;
495 if (key) {
496 if (key > WEP_KEYS)
497 return -EINVAL;
498 key--;
499 } else
274bfb8d 500 key = ieee->crypt_info.tx_keyidx;
b453872c 501
274bfb8d 502 crypt = ieee->crypt_info.crypt[key];
b453872c
JG
503 erq->flags = key + 1;
504
f1bf6638 505 if (!sec->enabled) {
b453872c
JG
506 erq->length = 0;
507 erq->flags |= IW_ENCODE_DISABLED;
508 return 0;
509 }
510
f1bf6638
JK
511 len = sec->key_sizes[key];
512 memcpy(keybuf, sec->keys[key], len);
b453872c 513
6274115c 514 erq->length = len;
b453872c
JG
515 erq->flags |= IW_ENCODE_ENABLED;
516
517 if (ieee->open_wep)
518 erq->flags |= IW_ENCODE_OPEN;
519 else
520 erq->flags |= IW_ENCODE_RESTRICTED;
521
522 return 0;
523}
524
e0d369d1
JK
525int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
526 struct iw_request_info *info,
527 union iwreq_data *wrqu, char *extra)
528{
529 struct net_device *dev = ieee->dev;
530 struct iw_point *encoding = &wrqu->encoding;
531 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
532 int i, idx, ret = 0;
ccd0fda3 533 int group_key = 0;
e0d369d1 534 const char *alg, *module;
274bfb8d
JL
535 struct lib80211_crypto_ops *ops;
536 struct lib80211_crypt_data **crypt;
e0d369d1
JK
537
538 struct ieee80211_security sec = {
539 .flags = 0,
540 };
541
542 idx = encoding->flags & IW_ENCODE_INDEX;
543 if (idx) {
544 if (idx < 1 || idx > WEP_KEYS)
545 return -EINVAL;
546 idx--;
547 } else
274bfb8d 548 idx = ieee->crypt_info.tx_keyidx;
e0d369d1 549
ccd0fda3 550 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
274bfb8d 551 crypt = &ieee->crypt_info.crypt[idx];
ccd0fda3
JK
552 group_key = 1;
553 } else {
e189277a
VB
554 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
555 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
e0d369d1
JK
556 return -EINVAL;
557 if (ieee->iw_mode == IW_MODE_INFRA)
274bfb8d 558 crypt = &ieee->crypt_info.crypt[idx];
e0d369d1
JK
559 else
560 return -EINVAL;
561 }
562
563 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
564 if ((encoding->flags & IW_ENCODE_DISABLED) ||
565 ext->alg == IW_ENCODE_ALG_NONE) {
566 if (*crypt)
274bfb8d 567 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
e0d369d1
JK
568
569 for (i = 0; i < WEP_KEYS; i++)
274bfb8d 570 if (ieee->crypt_info.crypt[i] != NULL)
e0d369d1
JK
571 break;
572
573 if (i == WEP_KEYS) {
574 sec.enabled = 0;
575 sec.encrypt = 0;
576 sec.level = SEC_LEVEL_0;
577 sec.flags |= SEC_LEVEL;
578 }
579 goto done;
580 }
581
582 sec.enabled = 1;
583 sec.encrypt = 1;
584
ccd0fda3
JK
585 if (group_key ? !ieee->host_mc_decrypt :
586 !(ieee->host_encrypt || ieee->host_decrypt ||
587 ieee->host_encrypt_msdu))
e0d369d1
JK
588 goto skip_host_crypt;
589
590 switch (ext->alg) {
591 case IW_ENCODE_ALG_WEP:
592 alg = "WEP";
274bfb8d 593 module = "lib80211_crypt_wep";
e0d369d1
JK
594 break;
595 case IW_ENCODE_ALG_TKIP:
596 alg = "TKIP";
274bfb8d 597 module = "lib80211_crypt_tkip";
e0d369d1
JK
598 break;
599 case IW_ENCODE_ALG_CCMP:
600 alg = "CCMP";
274bfb8d 601 module = "lib80211_crypt_ccmp";
e0d369d1
JK
602 break;
603 default:
604 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
605 dev->name, ext->alg);
606 ret = -EINVAL;
607 goto done;
608 }
609
274bfb8d 610 ops = lib80211_get_crypto_ops(alg);
e0d369d1
JK
611 if (ops == NULL) {
612 request_module(module);
274bfb8d 613 ops = lib80211_get_crypto_ops(alg);
e0d369d1
JK
614 }
615 if (ops == NULL) {
616 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
617 dev->name, ext->alg);
618 ret = -EINVAL;
619 goto done;
620 }
621
622 if (*crypt == NULL || (*crypt)->ops != ops) {
274bfb8d 623 struct lib80211_crypt_data *new_crypt;
e0d369d1 624
274bfb8d 625 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
e0d369d1 626
0da974f4 627 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
e0d369d1
JK
628 if (new_crypt == NULL) {
629 ret = -ENOMEM;
630 goto done;
631 }
e0d369d1
JK
632 new_crypt->ops = ops;
633 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
6eb6edf0 634 new_crypt->priv = new_crypt->ops->init(idx);
e0d369d1
JK
635 if (new_crypt->priv == NULL) {
636 kfree(new_crypt);
637 ret = -EINVAL;
638 goto done;
639 }
640 *crypt = new_crypt;
641 }
642
643 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
644 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
645 (*crypt)->priv) < 0) {
646 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
647 ret = -EINVAL;
648 goto done;
649 }
650
651 skip_host_crypt:
652 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
274bfb8d 653 ieee->crypt_info.tx_keyidx = idx;
e0d369d1
JK
654 sec.active_key = idx;
655 sec.flags |= SEC_ACTIVE_KEY;
656 }
657
658 if (ext->alg != IW_ENCODE_ALG_NONE) {
659 memcpy(sec.keys[idx], ext->key, ext->key_len);
660 sec.key_sizes[idx] = ext->key_len;
661 sec.flags |= (1 << idx);
662 if (ext->alg == IW_ENCODE_ALG_WEP) {
663 sec.encode_alg[idx] = SEC_ALG_WEP;
664 sec.flags |= SEC_LEVEL;
665 sec.level = SEC_LEVEL_1;
666 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
667 sec.encode_alg[idx] = SEC_ALG_TKIP;
668 sec.flags |= SEC_LEVEL;
669 sec.level = SEC_LEVEL_2;
670 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
671 sec.encode_alg[idx] = SEC_ALG_CCMP;
672 sec.flags |= SEC_LEVEL;
673 sec.level = SEC_LEVEL_3;
674 }
ccd0fda3
JK
675 /* Don't set sec level for group keys. */
676 if (group_key)
677 sec.flags &= ~SEC_LEVEL;
e0d369d1
JK
678 }
679 done:
680 if (ieee->set_security)
681 ieee->set_security(ieee->dev, &sec);
682
683 /*
684 * Do not reset port if card is in Managed mode since resetting will
685 * generate new IEEE 802.11 authentication which may end up in looping
686 * with IEEE 802.1X. If your hardware requires a reset after WEP
687 * configuration (for example... Prism2), implement the reset_port in
688 * the callbacks structures used to initialize the 802.11 stack.
689 */
690 if (ieee->reset_on_keychange &&
691 ieee->iw_mode != IW_MODE_INFRA &&
692 ieee->reset_port && ieee->reset_port(dev)) {
693 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
694 return -EINVAL;
695 }
696
697 return ret;
698}
699
700int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
701 struct iw_request_info *info,
702 union iwreq_data *wrqu, char *extra)
703{
704 struct iw_point *encoding = &wrqu->encoding;
705 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
706 struct ieee80211_security *sec = &ieee->sec;
707 int idx, max_key_len;
708
709 max_key_len = encoding->length - sizeof(*ext);
710 if (max_key_len < 0)
711 return -EINVAL;
712
713 idx = encoding->flags & IW_ENCODE_INDEX;
714 if (idx) {
715 if (idx < 1 || idx > WEP_KEYS)
716 return -EINVAL;
717 idx--;
718 } else
274bfb8d 719 idx = ieee->crypt_info.tx_keyidx;
e0d369d1 720
f59d9782 721 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
e189277a 722 ext->alg != IW_ENCODE_ALG_WEP)
e0d369d1
JK
723 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
724 return -EINVAL;
725
726 encoding->flags = idx + 1;
727 memset(ext, 0, sizeof(*ext));
728
729 if (!sec->enabled) {
730 ext->alg = IW_ENCODE_ALG_NONE;
731 ext->key_len = 0;
732 encoding->flags |= IW_ENCODE_DISABLED;
733 } else {
734 if (sec->encode_alg[idx] == SEC_ALG_WEP)
735 ext->alg = IW_ENCODE_ALG_WEP;
736 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
737 ext->alg = IW_ENCODE_ALG_TKIP;
738 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
739 ext->alg = IW_ENCODE_ALG_CCMP;
740 else
741 return -EINVAL;
742
743 ext->key_len = sec->key_sizes[idx];
744 memcpy(ext->key, sec->keys[idx], ext->key_len);
745 encoding->flags |= IW_ENCODE_ENABLED;
746 if (ext->key_len &&
747 (ext->alg == IW_ENCODE_ALG_TKIP ||
748 ext->alg == IW_ENCODE_ALG_CCMP))
749 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
750
751 }
752
753 return 0;
754}
755
756EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
757EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
e0d369d1 758
b453872c
JG
759EXPORT_SYMBOL(ieee80211_wx_get_scan);
760EXPORT_SYMBOL(ieee80211_wx_set_encode);
761EXPORT_SYMBOL(ieee80211_wx_get_encode);
This page took 0.426493 seconds and 5 git commands to generate.