remove ieee80211_wx_{get,set}_auth()
[GitHub/mt8127/android_kernel_alcatel_ttab.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,
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
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;
93afe3da
LF
98 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
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;
107 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
108
109 /* Add basic and extended rates */
09593047
ZY
110 /* Rate : stuffing multiple values in a single event require a bit
111 * more of magic - Jean II */
112 current_val = start + IW_EV_LCP_LEN;
113 iwe.cmd = SIOCGIWRATE;
114 /* Those two flags are ignored... */
115 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
116
0edd5b44 117 for (i = 0, j = 0; i < network->rates_len;) {
b453872c
JG
118 if (j < network->rates_ex_len &&
119 ((network->rates_ex[j] & 0x7F) <
120 (network->rates[i] & 0x7F)))
121 rate = network->rates_ex[j++] & 0x7F;
122 else
123 rate = network->rates[i++] & 0x7F;
09593047
ZY
124 /* Bit rate given in 500 kb/s units (+ 0x80) */
125 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
126 /* Add new value to event */
127 current_val = iwe_stream_add_value(start, current_val, 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 */
134 current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
b453872c 135 }
09593047
ZY
136 /* Check if we added any rate */
137 if((current_val - start) > IW_EV_LCP_LEN)
138 start = current_val;
b453872c
JG
139
140 /* Add quality statistics */
b453872c 141 iwe.cmd = IWEVQUAL;
b1b508e1
JK
142 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
143 IW_QUAL_NOISE_UPDATED;
144
145 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
146 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
147 IW_QUAL_LEVEL_INVALID;
148 iwe.u.qual.qual = 0;
b1b508e1 149 } else {
757d18fa
JB
150 if (ieee->perfect_rssi == ieee->worst_rssi)
151 iwe.u.qual.qual = 100;
152 else
153 iwe.u.qual.qual =
154 (100 *
155 (ieee->perfect_rssi - ieee->worst_rssi) *
156 (ieee->perfect_rssi - ieee->worst_rssi) -
157 (ieee->perfect_rssi - network->stats.rssi) *
158 (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
81f87520
JK
159 62 * (ieee->perfect_rssi -
160 network->stats.rssi))) /
161 ((ieee->perfect_rssi -
162 ieee->worst_rssi) * (ieee->perfect_rssi -
163 ieee->worst_rssi));
b1b508e1
JK
164 if (iwe.u.qual.qual > 100)
165 iwe.u.qual.qual = 100;
166 else if (iwe.u.qual.qual < 1)
167 iwe.u.qual.qual = 0;
168 }
169
170 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
b453872c 171 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
b1b508e1
JK
172 iwe.u.qual.noise = 0;
173 } else {
174 iwe.u.qual.noise = network->stats.noise;
175 }
b453872c 176
7bd64366
ZY
177 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
178 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
179 iwe.u.qual.level = 0;
180 } else {
181 iwe.u.qual.level = network->stats.signal;
182 }
183
b453872c
JG
184 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
185
186 iwe.cmd = IWEVCUSTOM;
187 p = custom;
188
189 iwe.u.data.length = p - custom;
190 if (iwe.u.data.length)
191 start = iwe_stream_add_point(start, stop, &iwe, custom);
192
47168082 193 memset(&iwe, 0, sizeof(iwe));
20d64713 194 if (network->wpa_ie_len) {
47168082
ZY
195 char buf[MAX_WPA_IE_LEN];
196 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
197 iwe.cmd = IWEVGENIE;
198 iwe.u.data.length = network->wpa_ie_len;
b453872c
JG
199 start = iwe_stream_add_point(start, stop, &iwe, buf);
200 }
201
47168082 202 memset(&iwe, 0, sizeof(iwe));
20d64713 203 if (network->rsn_ie_len) {
47168082
ZY
204 char buf[MAX_WPA_IE_LEN];
205 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
206 iwe.cmd = IWEVGENIE;
207 iwe.u.data.length = network->rsn_ie_len;
b453872c
JG
208 start = iwe_stream_add_point(start, stop, &iwe, buf);
209 }
210
211 /* Add EXTRA: Age to display seconds since last beacon/probe response
212 * for given network. */
213 iwe.cmd = IWEVCUSTOM;
214 p = custom;
215 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
42e349fd
JK
216 " Last beacon: %dms ago",
217 jiffies_to_msecs(jiffies - network->last_scanned));
b453872c
JG
218 iwe.u.data.length = p - custom;
219 if (iwe.u.data.length)
220 start = iwe_stream_add_point(start, stop, &iwe, custom);
221
7bd64366
ZY
222 /* Add spectrum management information */
223 iwe.cmd = -1;
224 p = custom;
225 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
226
227 if (ieee80211_get_channel_flags(ieee, network->channel) &
228 IEEE80211_CH_INVALID) {
229 iwe.cmd = IWEVCUSTOM;
230 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
231 }
232
233 if (ieee80211_get_channel_flags(ieee, network->channel) &
234 IEEE80211_CH_RADAR_DETECT) {
235 iwe.cmd = IWEVCUSTOM;
236 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
237 }
238
239 if (iwe.cmd == IWEVCUSTOM) {
240 iwe.u.data.length = p - custom;
241 start = iwe_stream_add_point(start, stop, &iwe, custom);
242 }
243
b453872c
JG
244 return start;
245}
246
55cd94aa
ZY
247#define SCAN_ITEM_SIZE 128
248
b453872c
JG
249int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
250 struct iw_request_info *info,
251 union iwreq_data *wrqu, char *extra)
252{
253 struct ieee80211_network *network;
254 unsigned long flags;
55cd94aa 255 int err = 0;
b453872c
JG
256
257 char *ev = extra;
55cd94aa 258 char *stop = ev + wrqu->data.length;
b453872c 259 int i = 0;
0795af57 260 DECLARE_MAC_BUF(mac);
b453872c
JG
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 ("
0795af57 278 "%s)' due to age (%dms).\n",
0edd5b44
JG
279 escape_essid(network->ssid,
280 network->ssid_len),
0795af57 281 print_mac(mac, 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 */
0da974f4 372 new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
b453872c
JG
373 GFP_KERNEL);
374 if (new_crypt == NULL)
375 return -ENOMEM;
b453872c
JG
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))
6eb6edf0 383 new_crypt->priv = new_crypt->ops->init(key);
b453872c
JG
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: "
0edd5b44 390 "load module ieee80211_crypt_wep\n", dev->name);
b453872c
JG
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;
f1bf6638
JK
407 if (*crypt)
408 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
409 (*crypt)->priv);
b453872c
JG
410 sec.flags |= (1 << key);
411 /* This ensures a key will be activated if no key is
c03983ac 412 * explicitly set */
b453872c
JG
413 if (key == sec.active_key)
414 sec.flags |= SEC_ACTIVE_KEY;
f1bf6638 415
b453872c 416 } else {
f1bf6638
JK
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 }
b453872c 430 }
b453872c
JG
431 /* No key data - just set the default TX key index */
432 if (key_provided) {
f1bf6638
JK
433 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
434 "key.\n", key);
b453872c
JG
435 ieee->tx_keyidx = key;
436 sec.active_key = key;
437 sec.flags |= SEC_ACTIVE_KEY;
438 }
439 }
7dc888fe
JK
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 }
b453872c
JG
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;
0edd5b44 453 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
e0d369d1 454 sec.encode_alg[key] = SEC_ALG_WEP;
b453872c 455
259bf1fd 456 done:
b453872c
JG
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
474int 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;
f1bf6638 481 struct ieee80211_security *sec = &ieee->sec;
b453872c
JG
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
f1bf6638 496 if (!sec->enabled) {
b453872c
JG
497 erq->length = 0;
498 erq->flags |= IW_ENCODE_DISABLED;
499 return 0;
500 }
501
f1bf6638
JK
502 len = sec->key_sizes[key];
503 memcpy(keybuf, sec->keys[key], len);
b453872c 504
6274115c 505 erq->length = len;
b453872c
JG
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
e0d369d1
JK
516int 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;
ccd0fda3 524 int group_key = 0;
e0d369d1
JK
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
ccd0fda3 541 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
e0d369d1 542 crypt = &ieee->crypt[idx];
ccd0fda3
JK
543 group_key = 1;
544 } else {
e189277a
VB
545 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
546 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
e0d369d1
JK
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
ccd0fda3
JK
576 if (group_key ? !ieee->host_mc_decrypt :
577 !(ieee->host_encrypt || ieee->host_decrypt ||
578 ieee->host_encrypt_msdu))
e0d369d1
JK
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
0da974f4 618 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
e0d369d1
JK
619 if (new_crypt == NULL) {
620 ret = -ENOMEM;
621 goto done;
622 }
e0d369d1
JK
623 new_crypt->ops = ops;
624 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
6eb6edf0 625 new_crypt->priv = new_crypt->ops->init(idx);
e0d369d1
JK
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 }
ccd0fda3
JK
666 /* Don't set sec level for group keys. */
667 if (group_key)
668 sec.flags &= ~SEC_LEVEL;
e0d369d1
JK
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
691int 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
f59d9782 712 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
e189277a 713 ext->alg != IW_ENCODE_ALG_WEP)
e0d369d1
JK
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
747EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
748EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
e0d369d1 749
b453872c
JG
750EXPORT_SYMBOL(ieee80211_wx_get_scan);
751EXPORT_SYMBOL(ieee80211_wx_set_encode);
752EXPORT_SYMBOL(ieee80211_wx_get_encode);