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 = ieee80211_get_crypto_ops("WEP"); 368 if (!new_crypt->ops) { 369 request_module("ieee80211_crypt_wep"); 370 new_crypt->ops = ieee80211_get_crypto_ops("WEP"); 371 } 372 if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) 373 new_crypt->priv = new_crypt->ops->init(key); 374 375 if (!new_crypt->ops || !new_crypt->priv) { 376 kfree(new_crypt); 377 new_crypt = NULL; 378 379 printk(KERN_WARNING "%s: could not initialize WEP: " 380 "load module ieee80211_crypt_wep\n", 381 dev->name); 382 return -EOPNOTSUPP; 383 } 384 *crypt = new_crypt; 385 } 386 387 /* If a new key was provided, set it up */ 388 if (erq->length > 0) { 389 len = erq->length <= 5 ? 5 : 13; 390 memcpy(sec.keys[key], keybuf, erq->length); 391 if (len > erq->length) 392 memset(sec.keys[key] + erq->length, 0, 393 len - erq->length); 394 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", 395 key, escape_essid(sec.keys[key], len), 396 erq->length, len); 397 sec.key_sizes[key] = len; 398 (*crypt)->ops->set_key(sec.keys[key], len, NULL, 399 (*crypt)->priv); 400 sec.flags |= (1 << key); 401 /* This ensures a key will be activated if no key is 402 * explicitely set */ 403 if (key == sec.active_key) 404 sec.flags |= SEC_ACTIVE_KEY; 405 ieee->tx_keyidx = key; 406 407 } else { 408 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, 409 NULL, (*crypt)->priv); 410 if (len == 0) { 411 /* Set a default key of all 0 */ 412 printk("Setting key %d to all zero.\n", 413 key); 414 415 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", 416 key); 417 memset(sec.keys[key], 0, 13); 418 (*crypt)->ops->set_key(sec.keys[key], 13, NULL, 419 (*crypt)->priv); 420 sec.key_sizes[key] = 13; 421 sec.flags |= (1 << key); 422 } 423 424 /* No key data - just set the default TX key index */ 425 if (key_provided) { 426 IEEE80211_DEBUG_WX( 427 "Setting key %d to default Tx key.\n", key); 428 ieee->tx_keyidx = key; 429 sec.active_key = key; 430 sec.flags |= SEC_ACTIVE_KEY; 431 } 432 } 433 434 done: 435 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); 436 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; 437 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; 438 sec.flags |= SEC_AUTH_MODE; 439 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? 440 "OPEN" : "SHARED KEY"); 441 442 /* For now we just support WEP, so only set that security level... 443 * TODO: When WPA is added this is one place that needs to change */ 444 sec.flags |= SEC_LEVEL; 445 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ 446 447 if (ieee->set_security) 448 ieee->set_security(dev, &sec); 449 450 /* Do not reset port if card is in Managed mode since resetting will 451 * generate new IEEE 802.11 authentication which may end up in looping 452 * with IEEE 802.1X. If your hardware requires a reset after WEP 453 * configuration (for example... Prism2), implement the reset_port in 454 * the callbacks structures used to initialize the 802.11 stack. */ 455 if (ieee->reset_on_keychange && 456 ieee->iw_mode != IW_MODE_INFRA && 457 ieee->reset_port && ieee->reset_port(dev)) { 458 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); 459 return -EINVAL; 460 } 461 return 0; 462 } 463 EXPORT_SYMBOL(ieee80211_wx_set_encode); 464 465 int ieee80211_wx_get_encode(struct ieee80211_device *ieee, 466 struct iw_request_info *info, 467 union iwreq_data *wrqu, char *keybuf) 468 { 469 struct iw_point *erq = &(wrqu->encoding); 470 int len, key; 471 struct ieee80211_crypt_data *crypt; 472 473 IEEE80211_DEBUG_WX("GET_ENCODE\n"); 474 475 if(ieee->iw_mode == IW_MODE_MONITOR) 476 return -1; 477 478 key = erq->flags & IW_ENCODE_INDEX; 479 if (key) { 480 if (key > WEP_KEYS) 481 return -EINVAL; 482 key--; 483 } else 484 key = ieee->tx_keyidx; 485 486 crypt = ieee->crypt[key]; 487 erq->flags = key + 1; 488 489 if (crypt == NULL || crypt->ops == NULL) { 490 erq->length = 0; 491 erq->flags |= IW_ENCODE_DISABLED; 492 return 0; 493 } 494 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv); 495 erq->length = (len >= 0 ? len : 0); 496 497 erq->flags |= IW_ENCODE_ENABLED; 498 499 if (ieee->open_wep) 500 erq->flags |= IW_ENCODE_OPEN; 501 else 502 erq->flags |= IW_ENCODE_RESTRICTED; 503 504 return 0; 505 } 506 EXPORT_SYMBOL(ieee80211_wx_get_encode); 507 508 int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, 509 struct iw_request_info *info, 510 union iwreq_data *wrqu, char *extra) 511 { 512 int ret = 0; 513 struct net_device *dev = ieee->dev; 514 struct iw_point *encoding = &wrqu->encoding; 515 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 516 int i, idx; 517 int group_key = 0; 518 const char *alg, *module; 519 struct ieee80211_crypto_ops *ops; 520 struct ieee80211_crypt_data **crypt; 521 522 struct ieee80211_security sec = { 523 .flags = 0, 524 }; 525 idx = encoding->flags & IW_ENCODE_INDEX; 526 if (idx) { 527 if (idx < 1 || idx > WEP_KEYS) 528 return -EINVAL; 529 idx--; 530 } else 531 idx = ieee->tx_keyidx; 532 533 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { 534 535 crypt = &ieee->crypt[idx]; 536 537 group_key = 1; 538 } else { 539 /* some Cisco APs use idx>0 for unicast in dynamic WEP */ 540 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) 541 return -EINVAL; 542 if (ieee->iw_mode == IW_MODE_INFRA) 543 544 crypt = &ieee->crypt[idx]; 545 546 else 547 return -EINVAL; 548 } 549 550 sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT; 551 if ((encoding->flags & IW_ENCODE_DISABLED) || 552 ext->alg == IW_ENCODE_ALG_NONE) { 553 if (*crypt) 554 ieee80211_crypt_delayed_deinit(ieee, crypt); 555 556 for (i = 0; i < WEP_KEYS; i++) 557 558 if (ieee->crypt[i] != NULL) 559 560 break; 561 562 if (i == WEP_KEYS) { 563 sec.enabled = 0; 564 // sec.encrypt = 0; 565 sec.level = SEC_LEVEL_0; 566 sec.flags |= SEC_LEVEL; 567 } 568 goto done; 569 } 570 571 sec.enabled = 1; 572 // sec.encrypt = 1; 573 switch (ext->alg) { 574 case IW_ENCODE_ALG_WEP: 575 alg = "WEP"; 576 module = "ieee80211_crypt_wep"; 577 break; 578 case IW_ENCODE_ALG_TKIP: 579 alg = "TKIP"; 580 module = "ieee80211_crypt_tkip"; 581 break; 582 case IW_ENCODE_ALG_CCMP: 583 alg = "CCMP"; 584 module = "ieee80211_crypt_ccmp"; 585 break; 586 default: 587 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", 588 dev->name, ext->alg); 589 ret = -EINVAL; 590 goto done; 591 } 592 printk("alg name:%s\n",alg); 593 594 ops = ieee80211_get_crypto_ops(alg); 595 if (ops == NULL) { 596 request_module(module); 597 ops = ieee80211_get_crypto_ops(alg); 598 } 599 if (ops == NULL) { 600 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", 601 dev->name, ext->alg); 602 printk("========>unknown crypto alg %d\n", ext->alg); 603 ret = -EINVAL; 604 goto done; 605 } 606 607 if (*crypt == NULL || (*crypt)->ops != ops) { 608 struct ieee80211_crypt_data *new_crypt; 609 610 ieee80211_crypt_delayed_deinit(ieee, crypt); 611 612 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); 613 if (!new_crypt) { 614 ret = -ENOMEM; 615 goto done; 616 } 617 new_crypt->ops = ops; 618 if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) 619 new_crypt->priv = new_crypt->ops->init(idx); 620 if (new_crypt->priv == NULL) { 621 kfree(new_crypt); 622 ret = -EINVAL; 623 goto done; 624 } 625 *crypt = new_crypt; 626 } 627 628 if (ext->key_len > 0 && (*crypt)->ops->set_key && 629 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, 630 (*crypt)->priv) < 0) { 631 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); 632 printk("key setting failed\n"); 633 ret = -EINVAL; 634 goto done; 635 } 636 //skip_host_crypt: 637 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { 638 ieee->tx_keyidx = idx; 639 sec.active_key = idx; 640 sec.flags |= SEC_ACTIVE_KEY; 641 } 642 643 if (ext->alg != IW_ENCODE_ALG_NONE) { 644 //memcpy(sec.keys[idx], ext->key, ext->key_len); 645 sec.key_sizes[idx] = ext->key_len; 646 sec.flags |= (1 << idx); 647 if (ext->alg == IW_ENCODE_ALG_WEP) { 648 // sec.encode_alg[idx] = SEC_ALG_WEP; 649 sec.flags |= SEC_LEVEL; 650 sec.level = SEC_LEVEL_1; 651 } else if (ext->alg == IW_ENCODE_ALG_TKIP) { 652 // sec.encode_alg[idx] = SEC_ALG_TKIP; 653 sec.flags |= SEC_LEVEL; 654 sec.level = SEC_LEVEL_2; 655 } else if (ext->alg == IW_ENCODE_ALG_CCMP) { 656 // sec.encode_alg[idx] = SEC_ALG_CCMP; 657 sec.flags |= SEC_LEVEL; 658 sec.level = SEC_LEVEL_3; 659 } 660 /* Don't set sec level for group keys. */ 661 if (group_key) 662 sec.flags &= ~SEC_LEVEL; 663 } 664 done: 665 if (ieee->set_security) 666 ieee->set_security(ieee->dev, &sec); 667 668 if (ieee->reset_on_keychange && 669 ieee->iw_mode != IW_MODE_INFRA && 670 ieee->reset_port && ieee->reset_port(dev)) { 671 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); 672 return -EINVAL; 673 } 674 return ret; 675 } 676 EXPORT_SYMBOL(ieee80211_wx_set_encode_ext); 677 678 int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee, 679 struct iw_request_info *info, 680 union iwreq_data *wrqu, char *extra) 681 { 682 struct iw_point *encoding = &wrqu->encoding; 683 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; 684 struct ieee80211_crypt_data *crypt; 685 int idx, max_key_len; 686 687 max_key_len = encoding->length - sizeof(*ext); 688 if (max_key_len < 0) 689 return -EINVAL; 690 691 idx = encoding->flags & IW_ENCODE_INDEX; 692 if (idx) { 693 if (idx < 1 || idx > WEP_KEYS) 694 return -EINVAL; 695 idx--; 696 } else 697 idx = ieee->tx_keyidx; 698 699 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && 700 ext->alg != IW_ENCODE_ALG_WEP) 701 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA) 702 return -EINVAL; 703 704 crypt = ieee->crypt[idx]; 705 encoding->flags = idx + 1; 706 memset(ext, 0, sizeof(*ext)); 707 708 if (crypt == NULL || crypt->ops == NULL ) { 709 ext->alg = IW_ENCODE_ALG_NONE; 710 ext->key_len = 0; 711 encoding->flags |= IW_ENCODE_DISABLED; 712 } else { 713 if (strcmp(crypt->ops->name, "WEP") == 0 ) 714 ext->alg = IW_ENCODE_ALG_WEP; 715 else if (strcmp(crypt->ops->name, "TKIP")) 716 ext->alg = IW_ENCODE_ALG_TKIP; 717 else if (strcmp(crypt->ops->name, "CCMP")) 718 ext->alg = IW_ENCODE_ALG_CCMP; 719 else 720 return -EINVAL; 721 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv); 722 encoding->flags |= IW_ENCODE_ENABLED; 723 if (ext->key_len && 724 (ext->alg == IW_ENCODE_ALG_TKIP || 725 ext->alg == IW_ENCODE_ALG_CCMP)) 726 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; 727 } 728 729 return 0; 730 } 731 EXPORT_SYMBOL(ieee80211_wx_get_encode_ext); 732 733 int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, 734 struct iw_request_info *info, 735 union iwreq_data *wrqu, char *extra) 736 { 737 struct iw_mlme *mlme = (struct iw_mlme *) extra; 738 switch (mlme->cmd) { 739 case IW_MLME_DEAUTH: 740 case IW_MLME_DISASSOC: 741 ieee80211_disassociate(ieee); 742 break; 743 default: 744 return -EOPNOTSUPP; 745 } 746 return 0; 747 } 748 EXPORT_SYMBOL(ieee80211_wx_set_mlme); 749 750 int ieee80211_wx_set_auth(struct ieee80211_device *ieee, 751 struct iw_request_info *info, 752 struct iw_param *data, char *extra) 753 { 754 switch (data->flags & IW_AUTH_INDEX) { 755 case IW_AUTH_WPA_VERSION: 756 /*need to support wpa2 here*/ 757 break; 758 case IW_AUTH_CIPHER_PAIRWISE: 759 case IW_AUTH_CIPHER_GROUP: 760 case IW_AUTH_KEY_MGMT: 761 /* 762 * * Host AP driver does not use these parameters and allows 763 * * wpa_supplicant to control them internally. 764 * */ 765 break; 766 case IW_AUTH_TKIP_COUNTERMEASURES: 767 ieee->tkip_countermeasures = data->value; 768 break; 769 case IW_AUTH_DROP_UNENCRYPTED: 770 ieee->drop_unencrypted = data->value; 771 break; 772 773 case IW_AUTH_80211_AUTH_ALG: 774 //printk("======>%s():data->value is %d\n",__func__,data->value); 775 // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0; 776 if(data->value & IW_AUTH_ALG_SHARED_KEY){ 777 ieee->open_wep = 0; 778 ieee->auth_mode = 1; 779 } 780 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){ 781 ieee->open_wep = 1; 782 ieee->auth_mode = 0; 783 } 784 else if(data->value & IW_AUTH_ALG_LEAP){ 785 ieee->open_wep = 1; 786 ieee->auth_mode = 2; 787 } 788 else 789 return -EINVAL; 790 break; 791 792 case IW_AUTH_WPA_ENABLED: 793 ieee->wpa_enabled = (data->value)?1:0; 794 break; 795 796 case IW_AUTH_RX_UNENCRYPTED_EAPOL: 797 ieee->ieee802_1x = data->value; 798 break; 799 case IW_AUTH_PRIVACY_INVOKED: 800 ieee->privacy_invoked = data->value; 801 break; 802 default: 803 return -EOPNOTSUPP; 804 } 805 return 0; 806 } 807 EXPORT_SYMBOL(ieee80211_wx_set_auth); 808 809 int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len) 810 { 811 u8 *buf; 812 813 if (len>MAX_WPA_IE_LEN || (len && ie == NULL)) 814 { 815 // printk("return error out, len:%d\n", len); 816 return -EINVAL; 817 } 818 819 820 if (len) 821 { 822 if (len != ie[1]+2) 823 { 824 printk("len:%zu, ie:%d\n", len, ie[1]); 825 return -EINVAL; 826 } 827 buf = kmemdup(ie, len, GFP_KERNEL); 828 if (buf == NULL) 829 return -ENOMEM; 830 kfree(ieee->wpa_ie); 831 ieee->wpa_ie = buf; 832 ieee->wpa_ie_len = len; 833 } 834 else{ 835 kfree(ieee->wpa_ie); 836 ieee->wpa_ie = NULL; 837 ieee->wpa_ie_len = 0; 838 } 839 return 0; 840 } 841 EXPORT_SYMBOL(ieee80211_wx_set_gen_ie); 842