1 /****************************************************************************** 2 3 Copyright(c) 2004 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 <jkmaline@cc.hut.fi> 9 Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.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 James P. Ketrenos <ipw2100-admin@linux.intel.com> 29 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 30 31 ******************************************************************************/ 32 #include <linux/wireless.h> 33 #include <linux/kmod.h> 34 #include <linux/slab.h> 35 #include <linux/module.h> 36 37 #include "ieee80211.h" 38 struct modes_unit { 39 char *mode_string; 40 int mode_size; 41 }; 42 static struct modes_unit ieee80211_modes[] = { 43 {"a", 1}, 44 {"b", 1}, 45 {"g", 1}, 46 {"?", 1}, 47 {"N-24G", 5}, 48 {"N-5G", 4}, 49 }; 50 51 #define iwe_stream_add_event_rsl iwe_stream_add_event 52 53 #define MAX_CUSTOM_LEN 64 54 static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee, 55 char *start, char *stop, 56 struct ieee80211_network *network, 57 struct iw_request_info *info) 58 { 59 char custom[MAX_CUSTOM_LEN]; 60 char proto_name[IFNAMSIZ]; 61 char *pname = proto_name; 62 char *p; 63 struct iw_event iwe; 64 int i, j; 65 u16 max_rate, rate; 66 static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; 67 68 /* First entry *MUST* be the AP MAC address */ 69 iwe.cmd = SIOCGIWAP; 70 iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 71 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); 72 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN); 73 /* Remaining entries will be displayed in the order we provide them */ 74 75 /* Add the ESSID */ 76 iwe.cmd = SIOCGIWESSID; 77 iwe.u.data.flags = 1; 78 // if (network->flags & NETWORK_EMPTY_ESSID) { 79 if (network->ssid_len == 0) { 80 iwe.u.data.length = sizeof("<hidden>"); 81 start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>"); 82 } else { 83 iwe.u.data.length = min(network->ssid_len, (u8)32); 84 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); 85 } 86 /* Add the protocol name */ 87 iwe.cmd = SIOCGIWNAME; 88 for(i=0; i<ARRAY_SIZE(ieee80211_modes); i++) { 89 if(network->mode&(1<<i)) { 90 sprintf(pname,ieee80211_modes[i].mode_string,ieee80211_modes[i].mode_size); 91 pname +=ieee80211_modes[i].mode_size; 92 } 93 } 94 *pname = '\0'; 95 snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name); 96 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN); 97 /* Add mode */ 98 iwe.cmd = SIOCGIWMODE; 99 if (network->capability & 100 (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) { 101 if (network->capability & WLAN_CAPABILITY_BSS) 102 iwe.u.mode = IW_MODE_MASTER; 103 else 104 iwe.u.mode = IW_MODE_ADHOC; 105 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN); 106 } 107 108 /* Add frequency/channel */ 109 iwe.cmd = SIOCGIWFREQ; 110 /* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode); 111 iwe.u.freq.e = 3; */ 112 iwe.u.freq.m = network->channel; 113 iwe.u.freq.e = 0; 114 iwe.u.freq.i = 0; 115 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN); 116 /* Add encryption capability */ 117 iwe.cmd = SIOCGIWENCODE; 118 if (network->capability & WLAN_CAPABILITY_PRIVACY) 119 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; 120 else 121 iwe.u.data.flags = IW_ENCODE_DISABLED; 122 iwe.u.data.length = 0; 123 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); 124 /* Add basic and extended rates */ 125 max_rate = 0; 126 p = custom; 127 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); 128 for (i = 0, j = 0; i < network->rates_len; ) { 129 if (j < network->rates_ex_len && 130 ((network->rates_ex[j] & 0x7F) < 131 (network->rates[i] & 0x7F))) 132 rate = network->rates_ex[j++] & 0x7F; 133 else 134 rate = network->rates[i++] & 0x7F; 135 if (rate > max_rate) 136 max_rate = rate; 137 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), 138 "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); 139 } 140 for (; j < network->rates_ex_len; j++) { 141 rate = network->rates_ex[j] & 0x7F; 142 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), 143 "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); 144 if (rate > max_rate) 145 max_rate = rate; 146 } 147 148 if (network->mode >= IEEE_N_24G)//add N rate here; 149 { 150 PHT_CAPABILITY_ELE ht_cap = NULL; 151 bool is40M = false, isShortGI = false; 152 u8 max_mcs = 0; 153 if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4)) 154 ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4]; 155 else 156 ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0]; 157 is40M = (ht_cap->ChlWidth)?1:0; 158 isShortGI = (ht_cap->ChlWidth)? 159 ((ht_cap->ShortGI40Mhz)?1:0): 160 ((ht_cap->ShortGI20Mhz)?1:0); 161 162 max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL); 163 rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f]; 164 if (rate > max_rate) 165 max_rate = rate; 166 } 167 iwe.cmd = SIOCGIWRATE; 168 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; 169 iwe.u.bitrate.value = max_rate * 500000; 170 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, 171 IW_EV_PARAM_LEN); 172 iwe.cmd = IWEVCUSTOM; 173 iwe.u.data.length = p - custom; 174 if (iwe.u.data.length) 175 start = iwe_stream_add_point(info, start, stop, &iwe, custom); 176 /* Add quality statistics */ 177 /* TODO: Fix these values... */ 178 iwe.cmd = IWEVQUAL; 179 iwe.u.qual.qual = network->stats.signal; 180 iwe.u.qual.level = network->stats.rssi; 181 iwe.u.qual.noise = network->stats.noise; 182 iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK; 183 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) 184 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; 185 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) 186 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; 187 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) 188 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; 189 iwe.u.qual.updated = 7; 190 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN); 191 iwe.cmd = IWEVCUSTOM; 192 p = custom; 193 194 iwe.u.data.length = p - custom; 195 if (iwe.u.data.length) 196 start = iwe_stream_add_point(info, start, stop, &iwe, custom); 197 198 if (ieee->wpa_enabled && network->wpa_ie_len){ 199 char buf[MAX_WPA_IE_LEN * 2 + 30]; 200 // printk("WPA IE\n"); 201 u8 *p = buf; 202 p += sprintf(p, "wpa_ie="); 203 for (i = 0; i < network->wpa_ie_len; i++) { 204 p += sprintf(p, "%02x", network->wpa_ie[i]); 205 } 206 207 memset(&iwe, 0, sizeof(iwe)); 208 iwe.cmd = IWEVCUSTOM; 209 iwe.u.data.length = strlen(buf); 210 start = iwe_stream_add_point(info, start, stop, &iwe, buf); 211 } 212 213 if (ieee->wpa_enabled && network->rsn_ie_len){ 214 char buf[MAX_WPA_IE_LEN * 2 + 30]; 215 216 u8 *p = buf; 217 p += sprintf(p, "rsn_ie="); 218 for (i = 0; i < network->rsn_ie_len; i++) { 219 p += sprintf(p, "%02x", network->rsn_ie[i]); 220 } 221 222 memset(&iwe, 0, sizeof(iwe)); 223 iwe.cmd = IWEVCUSTOM; 224 iwe.u.data.length = strlen(buf); 225 start = iwe_stream_add_point(info, start, stop, &iwe, buf); 226 } 227 228 229 /* Add EXTRA: Age to display seconds since last beacon/probe response 230 * for given network. */ 231 iwe.cmd = IWEVCUSTOM; 232 p = custom; 233 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), 234 " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100)); 235 iwe.u.data.length = p - custom; 236 if (iwe.u.data.length) 237 start = iwe_stream_add_point(info, start, stop, &iwe, custom); 238 239 return start; 240 } 241 242 int ieee80211_wx_get_scan(struct ieee80211_device *ieee, 243 struct iw_request_info *info, 244 union iwreq_data *wrqu, char *extra) 245 { 246 struct ieee80211_network *network; 247 unsigned long flags; 248 249 char *ev = extra; 250 // char *stop = ev + IW_SCAN_MAX_DATA; 251 char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA; 252 //char *stop = ev + IW_SCAN_MAX_DATA; 253 int i = 0; 254 int err = 0; 255 IEEE80211_DEBUG_WX("Getting scan\n"); 256 mutex_lock(&ieee->wx_mutex); 257 spin_lock_irqsave(&ieee->lock, flags); 258 259 list_for_each_entry(network, &ieee->network_list, list) { 260 i++; 261 if((stop-ev)<200) 262 { 263 err = -E2BIG; 264 break; 265 } 266 if (ieee->scan_age == 0 || 267 time_after(network->last_scanned + ieee->scan_age, jiffies)) 268 ev = rtl819x_translate_scan(ieee, ev, stop, network, info); 269 else 270 IEEE80211_DEBUG_SCAN( 271 "Not showing network '%s (" 272 "%pM)' due to age (%lums).\n", 273 escape_essid(network->ssid, 274 network->ssid_len), 275 network->bssid, 276 (jiffies - network->last_scanned) / (HZ / 100)); 277 } 278 279 spin_unlock_irqrestore(&ieee->lock, flags); 280 mutex_unlock(&ieee->wx_mutex); 281 wrqu->data.length = ev - extra; 282 wrqu->data.flags = 0; 283 284 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); 285 286 return err; 287 } 288 EXPORT_SYMBOL(ieee80211_wx_get_scan); 289 290 int ieee80211_wx_set_encode(struct ieee80211_device *ieee, 291 struct iw_request_info *info, 292 union iwreq_data *wrqu, char *keybuf) 293 { 294 struct iw_point *erq = &(wrqu->encoding); 295 struct net_device *dev = ieee->dev; 296 struct ieee80211_security sec = { 297 .flags = 0 298 }; 299 int i, key, key_provided, len; 300 struct ieee80211_crypt_data **crypt; 301 302 IEEE80211_DEBUG_WX("SET_ENCODE\n"); 303 304 key = erq->flags & IW_ENCODE_INDEX; 305 if (key) { 306 if (key > WEP_KEYS) 307 return -EINVAL; 308 key--; 309 key_provided = 1; 310 } else { 311 key_provided = 0; 312 key = ieee->tx_keyidx; 313 } 314 315 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? 316 "provided" : "default"); 317 crypt = &ieee->crypt[key]; 318 319 if (erq->flags & IW_ENCODE_DISABLED) { 320 if (key_provided && *crypt) { 321 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", 322 key); 323 ieee80211_crypt_delayed_deinit(ieee, crypt); 324 } else 325 IEEE80211_DEBUG_WX("Disabling encryption.\n"); 326 327 /* Check all the keys to see if any are still configured, 328 * and if no key index was provided, de-init them all */ 329 for (i = 0; i < WEP_KEYS; i++) { 330 if (ieee->crypt[i] != NULL) { 331 if (key_provided) 332 break; 333 ieee80211_crypt_delayed_deinit( 334 ieee, &ieee->crypt[i]); 335 } 336 } 337 338 if (i == WEP_KEYS) { 339 sec.enabled = 0; 340 sec.level = SEC_LEVEL_0; 341 sec.flags |= SEC_ENABLED | SEC_LEVEL; 342 } 343 344 goto done; 345 } 346 347 348 349 sec.enabled = 1; 350 sec.flags |= SEC_ENABLED; 351 352 if (*crypt != NULL && (*crypt)->ops != NULL && 353 strcmp((*crypt)->ops->name, "WEP") != 0) { 354 /* changing to use WEP; deinit previously used algorithm 355 * on this key */ 356 ieee80211_crypt_delayed_deinit(ieee, crypt); 357 } 358 359 if (*crypt == NULL) { 360 struct ieee80211_crypt_data *new_crypt; 361 362 /* take WEP into use */ 363 new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), 364 GFP_KERNEL); 365 if (!new_crypt) 366 return -ENOMEM; 367 new_crypt->ops = try_then_request_module(ieee80211_get_crypto_ops("WEP"), 368 "ieee80211_crypt_wep"); 369 if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) 370 new_crypt->priv = new_crypt->ops->init(key); 371 372 if (!new_crypt->ops || !new_crypt->priv) { 373 kfree(new_crypt); 374 new_crypt = NULL; 375 376 printk(KERN_WARNING "%s: could not initialize WEP: " 377 "load module ieee80211_crypt_wep\n", 378 dev->name); 379 return -EOPNOTSUPP; 380 } 381 *crypt = new_crypt; 382 } 383 384 /* If a new key was provided, set it up */ 385 if (erq->length > 0) { 386 len = erq->length <= 5 ? 5 : 13; 387 memcpy(sec.keys[key], keybuf, erq->length); 388 if (len > erq->length) 389 memset(sec.keys[key] + erq->length, 0, 390 len - erq->length); 391 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", 392 key, escape_essid(sec.keys[key], len), 393 erq->length, len); 394 sec.key_sizes[key] = len; 395 (*crypt)->ops->set_key(sec.keys[key], len, NULL, 396 (*crypt)->priv); 397 sec.flags |= (1 << key); 398 /* This ensures a key will be activated if no key is 399 * explicitely set */ 400 if (key == sec.active_key) 401 sec.flags |= SEC_ACTIVE_KEY; 402 ieee->tx_keyidx = key; 403 404 } else { 405 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, 406 NULL, (*crypt)->priv); 407 if (len == 0) { 408 /* Set a default key of all 0 */ 409 printk("Setting key %d to all zero.\n", 410 key); 411 412 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", 413 key); 414 memset(sec.keys[key], 0, 13); 415 (*crypt)->ops->set_key(sec.keys[key], 13, NULL, 416 (*crypt)->priv); 417 sec.key_sizes[key] = 13; 418 sec.flags |= (1 << key); 419 } 420 421 /* No key data - just set the default TX key index */ 422 if (key_provided) { 423 IEEE80211_DEBUG_WX( 424 "Setting key %d to default Tx key.\n", key); 425 ieee->tx_keyidx = key; 426 sec.active_key = key; 427 sec.flags |= SEC_ACTIVE_KEY; 428 } 429 } 430 431 done: 432 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); 433 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; 434 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; 435 sec.flags |= SEC_AUTH_MODE; 436 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? 437 "OPEN" : "SHARED KEY"); 438 439 /* For now we just support WEP, so only set that security level... 440 * TODO: When WPA is added this is one place that needs to change */ 441 sec.flags |= SEC_LEVEL; 442 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ 443 444 if (ieee->set_security) 445 ieee->set_security(dev, &sec); 446 447 /* Do not reset port if card is in Managed mode since resetting will 448 * generate new IEEE 802.11 authentication which may end up in looping 449 * with IEEE 802.1X. If your hardware requires a reset after WEP 450 * configuration (for example... Prism2), implement the reset_port in 451 * the callbacks structures used to initialize the 802.11 stack. */ 452 if (ieee->reset_on_keychange && 453 ieee->iw_mode != IW_MODE_INFRA && 454 ieee->reset_port && ieee->reset_port(dev)) { 455 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); 456 return -EINVAL; 457 } 458 return 0; 459 } 460 EXPORT_SYMBOL(ieee80211_wx_set_encode); 461 462 int ieee80211_wx_get_encode(struct ieee80211_device *ieee, 463 struct iw_request_info *info, 464 union iwreq_data *wrqu, char *keybuf) 465 { 466 struct iw_point *erq = &(wrqu->encoding); 467 int len, key; 468 struct ieee80211_crypt_data *crypt; 469 470 IEEE80211_DEBUG_WX("GET_ENCODE\n"); 471 472 if(ieee->iw_mode == IW_MODE_MONITOR) 473 return -1; 474 475 key = erq->flags & IW_ENCODE_INDEX; 476 if (key) { 477 if (key > WEP_KEYS) 478 return -EINVAL; 479 key--; 480 } else 481 key = ieee->tx_keyidx; 482 483 crypt = ieee->crypt[key]; 484 erq->flags = key + 1; 485 486 if (crypt == NULL || crypt->ops == NULL) { 487 erq->length = 0; 488 erq->flags |= IW_ENCODE_DISABLED; 489 return 0; 490 } 491 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv); 492 erq->length = (len >= 0 ? len : 0); 493 494 erq->flags |= IW_ENCODE_ENABLED; 495 496 if (ieee->open_wep) 497 erq->flags |= IW_ENCODE_OPEN; 498 else 499 erq->flags |= IW_ENCODE_RESTRICTED; 500 501 return 0; 502 } 503 EXPORT_SYMBOL(ieee80211_wx_get_encode); 504 505 int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, 506 struct iw_request_info *info, 507 union iwreq_data *wrqu, char *extra) 508 { 509 int ret = 0; 510 struct net_device *dev = ieee->dev; 511 struct iw_point *encoding = &wrqu->encoding; 512 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 513 int i, idx; 514 int group_key = 0; 515 const char *alg, *module; 516 struct ieee80211_crypto_ops *ops; 517 struct ieee80211_crypt_data **crypt; 518 519 struct ieee80211_security sec = { 520 .flags = 0, 521 }; 522 idx = encoding->flags & IW_ENCODE_INDEX; 523 if (idx) { 524 if (idx < 1 || idx > WEP_KEYS) 525 return -EINVAL; 526 idx--; 527 } else 528 idx = ieee->tx_keyidx; 529 530 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { 531 532 crypt = &ieee->crypt[idx]; 533 534 group_key = 1; 535 } else { 536 /* some Cisco APs use idx>0 for unicast in dynamic WEP */ 537 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) 538 return -EINVAL; 539 if (ieee->iw_mode == IW_MODE_INFRA) 540 541 crypt = &ieee->crypt[idx]; 542 543 else 544 return -EINVAL; 545 } 546 547 sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT; 548 if ((encoding->flags & IW_ENCODE_DISABLED) || 549 ext->alg == IW_ENCODE_ALG_NONE) { 550 if (*crypt) 551 ieee80211_crypt_delayed_deinit(ieee, crypt); 552 553 for (i = 0; i < WEP_KEYS; i++) 554 555 if (ieee->crypt[i] != NULL) 556 557 break; 558 559 if (i == WEP_KEYS) { 560 sec.enabled = 0; 561 // sec.encrypt = 0; 562 sec.level = SEC_LEVEL_0; 563 sec.flags |= SEC_LEVEL; 564 } 565 goto done; 566 } 567 568 sec.enabled = 1; 569 // sec.encrypt = 1; 570 switch (ext->alg) { 571 case IW_ENCODE_ALG_WEP: 572 alg = "WEP"; 573 module = "ieee80211_crypt_wep"; 574 break; 575 case IW_ENCODE_ALG_TKIP: 576 alg = "TKIP"; 577 module = "ieee80211_crypt_tkip"; 578 break; 579 case IW_ENCODE_ALG_CCMP: 580 alg = "CCMP"; 581 module = "ieee80211_crypt_ccmp"; 582 break; 583 default: 584 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", 585 dev->name, ext->alg); 586 ret = -EINVAL; 587 goto done; 588 } 589 printk("alg name:%s\n",alg); 590 591 ops = try_then_request_module(ieee80211_get_crypto_ops(alg), module); 592 if (!ops) { 593 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", 594 dev->name, ext->alg); 595 printk("========>unknown crypto alg %d\n", ext->alg); 596 ret = -EINVAL; 597 goto done; 598 } 599 600 if (*crypt == NULL || (*crypt)->ops != ops) { 601 struct ieee80211_crypt_data *new_crypt; 602 603 ieee80211_crypt_delayed_deinit(ieee, crypt); 604 605 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); 606 if (!new_crypt) { 607 ret = -ENOMEM; 608 goto done; 609 } 610 new_crypt->ops = ops; 611 if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) 612 new_crypt->priv = new_crypt->ops->init(idx); 613 if (new_crypt->priv == NULL) { 614 kfree(new_crypt); 615 ret = -EINVAL; 616 goto done; 617 } 618 *crypt = new_crypt; 619 } 620 621 if (ext->key_len > 0 && (*crypt)->ops->set_key && 622 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, 623 (*crypt)->priv) < 0) { 624 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); 625 printk("key setting failed\n"); 626 ret = -EINVAL; 627 goto done; 628 } 629 //skip_host_crypt: 630 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { 631 ieee->tx_keyidx = idx; 632 sec.active_key = idx; 633 sec.flags |= SEC_ACTIVE_KEY; 634 } 635 636 if (ext->alg != IW_ENCODE_ALG_NONE) { 637 //memcpy(sec.keys[idx], ext->key, ext->key_len); 638 sec.key_sizes[idx] = ext->key_len; 639 sec.flags |= (1 << idx); 640 if (ext->alg == IW_ENCODE_ALG_WEP) { 641 // sec.encode_alg[idx] = SEC_ALG_WEP; 642 sec.flags |= SEC_LEVEL; 643 sec.level = SEC_LEVEL_1; 644 } else if (ext->alg == IW_ENCODE_ALG_TKIP) { 645 // sec.encode_alg[idx] = SEC_ALG_TKIP; 646 sec.flags |= SEC_LEVEL; 647 sec.level = SEC_LEVEL_2; 648 } else if (ext->alg == IW_ENCODE_ALG_CCMP) { 649 // sec.encode_alg[idx] = SEC_ALG_CCMP; 650 sec.flags |= SEC_LEVEL; 651 sec.level = SEC_LEVEL_3; 652 } 653 /* Don't set sec level for group keys. */ 654 if (group_key) 655 sec.flags &= ~SEC_LEVEL; 656 } 657 done: 658 if (ieee->set_security) 659 ieee->set_security(ieee->dev, &sec); 660 661 if (ieee->reset_on_keychange && 662 ieee->iw_mode != IW_MODE_INFRA && 663 ieee->reset_port && ieee->reset_port(dev)) { 664 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); 665 return -EINVAL; 666 } 667 return ret; 668 } 669 EXPORT_SYMBOL(ieee80211_wx_set_encode_ext); 670 671 int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee, 672 struct iw_request_info *info, 673 union iwreq_data *wrqu, char *extra) 674 { 675 struct iw_point *encoding = &wrqu->encoding; 676 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 677 struct ieee80211_crypt_data *crypt; 678 int idx, max_key_len; 679 680 max_key_len = encoding->length - sizeof(*ext); 681 if (max_key_len < 0) 682 return -EINVAL; 683 684 idx = encoding->flags & IW_ENCODE_INDEX; 685 if (idx) { 686 if (idx < 1 || idx > WEP_KEYS) 687 return -EINVAL; 688 idx--; 689 } else 690 idx = ieee->tx_keyidx; 691 692 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && 693 ext->alg != IW_ENCODE_ALG_WEP) 694 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA) 695 return -EINVAL; 696 697 crypt = ieee->crypt[idx]; 698 encoding->flags = idx + 1; 699 memset(ext, 0, sizeof(*ext)); 700 701 if (crypt == NULL || crypt->ops == NULL ) { 702 ext->alg = IW_ENCODE_ALG_NONE; 703 ext->key_len = 0; 704 encoding->flags |= IW_ENCODE_DISABLED; 705 } else { 706 if (strcmp(crypt->ops->name, "WEP") == 0 ) 707 ext->alg = IW_ENCODE_ALG_WEP; 708 else if (strcmp(crypt->ops->name, "TKIP")) 709 ext->alg = IW_ENCODE_ALG_TKIP; 710 else if (strcmp(crypt->ops->name, "CCMP")) 711 ext->alg = IW_ENCODE_ALG_CCMP; 712 else 713 return -EINVAL; 714 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv); 715 encoding->flags |= IW_ENCODE_ENABLED; 716 if (ext->key_len && 717 (ext->alg == IW_ENCODE_ALG_TKIP || 718 ext->alg == IW_ENCODE_ALG_CCMP)) 719 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; 720 } 721 722 return 0; 723 } 724 EXPORT_SYMBOL(ieee80211_wx_get_encode_ext); 725 726 int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, 727 struct iw_request_info *info, 728 union iwreq_data *wrqu, char *extra) 729 { 730 struct iw_mlme *mlme = (struct iw_mlme *) extra; 731 switch (mlme->cmd) { 732 case IW_MLME_DEAUTH: 733 case IW_MLME_DISASSOC: 734 ieee80211_disassociate(ieee); 735 break; 736 default: 737 return -EOPNOTSUPP; 738 } 739 return 0; 740 } 741 EXPORT_SYMBOL(ieee80211_wx_set_mlme); 742 743 int ieee80211_wx_set_auth(struct ieee80211_device *ieee, 744 struct iw_request_info *info, 745 struct iw_param *data, char *extra) 746 { 747 switch (data->flags & IW_AUTH_INDEX) { 748 case IW_AUTH_WPA_VERSION: 749 /*need to support wpa2 here*/ 750 break; 751 case IW_AUTH_CIPHER_PAIRWISE: 752 case IW_AUTH_CIPHER_GROUP: 753 case IW_AUTH_KEY_MGMT: 754 /* 755 * * Host AP driver does not use these parameters and allows 756 * * wpa_supplicant to control them internally. 757 * */ 758 break; 759 case IW_AUTH_TKIP_COUNTERMEASURES: 760 ieee->tkip_countermeasures = data->value; 761 break; 762 case IW_AUTH_DROP_UNENCRYPTED: 763 ieee->drop_unencrypted = data->value; 764 break; 765 766 case IW_AUTH_80211_AUTH_ALG: 767 //printk("======>%s():data->value is %d\n",__func__,data->value); 768 // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0; 769 if(data->value & IW_AUTH_ALG_SHARED_KEY){ 770 ieee->open_wep = 0; 771 ieee->auth_mode = 1; 772 } 773 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){ 774 ieee->open_wep = 1; 775 ieee->auth_mode = 0; 776 } 777 else if(data->value & IW_AUTH_ALG_LEAP){ 778 ieee->open_wep = 1; 779 ieee->auth_mode = 2; 780 } 781 else 782 return -EINVAL; 783 break; 784 785 case IW_AUTH_WPA_ENABLED: 786 ieee->wpa_enabled = (data->value)?1:0; 787 break; 788 789 case IW_AUTH_RX_UNENCRYPTED_EAPOL: 790 ieee->ieee802_1x = data->value; 791 break; 792 case IW_AUTH_PRIVACY_INVOKED: 793 ieee->privacy_invoked = data->value; 794 break; 795 default: 796 return -EOPNOTSUPP; 797 } 798 return 0; 799 } 800 EXPORT_SYMBOL(ieee80211_wx_set_auth); 801 802 int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len) 803 { 804 u8 *buf; 805 806 if (len>MAX_WPA_IE_LEN || (len && ie == NULL)) 807 { 808 // printk("return error out, len:%d\n", len); 809 return -EINVAL; 810 } 811 812 813 if (len) 814 { 815 if (len != ie[1]+2) 816 { 817 printk("len:%zu, ie:%d\n", len, ie[1]); 818 return -EINVAL; 819 } 820 buf = kmemdup(ie, len, GFP_KERNEL); 821 if (buf == NULL) 822 return -ENOMEM; 823 kfree(ieee->wpa_ie); 824 ieee->wpa_ie = buf; 825 ieee->wpa_ie_len = len; 826 } 827 else{ 828 kfree(ieee->wpa_ie); 829 ieee->wpa_ie = NULL; 830 ieee->wpa_ie_len = 0; 831 } 832 return 0; 833 } 834 EXPORT_SYMBOL(ieee80211_wx_set_gen_ie); 835