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