diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2010-12-13 10:14:41 -0800 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2010-12-13 10:14:41 -0800 |
commit | 65cd10f45530f4fec55626eea045ca1687caada2 (patch) | |
tree | 0aab48b17ea333a63e2d0e7cf46c4bc8730296f0 /bcm4329 | |
parent | 18a209f7ff1acb82ed370c5853369e5eb454fb06 (diff) | |
download | hardware_broadcom_wlan-65cd10f45530f4fec55626eea045ca1687caada2.zip hardware_broadcom_wlan-65cd10f45530f4fec55626eea045ca1687caada2.tar.gz hardware_broadcom_wlan-65cd10f45530f4fec55626eea045ca1687caada2.tar.bz2 |
bcm4329: Update to Version 4.218.248-17
=== Firmware ============
1) Increase internal Memory Heap for dual-band STA
2) Fix problem with PNO for -minioctl- firmware flavor
3) Fix SoftAP white list MAC filtering
4) Fix problem with timer for 11N/AMPDU
5) Added FW flavor "sdio-ag-cdc-full11n-minioctl-roml-wme-aoe-pktfilter-keepalive.bin" (w/o PNO)
=== Driver ============
1) Add CONFIG_FIRST_SCAN option with special CONFIG_FIRST_SCAN compilation flag
2) Fix SoftAP white list MAC filtering
3) Fix watchdog synchronization during start/stop
Change-Id: Icc470d9b18fd86f928abdef5cfdad4031a8e3b3e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'bcm4329')
-rw-r--r-- | bcm4329/firmware/fw_bcm4329.bin | bin | 249144 -> 249060 bytes | |||
-rw-r--r-- | bcm4329/firmware/fw_bcm4329_abg.bin | bin | 266219 -> 263547 bytes | |||
-rw-r--r-- | bcm4329/firmware/fw_bcm4329_apsta.bin | bin | 249503 -> 249371 bytes | |||
-rw-r--r-- | bcm4329/src/bcmsdio/linux/Makefile | 2 | ||||
-rw-r--r-- | bcm4329/src/bcmsdio/sys/bcmsdh_linux.c | 5 | ||||
-rw-r--r-- | bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c | 1 | ||||
-rw-r--r-- | bcm4329/src/dhd/linux/Makefile | 4 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd.h | 16 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_bus.h | 4 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_common.c | 137 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_linux.c | 266 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_sdio.c | 94 | ||||
-rw-r--r-- | bcm4329/src/include/epivers.h | 10 | ||||
-rw-r--r-- | bcm4329/src/include/proto/bcmevent.h | 11 | ||||
-rw-r--r-- | bcm4329/src/include/wlioctl.h | 3 | ||||
-rw-r--r-- | bcm4329/src/wl/sys/wl_iw.c | 1076 | ||||
-rw-r--r-- | bcm4329/src/wl/sys/wl_iw.h | 36 |
17 files changed, 1174 insertions, 491 deletions
diff --git a/bcm4329/firmware/fw_bcm4329.bin b/bcm4329/firmware/fw_bcm4329.bin Binary files differindex a9bf2b7..1418c79 100644 --- a/bcm4329/firmware/fw_bcm4329.bin +++ b/bcm4329/firmware/fw_bcm4329.bin diff --git a/bcm4329/firmware/fw_bcm4329_abg.bin b/bcm4329/firmware/fw_bcm4329_abg.bin Binary files differindex 8cf8423..928308f 100644 --- a/bcm4329/firmware/fw_bcm4329_abg.bin +++ b/bcm4329/firmware/fw_bcm4329_abg.bin diff --git a/bcm4329/firmware/fw_bcm4329_apsta.bin b/bcm4329/firmware/fw_bcm4329_apsta.bin Binary files differindex 74b70da..a84bc8c 100644 --- a/bcm4329/firmware/fw_bcm4329_apsta.bin +++ b/bcm4329/firmware/fw_bcm4329_apsta.bin diff --git a/bcm4329/src/bcmsdio/linux/Makefile b/bcm4329/src/bcmsdio/linux/Makefile index 41ed016..0b507ff 100644 --- a/bcm4329/src/bcmsdio/linux/Makefile +++ b/bcm4329/src/bcmsdio/linux/Makefile @@ -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: Makefile,v 1.5.8.4.6.1 2009/01/26 20:28:33 Exp $ +# $Id: Makefile,v 1.5.8.4.6.2 2010/04/09 23:54:38 Exp $ # # Try a couple of places for LINUXDIR if not specified diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c index 559f481..3b7da42 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c @@ -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) { diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c index bda9193..031367b 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c +++ b/bcm4329/src/bcmsdio/sys/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/bcm4329/src/dhd/linux/Makefile b/bcm4329/src/dhd/linux/Makefile index 4d5a957..224b41e 100644 --- a/bcm4329/src/dhd/linux/Makefile +++ b/bcm4329/src/dhd/linux/Makefile @@ -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: Makefile,v 1.55.2.6.2.10.6.42 2010/08/20 00:15:16 Exp $ +# $Id: Makefile,v 1.55.2.6.2.10.6.42.4.2 2010/12/02 01:23:07 Exp $ # # Try a couple of places for LINUXDIR if not specified @@ -237,7 +237,9 @@ DFLAGS += -DCUSTOM_OOB_GPIO_NUM=152 DFLAGS += -DOOB_INTR_ONLY DFLAGS += -DMMC_SDIO_ABORT DFLAGS += -DSOFTAP +DFLAGS += -DKEEP_ALIVE DFLAGS += -DPNO_SUPPORT +DFLAGS += -DCONFIG_FIRST_SCAN else ifneq ($(findstring -oob-,-$(TARGET)-),) DFLAGS += -DOOB_INTR_ONLY diff --git a/bcm4329/src/dhd/sys/dhd.h b/bcm4329/src/dhd/sys/dhd.h index cc7e8cb..1ddf1ff 100644 --- a/bcm4329/src/dhd/sys/dhd.h +++ b/bcm4329/src/dhd/sys/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 { @@ -218,6 +220,11 @@ extern int dhd_os_wake_unlock(dhd_pub_t *pub); extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); 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; uint8 action; @@ -345,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 */ @@ -396,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/bcm4329/src/dhd/sys/dhd_bus.h b/bcm4329/src/dhd/sys/dhd_bus.h index 9e29fb9..97af41b 100644 --- a/bcm4329/src/dhd/sys/dhd_bus.h +++ b/bcm4329/src/dhd/sys/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/bcm4329/src/dhd/sys/dhd_common.c b/bcm4329/src/dhd/sys/dhd_common.c index bea33b6..b8bab30 100644 --- a/bcm4329/src/dhd/sys/dhd_common.c +++ b/bcm4329/src/dhd/sys/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.16 2010/11/18 03:53:32 Exp $ */ #include <typedefs.h> #include <osl.h> @@ -71,6 +71,11 @@ 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(KEEP_ALIVE) +extern bool ap_fw_loaded; +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 @@ -1225,8 +1230,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint bcn_timeout = 3; int scan_assoc_time = 40; int scan_unassoc_time = 40; + uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ + int ret = 0; #ifdef GET_CUSTOM_MAC_ENABLE - int ret; struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ @@ -1253,7 +1259,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(); @@ -1284,6 +1289,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; @@ -1392,6 +1402,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; @@ -1446,7 +1469,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) { @@ -1779,6 +1802,57 @@ fail: #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) { @@ -1885,6 +1959,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)); @@ -1909,6 +1988,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)); } @@ -1930,6 +2012,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 */ diff --git a/bcm4329/src/dhd/sys/dhd_linux.c b/bcm4329/src/dhd/sys/dhd_linux.c index f687b31..c7ef3ed 100644 --- a/bcm4329/src/dhd/sys/dhd_linux.c +++ b/bcm4329/src/dhd/sys/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 @@ -106,7 +106,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); } @@ -117,7 +117,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) { @@ -217,9 +217,10 @@ print_tainted() #include <wl_iw.h> #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 <linux/earlysuspend.h> -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 @@ -260,6 +261,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; @@ -279,8 +282,10 @@ typedef struct dhd_info { int wl_count; int wl_packet; - int hang_was_sent; - + 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; @@ -304,7 +309,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); @@ -518,6 +523,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) { @@ -536,7 +543,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)); @@ -544,26 +551,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, @@ -572,11 +577,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)); @@ -898,13 +903,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 */ @@ -939,13 +949,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)); @@ -974,8 +983,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 */ } } @@ -987,16 +998,21 @@ _dhd_sysioc_thread(void *data) int i; #ifdef SOFTAP bool in_ap = FALSE; + unsigned long flags; #endif DAEMONIZE("dhd_sysioc"); while (down_interruptible(&dhd->sysioc_sem) == 0) { + dhd_os_start_lock(&dhd->pub); dhd_os_wake_lock(&dhd->pub); for (i = 0; i < DHD_MAX_IFS; i++) { 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]); @@ -1029,7 +1045,9 @@ _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); } @@ -1042,6 +1060,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr) struct sockaddr *sa = (struct sockaddr *)addr; int ifidx; + DHD_TRACE(("%s: Enter\n",__FUNCTION__)); ifidx = dhd_net2idx(dhd, dev); if (ifidx == DHD_BAD_IF) return -1; @@ -1060,6 +1079,7 @@ dhd_set_multicast_list(struct net_device *dev) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); int ifidx; + DHD_TRACE(("%s: Enter\n",__FUNCTION__)); ifidx = dhd_net2idx(dhd, dev); if (ifidx == DHD_BAD_IF) return; @@ -1379,22 +1399,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); @@ -1406,11 +1428,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); @@ -1420,6 +1448,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); } @@ -1844,7 +1873,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; } @@ -1869,7 +1898,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)); @@ -1879,7 +1909,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); @@ -2037,6 +2066,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); @@ -2046,7 +2076,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; @@ -2175,8 +2207,8 @@ dhd_bus_start(dhd_pub_t *dhdp) #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__)); return -ENODEV; } @@ -2187,8 +2219,8 @@ 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__)); return -ENODEV; } @@ -2216,6 +2248,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 */ @@ -2353,6 +2386,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 */ @@ -2360,6 +2394,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)) @@ -2396,8 +2431,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); } } } @@ -2423,16 +2458,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)) @@ -2661,29 +2698,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); } } @@ -2897,20 +2933,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) @@ -3021,6 +3055,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) { @@ -3203,16 +3288,21 @@ int net_os_wake_unlock(struct net_device *dev) return ret; } -int net_os_send_hang_message(struct net_device *dev) +unsigned long dhd_os_spin_lock(dhd_pub_t *pub) { - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags = 0; - if (dhd) { - if (!dhd->hang_was_sent) { - dhd->hang_was_sent = 1; - ret = wl_iw_send_priv_event(dev, "HANG"); - } - } - return ret; + if (dhd) + spin_lock_irqsave(&dhd->dhd_lock, flags); + + return flags; +} + +void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) + spin_unlock_irqrestore(&dhd->dhd_lock, flags); } diff --git a/bcm4329/src/dhd/sys/dhd_sdio.c b/bcm4329/src/dhd/sys/dhd_sdio.c index ff1bded..ac46ca9 100644 --- a/bcm4329/src/dhd/sys/dhd_sdio.c +++ b/bcm4329/src/dhd/sys/dhd_sdio.c @@ -438,7 +438,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 +705,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 +718,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 +727,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 +760,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 @@ -2719,6 +2723,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 +2734,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 +2786,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 +2878,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 +4637,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 +4706,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) } } - dhd_os_sdunlock(bus->dhd); - return bus->ipend; } @@ -5299,7 +5301,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 +5345,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 +5799,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 +5842,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/bcm4329/src/include/epivers.h b/bcm4329/src/include/epivers.h index 92dc326..6d5adf2 100644 --- a/bcm4329/src/include/epivers.h +++ b/bcm4329/src/include/epivers.h @@ -33,16 +33,16 @@ #define EPI_RC_NUMBER 248 -#define EPI_INCREMENTAL_NUMBER 6 +#define EPI_INCREMENTAL_NUMBER 17 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 4, 218, 248, 6 +#define EPI_VERSION 4, 218, 248, 17 -#define EPI_VERSION_NUM 0x04daf806 +#define EPI_VERSION_NUM 0x04daf811 -#define EPI_VERSION_STR "4.218.248.6" -#define EPI_ROUTER_VERSION_STR "4.219.248.6" +#define EPI_VERSION_STR "4.218.248.17" +#define EPI_ROUTER_VERSION_STR "4.219.248.17" #endif diff --git a/bcm4329/src/include/proto/bcmevent.h b/bcm4329/src/include/proto/bcmevent.h index 46c04d3..1f8ecb1 100644 --- a/bcm4329/src/include/proto/bcmevent.h +++ b/bcm4329/src/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 <packed_section_end.h> diff --git a/bcm4329/src/include/wlioctl.h b/bcm4329/src/include/wlioctl.h index 345ba34..cd7725a 100644 --- a/bcm4329/src/include/wlioctl.h +++ b/bcm4329/src/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/bcm4329/src/wl/sys/wl_iw.c b/bcm4329/src/wl/sys/wl_iw.c index 2cd629c..8adf2d8 100644 --- a/bcm4329/src/wl/sys/wl_iw.c +++ b/bcm4329/src/wl/sys/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.61 2010/12/03 22:09:41 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 <wl_iw.h> @@ -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) \ @@ -109,10 +112,13 @@ static int wl_iw_softap_deassoc_stations(struct net_device *dev); } while (0) static int g_onoff = G_WLAN_SET_ON; -wl_iw_extra_params_t g_wl_iw_params; -static struct mutex wl_start_lock; +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 <bcmsdbus.h> @@ -161,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)) @@ -184,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 @@ -219,6 +229,11 @@ typedef struct iscan_info { int iscan_ex_param_size; } iscan_info_t; #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); @@ -228,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; @@ -606,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( @@ -627,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; @@ -664,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"); @@ -697,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) { + 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, @@ -752,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); @@ -764,44 +917,37 @@ 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))) { + saved_status = TRUE; + 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 + 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)); + + if (btcoex_is_sco_active(dev)) { + 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__)); @@ -812,16 +958,22 @@ 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", \ @@ -837,11 +989,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"); @@ -881,6 +1037,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) { @@ -1063,7 +1235,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"); @@ -1165,15 +1336,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', @@ -1181,8 +1352,8 @@ wl_iw_set_pno_set( 0x04, 'G', 'O', 'O', 'G', 'T', - 0x00, - 0x0A + '1','E', + 0x00 }; #endif @@ -1239,29 +1410,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 { @@ -1300,19 +1457,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); @@ -1348,6 +1510,7 @@ int wl_control_wl_start(struct net_device *dev) { int ret = 0; + wl_iw_t *iw; WL_TRACE(("Enter %s \n", __FUNCTION__)); @@ -1356,7 +1519,13 @@ wl_control_wl_start(struct net_device *dev) return -1; } - mutex_lock(&wl_start_lock); + 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) { dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); @@ -1365,19 +1534,19 @@ 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__)); - mutex_unlock(&wl_start_lock); + dhd_os_start_unlock(iw->pub); return ret; } @@ -1389,6 +1558,8 @@ wl_iw_control_wl_off( ) { int ret = 0; + wl_iw_t *iw; + WL_TRACE(("Enter %s\n", __FUNCTION__)); if (!dev) { @@ -1396,7 +1567,12 @@ wl_iw_control_wl_off( return -1; } - mutex_lock(&wl_start_lock); + 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 ap_cfg_running = FALSE; @@ -1419,10 +1595,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); @@ -1435,7 +1612,7 @@ wl_iw_control_wl_off( wl_iw_send_priv_event(dev, "STOP"); } - mutex_unlock(&wl_start_lock); + dhd_os_start_unlock(iw->pub); WL_TRACE(("Exited %s\n", __FUNCTION__)); @@ -1452,7 +1629,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"); @@ -1473,7 +1658,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 @@ -1555,9 +1740,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; } @@ -1574,7 +1763,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)); @@ -1628,52 +1818,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; + + bzero(&scb_val, sizeof(scb_val_t)); - WL_SOFTAP(("dhd_drv>> sta_mac[%d] :", i)); - print_buf((unsigned char *)&sta_maclist->ea[i], 6, 0); + 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; } @@ -1681,19 +1905,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)); @@ -1713,25 +1938,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; } @@ -1740,19 +1961,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; @@ -1768,8 +1993,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 { @@ -2296,7 +2557,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))) { @@ -2305,7 +2566,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)); } @@ -2411,7 +2672,7 @@ wl_iw_get_aplist( list->version = dtoh32(list->version); list->count = dtoh32(list->count); if (list->version != WL_BSS_INFO_VERSION) { - WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ + WL_ERROR(("%s: list->version %d != WL_BSS_INFO_VERSION\n", \ __FUNCTION__, list->version)); kfree(list); return -EINVAL; @@ -2419,21 +2680,23 @@ wl_iw_get_aplist( for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; - ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + - buflen)); - + if ((dtoh32(bi->length) > buflen) || + (((uintptr)bi + dtoh32(bi->length)) > ((uintptr)list + buflen))) { + WL_ERROR(("%s: Scan results out of bounds: %u\n",__FUNCTION__,dtoh32(bi->length))); + kfree(list); + return -E2BIG; + } + if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) continue; - memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); addr[dwrq->length].sa_family = ARPHRD_ETHER; qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); qual[dwrq->length].noise = 0x100 + bi->phy_noise; - #if WIRELESS_EXT > 18 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; #else @@ -2496,21 +2759,22 @@ wl_iw_iscan_get_aplist( for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; - ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + - WLC_IW_ISCAN_MAXLEN)); - + if ((dtoh32(bi->length) > WLC_IW_ISCAN_MAXLEN) || + (((uintptr)bi + dtoh32(bi->length)) > ((uintptr)list + WLC_IW_ISCAN_MAXLEN))) { + WL_ERROR(("%s: Scan results out of bounds: %u\n",__FUNCTION__,dtoh32(bi->length))); + return -E2BIG; + } + if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) continue; - memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); addr[dwrq->length].sa_family = ARPHRD_ETHER; qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); qual[dwrq->length].noise = 0x100 + bi->phy_noise; - #if WIRELESS_EXT > 18 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; #else @@ -2542,7 +2806,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); @@ -2569,7 +2836,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)); @@ -2672,7 +2938,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 @@ -2690,9 +2956,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 } @@ -2997,7 +3265,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, @@ -3087,14 +3355,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; } @@ -3112,7 +3382,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; } @@ -3127,14 +3397,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) @@ -3144,7 +3416,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)); @@ -3179,7 +3451,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__)); @@ -3190,19 +3462,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 @@ -3212,7 +3484,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; @@ -3238,14 +3510,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) { @@ -3431,8 +3703,12 @@ 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; - ASSERT(list); + if (!list) { + WL_ERROR(("%s: Null list pointer",__FUNCTION__)); + return ret; + } for (i = 0; i < list->count && i < IW_MAX_AP; i++) { @@ -3440,7 +3716,7 @@ wl_iw_get_scan_prep( WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ __FUNCTION__, list->version)); return ret; - } + } bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; @@ -3456,7 +3732,6 @@ wl_iw_get_scan_prep( iwe.u.data.flags = 1; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); - if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { iwe.cmd = SIOCGIWMODE; if (dtoh16(bi->capability) & DOT11_CAP_ESS) @@ -3466,15 +3741,14 @@ wl_iw_get_scan_prep( event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); } - 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); - iwe.cmd = IWEVQUAL; iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); @@ -3491,7 +3765,6 @@ wl_iw_get_scan_prep( iwe.u.data.length = 0; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); - if (bi->rateset.count) { if (((event -extra) + IW_EV_LCP_LEN) <= (uintptr)end) { value = event + IW_EV_LCP_LEN; @@ -3548,7 +3821,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); @@ -3718,7 +3990,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) { @@ -3732,11 +4004,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__)); @@ -3783,26 +4057,27 @@ wl_iw_iscan_get_scan( bi = NULL; for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) { bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; - ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + - WLC_IW_ISCAN_MAXLEN)); - + if ((dtoh32(bi->length) > WLC_IW_ISCAN_MAXLEN) || + (((uintptr)bi + dtoh32(bi->length)) > ((uintptr)list + WLC_IW_ISCAN_MAXLEN))) { + WL_ERROR(("%s: Scan results out of bounds: %u\n",__FUNCTION__,dtoh32(bi->length))); + return -E2BIG; + } + if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >= end) return -E2BIG; - + iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); - iwe.u.data.length = dtoh32(bi->SSID_len); iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); - if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { iwe.cmd = SIOCGIWMODE; if (dtoh16(bi->capability) & DOT11_CAP_ESS) @@ -3812,7 +4087,6 @@ wl_iw_iscan_get_scan( event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); } - iwe.cmd = SIOCGIWFREQ; channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch; iwe.u.freq.m = wf_channel2mhz(channel, @@ -3821,17 +4095,14 @@ wl_iw_iscan_get_scan( iwe.u.freq.e = 6; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); - iwe.cmd = IWEVQUAL; iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); iwe.u.qual.noise = 0x100 + bi->phy_noise; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); - wl_iw_handle_scanresults_ies(&event, end, info, bi); - iwe.cmd = SIOCGIWENCODE; if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; @@ -3840,7 +4111,6 @@ wl_iw_iscan_get_scan( iwe.u.data.length = 0; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); - if (bi->rateset.count) { if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) return -E2BIG; @@ -3869,7 +4139,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)); @@ -4592,7 +4864,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); @@ -4822,7 +5094,7 @@ wl_iw_get_encodeext( char *extra ) { - WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name)); + WL_WSEC(("%s: SIOCGIWENCODEEXT\n", dev->name)); return 0; } @@ -4840,7 +5112,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) { @@ -4852,7 +5124,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) { @@ -4868,7 +5140,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; @@ -4898,24 +5170,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) @@ -4933,18 +5209,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) @@ -4961,15 +5241,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; } @@ -4977,11 +5263,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 @@ -5110,15 +5402,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: @@ -5347,7 +5648,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__)); @@ -5379,7 +5680,6 @@ wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nss p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16); } - iscan->iscan_ex_params_p->params.channel_num = \ htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | \ (nchan & WL_SCAN_PARAMS_COUNT_MASK)); @@ -5388,7 +5688,6 @@ wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nss (uint)((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) & \ WL_SCAN_PARAMS_COUNT_MASK); - params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t)); iscan->iscan_ex_param_size = params_size; @@ -5495,8 +5794,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); @@ -5716,6 +6019,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) { @@ -5730,6 +6034,7 @@ wl_iw_set_cscan( goto exit_proc; } } +#endif res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); @@ -5745,21 +6050,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; } @@ -5768,6 +6088,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"); @@ -5775,6 +6097,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 @@ -5889,15 +6214,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; @@ -5930,7 +6254,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; @@ -5951,7 +6278,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) { @@ -5960,6 +6287,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; @@ -6008,8 +6361,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; @@ -6055,8 +6410,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)); @@ -6157,6 +6513,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__)); @@ -6212,7 +6569,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))) { @@ -6269,27 +6625,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; } @@ -6300,18 +6665,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; @@ -6336,9 +6702,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)); @@ -6468,9 +6834,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)); } @@ -6492,84 +6863,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 @@ -6702,22 +7097,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) @@ -6884,6 +7283,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) @@ -6946,8 +7348,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" }, @@ -6985,6 +7387,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) { @@ -7262,6 +7671,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) { @@ -7312,10 +7727,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); @@ -7326,10 +7745,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: @@ -7618,13 +8033,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)); @@ -7633,6 +8056,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(); @@ -7665,14 +8089,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); @@ -7680,9 +8113,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; @@ -7757,7 +8195,7 @@ wl_iw_bt_init(struct net_device *dev) return 0; } -int wl_iw_attach(struct net_device *dev, void * dhdp) +int wl_iw_attach(struct net_device *dev, void *dhdp) { int params_size; wl_iw_t *iw; @@ -7766,7 +8204,6 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) #endif mutex_init(&wl_cache_lock); - mutex_init(&wl_start_lock); #if defined(WL_IW_USE_ISCAN) if (!dev) @@ -7794,9 +8231,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); @@ -7871,5 +8310,4 @@ void wl_iw_detach(void) wl_iw_send_priv_event(priv_dev, "AP_DOWN"); } #endif - } diff --git a/bcm4329/src/wl/sys/wl_iw.h b/bcm4329/src/wl/sys/wl_iw.h index 43088cf..928291f 100644 --- a/bcm4329/src/wl/sys/wl_iw.h +++ b/bcm4329/src/wl/sys/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; |