diff options
author | Daniel Hillenbrand <daniel.hillenbrand@codeworkx.de> | 2012-07-26 13:10:39 +0200 |
---|---|---|
committer | Daniel Hillenbrand <daniel.hillenbrand@codeworkx.de> | 2012-07-26 13:10:39 +0200 |
commit | 079c8bf723b03ac908b3c17b8223ffbc3bb670ce (patch) | |
tree | 5125ede6f1f86e5d79740ec16b47f72d7c697809 | |
parent | ba8ce2ed8f562b1397834abe23ada742d03f0d31 (diff) | |
download | kernel_samsung_espresso10-079c8bf723b03ac908b3c17b8223ffbc3bb670ce.tar.gz kernel_samsung_espresso10-079c8bf723b03ac908b3c17b8223ffbc3bb670ce.tar.bz2 kernel_samsung_espresso10-079c8bf723b03ac908b3c17b8223ffbc3bb670ce.zip |
bcmdhd: driver from t1, fixes tethering
28 files changed, 2343 insertions, 786 deletions
diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig index 4cc0264a0cc..d01c045a198 100644 --- a/drivers/net/wireless/bcmdhd/Kconfig +++ b/drivers/net/wireless/bcmdhd/Kconfig @@ -23,6 +23,11 @@ config BROADCOM_WIFI_RESERVED_MEM ---help--- This is a configuration for broadcom WLAN driver. +config WLAN_COUNTRY_CODE + tristate "---Broadcom WiFi Driver for 5GH channel setting" + depends on WLAN + default n + config WLAN_REGION_CODE int "---Region codes for Broadcom WiFi Driver" depends on (BCM4330 || BCM4334 || BCM43241) diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index 11a4b676260..8558f2440fe 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -14,23 +14,23 @@ ifeq ($(CONFIG_BCM4334),m) DHDCFLAGS += -DBCM4334_CHIP -DHW_OOB -DBCM4334_CHECK_CHIP_REV DHDCFLAGS += -DUSE_CID_CHECK -DCONFIG_CONTROL_PM DHDCFLAGS += -DPROP_TXSTATUS -DHDCFLAGS += -DVSDB -DHDCFLAGS += -DROAM_ENABLE -DROAM_API -DROAM_CHANNEL_CACHE +DHDCFLAGS += -DVSDB -DHT40_GO +DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST +DHDCFLAGS += -DDHD_USE_IDLECOUNT endif ifeq ($(CONFIG_BCM4334),y) DHDCFLAGS += -DBCM4334_CHIP -DHW_OOB -DBCM4334_CHECK_CHIP_REV DHDCFLAGS += -DUSE_CID_CHECK -DCONFIG_CONTROL_PM DHDCFLAGS += -DPROP_TXSTATUS -DHDCFLAGS += -DVSDB +DHDCFLAGS += -DVSDB -DHT40_GO DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -DHDCFLAGS += -DROAM_ENABLE -DROAM_API -DROAM_CHANNEL_CACHE +DHDCFLAGS += -DDHD_USE_IDLECOUNT endif ifeq ($(CONFIG_BCM4330),m) -DHDCFLAGS += -DBCM4330_CHIP +DHDCFLAGS += -DBCM4330_CHIP -DHW_OOB DHDCFLAGS += -DMCAST_LIST_ACCUMULATION DHDCFLAGS += -DCONFIG_CONTROL_PM DHDCFLAGS += -DDHD_USE_IDLECOUNT -DHDCFLAGS += -DROAM_ENABLE -DROAM_API -DROAM_CHANNEL_CACHE endif ifeq ($(CONFIG_BCM4330),y) @@ -38,18 +38,15 @@ DHDCFLAGS += -DBCM4330_CHIP DHDCFLAGS += -DMCAST_LIST_ACCUMULATION DHDCFLAGS += -DCONFIG_CONTROL_PM DHDCFLAGS += -DDHD_USE_IDLECOUNT -DHDCFLAGS += -DROAM_ENABLE -DROAM_API -DROAM_CHANNEL_CACHE endif ifeq ($(CONFIG_BCM43241),m) DHDCFLAGS += -DBCM43241_CHIP -DHW_OOB DHDCFLAGS += -DMCAST_LIST_ACCUMULATION -DHDCFLAGS += -DROAM_ENABLE -DROAM_API -DROAM_CHANNEL_CACHE DHDCFLAGS += -fno-pic endif ifeq ($(CONFIG_BCM43241),y) DHDCFLAGS += -DBCM43241_CHIP -DHW_OOB DHDCFLAGS += -DMCAST_LIST_ACCUMULATION -DHDCFLAGS += -DROAM_ENABLE -DROAM_API -DROAM_CHANNEL_CACHE endif # For p2p connection issue @@ -59,11 +56,21 @@ DHDCFLAGS += -DWL_CFG80211_SYNC_GON_TIME # For Passing all multicast packets to host when not in suspend mode. DHDCFLAGS += -DPASS_ALL_MCAST_PKTS + +#For INITIAL 2G scan features +#select only one from USE_INIITAL_2G_SCAN and INITIAL_2G_SCAN_ORG + DHDCFLAGS += -DUSE_INITIAL_2G_SCAN +#DHDCFLAGS += -DUSE_INITIAL_2G_SCAN_ORG + +DHDCFLAGS +=-DINITIAL_2G_SCAN_BY_ESCAN # For Scan result patch DHDCFLAGS += -DESCAN_RESULT_PATCH + +DHDCFLAGS += -DROAM_ENABLE -DROAM_CHANNEL_CACHE -DROAM_API + # For Static Buffer ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y) DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF @@ -74,6 +81,15 @@ ifeq ($(CONFIG_BRCM_CCX),y) DHDCFLAGS += -DBCMCCX endif +# For SLP feature +ifeq ($(CONFIG_SLP),y) +DHDCFLAGS += -DSLP_PATH -DWRITE_MACADDR +endif + +# 5GHz channels setting +ifeq ($(CONFIG_WLAN_COUNTRY_CODE),y) +DHDCFLAGS += -DGLOBALCONFIG_WLAN_COUNTRY_CODE +endif # For ICS SEC Features ifneq ($(findstring GlobalConfig, $(wildcard $(srctree)/include/sec_feature/*)),) diff --git a/drivers/net/wireless/bcmdhd/src/bcmsdio/sys/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/src/bcmsdio/sys/bcmsdh_sdmmc.c index 5eae9936d7e..7fdc1665363 100644 --- a/drivers/net/wireless/bcmdhd/src/bcmsdio/sys/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd/src/bcmsdio/sys/bcmsdh_sdmmc.c @@ -63,8 +63,11 @@ extern int sdio_reset_comm(struct mmc_card *card); extern PBCMSDH_SDMMC_INSTANCE gInstance; uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ +#if defined(SDIO_F2_BLKSIZE) +uint sd_f2_blocksize = SDIO_F2_BLKSIZE; +#else uint sd_f2_blocksize = 512; /* Default blocksize */ - +#endif uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ uint sd_power = 1; /* Default to SD Slot powered ON */ @@ -154,16 +157,22 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) gInstance->sd = sd; /* Claim host controller */ - sdio_claim_host(gInstance->func[1]); + if (gInstance->func[1]) { + sdio_claim_host(gInstance->func[1]); - sd->client_block_size[1] = 64; - err_ret = sdio_set_block_size(gInstance->func[1], 64); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); - } + sd->client_block_size[1] = 64; + err_ret = sdio_set_block_size(gInstance->func[1], 64); + if (err_ret) { + sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); + } - /* Release host controller F1 */ - sdio_release_host(gInstance->func[1]); + /* Release host controller F1 */ + sdio_release_host(gInstance->func[1]); + }else { + sd_err(("%s:gInstance->func[1] is null\n", __FUNCTION__)); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; + } if (gInstance->func[2]) { /* Claim host controller F2 */ @@ -178,6 +187,10 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) /* Release host controller F2 */ sdio_release_host(gInstance->func[2]); + }else { + sd_err(("%s:gInstance->func[2] is null\n", __FUNCTION__)); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; } sdioh_sdmmc_card_enablefuncs(sd); @@ -803,41 +816,49 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by #if defined(MMC_SDIO_ABORT) /* to allow abort command through F1 */ else if (regaddr == SDIOD_CCCR_IOABORT) { - sdio_claim_host(gInstance->func[func]); - /* - * this sdio_f0_writeb() can be replaced with another api - * depending upon MMC driver change. - * As of this time, this is temporaray one - */ - sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); - sdio_release_host(gInstance->func[func]); + if (gInstance->func[func]){ + sdio_claim_host(gInstance->func[func]); + /* + * this sdio_f0_writeb() can be replaced with another api + * depending upon MMC driver change. + * As of this time, this is temporaray one + */ + sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); + sdio_release_host(gInstance->func[func]); + } } #endif /* MMC_SDIO_ABORT */ else if (regaddr < 0xF0) { sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); } else { /* Claim host controller, perform F0 write, and release */ - sdio_claim_host(gInstance->func[func]); - sdio_f0_writeb(gInstance->func[func], *byte, regaddr, &err_ret); - sdio_release_host(gInstance->func[func]); + if (gInstance->func[func]){ + sdio_claim_host(gInstance->func[func]); + sdio_f0_writeb(gInstance->func[func], *byte, regaddr, &err_ret); + sdio_release_host(gInstance->func[func]); + } } } else { /* Claim host controller, perform Fn write, and release */ - sdio_claim_host(gInstance->func[func]); - sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); - sdio_release_host(gInstance->func[func]); + if (gInstance->func[func]){ + sdio_claim_host(gInstance->func[func]); + sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); + sdio_release_host(gInstance->func[func]); + } } } else { /* CMD52 Read */ /* Claim host controller, perform Fn read, and release */ - sdio_claim_host(gInstance->func[func]); + if (gInstance->func[func]){ + sdio_claim_host(gInstance->func[func]); - if (func == 0) { - *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret); - } else { - *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret); - } + if (func == 0) { + *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret); + } else { + *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret); + } - sdio_release_host(gInstance->func[func]); + sdio_release_host(gInstance->func[func]); + } } if (err_ret) { @@ -1016,7 +1037,13 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, pkt_len -= xfred_len; xfred_len = 0; } - pkt_len = (pkt_len + 3) & 0xFFFFFFFC; + + /* Align Patch */ + if (write == 0 || pkt_len < 32) // read or small packet(ex-BDC header) skip 32 byte align + pkt_len = (pkt_len + 3) & 0xFFFFFFFC; + else if(pkt_len % DHD_SDALIGN) // write + pkt_len += DHD_SDALIGN - (pkt_len % DHD_SDALIGN); + #ifdef CONFIG_MMC_MSM7X00A if ((pkt_len % 64) == 32) { sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); @@ -1303,12 +1330,14 @@ sdioh_start(sdioh_info_t *si, int stage) int ret; sdioh_info_t *sd = gInstance->sd; + if (!sd) return (0); + /* Need to do this stages as we can't enable the interrupt till downloading of the firmware is complete, other wise polling sdio access will come in way */ if (gInstance->func[0]) { - if (stage == 0) { + if (stage == 0) { /* Since the power to the chip is killed, we will have re enumerate the device again. Set the block size and enable the fucntion 1 for in preparation for @@ -1328,17 +1357,18 @@ sdioh_start(sdioh_info_t *si, int stage) sd->use_client_ints = TRUE; sd->client_block_size[0] = 64; - /* Claim host controller */ - sdio_claim_host(gInstance->func[1]); + if(gInstance->func[1]) { + /* Claim host controller */ + sdio_claim_host(gInstance->func[1]); - sd->client_block_size[1] = 64; - if (sdio_set_block_size(gInstance->func[1], 64)) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); + sd->client_block_size[1] = 64; + if (sdio_set_block_size(gInstance->func[1], 64)) { + sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); + } + /* Release host controller F1 */ + sdio_release_host(gInstance->func[1]); } - /* Release host controller F1 */ - sdio_release_host(gInstance->func[1]); - if (gInstance->func[2]) { /* Claim host controller F2 */ sdio_claim_host(gInstance->func[2]); @@ -1359,8 +1389,10 @@ sdioh_start(sdioh_info_t *si, int stage) } else { #if !defined(OOB_INTR_ONLY) sdio_claim_host(gInstance->func[0]); - sdio_claim_irq(gInstance->func[2], IRQHandlerF2); - sdio_claim_irq(gInstance->func[1], IRQHandler); + if (gInstance->func[2]) + sdio_claim_irq(gInstance->func[2], IRQHandlerF2); + if (gInstance->func[1]) + sdio_claim_irq(gInstance->func[1], IRQHandler); sdio_release_host(gInstance->func[0]); #else /* defined(OOB_INTR_ONLY) */ #if defined(HW_OOB) @@ -1388,8 +1420,10 @@ sdioh_stop(sdioh_info_t *si) if (gInstance->func[0]) { #if !defined(OOB_INTR_ONLY) sdio_claim_host(gInstance->func[0]); - sdio_release_irq(gInstance->func[1]); - sdio_release_irq(gInstance->func[2]); + if (gInstance->func[1]) + sdio_release_irq(gInstance->func[1]); + if (gInstance->func[2]) + sdio_release_irq(gInstance->func[2]); sdio_release_host(gInstance->func[0]); #else /* defined(OOB_INTR_ONLY) */ #if defined(HW_OOB) diff --git a/drivers/net/wireless/bcmdhd/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c index 0b35efb4bff..0ee8d1beeaa 100644 --- a/drivers/net/wireless/bcmdhd/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c @@ -109,31 +109,36 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, { int ret = 0; static struct sdio_func sdio_func_0; - sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); - sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class)); - sd_trace(("sdio_vendor: 0x%04x\n", func->vendor)); - sd_trace(("sdio_device: 0x%04x\n", func->device)); - sd_trace(("Function#: 0x%04x\n", func->num)); - - if (func->num == 1) { - sdio_func_0.num = 0; - sdio_func_0.card = func->card; - gInstance->func[0] = &sdio_func_0; - if(func->device == 0x4) { /* 4318 */ - gInstance->func[2] = NULL; - sd_trace(("NIC found, calling bcmsdh_probe...\n")); - ret = bcmsdh_probe(&func->dev); + + if (func) { + sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); + sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class)); + sd_trace(("sdio_vendor: 0x%04x\n", func->vendor)); + sd_trace(("sdio_device: 0x%04x\n", func->device)); + sd_trace(("Function#: 0x%04x\n", func->num)); + + if (func->num == 1) { + sdio_func_0.num = 0; + sdio_func_0.card = func->card; + gInstance->func[0] = &sdio_func_0; + if(func->device == 0x4) { /* 4318 */ + gInstance->func[2] = NULL; + sd_trace(("NIC found, calling bcmsdh_probe...\n")); + ret = bcmsdh_probe(&func->dev); + } } - } - gInstance->func[func->num] = func; + gInstance->func[func->num] = func; - if (func->num == 2) { + if (func->num == 2) { #ifdef WL_CFG80211 - wl_cfg80211_set_parent_dev(&func->dev); + wl_cfg80211_set_parent_dev(&func->dev); #endif - sd_trace(("F2 found, calling bcmsdh_probe...\n")); - ret = bcmsdh_probe(&func->dev); + sd_trace(("F2 found, calling bcmsdh_probe...\n")); + ret = bcmsdh_probe(&func->dev); + } + }else { + ret = -ENODEV; } return ret; @@ -141,20 +146,22 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, static void bcmsdh_sdmmc_remove(struct sdio_func *func) { - sd_err(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); - sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); - sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); - sd_info(("sdio_device: 0x%04x\n", func->device)); - sd_info(("Function#: 0x%04x\n", func->num)); - - if (func->num == 2) { - sd_err(("F2 found, calling bcmsdh_remove...\n")); - bcmsdh_remove(&func->dev); - } else if (func->num == 1) { - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); - gInstance->func[1] = NULL; + if (func) { + sd_err(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); + sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); + sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); + sd_info(("sdio_device: 0x%04x\n", func->device)); + sd_info(("Function#: 0x%04x\n", func->num)); + + if (func->num == 2) { + sd_err(("F2 found, calling bcmsdh_remove...\n")); + bcmsdh_remove(&func->dev); + } else if (func->num == 1) { + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + gInstance->func[1] = NULL; + } } } @@ -183,13 +190,15 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev) if (func->num != 2) return 0; - sd_trace(("%s Enter\n", __FUNCTION__)); + sd_err(("%s Enter\n", __FUNCTION__)); if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) return -EBUSY; +#if !defined(CUSTOMER_HW_SAMSUNG) #if defined(OOB_INTR_ONLY) bcmsdh_oob_intr_set(0); #endif /* defined(OOB_INTR_ONLY) */ +#endif /* !CUSTOMER_HW_SAMSUNG */ dhd_mmc_suspend = TRUE; smp_mb(); @@ -201,12 +210,15 @@ static int bcmsdh_sdmmc_resume(struct device *pdev) #if defined(OOB_INTR_ONLY) struct sdio_func *func = dev_to_sdio_func(pdev); #endif - sd_trace(("%s Enter\n", __FUNCTION__)); + if (func->num == 2) + sd_err(("%s Enter\n", __FUNCTION__)); dhd_mmc_suspend = FALSE; +#if !defined(CUSTOMER_HW_SAMSUNG) #if defined(OOB_INTR_ONLY) if ((func->num == 2) && dhd_os_check_if_up(bcmsdh_get_drvdata())) bcmsdh_oob_intr_set(1); #endif /* (OOB_INTR_ONLY) */ +#endif /* !CUSTOMER_HW_SAMSUNG */ smp_mb(); return 0; @@ -257,13 +269,11 @@ static struct sdio_driver bcmsdh_sdmmc_driver = { .remove = bcmsdh_sdmmc_remove, .name = "bcmsdh_sdmmc", .id_table = bcmsdh_sdmmc_ids, -#if 0 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) .drv = { .pm = &bcmsdh_sdmmc_pm_ops, }, #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ -#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ }; struct sdos_info { @@ -277,6 +287,9 @@ sdioh_sdmmc_osinit(sdioh_info_t *sd) { struct sdos_info *sdos; + if(!sd) + return BCME_BADARG; + sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); sd->sdos_info = (void*)sdos; if (sdos == NULL) @@ -304,6 +317,9 @@ sdioh_interrupt_set(sdioh_info_t *sd, bool enable) ulong flags; struct sdos_info *sdos; + if(!sd) + return BCME_BADARG; + sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); sdos = (struct sdos_info *)sd->sdos_info; diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd.h index 7d59cc6f7c5..af523b8d021 100644 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd.h +++ b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd.h @@ -253,6 +253,7 @@ typedef struct dhd_pub { void* wlfc_state; #endif bool dongle_isolation; + bool dongle_trap_occured; /* flag for forcible sending HANG event whenever trap occured */ int hang_was_sent; int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ int txcnt_timeout; /* counter txcnt timeout to send HANG */ @@ -260,6 +261,9 @@ typedef struct dhd_pub { uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ #endif struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; +#if defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) + struct wake_lock pno_wakelock; +#endif } dhd_pub_t; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) @@ -273,9 +277,19 @@ typedef struct dhd_pub { wait_event_interruptible_timeout(a, !dhd_mmc_suspend, HZ/100); \ } \ } while (0) +#ifdef CUSTOMER_HW_SAMSUNG + #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 500) +#else #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) +#endif /* CUSTOMER_HW_SAMSUNG */ #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) - #define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0) + #define DHD_PM_RESUME_RETURN_ERROR(a) do { \ + if (dhd_mmc_suspend) { \ + printf("mmc in suspend yet!!!: %s %d\n", \ + __FUNCTION__, __LINE__); \ + return a; \ + } \ + } while (0) #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); @@ -555,7 +569,7 @@ extern uint dhd_bus_status(dhd_pub_t *dhdp); extern int dhd_bus_start(dhd_pub_t *dhdp); extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); -extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf); +extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval); #if defined(KEEP_ALIVE) extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); @@ -657,13 +671,13 @@ extern char fw_path2[MOD_PARAM_PATHLEN]; /* Flag to indicate if we should download firmware on driver load */ extern uint dhd_download_fw_on_driverload; -#if defined(CUSTOMER_HW_SAMSUNG) && defined(WL_CFG80211) +#if defined(WL_CFG80211) && defined(CUSTOMER_HW_SAMSUNG) /* CSP#505233: Flags to indicate if we distingish power off policy when * user set the memu "Keep Wi-Fi on during sleep" to "Never" */ extern int sleep_never; int dhd_deepsleep(struct net_device *dev, int flag); -#endif /* CUSTOMER_HW_SAMSUNG && WL_CFG80211 */ +#endif /* WL_CFG80211 && CUSTOMER_HW_SAMSUNG */ #ifdef BCM4334_CHECK_CHIP_REV /* Check chip revision */ diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cdc.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cdc.c index 1df4f6c2712..2bac067b68f 100644 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cdc.c @@ -113,12 +113,20 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); +#ifdef CUSTOMER_HW_SAMSUNG + DHD_OS_WAKE_LOCK(dhd); +#endif /* CUSTOMER_HW_SAMSUNG */ + do { ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); if (ret < 0) break; } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); +#ifdef CUSTOMER_HW_SAMSUNG + DHD_OS_WAKE_UNLOCK(dhd); +#endif /* CUSTOMER_HW_SAMSUNG */ + return ret; } @@ -2203,6 +2211,9 @@ dhd_wlfc_cleanup(dhd_pub_t *dhd) for (i = 0; i < h->max_items; i++) { if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + h->items[i].pkt = NULL; + h->items[i].identifier = 0; } } return; diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_common.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_common.c index 59bf314b6ee..18a94bdc33d 100644 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_common.c @@ -267,13 +267,36 @@ int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex) { wl_ioctl_t ioc; +#ifdef CUSTOMER_HW_SAMSUNG + int ret; +#endif /* CUSTOMER_HW_SAMSUNG */ ioc.cmd = cmd; ioc.buf = arg; ioc.len = len; ioc.set = set; +#ifdef CUSTOMER_HW_SAMSUNG + ret = dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len); + if (ret < 0) { + if (ioc.cmd == WLC_GET_VAR) { + DHD_ERROR(("%s: WLC_GET_VAR: %s, error = %d\n", + __FUNCTION__, (char *)ioc.buf, ret)); + } else if (ioc.cmd == WLC_SET_VAR) { + char pkt_filter[] = "pkt_filter_add"; + if (strncmp(pkt_filter, ioc.buf, sizeof(pkt_filter)) != 0) { + DHD_ERROR(("%s: WLC_SET_VAR: %s, error = %d\n", + __FUNCTION__, (char *)ioc.buf, ret)); + } + } else { + DHD_ERROR(("%s: WLC_IOCTL: cmd:%d, error = %d\n", + __FUNCTION__, ioc.cmd, ret)); + } + } + return ret; +#else return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len); +#endif /* CUSTOMER_HW_SAMSUNG */ } @@ -285,7 +308,7 @@ dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int le dhd_os_proto_block(dhd_pub); ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); - if (!ret) + if (!ret || ret == -ETIMEDOUT) dhd_os_check_hang(dhd_pub, ifindex, ret); dhd_os_proto_unblock(dhd_pub); @@ -933,7 +956,7 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) p = (char *)&buf[MSGTRACE_HDRLEN]; while ((s = strstr(p, "\n")) != NULL) { *s = '\0'; - printf("%s\n", p); + printf("FW: %s\n", p); p = s+1; } printf("%s\n", p); @@ -1742,7 +1765,7 @@ fail: /* * returns = TRUE if associated, FALSE if not associated */ -bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf) +bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) { char bssid[6], zbuf[6]; int ret = -1; @@ -1757,6 +1780,9 @@ bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf) DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); } + if (retval) + *retval = ret; + if (ret < 0) return FALSE; @@ -1789,7 +1815,7 @@ dhd_get_dtim_skip(dhd_pub_t *dhd) bcn_li_dtim = dhd->dtim_skip; /* Check if associated */ - if (dhd_is_associated(dhd, NULL) == FALSE) { + if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); goto exit; } @@ -1889,7 +1915,7 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) memset(iovbuf, 0, sizeof(iovbuf)); - if ((pfn_enabled) && (dhd_is_associated(dhd, NULL) == TRUE)) { + if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) { DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__)); return ret; } diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_gpio.c index e33ab5dbaad..edb203e15fb 100644 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_gpio.c @@ -210,6 +210,7 @@ const struct cntry_locales_custom translate_custom_table[] = { {"BN", "BN", 1}, {"CA", "CA", 2}, {"CH", "CH", 1}, + {"CN", "CN", 0}, {"CY", "CY", 1}, {"CZ", "CZ", 1}, {"DE", "DE", 3}, @@ -246,6 +247,15 @@ const struct cntry_locales_custom translate_custom_table[] = { {"SK", "SK", 1}, {"TR", "TR", 7}, {"TW", "TW", 2}, +#ifdef CUSTOMER_HW_SAMSUNG + {"IR", "XZ", 11}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ + {"SD", "XZ", 11}, /* Universal if Country code is SUDAN */ + {"SY", "XZ", 11}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ + {"GL", "XZ", 11}, /* Universal if Country code is GREENLAND */ + {"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ + {"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ + {"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */ +#endif #ifdef BCM4334_CHIP {"RU", "RU", 5}, {"SG", "SG", 4}, diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_sec.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_sec.c index 9591f10347a..a651884babd 100644 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_sec.c +++ b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_sec.c @@ -18,7 +18,10 @@ extern int _dhd_set_mac_address(struct dhd_info *dhd, #ifdef SLP_PATH #define CIDINFO "/opt/etc/.cid.info" #define PSMINFO "/opt/etc/.psm.info" +#define MACINFO "/opt/etc/.mac.info" +#define REVINFO "/data/.rev" #else +#define REVINFO "/data/.rev" #define CIDINFO "/data/.cid.info" #define PSMINFO "/data/.psm.info" #endif /*SLP_PATH*/ @@ -32,52 +35,46 @@ int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac) char randommac[3] = {0}; char buf[18] = {0}; char *filepath = "/efs/wifi/.mac.info"; +#ifdef CONFIG_TARGET_LOCALE_VZW + char *nvfilepath = "/data/misc/wifi/.nvmac.info"; +#else + char *nvfilepath = "/data/.nvmac.info"; +#endif int ret = 0; - struct dentry *parent; - struct dentry *dentry; - struct inode *p_inode; - struct inode *c_inode; - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { -start_readmac: - /* File Doesn't Exist. Create and write mac addr.*/ - fp = filp_open(filepath, O_RDWR | O_CREAT, 0666); + fp = filp_open(filepath, O_RDONLY, 0); if (IS_ERR(fp)) { +start_readmac: + /* File Doesn't Exist. Create and write mac addr.*/ + fp = filp_open(filepath, O_RDWR | O_CREAT, 0666); + if (IS_ERR(fp)) { DHD_ERROR(("[WIFI] %s: File open error\n", filepath)); - return -1; - } - oldfs = get_fs(); - set_fs(get_ds()); - /* set uid , gid of parent directory */ - dentry = fp->f_path.dentry; - parent = dget_parent(dentry); - c_inode = dentry->d_inode; - p_inode = parent->d_inode; - c_inode->i_uid = p_inode->i_uid; - c_inode->i_gid = p_inode->i_gid; + return -1; + } + oldfs = get_fs(); + set_fs(get_ds()); /* Generating the Random Bytes for 3 last octects of the MAC address */ - get_random_bytes(randommac, 3); + get_random_bytes(randommac, 3); - sprintf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", + sprintf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", 0x00, 0x12, 0x34, randommac[0], randommac[1], randommac[2]); DHD_ERROR(("[WIFI]The Random Generated MAC ID: %s\n", macbuffer)); - if (fp->f_mode & FMODE_WRITE) { + if (fp->f_mode & FMODE_WRITE) { ret = fp->f_op->write(fp, (const char *)macbuffer, sizeof(macbuffer), &fp->f_pos); - if (ret < 0) + if (ret < 0) DHD_ERROR(("[WIFI]MAC address [%s] Failed to write into File: %s\n", macbuffer, filepath)); - else + else DHD_ERROR(("[WIFI]MAC address [%s] written into File: %s\n", macbuffer, filepath)); - } - set_fs(oldfs); + } + set_fs(oldfs); /* Reading the MAC Address from .mac.info file( the existed file or just created file)*/ ret = kernel_read(fp, 0, buf, 18); } else { /* Reading the MAC Address from .mac.info file( the existed file or just created file)*/ ret = kernel_read(fp, 0, buf, 18); - /* to prevent abnormal string display when mac address is displayed on the screen. */ +/* to prevent abnormal string display when mac address is displayed on the screen. */ buf[17] = '\0'; DHD_INFO(("Read MAC : [%s] [%d] \r\n" , buf, strncmp(buf , "00:00:00:00:00:00" , 17))); if (strncmp(buf , "00:00:00:00:00:00" , 17) < 1) { @@ -112,7 +109,7 @@ start_readmac: static int g_imac_flag; enum { - MACADDR_NONE =0 , + MACADDR_NONE = 0 , MACADDR_MOD, MACADDR_MOD_RANDOM, MACADDR_MOD_NONE, @@ -122,31 +119,54 @@ enum { int dhd_write_rdwr_macaddr(struct ether_addr *mac) { - char *filepath = "/efs/wifi/.mac.info"; - struct file *fp_mac = NULL; - char buf[18] = {0}; - mm_segment_t oldfs = {0}; + char *filepath_old = "/data/.mac.info"; + char *filepath = "/efs/wifi/.mac.info"; + struct file *fp_mac = NULL; + char buf[18] = {0}; + mm_segment_t oldfs = {0}; int ret = -1; if ((g_imac_flag != MACADDR_COB) && (g_imac_flag != MACADDR_MOD)) return 0; - sprintf(buf,"%02X:%02X:%02X:%02X:%02X:%02X\n", - mac->octet[0],mac->octet[1],mac->octet[2], - mac->octet[3],mac->octet[4],mac->octet[5]); + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X\n", + mac->octet[0], mac->octet[1], mac->octet[2], + mac->octet[3], mac->octet[4], mac->octet[5]); + + /* /data/.mac.info will be created */ + fp_mac = filp_open(filepath_old, O_RDWR | O_CREAT, 0666); + if (IS_ERR(fp_mac)) { + DHD_ERROR(("[WIFI] %s: File open error\n", filepath_old)); + return -1; + } else { + oldfs = get_fs(); + set_fs(get_ds()); - /* File is always created. */ + if (fp_mac->f_mode & FMODE_WRITE) { + ret = fp_mac->f_op->write(fp_mac, (const char *)buf, + sizeof(buf), &fp_mac->f_pos); + if (ret < 0) + DHD_ERROR(("[WIFI] Mac address [%s] Failed" + " to write into File: %s\n", buf, filepath_old)); + else + DHD_INFO(("[WIFI] Mac address [%s] written" + " into File: %s\n", buf, filepath_old)); + } + set_fs(oldfs); + filp_close(fp_mac, NULL); + } + /* /efs/wifi/.mac.info will be created */ fp_mac = filp_open(filepath, O_RDWR | O_CREAT, 0666); if (IS_ERR(fp_mac)) { DHD_ERROR(("[WIFI] %s: File open error\n", filepath)); return -1; - } else { + } else { oldfs = get_fs(); set_fs(get_ds()); if (fp_mac->f_mode & FMODE_WRITE) { ret = fp_mac->f_op->write(fp_mac, (const char *)buf, - sizeof(buf), &fp_mac->f_pos); + sizeof(buf), &fp_mac->f_pos); if (ret < 0) DHD_ERROR(("[WIFI] Mac address [%s] Failed" " to write into File: %s\n", buf, filepath)); @@ -163,32 +183,39 @@ int dhd_write_rdwr_macaddr(struct ether_addr *mac) } int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, - struct ether_addr *mac) + struct ether_addr *mac) { struct file *fp_mac = NULL; struct file *fp_nvm = NULL; - char macbuffer[18]= {0}; - char randommac[3] = {0}; - char buf[18] = {0}; - char *filepath = "/data/.mac.info"; + char macbuffer[18] = {0}; + char randommac[3] = {0}; + char buf[18] = {0}; + char *filepath_old = "/data/.mac.info"; + char *filepath = "/efs/wifi/.mac.info"; #ifdef CONFIG_TARGET_LOCALE_NA - char* nvfilepath = "/data/misc/wifi/.nvmac.info"; + char *nvfilepath = "/data/misc/wifi/.nvmac.info"; #else - char* nvfilepath = "/data/.nvmac.info"; + char *nvfilepath = "/data/.nvmac.info"; #endif - char cur_mac[128] = {0}; + char cur_mac[128] = {0}; char dummy_mac[ETHER_ADDR_LEN] = {0x00, 0x90, 0x4C, 0xC5, 0x12, 0x38}; - char cur_macbuffer[18] = {0}; + char cur_macbuffer[18] = {0}; int ret = -1; g_imac_flag = MACADDR_NONE; fp_nvm = filp_open(nvfilepath, O_RDONLY, 0); if (IS_ERR(fp_nvm)) { /* file does not exist */ + + /* Create the .nvmac.info */ + fp_nvm = filp_open(nvfilepath, O_RDWR | O_CREAT, 0666); + if (!IS_ERR(fp_nvm)) + filp_close(fp_nvm, NULL); + /* read MAC Address */ strcpy(cur_mac, "cur_etheraddr"); ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, cur_mac, - sizeof(cur_mac), 0, 0); + sizeof(cur_mac), 0, 0); if (ret < 0) { DHD_ERROR(("Current READ MAC error \r\n")); memset(cur_mac , 0 , ETHER_ADDR_LEN); @@ -200,10 +227,59 @@ int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, cur_mac[4], cur_mac[5])); } - sprintf(cur_macbuffer,"%02X:%02X:%02X:%02X:%02X:%02X\n", + sprintf(cur_macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", cur_mac[0], cur_mac[1], cur_mac[2], cur_mac[3], cur_mac[4], cur_mac[5]); + fp_mac = filp_open(filepath_old, O_RDONLY, 0); + if (IS_ERR(fp_mac)) { /* file does not exist */ + /* read mac is the dummy mac (00:90:4C:C5:12:38) */ + if (memcmp(cur_mac, dummy_mac, ETHER_ADDR_LEN) == 0) + g_imac_flag = MACADDR_MOD_RANDOM; + else if (strncmp(buf, "00:00:00:00:00:00", 17) == 0) + g_imac_flag = MACADDR_MOD_RANDOM; + else + g_imac_flag = MACADDR_MOD; + } else { + int is_zeromac; + + ret = kernel_read(fp_mac, 0, buf, 18); + filp_close(fp_mac, NULL); + buf[17] = '\0'; + + is_zeromac = strncmp(buf, "00:00:00:00:00:00", 17); + DHD_ERROR(("MAC (FILE): [%s] [%d] \r\n", + buf, is_zeromac)); + + if (is_zeromac == 0) { + DHD_ERROR(("Zero MAC detected." + " Trying Random MAC.\n")); + g_imac_flag = MACADDR_MOD_RANDOM; + } else { + sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + (unsigned int *)&(mac->octet[0]), + (unsigned int *)&(mac->octet[1]), + (unsigned int *)&(mac->octet[2]), + (unsigned int *)&(mac->octet[3]), + (unsigned int *)&(mac->octet[4]), + (unsigned int *)&(mac->octet[5])); + /* current MAC address is same as previous one */ + if(memcmp(cur_mac,mac->octet,ETHER_ADDR_LEN) == 0) { + g_imac_flag = MACADDR_NONE; + } else { /* change MAC address */ + if (0 == _dhd_set_mac_address(dhd, 0, mac)) { + DHD_INFO(("%s: MACID is" + " overwritten\n", __FUNCTION__)); + g_imac_flag = MACADDR_MOD; + } else { + DHD_ERROR(("%s: " + "_dhd_set_mac_address()" + " failed\n", __FUNCTION__)); + g_imac_flag = MACADDR_NONE; + } + } + } + } fp_mac = filp_open(filepath, O_RDONLY, 0); if (IS_ERR(fp_mac)) { /* file does not exist */ /* read mac is the dummy mac (00:90:4C:C5:12:38) */ @@ -218,7 +294,7 @@ int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, ret = kernel_read(fp_mac, 0, buf, 18); filp_close(fp_mac, NULL); - buf[17] ='\0'; + buf[17] = '\0'; is_zeromac = strncmp(buf, "00:00:00:00:00:00", 17); DHD_ERROR(("MAC (FILE): [%s] [%d] \r\n", @@ -229,14 +305,14 @@ int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, " Trying Random MAC.\n")); g_imac_flag = MACADDR_MOD_RANDOM; } else { - sscanf(buf,"%02X:%02X:%02X:%02X:%02X:%02X", + sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", (unsigned int *)&(mac->octet[0]), (unsigned int *)&(mac->octet[1]), (unsigned int *)&(mac->octet[2]), (unsigned int *)&(mac->octet[3]), (unsigned int *)&(mac->octet[4]), (unsigned int *)&(mac->octet[5])); - /* current MAC address is same as previous one */ + /* current MAC address is same as previous one */ if(memcmp(cur_mac,mac->octet,ETHER_ADDR_LEN) == 0) { g_imac_flag = MACADDR_NONE; } else { /* change MAC address */ @@ -263,14 +339,14 @@ int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, /* to prevent abnormal string display when mac address * is displayed on the screen. */ - buf[17] ='\0'; + buf[17] = '\0'; DHD_ERROR(("Read MAC : [%s] [%d] \r\n", buf, strncmp(buf, "00:00:00:00:00:00", 17))); if ((buf[0] == '\0') || (strncmp(buf, "00:00:00:00:00:00", 17) == 0)) { g_imac_flag = MACADDR_COB_RANDOM; } else { - sscanf(buf,"%02X:%02X:%02X:%02X:%02X:%02X", + sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", (unsigned int *)&(mac->octet[0]), (unsigned int *)&(mac->octet[1]), (unsigned int *)&(mac->octet[2]), @@ -293,12 +369,12 @@ int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, if ((g_imac_flag == MACADDR_COB_RANDOM) || (g_imac_flag == MACADDR_MOD_RANDOM)) { get_random_bytes(randommac, 3); - sprintf(macbuffer,"%02X:%02X:%02X:%02X:%02X:%02X\n", + sprintf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", 0x60, 0xd0, 0xa9, randommac[0], randommac[1], randommac[2]); DHD_ERROR(("[WIFI] The Random Generated MAC ID : %s\n", macbuffer)); - sscanf(macbuffer,"%02X:%02X:%02X:%02X:%02X:%02X", + sscanf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X", (unsigned int *)&(mac->octet[0]), (unsigned int *)&(mac->octet[1]), (unsigned int *)&(mac->octet[2]), @@ -456,33 +532,15 @@ int dhd_check_module_cid(dhd_pub_t *dhd) int ret = -1; #ifdef BCM4334_CHIP unsigned char cis_buf[250] = {0}; + const char *revfilepath = REVINFO; + int flag_b3 = 0; #else unsigned char cis_buf[128] = {0}; #endif - unsigned char cid_buf[10] = {0}; - const char* cidfilepath = "/data/.cid.info"; + const char *cidfilepath = CIDINFO; /* Try reading out from CIS */ cis_rw_t *cish = (cis_rw_t *)&cis_buf[8]; - struct file *fp_cid = NULL; - - fp_cid = filp_open(cidfilepath, O_RDONLY, 0); - if (!IS_ERR(fp_cid)) { - kernel_read(fp_cid, fp_cid->f_pos, cid_buf, sizeof(cid_buf)); - if (strstr(cid_buf, "samsung") || - strstr(cid_buf, "murata") -#ifdef BCM4330_CHIP - || strstr(cid_buf, "semcove") -#endif - ) { - /* file does exist, just return */ - filp_close(fp_cid, NULL); - return 0; - } - - DHD_ERROR(("[WIFI].cid.info file already exists but" - " it contains an unknown id [%s]\n", cid_buf)); - } cish->source = 0; cish->byteoff = 0; @@ -494,9 +552,11 @@ int dhd_check_module_cid(dhd_pub_t *dhd) if (ret < 0) { DHD_ERROR(("%s: CIS reading failed, err=%d\n", __FUNCTION__, ret)); + return ret; } else { #ifdef BCM4334_CHIP unsigned char semco_id[4] = {0x00, 0x00, 0x33, 0x33}; + unsigned char semco_id_sh[4] = {0x00, 0x00, 0xFB, 0x50}; //for SHARP FEM(new) DHD_ERROR(("%s: CIS reading success, err=%d\n", __FUNCTION__, ret)); #ifdef DUMP_CIS @@ -507,7 +567,13 @@ int dhd_check_module_cid(dhd_pub_t *dhd) 0x%02X 0x%02X\n", cis_buf[CIS_CID_OFFSET], cis_buf[CIS_CID_OFFSET+1], cis_buf[CIS_CID_OFFSET+2], cis_buf[CIS_CID_OFFSET+3])); - dhd_write_cid_file(cidfilepath, "samsung", 7); + dhd_write_cid_file(cidfilepath, "semco", 5); + } else if (memcmp(&cis_buf[CIS_CID_OFFSET], semco_id_sh, 4) == 0) { + DHD_ERROR(("CIS MATCH FOUND : Semco_sh, 0x%02X 0x%02X \ + 0x%02X 0x%02X\n", cis_buf[CIS_CID_OFFSET], + cis_buf[CIS_CID_OFFSET+1], cis_buf[CIS_CID_OFFSET+2], + cis_buf[CIS_CID_OFFSET+3])); + dhd_write_cid_file(cidfilepath, "semcosh", 7); } else { DHD_ERROR(("CID MATCH FOUND : Murata, 0x%02X 0x%02X \ 0x%02X 0x%02X\n", cis_buf[CIS_CID_OFFSET], @@ -516,6 +582,31 @@ int dhd_check_module_cid(dhd_pub_t *dhd) dhd_write_cid_file(cidfilepath, "murata", 6); } + /* Try reading out from OTP to distinguish B2 or B3 */ + memset(cis_buf, 0, sizeof(cis_buf)); + cish = (cis_rw_t *)&cis_buf[8]; + + cish->source = 0; + cish->byteoff = 0; + cish->nbytes = sizeof(cis_buf); + + strcpy(cis_buf, "otpdump"); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cis_buf, + sizeof(cis_buf), 0, 0); + if (ret < 0) { + DHD_ERROR(("%s: OTP reading failed, err=%d\n", + __FUNCTION__, ret)); + return ret; + } + + /* otp 33th character is identifier for 4334B3 */ + cis_buf[34] = '\0'; + flag_b3 = bcm_atoi(&cis_buf[33]); + if(flag_b3 & 0x1){ + DHD_ERROR(("REV MATCH FOUND : 4334B3, %c\n", cis_buf[33])); + dhd_write_cid_file(revfilepath, "4334B3", 6); + } + #else /* BCM4330_CHIP */ unsigned char murata_id[4] = {0x80, 0x06, 0x81, 0x00}; unsigned char semco_ve[4] = {0x80, 0x02, 0x81, 0x99}; @@ -635,20 +726,14 @@ int dhd_check_module_mac(dhd_pub_t *dhd) #ifdef WRITE_MACADDR int dhd_write_macaddr(struct ether_addr *mac) { -#ifdef U1_MACADDR - char *filepath = "/data/.mac.info"; -#else + char *filepath_old = "/data/.mac.info"; char *filepath = "/efs/wifi/.mac.info"; -#endif - struct file *fp_mac = NULL; - char buf[18] = {0}; - mm_segment_t oldfs = {0}; + + struct file *fp_mac = NULL; + char buf[18] = {0}; + mm_segment_t oldfs = {0}; int ret = -1; int retry_count = 0; - struct dentry *parent; - struct dentry *dentry; - struct inode *p_inode; - struct inode *c_inode; startwrite: @@ -656,7 +741,42 @@ startwrite: mac->octet[0], mac->octet[1], mac->octet[2], mac->octet[3], mac->octet[4], mac->octet[5]); - /*File is always created.*/ + /* File will be created /data/.mac.info. */ + fp_mac = filp_open(filepath_old, O_RDWR | O_CREAT, 0666); + + if (IS_ERR(fp_mac)) { + DHD_ERROR(("[WIFI] %s: File open error\n", filepath_old)); + return -1; + } else { + oldfs = get_fs(); + set_fs(get_ds()); + + if (fp_mac->f_mode & FMODE_WRITE) { + ret = fp_mac->f_op->write(fp_mac, (const char *)buf, + sizeof(buf), &fp_mac->f_pos); + if (ret < 0) + DHD_ERROR(("[WIFI] Mac address [%s] Failed to" + " write into File: %s\n", buf, filepath_old)); + else + DHD_INFO(("[WIFI] Mac address [%s] written" + " into File: %s\n", buf, filepath_old)); + } + set_fs(oldfs); + filp_close(fp_mac, NULL); + } + /* check .mac.info file is 0 byte */ + fp_mac = filp_open(filepath_old, O_RDONLY, 0); + ret = kernel_read(fp_mac, 0, buf, 18); + + if ((ret == 0) && (retry_count++ < 3)) { + filp_close(fp_mac, NULL); + goto startwrite; + } + + filp_close(fp_mac, NULL); + /* end of /data/.mac.info */ + + /* File will be created /efs/wifi/.mac.info. */ fp_mac = filp_open(filepath, O_RDWR | O_CREAT, 0666); if (IS_ERR(fp_mac)) { @@ -665,13 +785,6 @@ startwrite: } else { oldfs = get_fs(); set_fs(get_ds()); - /* set uid , gid of parent directory */ - dentry = fp_mac->f_path.dentry; - parent = dget_parent(dentry); - c_inode = dentry->d_inode; - p_inode = parent->d_inode; - c_inode->i_uid = p_inode->i_uid; - c_inode->i_gid = p_inode->i_gid; if (fp_mac->f_mode & FMODE_WRITE) { ret = fp_mac->f_op->write(fp_mac, (const char *)buf, @@ -726,14 +839,6 @@ void sec_control_pm(dhd_pub_t *dhd, uint *power_mode) __FUNCTION__, __LINE__)); return; } else { - struct dentry *dentry; - struct inode *c_inode; - /* set uid , gid to system id(1000) */ - dentry = fp->f_path.dentry; - c_inode = dentry->d_inode; - c_inode->i_uid = (uid_t)1000; - c_inode->i_gid = (uid_t)1000; - oldfs = get_fs(); set_fs(get_ds()); @@ -779,7 +884,7 @@ void sec_control_pm(dhd_pub_t *dhd, uint *power_mode) filp_close(fp, NULL); } #endif -#ifdef CUSTOMER_SET_COUNTRY +#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE int dhd_customer_set_country(dhd_pub_t *dhd) { struct file *fp = NULL; diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_linux.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_linux.c index ed840bc00fd..02b4d65e655 100644 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_linux.c @@ -194,7 +194,7 @@ extern int dhd_check_module_mac(dhd_pub_t *dhd); #endif #endif /* CUSTOMER_HW_SAMSUNG */ -#ifdef CUSTOMER_SET_COUNTRY +#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE int dhd_customer_set_country(dhd_pub_t *dhd); #endif @@ -213,6 +213,7 @@ typedef struct dhd_if { char name[IFNAMSIZ+1]; /* linux interface name */ uint8 bssidx; /* bsscfg index for the interface */ bool set_multicast; + bool event2cfg80211; /* To determine if pass event to cfg80211 */ } dhd_if_t; #ifdef WLMEDIA_HTSF @@ -336,6 +337,7 @@ char firmware_path[MOD_PARAM_PATHLEN]; char nvram_path[MOD_PARAM_PATHLEN]; int op_mode = 0; +int disable_proptx = 0; module_param(op_mode, int, 0644); extern int wl_control_wl_start(struct net_device *dev); extern int net_os_send_hang_message(struct net_device *dev); @@ -354,12 +356,15 @@ module_param(dhd_sysioc, uint, 0); /* Error bits */ module_param(dhd_msg_level, int, 0); +/* Disable Prop tx */ +module_param(disable_proptx, int, 0); + /* load firmware and/or nvram values from the filesystem */ module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); /* Watchdog interval */ -uint dhd_watchdog_ms = 100; +uint dhd_watchdog_ms = 10; module_param(dhd_watchdog_ms, uint, 0); #if defined(DHD_DEBUG) @@ -549,7 +554,7 @@ static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) { int ret = NOTIFY_DONE; - +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) switch (action) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: @@ -563,7 +568,7 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio break; } smp_mb(); - +#endif return ret; } @@ -922,7 +927,10 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) #endif /* MCAST_LIST_ACCUMULATION */ #ifdef PASS_ALL_MCAST_PKTS - allmulti = TRUE; +#ifdef PKT_FILTER_SUPPORT + if (!dhd->pub.early_suspended) + allmulti = TRUE; +#endif #endif /* PASS_ALL_MCAST_PKTS */ /* Send down the multicast list first. */ @@ -1156,6 +1164,7 @@ dhd_op_if(dhd_if_t *ifp) if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx, (void*)dhd_net_attach)) { ifp->state = DHD_IF_NONE; + ifp->event2cfg80211 = TRUE; return; } #endif @@ -1502,7 +1511,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) DHD_OS_WAKE_UNLOCK(&dhd->pub); return -ENODEV; } -#endif +#endif /* CUSTOMER_HW_SAMSUNG */ ifidx = dhd_net2idx(dhd, net); if (ifidx == DHD_BAD_IF) { @@ -2312,8 +2321,8 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) { if (!dhdp) return FALSE; - if ((error == -ETIMEDOUT) || ((dhdp->busstate == DHD_BUS_DOWN) && - (!dhdp->dongle_reset))) { + if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) + || ((dhdp->busstate == DHD_BUS_DOWN)&&(!dhdp->dongle_reset))) { DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate)); net_os_send_hang_message(net); @@ -2631,8 +2640,9 @@ dhd_stop(struct net_device *net) wl_android_wifi_off(net); #ifdef CUSTOMER_HW_SAMSUNG else { - /* CSP#505233: Flags to indicate if we distingish power off policy when - * user set the memu "Keep Wi-Fi on during sleep" to "Never" + /* CSP#505233: Flags to indicate if we distingish + * power off policy when user set the memu + * "Keep Wi-Fi on during sleep" to "Never" */ if (sleep_never) { dhd_deepsleep(net, 1); @@ -2642,6 +2652,7 @@ dhd_stop(struct net_device *net) #endif /* CUSTOMER_HW_SAMSUNG */ } #endif /* WL_CFG80211 */ + dhd->pub.dongle_trap_occured = 0; dhd->pub.hang_was_sent = 0; dhd->pub.rxcnt_timeout = 0; dhd->pub.txcnt_timeout = 0; @@ -2655,9 +2666,6 @@ static int dhd_open(struct net_device *net) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); -#ifdef PROP_TXSTATUS - uint up = 0; -#endif #ifdef TOE uint32 toe_ol; #endif @@ -2668,22 +2676,22 @@ dhd_open(struct net_device *net) #endif DHD_OS_WAKE_LOCK(&dhd->pub); /* Update FW path if it was changed */ - if ((firmware_path != NULL) && (firmware_path[0] != '\0')) { + if ((strlen(firmware_path) != 0) && (firmware_path[0] != '\0')) { if (firmware_path[strlen(firmware_path)-1] == '\n') firmware_path[strlen(firmware_path)-1] = '\0'; #ifdef WL_CFG80211 - if (dhd_download_fw_on_driverload && + if (dhd_download_fw_on_driverload && strcmp(fw_path, firmware_path)) { - DHD_ERROR(("firmware path changed:%s --> %s\n", - fw_path, firmware_path)); - fw_changed = TRUE; - } -#endif - strcpy(fw_path, firmware_path); + DHD_ERROR(("firmware path changed:%s --> %s\n", + fw_path, firmware_path)); + fw_changed = TRUE; + } +#endif /* WL_CFG80211 */ + strcpy(fw_path, firmware_path); #if defined(BCM4334_CHECK_CHIP_REV) - strcpy(fw_down_path, fw_path); - strcat(fw_down_path, chipver_tag); + strcpy(fw_down_path, fw_path); + strcat(fw_down_path, chipver_tag); #endif firmware_path[0] = '\0'; } @@ -2724,8 +2732,9 @@ dhd_open(struct net_device *net) } } else { #ifdef CUSTOMER_HW_SAMSUNG - /* CSP#505233: Flags to indicate if we distingish power off policy when - * user set the memu "Keep Wi-Fi on during sleep" to "Never" + /* CSP#505233: Flags to indicate if we distingish + * power off policy when user set the memu + * "Keep Wi-Fi on during sleep" to "Never" */ if (sleep_never) { dhd_deepsleep(net, 0); @@ -2733,12 +2742,12 @@ dhd_open(struct net_device *net) } else { #endif /* CUSTOMER_HW_SAMSUNG */ if (fw_changed) { - wl_android_wifi_off(net); - msleep(300); - ret = wl_android_wifi_on(net); - if (ret != 0) { - DHD_ERROR(("wl_android_wifi_on failed (%d)\n", ret)); - goto exit; + wl_android_wifi_off(net); + msleep(300); + ret = wl_android_wifi_on(net); + if (ret != 0) { + DHD_ERROR(("wl_android_wifi_on failed (%d)\n", ret)); + goto exit; } } #ifdef CUSTOMER_HW_SAMSUNG @@ -2781,7 +2790,6 @@ dhd_open(struct net_device *net) /* Allow transmit calls */ netif_start_queue(net); dhd->pub.up = 1; - #ifdef BCMDBGFS dhd_dbg_init(&dhd->pub); #endif @@ -2862,6 +2870,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, } memset(ifp, 0, sizeof(dhd_if_t)); + ifp->event2cfg80211 = FALSE; ifp->info = dhd; dhd->iflist[ifidx] = ifp; strncpy(ifp->name, name, IFNAMSIZ); @@ -2877,6 +2886,9 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, up(&dhd->thr_sysioc_ctl.sema); } else ifp->net = (struct net_device *)handle; + if (ifidx == 0) { + ifp->event2cfg80211 = TRUE; + } return 0; } @@ -2931,27 +2943,27 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); #ifdef BCM4334_CHECK_CHIP_REV - DHD_ERROR(("CHIP VER = [0x%x]\n", g_chipver)); - if (g_chipver == 1) { - DHD_ERROR(("----- CHIP bcm4334_B0 -----\n")); - strcpy(chipver_tag, "_b0"); - } else if (g_chipver == 2) { - DHD_ERROR(("----- CHIP bcm4334_B1 -----\n")); - strcpy(chipver_tag, "_b1"); - } else if (g_chipver == 3) { - DHD_ERROR(("----- CHIP bcm4334_B2 -----\n")); - strcpy(chipver_tag, "_b2"); + DHD_ERROR(("CHIP VER = [0x%x]\n", g_chipver)); + if (g_chipver == 1) { + DHD_ERROR(("----- CHIP bcm4334_B0 -----\n")); + strcpy(chipver_tag, "_b0"); + } else if (g_chipver == 2) { + DHD_ERROR(("----- CHIP bcm4334_B1 -----\n")); + strcpy(chipver_tag, "_b1"); + } else if (g_chipver == 3) { + DHD_ERROR(("----- CHIP bcm4334_B2 -----\n")); + strcpy(chipver_tag, "_b2"); } else { - DHD_ERROR(("----- Invalid chip version -----\n")); - goto fail; - } + DHD_ERROR(("----- Invalid chip version -----\n")); + goto fail; + } #endif /* BCM4334_CHECK_CHIP_REV */ /* updates firmware nvram path if it was provided as module parameters */ - if ((firmware_path != NULL) && (firmware_path[0] != '\0')) + if ((strlen(firmware_path) != 0) && (firmware_path[0] != '\0')) strcpy(fw_path, firmware_path); - if ((nvram_path != NULL) && (nvram_path[0] != '\0')) + if ((strlen(nvram_path) != 0) && (nvram_path[0] != '\0')) strcpy(nv_path, nvram_path); /* Allocate etherdev, including space for private structure */ @@ -3033,6 +3045,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #ifdef CONFIG_HAS_WAKELOCK wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); +#ifdef PNO_SUPPORT + wake_lock_init(&dhd->pub.pno_wakelock, WAKE_LOCK_SUSPEND, "pno_wake_lock"); +#endif #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 mutex_init(&dhd->dhd_net_if_mutex); @@ -3174,15 +3189,15 @@ dhd_bus_start(dhd_pub_t *dhdp) if ((dhd->pub.busstate == DHD_BUS_DOWN) && (fw_path[0] != '\0') && (nv_path[0] != '\0')) { - down_path = fw_path; + down_path = fw_path; #if defined(BCM4334_CHECK_CHIP_REV) - strcpy(fw_down_path, fw_path); - strcat(fw_down_path, chipver_tag); - down_path = fw_down_path; + strcpy(fw_down_path, fw_path); + strcat(fw_down_path, chipver_tag); + down_path = fw_down_path; #endif /* wake lock moved to dhdsdio_download_firmware */ if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, - down_path, nv_path))) { + down_path, nv_path))) { DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", __FUNCTION__, down_path, nv_path)); #ifdef DHDTHREAD @@ -3285,7 +3300,7 @@ dhd_bus_start(dhd_pub_t *dhdp) #ifdef RDWR_KORICS_MACADDR dhd_write_rdwr_korics_macaddr(dhd, &dhd->pub.mac); -#endif +#endif /* CUSTOMER_HW_SAMSUNG */ #ifdef ARP_OFFLOAD_SUPPORT if (dhd->pend_ipaddr) { @@ -3352,7 +3367,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #else uint32 glom = 0; #endif -#ifdef VSDB +#if defined(VSDB) || defined(ROAM_ENABLE) uint bcn_timeout = 8; #else uint bcn_timeout = 4; @@ -3410,13 +3425,16 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) int vlanmode = 0; #endif /* VLAN_MODE_OFF */ #ifdef BCM43241_CHIP - int mimo_bw_cap = 1; + int mimo_bw_cap = 2; #endif /* BCM43241_CHIP */ - +#ifdef AUTOCOUNTRY + int autocountry = 1; +#endif #ifdef PROP_TXSTATUS dhd->wlfc_enabled = FALSE; /* enable WLFC only if the firmware is VSDB */ #endif /* PROP_TXSTATUS */ + DHD_TRACE(("Enter %s\n", __FUNCTION__)); dhd->op_mode = 0; #ifdef GET_CUSTOM_MAC_ENABLE @@ -3544,10 +3562,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd_pkt_filter_enable = TRUE; if (dhd_concurrent_fw(dhd)) { dhd->op_mode |= WFD_MASK; -#ifdef PROP_TXSTATUS - dhd->wlfc_enabled = TRUE; - /* enable WLFC only if the firmware is VSDB */ -#endif /* PROP_TXSTATUS */ } } @@ -3585,6 +3599,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #endif +#ifdef AUTOCOUNTRY + bcm_mkiovar("autocountry", (char *)&autocountry, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif + #endif /* CUSTOMER_HW_SAMSUNG */ #ifdef CONFIG_CONTROL_PM @@ -3635,9 +3654,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(SOFTAP) if (ap_fw_loaded == FALSE) #endif + if ((dhd->op_mode & HOSTAPD_MASK) != HOSTAPD_MASK) { if ((res = dhd_keep_alive_onoff(dhd)) < 0) DHD_ERROR(("%s set keeplive failed %d\n", __FUNCTION__, res)); + } } #endif /* defined(KEEP_ALIVE) */ @@ -3677,6 +3698,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef PNO_SUPPORT setbit(eventmask, WLC_E_PFN_NET_FOUND); #endif /* PNO_SUPPORT */ +#ifdef USE_FW_TRACE + setbit(eventmask, WLC_E_TRACE); +#endif /* enable dongle roaming event */ setbit(eventmask, WLC_E_ROAM); #ifdef WL_CFG80211 @@ -3734,10 +3758,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #else /* Setup filter to allow only unicast */ #if defined(CUSTOMER_HW_SAMSUNG) + dhd->pktfilter_count = 5; dhd->pktfilter[0] = "100 0 0 0 " HEX_PREF_STR UNI_FILTER_STR ZERO_ADDR_STR ETHER_TYPE_STR IPV6_FILTER_STR " " HEX_PREF_STR ZERO_ADDR_STR ZERO_ADDR_STR ETHER_TYPE_STR ZERO_TYPE_STR; + dhd->pktfilter[4] = "104 0 0 0 0xFFFFFF 0x01005E"; + /* customer want to get IPV4 multicast packets */ #else #error Customer want to filter out all IPV6 packets dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; @@ -3761,7 +3788,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("vlan_mode", (char *)&vlanmode, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #endif /* VLAN_MODE_OFF */ -#ifdef CUSTOMER_SET_COUNTRY +#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE if (dhd_customer_set_country(dhd) < 0) DHD_ERROR(("%s: can't set country \n", __FUNCTION__)); #endif @@ -3928,13 +3955,16 @@ static int dhd_device_event(struct notifier_block *this, } #ifdef AOE_IP_ALIAS_SUPPORT - if (ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a) { - DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", - __FUNCTION__)); - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); + if ((dhd_pub->op_mode & HOSTAPD_MASK) != HOSTAPD_MASK) { + if (ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a) { + /* 0x3a = ':' */ + DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", + __FUNCTION__)); + aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); + } + else + aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); } - else - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); #endif break; @@ -3943,13 +3973,16 @@ static int dhd_device_event(struct notifier_block *this, __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); dhd->pend_ipaddr = 0; #ifdef AOE_IP_ALIAS_SUPPORT - if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) { - DHD_ARPOE(("%s: primary interface is down, AOE clr all\n", + if ((dhd_pub->op_mode & HOSTAPD_MASK) != HOSTAPD_MASK) { + if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) { + /* 0x3a = ':' */ + DHD_ARPOE(("%s: primary interface is down, AOE clr all\n", __FUNCTION__)); - dhd_aoe_hostip_clr(&dhd->pub); - dhd_aoe_arp_clr(&dhd->pub); - } else - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE); + dhd_aoe_hostip_clr(&dhd->pub); + dhd_aoe_arp_clr(&dhd->pub); + } else + aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE); + } #else dhd_aoe_hostip_clr(&dhd->pub); dhd_aoe_arp_clr(&dhd->pub); @@ -3965,7 +3998,6 @@ static int dhd_device_event(struct notifier_block *this, return NOTIFY_DONE; } #endif /* ARP_OFFLOAD_SUPPORT */ - int dhd_net_attach(dhd_pub_t *dhdp, int ifidx) { @@ -4005,6 +4037,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) #else net->netdev_ops = &dhd_ops_pri; #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ + memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); } else { /* * We have to use the primary MAC for virtual interfaces @@ -4249,6 +4282,9 @@ void dhd_detach(dhd_pub_t *dhdp) dhd->wakelock_timeout_enable = 0; wake_lock_destroy(&dhd->wl_wifi); wake_lock_destroy(&dhd->wl_rxwake); +#ifdef PNO_SUPPORT + wake_lock_destroy(&dhdp->pno_wakelock); +#endif #endif } } @@ -4336,8 +4372,10 @@ dhd_module_init(void) dhd_bus_reg_sdio_notify(&dhd_chipup_sem); dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); #if defined(CONFIG_WIFI_CONTROL_FUNC) - if (wl_android_wifictrl_func_add() < 0) + if (wl_android_wifictrl_func_add() < 0) { + dhd_bus_unreg_sdio_notify(); goto fail_1; + } #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { @@ -4372,7 +4410,7 @@ dhd_module_init(void) error = dhd_bus_register(); if (!error) - printf("\n%s\n", dhd_version); + DHD_TRACE(("%s: \n%s\n", __FUNCTION__, dhd_version)); else { DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); goto fail_1; @@ -4538,6 +4576,7 @@ dhd_os_wd_timer(void *bus, uint wdtick) if (!wdtick && dhd->wd_timer_valid == TRUE) { dhd->wd_timer_valid = FALSE; dhd_os_spin_unlock(pub, flags); + if (dhd) #ifdef DHDTHREAD del_timer_sync(&dhd->timer); #else @@ -4743,7 +4782,7 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, ASSERT(dhd->iflist[*ifidx] != NULL); ASSERT(dhd->iflist[*ifidx]->net != NULL); - if (dhd->iflist[*ifidx]->net) { + if (dhd->iflist[*ifidx]->event2cfg80211 && dhd->iflist[*ifidx]->net) { wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data); } #endif /* defined(WL_CFG80211) */ @@ -5053,9 +5092,12 @@ int net_os_send_hang_message(struct net_device *dev) #endif #if defined(WL_CFG80211) ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); - //dev_close(dev); - //dev_open(dev); +#if !defined(CUSTOMER_HW_SAMSUNG) +#error do not use these it cause kernel panic + dev_close(dev); + dev_open(dev); #endif +#endif /* WL_CFG80211 */ } } return ret; @@ -5210,6 +5252,21 @@ int net_os_wake_lock_timeout(struct net_device *dev) ret = dhd_os_wake_lock_timeout(&dhd->pub); return ret; } +#if defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) +int net_os_wake_lock_timeout_for_pno(struct net_device *dev, int sec) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + wake_lock_timeout(&dhd->pub.pno_wakelock, HZ * sec); + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; +} +#endif int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val) { diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_proto.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_proto.h index b597cc6fd23..8cc2542cf34 100644 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_proto.h +++ b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_proto.h @@ -34,7 +34,7 @@ #include <wlioctl.h> #ifndef IOCTL_RESP_TIMEOUT -#define IOCTL_RESP_TIMEOUT 20000 /* In milli second */ +#define IOCTL_RESP_TIMEOUT 5000 /* In milli second */ #endif /* IOCTL_RESP_TIMEOUT */ /* diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sdio.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sdio.c index 8d89377716d..25cbc700c49 100644 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sdio.c @@ -145,6 +145,10 @@ extern void bcmsdh_set_irq(int flag); extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) +DEFINE_MUTEX(_dhd_sdio_mutex_lock_); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ + #ifdef DHD_DEBUG /* Device console log buffer state */ #define CONSOLE_LINE_MAX 192 @@ -337,6 +341,7 @@ typedef struct dhd_bus { bool _slpauto; bool _oobwakeup; bool _srenab; + bool readframes; } dhd_bus_t; /* clkstate */ @@ -420,7 +425,7 @@ static bool dhd_readahead; /* To check if there's window offered */ #define DATAOK(bus) \ - (((uint8)(bus->tx_max - bus->tx_seq) > 2) && \ + (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) /* To check if there's window offered for ctrl frame */ @@ -599,6 +604,7 @@ dhdsdio_oobwakeup_init(dhd_bus_t *bus) } #endif /* USE_OOB_GPIO1 */ +#ifdef BCM4334_CHIP /* * Query if FW is in SR mode */ @@ -650,7 +656,6 @@ dhdsdio_sr_init(dhd_bus_t *bus) if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) dhdsdio_srwar_init(bus); - bus->srmemsize = si_socram_srmem_size(bus->sih); val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; @@ -671,6 +676,7 @@ dhdsdio_sr_init(dhd_bus_t *bus) return 0; } +#endif /* BCM4334_CHIP */ /* * FIX: Be sure KSO bit is enabled @@ -1171,7 +1177,7 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) ret = dhdsdio_htclk(bus, TRUE, pendok); if (ret == BCME_OK) { dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - bus->activity = TRUE; + bus->activity = TRUE; #ifdef DHD_USE_IDLECOUNT bus->dhd_idlecount = 0; #endif /* DHD_USE_IDLECOUNT */ @@ -1230,7 +1236,7 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) /* Going to sleep: set the alarm and turn off the lights... */ if (sleep) { /* Don't sleep if something is pending */ - if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) + if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq) || bus->readframes) return BCME_BUSY; @@ -1859,7 +1865,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); } else if (ret < 0) { /* On failure, abort the command and terminate the frame */ - DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", + DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n", __FUNCTION__, ret)); bus->tx_sderrs++; @@ -1930,13 +1936,21 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", __FUNCTION__, rxlen, msglen)); } else if (timeleft == 0) { - DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); + u32 status; + int retry = 0; + R_SDREG(status, &bus->regs->intstatus, retry); + DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n", __FUNCTION__, status)); #ifdef DHD_DEBUG +#if !defined(CUSTOMER_HW_SAMSUNG) +#error need debug message if dongle trap occured if (!SLPAUTO_ENAB(bus)) { +#endif dhd_os_sdlock(bus->dhd); dhdsdio_checkdied(bus, NULL, 0); dhd_os_sdunlock(bus->dhd); +#if !defined(CUSTOMER_HW_SAMSUNG) } +#endif #endif /* DHD_DEBUG */ } else if (pending == TRUE) { DHD_CTL(("%s: canceled\n", __FUNCTION__)); @@ -1964,6 +1978,9 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT) return -ETIMEDOUT; + if (bus->dhd->dongle_trap_occured) + return -EREMOTEIO; + return rxlen ? (int)rxlen : -EIO; } @@ -2303,26 +2320,36 @@ static int dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) { uint32 addr; - int rv; + int rv, i; uint32 shaddr = 0; - shaddr = bus->ramsize - bus->srmemsize - 4; - /* Read last word in memory to determine address of sdpcm_shared structure */ - if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) - return rv; + shaddr = bus->ramsize - 4; + + i = 0; + do { + /* Read last word in memory to determine address of sdpcm_shared structure */ + if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) + return rv; addr = ltoh32(addr); DHD_INFO(("sdpcm_shared address 0x%08X\n", addr)); - /* - * Check if addr is valid. - * NVRAM length at the end of memory should have been overwritten. - */ - if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { - DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", __FUNCTION__, addr)); - return BCME_ERROR; - } + /* + * Check if addr is valid. + * NVRAM length at the end of memory should have been overwritten. + */ + if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { + if ((bus->srmemsize > 0) && (i++ == 0)) { + shaddr -= bus->srmemsize; + } else { + DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", + __FUNCTION__, addr)); + return BCME_ERROR; + } + } else + break; + } while (i < 2); /* Read hndrte_shared structure */ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) @@ -2517,6 +2544,7 @@ dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) } if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { + bus->dhd->dongle_trap_occured = TRUE; if ((bcmerror = dhdsdio_membytes(bus, FALSE, sdpcm_shared.trap_addr, (uint8*)&tr, sizeof(trap_t))) < 0) @@ -3722,9 +3750,11 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); } +#ifdef BCM4334_CHIP if (dhdsdio_sr_cap(bus)) dhdsdio_sr_init(bus); else +#endif /* BCM4334_CHIP */ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); @@ -4365,8 +4395,10 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + bus->readframes = TRUE; if (!KSO_ENAB(bus)) { DHD_ERROR(("%s: KSO off\n", __FUNCTION__)); + bus->readframes = FALSE; return 0; } @@ -4934,6 +4966,7 @@ deliver: if (bus->rxskip) rxseq--; bus->rx_seq = rxseq; + bus->readframes = FALSE; return rxcount; } @@ -4990,6 +5023,8 @@ dhdsdio_hostmail(dhd_bus_t *bus) #ifdef DHD_DEBUG /* Retrieve console state address now that firmware should have updated it */ + // Kent: tempoprary rollback - firmware should be modified for a correct dconpoll operation + // if(dhd_console_ms > 0) { sdpcm_shared_t shared; if (dhdsdio_readshared(bus, &shared) == 0) @@ -5221,6 +5256,22 @@ clkwait: bcmsdh_intr_enable(sdh); } +#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) + /* In case of SW-OOB(using edge trigger), + * Check interrupt status in the dongle again after enable irq on the host. + * and rechedule dpc if interrupt is pended in the dongle. + * There is a chance to miss OOB interrupt while irq is disabled on the host. + * No need to do this with HW-OOB(level trigger) + */ + R_SDREG(newstatus, ®s->intstatus, retries); + if (bcmsdh_regfail(bus->sdh)) + newstatus = 0; + if (newstatus & bus->hostintmask) { + bus->ipend = TRUE; + resched = TRUE; + } +#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ + if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { int ret, i; @@ -5745,10 +5796,9 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) if (bus->dhd_idlecount >= (DHD_IDLE_TIMEOUT_MS/dhd_watchdog_ms)) { DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); - if (SLPAUTO_ENAB(bus)) { - if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) - dhd_os_wd_timer(bus->dhd, 0); - } else + if (SLPAUTO_ENAB(bus)) + dhdsdio_bussleep(bus, TRUE); + else dhdsdio_clkctl(bus, CLK_NONE, FALSE); bus->dhd_idlecount = 0; @@ -5904,6 +5954,17 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + + if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { + DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); + } + else { + DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); + } + mutex_lock(&_dhd_sdio_mutex_lock_); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ + /* Init global variables at run-time, not as part of the declaration. * This is required to support init/de-init of the driver. Initialization * of globals as part of the declaration results in non-deterministic @@ -5940,7 +6001,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, default: DHD_ERROR(("%s: unknown vendor: 0x%04x\n", __FUNCTION__, venid)); - return NULL; + goto forcereturn; } /* Check the Device ID and make sure it's one that we support */ @@ -5974,14 +6035,14 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, default: DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", __FUNCTION__, venid, devid)); - return NULL; + goto forcereturn; } if (osh == NULL) { /* Ask the OS interface part for an OSL handle */ if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) { DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__)); - return NULL; + goto forcereturn; } } @@ -6062,10 +6123,22 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, goto fail; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_unlock(&_dhd_sdio_mutex_lock_); + DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + return bus; fail: dhdsdio_release(bus, osh); + +forcereturn: +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_unlock(&_dhd_sdio_mutex_lock_); + DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + return NULL; } @@ -6213,6 +6286,8 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n", bus->ramsize, bus->orig_ramsize)); + + bus->srmemsize = si_socram_srmem_size(bus->sih); } /* ...but normally deal with the SDPCMDEV core */ @@ -6406,13 +6481,16 @@ dhdsdio_release(dhd_bus_t *bus, osl_t *osh) if (bus) { ASSERT(osh); + if (bus->dhd) { + dongle_isolation = bus->dhd->dongle_isolation; + dhd_detach(bus->dhd); + } + /* De-register interrupt handler */ bcmsdh_intr_disable(bus->sdh); bcmsdh_intr_dereg(bus->sdh); if (bus->dhd) { - dongle_isolation = bus->dhd->dongle_isolation; - dhd_detach(bus->dhd); dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); dhd_free(bus->dhd); bus->dhd = NULL; @@ -6499,6 +6577,17 @@ dhdsdio_disconnect(void *ptr) { dhd_bus_t *bus = (dhd_bus_t *)ptr; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + + if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { + DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); + } + else { + DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); + } + mutex_lock(&_dhd_sdio_mutex_lock_); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); if (bus) { @@ -6507,6 +6596,12 @@ dhdsdio_disconnect(void *ptr) } DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + mutex_unlock(&_dhd_sdio_mutex_lock_); + DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ + } diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sec_feature.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sec_feature.h index 5ead9f32efd..41f6e2c8a53 100644 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sec_feature.h +++ b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sec_feature.h @@ -1,4 +1,33 @@ -#ifdef USE_SECFEATURE +/* + * Header file describing the internal (inter-module) DHD interfaces. + * + * Provides type definitions and function prototypes used to link the + * DHD OS, bus, and protocol modules. + * + * Copyright (C) 1999-2012, 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 + * you also meet, for each linked independent module, the terms and conditions of + * 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. + * + * $Id: dhd_sec_feature.h 309548 2012-01-20 01:13:08Z $ + */ + +#ifdef USE_SECFEATURE #include <sec_feature/GlobalConfig.h> #include <sec_feature/CustFeature.h> #endif @@ -12,9 +41,8 @@ #define HW_OOB #endif -#ifdef CONFIG_MACH_U1 +#ifdef CONFIG_MACH_U1 /* Q1 also uses this feature */ #define USE_CID_CHECK -#define U1_MACADDR #define WRITE_MACADDR #endif @@ -23,6 +51,13 @@ #define WRITE_MACADDR #endif +/* Temporary roaming undef of D2_ATT models for the ATT hotspot connection problem */ +#if defined (CONFIG_MACH_M2_ATT) +#undef ROAM_ENABLE +#undef ROAM_CHANNEL_CACHE +#undef ROAM_API +#endif + /* REGION CODE */ #if (WLAN_REGION_CODE >= 100) && (WLAN_REGION_CODE < 200) /*EUR*/ @@ -33,7 +68,7 @@ #endif #if (WLAN_REGION_CODE >= 200) && (WLAN_REGION_CODE < 300) /* KOR */ -#undef USE_INITIAL_2G_SCAN +#undef USE_INITIAL_2G_SCAN_ORG #ifndef ROAM_ENABLE #define ROAM_ENABLE #endif diff --git a/drivers/net/wireless/bcmdhd/src/include/epivers.h b/drivers/net/wireless/bcmdhd/src/include/epivers.h index c6354cfc551..058f1d458f8 100644 --- a/drivers/net/wireless/bcmdhd/src/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/src/include/epivers.h @@ -30,19 +30,19 @@ #define EPI_MINOR_VERSION 15 -#define EPI_RC_NUMBER 2 +#define EPI_RC_NUMBER 11 #define EPI_INCREMENTAL_NUMBER 0 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 15, 2, 0 +#define EPI_VERSION 1, 15, 11, 0 -#define EPI_VERSION_NUM 0x010f0200 +#define EPI_VERSION_NUM 0x010f0900 -#define EPI_VERSION_DEV 1.15.2 +#define EPI_VERSION_DEV 1.15.11 -#define EPI_VERSION_STR "1.15.2" +#define EPI_VERSION_STR "1.15.11" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd/src/include/linuxver.h b/drivers/net/wireless/bcmdhd/src/include/linuxver.h index 1a5d27b9f8d..40830d922f8 100644 --- a/drivers/net/wireless/bcmdhd/src/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd/src/include/linuxver.h @@ -500,6 +500,7 @@ typedef struct { (tsk_ctl)->parent = owner; \ (tsk_ctl)->terminated = FALSE; \ (tsk_ctl)->thr_pid = kernel_thread(thread_func, tsk_ctl, flags); \ + DBG_THR(("%s thr:%lx created\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ if ((tsk_ctl)->thr_pid > 0) \ wait_for_completion(&((tsk_ctl)->completed)); \ DBG_THR(("%s thr:%lx started\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ diff --git a/drivers/net/wireless/bcmdhd/src/include/proto/p2p.h b/drivers/net/wireless/bcmdhd/src/include/proto/p2p.h index d3e138b154f..0c974c7c0a4 100644 --- a/drivers/net/wireless/bcmdhd/src/include/proto/p2p.h +++ b/drivers/net/wireless/bcmdhd/src/include/proto/p2p.h @@ -85,7 +85,7 @@ typedef struct wifi_p2p_ie wifi_p2p_ie_t; #define P2P_SEID_INVITE_FLAGS 18 #define P2P_SEID_VNDR 221 /* Vendor-specific subelement */ -#define P2P_SE_VS_ID_SERVICES 0x1b /* BRCM proprietary subel: L2 Services */ +#define P2P_SE_VS_ID_SERVICES 0x1b /* BRCM subel: L2 Services */ /* WiFi P2P IE subelement: P2P Capability (capabilities info) */ diff --git a/drivers/net/wireless/bcmdhd/src/include/wlioctl.h b/drivers/net/wireless/bcmdhd/src/include/wlioctl.h index c6b9eb4604f..72a54ce7db8 100644 --- a/drivers/net/wireless/bcmdhd/src/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/src/include/wlioctl.h @@ -1674,7 +1674,12 @@ typedef struct { /* WLC_GET_AUTH, WLC_SET_AUTH values */ #define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ #define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ -#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ +#ifdef BCM4330_CHIP +#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ +#else +/* BCM4334(Phoenex branch) value changed to 3 */ +#define WL_AUTH_OPEN_SHARED 3 /* try open, then shared if open failed w/rc 13 */ +#endif /* Bit masks for radio disabled status - returned by WL_GET_RADIO */ #define WL_RADIO_SW_DISABLE (1<<0) diff --git a/drivers/net/wireless/bcmdhd/src/shared/siutils.c b/drivers/net/wireless/bcmdhd/src/shared/siutils.c index b6dbda9e451..0c8a9fe3df8 100644 --- a/drivers/net/wireless/bcmdhd/src/shared/siutils.c +++ b/drivers/net/wireless/bcmdhd/src/shared/siutils.c @@ -1934,6 +1934,11 @@ si_socram_srmem_size(si_t *sih) uint32 coreinfo; uint memsize = 0; + if ((CHIPID(sih->chip) == BCM4334_CHIP_ID) && (CHIPREV(sih->chiprev) < 2)) { + return (32 * 1024); + } + + sii = SI_INFO(sih); /* Block ints and save current core */ diff --git a/drivers/net/wireless/bcmdhd/src/wl/bcmwifi/include/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd/src/wl/bcmwifi/include/bcmwifi_channels.h index 4491348f291..a62c16d153c 100644 --- a/drivers/net/wireless/bcmdhd/src/wl/bcmwifi/include/bcmwifi_channels.h +++ b/drivers/net/wireless/bcmdhd/src/wl/bcmwifi/include/bcmwifi_channels.h @@ -65,7 +65,7 @@ typedef uint16 chanspec_t; #define WL_CHANSPEC_BAND_SHIFT 12 #define WL_CHANSPEC_BAND_5G 0x1000 #define WL_CHANSPEC_BAND_2G 0x2000 -#define INVCHANSPEC (-1) +#define INVCHANSPEC 255 #define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? ((channel) - CH_10MHZ_APART) : 0) @@ -162,7 +162,7 @@ typedef uint16 chanspec_t; #define WL_CHANSPEC_BAND_3G 0x4000 #define WL_CHANSPEC_BAND_4G 0x8000 #define WL_CHANSPEC_BAND_5G 0xc000 -#define INVCHANSPEC (-1) +#define INVCHANSPEC 255 #define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ ((channel) - CH_10MHZ_APART) : 0) diff --git a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_android.c b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_android.c index 0238a63b060..916509d5cb4 100644 --- a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_android.c +++ b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_android.c @@ -73,13 +73,23 @@ #define CMD_GETBAND "GETBAND" #define CMD_COUNTRY "COUNTRY" #define CMD_P2P_SET_NOA "P2P_SET_NOA" +#define CMD_P2P_GET_NOA "P2P_GET_NOA" #define CMD_P2P_SET_PS "P2P_SET_PS" #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" /* Hostapd private command */ +#define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL" #define CMD_SET_HAPD_MAX_NUM_STA "HAPD_MAX_NUM_STA" #define CMD_SET_HAPD_SSID "HAPD_SSID" #define CMD_SET_HAPD_HIDE_SSID "HAPD_HIDE_SSID" +#define CMD_HAPD_STA_DISASSOC "HAPD_STA_DISASSOC" + +/* CCX Private Commands */ +#ifdef BCMCCX +#define CMD_GETCCKM_RN "get cckm_rn" +#define CMD_SETCCKM_KRK "set cckm_krk" +#define CMD_GET_ASSOC_RES_IES "get assoc_res_ies" +#endif #ifdef PNO_SUPPORT #define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" @@ -118,7 +128,11 @@ typedef struct cmd_tlv { #ifdef OKC_SUPPORT #define CMD_OKC_SET_PMK "SET_PMK" #define CMD_OKC_ENABLE "OKC_ENABLE" -#endif +#endif /* OKC_SUPPORT */ + +#ifdef CUSTOMER_HW_SAMSUNG +#define CMD_AMPDU_MPDU "AMPDU_MPDU" +#endif /* CUSTOMER_HW_SAMSUNG */ typedef struct android_wifi_priv_cmd { char *buf; @@ -214,6 +228,9 @@ static int wl_android_set_suspendopt(struct net_device *dev, char *command, int int ret_now; int ret = 0; +#ifdef CUSTOMER_HW_SAMSUNG + if (!dhd_download_fw_on_driverload) { +#endif /* CUSTOMER_HW_SAMSUNG */ suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; if (suspend_flag != 0) @@ -227,6 +244,9 @@ static int wl_android_set_suspendopt(struct net_device *dev, char *command, int else DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); } +#ifdef CUSTOMER_HW_SAMSUNG + } +#endif /* CUSTOMER_HW_SAMSUNG */ return ret; } @@ -517,6 +537,90 @@ static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, i return bytes_written; } +#ifdef BCMCCX +static int wl_android_get_cckm_rn(struct net_device *dev, char *command) +{ + int error, rn; + + WL_TRACE(("%s:wl_android_get_cckm_rn\n", dev->name)); + + error = wldev_iovar_getint(dev, "cckm_rn", &rn); + if (unlikely(error)) { + WL_ERR(("wl_android_get_cckm_rn error (%d)\n", error)); + return -1; + } + //WL_ERR(("wl_android_get_cckm_rn = %d\n", rn)); + memcpy(command, &rn, sizeof(int)); + + return sizeof(int); +} + +static int wl_android_set_cckm_krk(struct net_device *dev, char *command) +{ + int error; + unsigned char key[16]; + + static char iovar_buf[WLC_IOCTL_MEDLEN]; + + WL_TRACE(("%s: wl_iw_set_cckm_krk\n", dev->name)); + + memset(iovar_buf, 0, sizeof(iovar_buf)); + memcpy(key, command+strlen("set cckm_krk")+1, 16); + + error = wldev_iovar_setbuf(dev, "cckm_krk",key, sizeof(key), iovar_buf, WLC_IOCTL_MEDLEN,NULL); + if (unlikely(error)) + { + WL_ERR((" cckm_krk set error (%d)\n", error)); + return -1; + } + return 0; +} + +static int wl_android_get_assoc_res_ies(struct net_device *dev, char *command) +{ + int error; + u8 buf[WL_ASSOC_INFO_MAX]; + wl_assoc_info_t assoc_info; + u32 resp_ies_len = 0; + int bytes_written = 0; + + WL_TRACE(("%s: wl_iw_get_assoc_res_ies\n", dev->name)); + + error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, buf,WL_ASSOC_INFO_MAX, NULL); + if (unlikely(error)) { + WL_ERR(("could not get assoc info (%d)\n", error)); + return -1; + } + + memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t)); + assoc_info.req_len = htod32(assoc_info.req_len); + assoc_info.resp_len = htod32(assoc_info.resp_len); + assoc_info.flags = htod32(assoc_info.flags); + + if (assoc_info.resp_len) { + resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp); + } + + /* first 4 bytes are ie len */ + memcpy(command, &resp_ies_len, sizeof(u32)); + bytes_written= sizeof(u32); + + /* get the association resp IE's if there are any */ + if (resp_ies_len) { + error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0, buf,WL_ASSOC_INFO_MAX, NULL); + if (unlikely(error)) { + WL_ERR(("could not get assoc resp_ies (%d)\n", error)); + return -1; + } + + memcpy(command+sizeof(u32), buf, resp_ies_len); + bytes_written += resp_ies_len; + } + return bytes_written; +} + +#endif /* BCMCCX */ + /** * Global function definitions (declared in wl_android.h) */ @@ -537,7 +641,7 @@ int wl_android_wifi_on(struct net_device *dev) do { dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); if (dhd_download_fw_on_driverload) - msleep(100); + msleep(300); ret = sdioh_start(NULL, 0); if (ret == 0) @@ -617,7 +721,74 @@ static int my_atoi(const char *string_num) return int_val; } -static int wl_android_set_max_num_sta(struct net_device *dev, const char* string_num) +static int +wl_android_set_auto_channel(struct net_device *dev, const char* string_num, + char* command, int total_len) +{ + int channel; + int chosen = 0; + int retry = 0; + int ret = 0; + + /* Restrict channel to 1 - 7: 2GHz, 20MHz BW, No SB */ + u32 req_buf[8] = {7, 0x2B01, 0x2B02, 0x2B03, 0x2B04, 0x2B05, 0x2B06, + 0x2B07}; + + /* Auto channel select */ + wl_uint32_list_t request; + + channel = my_atoi(string_num); + DHD_INFO(("%s : HAPD_AUTO_CHANNEL = %d\n", __FUNCTION__, channel)); + + if (channel == 20) + ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, (void *)&req_buf, + sizeof(req_buf), true); + else { /* channel == 0 */ + request.count = htod32(0); + ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, (void *)&request, + sizeof(request), true); + } + + if (ret < 0) { + DHD_ERROR(("%s: can't start auto channel scan, err = %d\n", + __FUNCTION__, ret)); + channel = 0; + goto done; + } + + /* Wait for auto channel selection, max 2500 ms */ + bcm_mdelay(500); + + retry = 10; + while(retry--) { + ret = wldev_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen), + false); + if (ret < 0 || dtoh32(chosen) == 0) { + DHD_INFO(("%s: %d tried, ret = %d, chosen = %d\n", + __FUNCTION__, (10 - retry), ret, chosen)); + bcm_mdelay(200); + } + else { + channel = (u16)chosen & 0x00FF; + DHD_ERROR(("%s: selected channel = %d\n", __FUNCTION__, channel)); + break; + } + } + + if (retry == 0) { + DHD_ERROR(("%s: auto channel timed out, failed\n", __FUNCTION__)); + channel = 0; + } + +done: + snprintf(command, total_len, "%d", channel); + DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command)); + + return 1; +} + +static int +wl_android_set_max_num_sta(struct net_device *dev, const char* string_num) { int max_assoc; @@ -627,19 +798,25 @@ static int wl_android_set_max_num_sta(struct net_device *dev, const char* string return 1; } -static int wl_android_set_ssid (struct net_device *dev, const char* hapd_ssid) +static int +wl_android_set_ssid (struct net_device *dev, const char* hapd_ssid) { wlc_ssid_t ssid; + s32 ret; ssid.SSID_len = strlen(hapd_ssid); bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len); DHD_INFO(("%s: HAPD_SSID = %s\n", __FUNCTION__, ssid.SSID)); - wldev_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t), true); + ret = wldev_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t), true); + if (ret < 0) { + DHD_ERROR(("%s : WLC_SET_SSID Error:%d\n", __FUNCTION__, ret)); + } return 1; } -static int wl_android_set_hide_ssid(struct net_device *dev, const char* string_num) +static int +wl_android_set_hide_ssid(struct net_device *dev, const char* string_num) { int hide_ssid; int enable = 0; @@ -652,6 +829,30 @@ static int wl_android_set_hide_ssid(struct net_device *dev, const char* string_n return 1; } +static int +wl_android_sta_diassoc(struct net_device *dev, const char* straddr) +{ + scb_val_t scbval; + s32 ret; + + DHD_INFO(("%s: deauth STA %s\n", __FUNCTION__, straddr)); + + /* Unspecified reason */ + scbval.val = htod32(1); + bcm_ether_atoe(straddr, &scbval.ea); + + DHD_INFO(("%s: deauth STA: %02X:%02X:%02X:%02X:%02X:%02X\n", __FUNCTION__, + scbval.ea.octet[0], scbval.ea.octet[1], scbval.ea.octet[2], + scbval.ea.octet[3], scbval.ea.octet[4], scbval.ea.octet[5])); + + if ((ret = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, + sizeof(scb_val_t), true)) < 0) { + DHD_ERROR(("%s : WLC_SCB_DEAUTHENTICATE_FOR_REASON error:%d\n", __FUNCTION__ , ret)); + } + + return 1; +} + #ifdef OKC_SUPPORT static int @@ -698,6 +899,31 @@ wl_android_okc_enable(struct net_device *dev, char *command, int total_len) #endif /* OKC_ SUPPORT */ +#ifdef CUSTOMER_HW_SAMSUNG +/* CMD_AMPDU_MPDU */ +static int +wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num) +{ + int err = 0; + int ampdu_mpdu; + + ampdu_mpdu = bcm_atoi(string_num); + + if (ampdu_mpdu > 32) { + DHD_ERROR(("%s : ampdu_mpdu MAX value is 32.\n", __FUNCTION__)); + return -1; + } + + DHD_ERROR(("%s : ampdu_mpdu = %d\n", __FUNCTION__, ampdu_mpdu)); + err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu); + if (err < 0) { + DHD_ERROR(("%s : ampdu_mpdu set error. %d\n", __FUNCTION__, err)); + return -1; + } + + return 0; +} +#endif /* CUSTOMER_HW_SAMSUNG*/ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) { @@ -810,46 +1036,48 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); } -#ifndef CUSTOMER_SET_COUNTRY /*CUSTOMER_SET_COUNTRY feature is define for only GGSM model */ +#ifndef GLOBALCONFIG_WLAN_COUNTRY_CODE else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { char *country_code = command + strlen(CMD_COUNTRY) + 1; bytes_written = wldev_set_country(net, country_code); + wl_update_wiphybands(NULL); } #endif #ifdef ROAM_API else if (strnicmp(command, CMD_ROAMTRIGGER_SET, - strlen(CMD_ROAMTRIGGER_SET)) == 0) { + strlen(CMD_ROAMTRIGGER_SET)) == 0) { bytes_written = wl_android_set_roam_trigger(net, command, - priv_cmd.total_len); + priv_cmd.total_len); } else if (strnicmp(command, CMD_ROAMTRIGGER_GET, - strlen(CMD_ROAMTRIGGER_GET)) == 0) { + strlen(CMD_ROAMTRIGGER_GET)) == 0) { bytes_written = wl_android_get_roam_trigger(net, command, - priv_cmd.total_len); + priv_cmd.total_len); } else if (strnicmp(command, CMD_ROAMDELTA_SET, - strlen(CMD_ROAMDELTA_SET)) == 0) { + strlen(CMD_ROAMDELTA_SET)) == 0) { bytes_written = wl_android_set_roam_delta(net, command, - priv_cmd.total_len); + priv_cmd.total_len); } else if (strnicmp(command, CMD_ROAMDELTA_GET, - strlen(CMD_ROAMDELTA_GET)) == 0) { + strlen(CMD_ROAMDELTA_GET)) == 0) { bytes_written = wl_android_get_roam_delta(net, command, - priv_cmd.total_len); + priv_cmd.total_len); } else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET, - strlen(CMD_ROAMSCANPERIOD_SET)) == 0) { + strlen(CMD_ROAMSCANPERIOD_SET)) == 0) { bytes_written = wl_android_set_roam_scan_period(net, command, - priv_cmd.total_len); + priv_cmd.total_len); } else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET, - strlen(CMD_ROAMSCANPERIOD_GET)) == 0) { + strlen(CMD_ROAMSCANPERIOD_GET)) == 0) { bytes_written = wl_android_get_roam_scan_period(net, command, - priv_cmd.total_len); + priv_cmd.total_len); } else if (strnicmp(command, CMD_COUNTRYREV_SET, - strlen(CMD_COUNTRYREV_SET)) == 0) { + strlen(CMD_COUNTRYREV_SET)) == 0) { bytes_written = wl_android_set_country_rev(net, command, - priv_cmd.total_len); + priv_cmd.total_len); + wl_update_wiphybands(NULL); } else if (strnicmp(command, CMD_COUNTRYREV_GET, - strlen(CMD_COUNTRYREV_GET)) == 0) { + strlen(CMD_COUNTRYREV_GET)) == 0) { bytes_written = wl_android_get_country_rev(net, command, - priv_cmd.total_len); + priv_cmd.total_len); } #endif /* ROAM_API */ #ifdef PNO_SUPPORT @@ -872,6 +1100,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip); } + else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { + bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { int skip = strlen(CMD_P2P_SET_PS) + 1; bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, @@ -885,27 +1116,60 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) priv_cmd.total_len - skip, *(command + skip - 2) - '0'); } #endif /* WL_CFG80211 */ - else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA, strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) { + else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL, + strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) { + int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 3; + wl_android_set_auto_channel(net, (const char*)command+skip, command, + priv_cmd.total_len); + } + else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA, + strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) { int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3; wl_android_set_max_num_sta(net, (const char*)command+skip); } - else if (strnicmp(command, CMD_SET_HAPD_SSID, strlen(CMD_SET_HAPD_SSID)) == 0) { + else if (strnicmp(command, CMD_SET_HAPD_SSID, + strlen(CMD_SET_HAPD_SSID)) == 0) { int skip = strlen(CMD_SET_HAPD_SSID) + 3; wl_android_set_ssid(net, (const char*)command+skip); } - else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID, strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) { + else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID, + strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) { int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3; wl_android_set_hide_ssid(net, (const char*)command+skip); } + else if (strnicmp(command, CMD_HAPD_STA_DISASSOC, + strlen(CMD_HAPD_STA_DISASSOC)) == 0) { + int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1; + wl_android_sta_diassoc(net, (const char*)command+skip); + } #ifdef OKC_SUPPORT else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); #endif /* OKC_SUPPORT */ - +#ifdef BCMCCX + else if (strnicmp(command, CMD_GETCCKM_RN, strlen(CMD_GETCCKM_RN)) == 0) { + bytes_written = wl_android_get_cckm_rn(net, command); + } + else if (strnicmp(command, CMD_SETCCKM_KRK, strlen(CMD_SETCCKM_KRK)) == 0) { + bytes_written = wl_android_set_cckm_krk(net, command); + } + else if (strnicmp(command, CMD_GET_ASSOC_RES_IES, strlen(CMD_GET_ASSOC_RES_IES)) == 0) { + bytes_written = wl_android_get_assoc_res_ies(net, command); + } +#endif /* BCMCCX */ +#ifdef CUSTOMER_HW_SAMSUNG + /* CMD_AMPDU_MPDU */ + else if (strnicmp(command, CMD_AMPDU_MPDU,strlen(CMD_AMPDU_MPDU)) == 0) { + int skip = strlen(CMD_AMPDU_MPDU) + 1; + bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip); + } +#endif /* CUSTOMER_HW_SAMSUNG */ else { - DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); + if ((strnicmp(command, CMD_START, strlen(CMD_START)) != 0) && + (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) != 0)) + DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); snprintf(command, 3, "OK"); bytes_written = strlen("OK"); } @@ -1116,7 +1380,7 @@ static int wifi_remove(struct platform_device *pdev) DHD_ERROR(("## %s\n", __FUNCTION__)); wifi_control_data = wifi_ctrl; - wifi_set_power(0, 0); /* Power Off */ + wifi_set_power(0, 100); /* Power Off */ wifi_set_carddetect(0); /* CardDetect (1->0) */ up(&wifi_control_sem); @@ -1126,37 +1390,20 @@ int dhd_os_check_wakelock(void *dhdp); static int wifi_suspend(struct platform_device *pdev, pm_message_t state) { - DHD_ERROR(("##> %s\n", __FUNCTION__)); + DHD_TRACE(("##> %s\n", __FUNCTION__)); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1 - if (dhd_os_check_if_up(bcmsdh_get_drvdata())) - bcmsdh_oob_intr_set(0); + bcmsdh_oob_intr_set(0); #endif /* (OOB_INTR_ONLY) */ - if (dhd_os_check_if_up(bcmsdh_get_drvdata()) && - dhd_os_check_wakelock(bcmsdh_get_drvdata())) { - DHD_ERROR(("%s no driver data\n", __FUNCTION__)); - return -EBUSY; - } -#if defined(OOB_INTR_ONLY) - if (dhd_os_check_if_up(bcmsdh_get_drvdata())) - bcmsdh_oob_intr_set(0); -#endif /* defined(OOB_INTR_ONLY) */ - smp_mb(); return 0; } static int wifi_resume(struct platform_device *pdev) { - DHD_ERROR(("##> %s\n", __FUNCTION__)); - + DHD_TRACE(("##> %s\n", __FUNCTION__)); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1 if (dhd_os_check_if_up(bcmsdh_get_drvdata())) bcmsdh_oob_intr_set(1); #endif /* (OOB_INTR_ONLY) */ -#if defined(OOB_INTR_ONLY) - if (dhd_os_check_if_up(bcmsdh_get_drvdata())) - bcmsdh_oob_intr_set(1); -#endif /* (OOB_INTR_ONLY) */ - smp_mb(); return 0; } diff --git a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfg80211.c index db09ae139f6..1d6ba3a90ed 100644 --- a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfg80211.c @@ -117,6 +117,26 @@ u32 wl_dbg_level = WL_DBG_ERR; #define WL_SCAN_ACTIVE_TIME 40 /* ms : Embedded default Active setting from DHD Driver */ #define WL_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD Driver */ +#ifdef VSDB +/* ms : default wait time to keep STA's connecting or connection during continuous af tx */ +#define DEFAULT_SLEEP_TIME_VSDB 200 +#define WL_CHANNEL_SYNC_RETRY_VSDB 3 + +/* if sta is connected or connecting, sleep for a while before retry for VSDB */ +#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) \ + do { \ + if (wl_get_drv_status(wl, CONNECTED, wl_to_prmry_ndev(wl)) || \ + wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { \ + msleep(DEFAULT_SLEEP_TIME_VSDB); \ + } \ + } while (0) +#define WL_AF_TX_REDUCE_RETRY_VSDB(wl, max_retry) +#else /* VSDB */ +/* if not VSDB, do nothing */ +#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) +#define WL_AF_TX_REDUCE_RETRY_VSDB(wl, max_retry) +#endif /* VSDB */ + #ifdef D11AC_IOTYPES #define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL #endif /* D11AC_IOTYPES */ @@ -144,16 +164,12 @@ static const struct ieee80211_regdomain brcm_regdom = { /* IEEE 802.11b/g, channels 12..13. No HT40 * channel fits here. */ - REG_RULE(2467-10, 2472+10, 20, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS), + REG_RULE(2467-10, 2472+10, 20, 6, 20, 0), /* IEEE 802.11 channel 14 - Only JP enables * this and for 802.11b only */ - REG_RULE(2484-10, 2484+10, 20, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS | - NL80211_RRF_NO_OFDM), + REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), + /* IEEE 802.11a, channel 36..64 */ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), /* IEEE 802.11a, channel 100..165 */ @@ -194,6 +210,9 @@ static const struct ieee80211_regdomain brcm_regdom = { #define WPS_CONFIG_VIRT_DISPLAY 0x2008 #define WPS_CONFIG_PHY_DISPLAY 0x4008 +#define PM_BLOCK 1 +#define PM_ENABLE 0 + #ifdef BCMCCX #ifndef WLAN_AKM_SUITE_CCKM #define WLAN_AKM_SUITE_CCKM 0x000FAC04 @@ -291,6 +310,8 @@ static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); +static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, + enum wl_status state, bool set); /* * register/deregister parent device */ @@ -390,7 +411,7 @@ static void wl_link_up(struct wl_priv *wl); static void wl_link_down(struct wl_priv *wl); static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype); static void wl_init_conf(struct wl_conf *conf); -static s32 wl_update_wiphybands(struct wl_priv *wl); + /* * iscan handler @@ -441,6 +462,7 @@ void reset_roam_cache(void); void add_roam_cache(wl_bss_info_t *bi); int get_roam_channel_list(int target_chan, chanspec_t *channels, const wlc_ssid_t *ssid); void print_roam_cache(void); +void set_roam_band(int band); #endif #define CHECK_SYS_UP(wlpriv) \ do { \ @@ -459,6 +481,7 @@ do { \ extern int dhd_wait_pend8021x(struct net_device *dev); #ifdef PROP_TXSTATUS +extern int disable_proptx; extern int dhd_wlfc_init(dhd_pub_t *dhd); extern void dhd_wlfc_deinit(dhd_pub_t *dhd); #endif @@ -759,13 +782,13 @@ wl_chspec_driver_to_host(chanspec_t chanspec) } #else /* not D11AC_IOTYPES */ - +#ifndef ROAM_CHANNEL_CACHE static chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec) { return htodchanspec(chanspec); } - +#endif static chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec) { @@ -947,7 +970,7 @@ static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, - sizeof(WL_EXTRA_BUF_MAX), false))) { + WL_EXTRA_BUF_MAX, false))) { WL_ERR(("Failed to get associated bss info, use temp channel \n")); chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); } @@ -958,7 +981,7 @@ static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) } return chspec; -} + } } static struct net_device* wl_cfg80211_add_monitor_if(char *name) @@ -979,15 +1002,26 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, s32 timeout = -1; s32 wlif_type = -1; s32 mode = 0; - s32 up = 1; + s32 val = 0; chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *_ndev; struct ether_addr primary_mac; - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); int (*net_attach)(void *dhdp, int ifidx); bool rollback_lock = false; +#ifdef PROP_TXSTATUS + s32 up = 1; + dhd_pub_t *dhd; +#endif /* PROP_TXSTATUS */ + + if (!wl) + return ERR_PTR(-EINVAL); + +#ifdef PROP_TXSTATUS + dhd = (dhd_pub_t *)(wl->pub); +#endif /* PROP_TXSTATUS */ + /* Use primary I/F for to send commands down */ _ndev = wl_to_prmry_ndev(wl); @@ -1052,7 +1086,16 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, return ERR_PTR(-EAGAIN); } } - if (!p2p_is_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) { + + /* sanity check */ +#ifdef PROP_TXSTATUS + if (!dhd) + return ERR_PTR(-ENODEV); +#endif + if (!wl->p2p || !wl->p2p->vir_ifname) + return ERR_PTR(-ENODEV); + + if (!wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { p2p_on(wl) = true; wl_cfgp2p_set_firm_p2p(wl); wl_cfgp2p_init_discovery(wl); @@ -1063,11 +1106,15 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); + WL_SCAN2((" Scan Abort %p(id %d)\n", _ndev, wl->escan_info.cur_sync_id)); wl_cfg80211_scan_abort(wl, _ndev); #ifdef PROP_TXSTATUS - if (dhd->wlfc_enabled && !wl->wlfc_on) { + if (!wl->wlfc_on && !disable_proptx) { + dhd->wlfc_enabled = true; dhd_wlfc_init(dhd); - wldev_ioctl(_ndev, WLC_UP, &up, sizeof(s32), true); + err = wldev_ioctl(_ndev, WLC_UP, &up, sizeof(s32), true); + if (err < 0) + WL_ERR(("WLC_UP return err:%d\n", err)); wl->wlfc_on = true; } #endif @@ -1082,6 +1129,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, * bss: "wl p2p_ifadd" */ wl_set_p2p_status(wl, IF_ADD); + if (wlif_type == WL_P2P_IF_GO) + wldev_iovar_setint(_ndev, "mpc", 0); err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); if (unlikely(err)) { @@ -1117,9 +1166,14 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, rollback_lock = true; } if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) { - wl_alloc_netinfo(wl, _ndev, vwdev, mode); + wl_alloc_netinfo(wl, _ndev, vwdev, mode, PM_BLOCK); WL_DBG((" virtual interface(%s) is " "created net attach done\n", wl->p2p->vir_ifname)); + val = 1; + /* Disable firmware roaming for P2P interface */ + wldev_iovar_setint(_ndev, "roam_off", val); + if (mode == WL_MODE_AP) + wl_set_drv_status(wl, CONNECTED, _ndev); } else { /* put back the rtnl_lock again */ if (rollback_lock) @@ -1137,14 +1191,17 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); wl->p2p->vif_created = false; #ifdef PROP_TXSTATUS - if (dhd->wlfc_enabled && wl->wlfc_on) { - dhd_wlfc_deinit(dhd); - wl->wlfc_on = false; - } + if (dhd->wlfc_enabled && wl->wlfc_on) { + dhd->wlfc_enabled = false; + dhd_wlfc_deinit(dhd); + wl->wlfc_on = false; + } #endif } } fail: + if (wlif_type == WL_P2P_IF_GO) + wldev_iovar_setint(_ndev, "mpc", 1); return ERR_PTR(-ENODEV); } @@ -1156,7 +1213,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) s32 timeout = -1; s32 ret = 0; WL_DBG(("Enter\n")); - + WL_SCAN2(("Enter\n")); if (wl->p2p_net == dev) { /* Since there is no ifidx corresponding to p2p0, * all commands should be routed through primary I/F @@ -1171,7 +1228,28 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) wl_cfg80211_scan_abort(wl, dev); } wldev_iovar_setint(dev, "mpc", 1); + + /* for GC */ + if (wl_get_drv_status(wl, DISCONNECTING, dev) && + (wl_get_mode_by_netdev(wl, dev) != WL_MODE_AP)) { + WL_ERR(("Wait for Link Down event for GC !\n")); + wait_for_completion_timeout(&wl->iface_disable, msecs_to_jiffies(500)); + } wl_set_p2p_status(wl, IF_DELETING); + + /* for GO */ + if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { + /* disable interface before bsscfg free */ + ret = wl_cfgp2p_ifdisable(wl, &p2p_mac); + /* if fw doesn't support "ifdis", do not wait for link down of ap mode */ + if (ret == 0) { + WL_ERR(("Wait for Link Down event for GO !!!\n")); + wait_for_completion_timeout(&wl->iface_disable, msecs_to_jiffies(500)); + } else { + msleep(300); + } + } + /* delete interface after link down */ ret = wl_cfgp2p_ifdel(wl, &p2p_mac); /* Firmware could not delete the interface so we will not get WLC_E_IF * event for cleaning the dhd virtual nw interace @@ -1199,6 +1277,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) ret = dhd_del_monitor(dev); } } + WL_SCAN2(("Exit\n")); return ret; } @@ -1251,6 +1330,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, * channel. so retrieve the current channel of primary interface and * then start the virtual interface on that. */ + WL_SCAN2(("Scan Abort %p(id %d)\n", ndev, wl->escan_info.cur_sync_id)); wl_cfg80211_scan_abort(wl, ndev); chspec = wl_cfg80211_get_shared_freq(wiphy); @@ -1266,6 +1346,8 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, wl_set_mode_by_netdev(wl, ndev, mode); wl_clr_p2p_status(wl, IF_CHANGING); wl_clr_p2p_status(wl, IF_CHANGED); + if (mode == WL_MODE_AP) + wl_set_drv_status(wl, CONNECTED, ndev); } else if (ndev == wl_to_prmry_ndev(wl) && !wl_get_drv_status(wl, AP_CREATED, ndev)) { wl_set_drv_status(wl, AP_CREATING, ndev); @@ -1317,9 +1399,12 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) { struct wl_priv *wl = wlcfg_drv_priv; bool rollback_lock = false; - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); s32 index = 0; - if (!ndev || !ndev->name) { +#ifdef PROP_TXSTATUS + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); +#endif /* PROP_TXSTATUS */ + + if (!ndev || (strlen(ndev->name) == 0)) { WL_ERR(("net is NULL\n")); return 0; } @@ -1328,17 +1413,19 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) wl_get_p2p_status(wl, IF_DELETING)) { if (wl->scan_request && (wl->escan_info.ndev == ndev)) { - /* Abort any pending scan requests */ - wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (!rtnl_is_locked()) { - rtnl_lock(); + /* Abort any pending scan requests */ + wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + if (!rtnl_is_locked()) { + rtnl_lock(); rollback_lock = true; - } + } WL_DBG(("ESCAN COMPLETED\n")); + WL_SCAN2(("Send Notify Complete %p(id %d)\n", + ndev, wl->escan_info.cur_sync_id)); wl_notify_escan_complete(wl, ndev, true); - if (rollback_lock) - rtnl_unlock(); - } + if (rollback_lock) + rtnl_unlock(); + } WL_ERR(("IF_DEL event called from dongle, net %x, vif name: %s\n", (unsigned int)ndev, wl->p2p->vir_ifname)); @@ -1354,10 +1441,12 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) WL_DBG(("index : %d\n", index)); #ifdef PROP_TXSTATUS if (dhd->wlfc_enabled && wl->wlfc_on) { + dhd->wlfc_enabled = false; dhd_wlfc_deinit(dhd); wl->wlfc_on = false; } #endif + wl_clr_drv_status(wl, CONNECTED, ndev); } /* Wake up any waiting thread */ wake_up_interruptible(&wl->netif_change_event); @@ -1453,21 +1542,23 @@ static s32 wl_find_my_listen_channel(struct wl_priv *wl, return 0; } -static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) +static void wl_scan_prep(struct wl_scan_params *params, + struct cfg80211_scan_request *request, int32 active_time) { u32 n_ssids; u32 n_channels; u16 channel; chanspec_t chanspec; - s32 i, offset; + s32 i = 0; + s32 offset; char *ptr; wlc_ssid_t ssid; - + struct wl_priv *wl = wlcfg_drv_priv; memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); params->bss_type = DOT11_BSSTYPE_ANY; params->scan_type = 0; params->nprobes = -1; - params->active_time = -1; + params->active_time = active_time; params->passive_time = -1; params->home_time = -1; params->channel_num = 0; @@ -1488,6 +1579,7 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req if (!request) return; + /* TODO: validity check for null dereference is necessary. */ n_ssids = request->n_ssids; n_channels = request->n_channels; @@ -1496,34 +1588,36 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req if (n_channels > 0) { for (i = 0; i < n_channels; i++) { chanspec = 0; - channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); - if (request->channels[i]->band == IEEE80211_BAND_2GHZ) - chanspec |= WL_CHANSPEC_BAND_2G; - else - chanspec |= WL_CHANSPEC_BAND_5G; + if (!request->channels[i] || !request->channels[i]->center_freq) { + break; + } + else { + channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); + /* SKIP DFS channels for Secondary interface */ + if ((wl->escan_info.ndev != wl_to_prmry_ndev(wl)) && + (request->channels[i]->flags & (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN))) + continue; + + if (request->channels[i]->band == IEEE80211_BAND_2GHZ) + chanspec |= WL_CHANSPEC_BAND_2G; + else + chanspec |= WL_CHANSPEC_BAND_5G; - if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40) { chanspec |= WL_CHANSPEC_BW_20; chanspec |= WL_CHANSPEC_CTL_SB_NONE; - } else { - chanspec |= WL_CHANSPEC_BW_40; - if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40PLUS) - chanspec |= WL_CHANSPEC_CTL_SB_LOWER; - else - chanspec |= WL_CHANSPEC_CTL_SB_UPPER; - } - params->channel_list[i] = channel; - params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK; - params->channel_list[i] |= chanspec; - WL_SCAN(("Chan : %d, Channel spec: %x \n", - channel, params->channel_list[i])); - params->channel_list[i] = htod16(params->channel_list[i]); + params->channel_list[i] = channel; + params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK; + params->channel_list[i] |= chanspec; + WL_SCAN(("Chan : %d, Channel spec: %x \n", + channel, params->channel_list[i])); + params->channel_list[i] = htod16(params->channel_list[i]); + } } } else { WL_SCAN(("Scanning all channels\n")); } - + n_channels = i; /* Copy ssid array if applicable */ WL_SCAN(("### List of SSIDs to scan ###\n")); if (n_ssids > 0) { @@ -1532,8 +1626,14 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req ptr = (char*)params + offset; for (i = 0; i < n_ssids; i++) { memset(&ssid, 0, sizeof(wlc_ssid_t)); - ssid.SSID_len = request->ssids[i].ssid_len; - memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len); + if(request->ssids && request->ssids[i].ssid) { + ssid.SSID_len = request->ssids[i].ssid_len; + memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len); + } + else { + ssid.SSID_len = 0; + ssid.SSID[0] = '\0'; + } if (!ssid.SSID_len) WL_SCAN(("%d: Broadcast scan\n", i)); else @@ -1549,6 +1649,10 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req params->channel_num = htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); + + if (n_channels == 1 && wl_get_drv_status_all(wl, CONNECTED)) { + params->active_time = WL_SCAN_CONNECT_DWELL_TIME_MS; + } } static s32 @@ -1561,7 +1665,10 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, struct wl_iscan_params *params = NULL; s32 err = 0; - if (request != NULL) { + if (!request) { + err = -EINVAL; + goto done; + }else { n_channels = request->n_channels; n_ssids = request->n_ssids; /* Allocate space for populating ssids in wl_iscan_params struct */ @@ -1574,14 +1681,14 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, /* Allocate space for populating ssids in wl_iscan_params struct */ params_size += sizeof(struct wlc_ssid) * n_ssids; } + params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL); if (!params) { err = -ENOMEM; goto done; } - if (request != NULL) - wl_scan_prep(¶ms->params, request); + wl_scan_prep(¶ms->params, request, -1); params->version = htod32(ISCAN_REQ_VERSION); params->action = htod16(action); @@ -1602,7 +1709,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, } } done: - if(params) + if (params) kfree(params); return err; } @@ -1649,9 +1756,10 @@ wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) return err; } -#ifdef USE_INITIAL_2G_SCAN +#ifdef USE_INITIAL_2G_SCAN_ORG +#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40 static bool g_first_broadcast_scan = TRUE; -#endif /* USE_INITIAL_2G_SCAN */ +#endif /* USE_INITIAL_2G_SCAN_ORG */ static s32 wl_run_escan(struct wl_priv *wl, struct net_device *ndev, @@ -1662,7 +1770,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, u32 n_ssids; s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); wl_escan_params_t *params = NULL; - struct cfg80211_scan_request *scan_request = wl->scan_request; + u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)]; u32 num_chans = 0; s32 channel; @@ -1673,61 +1781,70 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wl_uint32_list_t *list; struct net_device *dev = NULL; WL_DBG(("Enter \n")); - WL_DBG(("p2p_supported ? %s, ndev is %s, p2p_scan ? %s, p2p_is_on ? %s\n", - (wl->p2p_supported) ? "YES":"NO", - (ndev == wl_to_prmry_ndev(wl)) ? "Primary":"P2P", - p2p_scan(wl) ? "YES":"NO", - p2p_is_on(wl) ? "YES":"NO")); - - if (!wl->p2p_supported || ((ndev == wl_to_prmry_ndev(wl)) && - !p2p_scan(wl))) { + + /* sanity check for pointer dereference */ + if (!request || !wl) { + err = -EINVAL; + goto exit; + } + + if (!wl->p2p_supported) + WL_SCAN2(("P2P is not supported\n")); + else + WL_SCAN2(("P2P is supported, ndev is %s, " + "p2p_scan ? %s, p2p_is_on ? %s\n", + (ndev == wl_to_prmry_ndev(wl)) ? "Primary" : "P2P", + p2p_scan(wl) ? "YES" : "NO", + p2p_is_on(wl) ? "YES" : "NO")); + + if (!wl->p2p_supported || !p2p_scan(wl)) { + s32 active_time = -1; + /* LEGACY SCAN TRIGGER */ WL_SCAN((" LEGACY E-SCAN START\n")); - if (request != NULL) { -#ifdef USE_INITIAL_2G_SCAN - if (g_first_broadcast_scan == TRUE) { - j = 0; - if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { - list = (wl_uint32_list_t *) chan_buf; - n_valid_chan = dtoh32(list->count); - for (i = 0; i < n_valid_chan; i++) { -#if defined(BCM4334_CHIP) - request->channels[i]->flags |= - IEEE80211_CHAN_NO_HT40; -#endif - WL_SCAN(("list->element[%d]=%d\n", - i, list->element[i])); - if (list->element[i] > CH_MAX_2G_CHANNEL) - break; - j++; - } - request->n_channels = j; - WL_SCAN(("request->n_channels=%d\n", request->n_channels)); - g_first_broadcast_scan = FALSE; +#ifdef USE_INITIAL_2G_SCAN_ORG + if (ndev == wl_to_prmry_ndev(wl) && g_first_broadcast_scan == true) { + j = 0; + if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { + list = (wl_uint32_list_t *) chan_buf; + n_valid_chan = dtoh32(list->count); + for (i = 0; i < n_valid_chan; i++) { + + WL_SCAN(("list->element[%d]=%d\n", + i, list->element[i])); + if (list->element[i] > CH_MAX_2G_CHANNEL) + break; + j++; } - } -#endif /* USE_INITIAL_2G_SCAN */ - n_channels = request->n_channels; - n_ssids = request->n_ssids; - /* Allocate space for populating ssids in wl_iscan_params struct */ - if (n_channels % 2) - /* If n_channels is odd, add a padd of u16 */ - params_size += sizeof(u16) * (n_channels + 1); - else - params_size += sizeof(u16) * n_channels; + request->n_channels = j; - /* Allocate space for populating ssids in wl_iscan_params struct */ - params_size += sizeof(struct wlc_ssid) * n_ssids; + active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS; + WL_SCAN(("request->n_channels=%d\n", request->n_channels)); + g_first_broadcast_scan = false; + } } +#endif /* USE_INITIAL_2G_SCAN_ORG */ + + n_channels = request->n_channels; + n_ssids = request->n_ssids; + /* Allocate space for populating ssids in wl_iscan_params struct */ + if (n_channels % 2) + /* If n_channels is odd, add a padd of u16 */ + params_size += sizeof(u16) * (n_channels + 1); + else + params_size += sizeof(u16) * n_channels; + + /* Allocate space for populating ssids in wl_iscan_params struct */ + params_size += sizeof(struct wlc_ssid) * n_ssids; + params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); if (params == NULL) { err = -ENOMEM; goto exit; } - if (request != NULL) - wl_scan_prep(¶ms->params, request); + wl_scan_prep(¶ms->params, request, active_time); params->version = htod32(ESCAN_REQ_VERSION); params->action = htod16(action); params->sync_id = wl->escan_info.cur_sync_id; @@ -1752,8 +1869,8 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, WL_DBG((" P2P E-SCAN START\n")); - if (scan_request && scan_request->n_channels) { - num_chans = scan_request->n_channels; + if (request->n_channels) { + num_chans = request->n_channels; WL_SCAN((" chann number : %d\n", num_chans)); default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), GFP_KERNEL); @@ -1767,10 +1884,11 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, n_valid_chan = dtoh32(list->count); for (i = 0; i < num_chans; i++) { - _freq = scan_request->channels[i]->center_freq; + _freq = request->channels[i]->center_freq; channel = ieee80211_frequency_to_channel(_freq); /* remove DFS channels */ - if (channel < 52 || channel > 140) { + if (!(request->channels[i]->flags & + (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN))) { for (j = 0; j < n_valid_chan; j++) { /* allows only supported channel on * current reguatory @@ -1824,6 +1942,13 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, s32 passive_scan; wl_scan_results_t *results; WL_SCAN(("Enter \n")); + + WL_SCAN2(("scan result set to sync id :%d\n", wl->escan_info.cur_sync_id%2)); + results = (wl_scan_results_t *) wl->escan_info.escan_buf[wl->escan_info.cur_sync_id%2]; + results->version = 0; + results->count = 0; + results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; + wl->escan_info.ndev = ndev; wl->escan_info.wiphy = wiphy; wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING; @@ -1834,10 +1959,6 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, WL_ERR(("error (%d)\n", err)); return err; } - results = (wl_scan_results_t *) wl->escan_info.escan_buf[wl->escan_info.cur_sync_id%2]; - results->version = 0; - results->count = 0; - results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; err = wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START); return err; @@ -1853,15 +1974,19 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct wl_scan_req *sr = wl_to_sr(wl); struct ether_addr primary_mac; wpa_ie_fixed_t *wps_ie; + wifi_p2p_ie_t *p2p_ie; s32 passive_scan; bool iscan_req; bool escan_req = false; bool p2p_ssid; s32 err = 0; + s32 bssidx = -1; s32 i; u32 wpsie_len = 0; + u32 p2pie_len = 0; u8 wpsie[IE_MAX_LEN]; unsigned long flags; + static s32 busy_count = 0; /* If scan req comes for p2p0, send it over primary I/F * Scan results will be delivered corresponding to cfg80211_scan_request @@ -1870,11 +1995,26 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ndev = wl_to_prmry_ndev(wl); } + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM) +#ifdef WL_CFG80211_SYNC_GON_TIME + || wl_get_drv_status_all(wl, WAITING_MORE_TIME_NEXT_ACT_FRM) +#endif /* WL_CFG80211_SYNC_GON_TIME */ + ) { + WL_ERR(("Sending Action Frames. Try it again.\n")); + return -EAGAIN; + } + WL_DBG(("Enter wiphy (%p)\n", wiphy)); if (wl_get_drv_status_all(wl, SCANNING)) { - WL_ERR(("Scanning already\n")); - return -EAGAIN; + if(wl->scan_request == NULL) { + wl_clr_drv_status_all(wl, SCANNING); + WL_DBG(( "<<<<<<<<<<<Force Clear Scanning Status>>>>>>>>>>>\n")); + } else { + WL_ERR(("Scanning already\n")); + return -EAGAIN; + } } + if (wl_get_drv_status(wl, SCAN_ABORTING, ndev)) { WL_ERR(("Scanning being aborted\n")); return -EAGAIN; @@ -1888,6 +2028,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL)) { + WL_SCAN2(("request scan abort: %p(%d)\n", ndev, wl->escan_info.cur_sync_id)); wl_cfg80211_scan_abort(wl, ndev); } #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ @@ -1903,7 +2044,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, escan_req = true; p2p_ssid = false; for (i = 0; i < request->n_ssids; i++) { - if (ssids[i].ssid_len && IS_P2P_SSID(ssids[i].ssid)) { + if (ssids[i].ssid_len && IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { p2p_ssid = true; break; } @@ -1930,8 +2071,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, /* If Netdevice is not equals to primary and p2p is on * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. */ - if (p2p_on(wl) && (ndev != wl_to_prmry_ndev(wl))) - p2p_scan(wl) = true; if (p2p_scan(wl) == false) { if (wl_get_p2p_status(wl, DISCOVERY_ON)) { @@ -1945,24 +2084,31 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } } if (!wl->p2p_supported || !p2p_scan(wl)) { - if (ndev == wl_to_prmry_ndev(wl)) { - /* find the WPSIE */ - memset(wpsie, 0, sizeof(wpsie)); - if ((wps_ie = wl_cfgp2p_find_wpsie( - (u8 *)request->ie, - request->ie_len)) != NULL) { - wpsie_len = - wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; - memcpy(wpsie, wps_ie, wpsie_len); - } else { - wpsie_len = 0; - } - err = wl_cfgp2p_set_management_ie(wl, ndev, -1, + /* find the WPSIE */ + memset(wpsie, 0, sizeof(wpsie)); + if ((wps_ie = wl_cfgp2p_find_wpsie( + (u8 *)request->ie, + request->ie_len)) != NULL) { + wpsie_len = + wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; + memcpy(wpsie, wps_ie, wpsie_len); + } else { + wpsie_len = 0; + } + if ((p2p_ie = wl_cfgp2p_find_p2pie( + (u8 *)request->ie, + request->ie_len)) != NULL && (ndev != wl_to_prmry_ndev(wl))) { + p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id); + memcpy(wpsie + wpsie_len, p2p_ie, p2pie_len); + wpsie_len += p2pie_len; + bssidx = wl_cfgp2p_find_idx(wl, ndev); + } + err = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, VNDR_IE_PRBREQ_FLAG, wpsie, wpsie_len); - if (unlikely(err)) { - goto scan_out; - } + if (unlikely(err)) { + goto scan_out; } + } } } @@ -1975,7 +2121,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (iscan_req) { err = wl_do_iscan(wl, request); if (likely(!err)) - return err; + goto scan_success; else goto scan_out; } else if (escan_req) { @@ -1995,7 +2141,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } err = wl_do_escan(wl, wiphy, ndev, request); if (likely(!err)) - return err; + goto scan_success; else goto scan_out; @@ -2033,6 +2179,10 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } } +scan_success: + + busy_count = 0; + return 0; scan_out: @@ -2042,10 +2192,21 @@ scan_out: err = -EBUSY; } + /*if continuous busy state , abort scan */ + if (err == -EBUSY) { + if (busy_count++ > 5) { + busy_count = 0; + wl_cfg80211_scan_abort(wl, ndev); + } + } else { + busy_count = 0; + } + wl_clr_drv_status(wl, SCANNING, ndev); spin_lock_irqsave(&wl->cfgdrv_lock, flags); wl->scan_request = NULL; spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + WL_SCAN2(("remove scan request:%p %d \n", ndev, wl->escan_info.cur_sync_id)); return err; } @@ -2057,6 +2218,7 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct wl_priv *wl = wiphy_priv(wiphy); WL_DBG(("Enter \n")); + WL_SCAN2(("start %p\n", ndev)); CHECK_SYS_UP(wl); err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); @@ -2313,15 +2475,15 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) s32 bssidx = wl_cfgp2p_find_idx(wl, dev); switch (sme->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: - val = 0; + val = WL_AUTH_OPEN_SYSTEM; WL_DBG(("open system\n")); break; case NL80211_AUTHTYPE_SHARED_KEY: - val = 1; + val = WL_AUTH_SHARED_KEY; WL_DBG(("shared key\n")); break; case NL80211_AUTHTYPE_AUTOMATIC: - val = 2; + val = WL_AUTH_OPEN_SHARED; WL_DBG(("automatic\n")); break; case NL80211_AUTHTYPE_NETWORK_EAP: @@ -2331,7 +2493,7 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) break; #endif default: - val = 2; + val = WL_AUTH_OPEN_SHARED; WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); break; } @@ -2417,7 +2579,11 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); if (is_wps_conn(sme)) { - err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); + if(sme->privacy) + err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); + else + /* WPS-2.0 allows no security */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); } else { #ifdef BCMWAPI_WPI if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) { @@ -2644,10 +2810,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, #ifdef ROAM_CHANNEL_CACHE chanspec_t chanspec_list[MAX_ROAM_CACHE_NUM]; #endif + int ret; WL_DBG(("In\n")); - if (unlikely(!sme->ssid) || unlikely(!sme->bssid)) { + if (unlikely(!sme->ssid)) { WL_ERR(("Invalid ssid\n")); return -EOPNOTSUPP; } @@ -2657,8 +2824,9 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, /* * Cancel ongoing scan to sync up with sme state machine of cfg80211. */ -#ifndef ESCAN_RESULT_PATCH +#if (defined (BCM4334_CHIP) || !defined(ESCAN_RESULT_PATCH)) if (wl->scan_request) { + WL_SCAN2(("Abort Scan %p(%d)\n", dev, wl->escan_info.cur_sync_id)); wl_cfg80211_scan_abort(wl, dev); } #endif @@ -2668,20 +2836,54 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, wl->block_gon_req_tx_count = 0; wl->block_gon_req_rx_count = 0; #endif /* WL_CFG80211_GON_COLLISION */ - WL_DBG(("Connect Request: \"%s\" %02x:%02x:%02x:%02x:%02x:%02x\n", - sme->ssid, sme->bssid[0], sme->bssid[1], sme->bssid[2], - sme->bssid[3], sme->bssid[4], sme->bssid[5])); + if (sme->bssid) { + WL_SCAN2(("Connect Request: \"%s\"" MACSTR "\n", + sme->ssid, MAC2STR(sme->bssid))); #ifdef ESCAN_RESULT_PATCH - memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); + memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); + }else { + bzero(connect_req_bssid, ETHER_ADDR_LEN); + } bzero(broad_bssid, ETHER_ADDR_LEN); +#else + } #endif + bzero(&bssid, sizeof(bssid)); + if (!wl_get_drv_status(wl, CONNECTED, dev)&& + (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) { + if(!ETHER_ISNULLADDR(&bssid)) { + scb_val_t scbval; + wl_set_drv_status(wl, DISCONNECTING, dev); + scbval.val = DOT11_RC_DISASSOC_LEAVING; + memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + + WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACSTR "/n" + , MAC2STR(bssid.octet))); + err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t), true); + if (unlikely(err)) { + wl_clr_drv_status(wl, DISCONNECTING, dev); + WL_ERR(("error (%d)\n", err)); + return err; + } + while (wl_get_drv_status(wl, DISCONNECTING, dev)) { + WL_ERR(("Waiting for disconnection terminated.\n")); + msleep(20); + } + } else + WL_DBG(("Currently not associated!\n")); + } + /* Clean BSSID */ bzero(&bssid, sizeof(bssid)); - wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID); + if (!wl_get_drv_status(wl, DISCONNECTING, dev)) + wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID); - if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) { + if (!memcmp(sme->ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && + (dev != wl_to_prmry_ndev(wl))) { /* we only allow to connect using virtual interface in case of P2P */ if (p2p_is_on(wl) && is_wps_conn(sme)) { WL_DBG(("ASSOC1 p2p index : %d sme->ie_len %d\n", @@ -2744,13 +2946,16 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return err; } } - if (unlikely(!sme->ssid)) { - WL_ERR(("Invalid ssid\n")); - return -EOPNOTSUPP; - } + if (chan) { #ifdef ROAM_CHANNEL_CACHE wlc_ssid_t ssid; + int band; + + err = wldev_get_band(dev, &band); + if (!err) { + set_roam_band(band); + } wl->channel = ieee80211_frequency_to_channel(chan->center_freq); memcpy(ssid.SSID, sme->ssid, sme->ssid_len); @@ -2787,11 +2992,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, else { WL_DBG(("4. wl_set_auth_type\n")); #endif - err = wl_set_auth_type(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid auth type\n")); - return err; - } + err = wl_set_auth_type(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid auth type\n")); + return err; + } #ifdef BCMWAPI_WPI } #endif @@ -2829,14 +3034,14 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len); memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len); ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); - /* Set up join scan parameters */ - ext_join_params->scan.scan_type = -1; - ext_join_params->scan.nprobes = 2; /* increate dwell time to receive probe response or detect Beacon * from target AP at a noisy air only during connect command */ - ext_join_params->scan.active_time = WL_SCAN_ACTIVE_TIME*3; + ext_join_params->scan.active_time = WL_SCAN_ACTIVE_TIME*8; ext_join_params->scan.passive_time = WL_SCAN_PASSIVE_TIME*3; + /* Set up join scan parameters */ + ext_join_params->scan.scan_type = -1; + ext_join_params->scan.nprobes = (ext_join_params->scan.active_time/(WL_SCAN_ACTIVE_TIME *2)); ext_join_params->scan.home_time = -1; if (sme->bssid) @@ -2932,9 +3137,10 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, /* * Cancel ongoing scan to sync up with sme state machine of cfg80211. */ -#ifndef ESCAN_RESULT_PATCH +#if (defined (BCM4334_CHIP) || !defined (ESCAN_RESULT_PATCH)) /* Let scan aborted by F/W */ if (wl->scan_request) { + WL_SCAN2(("Abort scan : %p(%d)\n", dev, wl->escan_info.cur_sync_id)); wl_cfg80211_scan_abort(wl, dev); } #endif /* ESCAN_RESULT_PATCH */ @@ -3412,8 +3618,10 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); if (!wl_get_drv_status(wl, CONNECTED, dev) || - (dhd_is_associated(dhd, NULL) == FALSE)) { + (dhd_is_associated(dhd, NULL, &err) == FALSE)) { WL_ERR(("NOT assoc\n")); + if(err == -ERESTARTSYS) + return err; #ifdef ESCAN_RESULT_PATCH return -ENODEV; #else @@ -3451,7 +3659,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("RSSI %d dBm\n", rssi)); get_station_err: - if (err) { + if (err && (err != -ERESTARTSYS)) { /* Disconnect due to zero BSSID or error to get RSSI */ WL_ERR(("force cfg80211_disconnected\n")); wl_clr_drv_status(wl, CONNECTED, dev); @@ -3469,18 +3677,20 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, { s32 pm; s32 err = 0; + struct wl_priv *wl = wiphy_priv(wiphy); + struct net_info *_net_info = wl_get_netinfo_by_netdev(wl, dev); CHECK_SYS_UP(wl); - if (wl->p2p_net == dev) { + if (wl->p2p_net == dev || _net_info == NULL) { return err; } pm = enabled ? PM_FAST : PM_OFF; /* Do not enable the power save after assoc if it is p2p interface */ - if (wl->p2p && wl->p2p->vif_created) { - WL_DBG(("Do not enable the power save for p2p interfaces even after assoc\n")); + if (_net_info->pm_block || wl->vsdb_mode) { + WL_DBG(("Do not enable the power save\n")); pm = PM_OFF; } pm = htod32(pm); @@ -3562,12 +3772,15 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy) if (wl->scan_request) { cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + WL_SCAN2(("remove scan_request %p, %d\n", ndev, wl->escan_info.cur_sync_id)); + } else { + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); } for_each_ndev(wl, iter, next) { wl_clr_drv_status(wl, SCANNING, iter->ndev); wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev); } - spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); for_each_ndev(wl, iter, next) { if (wl_get_drv_status(wl, CONNECTING, iter->ndev)) { wl_bss_connect_done(wl, iter->ndev, NULL, NULL, false); @@ -3769,13 +3982,21 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) } } del_timer_sync(&wl->scan_timeout); +#if defined(BCM4334_CHIP) + if (wl->scan_request) { + u8 temp_id = wl->escan_info.cur_sync_id; + wl->bss_list = (wl_scan_results_t *) wl->escan_info.escan_buf[(temp_id+1)%2]; + wl_inform_bss(wl); + } +#endif spin_lock_irqsave(&wl->cfgdrv_lock, flags); if (wl->scan_request) { cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; } - wl_clr_drv_status(wl, SCANNING, ndev); + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + wl_clr_drv_status(wl, SCANNING, ndev); if (params) kfree(params); return err; @@ -3791,9 +4012,10 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, u32 id; struct ether_addr primary_mac; struct net_device *ndev = NULL; - s32 err = BCME_OK; struct wl_priv *wl = wiphy_priv(wiphy); + + WL_SCAN2(("duration :%d\n", duration)); WL_DBG(("Enter, ifindex: %d, channel: %d, duration ms (%d) SCANNING ?? %s \n", dev->ifindex, ieee80211_frequency_to_channel(channel->center_freq), duration, (wl_get_drv_status(wl, SCANNING, ndev)) ? "YES":"NO")); @@ -3810,6 +4032,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, } #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST if (wl_get_drv_status(wl, SCANNING, ndev)) { + WL_SCAN2(("Abort Scan : %p(%d)\n", ndev, wl->escan_info.cur_sync_id)); wl_cfg80211_scan_abort(wl, ndev); } #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ @@ -3861,7 +4084,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, } #endif /* WL_CFG80211_SYNC_GON_TIME */ - if (!p2p_is_on(wl)) { + if (wl->p2p && !wl->p2p->on) { get_primary_mac(wl, &primary_mac); wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); @@ -3890,6 +4113,8 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, /* if failed, firmware may be internal scanning state. so other scan request shall not abort it */ wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); + /* set err = ok to prevent cookie mismatch */ + err = BCME_OK; } #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ } @@ -3911,6 +4136,10 @@ wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl) { wl_af_params_t *tx_act_frm; struct net_device *dev = wl->afx_hdl->dev; + + if (dev == NULL) + return -1; + if (!p2p_is_on(wl)) return -1; @@ -3930,7 +4159,10 @@ wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl) wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev); #endif wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); +/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary */ +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST wl_cfg80211_scan_abort(wl, dev); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ wl_cfgp2p_discover_enable_search(wl, false); tx_act_frm->channel = wl->afx_hdl->peer_chan; wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev, @@ -3947,9 +4179,9 @@ wl_cfg80211_afx_handler(struct work_struct *work) s32 ret = BCME_OK; afx_instance = container_of(work, struct afx_hdl, work); - if (afx_instance != NULL) { + if (afx_instance != NULL && wl->afx_hdl->is_active) { if (wl->afx_hdl->is_listen && wl->afx_hdl->my_listen_chan) { - ret = wl_cfgp2p_discover_listen(wl, wl->afx_hdl->my_listen_chan, 100); + ret = wl_cfgp2p_discover_listen(wl, wl->afx_hdl->my_listen_chan, 200); } else { ret = wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev, wl->afx_hdl->bssidx, wl->afx_hdl->peer_listen_chan); @@ -3967,6 +4199,8 @@ wl_cfg80211_send_at_common_channel(struct wl_priv *wl, struct net_device *dev, wl_af_params_t *af_params) { + u32 max_retry = WL_CHANNEL_SYNC_RETRY; + WL_DBG((" enter ) \n")); /* initialize afx_hdl */ wl->afx_hdl->pending_tx_act_frm = af_params; @@ -3976,11 +4210,15 @@ wl_cfg80211_send_at_common_channel(struct wl_priv *wl, wl->afx_hdl->peer_chan = WL_INVALID; wl->afx_hdl->ack_recv = false; + WL_AF_TX_REDUCE_RETRY_VSDB(wl, max_retry); + wl_set_drv_status(wl, SCANNING_PEER_CHANNEL, dev); + wl->afx_hdl->is_active = TRUE; + /* Loop to wait until we have sent the pending tx action frame or the * pending action frame tx is cancelled. */ - while ((wl->afx_hdl->retry < WL_CHANNEL_SYNC_RETRY) && + while ((wl->afx_hdl->retry < max_retry) && (wl->afx_hdl->peer_chan == WL_INVALID)) { wl->afx_hdl->is_listen = FALSE; wl_set_drv_status(wl, SCANNING, dev); @@ -3992,7 +4230,7 @@ wl_cfg80211_send_at_common_channel(struct wl_priv *wl, msecs_to_jiffies(MAX_WAIT_TIME)); if ((wl->afx_hdl->peer_chan != WL_INVALID) || - !(wl_get_drv_status_all(wl, SCANNING_PEER_CHANNEL))) + !(wl_get_drv_status(wl, SCANNING_PEER_CHANNEL, dev))) break; if (wl->afx_hdl->my_listen_chan) { @@ -4004,12 +4242,17 @@ wl_cfg80211_send_at_common_channel(struct wl_priv *wl, wait_for_completion_timeout(&wl->act_frm_scan, msecs_to_jiffies(MAX_WAIT_TIME)); } - if (!wl_get_drv_status_all(wl, SCANNING_PEER_CHANNEL)) + if (!wl_get_drv_status(wl, SCANNING_PEER_CHANNEL, dev)) break; wl->afx_hdl->retry++; + + WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); } - wl_clr_drv_status(wl, SCANNING_PEER_CHANNEL, wl->afx_hdl->dev); + wl->afx_hdl->is_active = FALSE; + + wl_clr_drv_status(wl, SCANNING, dev); + wl_clr_drv_status(wl, SCANNING_PEER_CHANNEL, dev); if (wl->afx_hdl->peer_chan != WL_INVALID) wl_cfg80211_send_pending_tx_act_frm(wl); @@ -4134,18 +4377,18 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, add_len = customer_ie->len + sizeof(customer_ie->len) + sizeof(customer_ie->id); customer_ie_len += add_len; - ptr = (u8 *)customer_ie + add_len; + ptr = (u8*)customer_ie + add_len; remain_len -= add_len; WL_INFO(("Customer IE exist(len:%d)\n", add_len)); } else break; } - /* Order of Vendor IE is 1) WPS IE + - * 2) P2P IE created by supplicant - * So, it is ok to find start address of WPS IE - * to save IEs - */ + /* Order of Vendor IE is 1) WPS IE + + * 2) P2P IE created by supplicant + * So, it is ok to find start address of WPS IE + * to save IEs + */ wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_PRBRSP_FLAG, @@ -4157,8 +4400,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, ieee80211_is_deauth(mgmt->frame_control)) { memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); scb_val.val = mgmt->u.disassoc.reason_code; - wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, - sizeof(scb_val_t), true); + if (wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, + sizeof(scb_val_t), true) < 0) + WL_ERR(("Connect Status check is required\n")); WL_DBG(("Disconnect STA : %s\n", bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf))); cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); @@ -4172,8 +4416,14 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, * tx is still in progress (including the dwell time), * then this new action frame will not be sent out. */ - wl_cfg80211_scan_abort(wl, dev); +/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary. + * And previous off-channel action frame must be ended before new af tx. + */ +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + WL_SCAN2(("Abort scan: %p(%d)\n", dev, wl->escan_info.cur_sync_id)); + wl_cfg80211_scan_abort(wl, dev); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ } } else { @@ -4210,13 +4460,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, wl->afx_hdl->peer_listen_chan = af_params->channel; WL_DBG(("channel from upper layer %d\n", wl->afx_hdl->peer_listen_chan)); - if (channel->band == IEEE80211_BAND_5GHZ) { - err = wldev_ioctl(dev, WLC_SET_CHANNEL, - &af_params->channel, sizeof(af_params->channel), true); - if (err < 0) { - WL_ERR(("WLC_SET_CHANNEL error %d\n", err)); - } - } + /* Add the dwell time * Dwell time to stay off-channel to wait for a response action frame @@ -4226,10 +4470,10 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); if (wl_cfgp2p_is_pub_action(action_frame->data, action_frame->len)) { - act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data); + act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data); WL_DBG(("P2P PUB action_frame->len: %d chan %d category %d subtype %d\n", - action_frame->len, af_params->channel, - act_frm->category, act_frm->subtype)); + action_frame->len, af_params->channel, + act_frm->category, act_frm->subtype)); } else if (wl_cfgp2p_is_p2p_action(action_frame->data, action_frame->len)) { p2p_act_frm = (wifi_p2p_action_frame_t *) (action_frame->data); WL_DBG(("P2P action_frame->len: %d chan %d category %d subtype %d\n", @@ -4307,6 +4551,18 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, } +#ifdef VSDB + /* if connecting, sleep for a while before retry for VSDB */ + if (wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { + msleep(50); + } +#endif + + /* if scanning, abort current scan. */ + if (wl_get_drv_status_all(wl, SCANNING)) { + wl_cfg80211_scan_abort(wl, dev); + } + /* Set SENDING_ACT_FRM and destinatio address for sending af */ wl_set_drv_status(wl, SENDING_ACT_FRM, dev); memcpy(wl->afx_hdl->tx_dst_addr.octet, @@ -4325,8 +4581,16 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, /* channel offload for action request frame */ ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params); } else { + if (!wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) + WL_ERR(("<<<< TX action frame without probe req ie >>>>\n")); + if (!IS_P2P_SOCIAL(af_params->channel)) + WL_ERR(("<<<< TX action frame with (CH %d) >>>>\n", + af_params->channel)); ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; if (!ack) { + u32 max_retry = WL_CHANNEL_SYNC_RETRY; + WL_AF_TX_REDUCE_RETRY_VSDB(wl, max_retry); + if (wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { /* if the NO ACK occurs, the peer device will be on * listen channel of the peer @@ -4340,7 +4604,8 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, !IS_P2P_PUB_ACT_RSP_SUBTYPE(act_frm->subtype)) { ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params); } else { - for (retry = 0; retry < WL_CHANNEL_SYNC_RETRY; retry++) { + for (retry = 0; retry < max_retry; retry++) { + WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; if (ack) @@ -4348,7 +4613,8 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, } } } else { - for (retry = 0; retry < WL_CHANNEL_SYNC_RETRY; retry++) { + for (retry = 0; retry < max_retry; retry++) { + WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; if (ack) @@ -4382,10 +4648,10 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, wait_for_completion_timeout(&wl->wait_next_af, msecs_to_jiffies(extar_listen_time + 100 + 300)); } + wl_clr_drv_status(wl, WAITING_MORE_TIME_NEXT_ACT_FRM, dev); } } wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, dev); - wl_clr_drv_status(wl, WAITING_MORE_TIME_NEXT_ACT_FRM, dev); WL_INFO(("-- sending Action Frame is %s, af sent chan: %d, my listen chan: %d\n", (ack) ? "Succeeded!!":"Failed!!", wl->af_sent_channel, wl->afx_hdl->my_listen_chan)); @@ -4460,20 +4726,75 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { - s32 channel; + s32 _chan; +#ifdef HT40_GO + s32 center_chan; + chanspec_t chspec = 0; +#endif s32 err = BCME_OK; struct wl_priv *wl = wiphy_priv(wiphy); if (wl->p2p_net == dev) { dev = wl_to_prmry_ndev(wl); } - channel = ieee80211_frequency_to_channel(chan->center_freq); - WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", - dev->ifindex, channel_type, channel)); - err = wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), true); + _chan = ieee80211_frequency_to_channel(chan->center_freq); + WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", + dev->ifindex, channel_type, _chan)); + +#ifdef NOT_YET + switch (channel_type) { + case NL80211_CHAN_HT40MINUS: + /* secondary channel is below the control channel */ + chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_UPPER); + break; + case NL80211_CHAN_HT40PLUS: + /* secondary channel is above the control channel */ + chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_LOWER); + break; + default: + chspec = CH20MHZ_CHSPEC(channel); + + } +#endif +#ifdef HT40_GO + switch(_chan) { + /* adjust channel to center of 40MHz band */ + case 40: + case 48: + case 153: + case 161: + if (_chan <= (MAXCHANNEL - CH_20MHZ_APART)) + center_chan = _chan - CH_10MHZ_APART; + chspec = CH40MHZ_CHSPEC(center_chan, WL_CHANSPEC_CTL_SB_UPPER); + break; + case 36: + case 44: + case 149: + case 157: + if (_chan <= (MAXCHANNEL - CH_20MHZ_APART)) + center_chan = _chan + CH_10MHZ_APART; + chspec = CH40MHZ_CHSPEC(center_chan, WL_CHANSPEC_CTL_SB_LOWER); + break; + default: + chspec = CH20MHZ_CHSPEC(_chan); + break; + } + + + if ((err = wldev_iovar_setint(dev, "chanspec", chspec)) == BCME_BADCHAN) { + err = wldev_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), true); + if (err < 0) { + WL_ERR(("WLC_SET_CHANNEL error %d" + "chip may not be supporting this channel\n", err)); + } + } +#else + err = wldev_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), true); if (err < 0) { - WL_ERR(("WLC_SET_CHANNEL error %d chip may not be supporting this channel\n", err)); + WL_ERR(("WLC_SET_CHANNEL error %d" + "chip may not be supporting this channel\n", err)); } +#endif return err; } @@ -4487,7 +4808,6 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) u32 pval = 0; u32 gval = 0; u32 wpa_auth = 0; - u8* tmp; wpa_suite_mcast_t *mcast; wpa_suite_ucast_t *ucast; wpa_suite_auth_key_mgmt_t *mgmt; @@ -4498,8 +4818,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) len = wpa2ie->len; /* check the mcast cipher */ mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; - tmp = mcast->oui; - switch (tmp[DOT11_OUI_LEN]) { + switch (mcast->type) { case WPA_CIPHER_NONE: gval = 0; break; @@ -4526,8 +4845,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) /* check the unicast cipher */ ucast = (wpa_suite_ucast_t *)&mcast[1]; ltoh16_ua(&ucast->count); - tmp = ucast->list[0].oui; - switch (tmp[DOT11_OUI_LEN]) { + switch (ucast->list[0].type) { case WPA_CIPHER_NONE: pval = 0; break; @@ -4554,8 +4872,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) /* check the AKM */ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[1]; ltoh16_ua(&mgmt->count); - tmp = (u8 *)&mgmt->list[0]; - switch (tmp[DOT11_OUI_LEN]) { + switch (mgmt->list[0].type) { case RSN_AKM_NONE: wpa_auth = WPA_AUTH_NONE; break; @@ -4875,8 +5192,16 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("SSID is (%s) in Head \n", ssid.SSID)); ssid.SSID_len = ssid_ie->len; wldev_iovar_setint(dev, "mpc", 0); - wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); - wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); + if (err < 0) { + WL_ERR(("WLC_DOWN error %d\n", err)); + goto exit; + } + err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); + goto exit; + } if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { WL_ERR(("setting AP mode failed %d \n", err)); return err; @@ -4936,7 +5261,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, memcpy(beacon_ie, wps_ie, wpsie_len); wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, beacon_ie, wpsie_len); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } else { @@ -4989,12 +5314,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) { WL_DBG((" WPS IE is changed\n")); kfree(wl->ap_info->wps_ie); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } else if (wl->ap_info->wps_ie == NULL) { WL_DBG((" WPS IE is added\n")); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } @@ -5152,10 +5477,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR); wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; -#ifndef CUSTOMER_HW_SAMSUNG -#error 5ghz cause p2p connection error wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; -#endif wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wdev->wiphy->cipher_suites = __wl_cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); @@ -5202,8 +5524,8 @@ static void wl_free_wdev(struct wl_priv *wl) wl_delete_all_netinfo(wl); wiphy_free(wiphy); /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "wl", - * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! - */ + * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! + */ } static s32 wl_inform_bss(struct wl_priv *wl) @@ -5247,13 +5569,16 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) s32 signal; u32 freq; s32 err = 0; + gfp_t aflags; if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { WL_DBG(("Beacon is larger than buffer. Discarding\n")); return err; } + + aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) - - sizeof(u8) + WL_BSS_INFO_MAX, GFP_KERNEL); + - sizeof(u8) + WL_BSS_INFO_MAX, aflags); if (unlikely(!notif_bss_info)) { WL_ERR(("notif_bss_info alloc failed\n")); return -ENOMEM; @@ -5267,7 +5592,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) else band = wiphy->bands[IEEE80211_BAND_5GHZ]; - if (band == NULL) { + if(band==NULL) { kfree(notif_bss_info); return err; } @@ -5314,7 +5639,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) signal = notif_bss_info->rssi * 100; #if defined(WLP2P) && (ENABLE_P2P_INTERFACE) if (wl->p2p_net && wl->scan_request && - wl->scan_request->dev == wl->p2p_net) { + wl->scan_request->dev == wl->p2p_net) { #else if (p2p_is_on(wl) && p2p_scan(wl)) { #endif @@ -5427,11 +5752,18 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, struct station_info sinfo; #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE */ + /* if link down, bsscfg is disabled. */ + if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS && + wl_get_p2p_status(wl, IF_DELETING) && (ndev != wl_to_prmry_ndev(wl))) { + WL_INFO(("AP mode link down !! \n")); + complete(&wl->iface_disable); + return 0; + } #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE body=kzalloc(len, GFP_KERNEL); - WL_DBG(("Enter\n")); - if (body == NULL) { + WL_DBG(("Enter \n")); + if(body==NULL) { WL_ERR(("wl_notify_connect_status: Failed to allocate body\n")); return WL_INVALID; } @@ -5443,62 +5775,68 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, return WL_INVALID; } - memcpy(body, data, len); - wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", - NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync); - memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); - err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); - switch (event) { - case WLC_E_ASSOC_IND: - fc = FC_ASSOC_REQ; - break; - case WLC_E_REASSOC_IND: - fc = FC_REASSOC_REQ; - break; - case WLC_E_DISASSOC_IND: - fc = FC_DISASSOC; - break; - case WLC_E_DEAUTH_IND: - fc = FC_DISASSOC; - break; - case WLC_E_DEAUTH: - fc = FC_DISASSOC; - break; - default: - fc = 0; - goto exit; - } - if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) { - kfree(body); - return err; - } + memcpy(body, data, len); + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync); + memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); + err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + switch (event) { + case WLC_E_ASSOC_IND: + fc = FC_ASSOC_REQ; + break; + case WLC_E_REASSOC_IND: + fc = FC_REASSOC_REQ; + break; + case WLC_E_DISASSOC_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH: + fc = FC_DISASSOC; + break; + default: + fc = 0; + goto exit; + } + if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) { + kfree (body); + return err; + } - channel = dtoh32(ci.hw_channel); - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; + channel = dtoh32(ci.hw_channel); + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + + if(band == NULL) { + WL_ERR(("band is null(channel=%d)\n", channel)); + kfree(body); + return WL_INVALID; + } #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) - freq = ieee80211_channel_to_frequency(channel); - (void)band->band; + freq = ieee80211_channel_to_frequency(channel); + (void)band->band; #else - freq = ieee80211_channel_to_frequency(channel, band->band); + freq = ieee80211_channel_to_frequency(channel, band->band); #endif - err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, - &mgmt_frame, &len, body); - if (err < 0) - goto exit; - isfree = true; + err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, + &mgmt_frame, &len, body); + if (err < 0) + goto exit; + isfree = true; - if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); - } else if (event == WLC_E_DISASSOC_IND) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); - } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); - } + if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } else if (event == WLC_E_DISASSOC_IND) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } exit: if (isfree) @@ -5540,7 +5878,7 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, } else { WL_DBG(("wl_notify_connect_status : event %d status : %d \n", ntoh32(e->event_type), ntoh32(e->status))); -//chanyun TBD from DHD 15 no p2p firmware exist should change to interface + /* chanyun TBD from DHD 15 no p2p firmware exist should change to interface */ if (strstr(fw_path, "_p2p") == NULL && event == WLC_E_DEAUTH) { WL_DBG(("unexpected event WLC_E_DEAUTH\n")); return WL_INVALID; @@ -5569,6 +5907,18 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, if (wl->scan_request) { del_timer_sync(&wl->scan_timeout); if (wl->escan_on) { + WL_SCAN2(("link down notify escan complete: %p(%d)\n", + ndev, wl->escan_info.cur_sync_id)); +#ifndef CUSTOMER_HW_SAMSUNG +#error inform bss will be done at notify function + { + u8 temp_id = wl->escan_info.cur_sync_id; + wl->bss_list = + (wl_scan_results_t *) + wl->escan_info.escan_buf[(temp_id+1)%2]; + wl_inform_bss(wl); + } +#endif wl_notify_escan_complete(wl, ndev, true); } else wl_iscan_aborted(wl); @@ -5594,8 +5944,10 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, scbval.val = WLAN_REASON_DEAUTH_LEAVING; memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); scbval.val = htod32(scbval.val); - wldev_ioctl(ndev, WLC_DISASSOC, &scbval, + err =wldev_ioctl(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); + if (err < 0) + WL_ERR(("Check Assoc Status : %d\n", err)); cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); wl_link_down(wl); wl_init_prof(wl, ndev); @@ -5615,17 +5967,25 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, } wl_clr_drv_status(wl, DISCONNECTING, ndev); + /* if link down, bsscfg is diabled */ + if (ndev != wl_to_prmry_ndev(wl)) + complete(&wl->iface_disable); + } else if (wl_is_nonetwork(wl, e)) { printk("connect failed event=%d e->status 0x%x\n", event, (int)ntoh32(e->status)); /* Clean up any pending scan request */ + if (wl->scan_request) { del_timer_sync(&wl->scan_timeout); if (wl->escan_on) { + WL_SCAN2((" send noti due to connect fail : %p(%d)\n", + ndev, wl->escan_info.cur_sync_id)); wl_notify_escan_complete(wl, ndev, true); } else wl_iscan_aborted(wl); } + if (wl_get_drv_status(wl, CONNECTING, ndev)) wl_bss_connect_done(wl, ndev, e, data, false); } else { @@ -5895,11 +6255,24 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, WL_DBG(("copy bssid\n")); memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN); } - WL_DBG(("Connect done bssid=%02x:%02x:%02x:%02x:%02x:%02x\n", - curbssid[0], curbssid[1], curbssid[2], - curbssid[3], curbssid[4], curbssid[5])); + if (wl_get_drv_status(wl, CONNECTED, ndev)) { + if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) { + WL_ERR((" Connected event of connected device, ignore it\n")); + return err; + } + } + + + WL_SCAN2(("Connect done \n")); +#if defined(BCM4334_CHIP) + if (wl->scan_request) { + WL_SCAN2(("Abort scan : %p(%d)\n", ndev, wl->escan_info.cur_sync_id)); + wl_cfg80211_scan_abort(wl, ndev); + } +#endif #else if (wl->scan_request) { + WL_SCAN2(("Abort scan : %p(%d)\n", ndev, wl->escan_info.cur_sync_id)); wl_cfg80211_scan_abort(wl, ndev); } #endif /* ESCAN_RESULT_PATCH */ @@ -5926,7 +6299,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); if (completed) - WL_INFO(("Report connect result - connection succeeded(%d)\n", + WL_SCAN2(("Report connect result - connection succeeded(%d)\n", conn_info->resp_ie_len)); else WL_ERR(("Report connect result - connection failed\n")); @@ -6010,11 +6383,14 @@ scan_done_out: del_timer_sync(&wl->scan_timeout); spin_lock_irqsave(&wl->cfgdrv_lock, flags); if (wl->scan_request) { - WL_DBG(("cfg80211_scan_done\n")); cfg80211_scan_done(wl->scan_request, false); wl->scan_request = NULL; + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + WL_DBG(("cfg80211_scan_done\n")); + WL_SCAN2(("Remove Scan Request %p, %d\n", ndev, wl->escan_info.cur_sync_id)); + } else { + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); } - spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); mutex_unlock(&wl->usr_sync); return err; } @@ -6116,6 +6492,11 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, else band = wiphy->bands[IEEE80211_BAND_5GHZ]; + if(band == NULL) { + WL_ERR(("band is null(channel=%d)\n", channel)); + return WL_INVALID; + } + #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) freq = ieee80211_channel_to_frequency(channel); (void)band->band; @@ -6126,7 +6507,11 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr", NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync); - wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + if( err < 0) { + bzero (&bssid, ETHER_ADDR_LEN); + WL_ERR (("NO Connected BSSID set to zero\n")); + } memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, &mgmt_frame, &mgmt_frame_len, @@ -6211,11 +6596,12 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, if (wl_get_drv_status_all(wl, SENDING_ACT_FRM) && (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK))) { - /* do not wait more time for OFF_CHAN_COMPLETE !!! - * we already have the next frame!! - */ - WL_DBG(("*** Wake UP ** send_af_done_event ** \n")); - wake_up_interruptible(&wl->send_af_done_event); + WL_DBG(("*** Wake UP ** abort actframe ** \n")); + //wake_up_interruptible(&wl->send_af_done_event); + /* if channel is not zero, "actfame" uses off channel scan. + * So abort scan for off channel completion. */ + if (wl->af_sent_channel) + wl_cfg80211_scan_abort(wl, dev); } else if (wl_get_drv_status_all(wl, WAITING_MORE_TIME_NEXT_ACT_FRM)) { WL_DBG(("*** Wake UP ** wait_next_af ** \n")); complete(&wl->wait_next_af); @@ -6390,17 +6776,14 @@ static s32 wl_init_priv_mem(struct wl_priv *wl) #ifdef CONFIG_DHD_USE_STATIC_BUF wl->escan_info.escan_buf[0] = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN0, 0); bzero(wl->escan_info.escan_buf[0], ESCAN_BUF_SIZE); + wl->escan_info.escan_buf[1] = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN1, 0); + bzero(wl->escan_info.escan_buf[1], ESCAN_BUF_SIZE); #else wl->escan_info.escan_buf[0] = (void *)kzalloc(ESCAN_BUF_SIZE, GFP_KERNEL); if (unlikely(!wl->escan_info.escan_buf[0])) { WL_ERR(("wl->escan_info.escan_buf[0] alloc failed\n")); goto init_priv_mem_out; } -#endif -#ifdef CONFIG_DHD_USE_STATIC_BUF - wl->escan_info.escan_buf[1] = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN1, 0); - bzero(wl->escan_info.escan_buf[1], ESCAN_BUF_SIZE); -#else wl->escan_info.escan_buf[1] = (void *)kzalloc(ESCAN_BUF_SIZE, GFP_KERNEL); if (unlikely(!wl->escan_info.escan_buf[1])) { WL_ERR(("wl->escan_info.escan_buf[1] alloc failed\n")); @@ -6518,12 +6901,12 @@ static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted) return; } spin_lock_irqsave(&wl->cfgdrv_lock, flags); - wl_clr_drv_status(wl, SCANNING, ndev); if (likely(wl->scan_request)) { cfg80211_scan_done(wl->scan_request, aborted); wl->scan_request = NULL; } spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + wl_clr_drv_status(wl, SCANNING, ndev); wl->iscan_kickstart = false; } @@ -6666,13 +7049,28 @@ static s32 wl_iscan_thread(void *data) static void wl_scan_timeout(unsigned long data) { - struct wl_priv *wl = (struct wl_priv *)data; - + struct wl_priv *wl = (struct wl_priv *) data; + wl_event_msg_t msg; + wl_escan_result_t *escan_results; if (wl->scan_request) { WL_ERR(("timer expired\n")); - if (wl->escan_on) - wl_notify_escan_complete(wl, wl->escan_info.ndev, true); - else + if (wl->escan_on) { + msg.event_type = hton32(WLC_E_ESCAN_RESULT); + msg.status = hton32(WLC_E_STATUS_SUCCESS); + escan_results = kzalloc(sizeof(wl_escan_result_t), GFP_ATOMIC); + if (escan_results != NULL) { + msg.datalen = hton32(sizeof(wl_escan_result_t)); + escan_results->sync_id = htod16(wl->escan_info.cur_sync_id); + escan_results->bss_count =htod16(0); + escan_results->buflen = htod32(WL_ESCAN_RESULTS_FIXED_SIZE); + escan_results->version =htod32(WL_BSS_INFO_VERSION); + wl_cfg80211_event(wl->escan_info.ndev, &msg, escan_results); + kfree(escan_results); + } else { + wl_notify_escan_complete(wl, wl->escan_info.ndev, true); + } + + } else wl_notify_iscan_complete(wl_to_iscan(wl), true); } } @@ -6724,11 +7122,23 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, struct net_device *dev = ndev; struct wireless_dev *wdev = dev->ieee80211_ptr; struct wl_priv *wl = wlcfg_drv_priv; + int refcnt = 0; WL_DBG(("Enter \n")); if (!wdev || !wl || dev == wl_to_prmry_ndev(wl)) return NOTIFY_DONE; switch (state) { + case NETDEV_DOWN: + while(work_pending(&wdev->cleanup_work)) { + WL_ERR(("%s : [NETDEV_DOWN] work_pending (%d th)\n", + __FUNCTION__, refcnt)); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(100); + set_current_state(TASK_RUNNING); + refcnt++; + } + break; + case NETDEV_UNREGISTER: /* after calling list_del_rcu(&wdev->list) */ wl_dealloc_netinfo(wl, ndev); @@ -6741,6 +7151,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, * make the scan done forcibly. */ if (wl_get_drv_status(wl, SCANNING, dev)) { + WL_SCAN2(("Abort Scan and send result\n")); wl_cfg80211_scan_abort(wl, dev); if (wl->escan_on) { wl_notify_escan_complete(wl, dev, true); @@ -6760,19 +7171,36 @@ static void wl_notify_escan_complete(struct wl_priv *wl, unsigned long flags; WL_DBG(("Enter \n")); + if (wl->escan_info.ndev != ndev) + { + WL_SCAN2(("ndev is different %p %p\n", wl->escan_info.ndev, ndev)); return; - + } wl_clr_drv_status(wl, SCANNING, ndev); if (p2p_is_on(wl)) wl_clr_p2p_status(wl, SCANNING); + if(likely(wl->scan_request)) { + u8 temp_id = wl->escan_info.cur_sync_id; + if (aborted) + wl->bss_list = + (wl_scan_results_t *)wl->escan_info.escan_buf[(temp_id+1)%2]; + else + wl->bss_list = + (wl_scan_results_t *)wl->escan_info.escan_buf[(temp_id)%2]; + wl_inform_bss(wl); + } spin_lock_irqsave(&wl->cfgdrv_lock, flags); if (likely(wl->scan_request)) { cfg80211_scan_done(wl->scan_request, aborted); wl->scan_request = NULL; + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + } + else { + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + WL_SCAN2(("no scan request is existed\n")); } - spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); WL_DBG(("Exit \n")); } @@ -6832,13 +7260,15 @@ static s32 wl_escan_handler(struct wl_priv *wl, goto exit; } - if (escan_result->sync_id != wl->escan_info.cur_sync_id) + if (dtoh16(escan_result->sync_id) != wl->escan_info.cur_sync_id) { WL_ERR(("Escan sync id mismatch: status %d cur_sync_id %d coming_sync_id %d\n" - , status, wl->escan_info.cur_sync_id, escan_result->sync_id)); + , status, wl->escan_info.cur_sync_id, dtoh16(escan_result->sync_id))); + goto exit; + } if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { - WL_ERR(("Ignoring IBSS result\n")); + WL_DBG(("Ignoring IBSS result\n")); goto exit; } } @@ -6859,6 +7289,7 @@ static s32 wl_escan_handler(struct wl_priv *wl, } } else { + int cur_len = 0; list = (wl_scan_results_t *)wl->escan_info.escan_buf[wl->escan_info.cur_sync_id%2]; if (bi_length > ESCAN_BUF_SIZE - list->buflen) { WL_ERR(("Buffer is too small: ignoring\n")); @@ -6868,11 +7299,29 @@ static s32 wl_escan_handler(struct wl_priv *wl, for (i = 0; i < list->count; i++) { bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) : list->bss_info; - if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) && bi->SSID_len == bss->SSID_len && - !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { + !bcmp(bi->SSID, bss->SSID, bi->SSID_len) + && (bi->length == bss->length)) { + if (p2p_is_on(wl) && p2p_scan(wl)) { + if (bss->dtoh32(ie_length)< bi_length) { + int prev_len = dtoh32(bss->length); + WL_SCAN2(("bss info replacement is occured(bcast:%d->probresp%d)\n", + bss->ie_length, bi->ie_length)); + /* prev : broadcast, cur : prob_resp */ + if (list->count != 1 && i < list->count -1) { + /* memory copy required by this case only */ + memcpy((u8 *)bss, + (u8 *)bss + prev_len, list->buflen - cur_len - prev_len); + } + list->buflen -= prev_len; + memcpy(&(((u8 *)list)[list->buflen]), bi, bi_length); + list->version = dtoh32(bi->version); + list->buflen += bi_length; + goto exit; + } + } if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) { /* preserve max RSSI if the measurements are @@ -6890,6 +7339,7 @@ static s32 wl_escan_handler(struct wl_priv *wl, goto exit; } + cur_len += dtoh32(bss->length); } memcpy(&(wl->escan_info.escan_buf[wl->escan_info.cur_sync_id%2][list->buflen]), bi, bi_length); list->version = dtoh32(bi->version); @@ -6901,9 +7351,9 @@ static s32 wl_escan_handler(struct wl_priv *wl, } else if (status == WLC_E_STATUS_SUCCESS) { wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (escan_result->sync_id != wl->escan_info.cur_sync_id) + if (dtoh16(escan_result->sync_id) != wl->escan_info.cur_sync_id) WL_ERR(("Escan sync id mismatch: status %d cur_sync_id %d coming_sync_id %d\n" - , status, wl->escan_info.cur_sync_id, escan_result->sync_id)); + , status, wl->escan_info.cur_sync_id, dtoh16(escan_result->sync_id))); if (wl_get_drv_status_all(wl, SCANNING_PEER_CHANNEL)) { WL_INFO(("ACTION FRAME SCAN DONE\n")); wl_clr_p2p_status(wl, SCANNING); @@ -6913,9 +7363,12 @@ static s32 wl_escan_handler(struct wl_priv *wl, } else if (likely(wl->scan_request)) { mutex_lock(&wl->usr_sync); del_timer_sync(&wl->scan_timeout); - WL_INFO(("ESCAN COMPLETED\n")); + WL_SCAN2(("ESCAN COMPLETED\n")); +#ifndef CUSTOMER_HW_SAMSUNG +#error bss list is informed at notify function wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf[wl->escan_info.cur_sync_id%2]; wl_inform_bss(wl); +#endif wl_notify_escan_complete(wl, ndev, false); mutex_unlock(&wl->usr_sync); } @@ -6923,9 +7376,9 @@ static s32 wl_escan_handler(struct wl_priv *wl, } else if (status == WLC_E_STATUS_ABORT) { wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (escan_result->sync_id!=wl->escan_info.cur_sync_id) + if (dtoh16(escan_result->sync_id) !=wl->escan_info.cur_sync_id) WL_ERR(("Escan sync id mismatch: status %d cur_sync_id %d coming_sync_id %d\n" - , status, wl->escan_info.cur_sync_id, escan_result->sync_id)); + , status, wl->escan_info.cur_sync_id, dtoh16(escan_result->sync_id))); if (wl_get_drv_status_all(wl, SCANNING_PEER_CHANNEL)) { WL_INFO(("ACTION FRAME SCAN DONE\n")); wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); @@ -6935,9 +7388,12 @@ static s32 wl_escan_handler(struct wl_priv *wl, } else if (likely(wl->scan_request)) { mutex_lock(&wl->usr_sync); del_timer_sync(&wl->scan_timeout); - WL_INFO(("ESCAN ABORTED\n")); + WL_SCAN2(("ESCAN ABORTED\n")); +#ifndef CUSTOMER_HW_SAMSUNG +#error bss list is informed at notify function wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf[(wl->escan_info.cur_sync_id+1)%2]; wl_inform_bss(wl); +#endif wl_notify_escan_complete(wl, ndev, true); mutex_unlock(&wl->usr_sync); } @@ -6946,9 +7402,9 @@ static s32 wl_escan_handler(struct wl_priv *wl, else { WL_ERR(("unexpected Escan Event %d : abort\n", status)); wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (escan_result->sync_id!=wl->escan_info.cur_sync_id) + if (dtoh16(escan_result->sync_id) != wl->escan_info.cur_sync_id) WL_ERR(("Escan sync id mismatch: status %d cur_sync_id %d coming_sync_id %d\n" - , status, wl->escan_info.cur_sync_id, escan_result->sync_id)); + , status, wl->escan_info.cur_sync_id, dtoh16(escan_result->sync_id))); if (wl_get_drv_status_all(wl, SCANNING_PEER_CHANNEL)) { WL_INFO(("ACTION FRAME SCAN DONE\n")); wl_clr_p2p_status(wl, SCANNING); @@ -6958,8 +7414,11 @@ static s32 wl_escan_handler(struct wl_priv *wl, } else if (likely(wl->scan_request)) { mutex_lock(&wl->usr_sync); del_timer_sync(&wl->scan_timeout); +#ifndef CUSTOMER_HW_SAMSUNG +#error bss list is informed at notify function wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf[(wl->escan_info.cur_sync_id+1)%2]; wl_inform_bss(wl); +#endif wl_notify_escan_complete(wl, ndev, true); mutex_unlock(&wl->usr_sync); } @@ -6968,7 +7427,79 @@ static s32 wl_escan_handler(struct wl_priv *wl, exit: return err; } - +static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, enum wl_status state, bool set) +{ + s32 pm = PM_FAST; + s32 err = BCME_OK; + struct net_info *iter, *next; + if (set) { /* set */ + switch (state) { + case WL_STATUS_CONNECTED: { + if (wl_get_drv_status_all(wl, CONNECTED) > 1) { + wl->vsdb_mode = true; + pm = PM_OFF; + WL_INFO(("Do not enable the power save for VSDB mode\n")); + } else if (_net_info->pm_block) { + pm = PM_OFF; + } else { + pm = PM_FAST; + } + for_each_ndev(wl, iter, next) { + if (!wl->vsdb_mode && (iter->ndev != _net_info->ndev)) + continue; + if (wl_get_drv_status(wl, CONNECTED, iter->ndev) && + (wl_get_mode_by_netdev(wl, iter->ndev) == WL_MODE_BSS)) { + pm = htod32(pm); + WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled"))); + err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, sizeof(pm), true); + if (unlikely(err)) { + if (err == -ENODEV) + WL_DBG(("net_device is not ready yet\n")); + else + WL_ERR(("error (%d)\n", err)); + break; + } + } + } + break; + } + default: + break; + } + } else { /* clear */ + switch (state) { + case WL_STATUS_CONNECTED: { + if (wl_get_drv_status_all(wl, CONNECTED) == 1) { + wl->vsdb_mode = false; + for_each_ndev(wl, iter, next) { + if (wl_get_drv_status(wl, CONNECTED, iter->ndev) && + (wl_get_mode_by_netdev(wl, iter->ndev) == WL_MODE_BSS)) { + if (wl_get_netinfo_by_netdev(wl, iter->ndev)->pm_block) + pm = PM_OFF; + else + pm = PM_FAST; + pm = htod32(pm); + WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled"))); + err = wldev_ioctl(iter->ndev, WLC_SET_PM, + &pm, sizeof(pm), true); + if (unlikely(err)) { + if (err == -ENODEV) + WL_DBG(("net_device is not ready yet\n")); + else + WL_ERR(("error (%d)\n", err)); + break; + } + } + } + } + break; + } + default: + break; + } + } + return err; +} static s32 wl_init_scan(struct wl_priv *wl) { struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); @@ -7019,10 +7550,13 @@ static s32 wl_init_priv(struct wl_priv *wl) wl->rf_blocked = false; wl->first_remain = true; wl->wlfc_on = false; + /* register interested state */ + set_bit(WL_STATUS_CONNECTED, &wl->interrested_state); spin_lock_init(&wl->cfgdrv_lock); mutex_init(&wl->ioctl_buf_sync); init_waitqueue_head(&wl->netif_change_event); - init_waitqueue_head(&wl->send_af_done_event); + init_completion(&wl->send_af_done); + init_completion(&wl->iface_disable); wl_init_eq(wl); err = wl_init_priv_mem(wl); if (err) @@ -7168,7 +7702,8 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) ndev->ieee80211_ptr = wdev; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; - err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS); + wl->state_notifier = wl_notifier_change_state; + err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS, PM_ENABLE); if (err) { WL_ERR(("Failed to alloc net_info (%d)\n", err)); goto cfg80211_attach_out; @@ -7178,7 +7713,6 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) WL_ERR(("Failed to init iwm_priv (%d)\n", err)); goto cfg80211_attach_out; } - err = wl_setup_rfkill(wl, TRUE); if (err) { WL_ERR(("Failed to setup rfkill %d\n", err)); @@ -7227,8 +7761,10 @@ void wl_cfg80211_detach(void *para) wl_cfg80211_detach_p2p(); #endif wl_setup_rfkill(wl, FALSE); - if (wl->p2p_supported) - wl_cfgp2p_deinit_priv(wl); + if (wl->p2p_supported) { + WL_ERR(("wl_cfgp2p_down() is not called yet\n")); + wl_cfgp2p_down(wl); + } wl_deinit_priv(wl); wlcfg_drv_priv = NULL; wl_cfg80211_clear_parent_dev(); @@ -7293,12 +7829,13 @@ static s32 wl_event_handler(void *data) wl = (struct wl_priv *)tsk->parent; DAEMONIZE("dhd_cfg80211_event"); complete(&tsk->completed); + WL_ERR(("%s: tsk completed\n", __func__)); while ((ret = down_interruptible (&tsk->sema)) == 0) { WL_DBG(("down the event sema\n")); SMP_RD_BARRIER_DEPENDS(); if (tsk->terminated) { - WL_ERR(("%s was terminated[%d] ret=%d\n", + WL_DBG(("%s was terminated[%d] ret=%d\n", __func__, __LINE__, ret)); break; } @@ -7336,6 +7873,9 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) { u32 event_type = ntoh32(e->event_type); struct wl_priv *wl = wlcfg_drv_priv; +#if defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) + int pno_wakelock_timeout = 10; /* 10 second */ +#endif #if (WL_DBG_LEVEL > 0) s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? @@ -7344,7 +7884,12 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) #endif /* (WL_DBG_LEVEL > 0) */ if (event_type == WLC_E_PFN_NET_FOUND) - WL_ERR((" PNOEVENT: PNO_NET_FOUND\n")); + { +#if defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) + net_os_wake_lock_timeout_for_pno(ndev, pno_wakelock_timeout); +#endif + WL_ERR((" PNO Event\n")); + } else if (event_type == WLC_E_PFN_NET_LOST) WL_ERR((" PNOEVENT: PNO_NET_LOST\n")); @@ -7509,31 +8054,187 @@ eventmsg_out: } +static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) +{ + struct net_device *dev = wl_to_prmry_ndev(wl); + struct ieee80211_channel *band_chan_arr = NULL; + wl_uint32_list_t *list; + u32 i, j, index, n_2g, n_5g, band, channel, array_size; + u32 *n_cnt = NULL; + chanspec_t c = 0; + s32 err = BCME_OK; + bool update; + bool ht40_allowed; + u8 *pbuf = NULL; +#define LOCAL_BUF_LEN 1024 + pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL); + + if (pbuf == NULL) { + WL_ERR(("failed to allocate local buf\n")); + return -ENOMEM; + } + list = (wl_uint32_list_t *)(void *) pbuf; + list->count = htod32(WL_NUMCHANSPECS); + + + err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, + 0, pbuf, LOCAL_BUF_LEN, 0, &wl->ioctl_buf_sync); + if (err != 0) { + WL_ERR(("get chanspecs failed with %d\n", err)); + kfree(pbuf); + return err; + } +#undef LOCAL_BUF_LEN + list = (wl_uint32_list_t *)(void *)pbuf; + band = array_size = n_2g = n_5g = 0; + for (i = 0; i < dtoh32(list->count); i++) { + index = 0; + update = false; + ht40_allowed = false; + c = (chanspec_t)dtoh32(list->element[i]); + channel = CHSPEC_CHANNEL(c); + if (CHSPEC_IS40(c)) { + if (CHSPEC_SB_UPPER(c)) + channel += CH_10MHZ_APART; + else + channel -= CH_10MHZ_APART; + } + if (CHSPEC_IS2G(c) && channel <= CH_MAX_2G_CHANNEL) { + band_chan_arr = __wl_2ghz_channels; + array_size = ARRAYSIZE(__wl_2ghz_channels); + n_cnt = &n_2g; + band = IEEE80211_BAND_2GHZ; + ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false; + } else if (CHSPEC_IS5G(c) && channel > CH_MAX_2G_CHANNEL) { + band_chan_arr = __wl_5ghz_a_channels; + array_size = ARRAYSIZE(__wl_5ghz_a_channels); + n_cnt = &n_5g; + band = IEEE80211_BAND_5GHZ; + ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; + } + for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { + if (band_chan_arr[j].hw_value == channel) { + update = true; + break; + } + } + if (update) + index = j; + else + index = *n_cnt; + if (index < array_size) { + band_chan_arr[index].center_freq = + ieee80211_channel_to_frequency(channel, band); + band_chan_arr[index].hw_value = channel; + + if (CHSPEC_IS40(c) && ht40_allowed) { + /* assuming the order is HT20, HT40 Upper, HT40 lower from chanspecs */ + u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; + if (CHSPEC_SB_UPPER(c)) { + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; + band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; + } else { + /* It should be one of + IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS + */ + band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40MINUS; + } + } else { + band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; + if (band == IEEE80211_BAND_2GHZ) + channel |= WL_CHANSPEC_BAND_2G; + else + channel |= WL_CHANSPEC_BAND_5G; + err = wldev_iovar_getint(dev, "per_chan_info", &channel); + if (!err) { + if (channel & WL_CHAN_RADAR) + band_chan_arr[index].flags |= (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS); + if (channel & WL_CHAN_PASSIVE) + band_chan_arr[index].flags |= IEEE80211_CHAN_PASSIVE_SCAN; + } + } + if (!update) + (*n_cnt)++; + } + + } + __wl_band_2ghz.n_channels = n_2g; + __wl_band_5ghz_a.n_channels = n_5g; + kfree(pbuf); + return err; +} + s32 wl_update_wiphybands(struct wl_priv *wl) { struct wiphy *wiphy; + struct net_device *dev; u32 bandlist[3]; u32 nband = 0; u32 i = 0; s32 err = 0; + s32 index = 0; + s32 nmode = 0; + s32 bw_cap = 0; + if (wl == NULL) + wl = wlcfg_drv_priv; + dev = wl_to_prmry_ndev(wl); + + memset(bandlist, 0, sizeof(bandlist)); - err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist, + err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist, sizeof(bandlist), false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; } + err = wldev_iovar_getint(dev, "nmode", &nmode); + if (err) { + return err; + } + + err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); + if (err) { + return err; + } + + err = wl_construct_reginfo(wl, bw_cap); + if (err) { + WL_ERR(("wl_construct_reginfo() fails err=%d\n", err)); + return err; + } + wiphy = wl_to_wiphy(wl); nband = bandlist[0]; wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; - for (i = 1; i <= nband && i < sizeof(bandlist); i++) { - if (bandlist[i] == WLC_BAND_5G) + for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { + index = -1; + if (bandlist[i] == WLC_BAND_5G) { wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - else if (bandlist[i] == WLC_BAND_2G) + index = IEEE80211_BAND_5GHZ; + if (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G) + wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + } + else if (bandlist[i] == WLC_BAND_2G) { wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + index = IEEE80211_BAND_2GHZ; + if (bw_cap == WLC_N_BW_40ALL) + wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + + } + if ((index >= 0) && nmode) { + wiphy->bands[index]->ht_cap.cap |= + (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40); + wiphy->bands[index]->ht_cap.ht_supported = TRUE; + wiphy->bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + wiphy->bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + } + } wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); return err; @@ -7581,11 +8282,7 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); wl_term_iscan(wl); - spin_lock_irqsave(&wl->cfgdrv_lock, flags); - if (wl->scan_request) { - cfg80211_scan_done(wl->scan_request, true); - wl->scan_request = NULL; - } + for_each_ndev(wl, iter, next) { wl_clr_drv_status(wl, READY, iter->ndev); wl_clr_drv_status(wl, SCANNING, iter->ndev); @@ -7596,6 +8293,11 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) wl_clr_drv_status(wl, AP_CREATED, iter->ndev); wl_clr_drv_status(wl, AP_CREATING, iter->ndev); } + spin_lock_irqsave(&wl->cfgdrv_lock, flags); + if (wl->scan_request) { + cfg80211_scan_done(wl->scan_request, true); + wl->scan_request = NULL; + } wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); @@ -7615,6 +8317,7 @@ s32 wl_cfg80211_up(void *para) struct wl_priv *wl; s32 err = 0; int val = 1; + dhd_pub_t *dhd; (void)para; WL_TRACE(("In\n")); @@ -7635,7 +8338,10 @@ s32 wl_cfg80211_up(void *para) WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version)); mutex_lock(&wl->usr_sync); - wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); + dhd = (dhd_pub_t *)(wl->pub); + if ((dhd->op_mode & HOSTAPD_MASK) != HOSTAPD_MASK) { + wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); + } err = __wl_cfg80211_up(wl); if (err) WL_ERR(("__wl_cfg80211_up failed\n")); @@ -7741,11 +8447,14 @@ wl_update_prof(struct wl_priv *wl, struct net_device *ndev, profile->dtim_period = *(u8 *)data; break; default: - WL_ERR(("unsupported item (%d)\n", item)); err = -EOPNOTSUPP; break; } spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + + if (err == EOPNOTSUPP) + WL_ERR(("unsupported item (%d)\n", item)); + return err; } diff --git a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfg80211.h index 9880fea975c..503d3eb31e7 100644 --- a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfg80211.h @@ -52,6 +52,7 @@ struct wl_ibss; #define dtohchanspec(i) i #define WL_DBG_NONE 0 +#define WL_DBG_SCAN2 (1 <<5) #define WL_DBG_TRACE (1 << 4) #define WL_DBG_SCAN (1 << 3) #define WL_DBG_DBG (1 << 2) @@ -64,7 +65,7 @@ struct wl_ibss; #define WL_ERR(args) \ do { \ if (wl_dbg_level & WL_DBG_ERR) { \ - printk(KERN_ERR "CFG80211-ERROR) %s : ", __func__); \ + printk(KERN_ERR "CFG80211-INF02) %s : ", __func__); \ printk args; \ } \ } while (0) @@ -111,12 +112,23 @@ do { \ #endif /* (WL_DBG_LEVEL > 0) */ +#if (WL_DBG_LEVEL > 0) +#define WL_SCAN2(args) \ +do { \ + if (wl_dbg_level & WL_DBG_SCAN2) { \ + printk(KERN_ERR "CFG80211-SCAN) %s :", __func__); \ + printk args; \ + } \ +} while (0) +#else /* !(WL_DBG_LEVEL > 0) */ +#define WL_DBG(args) +#endif /* (WL_DBG_LEVEL > 0) */ + #define WL_SCAN_RETRY_MAX 3 #define WL_NUM_PMKIDS_MAX MAXPMKID #define WL_SCAN_BUF_MAX (1024 * 8) -/* customer want to large size IE, so increase ie length */ -#define WL_TLV_INFO_MAX 1500 -#define WL_SCAN_IE_LEN_MAX 2048 +#define WL_TLV_INFO_MAX 1500 /* customer want to large size IE, so increase ie length */ +#define WL_SCAN_IE_LEN_MAX 2048 #define WL_BSS_INFO_MAX 2048 #define WL_ASSOC_INFO_MAX 512 #define WL_IOCTL_LEN_MAX 1024 @@ -126,14 +138,15 @@ do { \ #define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1) #define WL_AP_MAX 256 #define WL_FILE_NAME_MAX 256 -#define WL_DWELL_TIME 200 -#define WL_MED_DWELL_TIME 400 -#define WL_LONG_DWELL_TIME 1000 -#define IFACE_MAX_CNT 2 +#define WL_DWELL_TIME 200 +#define WL_MED_DWELL_TIME 400 +#define WL_LONG_DWELL_TIME 1000 +#define IFACE_MAX_CNT 2 +#define WL_SCAN_CONNECT_DWELL_TIME_MS 100 #define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */ #define WL_CHANNEL_SYNC_RETRY 5 -#define WL_INVALID -1 +#define WL_INVALID -1 /* driver status */ enum wl_status { @@ -294,6 +307,7 @@ struct net_info { struct wl_profile profile; s32 mode; unsigned long sme_state; + bool pm_block; struct list_head list; /* list of all net_info structure */ }; typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl); @@ -399,6 +413,7 @@ struct afx_hdl { s32 my_listen_chan; /* my listen channel in GON Req frame */ bool is_listen; bool ack_recv; + bool is_active; }; /* private data of cfg80211 interface */ @@ -416,6 +431,7 @@ struct wl_priv { spinlock_t eq_lock; /* for event queue synchronization */ spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */ struct completion act_frm_scan; + struct completion iface_disable; #ifdef WL_CFG80211_SYNC_GON_TIME struct completion wait_next_af; #endif /* WL_CFG80211_SYNC_GON_TIME */ @@ -458,6 +474,7 @@ struct wl_priv { bool roam_on; /* on/off switch for self-roaming */ bool scan_tried; /* indicates if first scan attempted */ bool wlfc_on; + bool vsdb_mode; u8 *ioctl_buf; /* ioctl buffer */ struct mutex ioctl_buf_sync; u8 *escan_ioctl_buf; @@ -470,7 +487,7 @@ struct wl_priv { u64 send_action_id; u64 last_roc_id; wait_queue_head_t netif_change_event; - wait_queue_head_t send_af_done_event; + struct completion send_af_done; struct afx_hdl *afx_hdl; struct ap_info *ap_info; struct sta_info *sta_info; @@ -483,6 +500,8 @@ struct wl_priv { u8 block_gon_req_tx_count; u8 block_gon_req_rx_count; #endif /* WL_CFG80211_GON_COLLISION */ + s32 (*state_notifier) (struct wl_priv *wl, struct net_info *_net_info, enum wl_status state, bool set); + unsigned long interrested_state; }; @@ -493,7 +512,7 @@ static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct } static inline s32 wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev, - struct wireless_dev * wdev, s32 mode) + struct wireless_dev * wdev, s32 mode, bool pm_block) { struct net_info *_net_info; s32 err = 0; @@ -506,6 +525,7 @@ wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev, _net_info->mode = mode; _net_info->ndev = ndev; _net_info->wdev = wdev; + _net_info->pm_block = pm_block; wl->iface_cnt++; list_add(&_net_info->list, &wl->net_list); } @@ -542,7 +562,7 @@ wl_delete_all_netinfo(struct wl_priv *wl) } wl->iface_cnt = 0; } -static inline bool +static inline u32 wl_get_status_all(struct wl_priv *wl, s32 status) { @@ -553,23 +573,87 @@ wl_get_status_all(struct wl_priv *wl, s32 status) test_bit(status, &_net_info->sme_state)) cnt++; } - return cnt? true: false; + return cnt; +} + +static inline void +wl_set_status_all(struct wl_priv *wl, s32 status, u32 op) +{ + struct net_info *_net_info, *next; + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + switch (op) { + case 1: + return; /* set all status is not allowed */ + case 2: + clear_bit(status, &_net_info->sme_state); + if (wl->state_notifier && test_bit(status, &(wl->interrested_state))) + wl->state_notifier(wl, _net_info, status, false); + break; + case 4: + return; /* change all status is not allowed */ + default: + return; /*unknown operation */ + } + } +} +#define wl_set_status_by_netdev(wl, status, _ndev, op) \ +{ \ + struct net_info *_net_info, *next;\ + int found = 0;\ + list_for_each_entry_safe(_net_info, next, &(wl)->net_list, list) {\ + if(_ndev && ((_net_info->ndev) == _ndev)) { \ + found = 1;\ + switch(op){\ + case 1: \ + set_bit(status, &(_net_info->sme_state));\ + if (wl->state_notifier && test_bit(status, &(wl->interrested_state))) \ + wl->state_notifier(wl, _net_info, status, true); \ + if(status == WL_STATUS_SCANNING)\ + WL_SCAN2(("<<<Set SCANNING bit %p>>>\n", _ndev));\ + break;\ + case 2:\ + clear_bit(status, &(_net_info->sme_state)); \ + if (wl->state_notifier && test_bit(status, &(wl->interrested_state))) \ + wl->state_notifier(wl, _net_info, status, false); \ + if(status == WL_STATUS_SCANNING) \ + WL_SCAN2(("<<<Clear SCANNING bit %p>>>\n", _ndev)); \ + break;\ + case 4:\ + change_bit(status, &(_net_info->sme_state));\ + break;\ + }\ + }\ + }\ + if(found == 0)\ + WL_ERR(("<<<Set Status command with not eixst device %p>>>\n", _ndev));\ } + +#if 0 static inline void wl_set_status_by_netdev(struct wl_priv *wl, s32 status, struct net_device *ndev, u32 op) { struct net_info *_net_info, *next; + int found = 0; list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { if (ndev && (_net_info->ndev == ndev)) { + found = 1; switch (op) { case 1: set_bit(status, &_net_info->sme_state); +#if (WL_DBG_LEVEL > 0) + if(status == WL_STATUS_SCANNING ) + WL_SCAN2(("<<<Set SCANNING bit %p >>>\n", ndev)); +#endif break; case 2: clear_bit(status, &_net_info->sme_state); +#if (WL_DBG_LEVEL > 0) + if(status == WL_STATUS_SCANNING ) + WL_SCAN2(("<<<Clear SCANNING bit %p >>>\n", ndev)); +#endif break; case 4: change_bit(status, &_net_info->sme_state); @@ -578,9 +662,11 @@ wl_set_status_by_netdev(struct wl_priv *wl, s32 status, } } + if(found ==0 ) + WL_ERR(("<<Set Status command with not exist device %p>>\n", ndev)); } - +#endif static inline u32 wl_get_status_by_netdev(struct wl_priv *wl, s32 status, struct net_device *ndev) @@ -629,6 +715,17 @@ wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev) } return NULL; } +static inline struct net_info * +wl_get_netinfo_by_netdev(struct wl_priv *wl, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return _net_info; + } + return NULL; +} #define wl_to_wiphy(w) (w->wdev->wiphy) #define wl_to_prmry_ndev(w) (w->wdev->netdev) #define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) @@ -646,6 +743,8 @@ wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev) (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 1)) #define wl_clr_drv_status(wl, stat, ndev) \ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 2)) +#define wl_clr_drv_status_all(wl, stat) \ + (wl_set_status_all(wl, WL_STATUS_ ## stat, 2)) #define wl_chg_drv_status(wl, stat, ndev) \ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 4)) @@ -693,7 +792,7 @@ extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); extern s32 wl_mode_to_nl80211_iftype(s32 mode); int wl_cfg80211_do_driver_init(struct net_device *net); void wl_cfg80211_enable_trace(int level); - +extern s32 wl_update_wiphybands(struct wl_priv *wl); /* do scan abort */ extern s32 wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev); diff --git a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfgp2p.c index c9218bd84fd..e9d68548141 100644 --- a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfgp2p.c @@ -134,12 +134,12 @@ void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) wifi_p2p_pub_act_frame_t *pact_frm; wifi_p2p_action_frame_t *act_frm; wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; - if (!frame || frame_len <= 2) + if(!frame || frame_len <= 2) return; if (wl_cfgp2p_is_pub_action(frame, frame_len)) { pact_frm = (wifi_p2p_pub_act_frame_t *)frame; - switch (pact_frm->subtype) { + switch(pact_frm->subtype) { case P2P_PAF_GON_REQ: CFGP2P_ERR(("%s P2P Group Owner Negotiation Req Frame\n", (tx)? "TX": "RX")); @@ -208,7 +208,7 @@ void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) { sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; - switch (sd_act_frm->action) { + switch(sd_act_frm->action) { case P2PSD_ACTION_ID_GAS_IREQ: CFGP2P_ERR(("%s P2P GAS Initial Request\n", (tx)? "TX" : "RX")); @@ -307,13 +307,19 @@ wl_cfgp2p_set_firm_p2p(struct wl_priv *wl) wldev_iovar_getint(ndev, "apsta", &val); if (val == 0) { val = 1; - wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); + ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); + if (ret < 0) { + CFGP2P_ERR(("WLC_DOWN error %d\n", ret)); + return ret; + } wldev_iovar_setint(ndev, "apsta", val); - wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); + ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); + if (ret < 0) { + CFGP2P_ERR(("WLC_UP error %d\n", ret)); + return ret; + } } - val = 1; - /* Disable firmware roaming for P2P */ - wldev_iovar_setint(ndev, "roam_off", val); + /* In case of COB type, firmware has default mac address * After Initializing firmware, we have to set current mac address to * firmware for P2P device address @@ -339,7 +345,7 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, { wl_p2p_if_t ifreq; s32 err; - u32 scb_timeout = 10; + u32 scb_timeout=10; struct net_device *ndev = wl_to_prmry_ndev(wl); ifreq.type = if_type; @@ -366,6 +372,28 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, return err; } +/* Disable a P2P BSS. + * Parameters: + * @mac : MAC address of the BSS to create + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac) +{ + s32 ret; + struct net_device *netdev = wl_to_prmry_ndev(wl); + + CFGP2P_INFO(("------primary idx %d : wl p2p_ifdis %02x:%02x:%02x:%02x:%02x:%02x\n", + netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2], + mac->octet[3], mac->octet[4], mac->octet[5])); + ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac), + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); + if (unlikely(ret < 0)) { + printk("'wl p2p_ifdis' error %d\n", ret); + } + return ret; +} + /* Delete a P2P BSS. * Parameters: * @mac : MAC address of the BSS to create @@ -399,7 +427,7 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, { wl_p2p_if_t ifreq; s32 err; - u32 scb_timeout = 10; + u32 scb_timeout=10; struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); ifreq.type = if_type; @@ -408,9 +436,9 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, CFGP2P_INFO(("---wl p2p_ifchange %02x:%02x:%02x:%02x:%02x:%02x %s %u" " chanspec 0x%04x\n", - ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2], - ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5], - (if_type == WL_P2P_IF_GO) ? "go" : "client", + ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2], + ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5], + (if_type == WL_P2P_IF_GO) ? "go" : "client", (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT, ifreq.chspec)); @@ -449,7 +477,7 @@ wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index) sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY), NULL); if (ret == 0) { - memcpy(index, getbuf, sizeof(index)); + memcpy(index, getbuf, sizeof(s32)); CFGP2P_INFO(("---wl p2p_if ==> %d\n", *index)); } @@ -488,8 +516,7 @@ wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, s32 ret; struct net_device *dev; CFGP2P_DBG(("enter\n")); - - if (unlikely(bssidx >= P2PAPI_BSSCFG_MAX)) { + if (unlikely(bssidx == WL_INVALID || bssidx >= P2PAPI_BSSCFG_MAX)) { CFGP2P_ERR((" %d index out of range\n", bssidx)); return -1; } @@ -711,8 +738,8 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, #define P2PAPI_SCAN_DWELL_TIME_MS 80 #define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 #define P2PAPI_SCAN_HOME_TIME_MS 60 -#define P2PAPI_SCAN_NPROBS_TIME_MS 25 -#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS (P2PAPI_SCAN_NPROBS_TIME_MS + 5) +#define P2PAPI_SCAN_NPROBS_TIME_MS 30 +#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); //wl_set_p2p_status(wl, SCANNING); @@ -767,12 +794,15 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t)); eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); - if (wl_get_drv_status_all(wl, CONNECTED)) - eparams->params.active_time = htod32(-1); - else if (num_chans == SOCIAL_CHAN_CNT) + + if (num_chans == SOCIAL_CHAN_CNT) eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); else if (num_chans == AF_PEER_SEARCH_CNT) eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); + else if (num_chans == 1) + eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); + else if (wl_get_drv_status_all(wl, CONNECTED)) + eparams->params.active_time = -1; else eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); eparams->params.nprobes = htod32((eparams->params.active_time / @@ -819,7 +849,7 @@ wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, s32 ret = 0; u32 chan_cnt = 0; u16 *default_chan_list = NULL; - if (!p2p_is_on(wl)) + if (!p2p_is_on(wl) || ndev == NULL || bssidx == WL_INVALID) return -BCME_ERROR; CFGP2P_DBG((" Enter\n")); if (bssidx == P2PAPI_BSSCFG_PRIMARY) @@ -865,7 +895,7 @@ exit: #define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) /* Check whether the given IE looks like WFA WFDisplay IE. */ -#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ +#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ #define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD) @@ -984,7 +1014,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss ret = -ENOMEM; } else { if (mgmt_ie_buf != NULL) { - if (vndr_ie_len && (vndr_ie_len == *mgmt_ie_len) && + if (vndr_ie && vndr_ie_len && (vndr_ie_len == *mgmt_ie_len) && (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) { CFGP2P_INFO(("Previous mgmt IE is equals to current IE")); goto exit; @@ -1013,7 +1043,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss } *mgmt_ie_len = 0; /* Add if there is any extra IE */ - if (vndr_ie && vndr_ie_len) { + if (mgmt_ie_buf && vndr_ie && vndr_ie_len) { /* save the current IE in wl struct */ memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len); *mgmt_ie_len = vndr_ie_len; @@ -1038,6 +1068,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss pos += ie_len; } } + } #undef IE_TYPE #undef IE_TYPE_LEN @@ -1356,8 +1387,11 @@ wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) CFGP2P_DBG(("previous LISTEN is not completed yet\n")); goto exit; - } else + } +#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + else wl_clr_p2p_status(wl, LISTEN_EXPIRED); +#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); @@ -1367,14 +1401,17 @@ wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) * otherwise we will wait up to duration_ms + 100ms + duration / 20 */ if (ret == BCME_OK) { - extra_delay = EXTRA_DEAY_TIME + (duration_ms / 20); + extra_delay = EXTRA_DEAY_TIME + (duration_ms / 10); } else { /* if failed to set listen, it doesn't need to wait whole duration. */ - duration_ms = 50 + duration_ms / 20; + duration_ms = 100 + duration_ms / 20; extra_delay = 0; } INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay); +#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST + wl_clr_p2p_status(wl, LISTEN_EXPIRED); +#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ #undef EXTRA_DEAY_TIME exit: @@ -1437,7 +1474,7 @@ wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, "status : %d\n", status)); if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) - wake_up_interruptible(&wl->send_af_done_event); + complete(&wl->send_af_done); } return ret; } @@ -1481,9 +1518,7 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, goto exit; } - timeout = wait_event_interruptible_timeout(wl->send_af_done_event, - (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)), - msecs_to_jiffies(MAX_WAIT_TIME)); + timeout = wait_for_completion_timeout(&wl->send_af_done, msecs_to_jiffies(MAX_WAIT_TIME)); if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) { CFGP2P_INFO(("tx action frame operation is completed\n")); @@ -1492,6 +1527,10 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, ret = BCME_ERROR; CFGP2P_INFO(("tx action frame operation is failed\n")); } + /* clear status bit for action tx */ + wl_clr_p2p_status(wl, ACTION_TX_COMPLETED); + wl_clr_p2p_status(wl, ACTION_TX_NOACK); + exit: CFGP2P_INFO((" via act frame iovar : status = %d\n", ret)); #undef MAX_WAIT_TIME @@ -1654,6 +1693,9 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev) s32 wl_cfgp2p_down(struct wl_priv *wl) { + if (wl->p2p == NULL) + return 0; + if (timer_pending(&wl->p2p->listen_timer)) del_timer_sync(&wl->p2p->listen_timer); wl_cfgp2p_deinit_priv(wl); @@ -1831,11 +1873,11 @@ wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) return 0; } - ie = (wifi_p2p_ie_t*) buf; + ie = (wifi_p2p_ie_t *) buf; len = ie->len; /* Point subel to the P2P IE's subelt field. - * Subtract the preceding fields (id, len, OUI, oui_type) from the length. + * Subtract the preceding fields (id,len,OUI,oui_type) from the length. */ subel = ie->subelts; len -= 4; /* exclude OUI + OUI_TYPE */ @@ -1872,7 +1914,7 @@ wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) u8 * wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) { - wifi_p2p_ie_t * p2p_ie = NULL; + wifi_p2p_ie_t *p2p_ie = NULL; u8 *capability = NULL; bool p2p_go = 0; u8 *ptr = NULL; diff --git a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfgp2p.h index 182b0b2ecf1..bd4d388255f 100644 --- a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_cfgp2p.h @@ -123,7 +123,7 @@ enum wl_cfgp2p_status { #define CFGP2P_ERR(args) \ do { \ if (wl_dbg_level & WL_DBG_ERR) { \ - printk(KERN_ERR "CFGP2P-ERROR) %s : ", __func__); \ + printk(KERN_ERR "CFGP2P-INF02) %s : ", __func__); \ printk args; \ } \ } while (0) @@ -172,6 +172,8 @@ extern s32 wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, chanspec_t chspec); extern s32 +wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac); +extern s32 wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac); extern s32 wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, chanspec_t chspec); @@ -279,7 +281,7 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl); #define SOCIAL_CHAN_2 6 #define SOCIAL_CHAN_3 11 #define SOCIAL_CHAN_CNT 3 -#define AF_PEER_SEARCH_CNT (SOCIAL_CHAN_CNT + 1) +#define AF_PEER_SEARCH_CNT 2 #define WL_P2P_WILDCARD_SSID "DIRECT-" #define WL_P2P_WILDCARD_SSID_LEN 7 #define WL_P2P_INTERFACE_PREFIX "p2p" @@ -298,5 +300,5 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl); (subtype == P2P_PAF_INVITE_RSP) || \ (subtype == P2P_PAF_PROVDIS_RSP))) #define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) -#define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0) +#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && (len == WL_P2P_WILDCARD_SSID_LEN)) #endif /* _wl_cfgp2p_h_ */ diff --git a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_linux_mon.c b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_linux_mon.c index dcdd83d9a00..8a29599ffc6 100644 --- a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_linux_mon.c +++ b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_linux_mon.c @@ -59,8 +59,15 @@ int dhd_monitor_uninit(void); #ifndef DHD_MAX_IFS #define DHD_MAX_IFS 16 #endif -#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__) -#define MON_TRACE MON_PRINT + +#define MON_DEBUG 0 +#if MON_DEBUG + #define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__) + #define MON_TRACE MON_PRINT +#else + #define MON_PRINT(format, ...) + #define MON_TRACE MON_PRINT +#endif typedef struct monitor_interface { int radiotap_enabled; diff --git a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_roam.c b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_roam.c index 9829b8f7fc4..5b77c5c94bd 100644 --- a/drivers/net/wireless/bcmdhd/src/wl/sys/wl_roam.c +++ b/drivers/net/wireless/bcmdhd/src/wl/sys/wl_roam.c @@ -2,13 +2,13 @@ * Linux Wireless Extensions support * * Copyright (C) 1999-2012, 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. @@ -31,7 +31,6 @@ #define WL_DBG(x) #define MAX_ROAM_CACHE 100 -#define WL_CHANSPEC_CTL_SB_NONE 0x0300 /*chanyun temp : fix chan spec*/ typedef struct { chanspec_t chanspec; @@ -40,8 +39,14 @@ typedef struct { } roam_channel_cache; static int n_roam_cache = 0; +static int roam_band = WLC_BAND_AUTO; static roam_channel_cache roam_cache[MAX_ROAM_CACHE]; +void set_roam_band(int band) +{ + roam_band = band; +} + void reset_roam_cache(void) { n_roam_cache = 0; @@ -55,10 +60,10 @@ void add_roam_cache(wl_bss_info_t *bi) if (n_roam_cache == MAX_ROAM_CACHE) return; - for(i=0; i<n_roam_cache; i++) { + for (i = 0; i < n_roam_cache; i++) { if ((roam_cache[i].ssid_len == bi->SSID_len) && - (roam_cache[i].chanspec == bi->chanspec) && - (memcmp(roam_cache[i].ssid, bi->SSID, bi->SSID_len) == 0)) { + (roam_cache[i].chanspec == bi->chanspec) && + (memcmp(roam_cache[i].ssid, bi->SSID, bi->SSID_len) == 0)) { /* identical one found, just return */ return; } @@ -74,7 +79,7 @@ void add_roam_cache(wl_bss_info_t *bi) int get_roam_channel_list(int target_chan, chanspec_t *channels, const wlc_ssid_t *ssid) { - int i, n=1; + int i, n = 1; uint band; WL_DBG((" %s: %02d\n", __FUNCTION__, target_chan)); @@ -86,17 +91,18 @@ int get_roam_channel_list(int target_chan, chanspec_t *channels, const wlc_ssid_ *channels++ = (target_chan & WL_CHANSPEC_CHAN_MASK) | band | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; for(i=0; i<n_roam_cache; i++) { + chanspec_t ch = roam_cache[i].chanspec; if ((roam_cache[i].ssid_len == ssid->SSID_len) && - ((roam_cache[i].chanspec & WL_CHANSPEC_CHAN_MASK) != target_chan) && + ((ch & WL_CHANSPEC_CHAN_MASK) != target_chan) && + ((roam_band == WLC_BAND_AUTO) || ((roam_band == WLC_BAND_2G) && CHSPEC_IS2G(ch)) || ((roam_band == WLC_BAND_5G) && CHSPEC_IS5G(ch))) && (memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) { /* match found, add it */ - *channels = roam_cache[i].chanspec & WL_CHANSPEC_CHAN_MASK; - WL_DBG((" %s: %02d\n", __FUNCTION__, *channels)); + *channels = ch & WL_CHANSPEC_CHAN_MASK; if (*channels <= 14) *channels |= WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; else *channels |= WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; - + WL_DBG((" %s: %02d 0x%04X\n", __FUNCTION__, ch & WL_CHANSPEC_CHAN_MASK, *channels)); channels++; n++; } } @@ -111,7 +117,7 @@ void print_roam_cache(void) WL_DBG((" %d cache\n", n_roam_cache)); - for(i=0; i<n_roam_cache; i++) { + for (i = 0; i < n_roam_cache; i++) { roam_cache[i].ssid[roam_cache[i].ssid_len] = 0; WL_DBG(("0x%02X %02d %s\n", roam_cache[i].chanspec, roam_cache[i].ssid_len, roam_cache[i].ssid)); } diff --git a/drivers/net/wireless/bcmdhd/src/wl/sys/wldev_common.c b/drivers/net/wireless/bcmdhd/src/wl/sys/wldev_common.c index f46c061332b..d19d64d7840 100644 --- a/drivers/net/wireless/bcmdhd/src/wl/sys/wldev_common.c +++ b/drivers/net/wireless/bcmdhd/src/wl/sys/wldev_common.c @@ -220,7 +220,14 @@ s32 wldev_iovar_setbuf_bsscfg( mutex_lock(buf_sync); } iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); - ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + if (iovar_len > 0) + ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + else { + if (buf_sync) { + mutex_unlock(buf_sync); + } + return BCME_BUFTOOSHORT; + } if (buf_sync) { mutex_unlock(buf_sync); } diff --git a/drivers/net/wireless/bcmdhd/src/wl/sys/wldev_common.h b/drivers/net/wireless/bcmdhd/src/wl/sys/wldev_common.h index c383aab9f91..6f7f1d6f078 100644 --- a/drivers/net/wireless/bcmdhd/src/wl/sys/wldev_common.h +++ b/drivers/net/wireless/bcmdhd/src/wl/sys/wldev_common.h @@ -95,6 +95,9 @@ extern int net_os_set_suspend_disable(struct net_device *dev, int val); extern int net_os_set_suspend(struct net_device *dev, int val); extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left); +#if defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) +int net_os_wake_lock_timeout_for_pno(struct net_device *dev, int sec); +#endif /* Get the link speed from dongle, speed is in kpbs */ int wldev_get_link_speed(struct net_device *dev, int *plink_speed); |