1 /* 2 * Linux Wireless Extensions support 3 * 4 * Copyright (C) 1999-2010, Broadcom Corporation 5 * 6 * Unless you and Broadcom execute a separate written software license 7 * agreement governing use of this software, this software is licensed to you 8 * under the terms of the GNU General Public License version 2 (the "GPL"), 9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the 10 * following added to such license: 11 * 12 * As a special exception, the copyright holders of this software give you 13 * permission to link this software with independent modules, and to copy and 14 * distribute the resulting executable under terms of your choice, provided that 15 * you also meet, for each linked independent module, the terms and conditions of 16 * the license of that module. An independent module is a module which is not 17 * derived from this software. The special exception does not apply to any 18 * modifications of the software. 19 * 20 * Notwithstanding the above, under no circumstances may you combine this 21 * software in any way with any other Broadcom software provided under a license 22 * other than the GPL, without Broadcom's express prior written consent. 23 * 24 * $Id: wl_iw.c,v 1.51.4.9.2.6.4.142.4.13 2010/09/15 03:34:56 Exp $ 25 */ 26 27 28 #include <typedefs.h> 29 #include <linuxver.h> 30 #include <osl.h> 31 32 #include <bcmutils.h> 33 #include <bcmendian.h> 34 #include <proto/ethernet.h> 35 36 #include <linux/if_arp.h> 37 #include <asm/uaccess.h> 38 39 #include <dngl_stats.h> 40 #include <dhd.h> 41 #include <dhdioctl.h> 42 43 typedef void wlc_info_t; 44 typedef void wl_info_t; 45 typedef const struct si_pub si_t; 46 #include <wlioctl.h> 47 48 #include <proto/ethernet.h> 49 #include <dngl_stats.h> 50 #include <dhd.h> 51 #define WL_ERROR(x) printf x 52 #define WL_TRACE(x) 53 #define WL_ASSOC(x) 54 #define WL_INFORM(x) 55 #define WL_WSEC(x) 56 #define WL_SCAN(x) 57 58 #include <wl_iw.h> 59 60 61 62 #ifndef IW_ENCODE_ALG_SM4 63 #define IW_ENCODE_ALG_SM4 0x20 64 #endif 65 66 #ifndef IW_AUTH_WAPI_ENABLED 67 #define IW_AUTH_WAPI_ENABLED 0x20 68 #endif 69 70 #ifndef IW_AUTH_WAPI_VERSION_1 71 #define IW_AUTH_WAPI_VERSION_1 0x00000008 72 #endif 73 74 #ifndef IW_AUTH_CIPHER_SMS4 75 #define IW_AUTH_CIPHER_SMS4 0x00000020 76 #endif 77 78 #ifndef IW_AUTH_KEY_MGMT_WAPI_PSK 79 #define IW_AUTH_KEY_MGMT_WAPI_PSK 4 80 #endif 81 82 #ifndef IW_AUTH_KEY_MGMT_WAPI_CERT 83 #define IW_AUTH_KEY_MGMT_WAPI_CERT 8 84 #endif 85 86 87 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) 88 89 #include <linux/rtnetlink.h> 90 #include <linux/mutex.h> 91 92 #define WL_IW_USE_ISCAN 1 93 #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1 94 95 #if defined(SOFTAP) 96 #define WL_SOFTAP(x) printk x 97 static struct net_device *priv_dev; 98 static bool ap_cfg_running = FALSE; 99 static bool ap_fw_loaded = FALSE; 100 struct net_device *ap_net_dev = NULL; 101 struct semaphore ap_eth_sema; 102 static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap); 103 static int wl_iw_softap_deassoc_stations(struct net_device *dev); 104 #endif 105 106 #define WL_IW_IOCTL_CALL(func_call) \ 107 do { \ 108 func_call; \ 109 } while (0) 110 111 static int g_onoff = G_WLAN_SET_ON; 112 wl_iw_extra_params_t g_wl_iw_params; 113 static struct mutex wl_start_lock; 114 static struct mutex wl_cache_lock; 115 116 extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, 117 uint32 reason, char* stringBuf, uint buflen); 118 #include <bcmsdbus.h> 119 extern void dhd_customer_gpio_wlan_ctrl(int onoff); 120 extern uint dhd_dev_reset(struct net_device *dev, uint8 flag); 121 extern void dhd_dev_init_ioctl(struct net_device *dev); 122 int dev_iw_write_cfg1_bss_var(struct net_device *dev, int val); 123 124 uint wl_msg_level = WL_ERROR_VAL; 125 126 #define MAX_WLIW_IOCTL_LEN 1024 127 128 129 #if defined(IL_BIGENDIAN) 130 #include <bcmendian.h> 131 #define htod32(i) (bcmswap32(i)) 132 #define htod16(i) (bcmswap16(i)) 133 #define dtoh32(i) (bcmswap32(i)) 134 #define dtoh16(i) (bcmswap16(i)) 135 #define htodchanspec(i) htod16(i) 136 #define dtohchanspec(i) dtoh16(i) 137 #else 138 #define htod32(i) i 139 #define htod16(i) i 140 #define dtoh32(i) i 141 #define dtoh16(i) i 142 #define htodchanspec(i) i 143 #define dtohchanspec(i) i 144 #endif 145 146 #ifdef CONFIG_WIRELESS_EXT 147 148 extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); 149 extern int dhd_wait_pend8021x(struct net_device *dev); 150 #endif 151 152 #if WIRELESS_EXT < 19 153 #define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) 154 #define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) 155 #endif 156 157 static void *g_scan = NULL; 158 static volatile uint g_scan_specified_ssid; 159 static wlc_ssid_t g_specific_ssid; 160 161 static wlc_ssid_t g_ssid; 162 163 static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; 164 static volatile uint g_first_broadcast_scan; 165 static volatile uint g_first_counter_scans; 166 #define MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN 3 167 168 169 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) 170 #define DAEMONIZE(a) daemonize(a); \ 171 allow_signal(SIGKILL); \ 172 allow_signal(SIGTERM); 173 #else 174 #define RAISE_RX_SOFTIRQ() \ 175 cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) 176 #define DAEMONIZE(a) daemonize(); \ 177 do { if (a) \ 178 strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ 179 } while (0); 180 #endif 181 182 #if defined(WL_IW_USE_ISCAN) 183 #if !defined(CSCAN) 184 static void wl_iw_free_ss_cache(void); 185 static int wl_iw_run_ss_cache_timer(int kick_off); 186 #endif 187 int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); 188 static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len); 189 #define ISCAN_STATE_IDLE 0 190 #define ISCAN_STATE_SCANING 1 191 192 #define WLC_IW_ISCAN_MAXLEN 2048 193 typedef struct iscan_buf { 194 struct iscan_buf * next; 195 char iscan_buf[WLC_IW_ISCAN_MAXLEN]; 196 } iscan_buf_t; 197 198 typedef struct iscan_info { 199 struct net_device *dev; 200 struct timer_list timer; 201 uint32 timer_ms; 202 uint32 timer_on; 203 int iscan_state; 204 iscan_buf_t * list_hdr; 205 iscan_buf_t * list_cur; 206 207 208 long sysioc_pid; 209 struct semaphore sysioc_sem; 210 struct completion sysioc_exited; 211 212 uint32 scan_flag; 213 #if defined CSCAN 214 char ioctlbuf[WLC_IOCTL_MEDLEN]; 215 #else 216 char ioctlbuf[WLC_IOCTL_SMLEN]; 217 #endif 218 wl_iscan_params_t *iscan_ex_params_p; 219 int iscan_ex_param_size; 220 } iscan_info_t; 221 #define COEX_DHCP 1 222 static void wl_iw_bt_flag_set(struct net_device *dev, bool set); 223 static void wl_iw_bt_release(void); 224 225 typedef enum bt_coex_status { 226 BT_DHCP_IDLE = 0, 227 BT_DHCP_START, 228 BT_DHCP_OPPORTUNITY_WINDOW, 229 BT_DHCP_FLAG_FORCE_TIMEOUT 230 } coex_status_t; 231 #define BT_DHCP_OPPORTUNITY_WINDOW_TIEM 2500 232 #define BT_DHCP_FLAG_FORCE_TIME 5500 233 234 typedef struct bt_info { 235 struct net_device *dev; 236 struct timer_list timer; 237 uint32 timer_ms; 238 uint32 timer_on; 239 int bt_state; 240 241 242 long bt_pid; 243 struct semaphore bt_sem; 244 struct completion bt_exited; 245 } bt_info_t; 246 247 bt_info_t *g_bt = NULL; 248 static void wl_iw_bt_timerfunc(ulong data); 249 iscan_info_t *g_iscan = NULL; 250 static void wl_iw_timerfunc(ulong data); 251 static void wl_iw_set_event_mask(struct net_device *dev); 252 static int 253 wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action); 254 #endif 255 static int 256 wl_iw_set_scan( 257 struct net_device *dev, 258 struct iw_request_info *info, 259 union iwreq_data *wrqu, 260 char *extra 261 ); 262 263 #ifndef CSCAN 264 static int 265 wl_iw_get_scan( 266 struct net_device *dev, 267 struct iw_request_info *info, 268 struct iw_point *dwrq, 269 char *extra 270 ); 271 272 static uint 273 wl_iw_get_scan_prep( 274 wl_scan_results_t *list, 275 struct iw_request_info *info, 276 char *extra, 277 short max_size 278 ); 279 #endif 280 281 static void swap_key_from_BE( 282 wl_wsec_key_t *key 283 ) 284 { 285 key->index = htod32(key->index); 286 key->len = htod32(key->len); 287 key->algo = htod32(key->algo); 288 key->flags = htod32(key->flags); 289 key->rxiv.hi = htod32(key->rxiv.hi); 290 key->rxiv.lo = htod16(key->rxiv.lo); 291 key->iv_initialized = htod32(key->iv_initialized); 292 } 293 294 static void swap_key_to_BE( 295 wl_wsec_key_t *key 296 ) 297 { 298 key->index = dtoh32(key->index); 299 key->len = dtoh32(key->len); 300 key->algo = dtoh32(key->algo); 301 key->flags = dtoh32(key->flags); 302 key->rxiv.hi = dtoh32(key->rxiv.hi); 303 key->rxiv.lo = dtoh16(key->rxiv.lo); 304 key->iv_initialized = dtoh32(key->iv_initialized); 305 } 306 307 static int 308 dev_wlc_ioctl( 309 struct net_device *dev, 310 int cmd, 311 void *arg, 312 int len 313 ) 314 { 315 struct ifreq ifr; 316 wl_ioctl_t ioc; 317 mm_segment_t fs; 318 int ret = -EINVAL; 319 320 if (!dev) { 321 WL_ERROR(("%s: dev is null\n", __FUNCTION__)); 322 return ret; 323 } 324 325 net_os_wake_lock(dev); 326 327 WL_INFORM(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n", 328 __FUNCTION__, current->pid, cmd, arg, len)); 329 330 if (g_onoff == G_WLAN_SET_ON) { 331 memset(&ioc, 0, sizeof(ioc)); 332 ioc.cmd = cmd; 333 ioc.buf = arg; 334 ioc.len = len; 335 336 strcpy(ifr.ifr_name, dev->name); 337 ifr.ifr_data = (caddr_t) &ioc; 338 339 ret = dev_open(dev); 340 if (ret) { 341 WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret)); 342 net_os_wake_unlock(dev); 343 return ret; 344 } 345 346 fs = get_fs(); 347 set_fs(get_ds()); 348 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) 349 ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); 350 #else 351 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); 352 #endif 353 set_fs(fs); 354 } 355 else { 356 WL_TRACE(("%s: call after driver stop : ignored\n", __FUNCTION__)); 357 } 358 359 net_os_wake_unlock(dev); 360 361 return ret; 362 } 363 364 365 static int 366 dev_wlc_intvar_get_reg( 367 struct net_device *dev, 368 char *name, 369 uint reg, 370 int *retval) 371 { 372 union { 373 char buf[WLC_IOCTL_SMLEN]; 374 int val; 375 } var; 376 int error; 377 378 uint len; 379 len = bcm_mkiovar(name, (char *)(®), sizeof(reg), (char *)(&var), sizeof(var.buf)); 380 ASSERT(len); 381 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len); 382 383 *retval = dtoh32(var.val); 384 return (error); 385 } 386 387 388 static int 389 dev_wlc_intvar_set_reg( 390 struct net_device *dev, 391 char *name, 392 char *addr, 393 char * val) 394 { 395 char reg_addr[8]; 396 397 memset(reg_addr, 0, sizeof(reg_addr)); 398 memcpy((char *)®_addr[0], (char *)addr, 4); 399 memcpy((char *)®_addr[4], (char *)val, 4); 400 401 return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); 402 } 403 404 405 static int 406 dev_wlc_intvar_set( 407 struct net_device *dev, 408 char *name, 409 int val) 410 { 411 char buf[WLC_IOCTL_SMLEN]; 412 uint len; 413 414 val = htod32(val); 415 len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); 416 ASSERT(len); 417 418 return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len)); 419 } 420 421 #if defined(WL_IW_USE_ISCAN) 422 static int 423 dev_iw_iovar_setbuf( 424 struct net_device *dev, 425 char *iovar, 426 void *param, 427 int paramlen, 428 void *bufptr, 429 int buflen) 430 { 431 int iolen; 432 433 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); 434 ASSERT(iolen); 435 436 if (iolen == 0) 437 return 0; 438 439 return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen)); 440 } 441 442 static int 443 dev_iw_iovar_getbuf( 444 struct net_device *dev, 445 char *iovar, 446 void *param, 447 int paramlen, 448 void *bufptr, 449 int buflen) 450 { 451 int iolen; 452 453 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); 454 ASSERT(iolen); 455 456 return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen)); 457 } 458 #endif 459 460 461 #if WIRELESS_EXT > 17 462 static int 463 dev_wlc_bufvar_set( 464 struct net_device *dev, 465 char *name, 466 char *buf, int len) 467 { 468 static char ioctlbuf[MAX_WLIW_IOCTL_LEN]; 469 uint buflen; 470 471 buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf)); 472 ASSERT(buflen); 473 474 return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen)); 475 } 476 #endif 477 478 479 static int 480 dev_wlc_bufvar_get( 481 struct net_device *dev, 482 char *name, 483 char *buf, int buflen) 484 { 485 static char ioctlbuf[MAX_WLIW_IOCTL_LEN]; 486 int error; 487 uint len; 488 489 len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf)); 490 ASSERT(len); 491 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN); 492 if (!error) 493 bcopy(ioctlbuf, buf, buflen); 494 495 return (error); 496 } 497 498 499 500 static int 501 dev_wlc_intvar_get( 502 struct net_device *dev, 503 char *name, 504 int *retval) 505 { 506 union { 507 char buf[WLC_IOCTL_SMLEN]; 508 int val; 509 } var; 510 int error; 511 512 uint len; 513 uint data_null; 514 515 len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf)); 516 ASSERT(len); 517 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len); 518 519 *retval = dtoh32(var.val); 520 521 return (error); 522 } 523 524 525 #if WIRELESS_EXT > 12 526 static int 527 wl_iw_set_active_scan( 528 struct net_device *dev, 529 struct iw_request_info *info, 530 union iwreq_data *wrqu, 531 char *extra 532 ) 533 { 534 int as = 0; 535 int error = 0; 536 char *p = extra; 537 538 #if defined(WL_IW_USE_ISCAN) 539 if (g_iscan->iscan_state == ISCAN_STATE_IDLE) 540 #endif 541 error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as)); 542 #if defined(WL_IW_USE_ISCAN) 543 else 544 g_iscan->scan_flag = as; 545 #endif 546 p += snprintf(p, MAX_WX_STRING, "OK"); 547 548 wrqu->data.length = p - extra + 1; 549 return error; 550 } 551 552 static int 553 wl_iw_set_passive_scan( 554 struct net_device *dev, 555 struct iw_request_info *info, 556 union iwreq_data *wrqu, 557 char *extra 558 ) 559 { 560 int ps = 1; 561 int error = 0; 562 char *p = extra; 563 564 #if defined(WL_IW_USE_ISCAN) 565 if (g_iscan->iscan_state == ISCAN_STATE_IDLE) { 566 #endif 567 568 569 if (g_scan_specified_ssid == 0) { 570 error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &ps, sizeof(ps)); 571 } 572 #if defined(WL_IW_USE_ISCAN) 573 } 574 else 575 g_iscan->scan_flag = ps; 576 #endif 577 578 p += snprintf(p, MAX_WX_STRING, "OK"); 579 580 wrqu->data.length = p - extra + 1; 581 return error; 582 } 583 584 static int 585 wl_iw_get_macaddr( 586 struct net_device *dev, 587 struct iw_request_info *info, 588 union iwreq_data *wrqu, 589 char *extra 590 ) 591 { 592 int error; 593 char buf[128]; 594 struct ether_addr *id; 595 char *p = extra; 596 597 598 strcpy(buf, "cur_etheraddr"); 599 error = dev_wlc_ioctl(dev, WLC_GET_VAR, buf, sizeof(buf)); 600 id = (struct ether_addr *) buf; 601 p += snprintf(p, MAX_WX_STRING, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", 602 id->octet[0], id->octet[1], id->octet[2], 603 id->octet[3], id->octet[4], id->octet[5]); 604 wrqu->data.length = p - extra + 1; 605 606 return error; 607 } 608 609 610 static int 611 wl_iw_set_country( 612 struct net_device *dev, 613 struct iw_request_info *info, 614 union iwreq_data *wrqu, 615 char *extra 616 ) 617 { 618 char country_code[WLC_CNTRY_BUF_SZ]; 619 int error = 0; 620 char *p = extra; 621 int country_offset; 622 int country_code_size; 623 624 WL_TRACE(("%s\n", __FUNCTION__)); 625 memset(country_code, 0, sizeof(country_code)); 626 627 country_offset = strcspn(extra, " "); 628 country_code_size = strlen(extra) - country_offset; 629 630 631 if (country_offset != 0) { 632 strncpy(country_code, extra + country_offset + 1, 633 MIN(country_code_size, sizeof(country_code))); 634 635 636 if ((error = dev_wlc_ioctl(dev, WLC_SET_COUNTRY, 637 &country_code, sizeof(country_code))) >= 0) { 638 p += snprintf(p, MAX_WX_STRING, "OK"); 639 WL_TRACE(("%s: set country %s OK\n", __FUNCTION__, country_code)); 640 goto exit; 641 } 642 } 643 644 WL_ERROR(("%s: set country %s failed code %d\n", __FUNCTION__, country_code, error)); 645 p += snprintf(p, MAX_WX_STRING, "FAIL"); 646 647 exit: 648 wrqu->data.length = p - extra + 1; 649 return error; 650 } 651 652 #ifdef CUSTOMER_HW2 653 static int 654 wl_iw_set_power_mode( 655 struct net_device *dev, 656 struct iw_request_info *info, 657 union iwreq_data *wrqu, 658 char *extra 659 ) 660 { 661 int error = 0; 662 char *p = extra; 663 static int pm = PM_FAST; 664 int pm_local = PM_OFF; 665 char powermode_val = 0; 666 667 strncpy((char *)&powermode_val, extra + strlen("POWERMODE") + 1, 1); 668 669 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { 670 671 WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__)); 672 673 dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm)); 674 dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); 675 676 /* Disable packet filtering if necessary */ 677 net_os_set_packet_filter(dev, 0); 678 679 } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) { 680 681 WL_TRACE(("%s: DHCP session done\n", __FUNCTION__)); 682 683 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); 684 685 /* Enable packet filtering if was turned off */ 686 net_os_set_packet_filter(dev, 1); 687 688 } else { 689 WL_ERROR(("Unkwown yet power setting, ignored\n")); 690 } 691 692 p += snprintf(p, MAX_WX_STRING, "OK"); 693 694 wrqu->data.length = p - extra + 1; 695 696 return error; 697 } 698 #endif 699 700 static int 701 wl_iw_get_power_mode( 702 struct net_device *dev, 703 struct iw_request_info *info, 704 union iwreq_data *wrqu, 705 char *extra 706 ) 707 { 708 int error; 709 char *p = extra; 710 int pm_local = PM_FAST; 711 712 error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm_local, sizeof(pm_local)); 713 if (!error) { 714 WL_TRACE(("%s: Powermode = %d\n", __func__, pm_local)); 715 if (pm_local == PM_OFF) 716 pm_local = 1; /* Active */ 717 else 718 pm_local = 0; /* Auto */ 719 p += snprintf(p, MAX_WX_STRING, "powermode = %d", pm_local); 720 } 721 else { 722 WL_TRACE(("%s: Error = %d\n", __func__, error)); 723 p += snprintf(p, MAX_WX_STRING, "FAIL"); 724 } 725 wrqu->data.length = p - extra + 1; 726 return error; 727 } 728 729 static int 730 wl_iw_set_btcoex_dhcp( 731 struct net_device *dev, 732 struct iw_request_info *info, 733 union iwreq_data *wrqu, 734 char *extra 735 ) 736 { 737 int error = 0; 738 char *p = extra; 739 #ifndef CUSTOMER_HW2 740 static int pm = PM_FAST; 741 int pm_local = PM_OFF; 742 #endif 743 char powermode_val = 0; 744 char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; 745 char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; 746 char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; 747 748 uint32 regaddr; 749 static uint32 saved_reg66; 750 static uint32 saved_reg41; 751 static uint32 saved_reg68; 752 static bool saved_status = FALSE; 753 754 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; 755 #ifndef CUSTOMER_HW2 756 uint32 temp1, temp2; 757 #endif 758 759 #ifdef CUSTOMER_HW2 760 strncpy((char *)&powermode_val, extra + strlen("BTCOEXMODE") + 1, 1); 761 #else 762 strncpy((char *)&powermode_val, extra + strlen("POWERMODE") + 1, 1); 763 #endif 764 765 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { 766 767 WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__)); 768 769 if ((saved_status == FALSE) && 770 #ifndef CUSTOMER_HW2 771 (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) && 772 #endif 773 (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && 774 (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && 775 (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { 776 saved_status = TRUE; 777 WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", \ 778 saved_reg66, saved_reg41, saved_reg68)); 779 780 #ifndef CUSTOMER_HW2 781 dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); 782 #endif 783 784 dev_wlc_bufvar_set(dev, "btc_params", \ 785 (char *)&buf_reg66va_dhcp_on[0], sizeof(buf_reg66va_dhcp_on)); 786 dev_wlc_bufvar_set(dev, "btc_params", \ 787 (char *)&buf_reg41va_dhcp_on[0], sizeof(buf_reg41va_dhcp_on)); 788 dev_wlc_bufvar_set(dev, "btc_params", \ 789 (char *)&buf_reg68va_dhcp_on[0], sizeof(buf_reg68va_dhcp_on)); 790 #ifndef CUSTOMER_HW2 791 if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 12, &temp1)) && 792 (!dev_wlc_intvar_get_reg(dev, "btc_params", 13, &temp2))) 793 { 794 if ((temp1 != 0) && (temp2 != 0)) { 795 #endif 796 g_bt->bt_state = BT_DHCP_START; 797 g_bt->timer_on = 1; 798 mod_timer(&g_bt->timer, g_bt->timer.expires); 799 WL_TRACE(("%s enable BT DHCP Timer\n", \ 800 __FUNCTION__)); 801 #ifndef CUSTOMER_HW2 802 } 803 } 804 #endif 805 } 806 else if (saved_status == TRUE) { 807 WL_ERROR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__)); 808 } 809 } 810 #ifdef CUSTOMER_HW2 811 else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { 812 #else 813 else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) { 814 #endif 815 WL_TRACE(("%s: DHCP session done\n", __FUNCTION__)); 816 817 #ifndef CUSTOMER_HW2 818 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); 819 #endif 820 821 WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__)); 822 if (g_bt->timer_on) { 823 g_bt->timer_on = 0; 824 del_timer_sync(&g_bt->timer); 825 } 826 827 dev_wlc_bufvar_set(dev, "btc_flags", \ 828 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); 829 830 if (saved_status) { 831 regaddr = 66; 832 dev_wlc_intvar_set_reg(dev, "btc_params", \ 833 (char *)®addr, (char *)&saved_reg66); 834 regaddr = 41; 835 dev_wlc_intvar_set_reg(dev, "btc_params", \ 836 (char *)®addr, (char *)&saved_reg41); 837 regaddr = 68; 838 dev_wlc_intvar_set_reg(dev, "btc_params", \ 839 (char *)®addr, (char *)&saved_reg68); 840 } 841 saved_status = FALSE; 842 } 843 else { 844 WL_ERROR(("Unkwown yet power setting, ignored\n")); 845 } 846 847 p += snprintf(p, MAX_WX_STRING, "OK"); 848 849 wrqu->data.length = p - extra + 1; 850 851 return error; 852 } 853 854 static int 855 wl_iw_set_suspend( 856 struct net_device *dev, 857 struct iw_request_info *info, 858 union iwreq_data *wrqu, 859 char *extra 860 ) 861 { 862 int suspend_flag; 863 int ret_now; 864 int ret = 0; 865 866 suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0'; 867 868 if (suspend_flag != 0) 869 suspend_flag = 1; 870 871 ret_now = net_os_set_suspend_disable(dev, suspend_flag); 872 873 if (ret_now != suspend_flag) { 874 if (!(ret = net_os_set_suspend(dev, ret_now))) 875 WL_ERROR(("%s: Suspend Flag %d -> %d\n", \ 876 __FUNCTION__, ret_now, suspend_flag)); 877 else 878 WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); 879 } 880 881 return ret; 882 } 883 884 int 885 wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len) 886 { 887 int i, c; 888 char *p = ssid_buf; 889 890 if (ssid_len > 32) ssid_len = 32; 891 892 for (i = 0; i < ssid_len; i++) { 893 c = (int)ssid[i]; 894 if (c == '\\') { 895 *p++ = '\\'; 896 *p++ = '\\'; 897 } else if (isprint((uchar)c)) { 898 *p++ = (char)c; 899 } else { 900 p += sprintf(p, "\\x%02X", c); 901 } 902 } 903 *p = '\0'; 904 905 return p - ssid_buf; 906 } 907 908 static int 909 wl_iw_get_link_speed( 910 struct net_device *dev, 911 struct iw_request_info *info, 912 union iwreq_data *wrqu, 913 char *extra 914 ) 915 { 916 int error = 0; 917 char *p = extra; 918 static int link_speed; 919 920 net_os_wake_lock(dev); 921 if (g_onoff == G_WLAN_SET_ON) { 922 error = dev_wlc_ioctl(dev, WLC_GET_RATE, &link_speed, sizeof(link_speed)); 923 link_speed *= 500000; 924 } 925 926 p += snprintf(p, MAX_WX_STRING, "LinkSpeed %d", link_speed/1000000); 927 928 wrqu->data.length = p - extra + 1; 929 930 net_os_wake_unlock(dev); 931 return error; 932 } 933 934 935 static int 936 wl_iw_get_dtim_skip( 937 struct net_device *dev, 938 struct iw_request_info *info, 939 union iwreq_data *wrqu, 940 char *extra 941 ) 942 { 943 int error = -1; 944 char *p = extra; 945 char iovbuf[32]; 946 947 net_os_wake_lock(dev); 948 if (g_onoff == G_WLAN_SET_ON) { 949 950 memset(iovbuf, 0, sizeof(iovbuf)); 951 strcpy(iovbuf, "bcn_li_dtim"); 952 953 if ((error = dev_wlc_ioctl(dev, WLC_GET_VAR, 954 &iovbuf, sizeof(iovbuf))) >= 0) { 955 956 p += snprintf(p, MAX_WX_STRING, "Dtim_skip %d", iovbuf[0]); 957 WL_TRACE(("%s: get dtim_skip = %d\n", __FUNCTION__, iovbuf[0])); 958 wrqu->data.length = p - extra + 1; 959 } 960 else 961 WL_ERROR(("%s: get dtim_skip failed code %d\n", \ 962 __FUNCTION__, error)); 963 } 964 net_os_wake_unlock(dev); 965 return error; 966 } 967 968 969 static int 970 wl_iw_set_dtim_skip( 971 struct net_device *dev, 972 struct iw_request_info *info, 973 union iwreq_data *wrqu, 974 char *extra 975 ) 976 { 977 int error = -1; 978 char *p = extra; 979 int bcn_li_dtim; 980 char iovbuf[32]; 981 982 net_os_wake_lock(dev); 983 if (g_onoff == G_WLAN_SET_ON) { 984 985 bcn_li_dtim = htod32((uint)*(extra + strlen(DTIM_SKIP_SET_CMD) + 1) - '0'); 986 987 if ((bcn_li_dtim >= 0) || ((bcn_li_dtim <= 5))) { 988 989 memset(iovbuf, 0, sizeof(iovbuf)); 990 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, 991 4, iovbuf, sizeof(iovbuf)); 992 993 if ((error = dev_wlc_ioctl(dev, WLC_SET_VAR, 994 &iovbuf, sizeof(iovbuf))) >= 0) { 995 p += snprintf(p, MAX_WX_STRING, "OK"); 996 997 net_os_set_dtim_skip(dev, bcn_li_dtim); 998 999 WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__, \ 1000 bcn_li_dtim)); 1001 goto exit; 1002 } 1003 else WL_ERROR(("%s: set dtim_skip %d failed code %d\n", \ 1004 __FUNCTION__, bcn_li_dtim, error)); 1005 } 1006 else WL_ERROR(("%s Incorrect dtim_skip setting %d, ignored\n", \ 1007 __FUNCTION__, bcn_li_dtim)); 1008 } 1009 1010 p += snprintf(p, MAX_WX_STRING, "FAIL"); 1011 1012 exit: 1013 wrqu->data.length = p - extra + 1; 1014 net_os_wake_unlock(dev); 1015 return error; 1016 } 1017 1018 1019 static int 1020 wl_iw_get_band( 1021 struct net_device *dev, 1022 struct iw_request_info *info, 1023 union iwreq_data *wrqu, 1024 char *extra 1025 ) 1026 { 1027 int error = -1; 1028 char *p = extra; 1029 static int band; 1030 1031 net_os_wake_lock(dev); 1032 1033 if (g_onoff == G_WLAN_SET_ON) { 1034 error = dev_wlc_ioctl(dev, WLC_GET_BAND, &band, sizeof(band)); 1035 1036 p += snprintf(p, MAX_WX_STRING, "Band %d", band); 1037 1038 wrqu->data.length = p - extra + 1; 1039 } 1040 1041 net_os_wake_unlock(dev); 1042 return error; 1043 } 1044 1045 1046 static int 1047 wl_iw_set_band( 1048 struct net_device *dev, 1049 struct iw_request_info *info, 1050 union iwreq_data *wrqu, 1051 char *extra 1052 ) 1053 { 1054 int error = -1; 1055 char *p = extra; 1056 uint band; 1057 1058 net_os_wake_lock(dev); 1059 1060 if (g_onoff == G_WLAN_SET_ON) { 1061 1062 band = htod32((uint)*(extra + strlen(BAND_SET_CMD) + 1) - '0'); 1063 1064 if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { 1065 1066 1067 if ((error = dev_wlc_ioctl(dev, WLC_SET_BAND, 1068 &band, sizeof(band))) >= 0) { 1069 p += snprintf(p, MAX_WX_STRING, "OK"); 1070 WL_TRACE(("%s: set band %d OK\n", __FUNCTION__, band)); 1071 goto exit; 1072 } 1073 else WL_ERROR(("%s: set band %d failed code %d\n", __FUNCTION__, \ 1074 band, error)); 1075 } 1076 else WL_ERROR(("%s Incorrect band setting %d, ignored\n", __FUNCTION__, band)); 1077 } 1078 1079 p += snprintf(p, MAX_WX_STRING, "FAIL"); 1080 1081 exit: 1082 wrqu->data.length = p - extra + 1; 1083 net_os_wake_unlock(dev); 1084 return error; 1085 } 1086 1087 #ifdef PNO_SUPPORT 1088 1089 static int 1090 wl_iw_set_pno_reset( 1091 struct net_device *dev, 1092 struct iw_request_info *info, 1093 union iwreq_data *wrqu, 1094 char *extra 1095 ) 1096 { 1097 int error = -1; 1098 char *p = extra; 1099 1100 net_os_wake_lock(dev); 1101 if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) { 1102 1103 if ((error = dhd_dev_pno_reset(dev)) >= 0) { 1104 p += snprintf(p, MAX_WX_STRING, "OK"); 1105 WL_TRACE(("%s: set OK\n", __FUNCTION__)); 1106 goto exit; 1107 } 1108 else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error)); 1109 } 1110 1111 p += snprintf(p, MAX_WX_STRING, "FAIL"); 1112 1113 exit: 1114 wrqu->data.length = p - extra + 1; 1115 net_os_wake_unlock(dev); 1116 return error; 1117 } 1118 1119 1120 1121 static int 1122 wl_iw_set_pno_enable( 1123 struct net_device *dev, 1124 struct iw_request_info *info, 1125 union iwreq_data *wrqu, 1126 char *extra 1127 ) 1128 { 1129 int error = -1; 1130 char *p = extra; 1131 int pfn_enabled; 1132 1133 net_os_wake_lock(dev); 1134 pfn_enabled = htod32((uint)*(extra + strlen(PNOENABLE_SET_CMD) + 1) - '0'); 1135 1136 if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) { 1137 1138 if ((error = dhd_dev_pno_enable(dev, pfn_enabled)) >= 0) { 1139 p += snprintf(p, MAX_WX_STRING, "OK"); 1140 WL_TRACE(("%s: set OK\n", __FUNCTION__)); 1141 goto exit; 1142 } 1143 else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error)); 1144 } 1145 1146 p += snprintf(p, MAX_WX_STRING, "FAIL"); 1147 1148 exit: 1149 wrqu->data.length = p - extra + 1; 1150 net_os_wake_unlock(dev); 1151 return error; 1152 } 1153 1154 1155 1156 static int 1157 wl_iw_set_pno_set( 1158 struct net_device *dev, 1159 struct iw_request_info *info, 1160 union iwreq_data *wrqu, 1161 char *extra 1162 ) 1163 { 1164 int res = -1; 1165 wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; 1166 int nssid = 0; 1167 cmd_tlv_t *cmd_tlv_temp; 1168 char type; 1169 char *str_ptr; 1170 int tlv_size_left; 1171 int pno_time; 1172 1173 #ifdef PNO_SET_DEBUG 1174 int i; 1175 char pno_in_example[] = {'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', \ 1176 'S', 0x01, 0x01, 0x00, 1177 'S', 1178 0x04, 1179 'B', 'R', 'C', 'M', 1180 'S', 1181 0x04, 1182 'G', 'O', 'O', 'G', 1183 'T', 1184 0x00, 1185 0x0A 1186 }; 1187 #endif 1188 1189 net_os_wake_lock(dev); 1190 WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", 1191 __FUNCTION__, info->cmd, info->flags, 1192 wrqu->data.pointer, wrqu->data.length)); 1193 1194 if (g_onoff == G_WLAN_SET_OFF) { 1195 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); 1196 goto exit_proc; 1197 } 1198 1199 if (wrqu->data.length < (strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))) { 1200 WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, \ 1201 wrqu->data.length, strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))); 1202 goto exit_proc; 1203 } 1204 1205 #ifdef PNO_SET_DEBUG 1206 if (!(extra = kmalloc(sizeof(pno_in_example) +100, GFP_KERNEL))) { 1207 res = -ENOMEM; 1208 goto exit_proc; 1209 } 1210 memcpy(extra, pno_in_example, sizeof(pno_in_example)); 1211 wrqu->data.length = sizeof(pno_in_example); 1212 for (i = 0; i < wrqu->data.length; i++) 1213 printf("%02X ", extra[i]); 1214 printf("\n"); 1215 #endif 1216 1217 str_ptr = extra; 1218 #ifdef PNO_SET_DEBUG 1219 str_ptr += strlen("PNOSETUP "); 1220 tlv_size_left = wrqu->data.length - strlen("PNOSETUP "); 1221 #else 1222 str_ptr += strlen(PNOSETUP_SET_CMD); 1223 tlv_size_left = wrqu->data.length - strlen(PNOSETUP_SET_CMD); 1224 #endif 1225 1226 cmd_tlv_temp = (cmd_tlv_t *)str_ptr; 1227 memset(ssids_local, 0, sizeof(ssids_local)); 1228 1229 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && \ 1230 (cmd_tlv_temp->version == PNO_TLV_VERSION) && \ 1231 (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) 1232 { 1233 str_ptr += sizeof(cmd_tlv_t); 1234 tlv_size_left -= sizeof(cmd_tlv_t); 1235 1236 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \ 1237 MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { 1238 WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); 1239 goto exit_proc; 1240 } 1241 else { 1242 while (tlv_size_left > 0) 1243 { 1244 type = str_ptr[0]; 1245 switch (type) { 1246 case PNO_TLV_TYPE_TIME: 1247 1248 if ((res = wl_iw_parse_data_tlv(&str_ptr, \ 1249 &pno_time, \ 1250 sizeof(pno_time), \ 1251 type, sizeof(short), &tlv_size_left)) == -1) { 1252 WL_ERROR(("%s return %d\n", \ 1253 __FUNCTION__, res)); 1254 goto exit_proc; 1255 } 1256 break; 1257 1258 default: 1259 WL_ERROR(("%s get unkwown type %X\n", \ 1260 __FUNCTION__, type)); 1261 goto exit_proc; 1262 break; 1263 } 1264 } 1265 } 1266 } 1267 else { 1268 WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); 1269 goto exit_proc; 1270 } 1271 1272 res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time); 1273 1274 exit_proc: 1275 net_os_wake_unlock(dev); 1276 return res; 1277 } 1278 #endif 1279 1280 static int 1281 wl_iw_get_rssi( 1282 struct net_device *dev, 1283 struct iw_request_info *info, 1284 union iwreq_data *wrqu, 1285 char *extra 1286 ) 1287 { 1288 static int rssi = 0; 1289 static wlc_ssid_t ssid = {0}; 1290 int error = 0; 1291 char *p = extra; 1292 static char ssidbuf[SSID_FMT_BUF_LEN]; 1293 scb_val_t scb_val; 1294 1295 net_os_wake_lock(dev); 1296 1297 bzero(&scb_val, sizeof(scb_val_t)); 1298 1299 if (g_onoff == G_WLAN_SET_ON) { 1300 error = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); 1301 if (error) { 1302 WL_ERROR(("%s: Fails %d\n", __FUNCTION__, error)); 1303 net_os_wake_unlock(dev); 1304 return error; 1305 } 1306 rssi = dtoh32(scb_val.val); 1307 1308 error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)); 1309 if (!error) { 1310 ssid.SSID_len = dtoh32(ssid.SSID_len); 1311 wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len)); 1312 } 1313 } 1314 1315 p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi); 1316 wrqu->data.length = p - extra + 1; 1317 1318 net_os_wake_unlock(dev); 1319 return error; 1320 } 1321 1322 int 1323 wl_iw_send_priv_event( 1324 struct net_device *dev, 1325 char *flag 1326 ) 1327 { 1328 union iwreq_data wrqu; 1329 char extra[IW_CUSTOM_MAX + 1]; 1330 int cmd; 1331 1332 cmd = IWEVCUSTOM; 1333 memset(&wrqu, 0, sizeof(wrqu)); 1334 if (strlen(flag) > sizeof(extra)) 1335 return -1; 1336 1337 strcpy(extra, flag); 1338 wrqu.data.length = strlen(extra); 1339 wireless_send_event(dev, cmd, &wrqu, extra); 1340 net_os_wake_lock_timeout_enable(dev); 1341 WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra)); 1342 1343 return 0; 1344 } 1345 1346 1347 int 1348 wl_control_wl_start(struct net_device *dev) 1349 { 1350 int ret = 0; 1351 1352 WL_TRACE(("Enter %s \n", __FUNCTION__)); 1353 1354 if (!dev) { 1355 WL_ERROR(("%s: dev is null\n", __FUNCTION__)); 1356 return -1; 1357 } 1358 1359 mutex_lock(&wl_start_lock); 1360 1361 if (g_onoff == G_WLAN_SET_OFF) { 1362 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); 1363 1364 #if defined(BCMLXSDMMC) 1365 sdioh_start(NULL, 0); 1366 #endif 1367 1368 dhd_dev_reset(dev, 0); 1369 1370 #if defined(BCMLXSDMMC) 1371 sdioh_start(NULL, 1); 1372 #endif 1373 1374 dhd_dev_init_ioctl(dev); 1375 1376 g_onoff = G_WLAN_SET_ON; 1377 } 1378 WL_TRACE(("Exited %s \n", __FUNCTION__)); 1379 1380 mutex_unlock(&wl_start_lock); 1381 return ret; 1382 } 1383 1384 1385 static int 1386 wl_iw_control_wl_off( 1387 struct net_device *dev, 1388 struct iw_request_info *info 1389 ) 1390 { 1391 int ret = 0; 1392 WL_TRACE(("Enter %s\n", __FUNCTION__)); 1393 1394 if (!dev) { 1395 WL_ERROR(("%s: dev is null\n", __FUNCTION__)); 1396 return -1; 1397 } 1398 1399 mutex_lock(&wl_start_lock); 1400 1401 #ifdef SOFTAP 1402 ap_cfg_running = FALSE; 1403 #endif 1404 1405 if (g_onoff == G_WLAN_SET_ON) { 1406 g_onoff = G_WLAN_SET_OFF; 1407 #if defined(WL_IW_USE_ISCAN) 1408 g_iscan->iscan_state = ISCAN_STATE_IDLE; 1409 #endif 1410 1411 dhd_dev_reset(dev, 1); 1412 1413 #if defined(WL_IW_USE_ISCAN) 1414 #if !defined(CSCAN) 1415 wl_iw_free_ss_cache(); 1416 wl_iw_run_ss_cache_timer(0); 1417 1418 g_ss_cache_ctrl.m_link_down = 1; 1419 #endif 1420 memset(g_scan, 0, G_SCAN_RESULTS); 1421 g_scan_specified_ssid = 0; 1422 1423 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; 1424 g_first_counter_scans = 0; 1425 #endif 1426 1427 #if defined(BCMLXSDMMC) 1428 sdioh_stop(NULL); 1429 #endif 1430 1431 net_os_set_dtim_skip(dev, 0); 1432 1433 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); 1434 1435 wl_iw_send_priv_event(dev, "STOP"); 1436 } 1437 1438 mutex_unlock(&wl_start_lock); 1439 1440 WL_TRACE(("Exited %s\n", __FUNCTION__)); 1441 1442 return ret; 1443 } 1444 1445 static int 1446 wl_iw_control_wl_on( 1447 struct net_device *dev, 1448 struct iw_request_info *info 1449 ) 1450 { 1451 int ret = 0; 1452 1453 WL_TRACE(("Enter %s \n", __FUNCTION__)); 1454 1455 ret = wl_control_wl_start(dev); 1456 1457 wl_iw_send_priv_event(dev, "START"); 1458 1459 #ifdef SOFTAP 1460 if (!ap_fw_loaded) { 1461 wl_iw_iscan_set_scan_broadcast_prep(dev, 0); 1462 } 1463 #else 1464 wl_iw_iscan_set_scan_broadcast_prep(dev, 0); 1465 #endif 1466 1467 WL_TRACE(("Exited %s \n", __FUNCTION__)); 1468 1469 return ret; 1470 } 1471 1472 #ifdef SOFTAP 1473 static struct ap_profile my_ap; 1474 static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap); 1475 static int get_assoc_sta_list(struct net_device *dev, char *buf, int len); 1476 static int set_ap_mac_list(struct net_device *dev, char *buf); 1477 1478 #define PTYPE_STRING 0 1479 #define PTYPE_INTDEC 1 1480 #define PTYPE_INTHEX 2 1481 #define PTYPE_STR_HEX 3 1482 int get_parmeter_from_string( 1483 char **str_ptr, const char *token, int param_type, void *dst, int param_max_len); 1484 1485 #endif 1486 1487 int hex2num(char c) 1488 { 1489 if (c >= '0' && c <= '9') 1490 return c - '0'; 1491 if (c >= 'a' && c <= 'f') 1492 return c - 'a' + 10; 1493 if (c >= 'A' && c <= 'F') 1494 return c - 'A' + 10; 1495 return -1; 1496 } 1497 1498 int hex2byte(const char *hex) 1499 { 1500 int a, b; 1501 a = hex2num(*hex++); 1502 if (a < 0) 1503 return -1; 1504 b = hex2num(*hex++); 1505 if (b < 0) 1506 return -1; 1507 return (a << 4) | b; 1508 } 1509 1510 1511 1512 int hstr_2_buf(const char *txt, u8 *buf, int len) 1513 { 1514 int i; 1515 1516 for (i = 0; i < len; i++) { 1517 int a, b; 1518 1519 a = hex2num(*txt++); 1520 if (a < 0) 1521 return -1; 1522 b = hex2num(*txt++); 1523 if (b < 0) 1524 return -1; 1525 *buf++ = (a << 4) | b; 1526 } 1527 1528 return 0; 1529 } 1530 1531 #ifdef SOFTAP 1532 int init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg) 1533 { 1534 char *str_ptr = param_str; 1535 char sub_cmd[16]; 1536 int ret = 0; 1537 1538 memset(sub_cmd, 0, sizeof(sub_cmd)); 1539 memset(ap_cfg, 0, sizeof(struct ap_profile)); 1540 1541 if (get_parmeter_from_string(&str_ptr, "ASCII_CMD=", 1542 PTYPE_STRING, sub_cmd, SSID_LEN) != 0) { 1543 return -1; 1544 } 1545 if (strncmp(sub_cmd, "AP_CFG", 6)) { 1546 WL_ERROR(("ERROR: sub_cmd:%s != 'AP_CFG'!\n", sub_cmd)); 1547 return -1; 1548 } 1549 1550 ret = get_parmeter_from_string(&str_ptr, "SSID=", PTYPE_STRING, ap_cfg->ssid, SSID_LEN); 1551 1552 ret |= get_parmeter_from_string(&str_ptr, "SEC=", PTYPE_STRING, ap_cfg->sec, SEC_LEN); 1553 1554 ret |= get_parmeter_from_string(&str_ptr, "KEY=", PTYPE_STRING, ap_cfg->key, KEY_LEN); 1555 1556 ret |= get_parmeter_from_string(&str_ptr, "CHANNEL=", PTYPE_INTDEC, &ap_cfg->channel, 5); 1557 1558 ret |= get_parmeter_from_string(&str_ptr, "PREAMBLE=", PTYPE_INTDEC, &ap_cfg->preamble, 5); 1559 1560 ret |= get_parmeter_from_string(&str_ptr, "MAX_SCB=", PTYPE_INTDEC, &ap_cfg->max_scb, 5); 1561 1562 return ret; 1563 } 1564 #endif 1565 1566 1567 #ifdef SOFTAP 1568 static int iwpriv_set_ap_config(struct net_device *dev, 1569 struct iw_request_info *info, 1570 union iwreq_data *wrqu, 1571 char *ext) 1572 { 1573 int res = 0; 1574 char *extra = NULL; 1575 struct ap_profile *ap_cfg = &my_ap; 1576 1577 WL_TRACE(("> Got IWPRIV SET_AP IOCTL: info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n", 1578 info->cmd, info->flags, 1579 wrqu->data.pointer, wrqu->data.length)); 1580 1581 if (wrqu->data.length != 0) { 1582 1583 char *str_ptr; 1584 1585 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL))) 1586 return -ENOMEM; 1587 1588 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) { 1589 kfree(extra); 1590 return -EFAULT; 1591 } 1592 1593 extra[wrqu->data.length] = 0; 1594 WL_SOFTAP((" Got str param in iw_point:\n %s\n", extra)); 1595 1596 memset(ap_cfg, 0, sizeof(struct ap_profile)); 1597 1598 str_ptr = extra; 1599 1600 if ((res = init_ap_profile_from_string(extra, ap_cfg)) < 0) { 1601 WL_ERROR(("%s failed to parse %d\n", __FUNCTION__, res)); 1602 kfree(extra); 1603 return -1; 1604 } 1605 1606 } else { 1607 WL_ERROR(("IWPRIV argument len = 0 \n")); 1608 return -1; 1609 } 1610 1611 if ((res = set_ap_cfg(dev, ap_cfg)) < 0) 1612 WL_ERROR(("%s failed to set_ap_cfg %d\n", __FUNCTION__, res)); 1613 1614 kfree(extra); 1615 1616 return res; 1617 } 1618 #endif 1619 1620 1621 #ifdef SOFTAP 1622 static int iwpriv_get_assoc_list(struct net_device *dev, 1623 struct iw_request_info *info, 1624 union iwreq_data *p_iwrq, 1625 char *extra) 1626 { 1627 int i, ret = 0; 1628 char mac_buf[256]; 1629 struct maclist *sta_maclist = (struct maclist *)mac_buf; 1630 1631 char mac_lst[256]; 1632 char *p_mac_str; 1633 1634 WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d, \ 1635 iwp.len:%p, iwp.flags:%x \n", __FUNCTION__, info->cmd, info->flags, \ 1636 extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags)); 1637 1638 WL_SOFTAP(("extra:%s\n", extra)); 1639 print_buf((u8 *)p_iwrq, 16, 0); 1640 1641 memset(sta_maclist, 0, sizeof(mac_buf)); 1642 1643 sta_maclist->count = 8; 1644 1645 WL_TRACE((" net device:%s, buf_sz:%d\n", dev->name, sizeof(mac_buf))); 1646 get_assoc_sta_list(dev, mac_buf, 256); 1647 WL_TRACE((" got %d stations\n", sta_maclist->count)); 1648 1649 memset(mac_lst, 0, sizeof(mac_lst)); 1650 p_mac_str = mac_lst; 1651 1652 for (i = 0; i < 8; i++) { 1653 struct ether_addr *id = &sta_maclist->ea[i]; 1654 1655 WL_SOFTAP(("dhd_drv>> sta_mac[%d] :", i)); 1656 print_buf((unsigned char *)&sta_maclist->ea[i], 6, 0); 1657 1658 p_mac_str += snprintf(p_mac_str, MAX_WX_STRING, 1659 "Mac[%d]=%02X:%02X:%02X:%02X:%02X:%02X\n", i, 1660 id->octet[0], id->octet[1], id->octet[2], 1661 id->octet[3], id->octet[4], id->octet[5]); 1662 1663 } 1664 1665 p_iwrq->data.length = strlen(mac_lst); 1666 1667 WL_TRACE(("u.pointer:%p\n", p_iwrq->data.pointer)); 1668 WL_TRACE(("resulting str:\n%s \n len:%d\n\n", mac_lst, p_iwrq->data.length)); 1669 1670 if (p_iwrq->data.length) { 1671 if (copy_to_user(p_iwrq->data.pointer, mac_lst, p_iwrq->data.length)) { 1672 WL_ERROR(("%s: Can't copy to user\n", __FUNCTION__)); 1673 return -EFAULT; 1674 } 1675 } 1676 1677 WL_TRACE(("Exited %s \n", __FUNCTION__)); 1678 return ret; 1679 } 1680 #endif 1681 1682 1683 #ifdef SOFTAP 1684 static int iwpriv_set_mac_filters(struct net_device *dev, 1685 struct iw_request_info *info, 1686 union iwreq_data *wrqu, 1687 char *ext) 1688 { 1689 1690 int i, ret = -1; 1691 char *extra = NULL; 1692 u8 macfilt[8][6]; 1693 int mac_cnt = 0; 1694 char sub_cmd[16]; 1695 1696 WL_TRACE((">>> Got IWPRIV SET_MAC_FILTER IOCTL: info->cmd:%x, \ 1697 info->flags:%x, u.data:%p, u.len:%d\n", 1698 info->cmd, info->flags, 1699 wrqu->data.pointer, wrqu->data.length)); 1700 1701 if (wrqu->data.length != 0) { 1702 1703 char *str_ptr; 1704 1705 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL))) 1706 return -ENOMEM; 1707 1708 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) { 1709 kfree(extra); 1710 return -EFAULT; 1711 } 1712 1713 extra[wrqu->data.length] = 0; 1714 WL_SOFTAP((" Got parameter string in iw_point:\n %s \n", extra)); 1715 1716 memset(macfilt, 0, sizeof(macfilt)); 1717 memset(sub_cmd, 0, sizeof(sub_cmd)); 1718 1719 str_ptr = extra; 1720 1721 if (get_parmeter_from_string(&str_ptr, "ASCII_CMD=", PTYPE_STRING, sub_cmd, 15) != 0) { 1722 goto exit_proc; 1723 } 1724 1725 #define MAC_FILT_MAX 8 1726 1727 if (strncmp(sub_cmd, "MAC_FLT_W", strlen("MAC_FLT_W"))) { 1728 WL_ERROR(("ERROR: sub_cmd:%s != 'MAC_FLT_W'!\n", sub_cmd)); 1729 goto exit_proc; 1730 } 1731 1732 if (get_parmeter_from_string(&str_ptr, "MAC_CNT=", 1733 PTYPE_INTDEC, &mac_cnt, 4) != 0) { 1734 WL_ERROR(("ERROR: MAC_CNT param is missing \n")); 1735 goto exit_proc; 1736 } 1737 1738 if (mac_cnt > MAC_FILT_MAX) { 1739 WL_ERROR(("ERROR: number of MAC filters > MAX\n")); 1740 goto exit_proc; 1741 } 1742 1743 for (i = 0; i < mac_cnt; i++) { 1744 if (get_parmeter_from_string(&str_ptr, "MAC=", 1745 PTYPE_STR_HEX, macfilt[i], 12) != 0) { 1746 WL_ERROR(("ERROR: MAC_filter[%d] is missing !\n", i)); 1747 goto exit_proc; 1748 } 1749 } 1750 1751 for (i = 0; i < mac_cnt; i++) { 1752 WL_SOFTAP(("mac_filt[%d]:", i)); 1753 print_buf(macfilt[i], 6, 0); 1754 } 1755 1756 wrqu->data.pointer = NULL; 1757 wrqu->data.length = 0; 1758 ret = 0; 1759 1760 } else { 1761 WL_ERROR(("IWPRIV argument len is 0\n")); 1762 return -1; 1763 } 1764 1765 exit_proc: 1766 kfree(extra); 1767 return ret; 1768 } 1769 #endif 1770 1771 #endif 1772 1773 #if WIRELESS_EXT < 13 1774 struct iw_request_info 1775 { 1776 __u16 cmd; 1777 __u16 flags; 1778 }; 1779 1780 typedef int (*iw_handler)(struct net_device *dev, 1781 struct iw_request_info *info, 1782 void *wrqu, 1783 char *extra); 1784 #endif 1785 1786 static int 1787 wl_iw_config_commit( 1788 struct net_device *dev, 1789 struct iw_request_info *info, 1790 void *zwrq, 1791 char *extra 1792 ) 1793 { 1794 wlc_ssid_t ssid; 1795 int error; 1796 struct sockaddr bssid; 1797 1798 WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name)); 1799 1800 if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) 1801 return error; 1802 1803 ssid.SSID_len = dtoh32(ssid.SSID_len); 1804 1805 if (!ssid.SSID_len) 1806 return 0; 1807 1808 bzero(&bssid, sizeof(struct sockaddr)); 1809 if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) { 1810 WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __FUNCTION__, ssid.SSID)); 1811 return error; 1812 } 1813 1814 return 0; 1815 } 1816 1817 static int 1818 wl_iw_get_name( 1819 struct net_device *dev, 1820 struct iw_request_info *info, 1821 char *cwrq, 1822 char *extra 1823 ) 1824 { 1825 WL_TRACE(("%s: SIOCGIWNAME\n", dev->name)); 1826 1827 strcpy(cwrq, "IEEE 802.11-DS"); 1828 1829 return 0; 1830 } 1831 1832 static int 1833 wl_iw_set_freq( 1834 struct net_device *dev, 1835 struct iw_request_info *info, 1836 struct iw_freq *fwrq, 1837 char *extra 1838 ) 1839 { 1840 int error, chan; 1841 uint sf = 0; 1842 1843 WL_TRACE(("%s %s: SIOCSIWFREQ\n", __FUNCTION__, dev->name)); 1844 1845 #if defined(SOFTAP) 1846 if (ap_cfg_running) { 1847 WL_TRACE(("%s:>> not executed, 'SOFT_AP is active' \n", __FUNCTION__)); 1848 return 0; 1849 } 1850 #endif 1851 1852 1853 if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) { 1854 chan = fwrq->m; 1855 } 1856 1857 1858 else { 1859 1860 if (fwrq->e >= 6) { 1861 fwrq->e -= 6; 1862 while (fwrq->e--) 1863 fwrq->m *= 10; 1864 } else if (fwrq->e < 6) { 1865 while (fwrq->e++ < 6) 1866 fwrq->m /= 10; 1867 } 1868 1869 if (fwrq->m > 4000 && fwrq->m < 5000) 1870 sf = WF_CHAN_FACTOR_4_G; 1871 1872 chan = wf_mhz2channel(fwrq->m, sf); 1873 } 1874 chan = htod32(chan); 1875 if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) 1876 return error; 1877 1878 g_wl_iw_params.target_channel = chan; 1879 1880 return -EINPROGRESS; 1881 } 1882 1883 static int 1884 wl_iw_get_freq( 1885 struct net_device *dev, 1886 struct iw_request_info *info, 1887 struct iw_freq *fwrq, 1888 char *extra 1889 ) 1890 { 1891 channel_info_t ci; 1892 int error; 1893 1894 WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name)); 1895 1896 if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) 1897 return error; 1898 1899 fwrq->m = dtoh32(ci.hw_channel); 1900 fwrq->e = dtoh32(0); 1901 return 0; 1902 } 1903 1904 static int 1905 wl_iw_set_mode( 1906 struct net_device *dev, 1907 struct iw_request_info *info, 1908 __u32 *uwrq, 1909 char *extra 1910 ) 1911 { 1912 int infra = 0, ap = 0, error = 0; 1913 1914 WL_TRACE(("%s: SIOCSIWMODE\n", dev->name)); 1915 1916 switch (*uwrq) { 1917 case IW_MODE_MASTER: 1918 infra = ap = 1; 1919 break; 1920 case IW_MODE_ADHOC: 1921 case IW_MODE_AUTO: 1922 break; 1923 case IW_MODE_INFRA: 1924 infra = 1; 1925 break; 1926 default: 1927 return -EINVAL; 1928 } 1929 infra = htod32(infra); 1930 ap = htod32(ap); 1931 1932 if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) || 1933 (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap)))) 1934 return error; 1935 1936 1937 return -EINPROGRESS; 1938 } 1939 1940 static int 1941 wl_iw_get_mode( 1942 struct net_device *dev, 1943 struct iw_request_info *info, 1944 __u32 *uwrq, 1945 char *extra 1946 ) 1947 { 1948 int error, infra = 0, ap = 0; 1949 1950 WL_TRACE(("%s: SIOCGIWMODE\n", dev->name)); 1951 1952 if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) || 1953 (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap)))) 1954 return error; 1955 1956 infra = dtoh32(infra); 1957 ap = dtoh32(ap); 1958 *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC; 1959 1960 return 0; 1961 } 1962 1963 static int 1964 wl_iw_get_range( 1965 struct net_device *dev, 1966 struct iw_request_info *info, 1967 struct iw_point *dwrq, 1968 char *extra 1969 ) 1970 { 1971 struct iw_range *range = (struct iw_range *) extra; 1972 wl_uint32_list_t *list; 1973 wl_rateset_t rateset; 1974 int8 *channels; 1975 int error, i, k; 1976 uint sf, ch; 1977 1978 int phytype; 1979 int bw_cap = 0, sgi_tx = 0, nmode = 0; 1980 channel_info_t ci; 1981 uint8 nrate_list2copy = 0; 1982 uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130}, 1983 {14, 29, 43, 58, 87, 116, 130, 144}, 1984 {27, 54, 81, 108, 162, 216, 243, 270}, 1985 {30, 60, 90, 120, 180, 240, 270, 300}}; 1986 1987 WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name)); 1988 1989 if (!extra) 1990 return -EINVAL; 1991 1992 channels = kmalloc((MAXCHANNEL+1)*4, GFP_KERNEL); 1993 if (!channels) { 1994 WL_ERROR(("Could not alloc channels\n")); 1995 return -ENOMEM; 1996 } 1997 list = (wl_uint32_list_t *)channels; 1998 1999 dwrq->length = sizeof(struct iw_range); 2000 memset(range, 0, sizeof(range)); 2001 2002 range->min_nwid = range->max_nwid = 0; 2003 2004 list->count = htod32(MAXCHANNEL); 2005 if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) { 2006 kfree(channels); 2007 return error; 2008 } 2009 for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) { 2010 range->freq[i].i = dtoh32(list->element[i]); 2011 2012 ch = dtoh32(list->element[i]); 2013 if (ch <= CH_MAX_2G_CHANNEL) 2014 sf = WF_CHAN_FACTOR_2_4_G; 2015 else 2016 sf = WF_CHAN_FACTOR_5_G; 2017 2018 range->freq[i].m = wf_channel2mhz(ch, sf); 2019 range->freq[i].e = 6; 2020 } 2021 range->num_frequency = range->num_channels = i; 2022 2023 range->max_qual.qual = 5; 2024 2025 range->max_qual.level = 0x100 - 200; 2026 2027 range->max_qual.noise = 0x100 - 200; 2028 2029 range->sensitivity = 65535; 2030 2031 #if WIRELESS_EXT > 11 2032 2033 range->avg_qual.qual = 3; 2034 2035 range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD; 2036 2037 range->avg_qual.noise = 0x100 - 75; 2038 #endif 2039 2040 if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) { 2041 kfree(channels); 2042 return error; 2043 } 2044 rateset.count = dtoh32(rateset.count); 2045 range->num_bitrates = rateset.count; 2046 for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++) 2047 range->bitrate[i] = (rateset.rates[i]& 0x7f) * 500000; 2048 dev_wlc_intvar_get(dev, "nmode", &nmode); 2049 dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)); 2050 2051 if (nmode == 1 && phytype == WLC_PHY_TYPE_SSN) { 2052 dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap); 2053 dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx); 2054 dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t)); 2055 ci.hw_channel = dtoh32(ci.hw_channel); 2056 2057 if (bw_cap == 0 || 2058 (bw_cap == 2 && ci.hw_channel <= 14)) { 2059 if (sgi_tx == 0) 2060 nrate_list2copy = 0; 2061 else 2062 nrate_list2copy = 1; 2063 } 2064 if (bw_cap == 1 || 2065 (bw_cap == 2 && ci.hw_channel >= 36)) { 2066 if (sgi_tx == 0) 2067 nrate_list2copy = 2; 2068 else 2069 nrate_list2copy = 3; 2070 } 2071 range->num_bitrates += 8; 2072 for (k = 0; i < range->num_bitrates; k++, i++) { 2073 2074 range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000; 2075 } 2076 } 2077 2078 if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) { 2079 kfree(channels); 2080 return error; 2081 } 2082 i = dtoh32(i); 2083 if (i == WLC_PHY_TYPE_A) 2084 range->throughput = 24000000; 2085 else 2086 range->throughput = 1500000; 2087 2088 range->min_rts = 0; 2089 range->max_rts = 2347; 2090 range->min_frag = 256; 2091 range->max_frag = 2346; 2092 2093 range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS; 2094 range->num_encoding_sizes = 4; 2095 range->encoding_size[0] = WEP1_KEY_SIZE; 2096 range->encoding_size[1] = WEP128_KEY_SIZE; 2097 #if WIRELESS_EXT > 17 2098 range->encoding_size[2] = TKIP_KEY_SIZE; 2099 #else 2100 range->encoding_size[2] = 0; 2101 #endif 2102 range->encoding_size[3] = AES_KEY_SIZE; 2103 2104 range->min_pmp = 0; 2105 range->max_pmp = 0; 2106 range->min_pmt = 0; 2107 range->max_pmt = 0; 2108 range->pmp_flags = 0; 2109 range->pm_capa = 0; 2110 2111 range->num_txpower = 2; 2112 range->txpower[0] = 1; 2113 range->txpower[1] = 255; 2114 range->txpower_capa = IW_TXPOW_MWATT; 2115 2116 #if WIRELESS_EXT > 10 2117 range->we_version_compiled = WIRELESS_EXT; 2118 range->we_version_source = 19; 2119 2120 range->retry_capa = IW_RETRY_LIMIT; 2121 range->retry_flags = IW_RETRY_LIMIT; 2122 range->r_time_flags = 0; 2123 2124 range->min_retry = 1; 2125 range->max_retry = 255; 2126 2127 range->min_r_time = 0; 2128 range->max_r_time = 0; 2129 #endif 2130 2131 #if WIRELESS_EXT > 17 2132 range->enc_capa = IW_ENC_CAPA_WPA; 2133 range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; 2134 range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; 2135 #ifdef BCMWPA2 2136 range->enc_capa |= IW_ENC_CAPA_WPA2; 2137 #endif 2138 2139 IW_EVENT_CAPA_SET_KERNEL(range->event_capa); 2140 2141 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); 2142 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); 2143 IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); 2144 IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE); 2145 #ifdef BCMWPA2 2146 IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND); 2147 #endif 2148 #endif 2149 2150 kfree(channels); 2151 2152 return 0; 2153 } 2154 2155 static int 2156 rssi_to_qual(int rssi) 2157 { 2158 if (rssi <= WL_IW_RSSI_NO_SIGNAL) 2159 return 0; 2160 else if (rssi <= WL_IW_RSSI_VERY_LOW) 2161 return 1; 2162 else if (rssi <= WL_IW_RSSI_LOW) 2163 return 2; 2164 else if (rssi <= WL_IW_RSSI_GOOD) 2165 return 3; 2166 else if (rssi <= WL_IW_RSSI_VERY_GOOD) 2167 return 4; 2168 else 2169 return 5; 2170 } 2171 2172 static int 2173 wl_iw_set_spy( 2174 struct net_device *dev, 2175 struct iw_request_info *info, 2176 struct iw_point *dwrq, 2177 char *extra 2178 ) 2179 { 2180 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); 2181 struct sockaddr *addr = (struct sockaddr *) extra; 2182 int i; 2183 2184 WL_TRACE(("%s: SIOCSIWSPY\n", dev->name)); 2185 2186 if (!extra) 2187 return -EINVAL; 2188 2189 iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length); 2190 for (i = 0; i < iw->spy_num; i++) 2191 memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN); 2192 memset(iw->spy_qual, 0, sizeof(iw->spy_qual)); 2193 2194 return 0; 2195 } 2196 2197 static int 2198 wl_iw_get_spy( 2199 struct net_device *dev, 2200 struct iw_request_info *info, 2201 struct iw_point *dwrq, 2202 char *extra 2203 ) 2204 { 2205 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); 2206 struct sockaddr *addr = (struct sockaddr *) extra; 2207 struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num]; 2208 int i; 2209 2210 WL_TRACE(("%s: SIOCGIWSPY\n", dev->name)); 2211 2212 if (!extra) 2213 return -EINVAL; 2214 2215 dwrq->length = iw->spy_num; 2216 for (i = 0; i < iw->spy_num; i++) { 2217 memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN); 2218 addr[i].sa_family = AF_UNIX; 2219 memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality)); 2220 iw->spy_qual[i].updated = 0; 2221 } 2222 2223 return 0; 2224 } 2225 2226 2227 static int 2228 wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params, int *join_params_size) 2229 { 2230 chanspec_t chanspec = 0; 2231 2232 if (ch != 0) { 2233 2234 join_params->params.chanspec_num = 1; 2235 join_params->params.chanspec_list[0] = ch; 2236 2237 if (join_params->params.chanspec_list[0]) 2238 chanspec |= WL_CHANSPEC_BAND_2G; 2239 else 2240 chanspec |= WL_CHANSPEC_BAND_5G; 2241 2242 chanspec |= WL_CHANSPEC_BW_20; 2243 chanspec |= WL_CHANSPEC_CTL_SB_NONE; 2244 2245 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE + 2246 join_params->params.chanspec_num * sizeof(chanspec_t); 2247 2248 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; 2249 join_params->params.chanspec_list[0] |= chanspec; 2250 join_params->params.chanspec_list[0] = 2251 htodchanspec(join_params->params.chanspec_list[0]); 2252 2253 join_params->params.chanspec_num = htod32(join_params->params.chanspec_num); 2254 2255 WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n", \ 2256 __FUNCTION__, join_params->params.chanspec_list[0])); 2257 } 2258 return 1; 2259 } 2260 2261 static int 2262 wl_iw_set_wap( 2263 struct net_device *dev, 2264 struct iw_request_info *info, 2265 struct sockaddr *awrq, 2266 char *extra 2267 ) 2268 { 2269 int error = -EINVAL; 2270 wl_join_params_t join_params; 2271 int join_params_size; 2272 2273 WL_TRACE(("%s: SIOCSIWAP\n", dev->name)); 2274 2275 if (awrq->sa_family != ARPHRD_ETHER) { 2276 WL_ERROR(("Invalid Header...sa_family\n")); 2277 return -EINVAL; 2278 } 2279 2280 2281 if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { 2282 scb_val_t scbval; 2283 2284 bzero(&scbval, sizeof(scb_val_t)); 2285 2286 (void) dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); 2287 return 0; 2288 } 2289 2290 2291 2292 memset(&join_params, 0, sizeof(join_params)); 2293 join_params_size = sizeof(join_params.ssid); 2294 2295 memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len); 2296 join_params.ssid.SSID_len = htod32(g_ssid.SSID_len); 2297 memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN); 2298 2299 WL_TRACE(("%s target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel)); 2300 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size); 2301 2302 if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) { 2303 WL_ERROR(("%s Invalid ioctl data=%d\n", __FUNCTION__, error)); 2304 return error; 2305 } 2306 2307 if (g_ssid.SSID_len) { 2308 WL_TRACE(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__, \ 2309 g_ssid.SSID, MAC2STR((u8 *)awrq->sa_data), \ 2310 g_wl_iw_params.target_channel)); 2311 } 2312 2313 2314 memset(&g_ssid, 0, sizeof(g_ssid)); 2315 return 0; 2316 } 2317 2318 static int 2319 wl_iw_get_wap( 2320 struct net_device *dev, 2321 struct iw_request_info *info, 2322 struct sockaddr *awrq, 2323 char *extra 2324 ) 2325 { 2326 WL_TRACE(("%s: SIOCGIWAP\n", dev->name)); 2327 2328 awrq->sa_family = ARPHRD_ETHER; 2329 memset(awrq->sa_data, 0, ETHER_ADDR_LEN); 2330 2331 2332 (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN); 2333 2334 return 0; 2335 } 2336 2337 #if WIRELESS_EXT > 17 2338 static int 2339 wl_iw_mlme( 2340 struct net_device *dev, 2341 struct iw_request_info *info, 2342 struct sockaddr *awrq, 2343 char *extra 2344 ) 2345 { 2346 struct iw_mlme *mlme; 2347 scb_val_t scbval; 2348 int error = -EINVAL; 2349 2350 WL_TRACE(("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name)); 2351 2352 mlme = (struct iw_mlme *)extra; 2353 if (mlme == NULL) { 2354 WL_ERROR(("Invalid ioctl data.\n")); 2355 return error; 2356 } 2357 2358 scbval.val = mlme->reason_code; 2359 bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN); 2360 2361 if (mlme->cmd == IW_MLME_DISASSOC) { 2362 scbval.val = htod32(scbval.val); 2363 error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); 2364 } 2365 else if (mlme->cmd == IW_MLME_DEAUTH) { 2366 scbval.val = htod32(scbval.val); 2367 error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, 2368 sizeof(scb_val_t)); 2369 } 2370 else { 2371 WL_ERROR(("Invalid ioctl data.\n")); 2372 return error; 2373 } 2374 2375 return error; 2376 } 2377 #endif 2378 2379 #ifndef WL_IW_USE_ISCAN 2380 static int 2381 wl_iw_get_aplist( 2382 struct net_device *dev, 2383 struct iw_request_info *info, 2384 struct iw_point *dwrq, 2385 char *extra 2386 ) 2387 { 2388 wl_scan_results_t *list; 2389 struct sockaddr *addr = (struct sockaddr *) extra; 2390 struct iw_quality qual[IW_MAX_AP]; 2391 wl_bss_info_t *bi = NULL; 2392 int error, i; 2393 uint buflen = dwrq->length; 2394 2395 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name)); 2396 2397 if (!extra) 2398 return -EINVAL; 2399 2400 list = kmalloc(buflen, GFP_KERNEL); 2401 if (!list) 2402 return -ENOMEM; 2403 memset(list, 0, buflen); 2404 list->buflen = htod32(buflen); 2405 if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) { 2406 WL_ERROR(("%d: Scan results error %d\n", __LINE__, error)); 2407 kfree(list); 2408 return error; 2409 } 2410 list->buflen = dtoh32(list->buflen); 2411 list->version = dtoh32(list->version); 2412 list->count = dtoh32(list->count); 2413 if (list->version != WL_BSS_INFO_VERSION) { 2414 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ 2415 __FUNCTION__, list->version)); 2416 kfree(list); 2417 return -EINVAL; 2418 } 2419 2420 for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { 2421 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; 2422 ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + 2423 buflen)); 2424 2425 2426 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) 2427 continue; 2428 2429 2430 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); 2431 addr[dwrq->length].sa_family = ARPHRD_ETHER; 2432 qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); 2433 qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); 2434 qual[dwrq->length].noise = 0x100 + bi->phy_noise; 2435 2436 2437 #if WIRELESS_EXT > 18 2438 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; 2439 #else 2440 qual[dwrq->length].updated = 7; 2441 #endif 2442 2443 dwrq->length++; 2444 } 2445 2446 kfree(list); 2447 2448 if (dwrq->length) { 2449 memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); 2450 2451 dwrq->flags = 1; 2452 } 2453 return 0; 2454 } 2455 #endif 2456 2457 #ifdef WL_IW_USE_ISCAN 2458 static int 2459 wl_iw_iscan_get_aplist( 2460 struct net_device *dev, 2461 struct iw_request_info *info, 2462 struct iw_point *dwrq, 2463 char *extra 2464 ) 2465 { 2466 wl_scan_results_t *list; 2467 iscan_buf_t * buf; 2468 iscan_info_t *iscan = g_iscan; 2469 2470 struct sockaddr *addr = (struct sockaddr *) extra; 2471 struct iw_quality qual[IW_MAX_AP]; 2472 wl_bss_info_t *bi = NULL; 2473 int i; 2474 2475 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name)); 2476 2477 if (!extra) 2478 return -EINVAL; 2479 2480 if ((!iscan) || (iscan->sysioc_pid < 0)) { 2481 WL_ERROR(("%s error\n", __FUNCTION__)); 2482 return 0; 2483 } 2484 2485 buf = iscan->list_hdr; 2486 2487 while (buf) { 2488 list = &((wl_iscan_results_t*)buf->iscan_buf)->results; 2489 if (list->version != WL_BSS_INFO_VERSION) { 2490 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ 2491 __FUNCTION__, list->version)); 2492 return -EINVAL; 2493 } 2494 2495 bi = NULL; 2496 for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { 2497 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) 2498 : list->bss_info; 2499 ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + 2500 WLC_IW_ISCAN_MAXLEN)); 2501 2502 2503 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) 2504 continue; 2505 2506 2507 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); 2508 addr[dwrq->length].sa_family = ARPHRD_ETHER; 2509 qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); 2510 qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); 2511 qual[dwrq->length].noise = 0x100 + bi->phy_noise; 2512 2513 2514 #if WIRELESS_EXT > 18 2515 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; 2516 #else 2517 qual[dwrq->length].updated = 7; 2518 #endif 2519 2520 dwrq->length++; 2521 } 2522 buf = buf->next; 2523 } 2524 if (dwrq->length) { 2525 memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); 2526 2527 dwrq->flags = 1; 2528 } 2529 return 0; 2530 } 2531 2532 static int 2533 wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) 2534 { 2535 int err = 0; 2536 2537 memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); 2538 params->bss_type = DOT11_BSSTYPE_ANY; 2539 params->scan_type = 0; 2540 params->nprobes = -1; 2541 params->active_time = -1; 2542 params->passive_time = -1; 2543 params->home_time = -1; 2544 params->channel_num = 0; 2545 2546 params->nprobes = htod32(params->nprobes); 2547 params->active_time = htod32(params->active_time); 2548 params->passive_time = htod32(params->passive_time); 2549 params->home_time = htod32(params->home_time); 2550 if (ssid && ssid->SSID_len) 2551 memcpy(¶ms->ssid, ssid, sizeof(wlc_ssid_t)); 2552 2553 return err; 2554 } 2555 2556 static int 2557 wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) 2558 { 2559 int err = 0; 2560 2561 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION); 2562 iscan->iscan_ex_params_p->action = htod16(action); 2563 iscan->iscan_ex_params_p->scan_duration = htod16(0); 2564 2565 WL_SCAN(("%s : nprobes=%d\n", __FUNCTION__, iscan->iscan_ex_params_p->params.nprobes)); 2566 WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time)); 2567 WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time)); 2568 WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time)); 2569 WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type)); 2570 WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type)); 2571 2572 2573 if ((err = dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, \ 2574 iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) { 2575 WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err)); 2576 err = -1; 2577 } 2578 2579 return err; 2580 } 2581 2582 static void 2583 wl_iw_timerfunc(ulong data) 2584 { 2585 iscan_info_t *iscan = (iscan_info_t *)data; 2586 if (iscan) { 2587 iscan->timer_on = 0; 2588 if (iscan->iscan_state != ISCAN_STATE_IDLE) { 2589 WL_SCAN(("timer trigger\n")); 2590 up(&iscan->sysioc_sem); 2591 } 2592 } 2593 } 2594 static void wl_iw_set_event_mask(struct net_device *dev) 2595 { 2596 char eventmask[WL_EVENTING_MASK_LEN]; 2597 char iovbuf[WL_EVENTING_MASK_LEN + 12]; 2598 2599 dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf)); 2600 bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); 2601 setbit(eventmask, WLC_E_SCAN_COMPLETE); 2602 dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, 2603 iovbuf, sizeof(iovbuf)); 2604 } 2605 2606 static uint32 2607 wl_iw_iscan_get(iscan_info_t *iscan) 2608 { 2609 iscan_buf_t * buf; 2610 iscan_buf_t * ptr; 2611 wl_iscan_results_t * list_buf; 2612 wl_iscan_results_t list; 2613 wl_scan_results_t *results; 2614 uint32 status; 2615 int res; 2616 2617 mutex_lock(&wl_cache_lock); 2618 if (iscan->list_cur) { 2619 buf = iscan->list_cur; 2620 iscan->list_cur = buf->next; 2621 } 2622 else { 2623 buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL); 2624 if (!buf) { 2625 WL_ERROR(("%s can't alloc iscan_buf_t : going to abort currect iscan\n", \ 2626 __FUNCTION__)); 2627 mutex_unlock(&wl_cache_lock); 2628 return WL_SCAN_RESULTS_NO_MEM; 2629 } 2630 buf->next = NULL; 2631 if (!iscan->list_hdr) 2632 iscan->list_hdr = buf; 2633 else { 2634 ptr = iscan->list_hdr; 2635 while (ptr->next) { 2636 ptr = ptr->next; 2637 } 2638 ptr->next = buf; 2639 } 2640 } 2641 memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN); 2642 list_buf = (wl_iscan_results_t*)buf->iscan_buf; 2643 results = &list_buf->results; 2644 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; 2645 results->version = 0; 2646 results->count = 0; 2647 2648 memset(&list, 0, sizeof(list)); 2649 list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); 2650 res = dev_iw_iovar_getbuf( 2651 iscan->dev, 2652 "iscanresults", 2653 &list, 2654 WL_ISCAN_RESULTS_FIXED_SIZE, 2655 buf->iscan_buf, 2656 WLC_IW_ISCAN_MAXLEN); 2657 if (res == 0) { 2658 results->buflen = dtoh32(results->buflen); 2659 results->version = dtoh32(results->version); 2660 results->count = dtoh32(results->count); 2661 WL_SCAN(("results->count = %d\n", results->count)); 2662 2663 WL_SCAN(("results->buflen = %d\n", results->buflen)); 2664 status = dtoh32(list_buf->status); 2665 } else { 2666 WL_ERROR(("%s returns error %d\n", __FUNCTION__, res)); 2667 status = WL_SCAN_RESULTS_NO_MEM; 2668 } 2669 mutex_unlock(&wl_cache_lock); 2670 return status; 2671 } 2672 2673 static void wl_iw_force_specific_scan(iscan_info_t *iscan) 2674 { 2675 WL_TRACE(("%s force Specific SCAN for %s\n", __FUNCTION__, g_specific_ssid.SSID)); 2676 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 2677 rtnl_lock(); 2678 #endif 2679 (void) dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)); 2680 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 2681 rtnl_unlock(); 2682 #endif 2683 } 2684 2685 static void wl_iw_send_scan_complete(iscan_info_t *iscan) 2686 { 2687 #ifndef SANDGATE2G 2688 union iwreq_data wrqu; 2689 2690 memset(&wrqu, 0, sizeof(wrqu)); 2691 2692 wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); 2693 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) 2694 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY; 2695 WL_TRACE(("Send Event ISCAN complete\n")); 2696 #endif 2697 } 2698 2699 static int 2700 _iscan_sysioc_thread(void *data) 2701 { 2702 uint32 status; 2703 iscan_info_t *iscan = (iscan_info_t *)data; 2704 static bool iscan_pass_abort = FALSE; 2705 2706 DAEMONIZE("iscan_sysioc"); 2707 2708 status = WL_SCAN_RESULTS_PARTIAL; 2709 while (down_interruptible(&iscan->sysioc_sem) == 0) { 2710 2711 net_os_wake_lock(iscan->dev); 2712 2713 #if defined(SOFTAP) 2714 if (ap_cfg_running) { 2715 WL_SCAN(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__)); 2716 net_os_wake_unlock(iscan->dev); 2717 continue; 2718 } 2719 #endif 2720 2721 if (iscan->timer_on) { 2722 iscan->timer_on = 0; 2723 del_timer_sync(&iscan->timer); 2724 } 2725 2726 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 2727 rtnl_lock(); 2728 #endif 2729 status = wl_iw_iscan_get(iscan); 2730 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 2731 rtnl_unlock(); 2732 #endif 2733 2734 if (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) { 2735 WL_SCAN(("%s Get results from specific scan status=%d\n", __FUNCTION__, status)); 2736 wl_iw_send_scan_complete(iscan); 2737 iscan_pass_abort = FALSE; 2738 status = -1; 2739 } 2740 2741 switch (status) { 2742 case WL_SCAN_RESULTS_PARTIAL: 2743 WL_SCAN(("iscanresults incomplete\n")); 2744 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 2745 rtnl_lock(); 2746 #endif 2747 2748 wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); 2749 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 2750 rtnl_unlock(); 2751 #endif 2752 2753 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); 2754 iscan->timer_on = 1; 2755 break; 2756 case WL_SCAN_RESULTS_SUCCESS: 2757 WL_SCAN(("iscanresults complete\n")); 2758 iscan->iscan_state = ISCAN_STATE_IDLE; 2759 wl_iw_send_scan_complete(iscan); 2760 break; 2761 case WL_SCAN_RESULTS_PENDING: 2762 WL_SCAN(("iscanresults pending\n")); 2763 2764 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); 2765 iscan->timer_on = 1; 2766 break; 2767 case WL_SCAN_RESULTS_ABORTED: 2768 WL_SCAN(("iscanresults aborted\n")); 2769 iscan->iscan_state = ISCAN_STATE_IDLE; 2770 if (g_scan_specified_ssid == 0) 2771 wl_iw_send_scan_complete(iscan); 2772 else { 2773 iscan_pass_abort = TRUE; 2774 wl_iw_force_specific_scan(iscan); 2775 } 2776 break; 2777 case WL_SCAN_RESULTS_NO_MEM: 2778 WL_SCAN(("iscanresults can't alloc memory: skip\n")); 2779 iscan->iscan_state = ISCAN_STATE_IDLE; 2780 break; 2781 default: 2782 WL_SCAN(("iscanresults returned unknown status %d\n", status)); 2783 break; 2784 } 2785 2786 net_os_wake_unlock(iscan->dev); 2787 } 2788 2789 if (iscan->timer_on) { 2790 iscan->timer_on = 0; 2791 del_timer_sync(&iscan->timer); 2792 } 2793 2794 complete_and_exit(&iscan->sysioc_exited, 0); 2795 } 2796 #endif 2797 2798 #if !defined(CSCAN) 2799 2800 static void 2801 wl_iw_set_ss_cache_timer_flag(void) 2802 { 2803 g_ss_cache_ctrl.m_timer_expired = 1; 2804 WL_TRACE(("%s called\n", __FUNCTION__)); 2805 } 2806 2807 static int 2808 wl_iw_init_ss_cache_ctrl(void) 2809 { 2810 WL_TRACE(("%s :\n", __FUNCTION__)); 2811 g_ss_cache_ctrl.m_prev_scan_mode = 0; 2812 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0; 2813 g_ss_cache_ctrl.m_cache_head = NULL; 2814 g_ss_cache_ctrl.m_link_down = 0; 2815 g_ss_cache_ctrl.m_timer_expired = 0; 2816 memset(g_ss_cache_ctrl.m_active_bssid, 0, ETHER_ADDR_LEN); 2817 2818 g_ss_cache_ctrl.m_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); 2819 if (!g_ss_cache_ctrl.m_timer) { 2820 return -ENOMEM; 2821 } 2822 g_ss_cache_ctrl.m_timer->function = (void *)wl_iw_set_ss_cache_timer_flag; 2823 init_timer(g_ss_cache_ctrl.m_timer); 2824 2825 return 0; 2826 } 2827 2828 2829 2830 static void 2831 wl_iw_free_ss_cache(void) 2832 { 2833 wl_iw_ss_cache_t *node, *cur; 2834 wl_iw_ss_cache_t **spec_scan_head; 2835 2836 WL_TRACE(("%s called\n", __FUNCTION__)); 2837 2838 mutex_lock(&wl_cache_lock); 2839 spec_scan_head = &g_ss_cache_ctrl.m_cache_head; 2840 node = *spec_scan_head; 2841 2842 for (;node;) { 2843 WL_TRACE(("%s : SSID - %s\n", __FUNCTION__, node->bss_info->SSID)); 2844 cur = node; 2845 node = cur->next; 2846 kfree(cur); 2847 } 2848 *spec_scan_head = NULL; 2849 mutex_unlock(&wl_cache_lock); 2850 } 2851 2852 2853 2854 static int 2855 wl_iw_run_ss_cache_timer(int kick_off) 2856 { 2857 struct timer_list **timer; 2858 2859 timer = &g_ss_cache_ctrl.m_timer; 2860 2861 if (*timer) { 2862 if (kick_off) { 2863 (*timer)->expires = jiffies + 30000 * HZ / 1000; 2864 add_timer(*timer); 2865 WL_TRACE(("%s : timer starts \n", __FUNCTION__)); 2866 } else { 2867 del_timer_sync(*timer); 2868 WL_TRACE(("%s : timer stops \n", __FUNCTION__)); 2869 } 2870 } 2871 2872 return 0; 2873 } 2874 2875 2876 void 2877 wl_iw_release_ss_cache_ctrl(void) 2878 { 2879 WL_TRACE(("%s :\n", __FUNCTION__)); 2880 wl_iw_free_ss_cache(); 2881 wl_iw_run_ss_cache_timer(0); 2882 if (g_ss_cache_ctrl.m_timer) { 2883 kfree(g_ss_cache_ctrl.m_timer); 2884 } 2885 } 2886 2887 2888 2889 static void 2890 wl_iw_reset_ss_cache(void) 2891 { 2892 wl_iw_ss_cache_t *node, *prev, *cur; 2893 wl_iw_ss_cache_t **spec_scan_head; 2894 2895 mutex_lock(&wl_cache_lock); 2896 spec_scan_head = &g_ss_cache_ctrl.m_cache_head; 2897 node = *spec_scan_head; 2898 prev = node; 2899 2900 for (;node;) { 2901 WL_TRACE(("%s : node SSID %s \n", __FUNCTION__, node->bss_info->SSID)); 2902 if (!node->dirty) { 2903 cur = node; 2904 if (cur == *spec_scan_head) { 2905 *spec_scan_head = cur->next; 2906 prev = *spec_scan_head; 2907 } 2908 else { 2909 prev->next = cur->next; 2910 } 2911 node = cur->next; 2912 2913 WL_TRACE(("%s : Del node : SSID %s\n", __FUNCTION__, cur->bss_info->SSID)); 2914 kfree(cur); 2915 continue; 2916 } 2917 2918 node->dirty = 0; 2919 prev = node; 2920 node = node->next; 2921 } 2922 mutex_unlock(&wl_cache_lock); 2923 } 2924 2925 2926 static int 2927 wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list) 2928 { 2929 2930 wl_iw_ss_cache_t *node, *prev, *leaf; 2931 wl_iw_ss_cache_t **spec_scan_head; 2932 wl_bss_info_t *bi = NULL; 2933 int i; 2934 2935 if (!ss_list->count) { 2936 return 0; 2937 } 2938 2939 mutex_lock(&wl_cache_lock); 2940 spec_scan_head = &g_ss_cache_ctrl.m_cache_head; 2941 2942 for (i = 0; i < ss_list->count; i++) { 2943 2944 node = *spec_scan_head; 2945 prev = node; 2946 2947 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; 2948 2949 WL_TRACE(("%s : find %d with specific SSID %s\n", __FUNCTION__, i, bi->SSID)); 2950 for (;node;) { 2951 if (!memcmp(&node->bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { 2952 2953 WL_TRACE(("dirty marked : SSID %s\n", bi->SSID)); 2954 node->dirty = 1; 2955 break; 2956 } 2957 prev = node; 2958 node = node->next; 2959 } 2960 2961 if (node) { 2962 continue; 2963 } 2964 leaf = kmalloc(bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL); 2965 if (!leaf) { 2966 WL_ERROR(("Memory alloc failure %d\n", \ 2967 bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN)); 2968 mutex_unlock(&wl_cache_lock); 2969 return -ENOMEM; 2970 } 2971 2972 memcpy(leaf->bss_info, bi, bi->length); 2973 leaf->next = NULL; 2974 leaf->dirty = 1; 2975 leaf->count = 1; 2976 leaf->version = ss_list->version; 2977 2978 if (!prev) { 2979 *spec_scan_head = leaf; 2980 } 2981 else { 2982 prev->next = leaf; 2983 } 2984 } 2985 mutex_unlock(&wl_cache_lock); 2986 return 0; 2987 } 2988 2989 2990 static int 2991 wl_iw_merge_scan_cache(struct iw_request_info *info, char *extra, uint buflen_from_user, 2992 __u16 *merged_len) 2993 { 2994 wl_iw_ss_cache_t *node; 2995 wl_scan_results_t *list_merge; 2996 2997 mutex_lock(&wl_cache_lock); 2998 node = g_ss_cache_ctrl.m_cache_head; 2999 for (;node;) { 3000 list_merge = (wl_scan_results_t *)node; 3001 WL_TRACE(("%s: Cached Specific APs list=%d\n", __FUNCTION__, list_merge->count)); 3002 if (buflen_from_user - *merged_len > 0) { 3003 *merged_len += (__u16) wl_iw_get_scan_prep(list_merge, info, 3004 extra + *merged_len, buflen_from_user - *merged_len); 3005 } 3006 else { 3007 WL_TRACE(("%s: exit with break\n", __FUNCTION__)); 3008 break; 3009 } 3010 node = node->next; 3011 } 3012 mutex_unlock(&wl_cache_lock); 3013 return 0; 3014 } 3015 3016 3017 static int 3018 wl_iw_delete_bss_from_ss_cache(void *addr) 3019 { 3020 3021 wl_iw_ss_cache_t *node, *prev; 3022 wl_iw_ss_cache_t **spec_scan_head; 3023 3024 mutex_lock(&wl_cache_lock); 3025 spec_scan_head = &g_ss_cache_ctrl.m_cache_head; 3026 node = *spec_scan_head; 3027 prev = node; 3028 for (;node;) { 3029 if (!memcmp(&node->bss_info->BSSID, addr, ETHER_ADDR_LEN)) { 3030 if (node == *spec_scan_head) { 3031 *spec_scan_head = node->next; 3032 } 3033 else { 3034 prev->next = node->next; 3035 } 3036 3037 WL_TRACE(("%s : Del node : %s\n", __FUNCTION__, node->bss_info->SSID)); 3038 kfree(node); 3039 break; 3040 } 3041 3042 prev = node; 3043 node = node->next; 3044 } 3045 3046 memset(addr, 0, ETHER_ADDR_LEN); 3047 mutex_unlock(&wl_cache_lock); 3048 return 0; 3049 } 3050 3051 #endif 3052 3053 3054 static int 3055 wl_iw_set_scan( 3056 struct net_device *dev, 3057 struct iw_request_info *info, 3058 union iwreq_data *wrqu, 3059 char *extra 3060 ) 3061 { 3062 int error; 3063 WL_TRACE(("%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name)); 3064 3065 #if defined(CSCAN) 3066 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__)); 3067 return -EINVAL; 3068 #endif 3069 3070 #if defined(SOFTAP) 3071 if (ap_cfg_running) { 3072 WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); 3073 return 0; 3074 } 3075 #endif 3076 3077 if (g_onoff == G_WLAN_SET_OFF) 3078 return 0; 3079 3080 memset(&g_specific_ssid, 0, sizeof(g_specific_ssid)); 3081 #ifndef WL_IW_USE_ISCAN 3082 g_scan_specified_ssid = 0; 3083 #endif 3084 3085 #if WIRELESS_EXT > 17 3086 3087 if (wrqu->data.length == sizeof(struct iw_scan_req)) { 3088 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { 3089 struct iw_scan_req *req = (struct iw_scan_req *)extra; 3090 if (g_first_broadcast_scan != BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { 3091 WL_TRACE(("%s Ignoring SC %s first BC is not done = %d\n", \ 3092 __FUNCTION__, req->essid, \ 3093 g_first_broadcast_scan)); 3094 return -EBUSY; 3095 } 3096 if (g_scan_specified_ssid) { 3097 WL_TRACE(("%s Specific SCAN is not done ignore scan for = %s \n", \ 3098 __FUNCTION__, req->essid)); 3099 return -EBUSY; 3100 } 3101 else { 3102 g_specific_ssid.SSID_len = MIN(sizeof(g_specific_ssid.SSID), \ 3103 req->essid_len); 3104 memcpy(g_specific_ssid.SSID, req->essid, g_specific_ssid.SSID_len); 3105 g_specific_ssid.SSID_len = htod32(g_specific_ssid.SSID_len); 3106 g_scan_specified_ssid = 1; 3107 WL_TRACE(("### Specific scan ssid=%s len=%d\n", \ 3108 g_specific_ssid.SSID, g_specific_ssid.SSID_len)); 3109 } 3110 } 3111 } 3112 #endif 3113 3114 if ((error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)))) { 3115 WL_TRACE(("#### Set SCAN for %s failed with %d\n", g_specific_ssid.SSID, error)); 3116 g_scan_specified_ssid = 0; 3117 return -EBUSY; 3118 } 3119 3120 return 0; 3121 } 3122 3123 #ifdef WL_IW_USE_ISCAN 3124 int 3125 wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) 3126 { 3127 wlc_ssid_t ssid; 3128 iscan_info_t *iscan = g_iscan; 3129 3130 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_IDLE) { 3131 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_STARTED; 3132 WL_TRACE(("%s: First Brodcast scan was forced\n", __FUNCTION__)); 3133 } 3134 else if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) { 3135 WL_TRACE(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__)); 3136 return 0; 3137 } 3138 3139 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 3140 if (flag) 3141 rtnl_lock(); 3142 #endif 3143 3144 dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &iscan->scan_flag, sizeof(iscan->scan_flag)); 3145 wl_iw_set_event_mask(dev); 3146 3147 WL_TRACE(("+++: Set Broadcast ISCAN\n")); 3148 3149 memset(&ssid, 0, sizeof(ssid)); 3150 3151 iscan->list_cur = iscan->list_hdr; 3152 iscan->iscan_state = ISCAN_STATE_SCANING; 3153 3154 memset(&iscan->iscan_ex_params_p->params, 0, iscan->iscan_ex_param_size); 3155 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid); 3156 wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START); 3157 3158 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 3159 if (flag) 3160 rtnl_unlock(); 3161 #endif 3162 3163 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); 3164 3165 iscan->timer_on = 1; 3166 3167 return 0; 3168 } 3169 3170 static int 3171 wl_iw_iscan_set_scan( 3172 struct net_device *dev, 3173 struct iw_request_info *info, 3174 union iwreq_data *wrqu, 3175 char *extra 3176 ) 3177 { 3178 wlc_ssid_t ssid; 3179 iscan_info_t *iscan = g_iscan; 3180 int ret = 0; 3181 3182 WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev->name)); 3183 3184 #if defined(CSCAN) 3185 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__)); 3186 return -EINVAL; 3187 #endif 3188 3189 net_os_wake_lock(dev); 3190 3191 #if defined(SOFTAP) 3192 if (ap_cfg_running) { 3193 WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); 3194 goto set_scan_end; 3195 } 3196 #endif 3197 3198 if (g_onoff == G_WLAN_SET_OFF) { 3199 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); 3200 goto set_scan_end; 3201 } 3202 3203 #ifdef PNO_SUPPORT 3204 if (dhd_dev_get_pno_status(dev)) { 3205 WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__)); 3206 } 3207 #endif 3208 3209 if ((!iscan) || (iscan->sysioc_pid < 0)) { 3210 WL_ERROR(("%s error\n", __FUNCTION__)); 3211 goto set_scan_end; 3212 } 3213 3214 if (g_scan_specified_ssid) { 3215 WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n", \ 3216 __FUNCTION__)); 3217 ret = EBUSY; 3218 goto set_scan_end; 3219 } 3220 3221 memset(&ssid, 0, sizeof(ssid)); 3222 3223 #if WIRELESS_EXT > 17 3224 3225 if (wrqu->data.length == sizeof(struct iw_scan_req)) { 3226 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { 3227 int as = 0; 3228 struct iw_scan_req *req = (struct iw_scan_req *)extra; 3229 ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); 3230 memcpy(ssid.SSID, req->essid, ssid.SSID_len); 3231 ssid.SSID_len = htod32(ssid.SSID_len); 3232 dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as)); 3233 wl_iw_set_event_mask(dev); 3234 ret = wl_iw_set_scan(dev, info, wrqu, extra); 3235 goto set_scan_end; 3236 } 3237 else { 3238 g_scan_specified_ssid = 0; 3239 3240 if (iscan->iscan_state == ISCAN_STATE_SCANING) { 3241 WL_TRACE(("%s ISCAN already in progress \n", __FUNCTION__)); 3242 goto set_scan_end; 3243 } 3244 } 3245 } 3246 #endif 3247 3248 #if !defined(CSCAN) 3249 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { 3250 if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) { 3251 3252 WL_ERROR(("%s Clean up First scan flag which is %d\n", \ 3253 __FUNCTION__, g_first_broadcast_scan)); 3254 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; 3255 } 3256 else { 3257 WL_ERROR(("%s Ignoring Broadcast Scan:First Scan is not done yet %d\n", \ 3258 __FUNCTION__, g_first_counter_scans)); 3259 ret = -EBUSY; 3260 goto set_scan_end; 3261 } 3262 } 3263 #endif 3264 3265 wl_iw_iscan_set_scan_broadcast_prep(dev, 0); 3266 3267 set_scan_end: 3268 net_os_wake_unlock(dev); 3269 return ret; 3270 } 3271 #endif 3272 3273 #if WIRELESS_EXT > 17 3274 static bool 3275 ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len) 3276 { 3277 uint8 *ie = *wpaie; 3278 3279 if ((ie[1] >= 6) && 3280 !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) { 3281 return TRUE; 3282 } 3283 3284 ie += ie[1] + 2; 3285 3286 *tlvs_len -= (int)(ie - *tlvs); 3287 3288 *tlvs = ie; 3289 return FALSE; 3290 } 3291 3292 static bool 3293 ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len) 3294 { 3295 uint8 *ie = *wpsie; 3296 3297 if ((ie[1] >= 4) && 3298 !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) { 3299 return TRUE; 3300 } 3301 3302 ie += ie[1] + 2; 3303 3304 *tlvs_len -= (int)(ie - *tlvs); 3305 3306 *tlvs = ie; 3307 return FALSE; 3308 } 3309 #endif 3310 3311 static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, 3312 size_t len, int uppercase) 3313 { 3314 size_t i; 3315 char *pos = buf, *end = buf + buf_size; 3316 int ret; 3317 if (buf_size == 0) 3318 return 0; 3319 for (i = 0; i < len; i++) { 3320 ret = snprintf(pos, end - pos, uppercase ? "%02X" : "%02x", 3321 data[i]); 3322 if (ret < 0 || ret >= end - pos) { 3323 end[-1] = '\0'; 3324 return pos - buf; 3325 } 3326 pos += ret; 3327 } 3328 end[-1] = '\0'; 3329 return pos - buf; 3330 } 3331 3332 3333 int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) 3334 { 3335 return _wpa_snprintf_hex(buf, buf_size, data, len, 0); 3336 } 3337 3338 static int 3339 wl_iw_handle_scanresults_ies(char **event_p, char *end, 3340 struct iw_request_info *info, wl_bss_info_t *bi) 3341 { 3342 #if WIRELESS_EXT > 17 3343 struct iw_event iwe; 3344 char *event; 3345 char *buf; 3346 int custom_event_len; 3347 3348 event = *event_p; 3349 if (bi->ie_length) { 3350 3351 bcm_tlv_t *ie; 3352 uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); 3353 int ptr_len = bi->ie_length; 3354 3355 #ifdef BCMWPA2 3356 if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) { 3357 iwe.cmd = IWEVGENIE; 3358 iwe.u.data.length = ie->len + 2; 3359 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); 3360 } 3361 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); 3362 #endif 3363 3364 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { 3365 3366 if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) { 3367 iwe.cmd = IWEVGENIE; 3368 iwe.u.data.length = ie->len + 2; 3369 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); 3370 break; 3371 } 3372 } 3373 3374 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); 3375 ptr_len = bi->ie_length; 3376 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { 3377 if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) { 3378 iwe.cmd = IWEVGENIE; 3379 iwe.u.data.length = ie->len + 2; 3380 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); 3381 break; 3382 } 3383 } 3384 3385 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); 3386 ptr_len = bi->ie_length; 3387 3388 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WAPI_ID))) { 3389 WL_TRACE(("%s: found a WAPI IE...\n", __FUNCTION__)); 3390 #ifdef WAPI_IE_USE_GENIE 3391 iwe.cmd = IWEVGENIE; 3392 iwe.u.data.length = ie->len + 2; 3393 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); 3394 #else 3395 iwe.cmd = IWEVCUSTOM; 3396 custom_event_len = strlen("wapi_ie=") + 2*(ie->len + 2); 3397 iwe.u.data.length = custom_event_len; 3398 3399 buf = kmalloc(custom_event_len+1, GFP_KERNEL); 3400 if (buf == NULL) 3401 { 3402 WL_ERROR(("malloc(%d) returned NULL...\n", custom_event_len)); 3403 break; 3404 } 3405 3406 memcpy(buf, "wapi_ie=", 8); 3407 wpa_snprintf_hex(buf + 8, 2+1, &(ie->id), 1); 3408 wpa_snprintf_hex(buf + 10, 2+1, &(ie->len), 1); 3409 wpa_snprintf_hex(buf + 12, 2*ie->len+1, ie->data, ie->len); 3410 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, buf); 3411 #endif 3412 break; 3413 } 3414 *event_p = event; 3415 } 3416 #endif 3417 3418 return 0; 3419 } 3420 3421 #ifndef CSCAN 3422 static uint 3423 wl_iw_get_scan_prep( 3424 wl_scan_results_t *list, 3425 struct iw_request_info *info, 3426 char *extra, 3427 short max_size) 3428 { 3429 int i, j; 3430 struct iw_event iwe; 3431 wl_bss_info_t *bi = NULL; 3432 char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value; 3433 int ret = 0; 3434 3435 ASSERT(list); 3436 3437 for (i = 0; i < list->count && i < IW_MAX_AP; i++) 3438 { 3439 if (list->version != WL_BSS_INFO_VERSION) { 3440 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ 3441 __FUNCTION__, list->version)); 3442 return ret; 3443 } 3444 3445 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; 3446 3447 WL_TRACE(("%s : %s\n", __FUNCTION__, bi->SSID)); 3448 3449 iwe.cmd = SIOCGIWAP; 3450 iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 3451 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); 3452 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); 3453 3454 iwe.u.data.length = dtoh32(bi->SSID_len); 3455 iwe.cmd = SIOCGIWESSID; 3456 iwe.u.data.flags = 1; 3457 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); 3458 3459 3460 if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { 3461 iwe.cmd = SIOCGIWMODE; 3462 if (dtoh16(bi->capability) & DOT11_CAP_ESS) 3463 iwe.u.mode = IW_MODE_INFRA; 3464 else 3465 iwe.u.mode = IW_MODE_ADHOC; 3466 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); 3467 } 3468 3469 3470 iwe.cmd = SIOCGIWFREQ; 3471 iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), 3472 CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? 3473 WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); 3474 iwe.u.freq.e = 6; 3475 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); 3476 3477 3478 iwe.cmd = IWEVQUAL; 3479 iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); 3480 iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); 3481 iwe.u.qual.noise = 0x100 + bi->phy_noise; 3482 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); 3483 3484 wl_iw_handle_scanresults_ies(&event, end, info, bi); 3485 3486 iwe.cmd = SIOCGIWENCODE; 3487 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) 3488 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; 3489 else 3490 iwe.u.data.flags = IW_ENCODE_DISABLED; 3491 iwe.u.data.length = 0; 3492 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); 3493 3494 3495 if (bi->rateset.count) { 3496 if (((event -extra) + IW_EV_LCP_LEN) <= (uintptr)end) { 3497 value = event + IW_EV_LCP_LEN; 3498 iwe.cmd = SIOCGIWRATE; 3499 3500 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; 3501 for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { 3502 iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; 3503 value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, 3504 IW_EV_PARAM_LEN); 3505 } 3506 event = value; 3507 } 3508 } 3509 } 3510 3511 if ((ret = (event - extra)) < 0) { 3512 WL_ERROR(("==> Wrong size\n")); 3513 ret = 0; 3514 } 3515 WL_TRACE(("%s: size=%d bytes prepared \n", __FUNCTION__, (unsigned int)(event - extra))); 3516 return (uint)ret; 3517 } 3518 3519 static int 3520 wl_iw_get_scan( 3521 struct net_device *dev, 3522 struct iw_request_info *info, 3523 struct iw_point *dwrq, 3524 char *extra 3525 ) 3526 { 3527 channel_info_t ci; 3528 wl_scan_results_t *list_merge; 3529 wl_scan_results_t *list = (wl_scan_results_t *) g_scan; 3530 int error; 3531 uint buflen_from_user = dwrq->length; 3532 uint len = G_SCAN_RESULTS; 3533 __u16 len_ret = 0; 3534 #if !defined(CSCAN) 3535 __u16 merged_len = 0; 3536 #endif 3537 #if defined(WL_IW_USE_ISCAN) 3538 iscan_info_t *iscan = g_iscan; 3539 iscan_buf_t * p_buf; 3540 #if !defined(CSCAN) 3541 uint32 counter = 0; 3542 #endif 3543 #endif 3544 WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user)); 3545 3546 if (!extra) { 3547 WL_TRACE(("%s: wl_iw_get_scan return -EINVAL\n", dev->name)); 3548 return -EINVAL; 3549 } 3550 3551 3552 if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) 3553 return error; 3554 ci.scan_channel = dtoh32(ci.scan_channel); 3555 if (ci.scan_channel) 3556 return -EAGAIN; 3557 3558 #if !defined(CSCAN) 3559 if (g_ss_cache_ctrl.m_timer_expired) { 3560 wl_iw_free_ss_cache(); 3561 g_ss_cache_ctrl.m_timer_expired ^= 1; 3562 } 3563 if ((!g_scan_specified_ssid && g_ss_cache_ctrl.m_prev_scan_mode) || 3564 g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) { 3565 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0; 3566 3567 wl_iw_reset_ss_cache(); 3568 } 3569 g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid; 3570 if (g_scan_specified_ssid) { 3571 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0; 3572 } 3573 else { 3574 g_ss_cache_ctrl.m_cons_br_scan_cnt++; 3575 } 3576 #endif 3577 3578 if (g_scan_specified_ssid) { 3579 3580 list = kmalloc(len, GFP_KERNEL); 3581 if (!list) { 3582 WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n", dev->name)); 3583 g_scan_specified_ssid = 0; 3584 return -ENOMEM; 3585 } 3586 } 3587 3588 memset(list, 0, len); 3589 list->buflen = htod32(len); 3590 if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len))) { 3591 WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, error)); 3592 dwrq->length = len; 3593 if (g_scan_specified_ssid) { 3594 g_scan_specified_ssid = 0; 3595 kfree(list); 3596 } 3597 return 0; 3598 } 3599 list->buflen = dtoh32(list->buflen); 3600 list->version = dtoh32(list->version); 3601 list->count = dtoh32(list->count); 3602 3603 if (list->version != WL_BSS_INFO_VERSION) { 3604 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", 3605 __FUNCTION__, list->version)); 3606 if (g_scan_specified_ssid) { 3607 g_scan_specified_ssid = 0; 3608 kfree(list); 3609 } 3610 return -EINVAL; 3611 } 3612 3613 #if !defined(CSCAN) 3614 if (g_scan_specified_ssid) { 3615 3616 wl_iw_add_bss_to_ss_cache(list); 3617 kfree(list); 3618 } 3619 3620 mutex_lock(&wl_cache_lock); 3621 #if defined(WL_IW_USE_ISCAN) 3622 if (g_scan_specified_ssid) 3623 WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count)); 3624 p_buf = iscan->list_hdr; 3625 3626 while (p_buf != iscan->list_cur) { 3627 list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; 3628 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count)); 3629 counter += list_merge->count; 3630 if (list_merge->count > 0) 3631 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, 3632 extra+len_ret, buflen_from_user -len_ret); 3633 p_buf = p_buf->next; 3634 } 3635 WL_TRACE(("%s merged with total Bcast APs=%d\n", __FUNCTION__, counter)); 3636 #else 3637 list_merge = (wl_scan_results_t *) g_scan; 3638 len_ret = (__u16) wl_iw_get_scan_prep(list_merge, info, extra, buflen_from_user); 3639 #endif 3640 mutex_unlock(&wl_cache_lock); 3641 if (g_ss_cache_ctrl.m_link_down) { 3642 wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid); 3643 } 3644 3645 wl_iw_merge_scan_cache(info, extra+len_ret, buflen_from_user-len_ret, &merged_len); 3646 len_ret += merged_len; 3647 wl_iw_run_ss_cache_timer(0); 3648 wl_iw_run_ss_cache_timer(1); 3649 #else 3650 3651 if (g_scan_specified_ssid) { 3652 WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count)); 3653 len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user); 3654 kfree(list); 3655 3656 #if defined(WL_IW_USE_ISCAN) 3657 p_buf = iscan->list_hdr; 3658 3659 while (p_buf != iscan->list_cur) { 3660 list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; 3661 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count)); 3662 if (list_merge->count > 0) 3663 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, 3664 extra+len_ret, buflen_from_user -len_ret); 3665 p_buf = p_buf->next; 3666 } 3667 #else 3668 list_merge = (wl_scan_results_t *) g_scan; 3669 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count)); 3670 if (list_merge->count > 0) 3671 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, extra+len_ret, 3672 buflen_from_user -len_ret); 3673 #endif 3674 } 3675 else { 3676 list = (wl_scan_results_t *) g_scan; 3677 len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user); 3678 } 3679 #endif 3680 3681 #if defined(WL_IW_USE_ISCAN) 3682 3683 g_scan_specified_ssid = 0; 3684 #endif 3685 3686 if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user) 3687 len = len_ret; 3688 3689 dwrq->length = len; 3690 dwrq->flags = 0; 3691 3692 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, list->count)); 3693 return 0; 3694 } 3695 #endif 3696 3697 #if defined(WL_IW_USE_ISCAN) 3698 static int 3699 wl_iw_iscan_get_scan( 3700 struct net_device *dev, 3701 struct iw_request_info *info, 3702 struct iw_point *dwrq, 3703 char *extra 3704 ) 3705 { 3706 wl_scan_results_t *list; 3707 struct iw_event iwe; 3708 wl_bss_info_t *bi = NULL; 3709 int ii, j; 3710 int apcnt; 3711 char *event = extra, *end = extra + dwrq->length, *value; 3712 iscan_info_t *iscan = g_iscan; 3713 iscan_buf_t * p_buf; 3714 uint32 counter = 0; 3715 uint8 channel; 3716 #if !defined(CSCAN) 3717 __u16 merged_len = 0; 3718 uint buflen_from_user = dwrq->length; 3719 #endif 3720 3721 WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length)); 3722 3723 #if defined(SOFTAP) 3724 if (ap_cfg_running) { 3725 WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); 3726 return -EINVAL; 3727 } 3728 #endif 3729 3730 if (!extra) { 3731 WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n", dev->name)); 3732 return -EINVAL; 3733 } 3734 3735 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) { 3736 WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n", \ 3737 dev->name, __FUNCTION__)); 3738 return -EAGAIN; 3739 } 3740 3741 if ((!iscan) || (iscan->sysioc_pid < 0)) { 3742 WL_ERROR(("%ssysioc_pid\n", __FUNCTION__)); 3743 return -EAGAIN; 3744 } 3745 3746 #if !defined(CSCAN) 3747 if (g_ss_cache_ctrl.m_timer_expired) { 3748 wl_iw_free_ss_cache(); 3749 g_ss_cache_ctrl.m_timer_expired ^= 1; 3750 } 3751 if (g_scan_specified_ssid) { 3752 return wl_iw_get_scan(dev, info, dwrq, extra); 3753 } 3754 else { 3755 if (g_ss_cache_ctrl.m_link_down) { 3756 wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid); 3757 } 3758 if (g_ss_cache_ctrl.m_prev_scan_mode || g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) { 3759 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0; 3760 3761 wl_iw_reset_ss_cache(); 3762 } 3763 g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid; 3764 g_ss_cache_ctrl.m_cons_br_scan_cnt++; 3765 } 3766 #endif 3767 3768 WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name)); 3769 apcnt = 0; 3770 p_buf = iscan->list_hdr; 3771 3772 while (p_buf != iscan->list_cur) { 3773 list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; 3774 3775 counter += list->count; 3776 3777 if (list->version != WL_BSS_INFO_VERSION) { 3778 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", 3779 __FUNCTION__, list->version)); 3780 return -EINVAL; 3781 } 3782 3783 bi = NULL; 3784 for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) { 3785 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; 3786 ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + 3787 WLC_IW_ISCAN_MAXLEN)); 3788 3789 3790 if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + 3791 IW_EV_QUAL_LEN >= end) 3792 return -E2BIG; 3793 3794 iwe.cmd = SIOCGIWAP; 3795 iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 3796 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); 3797 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); 3798 3799 3800 iwe.u.data.length = dtoh32(bi->SSID_len); 3801 iwe.cmd = SIOCGIWESSID; 3802 iwe.u.data.flags = 1; 3803 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); 3804 3805 3806 if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { 3807 iwe.cmd = SIOCGIWMODE; 3808 if (dtoh16(bi->capability) & DOT11_CAP_ESS) 3809 iwe.u.mode = IW_MODE_INFRA; 3810 else 3811 iwe.u.mode = IW_MODE_ADHOC; 3812 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); 3813 } 3814 3815 3816 iwe.cmd = SIOCGIWFREQ; 3817 channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch; 3818 iwe.u.freq.m = wf_channel2mhz(channel, 3819 channel <= CH_MAX_2G_CHANNEL ? 3820 WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); 3821 iwe.u.freq.e = 6; 3822 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); 3823 3824 3825 iwe.cmd = IWEVQUAL; 3826 iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); 3827 iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); 3828 iwe.u.qual.noise = 0x100 + bi->phy_noise; 3829 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); 3830 3831 3832 wl_iw_handle_scanresults_ies(&event, end, info, bi); 3833 3834 3835 iwe.cmd = SIOCGIWENCODE; 3836 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) 3837 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; 3838 else 3839 iwe.u.data.flags = IW_ENCODE_DISABLED; 3840 iwe.u.data.length = 0; 3841 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); 3842 3843 3844 if (bi->rateset.count) { 3845 if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) 3846 return -E2BIG; 3847 3848 value = event + IW_EV_LCP_LEN; 3849 iwe.cmd = SIOCGIWRATE; 3850 3851 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; 3852 for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { 3853 iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; 3854 value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, 3855 IW_EV_PARAM_LEN); 3856 } 3857 event = value; 3858 } 3859 } 3860 p_buf = p_buf->next; 3861 } 3862 3863 dwrq->length = event - extra; 3864 dwrq->flags = 0; 3865 3866 #if !defined(CSCAN) 3867 wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len); 3868 dwrq->length += merged_len; 3869 wl_iw_run_ss_cache_timer(0); 3870 wl_iw_run_ss_cache_timer(1); 3871 #endif /* CSCAN */ 3872 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; 3873 3874 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter)); 3875 3876 return 0; 3877 } 3878 #endif 3879 3880 static int 3881 wl_iw_set_essid( 3882 struct net_device *dev, 3883 struct iw_request_info *info, 3884 struct iw_point *dwrq, 3885 char *extra 3886 ) 3887 { 3888 int error; 3889 wl_join_params_t join_params; 3890 int join_params_size; 3891 3892 WL_TRACE(("%s: SIOCSIWESSID\n", dev->name)); 3893 3894 3895 memset(&g_ssid, 0, sizeof(g_ssid)); 3896 3897 CHECK_EXTRA_FOR_NULL(extra); 3898 3899 if (dwrq->length && extra) { 3900 #if WIRELESS_EXT > 20 3901 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length); 3902 #else 3903 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length-1); 3904 #endif 3905 memcpy(g_ssid.SSID, extra, g_ssid.SSID_len); 3906 } else { 3907 3908 g_ssid.SSID_len = 0; 3909 } 3910 g_ssid.SSID_len = htod32(g_ssid.SSID_len); 3911 3912 memset(&join_params, 0, sizeof(join_params)); 3913 join_params_size = sizeof(join_params.ssid); 3914 3915 memcpy(&join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len); 3916 join_params.ssid.SSID_len = htod32(g_ssid.SSID_len); 3917 memcpy(&join_params.params.bssid, ðer_bcast, ETHER_ADDR_LEN); 3918 3919 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size); 3920 3921 if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) { 3922 WL_ERROR(("Invalid ioctl data=%d\n", error)); 3923 return error; 3924 } 3925 3926 if (g_ssid.SSID_len) { 3927 WL_TRACE(("%s: join SSID=%s ch=%d\n", __FUNCTION__, \ 3928 g_ssid.SSID, g_wl_iw_params.target_channel)); 3929 } 3930 return 0; 3931 } 3932 3933 static int 3934 wl_iw_get_essid( 3935 struct net_device *dev, 3936 struct iw_request_info *info, 3937 struct iw_point *dwrq, 3938 char *extra 3939 ) 3940 { 3941 wlc_ssid_t ssid; 3942 int error; 3943 3944 WL_TRACE(("%s: SIOCGIWESSID\n", dev->name)); 3945 3946 if (!extra) 3947 return -EINVAL; 3948 3949 if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) { 3950 WL_ERROR(("Error getting the SSID\n")); 3951 return error; 3952 } 3953 3954 ssid.SSID_len = dtoh32(ssid.SSID_len); 3955 3956 memcpy(extra, ssid.SSID, ssid.SSID_len); 3957 3958 dwrq->length = ssid.SSID_len; 3959 3960 dwrq->flags = 1; 3961 3962 return 0; 3963 } 3964 3965 static int 3966 wl_iw_set_nick( 3967 struct net_device *dev, 3968 struct iw_request_info *info, 3969 struct iw_point *dwrq, 3970 char *extra 3971 ) 3972 { 3973 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); 3974 3975 WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name)); 3976 3977 if (!extra) 3978 return -EINVAL; 3979 3980 if (dwrq->length > sizeof(iw->nickname)) 3981 return -E2BIG; 3982 3983 memcpy(iw->nickname, extra, dwrq->length); 3984 iw->nickname[dwrq->length - 1] = '\0'; 3985 3986 return 0; 3987 } 3988 3989 static int 3990 wl_iw_get_nick( 3991 struct net_device *dev, 3992 struct iw_request_info *info, 3993 struct iw_point *dwrq, 3994 char *extra 3995 ) 3996 { 3997 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); 3998 3999 WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name)); 4000 4001 if (!extra) 4002 return -EINVAL; 4003 4004 strcpy(extra, iw->nickname); 4005 dwrq->length = strlen(extra) + 1; 4006 4007 return 0; 4008 } 4009 4010 static int wl_iw_set_rate( 4011 struct net_device *dev, 4012 struct iw_request_info *info, 4013 struct iw_param *vwrq, 4014 char *extra 4015 ) 4016 { 4017 wl_rateset_t rateset; 4018 int error, rate, i, error_bg, error_a; 4019 4020 WL_TRACE(("%s: SIOCSIWRATE\n", dev->name)); 4021 4022 4023 if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) 4024 return error; 4025 4026 rateset.count = dtoh32(rateset.count); 4027 4028 if (vwrq->value < 0) { 4029 4030 rate = rateset.rates[rateset.count - 1] & 0x7f; 4031 } else if (vwrq->value < rateset.count) { 4032 4033 rate = rateset.rates[vwrq->value] & 0x7f; 4034 } else { 4035 4036 rate = vwrq->value / 500000; 4037 } 4038 4039 if (vwrq->fixed) { 4040 4041 error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate); 4042 error_a = dev_wlc_intvar_set(dev, "a_rate", rate); 4043 4044 if (error_bg && error_a) 4045 return (error_bg | error_a); 4046 } else { 4047 4048 4049 error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0); 4050 4051 error_a = dev_wlc_intvar_set(dev, "a_rate", 0); 4052 4053 if (error_bg && error_a) 4054 return (error_bg | error_a); 4055 4056 4057 for (i = 0; i < rateset.count; i++) 4058 if ((rateset.rates[i] & 0x7f) > rate) 4059 break; 4060 rateset.count = htod32(i); 4061 4062 4063 if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset)))) 4064 return error; 4065 } 4066 4067 return 0; 4068 } 4069 4070 static int wl_iw_get_rate( 4071 struct net_device *dev, 4072 struct iw_request_info *info, 4073 struct iw_param *vwrq, 4074 char *extra 4075 ) 4076 { 4077 int error, rate; 4078 4079 WL_TRACE(("%s: SIOCGIWRATE\n", dev->name)); 4080 4081 4082 if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)))) 4083 return error; 4084 rate = dtoh32(rate); 4085 vwrq->value = rate * 500000; 4086 4087 return 0; 4088 } 4089 4090 static int 4091 wl_iw_set_rts( 4092 struct net_device *dev, 4093 struct iw_request_info *info, 4094 struct iw_param *vwrq, 4095 char *extra 4096 ) 4097 { 4098 int error, rts; 4099 4100 WL_TRACE(("%s: SIOCSIWRTS\n", dev->name)); 4101 4102 if (vwrq->disabled) 4103 rts = DOT11_DEFAULT_RTS_LEN; 4104 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN) 4105 return -EINVAL; 4106 else 4107 rts = vwrq->value; 4108 4109 if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts))) 4110 return error; 4111 4112 return 0; 4113 } 4114 4115 static int 4116 wl_iw_get_rts( 4117 struct net_device *dev, 4118 struct iw_request_info *info, 4119 struct iw_param *vwrq, 4120 char *extra 4121 ) 4122 { 4123 int error, rts; 4124 4125 WL_TRACE(("%s: SIOCGIWRTS\n", dev->name)); 4126 4127 if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts))) 4128 return error; 4129 4130 vwrq->value = rts; 4131 vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN); 4132 vwrq->fixed = 1; 4133 4134 return 0; 4135 } 4136 4137 static int 4138 wl_iw_set_frag( 4139 struct net_device *dev, 4140 struct iw_request_info *info, 4141 struct iw_param *vwrq, 4142 char *extra 4143 ) 4144 { 4145 int error, frag; 4146 4147 WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name)); 4148 4149 if (vwrq->disabled) 4150 frag = DOT11_DEFAULT_FRAG_LEN; 4151 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN) 4152 return -EINVAL; 4153 else 4154 frag = vwrq->value; 4155 4156 if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag))) 4157 return error; 4158 4159 return 0; 4160 } 4161 4162 static int 4163 wl_iw_get_frag( 4164 struct net_device *dev, 4165 struct iw_request_info *info, 4166 struct iw_param *vwrq, 4167 char *extra 4168 ) 4169 { 4170 int error, fragthreshold; 4171 4172 WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name)); 4173 4174 if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold))) 4175 return error; 4176 4177 vwrq->value = fragthreshold; 4178 vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN); 4179 vwrq->fixed = 1; 4180 4181 return 0; 4182 } 4183 4184 static int 4185 wl_iw_set_txpow( 4186 struct net_device *dev, 4187 struct iw_request_info *info, 4188 struct iw_param *vwrq, 4189 char *extra 4190 ) 4191 { 4192 int error, disable; 4193 uint16 txpwrmw; 4194 WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name)); 4195 4196 4197 disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0; 4198 disable += WL_RADIO_SW_DISABLE << 16; 4199 4200 disable = htod32(disable); 4201 if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable)))) 4202 return error; 4203 4204 4205 if (disable & WL_RADIO_SW_DISABLE) 4206 return 0; 4207 4208 4209 if (!(vwrq->flags & IW_TXPOW_MWATT)) 4210 return -EINVAL; 4211 4212 4213 if (vwrq->value < 0) 4214 return 0; 4215 4216 if (vwrq->value > 0xffff) txpwrmw = 0xffff; 4217 else txpwrmw = (uint16)vwrq->value; 4218 4219 4220 error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw))); 4221 return error; 4222 } 4223 4224 static int 4225 wl_iw_get_txpow( 4226 struct net_device *dev, 4227 struct iw_request_info *info, 4228 struct iw_param *vwrq, 4229 char *extra 4230 ) 4231 { 4232 int error, disable, txpwrdbm; 4233 uint8 result; 4234 4235 WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name)); 4236 4237 if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) || 4238 (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm))) 4239 return error; 4240 4241 disable = dtoh32(disable); 4242 result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE); 4243 vwrq->value = (int32)bcm_qdbm_to_mw(result); 4244 vwrq->fixed = 0; 4245 vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0; 4246 vwrq->flags = IW_TXPOW_MWATT; 4247 4248 return 0; 4249 } 4250 4251 #if WIRELESS_EXT > 10 4252 static int 4253 wl_iw_set_retry( 4254 struct net_device *dev, 4255 struct iw_request_info *info, 4256 struct iw_param *vwrq, 4257 char *extra 4258 ) 4259 { 4260 int error, lrl, srl; 4261 4262 WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name)); 4263 4264 4265 if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME)) 4266 return -EINVAL; 4267 4268 4269 if (vwrq->flags & IW_RETRY_LIMIT) { 4270 4271 4272 #if WIRELESS_EXT > 20 4273 if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) || 4274 !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) { 4275 #else 4276 if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) { 4277 #endif 4278 lrl = htod32(vwrq->value); 4279 if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl)))) 4280 return error; 4281 } 4282 4283 4284 #if WIRELESS_EXT > 20 4285 if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) || 4286 !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) { 4287 #else 4288 if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) { 4289 #endif 4290 srl = htod32(vwrq->value); 4291 if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl)))) 4292 return error; 4293 } 4294 } 4295 return 0; 4296 } 4297 4298 static int 4299 wl_iw_get_retry( 4300 struct net_device *dev, 4301 struct iw_request_info *info, 4302 struct iw_param *vwrq, 4303 char *extra 4304 ) 4305 { 4306 int error, lrl, srl; 4307 4308 WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name)); 4309 4310 vwrq->disabled = 0; 4311 4312 4313 if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) 4314 return -EINVAL; 4315 4316 4317 if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) || 4318 (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl)))) 4319 return error; 4320 4321 lrl = dtoh32(lrl); 4322 srl = dtoh32(srl); 4323 4324 4325 if (vwrq->flags & IW_RETRY_MAX) { 4326 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; 4327 vwrq->value = lrl; 4328 } else { 4329 vwrq->flags = IW_RETRY_LIMIT; 4330 vwrq->value = srl; 4331 if (srl != lrl) 4332 vwrq->flags |= IW_RETRY_MIN; 4333 } 4334 4335 return 0; 4336 } 4337 #endif 4338 4339 static int 4340 wl_iw_set_encode( 4341 struct net_device *dev, 4342 struct iw_request_info *info, 4343 struct iw_point *dwrq, 4344 char *extra 4345 ) 4346 { 4347 wl_wsec_key_t key; 4348 int error, val, wsec; 4349 4350 WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name)); 4351 4352 memset(&key, 0, sizeof(key)); 4353 4354 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { 4355 4356 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { 4357 val = htod32(key.index); 4358 if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) 4359 return error; 4360 val = dtoh32(val); 4361 if (val) 4362 break; 4363 } 4364 4365 if (key.index == DOT11_MAX_DEFAULT_KEYS) 4366 key.index = 0; 4367 } else { 4368 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; 4369 if (key.index >= DOT11_MAX_DEFAULT_KEYS) 4370 return -EINVAL; 4371 } 4372 4373 4374 if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) { 4375 4376 val = htod32(key.index); 4377 if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val)))) 4378 return error; 4379 } else { 4380 key.len = dwrq->length; 4381 4382 if (dwrq->length > sizeof(key.data)) 4383 return -EINVAL; 4384 4385 memcpy(key.data, extra, dwrq->length); 4386 4387 key.flags = WL_PRIMARY_KEY; 4388 switch (key.len) { 4389 case WEP1_KEY_SIZE: 4390 key.algo = CRYPTO_ALGO_WEP1; 4391 break; 4392 case WEP128_KEY_SIZE: 4393 key.algo = CRYPTO_ALGO_WEP128; 4394 break; 4395 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) 4396 case TKIP_KEY_SIZE: 4397 key.algo = CRYPTO_ALGO_TKIP; 4398 break; 4399 #endif 4400 case AES_KEY_SIZE: 4401 key.algo = CRYPTO_ALGO_AES_CCM; 4402 break; 4403 default: 4404 return -EINVAL; 4405 } 4406 4407 4408 swap_key_from_BE(&key); 4409 if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)))) 4410 return error; 4411 } 4412 4413 4414 val = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED; 4415 4416 if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec))) 4417 return error; 4418 4419 wsec &= ~(WEP_ENABLED); 4420 wsec |= val; 4421 4422 if ((error = dev_wlc_intvar_set(dev, "wsec", wsec))) 4423 return error; 4424 4425 4426 val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0; 4427 val = htod32(val); 4428 if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)))) 4429 return error; 4430 4431 return 0; 4432 } 4433 4434 static int 4435 wl_iw_get_encode( 4436 struct net_device *dev, 4437 struct iw_request_info *info, 4438 struct iw_point *dwrq, 4439 char *extra 4440 ) 4441 { 4442 wl_wsec_key_t key; 4443 int error, val, wsec, auth; 4444 4445 WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name)); 4446 4447 4448 bzero(&key, sizeof(wl_wsec_key_t)); 4449 4450 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { 4451 4452 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { 4453 val = key.index; 4454 if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) 4455 return error; 4456 val = dtoh32(val); 4457 if (val) 4458 break; 4459 } 4460 } else 4461 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; 4462 4463 if (key.index >= DOT11_MAX_DEFAULT_KEYS) 4464 key.index = 0; 4465 4466 4467 4468 if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) || 4469 (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth)))) 4470 return error; 4471 4472 swap_key_to_BE(&key); 4473 4474 wsec = dtoh32(wsec); 4475 auth = dtoh32(auth); 4476 4477 dwrq->length = MIN(DOT11_MAX_KEY_SIZE, key.len); 4478 4479 4480 dwrq->flags = key.index + 1; 4481 if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) { 4482 4483 dwrq->flags |= IW_ENCODE_DISABLED; 4484 } 4485 if (auth) { 4486 4487 dwrq->flags |= IW_ENCODE_RESTRICTED; 4488 } 4489 4490 4491 if (dwrq->length && extra) 4492 memcpy(extra, key.data, dwrq->length); 4493 4494 return 0; 4495 } 4496 4497 static int 4498 wl_iw_set_power( 4499 struct net_device *dev, 4500 struct iw_request_info *info, 4501 struct iw_param *vwrq, 4502 char *extra 4503 ) 4504 { 4505 int error, pm; 4506 4507 WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name)); 4508 4509 pm = vwrq->disabled ? PM_OFF : PM_MAX; 4510 4511 pm = htod32(pm); 4512 if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)))) 4513 return error; 4514 4515 return 0; 4516 } 4517 4518 static int 4519 wl_iw_get_power( 4520 struct net_device *dev, 4521 struct iw_request_info *info, 4522 struct iw_param *vwrq, 4523 char *extra 4524 ) 4525 { 4526 int error, pm; 4527 4528 WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name)); 4529 4530 if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm)))) 4531 return error; 4532 4533 pm = dtoh32(pm); 4534 vwrq->disabled = pm ? 0 : 1; 4535 vwrq->flags = IW_POWER_ALL_R; 4536 4537 return 0; 4538 } 4539 4540 #if WIRELESS_EXT > 17 4541 static int 4542 wl_iw_set_wpaie( 4543 struct net_device *dev, 4544 struct iw_request_info *info, 4545 struct iw_point *iwp, 4546 char *extra 4547 ) 4548 { 4549 uchar buf[WLC_IOCTL_SMLEN] = {0}; 4550 uchar *p = buf; 4551 int wapi_ie_size; 4552 4553 WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name)); 4554 4555 CHECK_EXTRA_FOR_NULL(extra); 4556 4557 if (extra[0] == DOT11_MNG_WAPI_ID) 4558 { 4559 wapi_ie_size = iwp->length; 4560 memcpy(p, extra, iwp->length); 4561 dev_wlc_bufvar_set(dev, "wapiie", buf, wapi_ie_size); 4562 } 4563 else 4564 dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length); 4565 4566 return 0; 4567 } 4568 4569 static int 4570 wl_iw_get_wpaie( 4571 struct net_device *dev, 4572 struct iw_request_info *info, 4573 struct iw_point *iwp, 4574 char *extra 4575 ) 4576 { 4577 WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name)); 4578 iwp->length = 64; 4579 dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length); 4580 return 0; 4581 } 4582 4583 static int 4584 wl_iw_set_encodeext( 4585 struct net_device *dev, 4586 struct iw_request_info *info, 4587 struct iw_point *dwrq, 4588 char *extra 4589 ) 4590 { 4591 wl_wsec_key_t key; 4592 int error; 4593 struct iw_encode_ext *iwe; 4594 4595 WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name)); 4596 4597 CHECK_EXTRA_FOR_NULL(extra); 4598 4599 memset(&key, 0, sizeof(key)); 4600 iwe = (struct iw_encode_ext *)extra; 4601 4602 4603 if (dwrq->flags & IW_ENCODE_DISABLED) { 4604 4605 } 4606 4607 4608 key.index = 0; 4609 if (dwrq->flags & IW_ENCODE_INDEX) 4610 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; 4611 4612 key.len = iwe->key_len; 4613 4614 4615 if (!ETHER_ISMULTI(iwe->addr.sa_data)) 4616 bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN); 4617 4618 4619 if (key.len == 0) { 4620 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { 4621 WL_WSEC(("Changing the the primary Key to %d\n", key.index)); 4622 4623 key.index = htod32(key.index); 4624 error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, 4625 &key.index, sizeof(key.index)); 4626 if (error) 4627 return error; 4628 } 4629 4630 else { 4631 swap_key_from_BE(&key); 4632 dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); 4633 } 4634 } 4635 else { 4636 if (iwe->key_len > sizeof(key.data)) 4637 return -EINVAL; 4638 4639 WL_WSEC(("Setting the key index %d\n", key.index)); 4640 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { 4641 WL_WSEC(("key is a Primary Key\n")); 4642 key.flags = WL_PRIMARY_KEY; 4643 } 4644 4645 bcopy((void *)iwe->key, key.data, iwe->key_len); 4646 4647 if (iwe->alg == IW_ENCODE_ALG_TKIP) { 4648 uint8 keybuf[8]; 4649 bcopy(&key.data[24], keybuf, sizeof(keybuf)); 4650 bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); 4651 bcopy(keybuf, &key.data[16], sizeof(keybuf)); 4652 } 4653 4654 4655 if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { 4656 uchar *ivptr; 4657 ivptr = (uchar *)iwe->rx_seq; 4658 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | 4659 (ivptr[3] << 8) | ivptr[2]; 4660 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; 4661 key.iv_initialized = TRUE; 4662 } 4663 4664 switch (iwe->alg) { 4665 case IW_ENCODE_ALG_NONE: 4666 key.algo = CRYPTO_ALGO_OFF; 4667 break; 4668 case IW_ENCODE_ALG_WEP: 4669 if (iwe->key_len == WEP1_KEY_SIZE) 4670 key.algo = CRYPTO_ALGO_WEP1; 4671 else 4672 key.algo = CRYPTO_ALGO_WEP128; 4673 break; 4674 case IW_ENCODE_ALG_TKIP: 4675 key.algo = CRYPTO_ALGO_TKIP; 4676 break; 4677 case IW_ENCODE_ALG_CCMP: 4678 key.algo = CRYPTO_ALGO_AES_CCM; 4679 break; 4680 case IW_ENCODE_ALG_SM4: 4681 key.algo = CRYPTO_ALGO_SMS4; 4682 if (iwe->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { 4683 key.flags &= ~WL_PRIMARY_KEY; 4684 } 4685 break; 4686 default: 4687 break; 4688 } 4689 swap_key_from_BE(&key); 4690 4691 dhd_wait_pend8021x(dev); 4692 4693 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); 4694 if (error) 4695 return error; 4696 } 4697 return 0; 4698 } 4699 4700 #if WIRELESS_EXT > 17 4701 #ifdef BCMWPA2 4702 struct { 4703 pmkid_list_t pmkids; 4704 pmkid_t foo[MAXPMKID-1]; 4705 } pmkid_list; 4706 4707 static int 4708 wl_iw_set_pmksa( 4709 struct net_device *dev, 4710 struct iw_request_info *info, 4711 struct iw_param *vwrq, 4712 char *extra 4713 ) 4714 { 4715 struct iw_pmksa *iwpmksa; 4716 uint i; 4717 int ret = 0; 4718 char eabuf[ETHER_ADDR_STR_LEN]; 4719 4720 WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name)); 4721 CHECK_EXTRA_FOR_NULL(extra); 4722 4723 iwpmksa = (struct iw_pmksa *)extra; 4724 bzero((char *)eabuf, ETHER_ADDR_STR_LEN); 4725 4726 if (iwpmksa->cmd == IW_PMKSA_FLUSH) { 4727 WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n")); 4728 bzero((char *)&pmkid_list, sizeof(pmkid_list)); 4729 } 4730 4731 else if (iwpmksa->cmd == IW_PMKSA_REMOVE) { 4732 { 4733 pmkid_list_t pmkid, *pmkidptr; 4734 uint j; 4735 pmkidptr = &pmkid; 4736 4737 bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN); 4738 bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); 4739 4740 WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ", 4741 bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID, 4742 eabuf))); 4743 for (j = 0; j < WPA2_PMKID_LEN; j++) 4744 WL_WSEC(("%02x ", pmkidptr->pmkid[0].PMKID[j])); 4745 WL_WSEC(("\n")); 4746 } 4747 4748 for (i = 0; i < pmkid_list.pmkids.npmkid; i++) 4749 if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID, 4750 ETHER_ADDR_LEN)) 4751 break; 4752 4753 if ((pmkid_list.pmkids.npmkid > 0) && (i < pmkid_list.pmkids.npmkid)) { 4754 bzero(&pmkid_list.pmkids.pmkid[i], sizeof(pmkid_t)); 4755 for (; i < (pmkid_list.pmkids.npmkid - 1); i++) { 4756 bcopy(&pmkid_list.pmkids.pmkid[i+1].BSSID, 4757 &pmkid_list.pmkids.pmkid[i].BSSID, 4758 ETHER_ADDR_LEN); 4759 bcopy(&pmkid_list.pmkids.pmkid[i+1].PMKID, 4760 &pmkid_list.pmkids.pmkid[i].PMKID, 4761 WPA2_PMKID_LEN); 4762 } 4763 pmkid_list.pmkids.npmkid--; 4764 } 4765 else 4766 ret = -EINVAL; 4767 } 4768 4769 else if (iwpmksa->cmd == IW_PMKSA_ADD) { 4770 for (i = 0; i < pmkid_list.pmkids.npmkid; i++) 4771 if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID, 4772 ETHER_ADDR_LEN)) 4773 break; 4774 if (i < MAXPMKID) { 4775 bcopy(&iwpmksa->bssid.sa_data[0], 4776 &pmkid_list.pmkids.pmkid[i].BSSID, 4777 ETHER_ADDR_LEN); 4778 bcopy(&iwpmksa->pmkid[0], &pmkid_list.pmkids.pmkid[i].PMKID, 4779 WPA2_PMKID_LEN); 4780 if (i == pmkid_list.pmkids.npmkid) 4781 pmkid_list.pmkids.npmkid++; 4782 } 4783 else 4784 ret = -EINVAL; 4785 4786 { 4787 uint j; 4788 uint k; 4789 k = pmkid_list.pmkids.npmkid; 4790 WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ", 4791 bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[k].BSSID, 4792 eabuf))); 4793 for (j = 0; j < WPA2_PMKID_LEN; j++) 4794 WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j])); 4795 WL_WSEC(("\n")); 4796 } 4797 } 4798 WL_WSEC(("PRINTING pmkid LIST - No of elements %d, ret = %d\n", pmkid_list.pmkids.npmkid, ret)); 4799 for (i = 0; i < pmkid_list.pmkids.npmkid; i++) { 4800 uint j; 4801 WL_WSEC(("PMKID[%d]: %s = ", i, 4802 bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[i].BSSID, 4803 eabuf))); 4804 for (j = 0; j < WPA2_PMKID_LEN; j++) 4805 WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j])); 4806 WL_WSEC(("\n")); 4807 } 4808 WL_WSEC(("\n")); 4809 4810 if (!ret) 4811 ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list)); 4812 return ret; 4813 } 4814 #endif 4815 #endif 4816 4817 static int 4818 wl_iw_get_encodeext( 4819 struct net_device *dev, 4820 struct iw_request_info *info, 4821 struct iw_param *vwrq, 4822 char *extra 4823 ) 4824 { 4825 WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name)); 4826 return 0; 4827 } 4828 4829 static int 4830 wl_iw_set_wpaauth( 4831 struct net_device *dev, 4832 struct iw_request_info *info, 4833 struct iw_param *vwrq, 4834 char *extra 4835 ) 4836 { 4837 int error = 0; 4838 int paramid; 4839 int paramval; 4840 int val = 0; 4841 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); 4842 4843 WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name)); 4844 4845 #if defined(SOFTAP) 4846 if (ap_cfg_running) { 4847 WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); 4848 return 0; 4849 } 4850 #endif 4851 4852 paramid = vwrq->flags & IW_AUTH_INDEX; 4853 paramval = vwrq->value; 4854 4855 WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n", 4856 dev->name, paramid, paramval)); 4857 4858 switch (paramid) { 4859 case IW_AUTH_WPA_VERSION: 4860 4861 if (paramval & IW_AUTH_WPA_VERSION_DISABLED) 4862 val = WPA_AUTH_DISABLED; 4863 else if (paramval & (IW_AUTH_WPA_VERSION_WPA)) 4864 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; 4865 #ifdef BCMWPA2 4866 else if (paramval & IW_AUTH_WPA_VERSION_WPA2) 4867 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; 4868 #endif 4869 else if (paramval & IW_AUTH_WAPI_VERSION_1) 4870 val = WPA_AUTH_WAPI; 4871 WL_INFORM(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val)); 4872 if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) 4873 return error; 4874 break; 4875 case IW_AUTH_CIPHER_PAIRWISE: 4876 case IW_AUTH_CIPHER_GROUP: 4877 4878 4879 if (paramval & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) 4880 val = WEP_ENABLED; 4881 if (paramval & IW_AUTH_CIPHER_TKIP) 4882 val = TKIP_ENABLED; 4883 if (paramval & IW_AUTH_CIPHER_CCMP) 4884 val = AES_ENABLED; 4885 if (paramval & IW_AUTH_CIPHER_SMS4) 4886 val = SMS4_ENABLED; 4887 4888 if (paramid == IW_AUTH_CIPHER_PAIRWISE) { 4889 iw->pwsec = val; 4890 val |= iw->gwsec; 4891 } 4892 else { 4893 iw->gwsec = val; 4894 val |= iw->pwsec; 4895 } 4896 4897 if (iw->privacy_invoked && !val) { 4898 WL_WSEC(("%s: %s: 'Privacy invoked' TRUE but clearing wsec, assuming " 4899 "we're a WPS enrollee\n", dev->name, __FUNCTION__)); 4900 if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { 4901 WL_WSEC(("Failed to set iovar is_WPS_enrollee\n")); 4902 return error; 4903 } 4904 } else if (val) { 4905 if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { 4906 WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n")); 4907 return error; 4908 } 4909 } 4910 4911 if ((error = dev_wlc_intvar_set(dev, "wsec", val))) 4912 return error; 4913 4914 break; 4915 4916 case IW_AUTH_KEY_MGMT: 4917 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) 4918 return error; 4919 4920 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { 4921 if (paramval & IW_AUTH_KEY_MGMT_PSK) 4922 val = WPA_AUTH_PSK; 4923 else 4924 val = WPA_AUTH_UNSPECIFIED; 4925 } 4926 #ifdef BCMWPA2 4927 else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { 4928 if (paramval & IW_AUTH_KEY_MGMT_PSK) 4929 val = WPA2_AUTH_PSK; 4930 else 4931 val = WPA2_AUTH_UNSPECIFIED; 4932 } 4933 #endif 4934 if (paramval & (IW_AUTH_KEY_MGMT_WAPI_PSK | IW_AUTH_KEY_MGMT_WAPI_CERT)) 4935 val = WPA_AUTH_WAPI; 4936 WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); 4937 if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) 4938 return error; 4939 4940 break; 4941 case IW_AUTH_TKIP_COUNTERMEASURES: 4942 dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)¶mval, 1); 4943 break; 4944 4945 case IW_AUTH_80211_AUTH_ALG: 4946 4947 WL_INFORM(("Setting the D11auth %d\n", paramval)); 4948 if (paramval == IW_AUTH_ALG_OPEN_SYSTEM) 4949 val = 0; 4950 else if (paramval == IW_AUTH_ALG_SHARED_KEY) 4951 val = 1; 4952 else if (paramval == (IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY)) 4953 val = 2; 4954 else 4955 error = 1; 4956 if (!error && (error = dev_wlc_intvar_set(dev, "auth", val))) 4957 return error; 4958 break; 4959 4960 case IW_AUTH_WPA_ENABLED: 4961 if (paramval == 0) { 4962 iw->pwsec = 0; 4963 iw->gwsec = 0; 4964 if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) 4965 return error; 4966 if (val & (TKIP_ENABLED | AES_ENABLED)) { 4967 val &= ~(TKIP_ENABLED | AES_ENABLED); 4968 dev_wlc_intvar_set(dev, "wsec", val); 4969 } 4970 val = 0; 4971 WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); 4972 dev_wlc_intvar_set(dev, "wpa_auth", 0); 4973 return error; 4974 } 4975 4976 4977 break; 4978 4979 case IW_AUTH_DROP_UNENCRYPTED: 4980 dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)¶mval, 1); 4981 break; 4982 4983 case IW_AUTH_RX_UNENCRYPTED_EAPOL: 4984 dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); 4985 break; 4986 4987 #if WIRELESS_EXT > 17 4988 case IW_AUTH_ROAMING_CONTROL: 4989 WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__)); 4990 4991 break; 4992 case IW_AUTH_PRIVACY_INVOKED: { 4993 int wsec; 4994 4995 if (paramval == 0) { 4996 iw->privacy_invoked = FALSE; 4997 if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { 4998 WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n")); 4999 return error; 5000 } 5001 } else { 5002 iw->privacy_invoked = TRUE; 5003 if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec))) 5004 return error; 5005 5006 if (!(IW_WSEC_ENABLED(wsec))) { 5007 5008 if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { 5009 WL_WSEC(("Failed to set iovar is_WPS_enrollee\n")); 5010 return error; 5011 } 5012 } else { 5013 if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { 5014 WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n")); 5015 return error; 5016 } 5017 } 5018 } 5019 break; 5020 } 5021 #endif 5022 case IW_AUTH_WAPI_ENABLED: 5023 if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) 5024 return error; 5025 if (paramval) { 5026 val |= SMS4_ENABLED; 5027 if ((error = dev_wlc_intvar_set(dev, "wsec", val))) { 5028 WL_ERROR(("%s: setting wsec to 0x%0x returned error %d\n", 5029 __FUNCTION__, val, error)); 5030 return error; 5031 } 5032 if ((error = dev_wlc_intvar_set(dev, "wpa_auth", WPA_AUTH_WAPI))) { 5033 WL_ERROR(("%s: setting wpa_auth(WPA_AUTH_WAPI) returned %d\n", 5034 __FUNCTION__, error)); 5035 return error; 5036 } 5037 } 5038 5039 break; 5040 default: 5041 break; 5042 } 5043 return 0; 5044 } 5045 #ifdef BCMWPA2 5046 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK)) 5047 #else 5048 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK)) 5049 #endif 5050 5051 static int 5052 wl_iw_get_wpaauth( 5053 struct net_device *dev, 5054 struct iw_request_info *info, 5055 struct iw_param *vwrq, 5056 char *extra 5057 ) 5058 { 5059 int error; 5060 int paramid; 5061 int paramval = 0; 5062 int val; 5063 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); 5064 5065 WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name)); 5066 5067 paramid = vwrq->flags & IW_AUTH_INDEX; 5068 5069 switch (paramid) { 5070 case IW_AUTH_WPA_VERSION: 5071 5072 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) 5073 return error; 5074 if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED)) 5075 paramval = IW_AUTH_WPA_VERSION_DISABLED; 5076 else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) 5077 paramval = IW_AUTH_WPA_VERSION_WPA; 5078 #ifdef BCMWPA2 5079 else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) 5080 paramval = IW_AUTH_WPA_VERSION_WPA2; 5081 #endif 5082 break; 5083 case IW_AUTH_CIPHER_PAIRWISE: 5084 case IW_AUTH_CIPHER_GROUP: 5085 if (paramid == IW_AUTH_CIPHER_PAIRWISE) 5086 val = iw->pwsec; 5087 else 5088 val = iw->gwsec; 5089 5090 paramval = 0; 5091 if (val) { 5092 if (val & WEP_ENABLED) 5093 paramval |= (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104); 5094 if (val & TKIP_ENABLED) 5095 paramval |= (IW_AUTH_CIPHER_TKIP); 5096 if (val & AES_ENABLED) 5097 paramval |= (IW_AUTH_CIPHER_CCMP); 5098 } 5099 else 5100 paramval = IW_AUTH_CIPHER_NONE; 5101 break; 5102 case IW_AUTH_KEY_MGMT: 5103 5104 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) 5105 return error; 5106 if (VAL_PSK(val)) 5107 paramval = IW_AUTH_KEY_MGMT_PSK; 5108 else 5109 paramval = IW_AUTH_KEY_MGMT_802_1X; 5110 5111 break; 5112 case IW_AUTH_TKIP_COUNTERMEASURES: 5113 dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)¶mval, 1); 5114 break; 5115 5116 case IW_AUTH_DROP_UNENCRYPTED: 5117 dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)¶mval, 1); 5118 break; 5119 5120 case IW_AUTH_RX_UNENCRYPTED_EAPOL: 5121 dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); 5122 break; 5123 5124 case IW_AUTH_80211_AUTH_ALG: 5125 5126 if ((error = dev_wlc_intvar_get(dev, "auth", &val))) 5127 return error; 5128 if (!val) 5129 paramval = IW_AUTH_ALG_OPEN_SYSTEM; 5130 else 5131 paramval = IW_AUTH_ALG_SHARED_KEY; 5132 break; 5133 case IW_AUTH_WPA_ENABLED: 5134 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) 5135 return error; 5136 if (val) 5137 paramval = TRUE; 5138 else 5139 paramval = FALSE; 5140 break; 5141 #if WIRELESS_EXT > 17 5142 case IW_AUTH_ROAMING_CONTROL: 5143 WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__)); 5144 5145 break; 5146 case IW_AUTH_PRIVACY_INVOKED: 5147 paramval = iw->privacy_invoked; 5148 break; 5149 #endif 5150 } 5151 vwrq->value = paramval; 5152 return 0; 5153 } 5154 #endif 5155 5156 5157 #ifdef SOFTAP 5158 5159 static int ap_macmode = MACLIST_MODE_DISABLED; 5160 static struct mflist ap_black_list; 5161 static int 5162 wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key) 5163 { 5164 char hex[] = "XX"; 5165 unsigned char *data = key->data; 5166 5167 switch (strlen(keystr)) { 5168 case 5: 5169 case 13: 5170 case 16: 5171 key->len = strlen(keystr); 5172 memcpy(data, keystr, key->len + 1); 5173 break; 5174 case 12: 5175 case 28: 5176 case 34: 5177 case 66: 5178 if (!strnicmp(keystr, "0x", 2)) 5179 keystr += 2; 5180 else 5181 return -1; 5182 case 10: 5183 case 26: 5184 case 32: 5185 case 64: 5186 key->len = strlen(keystr) / 2; 5187 while (*keystr) { 5188 strncpy(hex, keystr, 2); 5189 *data++ = (char) bcm_strtoul(hex, NULL, 16); 5190 keystr += 2; 5191 } 5192 break; 5193 default: 5194 return -1; 5195 } 5196 5197 switch (key->len) { 5198 case 5: 5199 key->algo = CRYPTO_ALGO_WEP1; 5200 break; 5201 case 13: 5202 key->algo = CRYPTO_ALGO_WEP128; 5203 break; 5204 case 16: 5205 key->algo = CRYPTO_ALGO_AES_CCM; 5206 break; 5207 case 32: 5208 key->algo = CRYPTO_ALGO_TKIP; 5209 break; 5210 default: 5211 return -1; 5212 } 5213 5214 key->flags |= WL_PRIMARY_KEY; 5215 5216 return 0; 5217 } 5218 5219 #ifdef EXT_WPA_CRYPTO 5220 #define SHA1HashSize 20 5221 extern void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, 5222 int iterations, u8 *buf, size_t buflen); 5223 5224 #else 5225 5226 #define SHA1HashSize 20 5227 int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, 5228 int iterations, u8 *buf, size_t buflen) 5229 { 5230 WL_ERROR(("WARNING: %s is not implemented !!!\n", __FUNCTION__)); 5231 return -1; 5232 } 5233 5234 #endif 5235 5236 5237 int dev_iw_write_cfg1_bss_var(struct net_device *dev, int val) 5238 { 5239 struct { 5240 int cfg; 5241 int val; 5242 } bss_setbuf; 5243 5244 int bss_set_res; 5245 char smbuf[WLC_IOCTL_SMLEN]; 5246 memset(smbuf, 0, sizeof(smbuf)); 5247 5248 bss_setbuf.cfg = 1; 5249 bss_setbuf.val = val; 5250 5251 bss_set_res = dev_iw_iovar_setbuf(dev, "bss", 5252 &bss_setbuf, sizeof(bss_setbuf), smbuf, sizeof(smbuf)); 5253 WL_TRACE(("%s: bss_set_result:%d set with %d\n", __FUNCTION__, bss_set_res, val)); 5254 5255 return bss_set_res; 5256 } 5257 5258 5259 int dev_iw_read_cfg1_bss_var(struct net_device *dev, int *val) 5260 { 5261 int bsscfg_idx = 1; 5262 int bss_set_res; 5263 char smbuf[WLC_IOCTL_SMLEN]; 5264 memset(smbuf, 0, sizeof(smbuf)); 5265 5266 bss_set_res = dev_iw_iovar_getbuf(dev, "bss", \ 5267 &bsscfg_idx, sizeof(bsscfg_idx), smbuf, sizeof(smbuf)); 5268 *val = *(int*)smbuf; 5269 *val = dtoh32(*val); 5270 WL_TRACE(("%s: status=%d bss_get_result=%d\n", __FUNCTION__, bss_set_res, *val)); 5271 return bss_set_res; 5272 } 5273 5274 5275 #ifndef AP_ONLY 5276 static int wl_bssiovar_mkbuf( 5277 const char *iovar, 5278 int bssidx, 5279 void *param, 5280 int paramlen, 5281 void *bufptr, 5282 int buflen, 5283 int *perr) 5284 { 5285 const char *prefix = "bsscfg:"; 5286 int8 *p; 5287 uint prefixlen; 5288 uint namelen; 5289 uint iolen; 5290 5291 prefixlen = strlen(prefix); 5292 namelen = strlen(iovar) + 1; 5293 iolen = prefixlen + namelen + sizeof(int) + paramlen; 5294 5295 if (buflen < 0 || iolen > (uint)buflen) { 5296 *perr = BCME_BUFTOOSHORT; 5297 return 0; 5298 } 5299 5300 p = (int8 *)bufptr; 5301 5302 memcpy(p, prefix, prefixlen); 5303 p += prefixlen; 5304 5305 memcpy(p, iovar, namelen); 5306 p += namelen; 5307 5308 bssidx = htod32(bssidx); 5309 memcpy(p, &bssidx, sizeof(int32)); 5310 p += sizeof(int32); 5311 5312 if (paramlen) 5313 memcpy(p, param, paramlen); 5314 5315 *perr = 0; 5316 return iolen; 5317 } 5318 #endif 5319 5320 5321 int get_user_params(char *user_params, struct iw_point *dwrq) 5322 { 5323 int ret = 0; 5324 5325 if (copy_from_user(user_params, dwrq->pointer, dwrq->length)) { 5326 WL_ERROR(("\n%s: no user params: uptr:%p, ulen:%d\n", 5327 __FUNCTION__, dwrq->pointer, dwrq->length)); 5328 return -EFAULT; 5329 } 5330 5331 WL_TRACE(("\n%s: iwpriv user params:%s\n", __FUNCTION__, user_params)); 5332 5333 return ret; 5334 } 5335 5336 5337 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) 5338 5339 #if defined(CSCAN) 5340 5341 static int 5342 wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan) 5343 { 5344 int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); 5345 int err = 0; 5346 char *p; 5347 int i; 5348 iscan_info_t *iscan = g_iscan; 5349 5350 WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan)); 5351 5352 if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) { 5353 WL_ERROR(("%s error exit\n", __FUNCTION__)); 5354 err = -1; 5355 goto exit; 5356 } 5357 5358 #ifdef PNO_SUPPORT 5359 if (dhd_dev_get_pno_status(dev)) { 5360 WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__)); 5361 } 5362 #endif 5363 5364 params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); 5365 5366 if (nssid > 0) { 5367 i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16); 5368 i = ROUNDUP(i, sizeof(uint32)); 5369 if (i + nssid * sizeof(wlc_ssid_t) > params_size) { 5370 printf("additional ssids exceed params_size\n"); 5371 err = -1; 5372 goto exit; 5373 } 5374 5375 p = ((char*)&iscan->iscan_ex_params_p->params) + i; 5376 memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t)); 5377 p += nssid * sizeof(wlc_ssid_t); 5378 } else { 5379 p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16); 5380 } 5381 5382 5383 iscan->iscan_ex_params_p->params.channel_num = \ 5384 htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | \ 5385 (nchan & WL_SCAN_PARAMS_COUNT_MASK)); 5386 5387 nssid = \ 5388 (uint)((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) & \ 5389 WL_SCAN_PARAMS_COUNT_MASK); 5390 5391 5392 params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t)); 5393 iscan->iscan_ex_param_size = params_size; 5394 5395 iscan->list_cur = iscan->list_hdr; 5396 iscan->iscan_state = ISCAN_STATE_SCANING; 5397 wl_iw_set_event_mask(dev); 5398 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); 5399 5400 iscan->timer_on = 1; 5401 5402 #ifdef SCAN_DUMP 5403 { 5404 int i; 5405 WL_SCAN(("\n### List of SSIDs to scan ###\n")); 5406 for (i = 0; i < nssid; i++) { 5407 if (!ssids_local[i].SSID_len) 5408 WL_SCAN(("%d: Broadcast scan\n", i)); 5409 else 5410 WL_SCAN(("%d: scan for %s size =%d\n", i, \ 5411 ssids_local[i].SSID, ssids_local[i].SSID_len)); 5412 } 5413 WL_SCAN(("### List of channels to scan ###\n")); 5414 for (i = 0; i < nchan; i++) 5415 { 5416 WL_SCAN(("%d ", iscan->iscan_ex_params_p->params.channel_list[i])); 5417 } 5418 WL_SCAN(("\nnprobes=%d\n", iscan->iscan_ex_params_p->params.nprobes)); 5419 WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time)); 5420 WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time)); 5421 WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time)); 5422 WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type)); 5423 WL_SCAN(("\n###################\n")); 5424 } 5425 #endif 5426 5427 if (params_size > WLC_IOCTL_MEDLEN) { 5428 WL_ERROR(("Set ISCAN for %s due to params_size=%d \n", \ 5429 __FUNCTION__, params_size)); 5430 err = -1; 5431 } 5432 5433 if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p, \ 5434 iscan->iscan_ex_param_size, \ 5435 iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) { 5436 WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err)); 5437 err = -1; 5438 } 5439 5440 exit: 5441 5442 return err; 5443 } 5444 5445 5446 static int iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info, \ 5447 union iwreq_data *wrqu, char *ext) 5448 { 5449 int res = 0; 5450 char *extra = NULL; 5451 iscan_info_t *iscan = g_iscan; 5452 wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX]; 5453 int nssid = 0; 5454 int nchan = 0; 5455 5456 WL_TRACE(("\%s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", 5457 __FUNCTION__, info->cmd, info->flags, 5458 wrqu->data.pointer, wrqu->data.length)); 5459 5460 if (g_onoff == G_WLAN_SET_OFF) { 5461 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); 5462 return -1; 5463 } 5464 5465 if (wrqu->data.length != 0) { 5466 5467 char *str_ptr; 5468 5469 if (!iscan->iscan_ex_params_p) { 5470 return -EFAULT; 5471 } 5472 5473 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL))) 5474 return -ENOMEM; 5475 5476 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) { 5477 kfree(extra); 5478 return -EFAULT; 5479 } 5480 5481 extra[wrqu->data.length] = 0; 5482 WL_ERROR(("Got str param in iw_point:\n %s\n", extra)); 5483 5484 str_ptr = extra; 5485 5486 if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) { 5487 WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__)); 5488 goto exit_proc; 5489 } 5490 str_ptr += strlen(GET_SSID); 5491 nssid = wl_iw_parse_ssid_list(&str_ptr, ssids_local, nssid, \ 5492 WL_SCAN_PARAMS_SSID_MAX); 5493 if (nssid == -1) { 5494 WL_ERROR(("%s wrong ssid list", __FUNCTION__)); 5495 return -1; 5496 } 5497 5498 memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size); 5499 ASSERT(iscan->iscan_ex_param_size < WLC_IOCTL_MAXLEN); 5500 5501 5502 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL); 5503 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION); 5504 iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START); 5505 iscan->iscan_ex_params_p->scan_duration = htod16(0); 5506 5507 5508 if ((nchan = wl_iw_parse_channel_list(&str_ptr, \ 5509 &iscan->iscan_ex_params_p->params.channel_list[0], \ 5510 WL_NUMCHANNELS)) == -1) { 5511 WL_ERROR(("%s missing channel list\n", __FUNCTION__)); 5512 return -1; 5513 } 5514 5515 5516 get_parmeter_from_string(&str_ptr, \ 5517 GET_NPROBE, PTYPE_INTDEC, \ 5518 &iscan->iscan_ex_params_p->params.nprobes, 2); 5519 5520 get_parmeter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC, \ 5521 &iscan->iscan_ex_params_p->params.active_time, 4); 5522 5523 get_parmeter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC, \ 5524 &iscan->iscan_ex_params_p->params.passive_time, 4); 5525 5526 get_parmeter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC, \ 5527 &iscan->iscan_ex_params_p->params.home_time, 4); 5528 5529 get_parmeter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC, \ 5530 &iscan->iscan_ex_params_p->params.scan_type, 1); 5531 5532 res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); 5533 5534 } else { 5535 WL_ERROR(("IWPRIV argument len = 0 \n")); 5536 return -1; 5537 } 5538 5539 exit_proc: 5540 5541 kfree(extra); 5542 5543 return res; 5544 } 5545 5546 5547 static int 5548 wl_iw_set_cscan( 5549 struct net_device *dev, 5550 struct iw_request_info *info, 5551 union iwreq_data *wrqu, 5552 char *extra 5553 ) 5554 { 5555 int res = -1; 5556 iscan_info_t *iscan = g_iscan; 5557 wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX]; 5558 int nssid = 0; 5559 int nchan = 0; 5560 cscan_tlv_t *cscan_tlv_temp; 5561 char type; 5562 char *str_ptr; 5563 int tlv_size_left; 5564 #ifdef TLV_DEBUG 5565 int i; 5566 char tlv_in_example[] = { 'C', 'S', 'C', 'A', 'N', ' ', \ 5567 0x53, 0x01, 0x00, 0x00, 5568 'S', 5569 0x00, 5570 'S', 5571 0x04, 5572 'B', 'R', 'C', 'M', 5573 'C', 5574 0x06, 5575 'P', 5576 0x94, 5577 0x11, 5578 'T', 5579 0x01 5580 }; 5581 #endif 5582 5583 WL_TRACE(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", 5584 __FUNCTION__, info->cmd, info->flags, 5585 wrqu->data.pointer, wrqu->data.length)); 5586 5587 net_os_wake_lock(dev); 5588 5589 if (g_onoff == G_WLAN_SET_OFF) { 5590 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); 5591 goto exit_proc; 5592 } 5593 5594 5595 if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) { 5596 WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, \ 5597 wrqu->data.length, strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))); 5598 goto exit_proc; 5599 } 5600 5601 #ifdef TLV_DEBUG 5602 memcpy(extra, tlv_in_example, sizeof(tlv_in_example)); 5603 wrqu->data.length = sizeof(tlv_in_example); 5604 for (i = 0; i < wrqu->data.length; i++) 5605 printf("%02X ", extra[i]); 5606 printf("\n"); 5607 #endif 5608 5609 str_ptr = extra; 5610 str_ptr += strlen(CSCAN_COMMAND); 5611 tlv_size_left = wrqu->data.length - strlen(CSCAN_COMMAND); 5612 5613 cscan_tlv_temp = (cscan_tlv_t *)str_ptr; 5614 memset(ssids_local, 0, sizeof(ssids_local)); 5615 5616 if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) && \ 5617 (cscan_tlv_temp->version == CSCAN_TLV_VERSION) && \ 5618 (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION)) 5619 { 5620 str_ptr += sizeof(cscan_tlv_t); 5621 tlv_size_left -= sizeof(cscan_tlv_t); 5622 5623 5624 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \ 5625 WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) { 5626 WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); 5627 goto exit_proc; 5628 } 5629 else { 5630 5631 memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size); 5632 5633 5634 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL); 5635 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION); 5636 iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START); 5637 iscan->iscan_ex_params_p->scan_duration = htod16(0); 5638 5639 5640 while (tlv_size_left > 0) 5641 { 5642 type = str_ptr[0]; 5643 switch (type) { 5644 case CSCAN_TLV_TYPE_CHANNEL_IE: 5645 5646 if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr, \ 5647 &iscan->iscan_ex_params_p->params.channel_list[0], \ 5648 WL_NUMCHANNELS, &tlv_size_left)) == -1) { 5649 WL_ERROR(("%s missing channel list\n", \ 5650 __FUNCTION__)); 5651 goto exit_proc; 5652 } 5653 break; 5654 case CSCAN_TLV_TYPE_NPROBE_IE: 5655 if ((res = wl_iw_parse_data_tlv(&str_ptr, \ 5656 &iscan->iscan_ex_params_p->params.nprobes, \ 5657 sizeof(iscan->iscan_ex_params_p->params.nprobes), \ 5658 type, sizeof(char), &tlv_size_left)) == -1) { 5659 WL_ERROR(("%s return %d\n", \ 5660 __FUNCTION__, res)); 5661 goto exit_proc; 5662 } 5663 break; 5664 case CSCAN_TLV_TYPE_ACTIVE_IE: 5665 if ((res = wl_iw_parse_data_tlv(&str_ptr, \ 5666 &iscan->iscan_ex_params_p->params.active_time, \ 5667 sizeof(iscan->iscan_ex_params_p->params.active_time), \ 5668 type, sizeof(short), &tlv_size_left)) == -1) { 5669 WL_ERROR(("%s return %d\n", \ 5670 __FUNCTION__, res)); 5671 goto exit_proc; 5672 } 5673 break; 5674 case CSCAN_TLV_TYPE_PASSIVE_IE: 5675 if ((res = wl_iw_parse_data_tlv(&str_ptr, \ 5676 &iscan->iscan_ex_params_p->params.passive_time, \ 5677 sizeof(iscan->iscan_ex_params_p->params.passive_time), \ 5678 type, sizeof(short), &tlv_size_left)) == -1) { 5679 WL_ERROR(("%s return %d\n", \ 5680 __FUNCTION__, res)); 5681 goto exit_proc; 5682 } 5683 break; 5684 case CSCAN_TLV_TYPE_HOME_IE: 5685 if ((res = wl_iw_parse_data_tlv(&str_ptr, \ 5686 &iscan->iscan_ex_params_p->params.home_time, \ 5687 sizeof(iscan->iscan_ex_params_p->params.home_time), \ 5688 type, sizeof(short), &tlv_size_left)) == -1) { 5689 WL_ERROR(("%s return %d\n", \ 5690 __FUNCTION__, res)); 5691 goto exit_proc; 5692 } 5693 break; 5694 case CSCAN_TLV_TYPE_STYPE_IE: 5695 if ((res = wl_iw_parse_data_tlv(&str_ptr, \ 5696 &iscan->iscan_ex_params_p->params.scan_type, \ 5697 sizeof(iscan->iscan_ex_params_p->params.scan_type), \ 5698 type, sizeof(char), &tlv_size_left)) == -1) { 5699 WL_ERROR(("%s return %d\n", \ 5700 __FUNCTION__, res)); 5701 goto exit_proc; 5702 } 5703 break; 5704 5705 default : 5706 WL_ERROR(("%s get unkwown type %X\n", \ 5707 __FUNCTION__, type)); 5708 goto exit_proc; 5709 break; 5710 } 5711 } 5712 } 5713 } 5714 else { 5715 WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); 5716 goto exit_proc; 5717 } 5718 5719 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { 5720 if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) { 5721 5722 WL_ERROR(("%s Clean up First scan flag which is %d\n", \ 5723 __FUNCTION__, g_first_broadcast_scan)); 5724 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; 5725 } 5726 else { 5727 WL_ERROR(("%s Ignoring CSCAN : First Scan is not done yet %d\n", \ 5728 __FUNCTION__, g_first_counter_scans)); 5729 res = -EBUSY; 5730 goto exit_proc; 5731 } 5732 } 5733 5734 res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); 5735 5736 exit_proc: 5737 net_os_wake_unlock(dev); 5738 return res; 5739 } 5740 5741 #endif 5742 5743 #ifdef SOFTAP 5744 #ifndef AP_ONLY 5745 5746 static int thr_wait_for_2nd_eth_dev(void *data) 5747 { 5748 int ret = 0; 5749 5750 DAEMONIZE("wl0_eth_wthread"); 5751 5752 WL_TRACE(("\n>%s threda started:, PID:%x\n", __FUNCTION__, current->pid)); 5753 5754 if (down_timeout(&ap_eth_sema, msecs_to_jiffies(5000)) != 0) { 5755 WL_ERROR(("\n%s: sap_eth_sema timeout \n", __FUNCTION__)); 5756 ret = -1; 5757 goto fail; 5758 } 5759 5760 if (!ap_net_dev) { 5761 WL_ERROR((" ap_net_dev is null !!!")); 5762 ret = -1; 5763 goto fail; 5764 } 5765 5766 WL_TRACE(("\n>%s: Thread:'softap ethdev IF:%s is detected !!!'\n\n", 5767 __FUNCTION__, ap_net_dev->name)); 5768 5769 ap_cfg_running = TRUE; 5770 5771 bcm_mdelay(500); 5772 5773 wl_iw_send_priv_event(priv_dev, "AP_SET_CFG_OK"); 5774 5775 fail: 5776 WL_TRACE(("\n>%s, thread completed\n", __FUNCTION__)); 5777 5778 return ret; 5779 } 5780 #endif 5781 #ifndef AP_ONLY 5782 static int last_auto_channel = 6; 5783 #endif 5784 static int get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap) 5785 { 5786 int chosen = 0; 5787 wl_uint32_list_t request; 5788 int rescan = 0; 5789 int retry = 0; 5790 int updown = 0; 5791 int ret = 0; 5792 wlc_ssid_t null_ssid; 5793 int res = 0; 5794 #ifndef AP_ONLY 5795 int iolen = 0; 5796 int mkvar_err = 0; 5797 int bsscfg_index = 1; 5798 char buf[WLC_IOCTL_SMLEN]; 5799 #endif 5800 WL_SOFTAP(("Enter %s\n", __FUNCTION__)); 5801 5802 #ifndef AP_ONLY 5803 if (ap_cfg_running) { 5804 ap->channel = last_auto_channel; 5805 return res; 5806 } 5807 #endif 5808 memset(&null_ssid, 0, sizeof(wlc_ssid_t)); 5809 res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)); 5810 #ifdef AP_ONLY 5811 res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid)); 5812 #else 5813 iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&null_ssid), \ 5814 null_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err); 5815 ASSERT(iolen); 5816 res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen); 5817 #endif 5818 auto_channel_retry: 5819 request.count = htod32(0); 5820 ret = dev_wlc_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request)); 5821 if (ret < 0) { 5822 WL_ERROR(("can't start auto channel scan\n")); 5823 goto fail; 5824 } 5825 5826 get_channel_retry: 5827 bcm_mdelay(500); 5828 5829 ret = dev_wlc_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)); 5830 if (ret < 0 || dtoh32(chosen) == 0) { 5831 if (retry++ < 3) 5832 goto get_channel_retry; 5833 else { 5834 WL_ERROR(("can't get auto channel sel, err = %d, \ 5835 chosen = %d\n", ret, chosen)); 5836 goto fail; 5837 } 5838 } 5839 if ((chosen == 1) && (!rescan++)) 5840 goto auto_channel_retry; 5841 WL_SOFTAP(("Set auto channel = %d\n", chosen)); 5842 ap->channel = chosen; 5843 if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown))) < 0) { 5844 WL_ERROR(("%s fail to set up err =%d\n", __FUNCTION__, res)); 5845 goto fail; 5846 } 5847 #ifndef AP_ONLY 5848 if (!res) 5849 last_auto_channel = ap->channel; 5850 #endif 5851 5852 fail : 5853 return res; 5854 } 5855 5856 5857 static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) 5858 { 5859 int updown = 0; 5860 int channel = 0; 5861 5862 wlc_ssid_t ap_ssid; 5863 int max_assoc = 8; 5864 5865 int res = 0; 5866 int apsta_var = 0; 5867 #ifndef AP_ONLY 5868 int mpc = 0; 5869 int iolen = 0; 5870 int mkvar_err = 0; 5871 int bsscfg_index = 1; 5872 char buf[WLC_IOCTL_SMLEN]; 5873 #endif 5874 5875 if (!dev) { 5876 WL_ERROR(("%s: dev is null\n", __FUNCTION__)); 5877 return -1; 5878 } 5879 5880 net_os_wake_lock(dev); 5881 5882 WL_SOFTAP(("wl_iw: set ap profile:\n")); 5883 WL_SOFTAP((" ssid = '%s'\n", ap->ssid)); 5884 WL_SOFTAP((" security = '%s'\n", ap->sec)); 5885 if (ap->key[0] != '\0') 5886 WL_SOFTAP((" key = '%s'\n", ap->key)); 5887 WL_SOFTAP((" channel = %d\n", ap->channel)); 5888 WL_SOFTAP((" max scb = %d\n", ap->max_scb)); 5889 5890 #ifdef AP_ONLY 5891 if (ap_cfg_running) { 5892 wl_iw_softap_deassoc_stations(dev); 5893 ap_cfg_running = FALSE; 5894 } 5895 #endif 5896 5897 if (ap_cfg_running == FALSE) { 5898 5899 #ifndef AP_ONLY 5900 5901 sema_init(&ap_eth_sema, 0); 5902 5903 mpc = 0; 5904 if ((res = dev_wlc_intvar_set(dev, "mpc", mpc))) { 5905 WL_ERROR(("%s fail to set mpc\n", __FUNCTION__)); 5906 goto fail; 5907 } 5908 #endif 5909 5910 updown = 0; 5911 if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)))) { 5912 WL_ERROR(("%s fail to set updown\n", __FUNCTION__)); 5913 goto fail; 5914 } 5915 5916 #ifdef AP_ONLY 5917 apsta_var = 0; 5918 if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) { 5919 WL_ERROR(("%s fail to set apsta_var 0\n", __FUNCTION__)); 5920 goto fail; 5921 } 5922 apsta_var = 1; 5923 if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) { 5924 WL_ERROR(("%s fail to set apsta_var 1\n", __FUNCTION__)); 5925 goto fail; 5926 } 5927 res = dev_wlc_ioctl(dev, WLC_GET_AP, &apsta_var, sizeof(apsta_var)); 5928 #else 5929 apsta_var = 1; 5930 iolen = wl_bssiovar_mkbuf("apsta", 5931 bsscfg_index, &apsta_var, sizeof(apsta_var)+4, 5932 buf, sizeof(buf), &mkvar_err); 5933 ASSERT(iolen); 5934 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) { 5935 WL_ERROR(("%s fail to set apsta \n", __FUNCTION__)); 5936 goto fail; 5937 } 5938 WL_TRACE(("\n>in %s: apsta set result: %d \n", __FUNCTION__, res)); 5939 #endif 5940 5941 updown = 1; 5942 if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown))) < 0) { 5943 WL_ERROR(("%s fail to set apsta \n", __FUNCTION__)); 5944 goto fail; 5945 } 5946 5947 } else { 5948 5949 if (!ap_net_dev) { 5950 WL_ERROR(("%s: ap_net_dev is null\n", __FUNCTION__)); 5951 goto fail; 5952 } 5953 5954 res = wl_iw_softap_deassoc_stations(ap_net_dev); 5955 5956 5957 if ((res = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) { 5958 WL_ERROR(("%s fail to set bss down\n", __FUNCTION__)); 5959 goto fail; 5960 } 5961 } 5962 5963 5964 if ((ap->channel == 0) && (get_softap_auto_channel(dev, ap) < 0)) { 5965 ap->channel = 1; 5966 WL_ERROR(("%s auto channel failed, pick up channel=%d\n", \ 5967 __FUNCTION__, ap->channel)); 5968 } 5969 5970 channel = ap->channel; 5971 if ((res = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)))) { 5972 WL_ERROR(("%s fail to set channel\n", __FUNCTION__)); 5973 goto fail; 5974 } 5975 5976 if (ap_cfg_running == FALSE) { 5977 updown = 0; 5978 if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)))) { 5979 WL_ERROR(("%s fail to set up\n", __FUNCTION__)); 5980 goto fail; 5981 } 5982 } 5983 5984 max_assoc = ap->max_scb; 5985 if ((res = dev_wlc_intvar_set(dev, "maxassoc", max_assoc))) { 5986 WL_ERROR(("%s fail to set maxassoc\n", __FUNCTION__)); 5987 goto fail; 5988 } 5989 5990 ap_ssid.SSID_len = strlen(ap->ssid); 5991 strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len); 5992 5993 #ifdef AP_ONLY 5994 if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) { 5995 WL_ERROR(("ERROR:%d in:%s, wl_iw_set_ap_security is skipped\n", \ 5996 res, __FUNCTION__)); 5997 goto fail; 5998 } 5999 wl_iw_send_priv_event(dev, "ASCII_CMD=AP_BSS_START"); 6000 ap_cfg_running = TRUE; 6001 #else 6002 iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&ap_ssid), 6003 ap_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err); 6004 ASSERT(iolen); 6005 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) != 0) { 6006 WL_ERROR(("ERROR:%d in:%s, Security & BSS reconfiguration is skipped\n", \ 6007 res, __FUNCTION__)); 6008 goto fail; 6009 } 6010 if (ap_cfg_running == FALSE) { 6011 kernel_thread(thr_wait_for_2nd_eth_dev, 0, 0); 6012 } else { 6013 if (ap_net_dev == NULL) { 6014 WL_ERROR(("%s ERROR: ap_net_dev is NULL !!!\n", __FUNCTION__)); 6015 goto fail; 6016 } 6017 6018 WL_ERROR(("%s: %s Configure security & restart AP bss \n", \ 6019 __FUNCTION__, ap_net_dev->name)); 6020 6021 if ((res = wl_iw_set_ap_security(ap_net_dev, &my_ap)) < 0) { 6022 WL_ERROR(("%s fail to set security : %d\n", __FUNCTION__, res)); 6023 goto fail; 6024 } 6025 6026 if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0) { 6027 WL_ERROR(("%s fail to set bss up\n", __FUNCTION__)); 6028 goto fail; 6029 } 6030 } 6031 #endif 6032 fail: 6033 WL_SOFTAP(("%s exit with %d\n", __FUNCTION__, res)); 6034 6035 net_os_wake_unlock(dev); 6036 6037 return res; 6038 } 6039 6040 6041 static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) 6042 { 6043 int wsec = 0; 6044 int wpa_auth = 0; 6045 int res = 0; 6046 int i; 6047 char *ptr; 6048 #ifdef AP_ONLY 6049 int mpc = 0; 6050 wlc_ssid_t ap_ssid; 6051 #endif 6052 wl_wsec_key_t key; 6053 6054 WL_SOFTAP(("\nsetting SOFTAP security mode:\n")); 6055 WL_SOFTAP(("wl_iw: set ap profile:\n")); 6056 WL_SOFTAP((" ssid = '%s'\n", ap->ssid)); 6057 WL_SOFTAP((" security = '%s'\n", ap->sec)); 6058 if (ap->key[0] != '\0') 6059 WL_SOFTAP((" key = '%s'\n", ap->key)); 6060 WL_SOFTAP((" channel = %d\n", ap->channel)); 6061 WL_SOFTAP((" max scb = %d\n", ap->max_scb)); 6062 6063 if (strnicmp(ap->sec, "open", strlen("open")) == 0) { 6064 wsec = 0; 6065 res = dev_wlc_intvar_set(dev, "wsec", wsec); 6066 wpa_auth = WPA_AUTH_DISABLED; 6067 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); 6068 6069 WL_SOFTAP(("=====================\n")); 6070 WL_SOFTAP((" wsec & wpa_auth set 'OPEN', result:&d %d\n", res)); 6071 WL_SOFTAP(("=====================\n")); 6072 6073 } else if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) { 6074 6075 memset(&key, 0, sizeof(key)); 6076 6077 wsec = WEP_ENABLED; 6078 res = dev_wlc_intvar_set(dev, "wsec", wsec); 6079 6080 key.index = 0; 6081 if (wl_iw_parse_wep(ap->key, &key)) { 6082 WL_SOFTAP(("wep key parse err!\n")); 6083 return -1; 6084 } 6085 6086 key.index = htod32(key.index); 6087 key.len = htod32(key.len); 6088 key.algo = htod32(key.algo); 6089 key.flags = htod32(key.flags); 6090 6091 res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); 6092 6093 wpa_auth = WPA_AUTH_DISABLED; 6094 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); 6095 6096 WL_SOFTAP(("=====================\n")); 6097 WL_SOFTAP((" wsec & auth set 'WEP', result:&d %d\n", res)); 6098 WL_SOFTAP(("=====================\n")); 6099 6100 } else if (strnicmp(ap->sec, "wpa2-psk", strlen("wpa2-psk")) == 0) { 6101 wsec_pmk_t psk; 6102 size_t key_len; 6103 6104 wsec = AES_ENABLED; 6105 dev_wlc_intvar_set(dev, "wsec", wsec); 6106 6107 key_len = strlen(ap->key); 6108 if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) { 6109 WL_SOFTAP(("passphrase must be between %d and %d characters long\n", 6110 WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN)); 6111 return -1; 6112 } 6113 6114 if (key_len < WSEC_MAX_PSK_LEN) { 6115 unsigned char output[2*SHA1HashSize]; 6116 char key_str_buf[WSEC_MAX_PSK_LEN+1]; 6117 6118 memset(output, 0, sizeof(output)); 6119 pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32); 6120 6121 ptr = key_str_buf; 6122 for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) { 6123 sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4], \ 6124 (uint)output[i*4+1], (uint)output[i*4+2], \ 6125 (uint)output[i*4+3]); 6126 ptr += 8; 6127 } 6128 WL_SOFTAP(("%s: passphase = %s\n", __FUNCTION__, key_str_buf)); 6129 6130 psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN); 6131 memcpy(psk.key, key_str_buf, psk.key_len); 6132 } else { 6133 psk.key_len = htod16((ushort) key_len); 6134 memcpy(psk.key, ap->key, key_len); 6135 } 6136 psk.flags = htod16(WSEC_PASSPHRASE); 6137 dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk)); 6138 6139 wpa_auth = WPA2_AUTH_PSK; 6140 dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); 6141 6142 } else if (strnicmp(ap->sec, "wpa-psk", strlen("wpa-psk")) == 0) { 6143 6144 wsec_pmk_t psk; 6145 size_t key_len; 6146 6147 wsec = TKIP_ENABLED; 6148 res = dev_wlc_intvar_set(dev, "wsec", wsec); 6149 6150 key_len = strlen(ap->key); 6151 if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) { 6152 WL_SOFTAP(("passphrase must be between %d and %d characters long\n", 6153 WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN)); 6154 return -1; 6155 } 6156 6157 if (key_len < WSEC_MAX_PSK_LEN) { 6158 unsigned char output[2*SHA1HashSize]; 6159 char key_str_buf[WSEC_MAX_PSK_LEN+1]; 6160 6161 WL_SOFTAP(("%s: do passhash...\n", __FUNCTION__)); 6162 6163 pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32); 6164 6165 ptr = key_str_buf; 6166 for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) { 6167 WL_SOFTAP(("[%02d]: %08x\n", i, *((unsigned int *)&output[i*4]))); 6168 6169 sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4], 6170 (uint)output[i*4+1], (uint)output[i*4+2], 6171 (uint)output[i*4+3]); 6172 ptr += 8; 6173 } 6174 WL_SOFTAP(("%s: passphase = %s\n", __FUNCTION__, key_str_buf)); 6175 6176 psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN); 6177 memcpy(psk.key, key_str_buf, psk.key_len); 6178 } else { 6179 psk.key_len = htod16((ushort) key_len); 6180 memcpy(psk.key, ap->key, key_len); 6181 } 6182 6183 psk.flags = htod16(WSEC_PASSPHRASE); 6184 res |= dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk)); 6185 6186 wpa_auth = WPA_AUTH_PSK; 6187 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); 6188 6189 WL_SOFTAP((" wsec & auth set 'wpa-psk' (TKIP), result:&d %d\n", res)); 6190 } 6191 6192 #ifdef AP_ONLY 6193 ap_ssid.SSID_len = strlen(ap->ssid); 6194 strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len); 6195 res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &ap_ssid, sizeof(ap_ssid)); 6196 mpc = 0; 6197 res |= dev_wlc_intvar_set(dev, "mpc", mpc); 6198 if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) { 6199 res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); 6200 } 6201 #endif 6202 return res; 6203 } 6204 6205 6206 6207 int get_parmeter_from_string( 6208 char **str_ptr, const char *token, 6209 int param_type, void *dst, int param_max_len) 6210 { 6211 char int_str[7] = "0"; 6212 int parm_str_len; 6213 char *param_str_begin; 6214 char *param_str_end; 6215 char *orig_str = *str_ptr; 6216 6217 if ((*str_ptr) && !strncmp(*str_ptr, token, strlen(token))) { 6218 6219 strsep(str_ptr, "=,"); 6220 param_str_begin = *str_ptr; 6221 strsep(str_ptr, "=,"); 6222 6223 if (*str_ptr == NULL) { 6224 parm_str_len = strlen(param_str_begin); 6225 } else { 6226 param_str_end = *str_ptr-1; 6227 parm_str_len = param_str_end - param_str_begin; 6228 } 6229 6230 WL_TRACE((" 'token:%s', len:%d, ", token, parm_str_len)); 6231 6232 if (parm_str_len > param_max_len) { 6233 WL_TRACE((" WARNING: extracted param len:%d is > MAX:%d\n", 6234 parm_str_len, param_max_len)); 6235 6236 parm_str_len = param_max_len; 6237 } 6238 6239 switch (param_type) { 6240 6241 case PTYPE_INTDEC: { 6242 int *pdst_int = dst; 6243 char *eptr; 6244 6245 if (parm_str_len > sizeof(int_str)) 6246 parm_str_len = sizeof(int_str); 6247 6248 memcpy(int_str, param_str_begin, parm_str_len); 6249 6250 *pdst_int = simple_strtoul(int_str, &eptr, 10); 6251 6252 WL_TRACE((" written as integer:%d\n", *pdst_int)); 6253 } 6254 break; 6255 case PTYPE_STR_HEX: { 6256 u8 *buf = dst; 6257 6258 param_max_len = param_max_len >> 1; 6259 hstr_2_buf(param_str_begin, buf, param_max_len); 6260 print_buf(buf, param_max_len, 0); 6261 } 6262 break; 6263 default: 6264 memcpy(dst, param_str_begin, parm_str_len); 6265 *((char *)dst + parm_str_len) = 0; 6266 WL_TRACE((" written as a string:%s\n", (char *)dst)); 6267 break; 6268 } 6269 6270 return 0; 6271 } else { 6272 WL_ERROR(("\n %s: ERROR: can't find token:%s in str:%s \n", 6273 __FUNCTION__, token, orig_str)); 6274 6275 return -1; 6276 } 6277 } 6278 6279 6280 static int wl_iw_softap_deassoc_stations(struct net_device *dev) 6281 { 6282 int i; 6283 int res = 0; 6284 char mac_buf[128] = {0}; 6285 struct maclist *assoc_maclist = (struct maclist *)mac_buf; 6286 6287 memset(assoc_maclist, 0, sizeof(mac_buf)); 6288 assoc_maclist->count = 8; 6289 6290 res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 128); 6291 if (res != 0) { 6292 WL_SOFTAP((" Error:%d in :%s, Couldn't get ASSOC List\n", res, __FUNCTION__)); 6293 return res; 6294 } 6295 6296 if (assoc_maclist->count) { 6297 for (i = 0; i < assoc_maclist->count; i++) { 6298 scb_val_t scbval; 6299 6300 scbval.val = htod32(1); 6301 bcopy(&assoc_maclist->ea[i], &scbval.ea, ETHER_ADDR_LEN); 6302 6303 WL_SOFTAP(("deauth STA:%d \n", i)); 6304 res |= dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, 6305 &scbval, sizeof(scb_val_t)); 6306 } 6307 } else { 6308 WL_SOFTAP((" STA ASSOC list is empty\n")); 6309 } 6310 6311 if (res != 0) 6312 WL_SOFTAP((" Error:%d in :%s\n", res, __FUNCTION__)); 6313 else if (assoc_maclist->count) { 6314 6315 bcm_mdelay(200); 6316 } 6317 return res; 6318 } 6319 6320 6321 static int iwpriv_softap_stop(struct net_device *dev, 6322 struct iw_request_info *info, 6323 union iwreq_data *wrqu, 6324 char *ext) 6325 { 6326 int res = 0; 6327 6328 WL_SOFTAP(("got iwpriv AP_BSS_STOP\n")); 6329 6330 if ((!dev) && (!ap_net_dev)) { 6331 WL_ERROR(("%s: dev is null\n", __FUNCTION__)); 6332 return res; 6333 } 6334 6335 net_os_wake_lock(dev); 6336 6337 if ((ap_cfg_running == TRUE)) { 6338 #ifdef AP_ONLY 6339 wl_iw_softap_deassoc_stations(dev); 6340 #else 6341 wl_iw_softap_deassoc_stations(ap_net_dev); 6342 6343 if ((res = dev_iw_write_cfg1_bss_var(dev, 2)) < 0) 6344 WL_ERROR(("%s failed to del BSS err = %d", __FUNCTION__, res)); 6345 #endif 6346 6347 bcm_mdelay(100); 6348 6349 wrqu->data.length = 0; 6350 ap_cfg_running = FALSE; 6351 } 6352 else 6353 WL_ERROR(("%s: was called when SoftAP is OFF : move on\n", __FUNCTION__)); 6354 6355 WL_SOFTAP(("%s Done with %d\n", __FUNCTION__, res)); 6356 6357 net_os_wake_unlock(dev); 6358 6359 return res; 6360 } 6361 6362 6363 static int iwpriv_fw_reload(struct net_device *dev, 6364 struct iw_request_info *info, 6365 union iwreq_data *wrqu, 6366 char *ext) 6367 { 6368 int ret = -1; 6369 char extra[256]; 6370 char *fwstr = fw_path; 6371 6372 WL_SOFTAP(("current firmware_path[]=%s\n", fwstr)); 6373 6374 WL_TRACE((">Got FW_RELOAD cmd:" 6375 "info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d, \ 6376 fw_path:%p, len:%d \n", 6377 info->cmd, info->flags, 6378 wrqu->data.pointer, wrqu->data.length, fwstr, strlen(fwstr))); 6379 6380 if ((wrqu->data.length > 4) && (wrqu->data.length < sizeof(extra))) { 6381 6382 char *str_ptr; 6383 6384 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) { 6385 ret = -EFAULT; 6386 goto exit_proc; 6387 } 6388 6389 extra[wrqu->data.length] = 8; 6390 str_ptr = extra; 6391 6392 if (get_parmeter_from_string(&str_ptr, "FW_PATH=", PTYPE_STRING, fwstr, 255) != 0) { 6393 WL_ERROR(("Error: extracting FW_PATH='' string\n")); 6394 goto exit_proc; 6395 } 6396 6397 if (strstr(fwstr, "apsta") != NULL) { 6398 WL_SOFTAP(("GOT APSTA FIRMWARE\n")); 6399 ap_fw_loaded = TRUE; 6400 } else { 6401 WL_SOFTAP(("GOT STA FIRMWARE\n")); 6402 ap_fw_loaded = FALSE; 6403 } 6404 6405 WL_SOFTAP(("SET firmware_path[]=%s , str_p:%p\n", fwstr, fwstr)); 6406 ret = 0; 6407 } else { 6408 WL_ERROR(("Error: ivalid param len:%d\n", wrqu->data.length)); 6409 } 6410 6411 exit_proc: 6412 return ret; 6413 } 6414 #endif 6415 6416 #ifdef SOFTAP 6417 static int iwpriv_wpasupp_loop_tst(struct net_device *dev, 6418 struct iw_request_info *info, 6419 union iwreq_data *wrqu, 6420 char *ext) 6421 { 6422 int res = 0; 6423 char *params = NULL; 6424 6425 WL_TRACE((">Got IWPRIV wp_supp loopback cmd test:" 6426 "info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n", 6427 info->cmd, info->flags, 6428 wrqu->data.pointer, wrqu->data.length)); 6429 6430 if (wrqu->data.length != 0) { 6431 6432 if (!(params = kmalloc(wrqu->data.length+1, GFP_KERNEL))) 6433 return -ENOMEM; 6434 6435 if (copy_from_user(params, wrqu->data.pointer, wrqu->data.length)) { 6436 kfree(params); 6437 return -EFAULT; 6438 } 6439 6440 params[wrqu->data.length] = 0; 6441 WL_SOFTAP(("\n>> copied from user:\n %s\n", params)); 6442 } else { 6443 WL_ERROR(("ERROR param length is 0\n")); 6444 return -EFAULT; 6445 } 6446 6447 res = wl_iw_send_priv_event(dev, params); 6448 kfree(params); 6449 6450 return res; 6451 } 6452 #endif 6453 6454 6455 static int 6456 iwpriv_en_ap_bss( 6457 struct net_device *dev, 6458 struct iw_request_info *info, 6459 void *wrqu, 6460 char *extra) 6461 { 6462 int res = 0; 6463 6464 if (!dev) { 6465 WL_ERROR(("%s: dev is null\n", __FUNCTION__)); 6466 return -1; 6467 } 6468 6469 net_os_wake_lock(dev); 6470 6471 WL_TRACE(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name)); 6472 6473 #ifndef AP_ONLY 6474 if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) { 6475 WL_ERROR((" %s ERROR setting SOFTAP security in :%d\n", __FUNCTION__, res)); 6476 } 6477 else { 6478 if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0) 6479 WL_ERROR(("%s fail to set bss up err=%d\n", __FUNCTION__, res)); 6480 else 6481 bcm_mdelay(100); 6482 } 6483 6484 #endif 6485 WL_SOFTAP(("%s done with res %d \n", __FUNCTION__, res)); 6486 6487 net_os_wake_unlock(dev); 6488 6489 return res; 6490 } 6491 6492 static int 6493 get_assoc_sta_list(struct net_device *dev, char *buf, int len) 6494 { 6495 WL_TRACE(("calling dev_wlc_ioctl(dev:%p, cmd:%d, buf:%p, len:%d)\n", 6496 dev, WLC_GET_ASSOCLIST, buf, len)); 6497 6498 dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, buf, len); 6499 6500 return 0; 6501 } 6502 6503 6504 static int 6505 set_ap_mac_list(struct net_device *dev, char *buf) 6506 { 6507 struct mac_list_set *mac_list_set = (struct mac_list_set *)buf; 6508 struct maclist *white_maclist = (struct maclist *)&mac_list_set->white_list; 6509 struct maclist *black_maclist = (struct maclist *)&mac_list_set->black_list; 6510 int mac_mode = mac_list_set->mode; 6511 int length; 6512 int i; 6513 6514 ap_macmode = mac_mode; 6515 if (mac_mode == MACLIST_MODE_DISABLED) { 6516 6517 bzero(&ap_black_list, sizeof(struct mflist)); 6518 6519 dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); 6520 } else { 6521 scb_val_t scbval; 6522 char mac_buf[256] = {0}; 6523 struct maclist *assoc_maclist = (struct maclist *) mac_buf; 6524 6525 mac_mode = MACLIST_MODE_ALLOW; 6526 6527 dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); 6528 6529 length = sizeof(white_maclist->count)+white_maclist->count*ETHER_ADDR_LEN; 6530 dev_wlc_ioctl(dev, WLC_SET_MACLIST, white_maclist, length); 6531 WL_SOFTAP(("White List, length %d:\n", length)); 6532 for (i = 0; i < white_maclist->count; i++) 6533 WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n", 6534 i, white_maclist->ea[i].octet[0], white_maclist->ea[i].octet[1], 6535 white_maclist->ea[i].octet[2], 6536 white_maclist->ea[i].octet[3], white_maclist->ea[i].octet[4], 6537 white_maclist->ea[i].octet[5])); 6538 6539 bcopy(black_maclist, &ap_black_list, sizeof(ap_black_list)); 6540 6541 WL_SOFTAP(("Black List, size %d:\n", sizeof(ap_black_list))); 6542 for (i = 0; i < ap_black_list.count; i++) 6543 WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n", 6544 i, ap_black_list.ea[i].octet[0], ap_black_list.ea[i].octet[1], 6545 ap_black_list.ea[i].octet[2], 6546 ap_black_list.ea[i].octet[3], 6547 ap_black_list.ea[i].octet[4], ap_black_list.ea[i].octet[5])); 6548 6549 dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 256); 6550 if (assoc_maclist->count) { 6551 int j; 6552 for (i = 0; i < assoc_maclist->count; i++) { 6553 for (j = 0; j < white_maclist->count; j++) { 6554 if (!bcmp(&assoc_maclist->ea[i], &white_maclist->ea[j], 6555 ETHER_ADDR_LEN)) { 6556 WL_SOFTAP(("match allow, let it be\n")); 6557 break; 6558 } 6559 } 6560 if (j == white_maclist->count) { 6561 WL_SOFTAP(("match black, deauth it\n")); 6562 scbval.val = htod32(1); 6563 bcopy(&assoc_maclist->ea[i], &scbval.ea, 6564 ETHER_ADDR_LEN); 6565 dev_wlc_ioctl(dev, 6566 WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, 6567 sizeof(scb_val_t)); 6568 } 6569 } 6570 } 6571 } 6572 return 0; 6573 } 6574 #endif 6575 6576 6577 #ifdef SOFTAP 6578 int set_macfilt_from_string(struct mflist *pmflist, char **param_str) 6579 { 6580 return 0; 6581 } 6582 #endif 6583 6584 6585 #ifdef SOFTAP 6586 #define PARAM_OFFSET PROFILE_OFFSET 6587 6588 int wl_iw_process_private_ascii_cmd( 6589 struct net_device *dev, 6590 struct iw_request_info *info, 6591 union iwreq_data *dwrq, 6592 char *cmd_str) 6593 { 6594 int ret = 0; 6595 char *sub_cmd = cmd_str + PROFILE_OFFSET + strlen("ASCII_CMD="); 6596 6597 WL_SOFTAP(("\n %s: ASCII_CMD: offs_0:%s, offset_32:\n'%s'\n", 6598 __FUNCTION__, cmd_str, cmd_str + PROFILE_OFFSET)); 6599 6600 if (strnicmp(sub_cmd, "AP_CFG", strlen("AP_CFG")) == 0) { 6601 6602 WL_SOFTAP((" AP_CFG \n")); 6603 6604 6605 if (init_ap_profile_from_string(cmd_str+PROFILE_OFFSET, &my_ap) != 0) { 6606 WL_ERROR(("ERROR: SoftAP CFG prams !\n")); 6607 ret = -1; 6608 } else { 6609 ret = set_ap_cfg(dev, &my_ap); 6610 } 6611 6612 } else if (strnicmp(sub_cmd, "AP_BSS_START", strlen("AP_BSS_START")) == 0) { 6613 6614 WL_SOFTAP(("\n SOFTAP - ENABLE BSS \n")); 6615 6616 WL_SOFTAP(("\n!!! got 'WL_AP_EN_BSS' from WPA supplicant, dev:%s\n", dev->name)); 6617 6618 #ifndef AP_ONLY 6619 if (ap_net_dev == NULL) { 6620 printf("\n ERROR: SOFTAP net_dev* is NULL !!!\n"); 6621 } else { 6622 if ((ret = iwpriv_en_ap_bss(ap_net_dev, info, dwrq, cmd_str)) < 0) 6623 WL_ERROR(("%s line %d fail to set bss up\n", \ 6624 __FUNCTION__, __LINE__)); 6625 } 6626 #else 6627 if ((ret = iwpriv_en_ap_bss(dev, info, dwrq, cmd_str)) < 0) 6628 WL_ERROR(("%s line %d fail to set bss up\n", \ 6629 __FUNCTION__, __LINE__)); 6630 #endif 6631 } else if (strnicmp(sub_cmd, "ASSOC_LST", strlen("ASSOC_LST")) == 0) { 6632 /* no code yet */ 6633 } else if (strnicmp(sub_cmd, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) { 6634 WL_SOFTAP((" \n temp DOWN SOFTAP\n")); 6635 #ifndef AP_ONLY 6636 if ((ret = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) { 6637 WL_ERROR(("%s line %d fail to set bss down\n", \ 6638 __FUNCTION__, __LINE__)); 6639 } 6640 #endif 6641 } 6642 6643 return ret; 6644 } 6645 #endif 6646 6647 static int wl_iw_set_priv( 6648 struct net_device *dev, 6649 struct iw_request_info *info, 6650 struct iw_point *dwrq, 6651 char *ext 6652 ) 6653 { 6654 int ret = 0; 6655 char * extra; 6656 6657 if (!(extra = kmalloc(dwrq->length, GFP_KERNEL))) 6658 return -ENOMEM; 6659 6660 if (copy_from_user(extra, dwrq->pointer, dwrq->length)) { 6661 kfree(extra); 6662 return -EFAULT; 6663 } 6664 6665 WL_TRACE(("%s: SIOCSIWPRIV request %s, info->cmd:%x, info->flags:%d\n dwrq->length:%d", 6666 dev->name, extra, info->cmd, info->flags, dwrq->length)); 6667 6668 net_os_wake_lock(dev); 6669 6670 if (dwrq->length && extra) { 6671 if (strnicmp(extra, "START", strlen("START")) == 0) { 6672 wl_iw_control_wl_on(dev, info); 6673 WL_TRACE(("%s, Received regular START command\n", __FUNCTION__)); 6674 } 6675 6676 if (g_onoff == G_WLAN_SET_OFF) { 6677 WL_TRACE(("%s, missing START, Fail\n", __FUNCTION__)); 6678 kfree(extra); 6679 net_os_wake_unlock(dev); 6680 return -EFAULT; 6681 } 6682 6683 if (strnicmp(extra, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) { 6684 #ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 6685 WL_TRACE(("%s: active scan setting suppressed\n", dev->name)); 6686 #else 6687 ret = wl_iw_set_active_scan(dev, info, (union iwreq_data *)dwrq, extra); 6688 #endif 6689 } else if (strnicmp(extra, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) 6690 #ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 6691 WL_TRACE(("%s: passive scan setting suppressed\n", dev->name)); 6692 #else 6693 ret = wl_iw_set_passive_scan(dev, info, (union iwreq_data *)dwrq, extra); 6694 #endif 6695 else if (strnicmp(extra, "RSSI", strlen("RSSI")) == 0) 6696 ret = wl_iw_get_rssi(dev, info, (union iwreq_data *)dwrq, extra); 6697 else if (strnicmp(extra, "LINKSPEED", strlen("LINKSPEED")) == 0) 6698 ret = wl_iw_get_link_speed(dev, info, (union iwreq_data *)dwrq, extra); 6699 else if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0) 6700 ret = wl_iw_get_macaddr(dev, info, (union iwreq_data *)dwrq, extra); 6701 else if (strnicmp(extra, "COUNTRY", strlen("COUNTRY")) == 0) 6702 ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra); 6703 else if (strnicmp(extra, "STOP", strlen("STOP")) == 0) 6704 ret = wl_iw_control_wl_off(dev, info); 6705 else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0) 6706 ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra); 6707 else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0) 6708 ret = wl_iw_set_band(dev, info, (union iwreq_data *)dwrq, extra); 6709 else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0) 6710 ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); 6711 else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0) 6712 ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); 6713 else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0) 6714 ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra); 6715 #if defined(PNO_SUPPORT) 6716 else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0) 6717 ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra); 6718 else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0) 6719 ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra); 6720 else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0) 6721 ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra); 6722 #endif 6723 #if defined(CSCAN) 6724 else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0) 6725 ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra); 6726 #endif 6727 #ifdef CUSTOMER_HW2 6728 else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) 6729 ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra); 6730 else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) 6731 ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra); 6732 #else 6733 else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) 6734 ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra); 6735 #endif 6736 else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0) 6737 ret = wl_iw_get_power_mode(dev, info, (union iwreq_data *)dwrq, extra); 6738 #ifdef SOFTAP 6739 else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) { 6740 wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra); 6741 } else if (strnicmp(extra, "AP_MAC_LIST_SET", strlen("AP_MAC_LIST_SET")) == 0) { 6742 WL_SOFTAP(("penguin, set AP_MAC_LIST_SET\n")); 6743 set_ap_mac_list(dev, (extra + PROFILE_OFFSET)); 6744 } 6745 #endif 6746 else { 6747 WL_TRACE(("Unknown PRIVATE command: %s: ignored\n", extra)); 6748 snprintf(extra, MAX_WX_STRING, "OK"); 6749 dwrq->length = strlen("OK") + 1; 6750 } 6751 } 6752 6753 net_os_wake_unlock(dev); 6754 6755 if (extra) { 6756 if (copy_to_user(dwrq->pointer, extra, dwrq->length)) { 6757 kfree(extra); 6758 return -EFAULT; 6759 } 6760 6761 kfree(extra); 6762 } 6763 6764 return ret; 6765 } 6766 6767 static const iw_handler wl_iw_handler[] = 6768 { 6769 (iw_handler) wl_iw_config_commit, 6770 (iw_handler) wl_iw_get_name, 6771 (iw_handler) NULL, 6772 (iw_handler) NULL, 6773 (iw_handler) wl_iw_set_freq, 6774 (iw_handler) wl_iw_get_freq, 6775 (iw_handler) wl_iw_set_mode, 6776 (iw_handler) wl_iw_get_mode, 6777 (iw_handler) NULL, 6778 (iw_handler) NULL, 6779 (iw_handler) NULL, 6780 (iw_handler) wl_iw_get_range, 6781 (iw_handler) wl_iw_set_priv, 6782 (iw_handler) NULL, 6783 (iw_handler) NULL, 6784 (iw_handler) NULL, 6785 (iw_handler) wl_iw_set_spy, 6786 (iw_handler) wl_iw_get_spy, 6787 (iw_handler) NULL, 6788 (iw_handler) NULL, 6789 (iw_handler) wl_iw_set_wap, 6790 (iw_handler) wl_iw_get_wap, 6791 #if WIRELESS_EXT > 17 6792 (iw_handler) wl_iw_mlme, 6793 #else 6794 (iw_handler) NULL, 6795 #endif 6796 #if defined(WL_IW_USE_ISCAN) 6797 (iw_handler) wl_iw_iscan_get_aplist, 6798 #else 6799 (iw_handler) wl_iw_get_aplist, 6800 #endif 6801 #if WIRELESS_EXT > 13 6802 #if defined(WL_IW_USE_ISCAN) 6803 (iw_handler) wl_iw_iscan_set_scan, 6804 (iw_handler) wl_iw_iscan_get_scan, 6805 #else 6806 (iw_handler) wl_iw_set_scan, 6807 (iw_handler) wl_iw_get_scan, 6808 #endif 6809 #else 6810 (iw_handler) NULL, 6811 (iw_handler) NULL, 6812 #endif 6813 (iw_handler) wl_iw_set_essid, 6814 (iw_handler) wl_iw_get_essid, 6815 (iw_handler) wl_iw_set_nick, 6816 (iw_handler) wl_iw_get_nick, 6817 (iw_handler) NULL, 6818 (iw_handler) NULL, 6819 (iw_handler) wl_iw_set_rate, 6820 (iw_handler) wl_iw_get_rate, 6821 (iw_handler) wl_iw_set_rts, 6822 (iw_handler) wl_iw_get_rts, 6823 (iw_handler) wl_iw_set_frag, 6824 (iw_handler) wl_iw_get_frag, 6825 (iw_handler) wl_iw_set_txpow, 6826 (iw_handler) wl_iw_get_txpow, 6827 #if WIRELESS_EXT > 10 6828 (iw_handler) wl_iw_set_retry, 6829 (iw_handler) wl_iw_get_retry, 6830 #endif 6831 (iw_handler) wl_iw_set_encode, 6832 (iw_handler) wl_iw_get_encode, 6833 (iw_handler) wl_iw_set_power, 6834 (iw_handler) wl_iw_get_power, 6835 #if WIRELESS_EXT > 17 6836 (iw_handler) NULL, 6837 (iw_handler) NULL, 6838 (iw_handler) wl_iw_set_wpaie, 6839 (iw_handler) wl_iw_get_wpaie, 6840 (iw_handler) wl_iw_set_wpaauth, 6841 (iw_handler) wl_iw_get_wpaauth, 6842 (iw_handler) wl_iw_set_encodeext, 6843 (iw_handler) wl_iw_get_encodeext, 6844 #ifdef BCMWPA2 6845 (iw_handler) wl_iw_set_pmksa, 6846 #endif 6847 #endif 6848 }; 6849 6850 #if WIRELESS_EXT > 12 6851 static const iw_handler wl_iw_priv_handler[] = { 6852 NULL, 6853 (iw_handler)wl_iw_set_active_scan, 6854 NULL, 6855 (iw_handler)wl_iw_get_rssi, 6856 NULL, 6857 (iw_handler)wl_iw_set_passive_scan, 6858 NULL, 6859 (iw_handler)wl_iw_get_link_speed, 6860 NULL, 6861 (iw_handler)wl_iw_get_macaddr, 6862 NULL, 6863 (iw_handler)wl_iw_control_wl_off, 6864 NULL, 6865 (iw_handler)wl_iw_control_wl_on, 6866 #ifdef SOFTAP 6867 NULL, 6868 (iw_handler)iwpriv_set_ap_config, 6869 6870 NULL, 6871 (iw_handler)iwpriv_get_assoc_list, 6872 6873 NULL, 6874 (iw_handler)iwpriv_set_mac_filters, 6875 6876 NULL, 6877 (iw_handler)iwpriv_en_ap_bss, 6878 6879 NULL, 6880 (iw_handler)iwpriv_wpasupp_loop_tst, 6881 6882 NULL, 6883 (iw_handler)iwpriv_softap_stop, 6884 6885 NULL, 6886 (iw_handler)iwpriv_fw_reload, 6887 #endif 6888 #if defined(CSCAN) 6889 6890 NULL, 6891 (iw_handler)iwpriv_set_cscan 6892 #endif 6893 }; 6894 6895 static const struct iw_priv_args wl_iw_priv_args[] = { 6896 { 6897 WL_IW_SET_ACTIVE_SCAN, 6898 0, 6899 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 6900 "SCAN-ACTIVE" 6901 }, 6902 { 6903 WL_IW_GET_RSSI, 6904 0, 6905 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 6906 "RSSI" 6907 }, 6908 { 6909 WL_IW_SET_PASSIVE_SCAN, 6910 0, 6911 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 6912 "SCAN-PASSIVE" 6913 }, 6914 { 6915 WL_IW_GET_LINK_SPEED, 6916 0, 6917 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 6918 "LINKSPEED" 6919 }, 6920 { 6921 WL_IW_GET_CURR_MACADDR, 6922 0, 6923 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 6924 "Macaddr" 6925 }, 6926 { 6927 WL_IW_SET_STOP, 6928 0, 6929 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 6930 "STOP" 6931 }, 6932 { 6933 WL_IW_SET_START, 6934 0, 6935 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 6936 "START" 6937 }, 6938 6939 #ifdef SOFTAP 6940 { 6941 WL_SET_AP_CFG, 6942 IW_PRIV_TYPE_CHAR | 256, 6943 0, 6944 "AP_SET_CFG" 6945 }, 6946 6947 { 6948 WL_AP_STA_LIST, 6949 0, 6950 IW_PRIV_TYPE_CHAR | 0, 6951 "AP_GET_STA_LIST" 6952 }, 6953 6954 { 6955 WL_AP_MAC_FLTR, 6956 IW_PRIV_TYPE_CHAR | 256, 6957 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, 6958 "AP_SET_MAC_FLTR" 6959 }, 6960 6961 { 6962 WL_AP_BSS_START, 6963 0, 6964 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 6965 "AP_BSS_START" 6966 }, 6967 6968 { 6969 AP_LPB_CMD, 6970 IW_PRIV_TYPE_CHAR | 256, 6971 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, 6972 "AP_LPB_CMD" 6973 }, 6974 6975 { 6976 WL_AP_STOP, 6977 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, 6978 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, 6979 "AP_BSS_STOP" 6980 }, 6981 6982 { 6983 WL_FW_RELOAD, 6984 IW_PRIV_TYPE_CHAR | 256, 6985 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, 6986 "WL_FW_RELOAD" 6987 }, 6988 #endif 6989 #if defined(CSCAN) 6990 { 6991 WL_COMBO_SCAN, 6992 IW_PRIV_TYPE_CHAR | 1024, 6993 0, 6994 "CSCAN" 6995 }, 6996 #endif 6997 }; 6998 6999 const struct iw_handler_def wl_iw_handler_def = 7000 { 7001 .num_standard = ARRAYSIZE(wl_iw_handler), 7002 .standard = (iw_handler *) wl_iw_handler, 7003 .num_private = ARRAYSIZE(wl_iw_priv_handler), 7004 .num_private_args = ARRAY_SIZE(wl_iw_priv_args), 7005 .private = (iw_handler *)wl_iw_priv_handler, 7006 .private_args = (void *) wl_iw_priv_args, 7007 7008 #if WIRELESS_EXT >= 19 7009 get_wireless_stats: dhd_get_wireless_stats, 7010 #endif 7011 }; 7012 #endif 7013 7014 7015 int wl_iw_ioctl( 7016 struct net_device *dev, 7017 struct ifreq *rq, 7018 int cmd 7019 ) 7020 { 7021 struct iwreq *wrq = (struct iwreq *) rq; 7022 struct iw_request_info info; 7023 iw_handler handler; 7024 char *extra = NULL; 7025 int token_size = 1, max_tokens = 0, ret = 0; 7026 7027 net_os_wake_lock(dev); 7028 7029 WL_TRACE(("%s: cmd:%x alled via dhd->do_ioctl()entry point\n", __FUNCTION__, cmd)); 7030 if (cmd < SIOCIWFIRST || 7031 IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) || 7032 !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) { 7033 WL_ERROR(("%s: error in cmd=%x : not supported\n", __FUNCTION__, cmd)); 7034 net_os_wake_unlock(dev); 7035 return -EOPNOTSUPP; 7036 } 7037 7038 switch (cmd) { 7039 7040 case SIOCSIWESSID: 7041 case SIOCGIWESSID: 7042 case SIOCSIWNICKN: 7043 case SIOCGIWNICKN: 7044 max_tokens = IW_ESSID_MAX_SIZE + 1; 7045 break; 7046 7047 case SIOCSIWENCODE: 7048 case SIOCGIWENCODE: 7049 #if WIRELESS_EXT > 17 7050 case SIOCSIWENCODEEXT: 7051 case SIOCGIWENCODEEXT: 7052 #endif 7053 max_tokens = wrq->u.data.length; 7054 break; 7055 7056 case SIOCGIWRANGE: 7057 max_tokens = sizeof(struct iw_range) + 500; 7058 break; 7059 7060 case SIOCGIWAPLIST: 7061 token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality); 7062 max_tokens = IW_MAX_AP; 7063 break; 7064 7065 #if WIRELESS_EXT > 13 7066 case SIOCGIWSCAN: 7067 #if defined(WL_IW_USE_ISCAN) 7068 if (g_iscan) 7069 max_tokens = wrq->u.data.length; 7070 else 7071 #endif 7072 max_tokens = IW_SCAN_MAX_DATA; 7073 break; 7074 #endif 7075 7076 case SIOCSIWSPY: 7077 token_size = sizeof(struct sockaddr); 7078 max_tokens = IW_MAX_SPY; 7079 break; 7080 7081 case SIOCGIWSPY: 7082 token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality); 7083 max_tokens = IW_MAX_SPY; 7084 break; 7085 7086 #if WIRELESS_EXT > 17 7087 case SIOCSIWPMKSA: 7088 case SIOCSIWGENIE: 7089 #endif 7090 case SIOCSIWPRIV: 7091 max_tokens = wrq->u.data.length; 7092 break; 7093 } 7094 7095 if (max_tokens && wrq->u.data.pointer) { 7096 if (wrq->u.data.length > max_tokens) { 7097 WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n", \ 7098 __FUNCTION__, cmd, wrq->u.data.length, max_tokens)); 7099 ret = -E2BIG; 7100 goto wl_iw_ioctl_done; 7101 } 7102 if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) { 7103 ret = -ENOMEM; 7104 goto wl_iw_ioctl_done; 7105 } 7106 7107 if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) { 7108 kfree(extra); 7109 ret = -EFAULT; 7110 goto wl_iw_ioctl_done; 7111 } 7112 } 7113 7114 info.cmd = cmd; 7115 info.flags = 0; 7116 7117 ret = handler(dev, &info, &wrq->u, extra); 7118 7119 if (extra) { 7120 if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) { 7121 kfree(extra); 7122 ret = -EFAULT; 7123 goto wl_iw_ioctl_done; 7124 } 7125 7126 kfree(extra); 7127 } 7128 7129 wl_iw_ioctl_done: 7130 7131 net_os_wake_unlock(dev); 7132 7133 return ret; 7134 } 7135 7136 7137 bool 7138 wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, 7139 char* stringBuf, uint buflen) 7140 { 7141 typedef struct conn_fail_event_map_t { 7142 uint32 inEvent; 7143 uint32 inStatus; 7144 uint32 inReason; 7145 const char* outName; 7146 const char* outCause; 7147 } conn_fail_event_map_t; 7148 7149 7150 # define WL_IW_DONT_CARE 9999 7151 const conn_fail_event_map_t event_map [] = { 7152 7153 7154 {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE, 7155 "Conn", "Success"}, 7156 {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE, 7157 "Conn", "NoNetworks"}, 7158 {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, 7159 "Conn", "ConfigMismatch"}, 7160 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH, 7161 "Conn", "EncrypMismatch"}, 7162 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH, 7163 "Conn", "RsnMismatch"}, 7164 {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE, 7165 "Conn", "AuthTimeout"}, 7166 {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, 7167 "Conn", "AuthFail"}, 7168 {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE, 7169 "Conn", "AuthNoAck"}, 7170 {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, 7171 "Conn", "ReassocFail"}, 7172 {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE, 7173 "Conn", "ReassocTimeout"}, 7174 {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE, 7175 "Conn", "ReassocAbort"}, 7176 {WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE, 7177 "Sup", "ConnSuccess"}, 7178 {WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE, 7179 "Sup", "WpaHandshakeFail"}, 7180 {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE, 7181 "Conn", "Deauth"}, 7182 {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE, 7183 "Conn", "DisassocInd"}, 7184 {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE, 7185 "Conn", "Disassoc"} 7186 }; 7187 7188 const char* name = ""; 7189 const char* cause = NULL; 7190 int i; 7191 7192 7193 for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) { 7194 const conn_fail_event_map_t* row = &event_map[i]; 7195 if (row->inEvent == event_type && 7196 (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) && 7197 (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) { 7198 name = row->outName; 7199 cause = row->outCause; 7200 break; 7201 } 7202 } 7203 7204 7205 if (cause) { 7206 memset(stringBuf, 0, buflen); 7207 snprintf(stringBuf, buflen, "%s %s %02d %02d", 7208 name, cause, status, reason); 7209 WL_INFORM(("Connection status: %s\n", stringBuf)); 7210 return TRUE; 7211 } else { 7212 return FALSE; 7213 } 7214 } 7215 7216 #if WIRELESS_EXT > 14 7217 7218 static bool 7219 wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen) 7220 { 7221 uint32 event = ntoh32(e->event_type); 7222 uint32 status = ntoh32(e->status); 7223 uint32 reason = ntoh32(e->reason); 7224 7225 if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) { 7226 return TRUE; 7227 } 7228 else 7229 return FALSE; 7230 } 7231 #endif 7232 7233 #ifndef IW_CUSTOM_MAX 7234 #define IW_CUSTOM_MAX 256 7235 #endif 7236 7237 void 7238 wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) 7239 { 7240 #if WIRELESS_EXT > 13 7241 union iwreq_data wrqu; 7242 char extra[IW_CUSTOM_MAX + 1]; 7243 int cmd = 0; 7244 uint32 event_type = ntoh32(e->event_type); 7245 uint16 flags = ntoh16(e->flags); 7246 uint32 datalen = ntoh32(e->datalen); 7247 uint32 status = ntoh32(e->status); 7248 uint32 toto; 7249 static uint32 roam_no_success = 0; 7250 static bool roam_no_success_send = FALSE; 7251 7252 memset(&wrqu, 0, sizeof(wrqu)); 7253 memset(extra, 0, sizeof(extra)); 7254 7255 if (!dev) { 7256 WL_ERROR(("%s: dev is null\n", __FUNCTION__)); 7257 return; 7258 } 7259 7260 net_os_wake_lock(dev); 7261 7262 WL_TRACE(("%s: dev=%s event=%d \n", __FUNCTION__, dev->name, event_type)); 7263 7264 switch (event_type) { 7265 #if defined(SOFTAP) 7266 case WLC_E_PRUNE: 7267 if (ap_cfg_running) { 7268 char *macaddr = (char *)&e->addr; 7269 WL_SOFTAP(("PRUNE received, %02X:%02X:%02X:%02X:%02X:%02X!\n", 7270 macaddr[0], macaddr[1], macaddr[2], macaddr[3], \ 7271 macaddr[4], macaddr[5])); 7272 7273 if (ap_macmode) { 7274 int i; 7275 for (i = 0; i < ap_black_list.count; i++) { 7276 if (!bcmp(macaddr, &ap_black_list.ea[i], \ 7277 sizeof(struct ether_addr))) { 7278 WL_SOFTAP(("mac in black list, ignore it\n")); 7279 break; 7280 } 7281 } 7282 7283 if (i == ap_black_list.count) { 7284 char mac_buf[32] = {0}; 7285 sprintf(mac_buf, "STA_BLOCK %02X:%02X:%02X:%02X:%02X:%02X", 7286 macaddr[0], macaddr[1], macaddr[2], 7287 macaddr[3], macaddr[4], macaddr[5]); 7288 wl_iw_send_priv_event(priv_dev, mac_buf); 7289 } 7290 } 7291 } 7292 break; 7293 #endif 7294 case WLC_E_TXFAIL: 7295 cmd = IWEVTXDROP; 7296 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); 7297 wrqu.addr.sa_family = ARPHRD_ETHER; 7298 break; 7299 #if WIRELESS_EXT > 14 7300 case WLC_E_JOIN: 7301 case WLC_E_ASSOC_IND: 7302 case WLC_E_REASSOC_IND: 7303 #if defined(SOFTAP) 7304 WL_SOFTAP(("STA connect received %d\n", event_type)); 7305 if (ap_cfg_running) { 7306 wl_iw_send_priv_event(priv_dev, "STA_JOIN"); 7307 goto wl_iw_event_end; 7308 } 7309 #endif 7310 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); 7311 wrqu.addr.sa_family = ARPHRD_ETHER; 7312 cmd = IWEVREGISTERED; 7313 break; 7314 case WLC_E_ROAM: 7315 if (status != WLC_E_STATUS_SUCCESS) { 7316 roam_no_success++; 7317 if ((roam_no_success == 3) && (roam_no_success_send == FALSE)) { 7318 7319 roam_no_success_send = TRUE; 7320 bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); 7321 bzero(&extra, ETHER_ADDR_LEN); 7322 cmd = SIOCGIWAP; 7323 WL_ERROR(("%s ROAMING did not succeeded , send Link Down\n", \ 7324 __FUNCTION__)); 7325 } else { 7326 WL_TRACE(("##### ROAMING did not succeeded %d\n", roam_no_success)); 7327 goto wl_iw_event_end; 7328 } 7329 } else { 7330 memcpy(wrqu.addr.sa_data, &e->addr.octet, ETHER_ADDR_LEN); 7331 wrqu.addr.sa_family = ARPHRD_ETHER; 7332 cmd = SIOCGIWAP; 7333 } 7334 break; 7335 case WLC_E_DEAUTH_IND: 7336 case WLC_E_DISASSOC_IND: 7337 #if defined(SOFTAP) 7338 WL_SOFTAP(("STA disconnect received %d\n", event_type)); 7339 if (ap_cfg_running) { 7340 wl_iw_send_priv_event(priv_dev, "STA_LEAVE"); 7341 goto wl_iw_event_end; 7342 } 7343 #endif 7344 cmd = SIOCGIWAP; 7345 bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); 7346 wrqu.addr.sa_family = ARPHRD_ETHER; 7347 bzero(&extra, ETHER_ADDR_LEN); 7348 break; 7349 case WLC_E_LINK: 7350 case WLC_E_NDIS_LINK: 7351 cmd = SIOCGIWAP; 7352 if (!(flags & WLC_EVENT_MSG_LINK)) { 7353 #ifdef SOFTAP 7354 #ifdef AP_ONLY 7355 if (ap_cfg_running) { 7356 #else 7357 if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) { 7358 #endif 7359 WL_SOFTAP(("AP DOWN %d\n", event_type)); 7360 wl_iw_send_priv_event(priv_dev, "AP_DOWN"); 7361 } else { 7362 WL_TRACE(("STA_Link Down\n")); 7363 g_ss_cache_ctrl.m_link_down = 1; 7364 } 7365 #else 7366 g_ss_cache_ctrl.m_link_down = 1; 7367 #endif 7368 WL_TRACE(("Link Down\n")); 7369 7370 bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); 7371 bzero(&extra, ETHER_ADDR_LEN); 7372 } 7373 else { 7374 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); 7375 g_ss_cache_ctrl.m_link_down = 0; 7376 7377 memcpy(g_ss_cache_ctrl.m_active_bssid, &e->addr, ETHER_ADDR_LEN); 7378 7379 #ifdef SOFTAP 7380 #ifdef AP_ONLY 7381 if (ap_cfg_running) { 7382 #else 7383 if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) { 7384 #endif 7385 WL_SOFTAP(("AP UP %d\n", event_type)); 7386 wl_iw_send_priv_event(priv_dev, "AP_UP"); 7387 } else { 7388 WL_TRACE(("STA_LINK_UP\n")); 7389 roam_no_success_send = FALSE; 7390 roam_no_success = 0; 7391 } 7392 #endif 7393 WL_TRACE(("Link UP\n")); 7394 7395 } 7396 net_os_wake_lock_timeout_enable(dev); 7397 wrqu.addr.sa_family = ARPHRD_ETHER; 7398 break; 7399 case WLC_E_ACTION_FRAME: 7400 cmd = IWEVCUSTOM; 7401 if (datalen + 1 <= sizeof(extra)) { 7402 wrqu.data.length = datalen + 1; 7403 extra[0] = WLC_E_ACTION_FRAME; 7404 memcpy(&extra[1], data, datalen); 7405 WL_TRACE(("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length)); 7406 } 7407 break; 7408 7409 case WLC_E_ACTION_FRAME_COMPLETE: 7410 cmd = IWEVCUSTOM; 7411 memcpy(&toto, data, 4); 7412 if (sizeof(status) + 1 <= sizeof(extra)) { 7413 wrqu.data.length = sizeof(status) + 1; 7414 extra[0] = WLC_E_ACTION_FRAME_COMPLETE; 7415 memcpy(&extra[1], &status, sizeof(status)); 7416 printf("wl_iw_event status %d PacketId %d \n", status, toto); 7417 printf("WLC_E_ACTION_FRAME_COMPLETE len %d \n", wrqu.data.length); 7418 } 7419 break; 7420 #endif 7421 #if WIRELESS_EXT > 17 7422 case WLC_E_MIC_ERROR: { 7423 struct iw_michaelmicfailure *micerrevt = (struct iw_michaelmicfailure *)&extra; 7424 cmd = IWEVMICHAELMICFAILURE; 7425 wrqu.data.length = sizeof(struct iw_michaelmicfailure); 7426 if (flags & WLC_EVENT_MSG_GROUP) 7427 micerrevt->flags |= IW_MICFAILURE_GROUP; 7428 else 7429 micerrevt->flags |= IW_MICFAILURE_PAIRWISE; 7430 memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN); 7431 micerrevt->src_addr.sa_family = ARPHRD_ETHER; 7432 7433 break; 7434 } 7435 #ifdef BCMWPA2 7436 case WLC_E_PMKID_CACHE: { 7437 if (data) 7438 { 7439 struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra; 7440 pmkid_cand_list_t *pmkcandlist; 7441 pmkid_cand_t *pmkidcand; 7442 int count; 7443 7444 cmd = IWEVPMKIDCAND; 7445 pmkcandlist = data; 7446 count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand); 7447 ASSERT(count >= 0); 7448 wrqu.data.length = sizeof(struct iw_pmkid_cand); 7449 pmkidcand = pmkcandlist->pmkid_cand; 7450 while (count) { 7451 bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand)); 7452 if (pmkidcand->preauth) 7453 iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH; 7454 bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data, 7455 ETHER_ADDR_LEN); 7456 #ifndef SANDGATE2G 7457 wireless_send_event(dev, cmd, &wrqu, extra); 7458 #endif 7459 pmkidcand++; 7460 count--; 7461 } 7462 } 7463 goto wl_iw_event_end; 7464 } 7465 #endif 7466 #endif 7467 7468 case WLC_E_SCAN_COMPLETE: 7469 #if defined(WL_IW_USE_ISCAN) 7470 if ((g_iscan) && (g_iscan->sysioc_pid >= 0) && 7471 (g_iscan->iscan_state != ISCAN_STATE_IDLE)) 7472 { 7473 up(&g_iscan->sysioc_sem); 7474 } else { 7475 cmd = SIOCGIWSCAN; 7476 wrqu.data.length = strlen(extra); 7477 WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific scan %d\n", \ 7478 g_iscan->iscan_state)); 7479 } 7480 #else 7481 cmd = SIOCGIWSCAN; 7482 wrqu.data.length = strlen(extra); 7483 WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n")); 7484 #endif 7485 break; 7486 7487 case WLC_E_PFN_NET_FOUND: 7488 { 7489 wlc_ssid_t * ssid; 7490 ssid = (wlc_ssid_t *)data; 7491 WL_TRACE(("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n", \ 7492 __FUNCTION__, PNO_EVENT_UP, ssid->SSID, ssid->SSID_len)); 7493 net_os_wake_lock_timeout_enable(dev); 7494 cmd = IWEVCUSTOM; 7495 memset(&wrqu, 0, sizeof(wrqu)); 7496 strcpy(extra, PNO_EVENT_UP); 7497 wrqu.data.length = strlen(extra); 7498 } 7499 break; 7500 7501 default: 7502 7503 WL_TRACE(("Unknown Event %d: ignoring\n", event_type)); 7504 break; 7505 } 7506 #ifndef SANDGATE2G 7507 if (cmd) { 7508 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) 7509 if (cmd == SIOCGIWSCAN) 7510 wireless_send_event(dev, cmd, &wrqu, NULL); 7511 else 7512 #endif 7513 wireless_send_event(dev, cmd, &wrqu, extra); 7514 } 7515 #endif 7516 7517 #if WIRELESS_EXT > 14 7518 7519 memset(extra, 0, sizeof(extra)); 7520 if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) { 7521 cmd = IWEVCUSTOM; 7522 wrqu.data.length = strlen(extra); 7523 #ifndef SANDGATE2G 7524 wireless_send_event(dev, cmd, &wrqu, extra); 7525 #endif 7526 } 7527 #endif 7528 wl_iw_event_end: 7529 net_os_wake_unlock(dev); 7530 #endif 7531 } 7532 7533 int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) 7534 { 7535 int res = 0; 7536 wl_cnt_t cnt; 7537 int phy_noise; 7538 int rssi; 7539 scb_val_t scb_val; 7540 7541 phy_noise = 0; 7542 if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise)))) 7543 goto done; 7544 7545 phy_noise = dtoh32(phy_noise); 7546 WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise)); 7547 7548 bzero(&scb_val, sizeof(scb_val_t)); 7549 if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) 7550 goto done; 7551 7552 rssi = dtoh32(scb_val.val); 7553 WL_TRACE(("wl_iw_get_wireless_stats rssi=%d\n", rssi)); 7554 if (rssi <= WL_IW_RSSI_NO_SIGNAL) 7555 wstats->qual.qual = 0; 7556 else if (rssi <= WL_IW_RSSI_VERY_LOW) 7557 wstats->qual.qual = 1; 7558 else if (rssi <= WL_IW_RSSI_LOW) 7559 wstats->qual.qual = 2; 7560 else if (rssi <= WL_IW_RSSI_GOOD) 7561 wstats->qual.qual = 3; 7562 else if (rssi <= WL_IW_RSSI_VERY_GOOD) 7563 wstats->qual.qual = 4; 7564 else 7565 wstats->qual.qual = 5; 7566 7567 7568 wstats->qual.level = 0x100 + rssi; 7569 wstats->qual.noise = 0x100 + phy_noise; 7570 #if WIRELESS_EXT > 18 7571 wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM); 7572 #else 7573 wstats->qual.updated |= 7; 7574 #endif 7575 7576 #if WIRELESS_EXT > 11 7577 WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n", (int)sizeof(wl_cnt_t))); 7578 7579 memset(&cnt, 0, sizeof(wl_cnt_t)); 7580 res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t)); 7581 if (res) 7582 { 7583 WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d\n", res)); 7584 goto done; 7585 } 7586 7587 cnt.version = dtoh16(cnt.version); 7588 if (cnt.version != WL_CNT_T_VERSION) { 7589 WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n", 7590 WL_CNT_T_VERSION, cnt.version)); 7591 goto done; 7592 } 7593 7594 wstats->discard.nwid = 0; 7595 wstats->discard.code = dtoh32(cnt.rxundec); 7596 wstats->discard.fragment = dtoh32(cnt.rxfragerr); 7597 wstats->discard.retries = dtoh32(cnt.txfail); 7598 wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant); 7599 wstats->miss.beacon = 0; 7600 7601 WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n", 7602 dtoh32(cnt.txframe), dtoh32(cnt.txbyte))); 7603 WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong))); 7604 WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp))); 7605 WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec))); 7606 WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr))); 7607 WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail))); 7608 WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt))); 7609 WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant))); 7610 7611 #endif 7612 7613 done: 7614 return res; 7615 } 7616 static void 7617 wl_iw_bt_flag_set( 7618 struct net_device *dev, 7619 bool set) 7620 { 7621 char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; 7622 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; 7623 7624 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 7625 rtnl_lock(); 7626 #endif 7627 7628 if (set == TRUE) { 7629 dev_wlc_bufvar_set(dev, "btc_flags", 7630 (char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on)); 7631 } 7632 else { 7633 dev_wlc_bufvar_set(dev, "btc_flags", 7634 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); 7635 } 7636 7637 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 7638 rtnl_unlock(); 7639 #endif 7640 } 7641 7642 static void 7643 wl_iw_bt_timerfunc(ulong data) 7644 { 7645 bt_info_t *bt_local = (bt_info_t *)data; 7646 bt_local->timer_on = 0; 7647 WL_TRACE(("%s\n", __FUNCTION__)); 7648 7649 up(&bt_local->bt_sem); 7650 } 7651 7652 static int 7653 _bt_dhcp_sysioc_thread(void *data) 7654 { 7655 DAEMONIZE("dhcp_sysioc"); 7656 7657 while (down_interruptible(&g_bt->bt_sem) == 0) { 7658 7659 net_os_wake_lock(g_bt->dev); 7660 7661 if (g_bt->timer_on) { 7662 g_bt->timer_on = 0; 7663 del_timer_sync(&g_bt->timer); 7664 } 7665 7666 switch (g_bt->bt_state) { 7667 case BT_DHCP_START: 7668 g_bt->bt_state = BT_DHCP_OPPORTUNITY_WINDOW; 7669 mod_timer(&g_bt->timer, jiffies + BT_DHCP_OPPORTUNITY_WINDOW_TIEM*HZ/1000); 7670 g_bt->timer_on = 1; 7671 break; 7672 7673 case BT_DHCP_OPPORTUNITY_WINDOW: 7674 WL_TRACE(("%s waiting for %d msec expired, force bt flag\n", \ 7675 __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIEM)); 7676 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, TRUE); 7677 g_bt->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; 7678 mod_timer(&g_bt->timer, jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000); 7679 g_bt->timer_on = 1; 7680 break; 7681 7682 case BT_DHCP_FLAG_FORCE_TIMEOUT: 7683 WL_TRACE(("%s waiting for %d msec expired remove bt flag\n", \ 7684 __FUNCTION__, BT_DHCP_FLAG_FORCE_TIME)); 7685 7686 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE); 7687 g_bt->bt_state = BT_DHCP_IDLE; 7688 g_bt->timer_on = 0; 7689 break; 7690 7691 default: 7692 WL_ERROR(("%s error g_status=%d !!!\n", __FUNCTION__, \ 7693 g_bt->bt_state)); 7694 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE); 7695 g_bt->bt_state = BT_DHCP_IDLE; 7696 g_bt->timer_on = 0; 7697 break; 7698 } 7699 7700 net_os_wake_unlock(g_bt->dev); 7701 } 7702 7703 if (g_bt->timer_on) { 7704 g_bt->timer_on = 0; 7705 del_timer_sync(&g_bt->timer); 7706 } 7707 7708 complete_and_exit(&g_bt->bt_exited, 0); 7709 } 7710 7711 static void 7712 wl_iw_bt_release(void) 7713 { 7714 bt_info_t *bt_local = g_bt; 7715 7716 if (!bt_local) { 7717 return; 7718 } 7719 7720 if (bt_local->bt_pid >= 0) { 7721 KILL_PROC(bt_local->bt_pid, SIGTERM); 7722 wait_for_completion(&bt_local->bt_exited); 7723 } 7724 kfree(bt_local); 7725 g_bt = NULL; 7726 } 7727 7728 static int 7729 wl_iw_bt_init(struct net_device *dev) 7730 { 7731 bt_info_t *bt_dhcp = NULL; 7732 7733 bt_dhcp = kmalloc(sizeof(bt_info_t), GFP_KERNEL); 7734 if (!bt_dhcp) 7735 return -ENOMEM; 7736 7737 memset(bt_dhcp, 0, sizeof(bt_info_t)); 7738 bt_dhcp->bt_pid = -1; 7739 g_bt = bt_dhcp; 7740 bt_dhcp->dev = dev; 7741 bt_dhcp->bt_state = BT_DHCP_IDLE; 7742 7743 7744 bt_dhcp->timer_ms = 10; 7745 init_timer(&bt_dhcp->timer); 7746 bt_dhcp->timer.data = (ulong)bt_dhcp; 7747 bt_dhcp->timer.function = wl_iw_bt_timerfunc; 7748 7749 sema_init(&bt_dhcp->bt_sem, 0); 7750 init_completion(&bt_dhcp->bt_exited); 7751 bt_dhcp->bt_pid = kernel_thread(_bt_dhcp_sysioc_thread, bt_dhcp, 0); 7752 if (bt_dhcp->bt_pid < 0) { 7753 WL_ERROR(("Failed in %s\n", __FUNCTION__)); 7754 return -ENOMEM; 7755 } 7756 7757 return 0; 7758 } 7759 7760 int wl_iw_attach(struct net_device *dev, void * dhdp) 7761 { 7762 int params_size; 7763 wl_iw_t *iw; 7764 #if defined(WL_IW_USE_ISCAN) 7765 iscan_info_t *iscan = NULL; 7766 #endif 7767 7768 mutex_init(&wl_cache_lock); 7769 mutex_init(&wl_start_lock); 7770 7771 #if defined(WL_IW_USE_ISCAN) 7772 if (!dev) 7773 return 0; 7774 7775 memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t)); 7776 7777 #ifdef CSCAN 7778 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) + 7779 (WL_NUMCHANNELS * sizeof(uint16)) + WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); 7780 #else 7781 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)); 7782 #endif 7783 iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL); 7784 if (!iscan) 7785 return -ENOMEM; 7786 memset(iscan, 0, sizeof(iscan_info_t)); 7787 7788 iscan->iscan_ex_params_p = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); 7789 if (!iscan->iscan_ex_params_p) 7790 return -ENOMEM; 7791 iscan->iscan_ex_param_size = params_size; 7792 iscan->sysioc_pid = -1; 7793 7794 g_iscan = iscan; 7795 iscan->dev = dev; 7796 iscan->iscan_state = ISCAN_STATE_IDLE; 7797 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; 7798 g_first_counter_scans = 0; 7799 g_iscan->scan_flag = 0; 7800 7801 iscan->timer_ms = 8000; 7802 init_timer(&iscan->timer); 7803 iscan->timer.data = (ulong)iscan; 7804 iscan->timer.function = wl_iw_timerfunc; 7805 7806 sema_init(&iscan->sysioc_sem, 0); 7807 init_completion(&iscan->sysioc_exited); 7808 iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0); 7809 if (iscan->sysioc_pid < 0) 7810 return -ENOMEM; 7811 #endif 7812 7813 iw = *(wl_iw_t **)netdev_priv(dev); 7814 iw->pub = (dhd_pub_t *)dhdp; 7815 #ifdef SOFTAP 7816 priv_dev = dev; 7817 #endif 7818 g_scan = NULL; 7819 7820 g_scan = (void *)kmalloc(G_SCAN_RESULTS, GFP_KERNEL); 7821 if (!g_scan) 7822 return -ENOMEM; 7823 7824 memset(g_scan, 0, G_SCAN_RESULTS); 7825 g_scan_specified_ssid = 0; 7826 7827 #if !defined(CSCAN) 7828 wl_iw_init_ss_cache_ctrl(); 7829 #endif 7830 7831 wl_iw_bt_init(dev); 7832 7833 return 0; 7834 } 7835 7836 void wl_iw_detach(void) 7837 { 7838 #if defined(WL_IW_USE_ISCAN) 7839 iscan_buf_t *buf; 7840 iscan_info_t *iscan = g_iscan; 7841 7842 if (!iscan) 7843 return; 7844 if (iscan->sysioc_pid >= 0) { 7845 KILL_PROC(iscan->sysioc_pid, SIGTERM); 7846 wait_for_completion(&iscan->sysioc_exited); 7847 } 7848 mutex_lock(&wl_cache_lock); 7849 while (iscan->list_hdr) { 7850 buf = iscan->list_hdr->next; 7851 kfree(iscan->list_hdr); 7852 iscan->list_hdr = buf; 7853 } 7854 kfree(iscan->iscan_ex_params_p); 7855 kfree(iscan); 7856 g_iscan = NULL; 7857 mutex_unlock(&wl_cache_lock); 7858 #endif 7859 7860 if (g_scan) 7861 kfree(g_scan); 7862 7863 g_scan = NULL; 7864 #if !defined(CSCAN) 7865 wl_iw_release_ss_cache_ctrl(); 7866 #endif 7867 wl_iw_bt_release(); 7868 #ifdef SOFTAP 7869 if (ap_cfg_running) { 7870 WL_TRACE(("\n%s AP is going down\n", __FUNCTION__)); 7871 wl_iw_send_priv_event(priv_dev, "AP_DOWN"); 7872 } 7873 #endif 7874 7875 } 7876