From a378ad648a4da8dc9461d748fc820e748287ec59 Mon Sep 17 00:00:00 2001 From: lbt Date: Mon, 14 Feb 2011 11:29:57 +0800 Subject: [PATCH] wifi:bcm4329: update to 4.218.248.20 --- drivers/net/wireless/bcm4329/Kconfig | 2 +- drivers/net/wireless/bcm4329/Makefile | 5 +- drivers/net/wireless/bcm4329/bcmsdh_linux.c | 17 +- drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c | 1 - .../net/wireless/bcm4329/bcmsdh_sdmmc_linux.c | 10 +- drivers/net/wireless/bcm4329/dhd.h | 13 +- drivers/net/wireless/bcm4329/dhd_bus.h | 4 +- drivers/net/wireless/bcm4329/dhd_common.c | 156 ++- drivers/net/wireless/bcm4329/dhd_dbg.h | 4 +- drivers/net/wireless/bcm4329/dhd_linux.c | 278 +++-- drivers/net/wireless/bcm4329/dhd_sdio.c | 154 +-- .../net/wireless/bcm4329/include/epivers.h | 10 +- .../wireless/bcm4329/include/proto/bcmevent.h | 11 +- .../net/wireless/bcm4329/include/wlioctl.h | 3 +- drivers/net/wireless/bcm4329/wl_iw.c | 1022 ++++++++++++----- drivers/net/wireless/bcm4329/wl_iw.h | 36 +- 16 files changed, 1172 insertions(+), 554 deletions(-) diff --git a/drivers/net/wireless/bcm4329/Kconfig b/drivers/net/wireless/bcm4329/Kconfig index aa4355a6225e..ca5760d32385 100644 --- a/drivers/net/wireless/bcm4329/Kconfig +++ b/drivers/net/wireless/bcm4329/Kconfig @@ -22,6 +22,6 @@ config BCM4329_FW_PATH config BCM4329_NVRAM_PATH depends on BCM4329 string "NVRAM path" - default "/system/etc/firmware/nvram_B23.txt" + default "/proc/calibration" ---help--- Path to the calibration file. diff --git a/drivers/net/wireless/bcm4329/Makefile b/drivers/net/wireless/bcm4329/Makefile index 3f3b0b0f21b9..6391138c765a 100755 --- a/drivers/net/wireless/bcm4329/Makefile +++ b/drivers/net/wireless/bcm4329/Makefile @@ -6,10 +6,11 @@ DHDCFLAGS = -DLINUX -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD -DBCMWPA2 \ -Wall -Wstrict-prototypes -Werror -DCUSTOMER_HW2 \ -DDHD_DEBUG_TRAP -DSOFTAP \ -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT \ - -DGET_CUSTOM_MAC_ENABLE -DSET_RANDOM_MAC_SOFTAP \ + -DGET_CUSTOM_MAC_ENABLE -DSET_RANDOM_MAC_SOFTAP \ + -DKEEP_ALIVE \ -Idrivers/net/wireless/bcm4329 -Idrivers/net/wireless/bcm4329/include -#options defines dependent on platform board and applicantion requirements: +#options defines dependent on platform board and applicantion requirements: #-DOOB_INTR_ONLY -DDHD_USE_STATIC_BUF -DMMC_SDIO_ABORT -DHW_OOB -DCSCAN DHDOFILES = dhd_linux.o linux_osl.o bcmutils.o dhd_common.o dhd_custom_gpio.o \ diff --git a/drivers/net/wireless/bcm4329/bcmsdh_linux.c b/drivers/net/wireless/bcm4329/bcmsdh_linux.c index 559f4819b1b6..1e33555b0531 100644 --- a/drivers/net/wireless/bcm4329/bcmsdh_linux.c +++ b/drivers/net/wireless/bcm4329/bcmsdh_linux.c @@ -301,7 +301,7 @@ int bcmsdh_remove(struct device *dev) MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); osl_detach(osh); -#if !defined(BCMLXSDMMC) +#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) dev_set_drvdata(dev, NULL); #endif /* !defined(BCMLXSDMMC) */ @@ -581,8 +581,6 @@ bcmsdh_unregister(void) #endif /* BCMPLATFORM_BUS */ } - - #if defined(OOB_INTR_ONLY) void bcmsdh_oob_intr_set(bool enable) { @@ -624,6 +622,9 @@ int bcmsdh_register_oob_intr(void * dhdp) SDLX_MSG(("%s Enter\n", __FUNCTION__)); +/* Example of HW_OOB for HW2: please refer to your host specifiction */ +/* sdhcinfo->oob_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; */ + dev_set_drvdata(sdhcinfo->dev, dhdp); if (!sdhcinfo->oob_irq_registered) { @@ -646,10 +647,12 @@ void bcmsdh_unregister_oob_intr(void) { SDLX_MSG(("%s: Enter\n", __FUNCTION__)); - set_irq_wake(sdhcinfo->oob_irq, 0); - disable_irq(sdhcinfo->oob_irq); /* just in case.. */ - free_irq(sdhcinfo->oob_irq, NULL); - sdhcinfo->oob_irq_registered = FALSE; + if (sdhcinfo->oob_irq_registered) { + set_irq_wake(sdhcinfo->oob_irq, 0); + disable_irq(sdhcinfo->oob_irq); /* just in case.. */ + free_irq(sdhcinfo->oob_irq, NULL); + sdhcinfo->oob_irq_registered = FALSE; + } } #endif /* defined(OOB_INTR_ONLY) */ /* Module parameters specific to each host-controller driver */ diff --git a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c index bda919390587..031367b8f18f 100644 --- a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c @@ -675,7 +675,6 @@ sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) data = 3; /* enable hw oob interrupt */ else data = 4; /* disable hw oob interrupt */ - data |= 4; /* Active HIGH */ status = sdioh_request_byte(sd, SDIOH_WRITE, 0, 0xf2, &data); diff --git a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c index 8992a4267f9f..5a1a46c93571 100644 --- a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c @@ -82,7 +82,6 @@ PBCMSDH_SDMMC_INSTANCE gInstance; extern int bcmsdh_probe(struct device *dev); extern int bcmsdh_remove(struct device *dev); -struct device sdmmc_dev; static int bcmsdh_sdmmc_probe(struct sdio_func *func, const struct sdio_device_id *id) @@ -102,7 +101,7 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, if(func->device == 0x4) { /* 4318 */ gInstance->func[2] = NULL; sd_trace(("NIC found, calling bcmsdh_probe...\n")); - ret = bcmsdh_probe(&sdmmc_dev); + ret = bcmsdh_probe(&func->dev); } } @@ -110,7 +109,7 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, if (func->num == 2) { sd_trace(("F2 found, calling bcmsdh_probe...\n")); - ret = bcmsdh_probe(&sdmmc_dev); + ret = bcmsdh_probe(&func->dev); } return ret; @@ -126,7 +125,7 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func) if (func->num == 2) { sd_trace(("F2 found, calling bcmsdh_remove...\n")); - bcmsdh_remove(&sdmmc_dev); + bcmsdh_remove(&func->dev); } } @@ -250,10 +249,8 @@ int sdio_function_init(void) if (!gInstance) return -ENOMEM; - bzero(&sdmmc_dev, sizeof(sdmmc_dev)); error = sdio_register_driver(&bcmsdh_sdmmc_driver); - return error; } @@ -265,7 +262,6 @@ void sdio_function_cleanup(void) { sd_trace(("%s Enter\n", __FUNCTION__)); - sdio_unregister_driver(&bcmsdh_sdmmc_driver); if (gInstance) diff --git a/drivers/net/wireless/bcm4329/dhd.h b/drivers/net/wireless/bcm4329/dhd.h index 5d8dc32fd304..1ddf1ff61e70 100644 --- a/drivers/net/wireless/bcm4329/dhd.h +++ b/drivers/net/wireless/bcm4329/dhd.h @@ -24,7 +24,7 @@ * 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.h,v 1.32.4.7.2.4.14.49 2010/08/20 17:32:48 Exp $ + * $Id: dhd.h,v 1.32.4.7.2.4.14.49.4.7 2010/11/12 22:48:36 Exp $ */ /**************** @@ -86,9 +86,11 @@ enum dhd_bus_wake_state { WAKE_LOCK_TMOUT, WAKE_LOCK_WATCHDOG, WAKE_LOCK_LINK_DOWN_TMOUT, + WAKE_LOCK_PNO_FIND_TMOUT, WAKE_LOCK_SOFTAP_SET, WAKE_LOCK_SOFTAP_STOP, WAKE_LOCK_SOFTAP_START, + WAKE_LOCK_SOFTAP_THREAD, WAKE_LOCK_MAX }; enum dhd_prealloc_index { @@ -220,6 +222,8 @@ extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub); extern void dhd_os_start_lock(dhd_pub_t *pub); extern void dhd_os_start_unlock(dhd_pub_t *pub); +extern unsigned long dhd_os_spin_lock(dhd_pub_t *pub); +extern void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); typedef struct dhd_if_event { uint8 ifidx; @@ -348,8 +352,11 @@ typedef enum cust_gpio_modes { WLAN_POWER_ON, WLAN_POWER_OFF } cust_gpio_modes_t; + extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); +extern int net_os_send_hang_message(struct net_device *dev); + /* * Insmod parameters for debug/test */ @@ -399,6 +406,10 @@ extern uint dhd_sdiod_drive_strength; /* Override to force tx queueing all the time */ extern uint dhd_force_tx_queueing; +/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ +#define KEEP_ALIVE_PERIOD 55000 +#define NULL_PKT_STR "null_pkt" + #ifdef SDTEST /* Echo packet generator (SDIO), pkts/s */ extern uint dhd_pktgen; diff --git a/drivers/net/wireless/bcm4329/dhd_bus.h b/drivers/net/wireless/bcm4329/dhd_bus.h index 9e29fb955444..97af41b313d0 100644 --- a/drivers/net/wireless/bcm4329/dhd_bus.h +++ b/drivers/net/wireless/bcm4329/dhd_bus.h @@ -24,7 +24,7 @@ * 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_bus.h,v 1.4.6.3.2.3.6.6 2010/05/17 18:18:13 Exp $ + * $Id: dhd_bus.h,v 1.4.6.3.2.3.6.7 2010/08/13 01:35:24 Exp $ */ #ifndef _dhd_bus_h_ @@ -63,7 +63,7 @@ extern bool dhd_bus_watchdog(dhd_pub_t *dhd); #ifdef DHD_DEBUG /* Device console input function */ extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); -#endif +#endif /* DHD_DEBUG */ /* Deferred processing for the bus, return TRUE requests reschedule */ extern bool dhd_bus_dpc(struct dhd_bus *bus); diff --git a/drivers/net/wireless/bcm4329/dhd_common.c b/drivers/net/wireless/bcm4329/dhd_common.c index dab1ca42b338..df7adbef6941 100644 --- a/drivers/net/wireless/bcm4329/dhd_common.c +++ b/drivers/net/wireless/bcm4329/dhd_common.c @@ -21,7 +21,7 @@ * 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_common.c,v 1.5.6.8.2.6.6.69.4.3 2010/09/10 21:30:16 Exp $ + * $Id: dhd_common.c,v 1.5.6.8.2.6.6.69.4.20 2010/12/20 23:37:28 Exp $ */ #include #include @@ -74,6 +74,13 @@ extern int dhd_wl_ioctl(dhd_pub_t *dhd, uint cmd, char *buf, uint buflen); void dhd_iscan_lock(void); void dhd_iscan_unlock(void); +#if defined(SOFTAP) +extern bool ap_fw_loaded; +#endif +#if defined(KEEP_ALIVE) +int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on); +#endif /* KEEP_ALIVE */ + /* Packet alignment for most efficient SDIO (can change based on platform) */ #ifndef DHD_SDALIGN #define DHD_SDALIGN 32 @@ -140,7 +147,7 @@ dhd_common_init(void) * behaviour since the value of the globals may be different on the * first time that the driver is initialized vs subsequent initializations. */ - dhd_msg_level = DHD_ERROR_VAL |DHD_TRACE_VAL|DHD_INFO_VAL; + dhd_msg_level = DHD_ERROR_VAL; #ifdef CONFIG_BCM4329_FW_PATH strncpy(fw_path, CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN-1); #else @@ -1225,11 +1232,15 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint power_mode = PM_FAST; uint32 dongle_align = DHD_SDALIGN; uint32 glom = 0; - uint bcn_timeout = 3; + uint bcn_timeout = 4; int scan_assoc_time = 40; int scan_unassoc_time = 40; + uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ +#if defined(SOFTAP) + uint dtim = 1; +#endif + int ret = 0; #ifdef GET_CUSTOM_MAC_ENABLE - int ret; struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ @@ -1256,7 +1267,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef SET_RANDOM_MAC_SOFTAP if (strstr(fw_path, "apsta") != NULL) { uint rand_mac; - int ret; srandom32((uint)jiffies); rand_mac = random32(); @@ -1287,6 +1297,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } } + /* Set Listen Interval */ + bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) + DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); + /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); ptr = buf; @@ -1315,6 +1330,12 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("roam_off", (char *)&dhd_roam, 4, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); +#if defined(SOFTAP) + if (ap_fw_loaded == TRUE) { + dhdcdc_set_ioctl(dhd, 0, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim)); + } +#endif + if (dhd_roam == 0) { /* set internal roaming roaming parameters */ @@ -1395,6 +1416,19 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #endif /* PKT_FILTER_SUPPORT */ +#if defined(KEEP_ALIVE) + { + /* Set Keep Alive : be sure to use FW with -keepalive */ + int res; + + if (ap_fw_loaded == FALSE) { + if ((res = dhd_keep_alive_onoff(dhd, 1)) < 0) + DHD_ERROR(("%s set keeplive failed %d\n", \ + __FUNCTION__, res)); + } + } +#endif + dhd_os_proto_unblock(dhd); return 0; @@ -1449,7 +1483,7 @@ dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete) dhd_pub_t *dhd = dhd_bus_pub(dhdp); dhd_iscan_lock(); - /* If iscan_delete is null then delete the entire + /* If iscan_delete is null then delete the entire * chain or else delete specific one provided */ if (!iscan_delete) { @@ -1780,7 +1814,58 @@ fail: return status; } -#endif +#endif + +/* Function to estimate possible DTIM_SKIP value */ +int dhd_get_dtim_skip(dhd_pub_t *dhd) +{ + int bcn_li_dtim; + char buf[128]; + int ret; + int dtim_assoc = 0; + + if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1)) + bcn_li_dtim = 3; + else + bcn_li_dtim = dhd->dtim_skip; + + /* Read DTIM value if associated */ + memset(buf, 0, sizeof(buf)); + bcm_mkiovar("dtim_assoc", 0, 0, buf, sizeof(buf)); + if ((ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf))) < 0) { + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); + bcn_li_dtim = 1; + goto exit; + } + else + dtim_assoc = dtoh32(*(int *)buf); + + DHD_ERROR(("%s bcn_li_dtim=%d DTIM=%d Listen=%d\n", \ + __FUNCTION__, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL)); + + /* if not assocated just eixt */ + if (dtim_assoc == 0) { + goto exit; + } + + /* check if sta listen interval fits into AP dtim */ + if (dtim_assoc > LISTEN_INTERVAL) { + /* AP DTIM to big for our Listen Interval : no dtim skiping */ + bcn_li_dtim = 1; + DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", \ + __FUNCTION__, dtim_assoc, LISTEN_INTERVAL)); + goto exit; + } + + if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) { + /* Round up dtim_skip to fit into STAs Listen Interval */ + bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc); + DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); + } + +exit: + return bcn_li_dtim; +} #ifdef PNO_SUPPORT int dhd_pno_clean(dhd_pub_t *dhd) @@ -1888,6 +1973,11 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr) if (scan_fr != 0) pfn_param.scan_freq = htod32(scan_fr); + if (pfn_param.scan_freq > PNO_SCAN_MAX_FW) { + DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW)); + return err; + } + bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); @@ -1912,6 +2002,9 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr) __FUNCTION__, i, err)); return err; } + else + DHD_ERROR(("%s set OK with PNO time=%d\n", __FUNCTION__, \ + pfn_param.scan_freq)); } else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err)); } @@ -1933,6 +2026,53 @@ int dhd_pno_get_status(dhd_pub_t *dhd) #endif /* PNO_SUPPORT */ +#if defined(KEEP_ALIVE) +int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on) +{ + char buf[256]; + char *buf_ptr = buf; + wl_keep_alive_pkt_t keep_alive_pkt; + char * str; + int str_len, buf_len; + int res = 0; + int keep_alive_period = KEEP_ALIVE_PERIOD; /* in ms */ + + DHD_TRACE(("%s: ka:%d\n", __FUNCTION__, ka_on)); + + if (ka_on) { /* on suspend */ + keep_alive_pkt.period_msec = keep_alive_period; + + } else { + /* on resume, turn off keep_alive packets */ + keep_alive_pkt.period_msec = 0; + } + + /* IOC var name */ + str = "keep_alive"; + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[str_len] = '\0'; + buf_len = str_len + 1; + + /* set ptr to IOCTL payload after the var name */ + buf_ptr += buf_len; /* include term Z */ + + /* copy Keep-alive attributes from local var keep_alive_pkt */ + str = NULL_PKT_STR; + keep_alive_pkt.len_bytes = strlen(str); + + memcpy(buf_ptr, &keep_alive_pkt, WL_KEEP_ALIVE_FIXED_LEN); + buf_ptr += WL_KEEP_ALIVE_FIXED_LEN; + + /* copy packet data */ + memcpy(buf_ptr, str, keep_alive_pkt.len_bytes); + buf_len += (WL_KEEP_ALIVE_FIXED_LEN + keep_alive_pkt.len_bytes); + + res = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len); + return res; +} +#endif /* defined(KEEP_ALIVE) */ + #if defined(CSCAN) /* Androd ComboSCAN support */ @@ -2183,4 +2323,4 @@ wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) return num; } -#endif +#endif diff --git a/drivers/net/wireless/bcm4329/dhd_dbg.h b/drivers/net/wireless/bcm4329/dhd_dbg.h index 9bbd289ce496..b48c1d70f144 100644 --- a/drivers/net/wireless/bcm4329/dhd_dbg.h +++ b/drivers/net/wireless/bcm4329/dhd_dbg.h @@ -29,8 +29,8 @@ #ifdef DHD_DEBUG -#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && (net_ratelimit())) \ - printf args;} while (0) +#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && (net_ratelimit())) \ + printf args;} while (0) #define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0) #define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) #define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) diff --git a/drivers/net/wireless/bcm4329/dhd_linux.c b/drivers/net/wireless/bcm4329/dhd_linux.c index f35ed9cd834c..f6b47a26e29e 100644 --- a/drivers/net/wireless/bcm4329/dhd_linux.c +++ b/drivers/net/wireless/bcm4329/dhd_linux.c @@ -22,7 +22,7 @@ * 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_linux.c,v 1.65.4.9.2.12.2.104 2010/08/20 19:15:40 Exp $ + * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.104.4.35 2010/11/17 03:13:21 Exp $ */ #ifdef CONFIG_WIFI_CONTROL_FUNC @@ -107,7 +107,7 @@ int wifi_set_power(int on, unsigned long msec) int wifi_set_reset(int on, unsigned long msec) { - printk("%s = %d\n", __FUNCTION__, on); + DHD_TRACE(("%s = %d\n", __FUNCTION__, on)); if (wifi_control_data && wifi_control_data->set_reset) { wifi_control_data->set_reset(on); } @@ -118,7 +118,7 @@ int wifi_set_reset(int on, unsigned long msec) int wifi_get_mac_addr(unsigned char *buf) { - printk("%s\n", __FUNCTION__); + DHD_TRACE(("%s\n", __FUNCTION__)); if (!buf) return -EINVAL; if (wifi_control_data && wifi_control_data->get_mac_addr) { @@ -220,9 +220,10 @@ print_tainted() #include #endif /* defined(CONFIG_WIRELESS_EXT) */ +extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); + #if defined(CONFIG_HAS_EARLYSUSPEND) #include -extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ #ifdef PKT_FILTER_SUPPORT @@ -263,6 +264,8 @@ typedef struct dhd_info { struct tasklet_struct tasklet; spinlock_t sdlock; spinlock_t txqlock; + spinlock_t dhd_lock; + /* Thread based operation */ bool threads_only; struct semaphore sdsem; @@ -282,10 +285,10 @@ typedef struct dhd_info { int wl_count; int wl_packet; - int hang_was_sent; - - struct mutex wl_start_lock; - + int hang_was_sent; /* flag that message was send at least once */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + struct mutex wl_start_lock; /* mutex when START called to prevent any other Linux calls */ +#endif /* Thread to issue ioctl for multicast */ long sysioc_pid; struct semaphore sysioc_sem; @@ -309,7 +312,7 @@ char nvram_path[MOD_PARAM_PATHLEN]; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) struct semaphore dhd_registration_sem; -#define DHD_REGISTRATION_TIMEOUT 8000 /* msec : allowed time to finished dhd registration */ +#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ /* load firmware and/or nvram values from the filesystem */ module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0); @@ -523,6 +526,8 @@ static void dhd_set_packet_filter(int value, dhd_pub_t *dhd) #endif } + + #if defined(CONFIG_HAS_EARLYSUSPEND) static int dhd_set_suspend(int value, dhd_pub_t *dhd) { @@ -541,7 +546,7 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) if (value && dhd->in_suspend) { /* Kernel suspended */ - DHD_TRACE(("%s: force extra Suspend setting \n", __FUNCTION__)); + DHD_TRACE(("%s: force extra Suspend setting \n", __FUNCTION__)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode)); @@ -549,26 +554,24 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) /* Enable packet filter, only allow unicast packet to send up */ dhd_set_packet_filter(1, dhd); - /* if dtim skip setup as default force it to wake each thrid dtim - * for better power saving. - * Note that side effect is chance to miss BC/MC packet - */ - if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1)) - bcn_li_dtim = 3; - else - bcn_li_dtim = dhd->dtim_skip; + /* if dtim skip setup as default force it to wake each thrid dtim + * for better power saving. + * Note that side effect is chance to miss BC/MC packet + */ + bcn_li_dtim = dhd_get_dtim_skip(dhd); bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, 4, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); #ifdef CUSTOMER_HW2 - /* Disable build-in roaming to allowed ext supplicant to take of roaming */ + /* Disable build-in roaming during suspend */ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); #endif /* CUSTOMER_HW2 */ + } else { /* Kernel resumed */ - DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); + DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); power_mode = PM_FAST; dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, @@ -577,11 +580,11 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) /* disable pkt filter */ dhd_set_packet_filter(0, dhd); - /* restore pre-suspend setting for dtim_skip */ - bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, - 4, iovbuf, sizeof(iovbuf)); + /* restore pre-suspend setting for dtim_skip */ + bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, + 4, iovbuf, sizeof(iovbuf)); - dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); #ifdef CUSTOMER_HW2 roamvar = dhd_roam; bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); @@ -903,13 +906,18 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) #ifdef SOFTAP extern struct net_device *ap_net_dev; +/* semaphore that the soft AP CODE waits on */ +extern struct semaphore ap_eth_sema; #endif static void dhd_op_if(dhd_if_t *ifp) { - dhd_info_t *dhd; - int ret = 0, err = 0; + dhd_info_t *dhd; + int ret = 0, err = 0; +#ifdef SOFTAP + unsigned long flags; +#endif ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ @@ -944,13 +952,12 @@ dhd_op_if(dhd_if_t *ifp) ret = -EOPNOTSUPP; } else { #ifdef SOFTAP - /* semaphore that the soft AP CODE waits on */ - extern struct semaphore ap_eth_sema; - + flags = dhd_os_spin_lock(&dhd->pub); /* save ptr to wl0.1 netdev for use in wl_iw.c */ ap_net_dev = ifp->net; /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */ up(&ap_eth_sema); + dhd_os_spin_unlock(&dhd->pub, flags); #endif DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n", current->pid, ifp->net->name)); @@ -979,8 +986,10 @@ dhd_op_if(dhd_if_t *ifp) dhd->iflist[ifp->idx] = NULL; MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); #ifdef SOFTAP + flags = dhd_os_spin_lock(&dhd->pub); if (ifp->net == ap_net_dev) ap_net_dev = NULL; /* NULL SOFTAP global as well */ + dhd_os_spin_unlock(&dhd->pub, flags); #endif /* SOFTAP */ } } @@ -992,6 +1001,7 @@ _dhd_sysioc_thread(void *data) int i; #ifdef SOFTAP bool in_ap = FALSE; + unsigned long flags; #endif DAEMONIZE("dhd_sysioc"); @@ -1003,7 +1013,9 @@ _dhd_sysioc_thread(void *data) if (dhd->iflist[i]) { DHD_TRACE(("%s: interface %d\n",__FUNCTION__, i)); #ifdef SOFTAP + flags = dhd_os_spin_lock(&dhd->pub); in_ap = (ap_net_dev != NULL); + dhd_os_spin_unlock(&dhd->pub, flags); #endif /* SOFTAP */ if (dhd->iflist[i]->state) dhd_op_if(dhd->iflist[i]); @@ -1038,6 +1050,7 @@ _dhd_sysioc_thread(void *data) dhd_os_wake_unlock(&dhd->pub); dhd_os_start_unlock(&dhd->pub); } + DHD_TRACE(("%s: stopped\n",__FUNCTION__)); complete_and_exit(&dhd->sysioc_exited, 0); } @@ -1389,22 +1402,24 @@ dhd_watchdog_thread(void *data) /* Run until signal received */ while (1) { if (down_interruptible (&dhd->watchdog_sem) == 0) { - + dhd_os_sdlock(&dhd->pub); if (dhd->pub.dongle_reset == FALSE) { + DHD_TIMER(("%s:\n", __FUNCTION__)); /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); - } - /* Count the tick for reference */ - dhd->pub.tickcnt++; - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + /* Count the tick for reference */ + dhd->pub.tickcnt++; + /* Reschedule the watchdog */ + if (dhd->wd_timer_valid) + mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + } + dhd_os_sdunlock(&dhd->pub); dhd_os_wake_unlock(&dhd->pub); - } - else + } else { break; + } } complete_and_exit(&dhd->watchdog_exited, 0); @@ -1416,11 +1431,17 @@ dhd_watchdog(ulong data) dhd_info_t *dhd = (dhd_info_t *)data; dhd_os_wake_lock(&dhd->pub); + if (dhd->pub.dongle_reset) { + dhd_os_wake_unlock(&dhd->pub); + return; + } + if (dhd->watchdog_pid >= 0) { up(&dhd->watchdog_sem); return; } + dhd_os_sdlock(&dhd->pub); /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); @@ -1430,6 +1451,7 @@ dhd_watchdog(ulong data) /* Reschedule the watchdog */ if (dhd->wd_timer_valid) mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + dhd_os_sdunlock(&dhd->pub); dhd_os_wake_unlock(&dhd->pub); } @@ -1854,7 +1876,7 @@ dhd_stop(struct net_device *net) #if !defined(IGNORE_ETH0_DOWN) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_TRACE(("%s: Enter %s\n", __FUNCTION__, net->name)); if (dhd->pub.up == 0) { return 0; } @@ -1879,7 +1901,8 @@ dhd_open(struct net_device *net) #endif int ifidx; - wl_control_wl_start(net); /* start if needed */ + /* Force start if ifconfig_up gets called before START command */ + wl_control_wl_start(net); ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); @@ -1889,7 +1912,6 @@ dhd_open(struct net_device *net) return -1; } - if (ifidx == 0) { /* do it only for primary eth0 */ atomic_set(&dhd->pend_8021x_cnt, 0); @@ -2047,6 +2069,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) /* Initialize the spinlocks */ spin_lock_init(&dhd->sdlock); spin_lock_init(&dhd->txqlock); + spin_lock_init(&dhd->dhd_lock); /* Initialize Wakelock stuff */ spin_lock_init(&dhd->wl_lock); @@ -2056,8 +2079,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) mutex_init(&dhd->wl_start_lock); - +#endif /* Link to info module */ dhd->pub.info = dhd; @@ -2164,12 +2188,15 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_TRACE(("%s: \n", __FUNCTION__)); + dhd_os_sdlock(dhdp); + /* try to download image and nvram to the dongle */ if (dhd->pub.busstate == DHD_BUS_DOWN) { if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, fw_path, nv_path))) { DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", __FUNCTION__, fw_path, nv_path)); + dhd_os_sdunlock(dhdp); return -1; } } @@ -2179,16 +2206,18 @@ dhd_bus_start(dhd_pub_t *dhdp) dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); /* Bring up the bus */ - if ((ret = dhd_bus_init(&dhd->pub, TRUE)) != 0) { + if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); + dhd_os_sdunlock(dhdp); return ret; } #if defined(OOB_INTR_ONLY) /* Host registration for OOB interrupt */ if (bcmsdh_register_oob_intr(dhdp)) { - del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; + del_timer_sync(&dhd->timer); DHD_ERROR(("%s Host failed to resgister for OOB\n", __FUNCTION__)); + dhd_os_sdunlock(dhdp); return -ENODEV; } @@ -2198,12 +2227,15 @@ dhd_bus_start(dhd_pub_t *dhdp) /* If bus is not ready, can't come up */ if (dhd->pub.busstate != DHD_BUS_DATA) { - del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; + del_timer_sync(&dhd->timer); DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); + dhd_os_sdunlock(dhdp); return -ENODEV; } + dhd_os_sdunlock(dhdp); + #ifdef EMBEDDED_PLATFORM bcm_mkiovar("event_msgs", dhdp->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); dhdcdc_query_ioctl(dhdp, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf)); @@ -2227,6 +2259,7 @@ dhd_bus_start(dhd_pub_t *dhdp) setbit(dhdp->eventmask, WLC_E_TXFAIL); setbit(dhdp->eventmask, WLC_E_JOIN_START); setbit(dhdp->eventmask, WLC_E_SCAN_COMPLETE); + setbit(dhdp->eventmask, WLC_E_RELOAD); #ifdef PNO_SUPPORT setbit(dhdp->eventmask, WLC_E_PFN_NET_FOUND); #endif /* PNO_SUPPORT */ @@ -2364,6 +2397,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) dhd->pub.mac.octet[3], dhd->pub.mac.octet[4], dhd->pub.mac.octet[5]); #if defined(CONFIG_WIRELESS_EXT) +#if defined(CONFIG_FIRST_SCAN) #ifdef SOFTAP if (ifidx == 0) /* Don't call for SOFTAP Interface in SOFTAP MODE */ @@ -2371,6 +2405,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) #else wl_iw_iscan_set_scan_broadcast_prep(net, 1); #endif /* SOFTAP */ +#endif /* CONFIG_FIRST_SCAN */ #endif /* CONFIG_WIRELESS_EXT */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) @@ -2407,8 +2442,8 @@ dhd_bus_detach(dhd_pub_t *dhdp) #endif /* defined(OOB_INTR_ONLY) */ /* Clear the watchdog timer */ - del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; + del_timer_sync(&dhd->timer); } } } @@ -2434,16 +2469,18 @@ dhd_detach(dhd_pub_t *dhdp) /* Attach and link in the iw */ wl_iw_detach(); #endif - - for (i = 1; i < DHD_MAX_IFS; i++) - if (dhd->iflist[i]) - dhd_del_if(dhd, i); - if (dhd->sysioc_pid >= 0) { KILL_PROC(dhd->sysioc_pid, SIGTERM); wait_for_completion(&dhd->sysioc_exited); } + for (i = 1; i < DHD_MAX_IFS; i++) + if (dhd->iflist[i]) { + dhd->iflist[i]->state = WLC_E_IF_DEL; + dhd->iflist[i]->idx = i; + dhd_op_if(dhd->iflist[i]); + } + ifp = dhd->iflist[0]; ASSERT(ifp); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) @@ -2488,8 +2525,7 @@ dhd_detach(dhd_pub_t *dhdp) } } -void -rockchip_wifi_exit_module(void) +void rockchip_wifi_exit_module(void) { DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -2501,8 +2537,7 @@ rockchip_wifi_exit_module(void) dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); } -int -rockchip_wifi_init_module(void) +int rockchip_wifi_init_module(void) { int error; @@ -2686,29 +2721,28 @@ void dhd_os_wd_timer(void *bus, uint wdtick) { dhd_pub_t *pub = bus; - static uint save_dhd_watchdog_ms = 0; dhd_info_t *dhd = (dhd_info_t *)pub->info; + unsigned long flags; + int del_timer_flag = FALSE; - /* don't start the wd until fw is loaded */ - if (pub->busstate == DHD_BUS_DOWN) - return; + flags = dhd_os_spin_lock(pub); - /* Totally stop the timer */ - if (!wdtick && dhd->wd_timer_valid == TRUE) { - del_timer_sync(&dhd->timer); - dhd->wd_timer_valid = FALSE; - save_dhd_watchdog_ms = wdtick; - return; + /* don't start the wd until fw is loaded */ + if (pub->busstate != DHD_BUS_DOWN) { + if (wdtick) { + dhd_watchdog_ms = (uint)wdtick; + dhd->wd_timer_valid = TRUE; + /* Re arm the timer, at last watchdog period */ + mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + } else if (dhd->wd_timer_valid == TRUE) { + /* Totally stop the timer */ + dhd->wd_timer_valid = FALSE; + del_timer_flag = TRUE; + } } - - if (wdtick) { - dhd_watchdog_ms = (uint)wdtick; - - /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); - - dhd->wd_timer_valid = TRUE; - save_dhd_watchdog_ms = wdtick; + dhd_os_spin_unlock(pub, flags); + if (del_timer_flag) { + del_timer_sync(&dhd->timer); } } @@ -2922,20 +2956,18 @@ void dhd_wait_event_wakeup(dhd_pub_t *dhd) int dhd_dev_reset(struct net_device *dev, uint8 flag) { - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - /* Turning off watchdog */ - if (flag) - dhd_os_wd_timer(&dhd->pub, 0); + int ret; - dhd_bus_devreset(&dhd->pub, flag); + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - /* Turning on watchdog back */ - if (!flag) - dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); - DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__)); + ret = dhd_bus_devreset(&dhd->pub, flag); + if (ret) { + DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); + return ret; + } + DHD_ERROR(("%s: WLAN %s DONE\n", __FUNCTION__, flag ? "OFF" : "ON")); - return 1; + return ret; } int net_os_set_suspend_disable(struct net_device *dev, int val) @@ -3046,6 +3078,57 @@ dhd_dev_get_pno_status(struct net_device *dev) #endif /* PNO_SUPPORT */ +int net_os_send_hang_message(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) { + if (!dhd->hang_was_sent) { + dhd->hang_was_sent = 1; + ret = wl_iw_send_priv_event(dev, "HANG"); + } + } + return ret; +} + +void dhd_bus_country_set(struct net_device *dev, char *country_code) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (dhd && dhd->pub.up) + strncpy(dhd->pub.country_code, country_code, WLC_CNTRY_BUF_SZ); +} + +char *dhd_bus_country_get(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (dhd && (dhd->pub.country_code[0] != 0)) + return dhd->pub.country_code; + return NULL; +} + +void dhd_os_start_lock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) + mutex_lock(&dhd->wl_start_lock); +#endif +} + +void dhd_os_start_unlock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) + mutex_unlock(&dhd->wl_start_lock); +#endif +} + static int dhd_get_pend_8021x_cnt(dhd_info_t *dhd) { @@ -3228,32 +3311,21 @@ int net_os_wake_unlock(struct net_device *dev) return ret; } -int net_os_send_hang_message(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) { - if (!dhd->hang_was_sent) { - dhd->hang_was_sent = 1; - ret = wl_iw_send_priv_event(dev, "HANG"); - } - } - return ret; -} - -void dhd_os_start_lock(dhd_pub_t *pub) +unsigned long dhd_os_spin_lock(dhd_pub_t *pub) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags = 0; if (dhd) - mutex_lock(&dhd->wl_start_lock); + spin_lock_irqsave(&dhd->dhd_lock, flags); + + return flags; } -void dhd_os_start_unlock(dhd_pub_t *pub) +void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); if (dhd) - mutex_unlock(&dhd->wl_start_lock); + spin_unlock_irqrestore(&dhd->dhd_lock, flags); } diff --git a/drivers/net/wireless/bcm4329/dhd_sdio.c b/drivers/net/wireless/bcm4329/dhd_sdio.c index ff1bdedbc9f3..f9b9eceb91c7 100644 --- a/drivers/net/wireless/bcm4329/dhd_sdio.c +++ b/drivers/net/wireless/bcm4329/dhd_sdio.c @@ -426,7 +426,6 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start); #ifdef DHD_DEBUG_TRAP static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size); -static int dhdsdio_mem_dump(dhd_bus_t *bus); #endif /* DHD_DEBUG_TRAP */ static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); @@ -438,7 +437,7 @@ static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, void * regsva, uint16 devid); static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); -static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh); +static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, int reset_flag); static uint process_nvram_vars(char *varbuf, uint len); @@ -705,6 +704,7 @@ dhdsdio_sdclk(dhd_bus_t *bus, bool on) static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) { + int ret = BCME_OK; #ifdef DHD_DEBUG uint oldstate = bus->clkstate; #endif /* DHD_DEBUG */ @@ -717,7 +717,7 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); bus->activity = TRUE; } - return BCME_OK; + return ret; } switch (target) { @@ -726,29 +726,32 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) if (bus->clkstate == CLK_NONE) dhdsdio_sdclk(bus, TRUE); /* Now request HT Avail on the backplane */ - dhdsdio_htclk(bus, TRUE, pendok); - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - bus->activity = TRUE; + ret = dhdsdio_htclk(bus, TRUE, pendok); + if (ret == BCME_OK) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + bus->activity = TRUE; + } break; case CLK_SDONLY: /* Remove HT request, or bring up SD clock */ if (bus->clkstate == CLK_NONE) - dhdsdio_sdclk(bus, TRUE); + ret = dhdsdio_sdclk(bus, TRUE); else if (bus->clkstate == CLK_AVAIL) - dhdsdio_htclk(bus, FALSE, FALSE); + ret = dhdsdio_htclk(bus, FALSE, FALSE); else DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", bus->clkstate, target)); - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + if (ret == BCME_OK) + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); break; case CLK_NONE: /* Make sure to remove HT request */ if (bus->clkstate == CLK_AVAIL) - dhdsdio_htclk(bus, FALSE, FALSE); + ret = dhdsdio_htclk(bus, FALSE, FALSE); /* Now remove the SD clock */ - dhdsdio_sdclk(bus, FALSE); + ret = dhdsdio_sdclk(bus, FALSE); dhd_os_wd_timer(bus->dhd, 0); break; } @@ -756,7 +759,7 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); #endif /* DHD_DEBUG */ - return BCME_OK; + return ret; } int @@ -1839,11 +1842,6 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size) DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); } - if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { - /* Mem dump to a file on device */ - dhdsdio_mem_dump(bus); - } - done: if (mbuffer) MFREE(bus->dhd->osh, mbuffer, msize); @@ -1852,60 +1850,6 @@ done: return bcmerror; } - -static int -dhdsdio_mem_dump(dhd_bus_t *bus) -{ - int ret = 0; - int size; /* Full mem size */ - int start = 0; /* Start address */ - int read_size = 0; /* Read size of each iteration */ - uint8 *buf = NULL, *databuf = NULL; - - /* Get full mem size */ - size = bus->ramsize; - buf = MALLOC(bus->dhd->osh, size); - if (!buf) { - printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size); - return -1; - } - - /* Read mem content */ - printf("Dump dongle memory"); - databuf = buf; - while (size) - { - read_size = MIN(MEMBLOCK, size); - if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size))) - { - printf("%s: Error membytes %d\n", __FUNCTION__, ret); - if (buf) { - MFREE(bus->dhd->osh, buf, size); - } - return -1; - } - printf("."); - - /* Decrement size and increment start address */ - size -= read_size; - start += read_size; - databuf += read_size; - } - printf("Done\n"); - -#ifdef DHD_DEBUG - /* free buf before return !!! */ - if (write_to_file(bus->dhd, buf, bus->ramsize)) - { - printf("%s: Error writing to files\n", __FUNCTION__); - return -1; - } - /* buf free handled in write_to_file, not here */ -#else - MFREE(bus->dhd->osh, buf, size); -#endif - return 0; -} #endif /* DHD_DEBUG_TRAP */ #ifdef DHD_DEBUG @@ -2719,6 +2663,9 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) BUS_WAKE(bus); + /* Change our idea of bus state */ + bus->dhd->busstate = DHD_BUS_DOWN; + /* Enable clock for device interrupts */ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); @@ -2727,9 +2674,6 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) local_hostintmask = bus->hostintmask; bus->hostintmask = 0; - /* Change our idea of bus state */ - bus->dhd->busstate = DHD_BUS_DOWN; - /* Force clocks on backplane to be sure F2 interrupt propagates */ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); if (!err) { @@ -2782,23 +2726,24 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) dhd_timeout_t tmo; uint retries = 0; uint8 ready, enable; - int err, ret = 0; + int err, ret = BCME_ERROR; uint8 saveclk; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ASSERT(bus->dhd); if (!bus->dhd) - return 0; + return BCME_OK; if (enforce_mutex) dhd_os_sdlock(bus->dhd); /* Make sure backplane clock is on, needed to generate F2 interrupt */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (bus->clkstate != CLK_AVAIL) + err = dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if ((err != BCME_OK) || (bus->clkstate != CLK_AVAIL)) { + DHD_ERROR(("%s: Failed to set backplane clock: err %d\n", __FUNCTION__, err)); goto exit; - + } /* Force clocks on backplane to be sure F2 interrupt propagates */ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); @@ -2873,6 +2818,7 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) if (dhdp->busstate != DHD_BUS_DATA) dhdsdio_clkctl(bus, CLK_NONE, FALSE); + ret = BCME_OK; exit: if (enforce_mutex) dhd_os_sdunlock(bus->dhd); @@ -4631,8 +4577,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) if (bus->sleeping) return FALSE; - dhd_os_sdlock(bus->dhd); - /* Poll period: check device if appropriate. */ if (bus->poll && (++bus->polltick >= bus->pollrate)) { uint32 intstatus = 0; @@ -4702,8 +4646,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) } } - dhd_os_sdunlock(bus->dhd); - return bus->ipend; } @@ -5299,7 +5241,7 @@ dhdsdio_release(dhd_bus_t *bus, osl_t *osh) if (bus->dhd) { - dhdsdio_release_dongle(bus, osh); + dhdsdio_release_dongle(bus, osh, TRUE); dhd_detach(bus->dhd); bus->dhd = NULL; @@ -5343,11 +5285,11 @@ dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) static void -dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh) +dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, int reset_flag) { DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (bus->dhd && bus->dhd->dongle_reset) + if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) return; if (bus->sih) { @@ -5797,27 +5739,22 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) if (flag == TRUE) { if (!bus->dhd->dongle_reset) { + dhd_os_sdlock(dhdp); + /* Turning off watchdog */ + dhd_os_wd_timer(dhdp, 0); #if !defined(IGNORE_ETH0_DOWN) /* Force flow control as protection when stop come before ifconfig_down */ dhd_txflowcontrol(bus->dhd, 0, ON); #endif /* !defined(IGNORE_ETH0_DOWN) */ - /* save country settinng if was pre-setup with priv ioctl */ - dhd_os_proto_block(dhdp); - dhdcdc_query_ioctl(bus->dhd, 0, WLC_GET_COUNTRY, - bus->dhd->country_code, sizeof(bus->dhd->country_code)); - dhd_os_proto_unblock(dhdp); /* Expect app to have torn down any connection before calling */ /* Stop the bus, disable F2 */ - dhd_os_sdlock(dhdp); - dhd_bus_stop(bus, FALSE); /* Clean tx/rx buffer pointers, detach from the dongle */ - dhdsdio_release_dongle(bus, bus->dhd->osh); + dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE); bus->dhd->dongle_reset = TRUE; bus->dhd->up = FALSE; - dhd_os_sdunlock(dhdp); DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__)); @@ -5845,25 +5782,30 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) { /* Re-init bus, enable F2 transfer */ - dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); - + bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); + if (bcmerror == BCME_OK) { #if defined(OOB_INTR_ONLY) - dhd_enable_oob_intr(bus, TRUE); + dhd_enable_oob_intr(bus, TRUE); #endif /* defined(OOB_INTR_ONLY) */ - - bus->dhd->dongle_reset = FALSE; - bus->dhd->up = TRUE; - + bus->dhd->dongle_reset = FALSE; + bus->dhd->up = TRUE; #if !defined(IGNORE_ETH0_DOWN) - /* Restore flow control */ - dhd_txflowcontrol(bus->dhd, 0, OFF); -#endif + /* Restore flow control */ + dhd_txflowcontrol(bus->dhd, 0, OFF); +#endif + /* Turning on watchdog back */ + dhd_os_wd_timer(dhdp, dhd_watchdog_ms); - DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); + DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); + } else { + dhd_bus_stop(bus, FALSE); + dhdsdio_release_dongle(bus, bus->dhd->osh, FALSE); + } } else bcmerror = BCME_SDIO_ERROR; } else bcmerror = BCME_SDIO_ERROR; + dhd_os_sdunlock(dhdp); } else { bcmerror = BCME_NOTDOWN; diff --git a/drivers/net/wireless/bcm4329/include/epivers.h b/drivers/net/wireless/bcm4329/include/epivers.h index 92dc32635a25..00e3cac14dc5 100644 --- a/drivers/net/wireless/bcm4329/include/epivers.h +++ b/drivers/net/wireless/bcm4329/include/epivers.h @@ -33,16 +33,16 @@ #define EPI_RC_NUMBER 248 -#define EPI_INCREMENTAL_NUMBER 6 +#define EPI_INCREMENTAL_NUMBER 20 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 4, 218, 248, 6 +#define EPI_VERSION 4, 218, 248, 20 -#define EPI_VERSION_NUM 0x04daf806 +#define EPI_VERSION_NUM 0x04daf814 -#define EPI_VERSION_STR "4.218.248.6" -#define EPI_ROUTER_VERSION_STR "4.219.248.6" +#define EPI_VERSION_STR "4.218.248.20" +#define EPI_ROUTER_VERSION_STR "4.219.248.20" #endif diff --git a/drivers/net/wireless/bcm4329/include/proto/bcmevent.h b/drivers/net/wireless/bcm4329/include/proto/bcmevent.h index 46c04d379227..1f8ecb14d97a 100644 --- a/drivers/net/wireless/bcm4329/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcm4329/include/proto/bcmevent.h @@ -24,7 +24,7 @@ * * Dependencies: proto/bcmeth.h * - * $Id: bcmevent.h,v 9.34.4.1.20.16 2009/09/25 23:52:38 Exp $ + * $Id: bcmevent.h,v 9.34.4.1.20.16.64.1 2010/11/08 21:57:03 Exp $ * */ @@ -131,10 +131,10 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_ACTION_FRAME 58 #define WLC_E_ACTION_FRAME_COMPLETE 59 -#define WLC_E_ESCAN_RESULT 69 -#define WLC_E_WAKE_EVENT 70 -#define WLC_E_LAST 71 - +#define WLC_E_ESCAN_RESULT 69 +#define WLC_E_WAKE_EVENT 70 +#define WLC_E_RELOAD 71 +#define WLC_E_LAST 72 @@ -205,6 +205,7 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_IF_ADD 1 #define WLC_E_IF_DEL 2 +#define WLC_E_RELOAD_STATUS1 1 #include diff --git a/drivers/net/wireless/bcm4329/include/wlioctl.h b/drivers/net/wireless/bcm4329/include/wlioctl.h index 345ba34b94c0..cd7725a70db4 100644 --- a/drivers/net/wireless/bcm4329/include/wlioctl.h +++ b/drivers/net/wireless/bcm4329/include/wlioctl.h @@ -24,7 +24,7 @@ * 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: wlioctl.h,v 1.601.4.15.2.14.2.62 2010/08/19 01:20:12 Exp $ + * $Id: wlioctl.h,v 1.601.4.15.2.14.2.62.4.1 2010/11/17 03:09:28 Exp $ */ @@ -857,6 +857,7 @@ typedef struct wl_ioctl { #define PM_MAX 1 #define PM_FAST 2 +#define LISTEN_INTERVAL 20 #define INTERFERE_NONE 0 #define NON_WLAN 1 diff --git a/drivers/net/wireless/bcm4329/wl_iw.c b/drivers/net/wireless/bcm4329/wl_iw.c index eb8649f4d832..351c740368db 100644 --- a/drivers/net/wireless/bcm4329/wl_iw.c +++ b/drivers/net/wireless/bcm4329/wl_iw.c @@ -21,7 +21,7 @@ * 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: wl_iw.c,v 1.51.4.9.2.6.4.142.4.13 2010/09/15 03:34:56 Exp $ + * $Id: wl_iw.c,v 1.51.4.9.2.6.4.142.4.69 2010/12/21 03:00:08 Exp $ */ @@ -54,6 +54,7 @@ typedef const struct si_pub si_t; #define WL_INFORM(x) #define WL_WSEC(x) #define WL_SCAN(x) +#define WL_TRACE_COEX(x) #include @@ -96,11 +97,13 @@ typedef const struct si_pub si_t; #define WL_SOFTAP(x) printk x static struct net_device *priv_dev; static bool ap_cfg_running = FALSE; -static bool ap_fw_loaded = FALSE; +bool ap_fw_loaded = FALSE; +static long ap_cfg_pid = -1; struct net_device *ap_net_dev = NULL; struct semaphore ap_eth_sema; +static struct completion ap_cfg_exited; static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap); -static int wl_iw_softap_deassoc_stations(struct net_device *dev); +static int wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac); #endif #define WL_IW_IOCTL_CALL(func_call) \ @@ -112,6 +115,10 @@ static int g_onoff = G_WLAN_SET_ON; wl_iw_extra_params_t g_wl_iw_params; static struct mutex wl_cache_lock; +#ifdef CONFIG_US_NON_DFS_CHANNELS_ONLY +static bool use_non_dfs_channels = true; +#endif + extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, char* stringBuf, uint buflen); #include @@ -160,9 +167,11 @@ static wlc_ssid_t g_specific_ssid; static wlc_ssid_t g_ssid; static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; +#if defined(CONFIG_FIRST_SCAN) static volatile uint g_first_broadcast_scan; static volatile uint g_first_counter_scans; #define MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN 3 +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) @@ -183,7 +192,9 @@ static volatile uint g_first_counter_scans; static void wl_iw_free_ss_cache(void); static int wl_iw_run_ss_cache_timer(int kick_off); #endif +#if defined(CONFIG_FIRST_SCAN) int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); +#endif static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len); #define ISCAN_STATE_IDLE 0 #define ISCAN_STATE_SCANING 1 @@ -217,7 +228,12 @@ typedef struct iscan_info { wl_iscan_params_t *iscan_ex_params_p; int iscan_ex_param_size; } iscan_info_t; -#define COEX_DHCP 1 +#define COEX_DHCP 1 + +#define BT_DHCP_eSCO_FIX +#define BT_DHCP_USE_FLAGS +#define BT_DHCP_OPPORTUNITY_WINDOW_TIME 2500 +#define BT_DHCP_FLAG_FORCE_TIME 5500 static void wl_iw_bt_flag_set(struct net_device *dev, bool set); static void wl_iw_bt_release(void); @@ -227,18 +243,16 @@ typedef enum bt_coex_status { BT_DHCP_OPPORTUNITY_WINDOW, BT_DHCP_FLAG_FORCE_TIMEOUT } coex_status_t; -#define BT_DHCP_OPPORTUNITY_WINDOW_TIEM 2500 -#define BT_DHCP_FLAG_FORCE_TIME 5500 typedef struct bt_info { struct net_device *dev; struct timer_list timer; uint32 timer_ms; uint32 timer_on; - int bt_state; + bool dhcp_done; + int bt_state; - - long bt_pid; + long bt_pid; struct semaphore bt_sem; struct completion bt_exited; } bt_info_t; @@ -605,6 +619,31 @@ wl_iw_get_macaddr( return error; } +static int +wl_iw_set_country_code(struct net_device *dev, char *ccode) +{ + char country_code[WLC_CNTRY_BUF_SZ]; + int ret = -1; + + WL_TRACE(("%s\n", __FUNCTION__)); + if (!ccode) + ccode = dhd_bus_country_get(dev); + strncpy(country_code, ccode, sizeof(country_code)); + if (ccode && (country_code[0] != 0)) { +#ifdef CONFIG_US_NON_DFS_CHANNELS_ONLY + if (use_non_dfs_channels && !strncmp(country_code, "US", 2)) + strncpy(country_code, "Q2", WLC_CNTRY_BUF_SZ); + if (!use_non_dfs_channels && !strncmp(country_code, "Q2", 2)) + strncpy(country_code, "US", WLC_CNTRY_BUF_SZ); +#endif + ret = dev_wlc_ioctl(dev, WLC_SET_COUNTRY, &country_code, sizeof(country_code)); + if (ret >= 0) { + WL_TRACE(("%s: set country %s OK\n", __FUNCTION__, country_code)); + dhd_bus_country_set(dev, &country_code[0]); + } + } + return ret; +} static int wl_iw_set_country( @@ -626,14 +665,11 @@ wl_iw_set_country( country_offset = strcspn(extra, " "); country_code_size = strlen(extra) - country_offset; - if (country_offset != 0) { strncpy(country_code, extra + country_offset + 1, MIN(country_code_size, sizeof(country_code))); - - - if ((error = dev_wlc_ioctl(dev, WLC_SET_COUNTRY, - &country_code, sizeof(country_code))) >= 0) { + error = wl_iw_set_country_code(dev, country_code); + if (error >= 0) { p += snprintf(p, MAX_WX_STRING, "OK"); WL_TRACE(("%s: set country %s OK\n", __FUNCTION__, country_code)); goto exit; @@ -663,29 +699,34 @@ wl_iw_set_power_mode( int pm_local = PM_OFF; char powermode_val = 0; + WL_TRACE_COEX(("%s: DHCP session cmd:%s\n", __FUNCTION__, extra)); + strncpy((char *)&powermode_val, extra + strlen("POWERMODE") + 1, 1); if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { - WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__)); - dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm)); dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); /* Disable packet filtering if necessary */ net_os_set_packet_filter(dev, 0); - } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) { + g_bt->dhcp_done = false; + WL_TRACE_COEX(("%s: DHCP start, pm:%d changed to pm:%d\n", + __FUNCTION__, pm, pm_local)); - WL_TRACE(("%s: DHCP session done\n", __FUNCTION__)); + } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) { dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); /* Enable packet filtering if was turned off */ net_os_set_packet_filter(dev, 1); + g_bt->dhcp_done = true; + } else { - WL_ERROR(("Unkwown yet power setting, ignored\n")); + WL_ERROR(("%s Unkwown yet power setting, ignored\n", + __FUNCTION__)); } p += snprintf(p, MAX_WX_STRING, "OK"); @@ -696,6 +737,122 @@ wl_iw_set_power_mode( } #endif + +static bool btcoex_is_sco_active(struct net_device *dev) +{ + int ioc_res = 0; + bool res = false; + int temp = 0; + + ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 4, &temp); + + if (ioc_res == 0) { + WL_TRACE_COEX(("%s: read btc_params[4] = %x\n", __FUNCTION__, temp)); + + if ((temp > 0xea0) && (temp < 0xed8)) { + WL_TRACE_COEX(("%s: BT SCO/eSCO is ACTIVE\n", __FUNCTION__)); + res = true; + } else { + WL_TRACE_COEX(("%s: BT SCO/eSCO is NOT detected\n", __FUNCTION__)); + } + } else { + WL_ERROR(("%s ioc read btc params error\n", __FUNCTION__)); + } + return res; +} + +#if defined(BT_DHCP_eSCO_FIX) + +static int set_btc_esco_params(struct net_device *dev, bool trump_sco) +{ + static bool saved_status = false; + + char buf_reg50va_dhcp_on[8] = { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; + char buf_reg51va_dhcp_on[8] = { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg64va_dhcp_on[8] = { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg65va_dhcp_on[8] = { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg71va_dhcp_on[8] = { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + + uint32 regaddr; + static uint32 saved_reg50; + static uint32 saved_reg51; + static uint32 saved_reg64; + static uint32 saved_reg65; + static uint32 saved_reg71; + + if (trump_sco) { + + WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n")); + + if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { + + saved_status = TRUE; + WL_TRACE_COEX(("%s saved bt_params[50,51,64,65,71]:" + " 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __FUNCTION__, saved_reg50, saved_reg51, + saved_reg64, saved_reg65, saved_reg71)); + + } else { + WL_ERROR((":%s: save btc_params failed\n", + __FUNCTION__)); + saved_status = false; + return -1; + } + + WL_TRACE_COEX(("override with [50,51,64,65,71]:" + " 0x%x 0x%x 0x%x 0x%x 0x%x\n", + *(u32 *)(buf_reg50va_dhcp_on+4), + *(u32 *)(buf_reg51va_dhcp_on+4), + *(u32 *)(buf_reg64va_dhcp_on+4), + *(u32 *)(buf_reg65va_dhcp_on+4), + *(u32 *)(buf_reg71va_dhcp_on+4))); + + dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg50va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg51va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg64va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg65va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg71va_dhcp_on[0], 8); + + saved_status = true; + + } else if (saved_status) { + + WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n")); + + regaddr = 50; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg50); + regaddr = 51; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg51); + regaddr = 64; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg64); + regaddr = 65; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg65); + regaddr = 71; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg71); + + WL_TRACE_COEX(("restore bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n", + saved_reg50, saved_reg51, saved_reg64, + saved_reg65, saved_reg71)); + + saved_status = false; + } else { + WL_ERROR((":%s att to restore not saved BTCOEX params\n", + __FUNCTION__)); + return -1; + } + return 0; +} +#endif + static int wl_iw_get_power_mode( struct net_device *dev, @@ -751,9 +908,6 @@ wl_iw_set_btcoex_dhcp( static bool saved_status = FALSE; char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; -#ifndef CUSTOMER_HW2 - uint32 temp1, temp2; -#endif #ifdef CUSTOMER_HW2 strncpy((char *)&powermode_val, extra + strlen("BTCOEXMODE") + 1, 1); @@ -763,44 +917,43 @@ wl_iw_set_btcoex_dhcp( if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { - WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__)); + WL_TRACE_COEX(("%s: DHCP session start, cmd:%s\n", __FUNCTION__, extra)); if ((saved_status == FALSE) && #ifndef CUSTOMER_HW2 - (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) && + (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) && #endif - (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { - saved_status = TRUE; - WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", \ - saved_reg66, saved_reg41, saved_reg68)); + (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { + WL_TRACE_COEX(("save regs {66,41,68} ->: 0x%x 0x%x 0x%x\n", \ + saved_reg66, saved_reg41, saved_reg68)); #ifndef CUSTOMER_HW2 - dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); + dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); #endif - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg66va_dhcp_on[0], sizeof(buf_reg66va_dhcp_on)); - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg41va_dhcp_on[0], sizeof(buf_reg41va_dhcp_on)); - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg68va_dhcp_on[0], sizeof(buf_reg68va_dhcp_on)); -#ifndef CUSTOMER_HW2 - if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 12, &temp1)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 13, &temp2))) - { - if ((temp1 != 0) && (temp2 != 0)) { -#endif - g_bt->bt_state = BT_DHCP_START; - g_bt->timer_on = 1; - mod_timer(&g_bt->timer, g_bt->timer.expires); - WL_TRACE(("%s enable BT DHCP Timer\n", \ - __FUNCTION__)); -#ifndef CUSTOMER_HW2 - } - } -#endif + if (btcoex_is_sco_active(dev)) { + + dev_wlc_bufvar_set(dev, "btc_params", \ + (char *)&buf_reg66va_dhcp_on[0], \ + sizeof(buf_reg66va_dhcp_on)); + + dev_wlc_bufvar_set(dev, "btc_params", \ + (char *)&buf_reg41va_dhcp_on[0], \ + sizeof(buf_reg41va_dhcp_on)); + + dev_wlc_bufvar_set(dev, "btc_params", \ + (char *)&buf_reg68va_dhcp_on[0], \ + sizeof(buf_reg68va_dhcp_on)); + saved_status = TRUE; + + g_bt->bt_state = BT_DHCP_START; + g_bt->timer_on = 1; + mod_timer(&g_bt->timer, g_bt->timer.expires); + WL_TRACE_COEX(("%s enable BT DHCP Timer\n", \ + __FUNCTION__)); + } } else if (saved_status == TRUE) { WL_ERROR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__)); @@ -811,22 +964,28 @@ wl_iw_set_btcoex_dhcp( #else else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) { #endif - WL_TRACE(("%s: DHCP session done\n", __FUNCTION__)); #ifndef CUSTOMER_HW2 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); #endif - WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__)); + WL_TRACE_COEX(("%s disable BT DHCP Timer\n", __FUNCTION__)); if (g_bt->timer_on) { g_bt->timer_on = 0; del_timer_sync(&g_bt->timer); + + if (g_bt->bt_state != BT_DHCP_IDLE) { + WL_TRACE_COEX(("%s bt->bt_state:%d\n", + __FUNCTION__, g_bt->bt_state)); + + up(&g_bt->bt_sem); + } } - dev_wlc_bufvar_set(dev, "btc_flags", \ + if (saved_status == TRUE) { + dev_wlc_bufvar_set(dev, "btc_flags", \ (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); - if (saved_status) { regaddr = 66; dev_wlc_intvar_set_reg(dev, "btc_params", \ (char *)®addr, (char *)&saved_reg66); @@ -836,11 +995,15 @@ wl_iw_set_btcoex_dhcp( regaddr = 68; dev_wlc_intvar_set_reg(dev, "btc_params", \ (char *)®addr, (char *)&saved_reg68); + + WL_TRACE_COEX(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", \ + saved_reg66, saved_reg41, saved_reg68)); } saved_status = FALSE; } else { - WL_ERROR(("Unkwown yet power setting, ignored\n")); + WL_ERROR(("%s Unkwown yet power setting, ignored\n", + __FUNCTION__)); } p += snprintf(p, MAX_WX_STRING, "OK"); @@ -880,6 +1043,22 @@ wl_iw_set_suspend( return ret; } +#ifdef CONFIG_US_NON_DFS_CHANNELS_ONLY +static int +wl_iw_set_dfs_channels( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + use_non_dfs_channels = *(extra + strlen(SETDFSCHANNELS_CMD) + 1) - '0'; + use_non_dfs_channels = (use_non_dfs_channels != 0) ? false : true; + wl_iw_set_country_code(dev, NULL); + return 0; +} +#endif + int wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len) { @@ -1062,7 +1241,6 @@ wl_iw_set_band( if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { - if ((error = dev_wlc_ioctl(dev, WLC_SET_BAND, &band, sizeof(band))) >= 0) { p += snprintf(p, MAX_WX_STRING, "OK"); @@ -1164,15 +1342,15 @@ wl_iw_set_pno_set( wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; int nssid = 0; cmd_tlv_t *cmd_tlv_temp; - char type; char *str_ptr; + char *str_ptr_end; int tlv_size_left; int pno_time; #ifdef PNO_SET_DEBUG int i; char pno_in_example[] = {'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', \ - 'S', 0x01, 0x01, 0x00, + 'S', '1', '2', '0', 'S', 0x04, 'B', 'R', 'C', 'M', @@ -1180,8 +1358,8 @@ wl_iw_set_pno_set( 0x04, 'G', 'O', 'O', 'G', 'T', - 0x00, - 0x0A + '1','E', + 0x00 }; #endif @@ -1238,29 +1416,15 @@ wl_iw_set_pno_set( goto exit_proc; } else { - while (tlv_size_left > 0) - { - type = str_ptr[0]; - switch (type) { - case PNO_TLV_TYPE_TIME: - - if ((res = wl_iw_parse_data_tlv(&str_ptr, \ - &pno_time, \ - sizeof(pno_time), \ - type, sizeof(short), &tlv_size_left)) == -1) { - WL_ERROR(("%s return %d\n", \ - __FUNCTION__, res)); - goto exit_proc; - } - break; - - default: - WL_ERROR(("%s get unkwown type %X\n", \ - __FUNCTION__, type)); - goto exit_proc; - break; - } + if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { + WL_ERROR(("%s scan duration corrupted field size %d\n", \ + __FUNCTION__, tlv_size_left)); + goto exit_proc; } + str_ptr++; + pno_time = simple_strtoul(str_ptr, &str_ptr_end, 16); + WL_ERROR((" got %d bytes left pno_time %d or %#x\n", \ + tlv_size_left, pno_time, pno_time)); } } else { @@ -1279,7 +1443,7 @@ exit_proc: static int wl_iw_get_wext_rssi( struct net_device *dev, - struct iw_request_info *info, + struct iw_request_info *info, union iwreq_data *wrqu, char *extra ) @@ -1341,19 +1505,24 @@ wl_iw_get_rssi( error = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); if (error) { WL_ERROR(("%s: Fails %d\n", __FUNCTION__, error)); - net_os_wake_unlock(dev); - return error; - } - rssi = dtoh32(scb_val.val); + } else { + rssi = dtoh32(scb_val.val); - error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)); - if (!error) { - ssid.SSID_len = dtoh32(ssid.SSID_len); - wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len)); + error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)); + if (!error) { + ssid.SSID_len = dtoh32(ssid.SSID_len); + wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len)); + } } } - p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi); + WL_ASSOC(("%s ssid_len:%d, rssi:%d\n", __FUNCTION__, ssid.SSID_len, rssi)); + + if (error || (ssid.SSID_len == 0)) { + p += snprintf(p, MAX_WX_STRING, "FAIL"); + } else { + p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi); + } wrqu->data.length = p - extra + 1; net_os_wake_unlock(dev); @@ -1388,8 +1557,8 @@ wl_iw_send_priv_event( int wl_control_wl_start(struct net_device *dev) { - wl_iw_t *iw; int ret = 0; + wl_iw_t *iw; WL_TRACE(("Enter %s \n", __FUNCTION__)); @@ -1399,6 +1568,11 @@ wl_control_wl_start(struct net_device *dev) } iw = *(wl_iw_t **)netdev_priv(dev); + + if (!iw) { + WL_ERROR(("%s: wl is null\n", __FUNCTION__)); + return -1; + } dhd_os_start_lock(iw->pub); if (g_onoff == G_WLAN_SET_OFF) { @@ -1408,15 +1582,15 @@ wl_control_wl_start(struct net_device *dev) sdioh_start(NULL, 0); #endif - dhd_dev_reset(dev, 0); + ret = dhd_dev_reset(dev, 0); + if (ret == BCME_OK) { #if defined(BCMLXSDMMC) - sdioh_start(NULL, 1); + sdioh_start(NULL, 1); #endif - - dhd_dev_init_ioctl(dev); - - g_onoff = G_WLAN_SET_ON; + dhd_dev_init_ioctl(dev); + g_onoff = G_WLAN_SET_ON; + } } WL_TRACE(("Exited %s \n", __FUNCTION__)); @@ -1431,8 +1605,8 @@ wl_iw_control_wl_off( struct iw_request_info *info ) { - wl_iw_t *iw; int ret = 0; + wl_iw_t *iw; WL_TRACE(("Enter %s\n", __FUNCTION__)); @@ -1442,6 +1616,10 @@ wl_iw_control_wl_off( } iw = *(wl_iw_t **)netdev_priv(dev); + if (!iw) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + return -1; + } dhd_os_start_lock(iw->pub); #ifdef SOFTAP @@ -1465,10 +1643,11 @@ wl_iw_control_wl_off( #endif memset(g_scan, 0, G_SCAN_RESULTS); g_scan_specified_ssid = 0; - +#if defined(CONFIG_FIRST_SCAN) g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; g_first_counter_scans = 0; #endif +#endif #if defined(BCMLXSDMMC) sdioh_stop(NULL); @@ -1498,7 +1677,15 @@ wl_iw_control_wl_on( WL_TRACE(("Enter %s \n", __FUNCTION__)); - ret = wl_control_wl_start(dev); + if ((ret = wl_control_wl_start(dev)) != BCME_OK) { + WL_ERROR(("%s failed first attemp\n", __FUNCTION__)); + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); + if ((ret = wl_control_wl_start(dev)) != BCME_OK) { + WL_ERROR(("%s failed second attemp\n", __FUNCTION__)); + net_os_send_hang_message(dev); + return ret; + } + } wl_iw_send_priv_event(dev, "START"); @@ -1519,7 +1706,7 @@ wl_iw_control_wl_on( static struct ap_profile my_ap; static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap); static int get_assoc_sta_list(struct net_device *dev, char *buf, int len); -static int set_ap_mac_list(struct net_device *dev, char *buf); +static int set_ap_mac_list(struct net_device *dev, void *buf); #define PTYPE_STRING 0 #define PTYPE_INTDEC 1 @@ -1601,9 +1788,13 @@ int init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg) ret |= get_parmeter_from_string(&str_ptr, "CHANNEL=", PTYPE_INTDEC, &ap_cfg->channel, 5); - ret |= get_parmeter_from_string(&str_ptr, "PREAMBLE=", PTYPE_INTDEC, &ap_cfg->preamble, 5); + get_parmeter_from_string(&str_ptr, "PREAMBLE=", PTYPE_INTDEC, &ap_cfg->preamble, 5); + + get_parmeter_from_string(&str_ptr, "MAX_SCB=", PTYPE_INTDEC, &ap_cfg->max_scb, 5); - ret |= get_parmeter_from_string(&str_ptr, "MAX_SCB=", PTYPE_INTDEC, &ap_cfg->max_scb, 5); + get_parmeter_from_string(&str_ptr, "HIDDEN=", PTYPE_INTDEC, &ap_cfg->closednet, 5); + + get_parmeter_from_string(&str_ptr, "COUNTRY=", PTYPE_STRING, &ap_cfg->country_code, 3); return ret; } @@ -1620,7 +1811,8 @@ static int iwpriv_set_ap_config(struct net_device *dev, char *extra = NULL; struct ap_profile *ap_cfg = &my_ap; - WL_TRACE(("> Got IWPRIV SET_AP IOCTL: info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n", + WL_TRACE(("%s: info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n", + __FUNCTION__, info->cmd, info->flags, wrqu->data.pointer, wrqu->data.length)); @@ -1674,52 +1866,86 @@ static int iwpriv_get_assoc_list(struct net_device *dev, char mac_buf[256]; struct maclist *sta_maclist = (struct maclist *)mac_buf; - char mac_lst[256]; + char mac_lst[384]; char *p_mac_str; + char *p_mac_str_end; + + if ((!dev) || (!extra)) { + return -EINVAL; + } + + net_os_wake_lock(dev); WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d, \ iwp.len:%p, iwp.flags:%x \n", __FUNCTION__, info->cmd, info->flags, \ extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags)); - WL_SOFTAP(("extra:%s\n", extra)); - print_buf((u8 *)p_iwrq, 16, 0); - memset(sta_maclist, 0, sizeof(mac_buf)); sta_maclist->count = 8; - WL_TRACE((" net device:%s, buf_sz:%d\n", dev->name, sizeof(mac_buf))); - get_assoc_sta_list(dev, mac_buf, 256); - WL_TRACE((" got %d stations\n", sta_maclist->count)); + WL_SOFTAP(("%s: net device:%s, buf_sz:%d\n", + __FUNCTION__, dev->name, sizeof(mac_buf))); + + if ((ret = get_assoc_sta_list(dev, mac_buf, sizeof(mac_buf))) < 0) { + WL_ERROR(("%s: sta list ioctl error:%d\n", + __FUNCTION__, ret)); + goto func_exit; + } + + WL_SOFTAP(("%s: got %d stations\n", __FUNCTION__, + sta_maclist->count)); memset(mac_lst, 0, sizeof(mac_lst)); p_mac_str = mac_lst; + p_mac_str_end = &mac_lst[sizeof(mac_lst)-1]; for (i = 0; i < 8; i++) { struct ether_addr *id = &sta_maclist->ea[i]; + if (!ETHER_ISNULLADDR(id->octet)) { + scb_val_t scb_val; + int rssi = 0; - WL_SOFTAP(("dhd_drv>> sta_mac[%d] :", i)); - print_buf((unsigned char *)&sta_maclist->ea[i], 6, 0); + bzero(&scb_val, sizeof(scb_val_t)); + + if ((p_mac_str_end - p_mac_str) <= 36) { + WL_ERROR(("%s: mac list buf is < 36 for item[%i] item\n", + __FUNCTION__, i)); + break; + } - p_mac_str += snprintf(p_mac_str, MAX_WX_STRING, - "Mac[%d]=%02X:%02X:%02X:%02X:%02X:%02X\n", i, + p_mac_str += snprintf(p_mac_str, MAX_WX_STRING, + "\nMac[%d]=%02X:%02X:%02X:%02X:%02X:%02X,", i, id->octet[0], id->octet[1], id->octet[2], id->octet[3], id->octet[4], id->octet[5]); + bcopy(id->octet, &scb_val.ea, 6); + ret = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); + if (ret < 0) { + snprintf(p_mac_str, MAX_WX_STRING, "RSSI:ERR"); + WL_ERROR(("%s: RSSI ioctl error:%d\n", + __FUNCTION__, ret)); + break; + } + + rssi = dtoh32(scb_val.val); + p_mac_str += snprintf(p_mac_str, MAX_WX_STRING, + "RSSI:%d", rssi); + } } - p_iwrq->data.length = strlen(mac_lst); + p_iwrq->data.length = strlen(mac_lst) + 1; - WL_TRACE(("u.pointer:%p\n", p_iwrq->data.pointer)); - WL_TRACE(("resulting str:\n%s \n len:%d\n\n", mac_lst, p_iwrq->data.length)); + WL_SOFTAP(("%s: data to user:\n%s\n usr_ptr:%p\n", __FUNCTION__, + mac_lst, p_iwrq->data.pointer)); if (p_iwrq->data.length) { - if (copy_to_user(p_iwrq->data.pointer, mac_lst, p_iwrq->data.length)) { - WL_ERROR(("%s: Can't copy to user\n", __FUNCTION__)); - return -EFAULT; - } + bcopy(mac_lst, extra, p_iwrq->data.length); } +func_exit: + net_os_wake_unlock(dev); + WL_TRACE(("Exited %s \n", __FUNCTION__)); return ret; } @@ -1727,19 +1953,20 @@ static int iwpriv_get_assoc_list(struct net_device *dev, #ifdef SOFTAP +#define MAC_FILT_MAX 8 static int iwpriv_set_mac_filters(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *ext) { - int i, ret = -1; - char *extra = NULL; - u8 macfilt[8][6]; + char * extra = NULL; int mac_cnt = 0; - char sub_cmd[16]; + int mac_mode = 0; + struct ether_addr *p_ea; + struct mac_list_set mflist_set; - WL_TRACE((">>> Got IWPRIV SET_MAC_FILTER IOCTL: info->cmd:%x, \ + WL_SOFTAP((">>> Got IWPRIV SET_MAC_FILTER IOCTL: info->cmd:%x, \ info->flags:%x, u.data:%p, u.len:%d\n", info->cmd, info->flags, wrqu->data.pointer, wrqu->data.length)); @@ -1759,25 +1986,21 @@ static int iwpriv_set_mac_filters(struct net_device *dev, extra[wrqu->data.length] = 0; WL_SOFTAP((" Got parameter string in iw_point:\n %s \n", extra)); - memset(macfilt, 0, sizeof(macfilt)); - memset(sub_cmd, 0, sizeof(sub_cmd)); + memset(&mflist_set, 0, sizeof(mflist_set)); str_ptr = extra; - if (get_parmeter_from_string(&str_ptr, "ASCII_CMD=", PTYPE_STRING, sub_cmd, 15) != 0) { + if (get_parmeter_from_string(&str_ptr, "MAC_MODE=", + PTYPE_INTDEC, &mac_mode, 4) != 0) { + WL_ERROR(("ERROR: 'MAC_MODE=' token is missing\n")); goto exit_proc; } -#define MAC_FILT_MAX 8 - - if (strncmp(sub_cmd, "MAC_FLT_W", strlen("MAC_FLT_W"))) { - WL_ERROR(("ERROR: sub_cmd:%s != 'MAC_FLT_W'!\n", sub_cmd)); - goto exit_proc; - } + p_ea = &mflist_set.mac_list.ea[0]; if (get_parmeter_from_string(&str_ptr, "MAC_CNT=", PTYPE_INTDEC, &mac_cnt, 4) != 0) { - WL_ERROR(("ERROR: MAC_CNT param is missing \n")); + WL_ERROR(("ERROR: 'MAC_CNT=' token param is missing \n")); goto exit_proc; } @@ -1786,19 +2009,23 @@ static int iwpriv_set_mac_filters(struct net_device *dev, goto exit_proc; } - for (i = 0; i < mac_cnt; i++) { + for (i=0; i < mac_cnt; i++) if (get_parmeter_from_string(&str_ptr, "MAC=", - PTYPE_STR_HEX, macfilt[i], 12) != 0) { + PTYPE_STR_HEX, &p_ea[i], 12) != 0) { WL_ERROR(("ERROR: MAC_filter[%d] is missing !\n", i)); goto exit_proc; } - } + WL_SOFTAP(("MAC_MODE=:%d, MAC_CNT=%d, MACs:..\n", mac_mode, mac_cnt)); for (i = 0; i < mac_cnt; i++) { - WL_SOFTAP(("mac_filt[%d]:", i)); - print_buf(macfilt[i], 6, 0); + WL_SOFTAP(("mac_filt[%d]:", i)); + print_buf(&p_ea[i], 6, 0); } + mflist_set.mode = mac_mode; + mflist_set.mac_list.count = mac_cnt; + set_ap_mac_list(dev, &mflist_set); + wrqu->data.pointer = NULL; wrqu->data.length = 0; ret = 0; @@ -1814,8 +2041,44 @@ static int iwpriv_set_mac_filters(struct net_device *dev, } #endif + +#ifdef SOFTAP +static int iwpriv_set_ap_sta_disassoc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) +{ + int res = 0; + char sta_mac[6] = {0, 0, 0, 0, 0, 0}; + char cmd_buf[256]; + char *str_ptr = cmd_buf; + + WL_SOFTAP((">>%s called\n args: info->cmd:%x," + " info->flags:%x, u.data.p:%p, u.data.len:%d\n", + __FUNCTION__, info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + if (wrqu->data.length != 0) { + + if (copy_from_user(cmd_buf, wrqu->data.pointer, wrqu->data.length)) { + return -EFAULT; + } + + if (get_parmeter_from_string(&str_ptr, + "MAC=", PTYPE_STR_HEX, sta_mac, 12) == 0) { + res = wl_iw_softap_deassoc_stations(dev, sta_mac); + } else { + WL_ERROR(("ERROR: STA_MAC= token not found\n")); + } + } + + return res; +} +#endif + #endif + #if WIRELESS_EXT < 13 struct iw_request_info { @@ -2342,7 +2605,7 @@ wl_iw_set_wap( join_params.ssid.SSID_len = htod32(g_ssid.SSID_len); memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN); - WL_TRACE(("%s target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel)); + WL_ASSOC(("%s target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel)); wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size); if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) { @@ -2351,7 +2614,7 @@ wl_iw_set_wap( } if (g_ssid.SSID_len) { - WL_TRACE(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__, \ + WL_ASSOC(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__, \ g_ssid.SSID, MAC2STR((u8 *)awrq->sa_data), \ g_wl_iw_params.target_channel)); } @@ -2591,7 +2854,10 @@ wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) params->passive_time = -1; params->home_time = -1; params->channel_num = 0; - +#if defined(CONFIG_FIRST_SCAN) + if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) + params->passive_time = 30; +#endif params->nprobes = htod32(params->nprobes); params->active_time = htod32(params->active_time); params->passive_time = htod32(params->passive_time); @@ -2618,7 +2884,6 @@ wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type)); WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type)); - if ((err = dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, \ iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) { WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err)); @@ -2721,7 +2986,7 @@ wl_iw_iscan_get(iscan_info_t *iscan) static void wl_iw_force_specific_scan(iscan_info_t *iscan) { - WL_TRACE(("%s force Specific SCAN for %s\n", __FUNCTION__, g_specific_ssid.SSID)); + WL_SCAN(("%s force Specific SCAN for %s\n", __FUNCTION__, g_specific_ssid.SSID)); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_lock(); #endif @@ -2739,9 +3004,11 @@ static void wl_iw_send_scan_complete(iscan_info_t *iscan) memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); +#if defined(CONFIG_FIRST_SCAN) if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY; - WL_TRACE(("Send Event ISCAN complete\n")); +#endif + WL_SCAN(("Send Event ISCAN complete\n")); #endif } @@ -3046,7 +3313,7 @@ __u16 *merged_len) mutex_lock(&wl_cache_lock); node = g_ss_cache_ctrl.m_cache_head; for (;node;) { - list_merge = (wl_scan_results_t *)node; + list_merge = (wl_scan_results_t *)&node->buflen; WL_TRACE(("%s: Cached Specific APs list=%d\n", __FUNCTION__, list_merge->count)); if (buflen_from_user - *merged_len > 0) { *merged_len += (__u16) wl_iw_get_scan_prep(list_merge, info, @@ -3136,14 +3403,16 @@ wl_iw_set_scan( if (wrqu->data.length == sizeof(struct iw_scan_req)) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { struct iw_scan_req *req = (struct iw_scan_req *)extra; +#if defined(CONFIG_FIRST_SCAN) if (g_first_broadcast_scan != BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { - WL_TRACE(("%s Ignoring SC %s first BC is not done = %d\n", \ + WL_ERROR(("%s Ignoring SC %s first BC is not done = %d\n", \ __FUNCTION__, req->essid, \ g_first_broadcast_scan)); return -EBUSY; } +#endif if (g_scan_specified_ssid) { - WL_TRACE(("%s Specific SCAN is not done ignore scan for = %s \n", \ + WL_SCAN(("%s Specific SCAN is not done ignore scan for = %s \n", \ __FUNCTION__, req->essid)); return -EBUSY; } @@ -3161,7 +3430,7 @@ wl_iw_set_scan( #endif if ((error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)))) { - WL_TRACE(("#### Set SCAN for %s failed with %d\n", g_specific_ssid.SSID, error)); + WL_SCAN(("Set SCAN for %s failed with %d\n", g_specific_ssid.SSID, error)); g_scan_specified_ssid = 0; return -EBUSY; } @@ -3176,14 +3445,16 @@ wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) wlc_ssid_t ssid; iscan_info_t *iscan = g_iscan; +#if defined(CONFIG_FIRST_SCAN) if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_IDLE) { g_first_broadcast_scan = BROADCAST_SCAN_FIRST_STARTED; - WL_TRACE(("%s: First Brodcast scan was forced\n", __FUNCTION__)); + WL_SCAN(("%s: First Brodcast scan was forced\n", __FUNCTION__)); } else if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) { - WL_TRACE(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__)); + WL_SCAN(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__)); return 0; } +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) if (flag) @@ -3193,7 +3464,7 @@ wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &iscan->scan_flag, sizeof(iscan->scan_flag)); wl_iw_set_event_mask(dev); - WL_TRACE(("+++: Set Broadcast ISCAN\n")); + WL_SCAN(("+++: Set Broadcast ISCAN\n")); memset(&ssid, 0, sizeof(ssid)); @@ -3228,7 +3499,7 @@ wl_iw_iscan_set_scan( iscan_info_t *iscan = g_iscan; int ret = 0; - WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev->name)); + WL_SCAN(("%s: SIOCSIWSCAN : ISCAN\n", dev->name)); #if defined(CSCAN) WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__)); @@ -3239,19 +3510,19 @@ wl_iw_iscan_set_scan( #if defined(SOFTAP) if (ap_cfg_running) { - WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); + WL_SCAN(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); goto set_scan_end; } #endif if (g_onoff == G_WLAN_SET_OFF) { - WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + WL_SCAN(("%s: driver is not up yet after START\n", __FUNCTION__)); goto set_scan_end; } #ifdef PNO_SUPPORT if (dhd_dev_get_pno_status(dev)) { - WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__)); + WL_SCAN(("%s: Scan called when PNO is active\n", __FUNCTION__)); } #endif @@ -3261,7 +3532,7 @@ wl_iw_iscan_set_scan( } if (g_scan_specified_ssid) { - WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n", \ + WL_SCAN(("%s Specific SCAN already running ignoring BC scan\n", \ __FUNCTION__)); ret = EBUSY; goto set_scan_end; @@ -3287,14 +3558,14 @@ wl_iw_iscan_set_scan( g_scan_specified_ssid = 0; if (iscan->iscan_state == ISCAN_STATE_SCANING) { - WL_TRACE(("%s ISCAN already in progress \n", __FUNCTION__)); + WL_SCAN(("%s ISCAN already in progress \n", __FUNCTION__)); goto set_scan_end; } } } #endif -#if !defined(CSCAN) +#if defined(CONFIG_FIRST_SCAN) && !defined(CSCAN) if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) { @@ -3457,6 +3728,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, wpa_snprintf_hex(buf + 10, 2+1, &(ie->len), 1); wpa_snprintf_hex(buf + 12, 2*ie->len+1, ie->data, ie->len); event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, buf); + kfree(buf); #endif break; } @@ -3480,6 +3752,7 @@ wl_iw_get_scan_prep( wl_bss_info_t *bi = NULL; char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value; int ret = 0; + int channel; if (!list) { WL_ERROR(("%s: Null list pointer",__FUNCTION__)); @@ -3518,8 +3791,9 @@ wl_iw_get_scan_prep( } iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), - CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? + channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch; + iwe.u.freq.m = wf_channel2mhz(channel, + channel <= CH_MAX_2G_CHANNEL ? WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); iwe.u.freq.e = 6; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); @@ -3596,7 +3870,6 @@ wl_iw_get_scan( return -EINVAL; } - if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) return error; ci.scan_channel = dtoh32(ci.scan_channel); @@ -3766,7 +4039,7 @@ wl_iw_iscan_get_scan( uint buflen_from_user = dwrq->length; #endif - WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length)); + WL_SCAN(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length)); #if defined(SOFTAP) if (ap_cfg_running) { @@ -3780,11 +4053,13 @@ wl_iw_iscan_get_scan( return -EINVAL; } +#if defined(CONFIG_FIRST_SCAN) if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) { WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n", \ dev->name, __FUNCTION__)); return -EAGAIN; } +#endif if ((!iscan) || (iscan->sysioc_pid < 0)) { WL_ERROR(("%ssysioc_pid\n", __FUNCTION__)); @@ -3913,7 +4188,9 @@ wl_iw_iscan_get_scan( wl_iw_run_ss_cache_timer(0); wl_iw_run_ss_cache_timer(1); #endif /* CSCAN */ +#if defined(CONFIG_FIRST_SCAN) g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; +#endif WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter)); @@ -4636,7 +4913,7 @@ wl_iw_set_encodeext( int error; struct iw_encode_ext *iwe; - WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name)); + WL_WSEC(("%s: SIOCSIWENCODEEXT\n", dev->name)); CHECK_EXTRA_FOR_NULL(extra); @@ -4866,7 +5143,7 @@ wl_iw_get_encodeext( char *extra ) { - WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name)); + WL_WSEC(("%s: SIOCGIWENCODEEXT\n", dev->name)); return 0; } @@ -4884,7 +5161,7 @@ wl_iw_set_wpaauth( int val = 0; wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); - WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name)); + WL_WSEC(("%s: SIOCSIWAUTH\n", dev->name)); #if defined(SOFTAP) if (ap_cfg_running) { @@ -4896,7 +5173,7 @@ wl_iw_set_wpaauth( paramid = vwrq->flags & IW_AUTH_INDEX; paramval = vwrq->value; - WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n", + WL_WSEC(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n", dev->name, paramid, paramval)); switch (paramid) { @@ -4912,7 +5189,7 @@ wl_iw_set_wpaauth( #endif else if (paramval & IW_AUTH_WAPI_VERSION_1) val = WPA_AUTH_WAPI; - WL_INFORM(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val)); + WL_WSEC(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val)); if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) return error; break; @@ -4942,24 +5219,28 @@ wl_iw_set_wpaauth( WL_WSEC(("%s: %s: 'Privacy invoked' TRUE but clearing wsec, assuming " "we're a WPS enrollee\n", dev->name, __FUNCTION__)); if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { - WL_WSEC(("Failed to set iovar is_WPS_enrollee\n")); + WL_ERROR(("Failed to set iovar is_WPS_enrollee\n")); return error; } } else if (val) { if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { - WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n")); + WL_ERROR(("Failed to clear iovar is_WPS_enrollee\n")); return error; } } - if ((error = dev_wlc_intvar_set(dev, "wsec", val))) + if ((error = dev_wlc_intvar_set(dev, "wsec", val))) { + WL_ERROR(("Failed to set 'wsec'iovar\n")); return error; + } break; case IW_AUTH_KEY_MGMT: - if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) + if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) { + WL_ERROR(("Failed to get 'wpa_auth'iovar\n")); return error; + } if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { if (paramval & IW_AUTH_KEY_MGMT_PSK) @@ -4977,18 +5258,22 @@ wl_iw_set_wpaauth( #endif if (paramval & (IW_AUTH_KEY_MGMT_WAPI_PSK | IW_AUTH_KEY_MGMT_WAPI_CERT)) val = WPA_AUTH_WAPI; - WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); - if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) + WL_WSEC(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); + if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) { + WL_ERROR(("Failed to set 'wpa_auth'iovar\n")); return error; + } break; case IW_AUTH_TKIP_COUNTERMEASURES: - dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)¶mval, 1); + if ((error = dev_wlc_bufvar_set(dev, "tkip_countermeasures", \ + (char *)¶mval, sizeof(paramval)))) + WL_WSEC(("%s: tkip_countermeasures failed %d\n", __FUNCTION__, error)); break; case IW_AUTH_80211_AUTH_ALG: - WL_INFORM(("Setting the D11auth %d\n", paramval)); + WL_WSEC(("Setting the D11auth %d\n", paramval)); if (paramval == IW_AUTH_ALG_OPEN_SYSTEM) val = 0; else if (paramval == IW_AUTH_ALG_SHARED_KEY) @@ -5005,15 +5290,21 @@ wl_iw_set_wpaauth( if (paramval == 0) { iw->pwsec = 0; iw->gwsec = 0; - if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) + if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) { + WL_ERROR(("Failed to get 'wsec'iovar\n")); return error; + } if (val & (TKIP_ENABLED | AES_ENABLED)) { val &= ~(TKIP_ENABLED | AES_ENABLED); dev_wlc_intvar_set(dev, "wsec", val); } val = 0; - WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); - dev_wlc_intvar_set(dev, "wpa_auth", 0); + + WL_INFORM(("%s: %d: setting wpa_auth to %d\n", + __FUNCTION__, __LINE__, val)); + error = dev_wlc_intvar_set(dev, "wpa_auth", 0); + if (error) + WL_ERROR(("Failed to set 'wpa_auth'iovar\n")); return error; } @@ -5021,11 +5312,17 @@ wl_iw_set_wpaauth( break; case IW_AUTH_DROP_UNENCRYPTED: - dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)¶mval, 1); + error = dev_wlc_bufvar_set(dev, "wsec_restrict", \ + (char *)¶mval, sizeof(paramval)); + if (error) + WL_ERROR(("%s: wsec_restrict %d\n", __FUNCTION__, error)); break; case IW_AUTH_RX_UNENCRYPTED_EAPOL: - dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); + error = dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", \ + (char *)¶mval, sizeof(paramval)); + if (error) + WL_WSEC(("%s: rx_unencrypted_eapol %d\n", __FUNCTION__, error)); break; #if WIRELESS_EXT > 17 @@ -5154,15 +5451,24 @@ wl_iw_get_wpaauth( break; case IW_AUTH_TKIP_COUNTERMEASURES: - dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)¶mval, 1); + error = dev_wlc_bufvar_get(dev, "tkip_countermeasures", \ + (char *)¶mval, sizeof(paramval)); + if (error) + WL_ERROR(("%s get tkip_countermeasures %d\n", __FUNCTION__, error)); break; case IW_AUTH_DROP_UNENCRYPTED: - dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)¶mval, 1); + error = dev_wlc_bufvar_get(dev, "wsec_restrict", \ + (char *)¶mval, sizeof(paramval)); + if (error) + WL_ERROR(("%s get wsec_restrict %d\n", __FUNCTION__, error)); break; case IW_AUTH_RX_UNENCRYPTED_EAPOL: - dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); + error = dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", \ + (char *)¶mval, sizeof(paramval)); + if (error) + WL_ERROR(("%s get rx_unencrypted_eapol %d\n", __FUNCTION__, error)); break; case IW_AUTH_80211_AUTH_ALG: @@ -5391,7 +5697,7 @@ wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nss int i; iscan_info_t *iscan = g_iscan; - WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan)); + WL_SCAN(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan)); if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) { WL_ERROR(("%s error exit\n", __FUNCTION__)); @@ -5537,8 +5843,12 @@ static int iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info return -1; } + if (iscan->iscan_ex_param_size > WLC_IOCTL_MAXLEN) { + WL_ERROR(("%s wrong ex_param_size %d", \ + __FUNCTION__, iscan->iscan_ex_param_size)); + return -1; + } memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size); - ASSERT(iscan->iscan_ex_param_size < WLC_IOCTL_MAXLEN); wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL); @@ -5758,6 +6068,7 @@ wl_iw_set_cscan( goto exit_proc; } +#if defined(CONFIG_FIRST_SCAN) if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) { @@ -5772,6 +6083,7 @@ wl_iw_set_cscan( goto exit_proc; } } +#endif res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); @@ -5787,21 +6099,36 @@ exit_proc: static int thr_wait_for_2nd_eth_dev(void *data) { + struct net_device *dev = (struct net_device *)data; + wl_iw_t *iw; int ret = 0; + unsigned long flags; + + net_os_wake_lock(dev); DAEMONIZE("wl0_eth_wthread"); - WL_TRACE(("\n>%s threda started:, PID:%x\n", __FUNCTION__, current->pid)); + WL_TRACE(("\n>%s thread started:, PID:%x\n", __FUNCTION__, current->pid)); + iw = *(wl_iw_t **)netdev_priv(dev); + if (!iw) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + ret = -1; + goto fail; + } +#ifndef BCMSDIOH_STD if (down_timeout(&ap_eth_sema, msecs_to_jiffies(5000)) != 0) { WL_ERROR(("\n%s: sap_eth_sema timeout \n", __FUNCTION__)); ret = -1; goto fail; } +#endif + flags = dhd_os_spin_lock(iw->pub); if (!ap_net_dev) { WL_ERROR((" ap_net_dev is null !!!")); ret = -1; + dhd_os_spin_unlock(iw->pub, flags); goto fail; } @@ -5810,6 +6137,8 @@ static int thr_wait_for_2nd_eth_dev(void *data) ap_cfg_running = TRUE; + dhd_os_spin_unlock(iw->pub, flags); + bcm_mdelay(500); wl_iw_send_priv_event(priv_dev, "AP_SET_CFG_OK"); @@ -5817,6 +6146,9 @@ static int thr_wait_for_2nd_eth_dev(void *data) fail: WL_TRACE(("\n>%s, thread completed\n", __FUNCTION__)); + net_os_wake_unlock(dev); + + complete_and_exit(&ap_cfg_exited, 0); return ret; } #endif @@ -5931,15 +6263,14 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) #ifdef AP_ONLY if (ap_cfg_running) { - wl_iw_softap_deassoc_stations(dev); + wl_iw_softap_deassoc_stations(dev, NULL); ap_cfg_running = FALSE; } -#endif +#endif if (ap_cfg_running == FALSE) { #ifndef AP_ONLY - sema_init(&ap_eth_sema, 0); mpc = 0; @@ -5972,7 +6303,10 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) iolen = wl_bssiovar_mkbuf("apsta", bsscfg_index, &apsta_var, sizeof(apsta_var)+4, buf, sizeof(buf), &mkvar_err); - ASSERT(iolen); + + if (iolen <= 0) + goto fail; + if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) { WL_ERROR(("%s fail to set apsta \n", __FUNCTION__)); goto fail; @@ -5993,7 +6327,7 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) goto fail; } - res = wl_iw_softap_deassoc_stations(ap_net_dev); + res = wl_iw_softap_deassoc_stations(ap_net_dev, NULL); if ((res = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) { @@ -6002,6 +6336,32 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) } } + if (strlen(ap->country_code)) { + int error = 0; + if ((error = dev_wlc_ioctl(dev, WLC_SET_COUNTRY, + ap->country_code, sizeof(ap->country_code))) >= 0) { + WL_SOFTAP(("%s: set country %s OK\n", + __FUNCTION__, ap->country_code)); + dhd_bus_country_set(dev, &ap->country_code[0]); + } else { + WL_ERROR(("%s: ERROR:%d setting country %s\n", + __FUNCTION__, error, ap->country_code)); + } + } else { + WL_SOFTAP(("%s: Country code is not specified," + " will use Radio's default\n", + __FUNCTION__)); + } + + iolen = wl_bssiovar_mkbuf("closednet", + bsscfg_index, &ap->closednet, sizeof(ap->closednet)+4, + buf, sizeof(buf), &mkvar_err); + ASSERT(iolen); + if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) { + WL_ERROR(("%s failed to set 'closednet'for apsta \n", __FUNCTION__)); + goto fail; + } + if ((ap->channel == 0) && (get_softap_auto_channel(dev, ap) < 0)) { ap->channel = 1; @@ -6050,8 +6410,10 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) goto fail; } if (ap_cfg_running == FALSE) { - kernel_thread(thr_wait_for_2nd_eth_dev, 0, 0); + init_completion(&ap_cfg_exited); + ap_cfg_pid = kernel_thread(thr_wait_for_2nd_eth_dev, dev, 0); } else { + ap_cfg_pid = -1; if (ap_net_dev == NULL) { WL_ERROR(("%s ERROR: ap_net_dev is NULL !!!\n", __FUNCTION__)); goto fail; @@ -6097,8 +6459,9 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) WL_SOFTAP(("wl_iw: set ap profile:\n")); WL_SOFTAP((" ssid = '%s'\n", ap->ssid)); WL_SOFTAP((" security = '%s'\n", ap->sec)); - if (ap->key[0] != '\0') + if (ap->key[0] != '\0') { WL_SOFTAP((" key = '%s'\n", ap->key)); + } WL_SOFTAP((" channel = %d\n", ap->channel)); WL_SOFTAP((" max scb = %d\n", ap->max_scb)); @@ -6199,6 +6562,7 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) if (key_len < WSEC_MAX_PSK_LEN) { unsigned char output[2*SHA1HashSize]; char key_str_buf[WSEC_MAX_PSK_LEN+1]; + bzero(output, 2*SHA1HashSize); WL_SOFTAP(("%s: do passhash...\n", __FUNCTION__)); @@ -6254,7 +6618,6 @@ int get_parmeter_from_string( int parm_str_len; char *param_str_begin; char *param_str_end; - char *orig_str = *str_ptr; if ((*str_ptr) && !strncmp(*str_ptr, token, strlen(token))) { @@ -6311,27 +6674,36 @@ int get_parmeter_from_string( return 0; } else { - WL_ERROR(("\n %s: ERROR: can't find token:%s in str:%s \n", - __FUNCTION__, token, orig_str)); + WL_ERROR(("\n %s: No token:%s in str:%s\n", + __FUNCTION__, token, *str_ptr)); return -1; } } - -static int wl_iw_softap_deassoc_stations(struct net_device *dev) +static int wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac) { int i; int res = 0; char mac_buf[128] = {0}; - struct maclist *assoc_maclist = (struct maclist *)mac_buf; + char z_mac[6] = {0, 0, 0, 0, 0, 0}; + char *sta_mac; + struct maclist *assoc_maclist = (struct maclist *) mac_buf; + bool deauth_all = false; + + if (mac == NULL) { + deauth_all = true; + sta_mac = z_mac; + } else { + sta_mac = mac; + } memset(assoc_maclist, 0, sizeof(mac_buf)); assoc_maclist->count = 8; res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 128); if (res != 0) { - WL_SOFTAP((" Error:%d in :%s, Couldn't get ASSOC List\n", res, __FUNCTION__)); + WL_SOFTAP(("%s: Error:%d Couldn't get ASSOC List\n", __FUNCTION__, res)); return res; } @@ -6342,18 +6714,19 @@ static int wl_iw_softap_deassoc_stations(struct net_device *dev) scbval.val = htod32(1); bcopy(&assoc_maclist->ea[i], &scbval.ea, ETHER_ADDR_LEN); - WL_SOFTAP(("deauth STA:%d \n", i)); - res |= dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, + if (deauth_all || (memcmp(&scbval.ea, sta_mac, ETHER_ADDR_LEN) == 0)) { + WL_SOFTAP(("%s, deauth STA:%d \n", __FUNCTION__, i)); + res |= dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, sizeof(scb_val_t)); + } } } else { WL_SOFTAP((" STA ASSOC list is empty\n")); } - if (res != 0) - WL_SOFTAP((" Error:%d in :%s\n", res, __FUNCTION__)); - else if (assoc_maclist->count) { - + if (res != 0) { + WL_ERROR(("%s: Error:%d\n", __FUNCTION__, res)); + } else if (assoc_maclist->count) { bcm_mdelay(200); } return res; @@ -6378,9 +6751,9 @@ static int iwpriv_softap_stop(struct net_device *dev, if ((ap_cfg_running == TRUE)) { #ifdef AP_ONLY - wl_iw_softap_deassoc_stations(dev); + wl_iw_softap_deassoc_stations(dev, NULL); #else - wl_iw_softap_deassoc_stations(ap_net_dev); + wl_iw_softap_deassoc_stations(ap_net_dev, NULL); if ((res = dev_iw_write_cfg1_bss_var(dev, 2)) < 0) WL_ERROR(("%s failed to del BSS err = %d", __FUNCTION__, res)); @@ -6510,9 +6883,14 @@ iwpriv_en_ap_bss( net_os_wake_lock(dev); - WL_TRACE(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name)); + WL_SOFTAP(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name)); #ifndef AP_ONLY + if (ap_cfg_pid >= 0) { + wait_for_completion(&ap_cfg_exited); + ap_cfg_pid = -1; + } + if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) { WL_ERROR((" %s ERROR setting SOFTAP security in :%d\n", __FUNCTION__, res)); } @@ -6534,84 +6912,108 @@ iwpriv_en_ap_bss( static int get_assoc_sta_list(struct net_device *dev, char *buf, int len) { - WL_TRACE(("calling dev_wlc_ioctl(dev:%p, cmd:%d, buf:%p, len:%d)\n", - dev, WLC_GET_ASSOCLIST, buf, len)); + WL_TRACE(("%s: dev_wlc_ioctl(dev:%p, cmd:%d, buf:%p, len:%d)\n", + __FUNCTION__, dev, WLC_GET_ASSOCLIST, buf, len)); - dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, buf, len); + return dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, buf, len); - return 0; } +void check_error(int res, const char *msg, const char *func, int line) +{ + if (res != 0) + WL_ERROR(("%s, %d function:%s, line:%d\n", msg, res, func, line)); +} + static int -set_ap_mac_list(struct net_device *dev, char *buf) +set_ap_mac_list(struct net_device *dev, void *buf) { struct mac_list_set *mac_list_set = (struct mac_list_set *)buf; - struct maclist *white_maclist = (struct maclist *)&mac_list_set->white_list; - struct maclist *black_maclist = (struct maclist *)&mac_list_set->black_list; - int mac_mode = mac_list_set->mode; + struct maclist *maclist = (struct maclist *)&mac_list_set->mac_list; int length; int i; + int mac_mode = mac_list_set->mode; + int ioc_res = 0; + ap_macmode = mac_list_set->mode; - ap_macmode = mac_mode; - if (mac_mode == MACLIST_MODE_DISABLED) { + bzero(&ap_black_list, sizeof(struct mflist)); - bzero(&ap_black_list, sizeof(struct mflist)); + if (mac_mode == MACLIST_MODE_DISABLED) { - dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); + ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); + check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__); + WL_SOFTAP(("%s: MAC filtering disabled\n", __FUNCTION__)); } else { + scb_val_t scbval; char mac_buf[256] = {0}; struct maclist *assoc_maclist = (struct maclist *) mac_buf; - mac_mode = MACLIST_MODE_ALLOW; + bcopy(maclist, &ap_black_list, sizeof(ap_black_list)); + + ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); + check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__); - dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); + length = sizeof(maclist->count) + maclist->count*ETHER_ADDR_LEN; + dev_wlc_ioctl(dev, WLC_SET_MACLIST, maclist, length); - length = sizeof(white_maclist->count)+white_maclist->count*ETHER_ADDR_LEN; - dev_wlc_ioctl(dev, WLC_SET_MACLIST, white_maclist, length); - WL_SOFTAP(("White List, length %d:\n", length)); - for (i = 0; i < white_maclist->count; i++) + WL_SOFTAP(("%s: applied MAC List, mode:%d, length %d:\n", + __FUNCTION__, mac_mode, length)); + for (i = 0; i < maclist->count; i++) WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n", - i, white_maclist->ea[i].octet[0], white_maclist->ea[i].octet[1], - white_maclist->ea[i].octet[2], - white_maclist->ea[i].octet[3], white_maclist->ea[i].octet[4], - white_maclist->ea[i].octet[5])); + i, maclist->ea[i].octet[0], maclist->ea[i].octet[1], \ + maclist->ea[i].octet[2], \ + maclist->ea[i].octet[3], maclist->ea[i].octet[4], \ + maclist->ea[i].octet[5])); - bcopy(black_maclist, &ap_black_list, sizeof(ap_black_list)); + assoc_maclist->count = 8; + ioc_res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 256); + check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__); + WL_SOFTAP((" Cur assoc clients:%d\n", assoc_maclist->count)); - WL_SOFTAP(("Black List, size %d:\n", sizeof(ap_black_list))); - for (i = 0; i < ap_black_list.count; i++) - WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n", - i, ap_black_list.ea[i].octet[0], ap_black_list.ea[i].octet[1], - ap_black_list.ea[i].octet[2], - ap_black_list.ea[i].octet[3], - ap_black_list.ea[i].octet[4], ap_black_list.ea[i].octet[5])); - - dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 256); - if (assoc_maclist->count) { - int j; + if (assoc_maclist->count) for (i = 0; i < assoc_maclist->count; i++) { - for (j = 0; j < white_maclist->count; j++) { - if (!bcmp(&assoc_maclist->ea[i], &white_maclist->ea[j], + int j; + bool assoc_mac_matched = false; + + WL_SOFTAP(("\n Cheking assoc STA: ")); + print_buf(&assoc_maclist->ea[i], 6, 7); + WL_SOFTAP(("with the b/w list:")); + + for (j = 0; j < maclist->count; j++) + if (!bcmp(&assoc_maclist->ea[i], &maclist->ea[j], ETHER_ADDR_LEN)) { - WL_SOFTAP(("match allow, let it be\n")); + + assoc_mac_matched = true; break; } - } - if (j == white_maclist->count) { - WL_SOFTAP(("match black, deauth it\n")); - scbval.val = htod32(1); - bcopy(&assoc_maclist->ea[i], &scbval.ea, + + if (((mac_mode == MACLIST_MODE_ALLOW) && !assoc_mac_matched) || + ((mac_mode == MACLIST_MODE_DENY) && assoc_mac_matched)) { + + WL_SOFTAP(("b-match or w-mismatch," + " do deauth/disassoc \n")); + scbval.val = htod32(1); + bcopy(&assoc_maclist->ea[i], &scbval.ea, \ ETHER_ADDR_LEN); - dev_wlc_ioctl(dev, - WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, - sizeof(scb_val_t)); + ioc_res = dev_wlc_ioctl(dev, + WLC_SCB_DEAUTHENTICATE_FOR_REASON, + &scbval, sizeof(scb_val_t)); + check_error(ioc_res, + "ioctl ERROR:", + __FUNCTION__, __LINE__); + + } else { + WL_SOFTAP((" no b/w list hits, let it be\n")); } - } + } else { + WL_SOFTAP(("No ASSOC CLIENTS\n")); } - } - return 0; + } + + WL_SOFTAP(("%s iocres:%d\n", __FUNCTION__, ioc_res)); + return ioc_res; } #endif @@ -6744,22 +7146,26 @@ static int wl_iw_set_priv( ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, "STOP", strlen("STOP")) == 0) ret = wl_iw_control_wl_off(dev, info); - else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0) + else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0) ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0) + else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0) ret = wl_iw_set_band(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0) + else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0) ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0) + else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0) ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0) + else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0) ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra); +#ifdef CONFIG_US_NON_DFS_CHANNELS_ONLY + else if (strnicmp(extra, SETDFSCHANNELS_CMD, strlen(SETDFSCHANNELS_CMD)) == 0) + ret = wl_iw_set_dfs_channels(dev, info, (union iwreq_data *)dwrq, extra); +#endif #if defined(PNO_SUPPORT) - else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0) + else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0) ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0) + else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0) ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0) + else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0) ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra); #endif #if defined(CSCAN) @@ -6816,7 +7222,7 @@ static const iw_handler wl_iw_handler[] = (iw_handler) wl_iw_get_freq, (iw_handler) wl_iw_set_mode, (iw_handler) wl_iw_get_mode, - (iw_handler) NULL, + (iw_handler) NULL, (iw_handler) wl_iw_get_wext_rssi, (iw_handler) NULL, (iw_handler) wl_iw_get_range, @@ -6926,6 +7332,9 @@ static const iw_handler wl_iw_priv_handler[] = { NULL, (iw_handler)iwpriv_fw_reload, + + NULL, + (iw_handler)iwpriv_set_ap_sta_disassoc, #endif #if defined(CSCAN) @@ -6988,8 +7397,8 @@ static const struct iw_priv_args wl_iw_priv_args[] = { { WL_AP_STA_LIST, - 0, IW_PRIV_TYPE_CHAR | 0, + IW_PRIV_TYPE_CHAR | 1024, "AP_GET_STA_LIST" }, @@ -7027,6 +7436,13 @@ static const struct iw_priv_args wl_iw_priv_args[] = { IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, "WL_FW_RELOAD" }, + + { + WL_AP_STA_DISASSOC, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 0, + "AP_STA_DISASSOC" + }, #endif #if defined(CSCAN) { @@ -7304,6 +7720,12 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) WL_TRACE(("%s: dev=%s event=%d \n", __FUNCTION__, dev->name, event_type)); switch (event_type) { + + case WLC_E_RELOAD: + WL_ERROR(("%s: Firmware ERROR %d\n", __FUNCTION__, status)); + net_os_send_hang_message(dev); + goto wl_iw_event_end; + #if defined(SOFTAP) case WLC_E_PRUNE: if (ap_cfg_running) { @@ -7354,10 +7776,14 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) cmd = IWEVREGISTERED; break; case WLC_E_ROAM: - if (status != WLC_E_STATUS_SUCCESS) { + if (status == WLC_E_STATUS_SUCCESS) { + memcpy(wrqu.addr.sa_data, &e->addr.octet, ETHER_ADDR_LEN); + wrqu.addr.sa_family = ARPHRD_ETHER; + cmd = SIOCGIWAP; + } + else if (status == WLC_E_STATUS_NO_NETWORKS) { roam_no_success++; - if ((roam_no_success == 3) && (roam_no_success_send == FALSE)) { - + if ((roam_no_success == 5) && (roam_no_success_send == FALSE)) { roam_no_success_send = TRUE; bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); bzero(&extra, ETHER_ADDR_LEN); @@ -7368,10 +7794,6 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) WL_TRACE(("##### ROAMING did not succeeded %d\n", roam_no_success)); goto wl_iw_event_end; } - } else { - memcpy(wrqu.addr.sa_data, &e->addr.octet, ETHER_ADDR_LEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - cmd = SIOCGIWAP; } break; case WLC_E_DEAUTH_IND: @@ -7660,13 +8082,21 @@ wl_iw_bt_flag_set( struct net_device *dev, bool set) { +#if defined(BT_DHCP_USE_FLAGS) char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_lock(); #endif +#if defined(BT_DHCP_eSCO_FIX) + set_btc_esco_params(dev, set); +#endif + +#if defined(BT_DHCP_USE_FLAGS) + WL_TRACE_COEX(("WI-FI priority boost via bt flags, set:%d\n", set)); if (set == TRUE) { dev_wlc_bufvar_set(dev, "btc_flags", (char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on)); @@ -7675,6 +8105,7 @@ wl_iw_bt_flag_set( dev_wlc_bufvar_set(dev, "btc_flags", (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); } +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_unlock(); @@ -7707,14 +8138,23 @@ _bt_dhcp_sysioc_thread(void *data) switch (g_bt->bt_state) { case BT_DHCP_START: + WL_TRACE_COEX(("%s bt_dhcp stm: started \n", __FUNCTION__)); g_bt->bt_state = BT_DHCP_OPPORTUNITY_WINDOW; - mod_timer(&g_bt->timer, jiffies + BT_DHCP_OPPORTUNITY_WINDOW_TIEM*HZ/1000); + mod_timer(&g_bt->timer, jiffies + BT_DHCP_OPPORTUNITY_WINDOW_TIME*HZ/1000); g_bt->timer_on = 1; break; case BT_DHCP_OPPORTUNITY_WINDOW: - WL_TRACE(("%s waiting for %d msec expired, force bt flag\n", \ - __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIEM)); + if (g_bt->dhcp_done) { + WL_TRACE_COEX(("%s DHCP Done before T1 expiration\n", \ + __FUNCTION__)); + g_bt->bt_state = BT_DHCP_IDLE; + g_bt->timer_on = 0; + break; + } + + WL_TRACE_COEX(("%s DHCP T1:%d expired\n", \ + __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIME)); if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, TRUE); g_bt->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; mod_timer(&g_bt->timer, jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000); @@ -7722,9 +8162,14 @@ _bt_dhcp_sysioc_thread(void *data) break; case BT_DHCP_FLAG_FORCE_TIMEOUT: - WL_TRACE(("%s waiting for %d msec expired remove bt flag\n", \ + if (g_bt->dhcp_done) { + WL_TRACE_COEX(("%s DHCP Done before T2 expiration\n", \ + __FUNCTION__)); + } else { + WL_TRACE_COEX(("%s DHCP wait interval T2:%d msec expired\n", __FUNCTION__, BT_DHCP_FLAG_FORCE_TIME)); - + } + if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE); g_bt->bt_state = BT_DHCP_IDLE; g_bt->timer_on = 0; @@ -7835,9 +8280,11 @@ int wl_iw_attach(struct net_device *dev, void *dhdp) g_iscan = iscan; iscan->dev = dev; iscan->iscan_state = ISCAN_STATE_IDLE; +#if defined(CONFIG_FIRST_SCAN) g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; g_first_counter_scans = 0; g_iscan->scan_flag = 0; +#endif iscan->timer_ms = 8000; init_timer(&iscan->timer); @@ -7912,5 +8359,4 @@ void wl_iw_detach(void) wl_iw_send_priv_event(priv_dev, "AP_DOWN"); } #endif - } diff --git a/drivers/net/wireless/bcm4329/wl_iw.h b/drivers/net/wireless/bcm4329/wl_iw.h index 43088cf886bd..928291fe589a 100644 --- a/drivers/net/wireless/bcm4329/wl_iw.h +++ b/drivers/net/wireless/bcm4329/wl_iw.h @@ -21,7 +21,7 @@ * 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: wl_iw.h,v 1.5.34.1.6.36.4.1 2010/09/10 19:24:30 Exp $ + * $Id: wl_iw.h,v 1.5.34.1.6.36.4.15 2010/11/17 03:13:51 Exp $ */ @@ -52,6 +52,7 @@ #define PNOSETUP_SET_CMD "PNOSETUP " #define PNOENABLE_SET_CMD "PNOFORCE" #define PNODEBUG_SET_CMD "PNODEBUG" +#define SETDFSCHANNELS_CMD "SETDFSCHANNELS" #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" @@ -87,8 +88,9 @@ typedef struct wl_iw_extra_params { #define AP_LPB_CMD (SIOCIWFIRSTPRIV+23) #define WL_AP_STOP (SIOCIWFIRSTPRIV+25) #define WL_FW_RELOAD (SIOCIWFIRSTPRIV+27) -#define WL_COMBO_SCAN (SIOCIWFIRSTPRIV+29) -#define WL_AP_SPARE3 (SIOCIWFIRSTPRIV+31) +#define WL_AP_STA_DISASSOC (SIOCIWFIRSTPRIV+29) +#define WL_COMBO_SCAN (SIOCIWFIRSTPRIV+31) + #define G_SCAN_RESULTS (8*1024) #define WE_ADD_EVENT_FIX 0x80 #define G_WLAN_SET_ON 0 @@ -116,19 +118,18 @@ typedef struct wl_iw { dhd_pub_t * pub; } wl_iw_t; -#define WLC_IW_SS_CACHE_MAXLEN 512 +#define WLC_IW_SS_CACHE_MAXLEN 2048 #define WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN 32 #define WLC_IW_BSS_INFO_MAXLEN \ (WLC_IW_SS_CACHE_MAXLEN - WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN) typedef struct wl_iw_ss_cache { + struct wl_iw_ss_cache *next; + int dirty; uint32 buflen; uint32 version; uint32 count; wl_bss_info_t bss_info[1]; - char dummy[WLC_IW_BSS_INFO_MAXLEN - sizeof(wl_bss_info_t)]; - int dirty; - struct wl_iw_ss_cache *next; } wl_iw_ss_cache_t; typedef struct wl_iw_ss_cache_ctrl { @@ -140,6 +141,7 @@ typedef struct wl_iw_ss_cache_ctrl { uint m_cons_br_scan_cnt; struct timer_list *m_timer; } wl_iw_ss_cache_ctrl_t; + typedef enum broadcast_first_scan { BROADCAST_SCAN_FIRST_IDLE = 0, BROADCAST_SCAN_FIRST_STARTED, @@ -158,12 +160,14 @@ struct ap_profile { uint32 channel; uint32 preamble; uint32 max_scb; + uint32 closednet; + char country_code[WLC_CNTRY_BUF_SZ]; }; #define MACLIST_MODE_DISABLED 0 -#define MACLIST_MODE_ENABLED 1 -#define MACLIST_MODE_ALLOW 2 +#define MACLIST_MODE_DENY 1 +#define MACLIST_MODE_ALLOW 2 struct mflist { uint count; struct ether_addr ea[16]; @@ -171,8 +175,7 @@ struct mflist { struct mac_list_set { uint32 mode; - struct mflist white_list; - struct mflist black_list; + struct mflist mac_list; }; #endif @@ -196,7 +199,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 net_os_set_dtim_skip(struct net_device *dev, int val); extern int net_os_set_packet_filter(struct net_device *dev, int val); -extern int net_os_send_hang_message(struct net_device *dev); +extern void dhd_bus_country_set(struct net_device *dev, char *country_code); +extern char *dhd_bus_country_get(struct net_device *dev); +extern int dhd_get_dtim_skip(dhd_pub_t *dhd); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) #define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ @@ -225,12 +230,13 @@ extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); extern int dhd_dev_get_pno_status(struct net_device *dev); #define PNO_TLV_PREFIX 'S' -#define PNO_TLV_VERSION 1 -#define PNO_TLV_SUBVERSION 1 -#define PNO_TLV_RESERVED 0 +#define PNO_TLV_VERSION '1' +#define PNO_TLV_SUBVERSION '2' +#define PNO_TLV_RESERVED '0' #define PNO_TLV_TYPE_SSID_IE 'S' #define PNO_TLV_TYPE_TIME 'T' #define PNO_EVENT_UP "PNO_EVENT" +#define PNO_SCAN_MAX_FW 508 typedef struct cmd_tlv { char prefix; -- 2.34.1