From: Ziggy471 Date: Sun, 19 Dec 2010 21:11:49 +0000 (-0500) Subject: Update BCM4329 Wifi drivers to the glacier version X-Git-Url: https://ziggy471.com/git/gitweb.cgi?p=ziggy471-frankenstein-kernel.git;a=commitdiff;h=50235202d46cc2a3baa0f616775e480e4be67c4f Update BCM4329 Wifi drivers to the glacier version --- --- a/arch/arm/mach-msm/board-bravo-wifi.c +++ b/arch/arm/mach-msm/board-bravo-wifi.c @@ -87,6 +87,7 @@ static struct wifi_platform_data bravo_w .set_carddetect = bravo_wifi_set_carddetect, .mem_prealloc = bravo_wifi_mem_prealloc, .dot11n_enable = 1, + .cscan_enable = 0, }; static struct platform_device bravo_wifi_device = { --- a/arch/arm/mach-msm/board-incrediblec-wifi.c +++ b/arch/arm/mach-msm/board-incrediblec-wifi.c @@ -102,6 +102,7 @@ static struct wifi_platform_data incredi .set_carddetect = incrediblec_wifi_set_carddetect, .mem_prealloc = incrediblec_wifi_mem_prealloc, .dot11n_enable = 1, + .cscan_enable = 0, }; static struct platform_device incrediblec_wifi_device = { --- a/arch/arm/mach-msm/board-supersonic-wifi.c +++ b/arch/arm/mach-msm/board-supersonic-wifi.c @@ -99,6 +99,7 @@ static struct wifi_platform_data superso .set_carddetect = supersonic_wifi_set_carddetect, .mem_prealloc = supersonic_wifi_mem_prealloc, .dot11n_enable = 1, + .cscan_enable = 0, }; static struct platform_device supersonic_wifi_device = { --- a/drivers/net/wireless/bcm4329_204/Makefile +++ b/drivers/net/wireless/bcm4329_204/Makefile @@ -5,7 +5,8 @@ DHDCFLAGS = -DLINUX -DBCMDRIVER -DBCMDON -DSHOW_EVENTS -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS \ -Wall -Wstrict-prototypes -Werror -DOOB_INTR_ONLY -DCUSTOMER_HW2 \ -DDHD_USE_STATIC_BUF -DMMC_SDIO_ABORT -DWLAN_PFN -DWLAN_PROTECT \ - -DBCMWAPI_WPI \ + -DBCMWAPI_WPI -DWLAN_LOW_RSSI_IND -DCSCAN -DSOFTAP_PROTECT \ + -DMMC_RECOVER \ -Idrivers/net/wireless/bcm4329_204 -Idrivers/net/wireless/bcm4329_204/include DHDOFILES = dhd_linux.o linux_osl.o bcmutils.o dhd_common.o dhd_custom_gpio.o \ --- a/drivers/net/wireless/bcm4329_204/bcmsdh_linux.c +++ b/drivers/net/wireless/bcm4329_204/bcmsdh_linux.c @@ -2,13 +2,13 @@ * SDIO access interface for drivers - linux specific (pci only) * * Copyright (C) 1999-2010, Broadcom Corporation - * + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,7 +16,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -600,7 +600,7 @@ int bcmsdh_register_oob_intr(void * dhdp return -ENODEV; set_irq_wake(sdhcinfo->oob_irq, 1); - + myprintf("irq: %d\n", sdhcinfo->oob_irq); return 0; } --- a/drivers/net/wireless/bcm4329_204/dhd.h +++ b/drivers/net/wireless/bcm4329_204/dhd.h @@ -413,6 +413,7 @@ enum dhdhtc_pwr_ctrl{ DHDHTC_POWER_CTRL_BROWSER_LOAD_PAGE, DHDHTC_POWER_CTRL_USER_CONFIG, DHDHTC_POWER_CTRL_WIFI_PHONE, + DHDHTC_POWER_CTRL_FOTA_DOWNLOADING, DHDHTC_POWER_CTRL_MAX_NUM, }; extern int dhdhtc_update_wifi_power_mode(int is_screen_off); @@ -420,5 +421,8 @@ extern int dhdhtc_set_power_control(int extern unsigned int dhdhtc_get_cur_pwr_ctrl(void); extern int dhdhtc_update_dtim_listen_interval(int is_screen_off); +#ifdef MMC_RECOVER +void dhdsdio_set_mmc_recover(int set); +#endif #endif /* _dhd_h_ */ --- a/drivers/net/wireless/bcm4329_204/dhd_cdc.c +++ b/drivers/net/wireless/bcm4329_204/dhd_cdc.c @@ -609,6 +609,7 @@ static int dhd_set_pfn(dhd_pub_t *dhd, i wl_pfn_t pfn_element; int i; int config_network = 0; + int iov_len = 0; /* Disable pfn */ bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); @@ -617,8 +618,9 @@ static int dhd_set_pfn(dhd_pub_t *dhd, i return 0; /* clear pfn */ - bcm_mkiovar("pfnclear", NULL, 0, iovbuf, sizeof(iovbuf)); - dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + iov_len = bcm_mkiovar("pfnclear", NULL, 0, iovbuf, sizeof(iovbuf)); + if (iov_len) + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len); /* set pfn parameters */ pfn_param.version = htod32(PFN_VERSION); @@ -704,6 +706,10 @@ int dhd_set_suspend(int value, dhd_pub_t /* set pfn */ dhd_set_pfn(dhd, 1); #endif + +#ifdef MMC_RECOVER + dhdsdio_set_mmc_recover(1); +#endif /* indicate wl_iw screen off */ wl_iw_set_screen_off(1); @@ -731,6 +737,9 @@ int dhd_set_suspend(int value, dhd_pub_t #ifdef WLAN_PFN dhd_set_pfn(dhd, 0); #endif +#ifdef MMC_RECOVER + dhdsdio_set_mmc_recover(0); +#endif /* indicate wl_iw screen on */ wl_iw_set_screen_off(0); } @@ -854,6 +863,9 @@ int dhd_set_pktfilter(int add, int id, i return 0; } +#define WLC_HT_WEP_RESTRICT 0x01 /* restrict HT with TKIP */ +#define WLC_HT_TKIP_RESTRICT 0x02 /* restrict HT with WEP */ + int dhd_preinit_ioctls(dhd_pub_t *dhd) { @@ -893,6 +905,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint filter_mode = 1; wl_keep_alive_pkt_t keep_alive_pkt; wl_keep_alive_pkt_t *keep_alive_pktp; + int ht_wsec_restrict = WLC_HT_TKIP_RESTRICT | WLC_HT_WEP_RESTRICT; pdhd = dhd; @@ -981,6 +994,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef WLAN_PFN setbit(eventmask, WLC_E_PFN_NET_FOUND); #endif +#ifdef WLAN_LOW_RSSI_IND + setbit(eventmask, WLC_E_RSSI_LOW); +#endif bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); @@ -1114,6 +1130,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len); + /* set HT restrict */ + bcm_mkiovar("ht_wsec_restrict", (char *)&ht_wsec_restrict, 4, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + dhd_os_proto_unblock(dhd); return 0; } --- a/drivers/net/wireless/bcm4329_204/dhd_common.c +++ b/drivers/net/wireless/bcm4329_204/dhd_common.c @@ -49,6 +49,10 @@ extern void htc_linux_periodic_wakeup_st int dhd_msg_level; +#if defined(CSCAN) +#include +#endif + char fw_path[MOD_PARAM_PATHLEN]; char nv_path[MOD_PARAM_PATHLEN]; @@ -57,6 +61,12 @@ uint32 dhd_conn_event; uint32 dhd_conn_status; uint32 dhd_conn_reason; +#define htod32(i) i +#define htod16(i) i +#define dtoh32(i) i +#define dtoh16(i) i +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) + #ifdef DHD_DEBUG const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " __DATE__ " at " __TIME__; @@ -926,3 +936,254 @@ wl_event_to_host_order(wl_event_msg_t *e evt->datalen = ntoh32(evt->datalen); evt->version = ntoh16(evt->version); } + +/* Androd ComboSCAN support */ +#if defined(CSCAN) + +/* + * data parsing from ComboScan tlv list +*/ +int +wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, \ + int input_size, int *bytes_left) +{ + char* str = *list_str; + uint16 short_temp; + uint32 int_temp; + + if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + + /* Clean all dest bytes */ + memset(dst, 0, dst_size); + while (*bytes_left > 0) { + + if (str[0] != token) { + DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", __FUNCTION__, \ + token, str[0], *bytes_left)); + return -1; + } + + *bytes_left -= 1; + str += 1; + + if (input_size == 1) { + memcpy(dst, str, input_size); + } + else if (input_size == 2) { + memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), \ + input_size); + } + else if (input_size == 4) { + memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), \ + input_size); + } + + *bytes_left -= input_size; + str += input_size; + *list_str = str; + return 1; + } + return 1; +} + +/* + * channel list parsing from cscan tlv list +*/ +int +wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, \ + int channel_num, int *bytes_left) +{ + char* str = *list_str; + int idx = 0; + if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + + while (*bytes_left > 0) { + + if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { + *list_str = str; + DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); + return idx; + } + /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ + *bytes_left -= 1; + str += 1; + + if (str[0] == 0) { + /* All channels */ + channel_list[idx] = 0x0; + } + else { + channel_list[idx] = (uint16)str[0]; + DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); + } + *bytes_left -= 1; + str += 1; + + if (idx++ > 255) { + DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); + return -1; + } + } + + *list_str = str; + return idx; +} + +/* + * SSIDs list parsing from cscan tlv list + */ +int +wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left) +{ + char* str = *list_str; + int idx = 0; + if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + + while (*bytes_left > 0) { + + if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { + *list_str = str; + DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); + return idx; + } + + /* Get proper CSCAN_TLV_TYPE_SSID_IE */ + *bytes_left -= 1; + str += 1; + + if (str[0] == 0) { + /* Broadcast SSID */ + ssid[idx].SSID_len = 0; + memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); + *bytes_left -= 1; + str += 1; + DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); + printk (KERN_INFO"[WLAN] BROADCAST SCAN\n"); + } + else if (str[0] <= DOT11_MAX_SSID_LEN) { + printk (KERN_INFO"[WLAN] Specific SSID scan\n"); + /* Get proper SSID size */ + ssid[idx].SSID_len = str[0]; + *bytes_left -= 1; + str += 1; + + /* Get SSID */ + if (ssid[idx].SSID_len > *bytes_left) { + DHD_ERROR(("%s out of memory range len=%d but left=%d\n", \ + __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); + return -1; + } + + memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); + + *bytes_left -= ssid[idx].SSID_len; + str += ssid[idx].SSID_len; + DHD_TRACE(("%s :size=%d left=%d\n", (char*)ssid[idx].SSID, \ + ssid[idx].SSID_len, *bytes_left)); + } + else { + DHD_ERROR(("### SSID size more that %d\n", str[0])); + return -1; + } + + if (idx++ > max) { + DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); + return -1; + } + } + + *list_str = str; + return idx; +} + +/* Parse a comma-separated list from list_str into ssid array, starting + * at index idx. Max specifies size of the ssid array. Parses ssids + * and returns updated idx; if idx >= max not all fit, the excess have + * not been copied. Returns -1 on empty string, or on ssid too long. + */ +int +wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) +{ + char* str, *ptr; + + if ((list_str == NULL) || (*list_str == NULL)) + return -1; + + for (str = *list_str; str != NULL; str = ptr) { + + /* check for next TAG */ + if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { + *list_str = str + strlen(GET_CHANNEL); + return idx; + } + + if ((ptr = strchr(str, ',')) != NULL) { + *ptr++ = '\0'; + } + + if (strlen(str) > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); + return -1; + } + + if (strlen(str) == 0) + ssid[idx].SSID_len = 0; + + if (idx < max) { + strcpy((char*)ssid[idx].SSID, str); + ssid[idx].SSID_len = strlen(str); + } + idx++; + } + return idx; +} + +/* + * Parse channel list from iwpriv CSCAN + */ +int +wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) +{ + int num; + int val; + char* str; + char* endptr = NULL; + + if ((list_str == NULL)||(*list_str == NULL)) + return -1; + + str = *list_str; + num = 0; + while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { + val = (int)strtoul(str, &endptr, 0); + if (endptr == str) { + printk(KERN_INFO"could not parse channel number starting at" + " substring \"%s\" in list:\n%s\n", + str, *list_str); + return -1; + } + str = endptr + strspn(endptr, " ,"); + + if (num == channel_num) { + DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", + channel_num, *list_str)); + return -1; + } + + channel_list[num++] = (uint16)val; + } + *list_str = str; + return num; +} + +#endif + --- a/drivers/net/wireless/bcm4329_204/dhd_linux.c +++ b/drivers/net/wireless/bcm4329_204/dhd_linux.c @@ -99,6 +99,14 @@ int wifi_get_dot11n_enable(void) return 0; } +int wifi_get_cscan_enable(void) +{ + if (wifi_control_data && wifi_control_data->cscan_enable) { + return wifi_control_data->cscan_enable; + } + return 0; +} + int wifi_set_carddetect(int on) { myprintf("%s = %d\n", __FUNCTION__, on); @@ -853,6 +861,8 @@ _dhd_sysioc_thread(void *data) } dhd_os_wake_unlock(&dhd->pub); } + + myprintf("%s exit\n", __func__); complete_and_exit(&dhd->sysioc_exited, 0); } @@ -865,6 +875,14 @@ dhd_set_mac_address(struct net_device *d struct sockaddr *sa = (struct sockaddr *)addr; int ifidx; + myprintf("enter %s\n", __func__); + + /* BRCM: anthony, add for debug, reject if down */ + if ( !dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) { + printk("%s: dhd is down. skip it.\n", __func__); + return -ENODEV; + } + ifidx = dhd_net2idx(dhd, dev); if (ifidx == DHD_BAD_IF) return -1; @@ -883,6 +901,15 @@ dhd_set_multicast_list(struct net_device dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); int ifidx; + + myprintf("enter %s\n", __func__); + + /* BRCM: anthoy, add for debug, reject if down */ + if ( !dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN) ) { + printk("%s: dhd is down. skip it.\n", __func__); + return; + } + ifidx = dhd_net2idx(dhd, dev); if (ifidx == DHD_BAD_IF) return; @@ -1208,7 +1235,7 @@ dhd_watchdog_thread(void *data) else break; } - + myprintf("%s exit\n", __func__); complete_and_exit(&dhd->watchdog_exited, 0); } @@ -1277,7 +1304,7 @@ dhd_dpc_thread(void *data) else break; } - + myprintf("%s exit\n", __func__); complete_and_exit(&dhd->dpc_exited, 0); } @@ -1525,6 +1552,13 @@ dhd_ioctl_entry(struct net_device *net, int ifidx; bool is_set_key_cmd; + + /* BRCM: anthoy, add for debug, reject if down */ + if ( !dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)){ + myprintf("%s: dhd is down. skip it.\n", __func__); + return -ENODEV; + } + ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); @@ -2418,6 +2452,11 @@ dhd_os_wd_timer(void *bus, uint wdtick) dhd_info_t *dhd = (dhd_info_t *)pub->info; static uint save_dhd_watchdog_ms = 0; + /* BRCM: anthony: stop timer, if bus down. */ + if (pub->busstate == DHD_BUS_DOWN) { + return; + } + /* Totally stop the timer */ if (!wdtick && dhd->wd_timer_valid == TRUE) { del_timer_sync(&dhd->timer); --- a/drivers/net/wireless/bcm4329_204/dhd_sdio.c +++ b/drivers/net/wireless/bcm4329_204/dhd_sdio.c @@ -2,13 +2,13 @@ * DHD Bus Module for SDIO * * Copyright (C) 1999-2010, Broadcom Corporation - * + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,7 +16,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -2445,6 +2445,8 @@ dhd_bus_stop(struct dhd_bus *bus, bool e if (enforce_mutex) dhd_os_sdlock(bus->dhd); + myprintf("%s enter\n", __func__); + BUS_WAKE(bus); /* Enable clock for device interrupts */ @@ -3798,6 +3800,21 @@ dhdsdio_hostmail(dhd_bus_t *bus) return intstatus; } +#ifdef MMC_RECOVER +static uint8 prev_tx_seq = 0; +static uint8 prev_tx_max = 0; +static int max_equal_count = 0; +static int start_mmc_recover = 0; +void dhdsdio_set_mmc_recover(int set) +{ + // myprintf("set mmc recover %d\n", set); + if (set) + start_mmc_recover = 1; + else + start_mmc_recover = 0; +} +#endif + static int dhdsdio_regfail = 0; bool dhdsdio_dpc(dhd_bus_t *bus) @@ -3957,6 +3974,28 @@ clkwait: bcmsdh_intr_enable(sdh); } +#ifdef MMC_RECOVER + if (start_mmc_recover) { + if ((bus->tx_max == bus->tx_seq)&&(bus->tx_max == prev_tx_max)&&(bus->tx_seq == prev_tx_seq)) { + max_equal_count++; + //myprintf("bad case, count %d\n", max_equal_count); + //myprintf("framecnt = %d\n", framecnt); + } else { + max_equal_count = 0; + } + + prev_tx_max = bus->tx_max; + prev_tx_seq = bus->tx_seq; + + if (max_equal_count >= 5) { + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + //bus->tx_max = bus->tx_seq + 2; + max_equal_count = 0; + //myprintf("reset count\n"); + } + } +#endif + if (DATAOK(bus) && bus->ctrl_frame_stat) { int ret, i; @@ -4102,7 +4141,7 @@ dhdsdio_isr(void *arg) #else bus->dpc_sched = TRUE; dhd_sched_dpc(bus->dhd); -#endif +#endif } @@ -5012,9 +5051,11 @@ dhdsdio_release(dhd_bus_t *bus, osl_t *o if (bus->dhd) { - dhdsdio_release_dongle(bus, osh); - + /* BRCM: anthony: move dhd_detach before dhdsdio_release_dongle + * to avoid unnecessary commands running. + */ dhd_detach(bus->dhd); + dhdsdio_release_dongle(bus, osh); bus->dhd = NULL; } @@ -5064,11 +5105,11 @@ dhdsdio_release_dongle(dhd_bus_t *bus, o return; if (bus->sih) { - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); #if !defined(BCMLXSDMMC) + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); si_watchdog(bus->sih, 4); -#endif /* !defined(BCMLXSDMMC) */ dhdsdio_clkctl(bus, CLK_NONE, FALSE); +#endif /* !defined(BCMLXSDMMC) */ si_detach(bus->sih); if (bus->vars && bus->varsz) MFREE(osh, bus->vars, bus->varsz); @@ -5564,7 +5605,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 #if !defined(IGNORE_ETH0_DOWN) /* Restore flow control */ dhd_txflowcontrol(bus->dhd, 0, OFF); -#endif +#endif DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); } else --- a/drivers/net/wireless/bcm4329_204/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcm4329_204/include/proto/bcmevent.h @@ -2,13 +2,13 @@ * Broadcom Event protocol definitions * * Copyright (C) 1999-2009, Broadcom Corporation - * + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,7 +16,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -41,26 +41,26 @@ #include -#define BCM_EVENT_MSG_VERSION 1 -#define BCM_MSG_IFNAME_MAX 16 +#define BCM_EVENT_MSG_VERSION 1 +#define BCM_MSG_IFNAME_MAX 16 -#define WLC_EVENT_MSG_LINK 0x01 -#define WLC_EVENT_MSG_FLUSHTXQ 0x02 -#define WLC_EVENT_MSG_GROUP 0x04 +#define WLC_EVENT_MSG_LINK 0x01 +#define WLC_EVENT_MSG_FLUSHTXQ 0x02 +#define WLC_EVENT_MSG_GROUP 0x04 typedef BWL_PRE_PACKED_STRUCT struct { uint16 version; - uint16 flags; - uint32 event_type; - uint32 status; - uint32 reason; - uint32 auth_type; - uint32 datalen; - struct ether_addr addr; - char ifname[BCM_MSG_IFNAME_MAX]; + uint16 flags; + uint32 event_type; + uint32 status; + uint32 reason; + uint32 auth_type; + uint32 datalen; + struct ether_addr addr; + char ifname[BCM_MSG_IFNAME_MAX]; } BWL_POST_PACKED_STRUCT wl_event_msg_t; @@ -68,145 +68,146 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm struct ether_header eth; bcmeth_hdr_t bcm_hdr; wl_event_msg_t event; - + } BWL_POST_PACKED_STRUCT bcm_event_t; #define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) -#define WLC_E_SET_SSID 0 -#define WLC_E_JOIN 1 -#define WLC_E_START 2 -#define WLC_E_AUTH 3 -#define WLC_E_AUTH_IND 4 -#define WLC_E_DEAUTH 5 -#define WLC_E_DEAUTH_IND 6 -#define WLC_E_ASSOC 7 -#define WLC_E_ASSOC_IND 8 -#define WLC_E_REASSOC 9 -#define WLC_E_REASSOC_IND 10 -#define WLC_E_DISASSOC 11 -#define WLC_E_DISASSOC_IND 12 -#define WLC_E_QUIET_START 13 -#define WLC_E_QUIET_END 14 -#define WLC_E_BEACON_RX 15 -#define WLC_E_LINK 16 -#define WLC_E_MIC_ERROR 17 -#define WLC_E_NDIS_LINK 18 -#define WLC_E_ROAM 19 -#define WLC_E_TXFAIL 20 -#define WLC_E_PMKID_CACHE 21 -#define WLC_E_RETROGRADE_TSF 22 -#define WLC_E_PRUNE 23 -#define WLC_E_AUTOAUTH 24 -#define WLC_E_EAPOL_MSG 25 -#define WLC_E_SCAN_COMPLETE 26 -#define WLC_E_ADDTS_IND 27 -#define WLC_E_DELTS_IND 28 -#define WLC_E_BCNSENT_IND 29 -#define WLC_E_BCNRX_MSG 30 -#define WLC_E_BCNLOST_MSG 31 -#define WLC_E_ROAM_PREP 32 -#define WLC_E_PFN_NET_FOUND 33 -#define WLC_E_PFN_NET_LOST 34 +#define WLC_E_SET_SSID 0 +#define WLC_E_JOIN 1 +#define WLC_E_START 2 +#define WLC_E_AUTH 3 +#define WLC_E_AUTH_IND 4 +#define WLC_E_DEAUTH 5 +#define WLC_E_DEAUTH_IND 6 +#define WLC_E_ASSOC 7 +#define WLC_E_ASSOC_IND 8 +#define WLC_E_REASSOC 9 +#define WLC_E_REASSOC_IND 10 +#define WLC_E_DISASSOC 11 +#define WLC_E_DISASSOC_IND 12 +#define WLC_E_QUIET_START 13 +#define WLC_E_QUIET_END 14 +#define WLC_E_BEACON_RX 15 +#define WLC_E_LINK 16 +#define WLC_E_MIC_ERROR 17 +#define WLC_E_NDIS_LINK 18 +#define WLC_E_ROAM 19 +#define WLC_E_TXFAIL 20 +#define WLC_E_PMKID_CACHE 21 +#define WLC_E_RETROGRADE_TSF 22 +#define WLC_E_PRUNE 23 +#define WLC_E_AUTOAUTH 24 +#define WLC_E_EAPOL_MSG 25 +#define WLC_E_SCAN_COMPLETE 26 +#define WLC_E_ADDTS_IND 27 +#define WLC_E_DELTS_IND 28 +#define WLC_E_BCNSENT_IND 29 +#define WLC_E_BCNRX_MSG 30 +#define WLC_E_BCNLOST_MSG 31 +#define WLC_E_ROAM_PREP 32 +#define WLC_E_PFN_NET_FOUND 33 +#define WLC_E_PFN_NET_LOST 34 #define WLC_E_RESET_COMPLETE 35 #define WLC_E_JOIN_START 36 #define WLC_E_ROAM_START 37 #define WLC_E_ASSOC_START 38 #define WLC_E_IBSS_ASSOC 39 #define WLC_E_RADIO 40 -#define WLC_E_PSM_WATCHDOG 41 -#define WLC_E_PROBREQ_MSG 44 +#define WLC_E_PSM_WATCHDOG 41 +#define WLC_E_PROBREQ_MSG 44 #define WLC_E_SCAN_CONFIRM_IND 45 -#define WLC_E_PSK_SUP 46 +#define WLC_E_PSK_SUP 46 #define WLC_E_COUNTRY_CODE_CHANGED 47 -#define WLC_E_EXCEEDED_MEDIUM_TIME 48 -#define WLC_E_ICV_ERROR 49 -#define WLC_E_UNICAST_DECODE_ERROR 50 -#define WLC_E_MULTICAST_DECODE_ERROR 51 +#define WLC_E_EXCEEDED_MEDIUM_TIME 48 +#define WLC_E_ICV_ERROR 49 +#define WLC_E_UNICAST_DECODE_ERROR 50 +#define WLC_E_MULTICAST_DECODE_ERROR 51 #define WLC_E_TRACE 52 -#define WLC_E_IF 54 +#define WLC_E_IF 54 #define WLC_E_ASSOCREQ_IE 55 /* penguin, Send up assoc ie */ -#define WLC_E_RSSI 56 -#define WLC_E_PFN_SCAN_COMPLETE 57 -#define WLC_E_ACTION_FRAME 58 -#define WLC_E_ACTION_FRAME_COMPLETE 59 - -#define WLC_E_ESCAN_RESULT 69 -#define WLC_E_WAKE_EVENT 70 -#define WLC_E_LAST 71 - - - - -#define WLC_E_STATUS_SUCCESS 0 -#define WLC_E_STATUS_FAIL 1 -#define WLC_E_STATUS_TIMEOUT 2 -#define WLC_E_STATUS_NO_NETWORKS 3 -#define WLC_E_STATUS_ABORT 4 -#define WLC_E_STATUS_NO_ACK 5 -#define WLC_E_STATUS_UNSOLICITED 6 -#define WLC_E_STATUS_ATTEMPT 7 -#define WLC_E_STATUS_PARTIAL 8 -#define WLC_E_STATUS_NEWSCAN 9 -#define WLC_E_STATUS_NEWASSOC 10 -#define WLC_E_STATUS_11HQUIET 11 -#define WLC_E_STATUS_SUPPRESS 12 -#define WLC_E_STATUS_NOCHANS 13 -#define WLC_E_STATUS_CCXFASTRM 14 -#define WLC_E_STATUS_CS_ABORT 15 - - -#define WLC_E_REASON_INITIAL_ASSOC 0 -#define WLC_E_REASON_LOW_RSSI 1 -#define WLC_E_REASON_DEAUTH 2 -#define WLC_E_REASON_DISASSOC 3 -#define WLC_E_REASON_BCNS_LOST 4 -#define WLC_E_REASON_FAST_ROAM_FAILED 5 -#define WLC_E_REASON_DIRECTED_ROAM 6 -#define WLC_E_REASON_TSPEC_REJECTED 7 -#define WLC_E_REASON_BETTER_AP 8 - - -#define WLC_E_PRUNE_ENCR_MISMATCH 1 -#define WLC_E_PRUNE_BCAST_BSSID 2 -#define WLC_E_PRUNE_MAC_DENY 3 -#define WLC_E_PRUNE_MAC_NA 4 -#define WLC_E_PRUNE_REG_PASSV 5 -#define WLC_E_PRUNE_SPCT_MGMT 6 -#define WLC_E_PRUNE_RADAR 7 -#define WLC_E_RSN_MISMATCH 8 -#define WLC_E_PRUNE_NO_COMMON_RATES 9 -#define WLC_E_PRUNE_BASIC_RATES 10 -#define WLC_E_PRUNE_CIPHER_NA 12 -#define WLC_E_PRUNE_KNOWN_STA 13 -#define WLC_E_PRUNE_WDS_PEER 15 -#define WLC_E_PRUNE_QBSS_LOAD 16 -#define WLC_E_PRUNE_HOME_AP 17 - - -#define WLC_E_SUP_OTHER 0 -#define WLC_E_SUP_DECRYPT_KEY_DATA 1 -#define WLC_E_SUP_BAD_UCAST_WEP128 2 -#define WLC_E_SUP_BAD_UCAST_WEP40 3 -#define WLC_E_SUP_UNSUP_KEY_LEN 4 -#define WLC_E_SUP_PW_KEY_CIPHER 5 -#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 -#define WLC_E_SUP_MSG3_IE_MISMATCH 7 -#define WLC_E_SUP_NO_INSTALL_FLAG 8 -#define WLC_E_SUP_MSG3_NO_GTK 9 -#define WLC_E_SUP_GRP_KEY_CIPHER 10 -#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 -#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 -#define WLC_E_SUP_SEND_FAIL 13 -#define WLC_E_SUP_DEAUTH 14 -#define WLC_E_SUP_WPA_PSK_TMO 15 +#define WLC_E_RSSI 56 +#define WLC_E_PFN_SCAN_COMPLETE 57 +#define WLC_E_ACTION_FRAME 58 +#define WLC_E_ACTION_FRAME_COMPLETE 59 +#define WLC_E_RSSI_LOW 60 /* penguin, Send up rssi low event */ + +#define WLC_E_ESCAN_RESULT 69 +#define WLC_E_WAKE_EVENT 70 +#define WLC_E_LAST 71 + + + + +#define WLC_E_STATUS_SUCCESS 0 +#define WLC_E_STATUS_FAIL 1 +#define WLC_E_STATUS_TIMEOUT 2 +#define WLC_E_STATUS_NO_NETWORKS 3 +#define WLC_E_STATUS_ABORT 4 +#define WLC_E_STATUS_NO_ACK 5 +#define WLC_E_STATUS_UNSOLICITED 6 +#define WLC_E_STATUS_ATTEMPT 7 +#define WLC_E_STATUS_PARTIAL 8 +#define WLC_E_STATUS_NEWSCAN 9 +#define WLC_E_STATUS_NEWASSOC 10 +#define WLC_E_STATUS_11HQUIET 11 +#define WLC_E_STATUS_SUPPRESS 12 +#define WLC_E_STATUS_NOCHANS 13 +#define WLC_E_STATUS_CCXFASTRM 14 +#define WLC_E_STATUS_CS_ABORT 15 + + +#define WLC_E_REASON_INITIAL_ASSOC 0 +#define WLC_E_REASON_LOW_RSSI 1 +#define WLC_E_REASON_DEAUTH 2 +#define WLC_E_REASON_DISASSOC 3 +#define WLC_E_REASON_BCNS_LOST 4 +#define WLC_E_REASON_FAST_ROAM_FAILED 5 +#define WLC_E_REASON_DIRECTED_ROAM 6 +#define WLC_E_REASON_TSPEC_REJECTED 7 +#define WLC_E_REASON_BETTER_AP 8 + + +#define WLC_E_PRUNE_ENCR_MISMATCH 1 +#define WLC_E_PRUNE_BCAST_BSSID 2 +#define WLC_E_PRUNE_MAC_DENY 3 +#define WLC_E_PRUNE_MAC_NA 4 +#define WLC_E_PRUNE_REG_PASSV 5 +#define WLC_E_PRUNE_SPCT_MGMT 6 +#define WLC_E_PRUNE_RADAR 7 +#define WLC_E_RSN_MISMATCH 8 +#define WLC_E_PRUNE_NO_COMMON_RATES 9 +#define WLC_E_PRUNE_BASIC_RATES 10 +#define WLC_E_PRUNE_CIPHER_NA 12 +#define WLC_E_PRUNE_KNOWN_STA 13 +#define WLC_E_PRUNE_WDS_PEER 15 +#define WLC_E_PRUNE_QBSS_LOAD 16 +#define WLC_E_PRUNE_HOME_AP 17 + + +#define WLC_E_SUP_OTHER 0 +#define WLC_E_SUP_DECRYPT_KEY_DATA 1 +#define WLC_E_SUP_BAD_UCAST_WEP128 2 +#define WLC_E_SUP_BAD_UCAST_WEP40 3 +#define WLC_E_SUP_UNSUP_KEY_LEN 4 +#define WLC_E_SUP_PW_KEY_CIPHER 5 +#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 +#define WLC_E_SUP_MSG3_IE_MISMATCH 7 +#define WLC_E_SUP_NO_INSTALL_FLAG 8 +#define WLC_E_SUP_MSG3_NO_GTK 9 +#define WLC_E_SUP_GRP_KEY_CIPHER 10 +#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 +#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 +#define WLC_E_SUP_SEND_FAIL 13 +#define WLC_E_SUP_DEAUTH 14 +#define WLC_E_SUP_WPA_PSK_TMO 15 -#define WLC_E_IF_ADD 1 -#define WLC_E_IF_DEL 2 +#define WLC_E_IF_ADD 1 +#define WLC_E_IF_DEL 2 #include -#endif +#endif --- a/drivers/net/wireless/bcm4329_204/wl_iw.c +++ b/drivers/net/wireless/bcm4329_204/wl_iw.c @@ -52,10 +52,11 @@ typedef const struct si_pub si_t; #include #include #define WL_ERROR(x) myprintf x -#define WL_TRACE(x) +#define WL_TRACE(x) //myprintf x #define WL_ASSOC(x) #define WL_INFORM(x) #define WL_WSEC(x) +#define WL_SCAN(x) //myprintf x #include @@ -100,6 +101,21 @@ static bool ap_cfg_running = FALSE; static bool ap_fw_loaded = FALSE; static int ap_mode = 0; #endif + +#ifdef SOFTAP_PROTECT +#define AP_PROTECT_TIME 5000 +#define AP_MAX_FAIL_COUNT 2 +typedef struct ap_info { + struct timer_list timer; + uint32 timer_on; + long ap_pid; + struct semaphore ap_sem; + struct completion ap_exited; +} ap_info_t; +ap_info_t *g_ap_protect = NULL; +static void wl_iw_ap_restart(void); +#endif + static struct net_device *priv_dev; #ifdef WLAN_AUTO_RSSI @@ -122,7 +138,7 @@ extern bool wl_iw_conn_status_str(uint32 extern void dhd_customer_gpio_wlan_ctrl(int onoff); extern uint dhd_dev_reset(struct net_device *dev, uint8 flag); extern void dhd_dev_init_ioctl(struct net_device *dev); - +extern int wifi_get_cscan_enable(void); uint wl_msg_level = WL_ERROR_VAL; #define MAX_WLIW_IOCTL_LEN 1024 @@ -225,12 +241,15 @@ typedef struct iscan_info { uint32 scan_flag; - char ioctlbuf[WLC_IOCTL_SMLEN]; + char ioctlbuf[WLC_IOCTL_MEDLEN]; + wl_iscan_params_t *iscan_ex_params_p; + int iscan_ex_param_size; } iscan_info_t; static void wl_iw_bt_flag_set(struct net_device *dev, bool set); static void wl_iw_bt_release(void); static int wl_iw_fixed_scan(struct net_device *dev); +static int wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan); typedef enum bt_coex_status { BT_DHCP_IDLE = 0, @@ -450,6 +469,10 @@ dev_wlc_ioctl( #ifdef WLAN_PROTECT void wl_iw_set_busdown(int busdown) { +#ifdef CONFIG_BCM4329_SOFTAP + if (ap_mode) /* handle by ap recover */ + return; +#endif wl_iw_busdown = busdown; } #endif @@ -785,7 +808,13 @@ wl_iw_del_pfn( return 0; } - strncpy(ssid, extra + ssid_offset+1, + if (ssid_size > 32) { + WL_ERROR(("%s: ssid too long: %s\n", __FUNCTION__, + (char *)extra + ssid_offset + 1)); + return 0; + } + + strncpy(ssid, extra + ssid_offset + 1, MIN(ssid_size, sizeof(ssid))); WL_ERROR(("%s: remove ssid: %s\n", __FUNCTION__, ssid)); @@ -798,6 +827,57 @@ wl_iw_del_pfn( } #endif +#ifdef WLAN_LOW_RSSI_IND +static int +wl_iw_low_rssi_set( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + char *p = extra; + int low_rssi_trigger; + int low_rssi_duration; + int trigger_offset; + int duration_offset; + char tran_buf[16] = {0}; + char *pp; + int err = 0; + WL_TRACE(("%s\n", __FUNCTION__)); + + trigger_offset = strcspn(extra, " "); + duration_offset = strcspn(extra+trigger_offset + 1, " "); + + // myprintf("%s: %s, t_off: %d, dur: %d\n", __func__, extra, trigger_offset, duration_offset); + + pp = extra+trigger_offset+1; + + memcpy(tran_buf, pp, duration_offset); + low_rssi_trigger = bcm_strtoul(tran_buf, NULL, 10); + + err |= dev_wlc_intvar_set(dev, "low_rssi_trigger", low_rssi_trigger); + + memset(tran_buf, 0, 16); + pp = extra+trigger_offset+duration_offset+2; + memcpy(tran_buf, pp, strlen(extra) - (trigger_offset+duration_offset+1)); + low_rssi_duration = bcm_strtoul(tran_buf, NULL, 10); + err |= dev_wlc_intvar_set(dev, "low_rssi_duration", low_rssi_duration); + + myprintf("set low rssi trigger %d, duration %d\n",low_rssi_trigger, low_rssi_duration); + + if (err) { + WL_ERROR(("set low rssi ind fail!\n")); + p += snprintf(p, MAX_WX_STRING, "FAIL"); + } else + p += snprintf(p, MAX_WX_STRING, "OK"); + wrqu->data.length = p - extra + 1; + + + return 0; +} +#endif + static int wl_iw_set_country( struct net_device *dev, @@ -911,7 +991,7 @@ static int btcoex_dhcp_timer_start(struc char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; char buf_reg12va_sco_time[4] = { 12, 0, 0, 0}; - int sco_lasttime; + int sco_lasttime = 0; int ret; bcm_mkiovar("btc_params", (char*)&buf_reg12va_sco_time[0], sizeof(buf_reg12va_sco_time), ioctlbuf, sizeof(ioctlbuf)); @@ -1030,6 +1110,15 @@ wl_iw_set_power_mode( dhdhtc_set_power_control(1, DHDHTC_POWER_CTRL_USER_CONFIG); dhdhtc_update_wifi_power_mode(screen_off); break; + /* for fota download */ + case 30: + dhdhtc_set_power_control(0, DHDHTC_POWER_CTRL_FOTA_DOWNLOADING); + dhdhtc_update_wifi_power_mode(screen_off); + break; + case 31: + dhdhtc_set_power_control(1, DHDHTC_POWER_CTRL_FOTA_DOWNLOADING); + dhdhtc_update_wifi_power_mode(screen_off); + break; case 99: /* For debug. power active or not while usb plugin */ dhdcdc_power_active_while_plugin = !dhdcdc_power_active_while_plugin; dhdhtc_update_wifi_power_mode(screen_off); @@ -1540,11 +1629,13 @@ _wl_control_sysioc_thread_wl_off(void *d dhd_dev_reset(wl_ctl->dev, 1); #if defined(WL_IW_USE_ISCAN) + if(!wifi_get_cscan_enable()) + { wl_iw_free_ss_cache(); wl_iw_run_ss_cache_timer(0); memset(g_scan, 0, G_SCAN_RESULTS); - g_ss_cache_ctrl.m_link_down = 1; + } g_scan_specified_ssid = 0; g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; @@ -1661,8 +1752,11 @@ wl_iw_control_wl_off( dhd_dev_reset(dev, 1); #if defined(WL_IW_USE_ISCAN) + if(!wifi_get_cscan_enable()) + { wl_iw_free_ss_cache(); wl_iw_run_ss_cache_timer(0); + } memset(g_scan, 0, G_SCAN_RESULTS); g_ss_cache_ctrl.m_link_down = 1; @@ -2805,26 +2899,25 @@ wl_iw_iscan(iscan_info_t *iscan, wlc_ssi return -EINVAL; } - if (ssid && ssid->SSID_len) { - params_size += sizeof(wlc_ssid_t); + if (ssid && ssid->SSID_len) { + params_size += sizeof(wlc_ssid_t); } - params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); + params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); if (params == NULL) { return -ENOMEM; } memset(params, 0, params_size); ASSERT(params_size < WLC_IOCTL_SMLEN); + if(!wifi_get_cscan_enable()){ + err = wl_iw_iscan_prep(¶ms->params, ssid); - err = wl_iw_iscan_prep(¶ms->params, ssid); - - if (!err) { - params->version = htod32(ISCAN_REQ_VERSION); - params->action = htod16(action); - params->scan_duration = htod16(0); - + if (!err) { + params->version = htod32(ISCAN_REQ_VERSION); + params->action = htod16(action); + params->scan_duration = htod16(0); iscan_retry: - err = dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size, + err = dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size, iscan->ioctlbuf, WLC_IOCTL_SMLEN); if (err&&(retry < 2)) { retry++; @@ -2835,10 +2928,38 @@ iscan_retry: if (err) WL_ERROR(("iscan fail!\n")); - } + } + } + else{ + iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION); + iscan->iscan_ex_params_p->action = htod16(action); + iscan->iscan_ex_params_p->scan_duration = htod16(0); + + WL_SCAN(("%s : nprobes=%d\n", __FUNCTION__, iscan->iscan_ex_params_p->params.nprobes)); + WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time)); + WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time)); + WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time)); + WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type)); + WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type)); + WL_SCAN(("channel_num=%d\n", iscan->iscan_ex_params_p->params.channel_num&WL_SCAN_PARAMS_COUNT_MASK)); - kfree(params); - return err; + + +cscan_retry: + err = dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, \ + iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)); + if (err&&(retry < 2)) { + retry++; + WL_ERROR(("iscan retry!\n")); + bcm_mdelay(500); + goto cscan_retry; + } + + if (err) + WL_ERROR(("iscan fail!\n")); + } + kfree(params); + return err; } static void @@ -2865,6 +2986,19 @@ static void wl_iw_set_event_mask(struct iovbuf, sizeof(iovbuf)); } +static void wl_iw_set_event_mask_deauth(struct net_device *dev) +{ + char eventmask[WL_EVENTING_MASK_LEN]; + char iovbuf[WL_EVENTING_MASK_LEN + 12]; + + WL_SOFTAP(("set deauth event!\n")); + dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf)); + bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); + setbit(eventmask, WLC_E_DEAUTH); + dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, + iovbuf, sizeof(iovbuf)); +} + static uint32 wl_iw_iscan_get(iscan_info_t *iscan) { @@ -2874,6 +3008,7 @@ wl_iw_iscan_get(iscan_info_t *iscan) wl_iscan_results_t list; wl_scan_results_t *results; uint32 status; + int res = 0; mutex_lock(&wl_cache_lock); if (iscan->list_cur) { @@ -2908,20 +3043,28 @@ wl_iw_iscan_get(iscan_info_t *iscan) memset(&list, 0, sizeof(list)); list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); - (void) dev_iw_iovar_getbuf( + res = dev_iw_iovar_getbuf( iscan->dev, "iscanresults", &list, WL_ISCAN_RESULTS_FIXED_SIZE, buf->iscan_buf, WLC_IW_ISCAN_MAXLEN); - results->buflen = dtoh32(results->buflen); - results->version = dtoh32(results->version); - results->count = dtoh32(results->count); - WL_TRACE(("results->count = %d\n", results->count)); + if (res == 0) { + results->buflen = dtoh32(results->buflen); + results->version = dtoh32(results->version); + results->count = dtoh32(results->count); + WL_TRACE(("results->count = %d\n", results->count)); + + WL_TRACE(("results->buflen = %d\n", results->buflen)); + status = dtoh32(list_buf->status); + } + else { + WL_ERROR(("%s returns error %d\n", __FUNCTION__, res)); + + status = WL_SCAN_RESULTS_NO_MEM; + } - WL_TRACE(("results->buflen = %d\n", results->buflen)); - status = dtoh32(list_buf->status); mutex_unlock(&wl_cache_lock); return status; } @@ -2949,6 +3092,7 @@ static void wl_iw_send_scan_complete(isc if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY; WL_TRACE(("Send Event ISCAN complete\n")); + printk (KERN_INFO"[WLAN] Send Event ISCAN complete\n"); #endif } @@ -3022,14 +3166,21 @@ _iscan_sysioc_thread(void *data) iscan->timer_on = 1; break; case WL_SCAN_RESULTS_ABORTED: - WL_TRACE(("iscanresults aborted\n")); + WL_ERROR(("iscanresults aborted\n")); iscan->iscan_state = ISCAN_STATE_IDLE; +#if 0 if (g_scan_specified_ssid == 0) wl_iw_send_scan_complete(iscan); else { iscan_pass_abort = TRUE; wl_iw_force_specific_scan(iscan); } +#else + /* scan again + */ + iscan_pass_abort = TRUE; + wl_iw_force_specific_scan(iscan); +#endif break; case WL_SCAN_RESULTS_NO_MEM: WL_TRACE(("iscanresults can't alloc memory: skip\n")); @@ -3221,6 +3372,8 @@ wl_iw_add_bss_to_ss_cache(wl_scan_result leaf = kmalloc(WLC_IW_SS_CACHE_MAXLEN, GFP_KERNEL); if (!leaf) { mutex_unlock(&wl_cache_lock); + WL_ERROR(("Memory alloc failure %d\n", \ + bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN)); return -ENOMEM; } @@ -3322,6 +3475,11 @@ wl_iw_set_scan( int ret, retry = 0; WL_TRACE(("%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name)); + if(wifi_get_cscan_enable()){ + WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported (Using CSCAN)\n", __FUNCTION__)); + return -EINVAL; + } + #if defined(CONFIG_BCM4329_SOFTAP) if (ap_cfg_running) { WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); @@ -3384,6 +3542,154 @@ specific_retry: return 0; } +int +wl_iw_CSCAN_first(struct net_device *dev) +{ + int res = -1; + iscan_info_t *iscan = g_iscan; + int nssid = 0; + int nchan = 0,datalength; + cscan_tlv_t *cscan_tlv_temp; + wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX]; + char type; + char *str_ptr; + int tlv_size_left; + char *temp; + char tlv_in_firstscan[] = { 'C', 'S', 'C', 'A', 'N', ' ', \ + 0x53, 0x01, 0x00, 0x00, + 'S',0x00, + 'C',0x01,'C',0x02,'C',0x03,'C',0x04,'C',0x05,'C',0x06,'C',0x07,'C',0x08,'C',0x09, + 'C',0x10,'C',0x11 + }; + datalength = sizeof(tlv_in_firstscan); + + if (!(temp = kmalloc(datalength, GFP_KERNEL))) + return -ENOMEM; + + if (g_onoff == G_WLAN_SET_OFF) { + WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + return -1; + } + + memcpy(temp, tlv_in_firstscan, sizeof(tlv_in_firstscan)); + + str_ptr = temp; + str_ptr += strlen(CSCAN_COMMAND); + tlv_size_left = datalength - strlen(CSCAN_COMMAND); + + cscan_tlv_temp = (cscan_tlv_t *)str_ptr; + memset(ssids_local, 0, sizeof(ssids_local)); + + if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) && \ + (cscan_tlv_temp->version == CSCAN_TLV_VERSION) && \ + (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION)) + { + str_ptr += sizeof(cscan_tlv_t); + tlv_size_left -= sizeof(cscan_tlv_t); + + + if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \ + WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) { + WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); + goto exit_proc; + } + else { + + memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size); + + + wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL); + iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION); + iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START); + iscan->iscan_ex_params_p->scan_duration = htod16(0); + + + while (tlv_size_left > 0) + { + type = str_ptr[0]; + switch (type) { + case CSCAN_TLV_TYPE_CHANNEL_IE: + + if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.channel_list[0], \ + WL_NUMCHANNELS, &tlv_size_left)) == -1) { + WL_ERROR(("%s missing channel list\n", \ + __FUNCTION__)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_NPROBE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.nprobes, \ + sizeof(iscan->iscan_ex_params_p->params.nprobes), \ + type, sizeof(char), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_ACTIVE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.active_time, \ + sizeof(iscan->iscan_ex_params_p->params.active_time), \ + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_PASSIVE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.passive_time, \ + sizeof(iscan->iscan_ex_params_p->params.passive_time), \ + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_HOME_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.home_time, \ + sizeof(iscan->iscan_ex_params_p->params.home_time), \ + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_STYPE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.scan_type, \ + sizeof(iscan->iscan_ex_params_p->params.scan_type), \ + type, sizeof(char), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + + default : + WL_ERROR(("%s get unkwown type %X\n", \ + __FUNCTION__, type)); + goto exit_proc; + break; + } + } + } + } + else { + WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); + goto exit_proc; + } + + res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); + +exit_proc: + + return res; +} + #ifdef WL_IW_USE_ISCAN int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) @@ -3415,13 +3721,18 @@ wl_iw_iscan_set_scan_broadcast_prep(stru if (flag) rtnl_lock(); #endif - + if(!wifi_get_cscan_enable()){ dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &iscan->scan_flag, sizeof(iscan->scan_flag)); wl_iw_set_event_mask(dev); WL_TRACE(("+++: Set Broadcast ISCAN\n")); ret = wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START); + }else + { + printk(KERN_INFO"Try to do scan first (CSCAN) !"); + ret=wl_iw_CSCAN_first(dev); + } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) if (flag) @@ -3449,6 +3760,11 @@ wl_iw_iscan_set_scan( WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev->name)); + if(wifi_get_cscan_enable()){ + WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported (Due to Using CSCAN)\n", __FUNCTION__)); + return -EINVAL; + } + if (dev_wlc_ioctl_off) { WL_ERROR(("%s: wl driver going down!\n", __FUNCTION__)); return -EINVAL; @@ -3498,11 +3814,13 @@ wl_iw_iscan_set_scan( if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { int as = 0; struct iw_scan_req *req = (struct iw_scan_req *)extra; + if(!wifi_get_cscan_enable()){ if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { WL_TRACE(("%s First ISCAN in progress : ignoring SC = %s\n", \ __FUNCTION__, req->essid)); return -EBUSY; } + } ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); memcpy(ssid.SSID, req->essid, ssid.SSID_len); ssid.SSID_len = htod32(ssid.SSID_len); @@ -3824,8 +4142,13 @@ wl_iw_get_scan( if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) return error; ci.scan_channel = dtoh32(ci.scan_channel); - if (ci.scan_channel) + if (ci.scan_channel) { + if(!wifi_get_cscan_enable()){ + WL_ERROR(("%s: scan is running. channel: %d\n", __func__, ci.scan_channel)); + wl_iw_fixed_scan(dev); + } return -EAGAIN; + } if (g_ss_cache_ctrl.m_timer_expired) { wl_iw_free_ss_cache(); @@ -3879,12 +4202,12 @@ wl_iw_get_scan( wl_iw_fixed_scan(dev); return -EINVAL; } + if(!wifi_get_cscan_enable()){ + if (g_scan_specified_ssid) { - if (g_scan_specified_ssid) { - - wl_iw_add_bss_to_ss_cache(list); - kfree(list); - } + wl_iw_add_bss_to_ss_cache(list); + kfree(list); + } mutex_lock(&wl_cache_lock); #if defined(WL_IW_USE_ISCAN) @@ -3915,9 +4238,38 @@ wl_iw_get_scan( len_ret += merged_len; wl_iw_run_ss_cache_timer(0); wl_iw_run_ss_cache_timer(1); + }else + { + if (g_scan_specified_ssid) { + WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count)); + len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user); + kfree(list); #if defined(WL_IW_USE_ISCAN) + p_buf = iscan->list_hdr; + while (p_buf != iscan->list_cur) { + list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; + WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count)); + if (list_merge->count > 0) + len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, + extra+len_ret, buflen_from_user -len_ret); + p_buf = p_buf->next; + } +#else + list_merge = (wl_scan_results_t *) g_scan; + WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count)); + if (list_merge->count > 0) + len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, extra+len_ret, + buflen_from_user -len_ret); +#endif + } + else { + list = (wl_scan_results_t *) g_scan; + len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user); + } + } +#if defined(WL_IW_USE_ISCAN) g_scan_specified_ssid = 0; #endif @@ -4030,6 +4382,7 @@ wl_iw_iscan_get_scan( uint32 counter = 0; __u16 merged_len = 0; uint buflen_from_user = dwrq->length; + uint8 channel; WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length)); @@ -4049,18 +4402,18 @@ wl_iw_iscan_get_scan( WL_ERROR(("%s: wl driver going down!\n", __FUNCTION__)); return -EINVAL; } - + if(!wifi_get_cscan_enable()){ if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) { - WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n", \ - dev->name, __FUNCTION__)); + WL_ERROR(("%s %s: first ISCAN results are NOT ready yet \n", \ + dev->name, __func__)); return -EAGAIN; } - + } if ((!iscan) || (iscan->sysioc_pid < 0)) { WL_TRACE(("%ssysioc_pid\n", __FUNCTION__)); return wl_iw_get_scan(dev, info, dwrq, extra); } - + if(!wifi_get_cscan_enable()){ if (g_ss_cache_ctrl.m_timer_expired) { wl_iw_free_ss_cache(); g_ss_cache_ctrl.m_timer_expired ^= 1; @@ -4080,7 +4433,7 @@ wl_iw_iscan_get_scan( g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid; g_ss_cache_ctrl.m_cons_br_scan_cnt++; } - + } WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name)); apcnt = 0; p_buf = iscan->list_hdr; @@ -4131,6 +4484,7 @@ wl_iw_iscan_get_scan( iwe.cmd = SIOCGIWFREQ; + if(!wifi_get_cscan_enable()){ #ifdef CUSTOMER_HW2 if (dtoh32(bi->version) != 107 && bi->n_cap) { @@ -4142,6 +4496,13 @@ wl_iw_iscan_get_scan( iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); + }else + { + channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch; + iwe.u.freq.m = wf_channel2mhz(channel, + channel <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); + } iwe.u.freq.e = 6; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); @@ -4186,15 +4547,15 @@ wl_iw_iscan_get_scan( dwrq->length = event - extra; dwrq->flags = 0; - - wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len); - dwrq->length += merged_len; - wl_iw_run_ss_cache_timer(0); - wl_iw_run_ss_cache_timer(1); - - g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; - - WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter)); + if(!wifi_get_cscan_enable()){ + wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len); + dwrq->length += merged_len; + wl_iw_run_ss_cache_timer(0); + wl_iw_run_ss_cache_timer(1); + + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; + } + myprintf("[WLAN] %s return to WE %d bytes APs=%d\n", __func__, dwrq->length, counter); if (!dwrq->length) return -EAGAIN; @@ -5620,6 +5981,405 @@ int get_user_params(char *user_params, s return ret; } +#if defined(CSCAN) + + + +static int +wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan) +{ + int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); + int err = 0; + char *p; + int i; + iscan_info_t *iscan = g_iscan; + + WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan)); + + if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) { + WL_ERROR(("%s error exit\n", __FUNCTION__)); + err = -1; + } + + params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + + + if (nssid > 0) { + i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16); + i = ROUNDUP(i, sizeof(uint32)); + if (i + nssid * sizeof(wlc_ssid_t) > params_size) { + printk(KERN_INFO"additional ssids exceed params_size\n"); + err = -1; + goto exit; + } + + p = ((char*)&iscan->iscan_ex_params_p->params) + i; + memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t)); + p += nssid * sizeof(wlc_ssid_t); + } else { + p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16); + } + + + iscan->iscan_ex_params_p->params.channel_num = \ + htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | \ + (nchan & WL_SCAN_PARAMS_COUNT_MASK)); + + nssid = \ + (uint)((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) & \ + WL_SCAN_PARAMS_COUNT_MASK); + + + params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t)); + iscan->iscan_ex_param_size = params_size; + + iscan->list_cur = iscan->list_hdr; + iscan->iscan_state = ISCAN_STATE_SCANING; + wl_iw_set_event_mask(dev); + mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); + + iscan->timer_on = 1; + +#define SCAN_DUMP 0 +#ifdef SCAN_DUMP + { + int i; + WL_SCAN(("\n### List of SSIDs to scan ###\n")); + for (i = 0; i < nssid; i++) { + if (!ssids_local[i].SSID_len) + WL_SCAN(("%d: Broadcast scan\n", i)); + else + WL_SCAN(("%d: scan for %s size =%d\n", i, \ + ssids_local[i].SSID, ssids_local[i].SSID_len)); + } + WL_SCAN(("### List of channels to scan ###\n")); + for (i = 0; i < nchan; i++) + { + WL_SCAN(("%d ", iscan->iscan_ex_params_p->params.channel_list[i])); + } + WL_SCAN(("\nnprobes=%d\n", iscan->iscan_ex_params_p->params.nprobes)); + WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time)); + WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time)); + WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time)); + WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type)); + WL_SCAN(("\n###################\n")); + } +#endif + + if (params_size > WLC_IOCTL_MEDLEN) { + printk (KERN_INFO"[WLAN] error1\n"); + WL_ERROR(("Set ISCAN for %s due to params_size=%d \n", \ + __FUNCTION__, params_size)); + err = -1; + } + + if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p, \ + iscan->iscan_ex_param_size, \ + iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) { + printk (KERN_INFO"[WLAN] error2\n"); + WL_TRACE(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err)); + err = -1; + } + +exit: + + return err; +} + + +static int iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info, \ + union iwreq_data *wrqu, char *ext) +{ + int res = 0; + char *extra = NULL; + iscan_info_t *iscan = g_iscan; + wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX]; + int nssid = 0; + int nchan = 0; + + + WL_TRACE(("\%s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", + __FUNCTION__, info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + if (g_onoff == G_WLAN_SET_OFF) { + WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + return -1; + } + + if (wrqu->data.length != 0) { + + char *str_ptr; + + if (!iscan->iscan_ex_params_p) { + return -EFAULT; + } + + if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL))) + return -ENOMEM; + + if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) { + kfree(extra); + return -EFAULT; + } + + extra[wrqu->data.length] = 0; + WL_ERROR(("Got str param in iw_point:\n %s\n", extra)); + + str_ptr = extra; + + + if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) { + WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__)); + goto exit_proc; + } + str_ptr += strlen(GET_SSID); + nssid = wl_iw_parse_ssid_list(&str_ptr, ssids_local, nssid, \ + WL_SCAN_PARAMS_SSID_MAX); + + if (nssid == -1) { + WL_ERROR(("%s wrong ssid list", __FUNCTION__)); + return -1; + } + + memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size); + ASSERT(iscan->iscan_ex_param_size < WLC_IOCTL_MAXLEN); + + + wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL); + iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION); + iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START); + iscan->iscan_ex_params_p->scan_duration = htod16(0); + + + if ((nchan = wl_iw_parse_channel_list(&str_ptr, \ + &iscan->iscan_ex_params_p->params.channel_list[0], \ + WL_NUMCHANNELS)) == -1) { + WL_ERROR(("%s missing channel list\n", __FUNCTION__)); + return -1; + } + + + get_parmeter_from_string(&str_ptr, \ + GET_NPROBE, PTYPE_INTDEC, \ + &iscan->iscan_ex_params_p->params.nprobes, 2); + + get_parmeter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC, \ + &iscan->iscan_ex_params_p->params.active_time, 4); + + get_parmeter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC, \ + &iscan->iscan_ex_params_p->params.passive_time, 4); + + get_parmeter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC, \ + &iscan->iscan_ex_params_p->params.home_time, 4); + + get_parmeter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC, \ + &iscan->iscan_ex_params_p->params.scan_type, 1); + + + res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); + + } else { + + WL_ERROR(("IWPRIV argument len = 0 \n")); + return -1; + } + +exit_proc: + + kfree(extra); + + return res; +} + + +static int +wl_iw_set_cscan( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int res = -1; + iscan_info_t *iscan = g_iscan; + wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX]; + int nssid = 0; + int nchan = 0; + cscan_tlv_t *cscan_tlv_temp; + char type; + char *str_ptr; + int tlv_size_left; +#ifdef TLV_DEBUG + int i; + char tlv_in_example[] = { 'C', 'S', 'C', 'A', 'N', ' ', \ + 0x53, 0x01, 0x00, 0x00, + 'S', + 0x00, + 'S', + 0x04, + 'B', 'R', 'C', 'M', + 'C', + 0x06, + //0x00, + //'P', + 'A', + 0x94, + 0x11, + 'T', + //0x01 + 0x00 + }; +#endif + WL_SCAN(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", + __FUNCTION__, info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + if (g_onoff == G_WLAN_SET_OFF) { + WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + return -1; + } + + + if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) { + WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, \ + wrqu->data.length, strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))); + return -1; + } + +#ifdef TLV_DEBUG + memcpy(extra, tlv_in_example, sizeof(tlv_in_example)); + wrqu->data.length = sizeof(tlv_in_example); + for (i = 0; i < wrqu->data.length; i++) + printk(KERN_INFO"%02X ", extra[i]); + printk(KERN_INFO"--\n"); +#endif + + str_ptr = extra; + str_ptr += strlen(CSCAN_COMMAND); + tlv_size_left = wrqu->data.length - strlen(CSCAN_COMMAND); + + cscan_tlv_temp = (cscan_tlv_t *)str_ptr; + memset(ssids_local, 0, sizeof(ssids_local)); + + if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) && \ + (cscan_tlv_temp->version == CSCAN_TLV_VERSION) && \ + (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION)) + { + str_ptr += sizeof(cscan_tlv_t); + tlv_size_left -= sizeof(cscan_tlv_t); + + + if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \ + WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) { + WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); + goto exit_proc; + } + else { + + memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size); + + + wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL); + iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION); + iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START); + iscan->iscan_ex_params_p->scan_duration = htod16(0); + + + while (tlv_size_left > 0) + { + type = str_ptr[0]; + switch (type) { + case CSCAN_TLV_TYPE_CHANNEL_IE: + + if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.channel_list[0], \ + WL_NUMCHANNELS, &tlv_size_left)) == -1) { + WL_ERROR(("%s missing channel list\n", \ + __FUNCTION__)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_NPROBE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.nprobes, \ + sizeof(iscan->iscan_ex_params_p->params.nprobes), \ + type, sizeof(char), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_ACTIVE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.active_time, \ + sizeof(iscan->iscan_ex_params_p->params.active_time), \ + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_PASSIVE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.passive_time, \ + sizeof(iscan->iscan_ex_params_p->params.passive_time), \ + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_HOME_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.home_time, \ + sizeof(iscan->iscan_ex_params_p->params.home_time), \ + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_STYPE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan->iscan_ex_params_p->params.scan_type, \ + sizeof(iscan->iscan_ex_params_p->params.scan_type), \ + type, sizeof(char), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + + default : + WL_ERROR(("%s get unkwown type %X\n", \ + __FUNCTION__, type)); + goto exit_proc; + break; + } + } + } + } + else { + WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); + goto exit_proc; + } + + //if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { + // WL_ERROR(("%s First ISCAN in progress : ignoring\n", __FUNCTION__)); + // return -EBUSY; + //} + + + res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); + +exit_proc: + + return res; +} + +#endif + #ifdef CONFIG_BCM4329_SOFTAP @@ -5877,6 +6637,8 @@ get_channel_retry: ap_mode = 1; } #endif + wl_iw_set_event_mask_deauth(dev); + return res; } @@ -6194,7 +6956,7 @@ int get_parmeter_from_string( char *param_str_end; char *orig_str = *str_ptr; - if (!strncmp(*str_ptr, token, strlen(token))) { + if ((*str_ptr) && !strncmp(*str_ptr, token, strlen(token))) { strsep(str_ptr, "=,"); param_str_begin = *str_ptr; @@ -6306,6 +7068,12 @@ static int iwpriv_softap_stop(struct net res = wl_iw_softap_deassoc_stations(dev); ap_mode = 0; wl_iw_send_priv_event(priv_dev, "AP_DOWN"); +#ifdef SOFTAP_PROTECT + if (g_ap_protect&&g_ap_protect->timer_on) { + g_ap_protect->timer_on = 0; + del_timer_sync(&g_ap_protect->timer); + } +#endif #else res = wl_iw_softap_deassoc_stations(ap_net_dev); @@ -6760,6 +7528,10 @@ static int wl_iw_set_priv( ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, "STOP", strlen("STOP")) == 0) ret = wl_iw_control_wl_off(dev, info); +#if defined(CSCAN) + else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0) + ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra); +#endif #ifdef CUSTOMER_HW2 else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra); @@ -6804,6 +7576,12 @@ static int wl_iw_set_priv( set_ap_mac_list(dev, (extra + PROFILE_OFFSET)); } #endif +#ifdef WLAN_LOW_RSSI_IND + else if (strnicmp(extra, "LOW_RSSI_IND_SET", strlen("LOW_RSSI_IND_SET")) == 0) { + WL_TRACE(("set LOW_RSSI_IND_SET\n")); + wl_iw_low_rssi_set(dev, info, (union iwreq_data *)dwrq, extra); + } +#endif /* for packet filter rule */ else if (strnicmp(extra, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0 || @@ -6952,7 +7730,10 @@ static const iw_handler wl_iw_priv_handl NULL, (iw_handler)iwpriv_fw_reload, - +#if defined(CSCAN) + NULL, + (iw_handler)iwpriv_set_cscan, +#endif NULL, (iw_handler)iwpriv_settxpower @@ -7060,6 +7841,14 @@ static const struct iw_priv_args wl_iw_p "AP_TX_POWER" }, #endif +#if defined(CSCAN) + { + WL_COMBO_SCAN, + IW_PRIV_TYPE_CHAR | 1024, + 0, + "CSCAN" + }, +#endif }; const struct iw_handler_def wl_iw_handler_def = @@ -7373,6 +8162,7 @@ wl_iw_event(struct net_device *dev, wl_e case WLC_E_DEAUTH_IND: case WLC_E_DISASSOC_IND: #if defined(CONFIG_BCM4329_SOFTAP) + case WLC_E_DEAUTH: WL_SOFTAP(("STA disconnect received %d\n", event_type)); if (ap_mode) { //wl_iw_send_priv_event(priv_dev, "STA_LEAVE"); @@ -7386,11 +8176,15 @@ wl_iw_event(struct net_device *dev, wl_e wl_iw_send_priv_event(priv_dev, mac_buf); return; } + if (event_type != WLC_E_DEAUTH) { #endif cmd = SIOCGIWAP; bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); wrqu.addr.sa_family = ARPHRD_ETHER; bzero(&extra, ETHER_ADDR_LEN); +#if defined(CONFIG_BCM4329_SOFTAP) + } +#endif break; case WLC_E_LINK: case WLC_E_NDIS_LINK: @@ -7404,6 +8198,12 @@ wl_iw_event(struct net_device *dev, wl_e #endif WL_SOFTAP(("AP DOWN %d\n", event_type)); wl_iw_send_priv_event(priv_dev, "AP_DOWN"); +#ifdef SOFTAP_PROTECT + if (g_ap_protect&&g_ap_protect->timer_on) { + g_ap_protect->timer_on = 0; + del_timer_sync(&g_ap_protect->timer); + } +#endif } else { WL_TRACE(("STA_Link Down\n")); if (g_ss_cache_ctrl.last_rssi == 0) @@ -7434,6 +8234,13 @@ wl_iw_event(struct net_device *dev, wl_e #endif WL_SOFTAP(("AP UP %d\n", event_type)); wl_iw_send_priv_event(priv_dev, "AP_UP"); +#ifdef SOFTAP_PROTECT + if (g_ap_protect->timer_on == 0) { + g_ap_protect->timer_on = 1; + mod_timer(&g_ap_protect->timer, jiffies + AP_PROTECT_TIME*HZ/1000); + WL_SOFTAP(("%s Start AP Timer\n", __FUNCTION__)); + } +#endif } else #endif { @@ -7548,6 +8355,14 @@ wl_iw_event(struct net_device *dev, wl_e break; } #endif +#ifdef WLAN_LOW_RSSI_IND + case WLC_E_RSSI_LOW: + { + myprintf("Recevied RSSI LOW event!\n"); + wl_iw_send_priv_event(priv_dev, "LOW_RSSI"); + break; + } +#endif case WLC_E_SCAN_COMPLETE: #if defined(WL_IW_USE_ISCAN) if ((g_iscan) && (g_iscan->sysioc_pid >= 0) && @@ -7833,8 +8648,139 @@ wl_iw_bt_init(struct net_device *dev) return 0; } +#ifdef SOFTAP_PROTECT +static void +wl_iw_ap_timerfunc(ulong data) +{ + ap_info_t *ap_local = (ap_info_t *)data; + ap_local->timer_on = 0; + WL_TRACE(("%s\n", __FUNCTION__)); + + up(&ap_local->ap_sem); +} + +static int ap_fail_count = 0; +static int +_ap_protect_sysioc_thread(void *data) +{ + int isup; + int ret = 0; + DAEMONIZE("ap_sysioc"); + + while (down_interruptible(&g_ap_protect->ap_sem) == 0) { + + net_os_wake_lock(priv_dev); + + if (g_ap_protect->timer_on) { + g_ap_protect->timer_on = 0; + del_timer_sync(&g_ap_protect->timer); + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + rtnl_lock(); +#endif + if ((ret = dev_wlc_ioctl(priv_dev, WLC_GET_UP, &isup, sizeof(isup))) != 0) + ap_fail_count++; + else + ap_fail_count = 0; + + if (ap_fail_count == AP_MAX_FAIL_COUNT) { + wl_iw_restart(priv_dev); + wl_iw_ap_restart(); + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + rtnl_unlock(); +#endif + mod_timer(&g_ap_protect->timer, jiffies + AP_PROTECT_TIME*HZ/1000); + g_ap_protect->timer_on = 1; + + net_os_wake_unlock(priv_dev); + } + + if (g_ap_protect->timer_on) { + g_ap_protect->timer_on = 0; + del_timer_sync(&g_ap_protect->timer); + } + + complete_and_exit(&g_ap_protect->ap_exited, 0); +} + +static int +wl_iw_ap_init(void) +{ + ap_info_t *ap_protect = NULL; + + ap_protect = kmalloc(sizeof(ap_info_t), GFP_KERNEL); + if (!ap_protect) + return -ENOMEM; + + memset(ap_protect, 0, sizeof(ap_info_t)); + ap_protect->ap_pid = -1; + g_ap_protect = ap_protect; + + + init_timer(&ap_protect->timer); + ap_protect->timer.data = (ulong)ap_protect; + ap_protect->timer.function = wl_iw_ap_timerfunc; + ap_protect->timer_on = 0; + + sema_init(&ap_protect->ap_sem, 0); + init_completion(&ap_protect->ap_exited); + ap_protect->ap_pid = kernel_thread(_ap_protect_sysioc_thread, ap_protect, 0); + if (ap_protect->ap_pid < 0) { + WL_ERROR(("Failed in %s\n", __FUNCTION__)); + return -ENOMEM; + } + + return 0; +} + + +static void +wl_iw_ap_release(void) +{ + ap_info_t *ap_local = g_ap_protect; + + if (!ap_local) { + return; + } + + if (ap_local->ap_pid >= 0) { + KILL_PROC(ap_local->ap_pid, SIGTERM); + wait_for_completion(&ap_local->ap_exited); + } + kfree(ap_local); + g_ap_protect = NULL; +} + + +static void wl_iw_ap_restart(void) +{ + WL_SOFTAP(("Enter %s...\n", __FUNCTION__)); + + ap_mode = 0; + ap_cfg_running = FALSE; + ap_net_dev = NULL; + + set_ap_cfg(priv_dev, &my_ap); + + WL_SOFTAP(("SOFTAP - ENABLE BSS \n")); + +#ifndef AP_ONLY + if (ap_net_dev == NULL) { + printk("ERROR: SOFTAP net_dev* is NULL !!!\n"); + } else { + iwpriv_en_ap_bss(ap_net_dev, NULL, NULL, NULL); + } +#endif +} + +#endif + int wl_iw_attach(struct net_device *dev, void * dhdp) { + int params_size; wl_iw_t *iw; #if defined(WL_IW_USE_ISCAN) iscan_info_t *iscan = NULL; @@ -7847,10 +8793,24 @@ int wl_iw_attach(struct net_device *dev, if (!dev) return 0; + + if(wifi_get_cscan_enable()){ + params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) + + (WL_NUMCHANNELS * sizeof(uint16)) + WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + }else{ + params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)); + } + iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL); if (!iscan) return -ENOMEM; memset(iscan, 0, sizeof(iscan_info_t)); + if(wifi_get_cscan_enable()){ + iscan->iscan_ex_params_p = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); + if (!iscan->iscan_ex_params_p) + return -ENOMEM; + iscan->iscan_ex_param_size = params_size; + } iscan->sysioc_pid = -1; g_iscan = iscan; @@ -7882,10 +8842,14 @@ int wl_iw_attach(struct net_device *dev, memset(g_scan, 0, G_SCAN_RESULTS); g_scan_specified_ssid = 0; - wl_iw_init_ss_cache_ctrl(); + if(!wifi_get_cscan_enable()){ + wl_iw_init_ss_cache_ctrl(); + } wl_iw_bt_init(dev); - +#ifdef SOFTAP_PROTECT + wl_iw_ap_init(); +#endif // perf_lock_init(&wl_wificall_perf_lock, PERF_LOCK_HIGHEST, "wifi-call"); mutex_init(&wl_wificall_mutex); @@ -7911,6 +8875,9 @@ void wl_iw_detach(void) kfree(iscan->list_hdr); iscan->list_hdr = buf; } + if(wifi_get_cscan_enable()) + kfree(iscan->iscan_ex_params_p); + kfree(iscan); g_iscan = NULL; mutex_unlock(&wl_cache_lock); @@ -7920,8 +8887,13 @@ void wl_iw_detach(void) kfree(g_scan); g_scan = NULL; + if(!wifi_get_cscan_enable()){ wl_iw_release_ss_cache_ctrl(); + } wl_iw_bt_release(); +#ifdef SOFTAP_PROTECT + wl_iw_ap_release(); +#endif #ifdef CONFIG_BCM4329_SOFTAP if (ap_mode) { WL_TRACE(("\n%s AP is going down\n", __FUNCTION__)); --- a/drivers/net/wireless/bcm4329_204/wl_iw.h +++ b/drivers/net/wireless/bcm4329_204/wl_iw.h @@ -34,6 +34,17 @@ #include #include +#define WL_SCAN_PARAMS_SSID_MAX 10 +#define GET_SSID "SSID=" +#define GET_CHANNEL "CH=" +#define GET_NPROBE "NPROBE=" +#define GET_ACTIVE_ASSOC_DWELL "ACTIVE=" +#define GET_PASSIVE_ASSOC_DWELL "PASSIVE=" +#define GET_HOME_DWELL "HOME=" +#define GET_SCAN_TYPE "TYPE=" + +#define BAND_GET_CMD "BANDGET" +#define BAND_SET_CMD "BANDSET" #define WL_IW_RSSI_MINVAL -200 #define WL_IW_RSSI_NO_SIGNAL -91 @@ -61,12 +72,9 @@ #define AP_LPB_CMD (SIOCIWFIRSTPRIV+23) #define WL_AP_STOP (SIOCIWFIRSTPRIV+25) #define WL_FW_RELOAD (SIOCIWFIRSTPRIV+27) -#if 0 -#define WL_AP_SPARE2 (SIOCIWFIRSTPRIV+29) -#else -#define WL_SET_AP_TXPWR (SIOCIWFIRSTPRIV+29) -#endif -#define WL_AP_SPARE3 (SIOCIWFIRSTPRIV+31) +#define WL_COMBO_SCAN (SIOCIWFIRSTPRIV+29) +//#define WL_AP_SPARE2 (SIOCIWFIRSTPRIV+29) +#define WL_SET_AP_TXPWR (SIOCIWFIRSTPRIV+31) #define G_SCAN_RESULTS (8*1024) #define WE_ADD_EVENT_FIX 0x80 #define G_WLAN_SET_ON 0 @@ -196,4 +204,40 @@ extern int net_os_wake_lock_timeout_enab iwe_stream_add_point(stream, ends, iwe, extra) #endif +#if defined(CSCAN) + +typedef struct cscan_tlv { + char prefix; + char version; + char subver; + char reserved; +} cscan_tlv_t; + +#define CSCAN_COMMAND "CSCAN " +#define CSCAN_TLV_PREFIX 'S' +#define CSCAN_TLV_VERSION 1 +#define CSCAN_TLV_SUBVERSION 0 +#define CSCAN_TLV_TYPE_SSID_IE 'S' +#define CSCAN_TLV_TYPE_CHANNEL_IE 'C' +#define CSCAN_TLV_TYPE_NPROBE_IE 'N' +#define CSCAN_TLV_TYPE_ACTIVE_IE 'A' +#define CSCAN_TLV_TYPE_PASSIVE_IE 'P' +#define CSCAN_TLV_TYPE_HOME_IE 'H' +#define CSCAN_TLV_TYPE_STYPE_IE 'T' + +extern int wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, \ + int channel_num, int *bytes_left); + +extern int wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, \ + const char token, int input_size, int *bytes_left); + +extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, \ + int max, int *bytes_left); + +extern int wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max); + +extern int wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num); + +#endif + #endif --- a/include/linux/wifi_tiwlan.h +++ b/include/linux/wifi_tiwlan.h @@ -29,6 +29,7 @@ struct wifi_platform_data { int (*set_carddetect)(int val); void *(*mem_prealloc)(int section, unsigned long size); int dot11n_enable; + int cscan_enable; }; #endif