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