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