diff options
-rw-r--r-- | arch/arm/common/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/common/fiq_debugger.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/bcm4329/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/bcm4329/dhd.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/bcm4329/dhd_linux.c | 120 | ||||
-rw-r--r-- | drivers/net/wireless/bcm4329/dhd_sdio.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/bcm4329/include/epivers.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/bcm4329/include/proto/bcmevent.h | 11 | ||||
-rw-r--r-- | drivers/net/wireless/bcm4329/wl_iw.c | 421 | ||||
-rw-r--r-- | drivers/net/wireless/bcm4329/wl_iw.h | 24 | ||||
-rw-r--r-- | drivers/usb/gadget/f_mtp.c | 233 | ||||
-rw-r--r-- | include/net/bluetooth/bluetooth.h | 6 | ||||
-rw-r--r-- | include/net/bluetooth/hci_core.h | 2 | ||||
-rw-r--r-- | include/net/bluetooth/l2cap.h | 1 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 9 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 4 | ||||
-rw-r--r-- | net/bluetooth/l2cap.c | 40 |
17 files changed, 576 insertions, 333 deletions
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 1777af96c309..2dbc36b05b1d 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -84,3 +84,11 @@ config FIQ_DEBUGGER_CONSOLE help Enables a console so that printk messages are displayed on the debugger serial port as the occur. + +config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE + bool "Put the FIQ debugger into console mode by default" + depends on FIQ_DEBUGGER_CONSOLE + default n + help + If enabled, this puts the fiq debugger into console mode by default. + Otherwise, the fiq debugger will start out in debug mode. diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 6b7ce432a31d..a97c9b2c197a 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -95,8 +95,14 @@ static bool initial_no_sleep = true; #else static bool initial_no_sleep; #endif + +#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE +static bool initial_debug_enable = true; +static bool initial_console_enable = true; +#else static bool initial_debug_enable; static bool initial_console_enable; +#endif module_param_named(no_sleep, initial_no_sleep, bool, 0644); module_param_named(debug_enable, initial_debug_enable, bool, 0644); diff --git a/drivers/net/wireless/bcm4329/Makefile b/drivers/net/wireless/bcm4329/Makefile index d0bc0b4806fc..3f49a643e8ff 100644 --- a/drivers/net/wireless/bcm4329/Makefile +++ b/drivers/net/wireless/bcm4329/Makefile @@ -7,6 +7,7 @@ DHDCFLAGS = -DLINUX -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD -DBCMWPA2 \ -DDHD_USE_STATIC_BUF -DMMC_SDIO_ABORT -DDHD_DEBUG_TRAP -DSOFTAP \ -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT \ -DGET_CUSTOM_MAC_ENABLE -DSET_RANDOM_MAC_SOFTAP -DCSCAN -DHW_OOB \ + -DKEEP_ALIVE \ -Idrivers/net/wireless/bcm4329 -Idrivers/net/wireless/bcm4329/include DHDOFILES = dhd_linux.o linux_osl.o bcmutils.o dhd_common.o dhd_custom_gpio.o \ diff --git a/drivers/net/wireless/bcm4329/dhd.h b/drivers/net/wireless/bcm4329/dhd.h index 59aa9f10ab1f..8f95e576ca65 100644 --- a/drivers/net/wireless/bcm4329/dhd.h +++ b/drivers/net/wireless/bcm4329/dhd.h @@ -221,6 +221,8 @@ extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub); extern void dhd_os_start_lock(dhd_pub_t *pub); extern void dhd_os_start_unlock(dhd_pub_t *pub); +extern unsigned long dhd_os_spin_lock(dhd_pub_t *pub); +extern void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); typedef struct dhd_if_event { uint8 ifidx; diff --git a/drivers/net/wireless/bcm4329/dhd_linux.c b/drivers/net/wireless/bcm4329/dhd_linux.c index e95e3b1e0f08..80dbbff9b772 100644 --- a/drivers/net/wireless/bcm4329/dhd_linux.c +++ b/drivers/net/wireless/bcm4329/dhd_linux.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.104.4.27 2010/10/29 02:31:24 Exp $ + * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.104.4.29 2010/11/04 01:14:41 Exp $ */ #ifdef CONFIG_WIFI_CONTROL_FUNC @@ -261,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; @@ -280,10 +282,10 @@ typedef struct dhd_info { int wl_count; int wl_packet; - int hang_was_sent; - - struct mutex wl_start_lock; - + int hang_was_sent; /* flag that message was send at least once */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + struct mutex wl_start_lock; /* mutex when START called to prevent any other Linux calls */ +#endif /* Thread to issue ioctl for multicast */ long sysioc_pid; struct semaphore sysioc_sem; @@ -307,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); @@ -904,13 +906,18 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) #ifdef SOFTAP extern struct net_device *ap_net_dev; +/* semaphore that the soft AP CODE waits on */ +extern struct semaphore ap_eth_sema; #endif static void dhd_op_if(dhd_if_t *ifp) { - dhd_info_t *dhd; - int ret = 0, err = 0; + dhd_info_t *dhd; + int ret = 0, err = 0; +#ifdef SOFTAP + unsigned long flags; +#endif ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ @@ -945,13 +952,12 @@ dhd_op_if(dhd_if_t *ifp) ret = -EOPNOTSUPP; } else { #ifdef SOFTAP - /* semaphore that the soft AP CODE waits on */ - extern struct semaphore ap_eth_sema; - + flags = dhd_os_spin_lock(&dhd->pub); /* save ptr to wl0.1 netdev for use in wl_iw.c */ ap_net_dev = ifp->net; /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */ up(&ap_eth_sema); + dhd_os_spin_unlock(&dhd->pub, flags); #endif DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n", current->pid, ifp->net->name)); @@ -980,8 +986,10 @@ dhd_op_if(dhd_if_t *ifp) dhd->iflist[ifp->idx] = NULL; MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); #ifdef SOFTAP + flags = dhd_os_spin_lock(&dhd->pub); if (ifp->net == ap_net_dev) ap_net_dev = NULL; /* NULL SOFTAP global as well */ + dhd_os_spin_unlock(&dhd->pub, flags); #endif /* SOFTAP */ } } @@ -993,6 +1001,7 @@ _dhd_sysioc_thread(void *data) int i; #ifdef SOFTAP bool in_ap = FALSE; + unsigned long flags; #endif DAEMONIZE("dhd_sysioc"); @@ -1004,7 +1013,9 @@ _dhd_sysioc_thread(void *data) if (dhd->iflist[i]) { DHD_TRACE(("%s: interface %d\n",__FUNCTION__, i)); #ifdef SOFTAP + flags = dhd_os_spin_lock(&dhd->pub); in_ap = (ap_net_dev != NULL); + dhd_os_spin_unlock(&dhd->pub, flags); #endif /* SOFTAP */ if (dhd->iflist[i]->state) dhd_op_if(dhd->iflist[i]); @@ -1039,6 +1050,7 @@ _dhd_sysioc_thread(void *data) dhd_os_wake_unlock(&dhd->pub); dhd_os_start_unlock(&dhd->pub); } + DHD_TRACE(("%s: stopped\n",__FUNCTION__)); complete_and_exit(&dhd->sysioc_exited, 0); } @@ -2048,6 +2060,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); @@ -2057,8 +2070,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; @@ -2228,6 +2242,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 */ @@ -2435,16 +2450,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)) @@ -2926,7 +2943,7 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) /* Turning on watchdog back */ if (!flag) dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); - DHD_ERROR(("%s: WLAN OFF DONE:\n", __FUNCTION__)); + DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__)); return ret; } @@ -3039,6 +3056,48 @@ 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); +} + +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) { @@ -3221,32 +3280,21 @@ int net_os_wake_unlock(struct net_device *dev) return ret; } -int net_os_send_hang_message(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) { - if (!dhd->hang_was_sent) { - dhd->hang_was_sent = 1; - ret = wl_iw_send_priv_event(dev, "HANG"); - } - } - return ret; -} - -void dhd_os_start_lock(dhd_pub_t *pub) +unsigned long dhd_os_spin_lock(dhd_pub_t *pub) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags = 0; if (dhd) - mutex_lock(&dhd->wl_start_lock); + spin_lock_irqsave(&dhd->dhd_lock, flags); + + return flags; } -void dhd_os_start_unlock(dhd_pub_t *pub) +void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); if (dhd) - mutex_unlock(&dhd->wl_start_lock); + spin_unlock_irqrestore(&dhd->dhd_lock, flags); } diff --git a/drivers/net/wireless/bcm4329/dhd_sdio.c b/drivers/net/wireless/bcm4329/dhd_sdio.c index abe92b7eb09a..7494e3836732 100644 --- a/drivers/net/wireless/bcm4329/dhd_sdio.c +++ b/drivers/net/wireless/bcm4329/dhd_sdio.c @@ -2719,6 +2719,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 +2730,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) { @@ -5801,11 +5801,6 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) /* 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); diff --git a/drivers/net/wireless/bcm4329/include/epivers.h b/drivers/net/wireless/bcm4329/include/epivers.h index 002aff6897de..9b5a2f1f20d7 100644 --- a/drivers/net/wireless/bcm4329/include/epivers.h +++ b/drivers/net/wireless/bcm4329/include/epivers.h @@ -33,16 +33,16 @@ #define EPI_RC_NUMBER 248 -#define EPI_INCREMENTAL_NUMBER 11 +#define EPI_INCREMENTAL_NUMBER 13 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 4, 218, 248, 11 +#define EPI_VERSION 4, 218, 248, 13 -#define EPI_VERSION_NUM 0x04daf80b +#define EPI_VERSION_NUM 0x04daf80d -#define EPI_VERSION_STR "4.218.248.11" -#define EPI_ROUTER_VERSION_STR "4.219.248.11" +#define EPI_VERSION_STR "4.218.248.13" +#define EPI_ROUTER_VERSION_STR "4.219.248.13" #endif diff --git a/drivers/net/wireless/bcm4329/include/proto/bcmevent.h b/drivers/net/wireless/bcm4329/include/proto/bcmevent.h index 46c04d379227..1f8ecb14d97a 100644 --- a/drivers/net/wireless/bcm4329/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcm4329/include/proto/bcmevent.h @@ -24,7 +24,7 @@ * * Dependencies: proto/bcmeth.h * - * $Id: bcmevent.h,v 9.34.4.1.20.16 2009/09/25 23:52:38 Exp $ + * $Id: bcmevent.h,v 9.34.4.1.20.16.64.1 2010/11/08 21:57:03 Exp $ * */ @@ -131,10 +131,10 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_ACTION_FRAME 58 #define WLC_E_ACTION_FRAME_COMPLETE 59 -#define WLC_E_ESCAN_RESULT 69 -#define WLC_E_WAKE_EVENT 70 -#define WLC_E_LAST 71 - +#define WLC_E_ESCAN_RESULT 69 +#define WLC_E_WAKE_EVENT 70 +#define WLC_E_RELOAD 71 +#define WLC_E_LAST 72 @@ -205,6 +205,7 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_IF_ADD 1 #define WLC_E_IF_DEL 2 +#define WLC_E_RELOAD_STATUS1 1 #include <packed_section_end.h> diff --git a/drivers/net/wireless/bcm4329/wl_iw.c b/drivers/net/wireless/bcm4329/wl_iw.c index 6d83a259bf95..547c6cee0082 100644 --- a/drivers/net/wireless/bcm4329/wl_iw.c +++ b/drivers/net/wireless/bcm4329/wl_iw.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_iw.c,v 1.51.4.9.2.6.4.142.4.28 2010/10/19 22:55:15 Exp $ + * $Id: wl_iw.c,v 1.51.4.9.2.6.4.142.4.45 2010/11/04 21:08:09 Exp $ */ @@ -98,10 +98,12 @@ typedef const struct si_pub si_t; static struct net_device *priv_dev; static bool ap_cfg_running = 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) \ @@ -635,11 +637,11 @@ wl_iw_set_country( 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) { p += snprintf(p, MAX_WX_STRING, "OK"); WL_TRACE(("%s: set country %s OK\n", __FUNCTION__, country_code)); + dhd_bus_country_set(dev, &country_code[0]); goto exit; } } @@ -1448,8 +1450,8 @@ wl_iw_send_priv_event( int wl_control_wl_start(struct net_device *dev) { - wl_iw_t *iw; int ret = 0; + wl_iw_t *iw; WL_TRACE(("Enter %s \n", __FUNCTION__)); @@ -1459,6 +1461,11 @@ wl_control_wl_start(struct net_device *dev) } iw = *(wl_iw_t **)netdev_priv(dev); + + if (!iw) { + WL_ERROR(("%s: wl is null\n", __FUNCTION__)); + return -1; + } dhd_os_start_lock(iw->pub); if (g_onoff == G_WLAN_SET_OFF) { @@ -1491,8 +1498,8 @@ wl_iw_control_wl_off( struct iw_request_info *info ) { - wl_iw_t *iw; int ret = 0; + wl_iw_t *iw; WL_TRACE(("Enter %s\n", __FUNCTION__)); @@ -1502,6 +1509,10 @@ wl_iw_control_wl_off( } iw = *(wl_iw_t **)netdev_priv(dev); + if (!iw) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + return -1; + } dhd_os_start_lock(iw->pub); #ifdef SOFTAP @@ -1587,7 +1598,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 @@ -1669,9 +1680,11 @@ 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); return ret; } @@ -1688,7 +1701,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)); @@ -1742,52 +1756,86 @@ static int iwpriv_get_assoc_list(struct net_device *dev, char mac_buf[256]; struct maclist *sta_maclist = (struct maclist *)mac_buf; - char mac_lst[256]; + char mac_lst[384]; char *p_mac_str; + char *p_mac_str_end; + + if ((!dev) || (!extra)) { + return -EINVAL; + } + + net_os_wake_lock(dev); WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d, \ iwp.len:%p, iwp.flags:%x \n", __FUNCTION__, info->cmd, info->flags, \ extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags)); - WL_SOFTAP(("extra:%s\n", extra)); - print_buf((u8 *)p_iwrq, 16, 0); - memset(sta_maclist, 0, sizeof(mac_buf)); sta_maclist->count = 8; - WL_TRACE((" net device:%s, buf_sz:%d\n", dev->name, sizeof(mac_buf))); - get_assoc_sta_list(dev, mac_buf, 256); - WL_TRACE((" got %d stations\n", sta_maclist->count)); + WL_SOFTAP(("%s: net device:%s, buf_sz:%d\n", + __FUNCTION__, dev->name, sizeof(mac_buf))); + + if ((ret = get_assoc_sta_list(dev, mac_buf, sizeof(mac_buf))) < 0) { + WL_ERROR(("%s: sta list ioctl error:%d\n", + __FUNCTION__, ret)); + goto func_exit; + } + + WL_SOFTAP(("%s: got %d stations\n", __FUNCTION__, + sta_maclist->count)); memset(mac_lst, 0, sizeof(mac_lst)); p_mac_str = mac_lst; + p_mac_str_end = &mac_lst[sizeof(mac_lst)-1]; for (i = 0; i < 8; i++) { struct ether_addr *id = &sta_maclist->ea[i]; + if (!ETHER_ISNULLADDR(id->octet)) { + scb_val_t scb_val; + int rssi = 0; - WL_SOFTAP(("dhd_drv>> sta_mac[%d] :", i)); - print_buf((unsigned char *)&sta_maclist->ea[i], 6, 0); + bzero(&scb_val, sizeof(scb_val_t)); - p_mac_str += snprintf(p_mac_str, MAX_WX_STRING, - "Mac[%d]=%02X:%02X:%02X:%02X:%02X:%02X\n", i, + 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, + "\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; } @@ -1795,19 +1843,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)); @@ -1827,25 +1876,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; } @@ -1854,19 +1899,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; @@ -1882,8 +1931,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 { @@ -2533,8 +2618,10 @@ 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; - if ((uintptr)bi >= ((uintptr)list + buflen)) { - WL_ERROR(("%s: Scan results out of bounds\n",__FUNCTION__)); + + 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; } @@ -2610,8 +2697,10 @@ 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; - if ((uintptr)bi >= ((uintptr)list + WLC_IW_ISCAN_MAXLEN)) { - WL_ERROR(("%s: Scan results out of bounds\n",__FUNCTION__)); + + 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; } @@ -3110,7 +3199,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, @@ -3548,7 +3637,7 @@ wl_iw_get_scan_prep( if (!list) { WL_ERROR(("%s: Null list pointer",__FUNCTION__)); - return -EINVAL; + return ret; } for (i = 0; i < list->count && i < IW_MAX_AP; i++) @@ -3898,8 +3987,9 @@ wl_iw_iscan_get_scan( 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; - if ((uintptr)bi >= ((uintptr)list + WLC_IW_ISCAN_MAXLEN)) { - WL_ERROR(("%s: Scan results out of bounds\n",__FUNCTION__)); + 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; } @@ -5602,8 +5692,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); @@ -5852,7 +5946,12 @@ 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"); @@ -5864,9 +5963,12 @@ static int thr_wait_for_2nd_eth_dev(void *data) goto fail; } + iw = *(wl_iw_t **)netdev_priv(dev); + 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; } @@ -5875,6 +5977,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"); @@ -5882,6 +5986,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 @@ -5996,15 +6103,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; @@ -6037,7 +6143,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; @@ -6045,6 +6154,15 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) WL_TRACE(("\n>in %s: apsta set result: %d \n", __FUNCTION__, res)); #endif + 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; + } + updown = 1; if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown))) < 0) { WL_ERROR(("%s fail to set apsta \n", __FUNCTION__)); @@ -6058,7 +6176,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) { @@ -6115,8 +6233,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; @@ -6162,8 +6282,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)); @@ -6264,6 +6385,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__)); @@ -6319,7 +6441,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))) { @@ -6376,27 +6497,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; } @@ -6407,18 +6537,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; @@ -6443,9 +6574,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)); @@ -6575,9 +6706,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)); } @@ -6599,84 +6735,105 @@ 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)); - 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)); + 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; + bool deny_if_matched = (mac_mode == MACLIST_MODE_DENY); - mac_mode = MACLIST_MODE_ALLOW; - - dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); + bcopy(maclist, &ap_black_list, sizeof(ap_black_list)); - 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(("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])); + ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); + check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__); - bcopy(black_maclist, &ap_black_list, sizeof(ap_black_list)); + length = sizeof(maclist->count) + maclist->count*ETHER_ADDR_LEN; + dev_wlc_ioctl(dev, WLC_SET_MACLIST, maclist, length); - WL_SOFTAP(("Black List, size %d:\n", sizeof(ap_black_list))); - for (i = 0; i < ap_black_list.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, 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])); + 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])); + + 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)); - dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 256); if (assoc_maclist->count) { int j; + 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], + + WL_SOFTAP(("\ncheking assoc STA:")); + print_buf(&assoc_maclist->ea[i], 6, 0); + + 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")); + + if (deny_if_matched) { + WL_SOFTAP(("black match," + " do deauth/disassoc \n")); + scbval.val = htod32(1); + bcopy(&assoc_maclist->ea[i], &scbval.ea, \ + ETHER_ADDR_LEN); + 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(("white match, let it be\n")); + } break; } } - if (j == white_maclist->count) { - WL_SOFTAP(("match black, deauth it\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)); - } } + } else { + WL_SOFTAP(("No ASSOC CLIENTS\n")); } - } - return 0; + } + + WL_SOFTAP(("%s iocres:%d\n", __FUNCTION__, ioc_res)); + return ioc_res; } #endif @@ -6991,6 +7148,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) @@ -7053,8 +7213,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" }, @@ -7092,6 +7252,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) { @@ -7369,6 +7536,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) { diff --git a/drivers/net/wireless/bcm4329/wl_iw.h b/drivers/net/wireless/bcm4329/wl_iw.h index 3b45792979af..0f5f4db32eff 100644 --- a/drivers/net/wireless/bcm4329/wl_iw.h +++ b/drivers/net/wireless/bcm4329/wl_iw.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_iw.h,v 1.5.34.1.6.36.4.1 2010/09/10 19:24:30 Exp $ + * $Id: wl_iw.h,v 1.5.34.1.6.36.4.12 2010/11/03 03:15:49 Exp $ */ @@ -87,8 +87,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 +117,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 +140,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 +159,13 @@ struct ap_profile { uint32 channel; uint32 preamble; uint32 max_scb; + uint32 closednet; }; #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 +173,7 @@ struct mflist { struct mac_list_set { uint32 mode; - struct mflist white_list; - struct mflist black_list; + struct mflist mac_list; }; #endif @@ -196,6 +197,7 @@ 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 void dhd_bus_country_set(struct net_device *dev, char *country_code); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) #define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c index 2c61a2613475..81075f2bf080 100644 --- a/drivers/usb/gadget/f_mtp.c +++ b/drivers/usb/gadget/f_mtp.c @@ -25,8 +25,6 @@ #include <linux/wait.h> #include <linux/err.h> #include <linux/interrupt.h> -#include <linux/kthread.h> -#include <linux/freezer.h> #include <linux/types.h> #include <linux/file.h> @@ -56,11 +54,6 @@ #define TX_REQ_MAX 4 #define RX_REQ_MAX 2 -/* IO Thread commands */ -#define ANDROID_THREAD_QUIT 1 -#define ANDROID_THREAD_SEND_FILE 2 -#define ANDROID_THREAD_RECEIVE_FILE 3 - /* ID for Microsoft MTP OS String */ #define MTP_OS_STRING_ID 0xEE @@ -92,6 +85,8 @@ struct mtp_dev { /* synchronize access to our device file */ atomic_t open_excl; + /* to enforce only one ioctl at a time */ + atomic_t ioctl_excl; struct list_head tx_idle; @@ -101,23 +96,19 @@ struct mtp_dev { struct usb_request *rx_req[RX_REQ_MAX]; struct usb_request *intr_req; int rx_done; - - /* synchronize access to interrupt endpoint */ - struct mutex intr_mutex; /* true if interrupt endpoint is busy */ int intr_busy; - /* for our file IO thread */ - struct task_struct *thread; - /* current command for IO thread (or zero for none) */ - int thread_command; - struct file *thread_file; - loff_t thread_file_offset; - size_t thread_file_length; - /* used to wait for thread to complete current command */ - struct completion thread_wait; - /* result from current command */ - int thread_result; + /* for processing MTP_SEND_FILE and MTP_RECEIVE_FILE + * ioctls on a work queue + */ + struct workqueue_struct *wq; + struct work_struct send_file_work; + struct work_struct receive_file_work; + struct file *xfer_file; + loff_t xfer_file_offset; + size_t xfer_file_length; + int xfer_result; }; static struct usb_interface_descriptor mtp_interface_desc = { @@ -622,14 +613,23 @@ static ssize_t mtp_write(struct file *fp, const char __user *buf, return r; } -static int mtp_send_file(struct mtp_dev *dev, struct file *filp, - loff_t offset, size_t count) -{ +/* read from a local file and write to USB */ +static void send_file_work(struct work_struct *data) { + struct mtp_dev *dev = container_of(data, struct mtp_dev, send_file_work); struct usb_composite_dev *cdev = dev->cdev; struct usb_request *req = 0; - int r = count, xfer, ret; + struct file *filp; + loff_t offset; + size_t count; + int r, xfer, ret; + + /* read our parameters */ + smp_rmb(); + filp = dev->xfer_file; + offset = dev->xfer_file_offset; + r = count = dev->xfer_file_length; - DBG(cdev, "mtp_send_file(%lld %d)\n", offset, count); + DBG(cdev, "send_file_work(%lld %d)\n", offset, count); while (count > 0) { /* get an idle tx request to use */ @@ -656,7 +656,7 @@ static int mtp_send_file(struct mtp_dev *dev, struct file *filp, req->length = xfer; ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); if (ret < 0) { - DBG(cdev, "mtp_write: xfer error %d\n", ret); + DBG(cdev, "send_file_work: xfer error %d\n", ret); dev->state = STATE_ERROR; r = -EIO; break; @@ -671,20 +671,30 @@ static int mtp_send_file(struct mtp_dev *dev, struct file *filp, if (req) req_put(dev, &dev->tx_idle, req); - DBG(cdev, "mtp_write returning %d\n", r); - return r; + DBG(cdev, "send_file_work returning %d\n", r); + /* write the result */ + dev->xfer_result = r; + smp_wmb(); } -static int mtp_receive_file(struct mtp_dev *dev, struct file *filp, - loff_t offset, size_t count) +/* read from USB and write to a local file */ +static void receive_file_work(struct work_struct *data) { + struct mtp_dev *dev = container_of(data, struct mtp_dev, receive_file_work); struct usb_composite_dev *cdev = dev->cdev; struct usb_request *read_req = NULL, *write_req = NULL; - int r = count; - int ret; - int cur_buf = 0; + struct file *filp; + loff_t offset; + size_t count; + int r, ret, cur_buf = 0; + + /* read our parameters */ + smp_rmb(); + filp = dev->xfer_file; + offset = dev->xfer_file_offset; + r = count = dev->xfer_file_length; - DBG(cdev, "mtp_receive_file(%d)\n", count); + DBG(cdev, "receive_file_work(%d)\n", count); while (count > 0 || write_req) { if (count > 0) { @@ -731,64 +741,10 @@ static int mtp_receive_file(struct mtp_dev *dev, struct file *filp, } } - DBG(cdev, "mtp_read returning %d\n", r); - return r; -} - -/* Kernel thread for handling file IO operations */ -static int mtp_thread(void *data) -{ - struct mtp_dev *dev = (struct mtp_dev *)data; - struct usb_composite_dev *cdev = dev->cdev; - int flags; - - DBG(cdev, "mtp_thread started\n"); - - while (1) { - /* wait for a command */ - while (1) { - try_to_freeze(); - set_current_state(TASK_INTERRUPTIBLE); - if (dev->thread_command != 0) - break; - schedule(); - } - __set_current_state(TASK_RUNNING); - - if (dev->thread_command == ANDROID_THREAD_QUIT) { - DBG(cdev, "ANDROID_THREAD_QUIT\n"); - dev->thread_result = 0; - goto done; - } - - if (dev->thread_command == ANDROID_THREAD_SEND_FILE) - flags = O_RDONLY | O_LARGEFILE; - else - flags = O_WRONLY | O_LARGEFILE | O_CREAT; - - if (dev->thread_command == ANDROID_THREAD_SEND_FILE) { - dev->thread_result = mtp_send_file(dev, - dev->thread_file, - dev->thread_file_offset, - dev->thread_file_length); - } else { - dev->thread_result = mtp_receive_file(dev, - dev->thread_file, - dev->thread_file_offset, - dev->thread_file_length); - } - - if (dev->thread_file) { - fput(dev->thread_file); - dev->thread_file = NULL; - } - dev->thread_command = 0; - complete(&dev->thread_wait); - } - -done: - DBG(cdev, "android_thread done\n"); - complete_and_exit(&dev->thread_wait, 0); + DBG(cdev, "receive_file_work returning %d\n", r); + /* write the result */ + dev->xfer_result = r; + smp_wmb(); } static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) @@ -802,29 +758,21 @@ static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) if (length < 0 || length > INTR_BUFFER_SIZE) return -EINVAL; - mutex_lock(&dev->intr_mutex); - /* wait for a request to complete */ ret = wait_event_interruptible(dev->intr_wq, !dev->intr_busy || dev->state == STATE_OFFLINE); if (ret < 0) - goto done; - if (dev->state == STATE_OFFLINE) { - ret = -ENODEV; - goto done; - } + return ret; + if (dev->state == STATE_OFFLINE) + return -ENODEV; req = dev->intr_req; - if (copy_from_user(req->buf, (void __user *)event->data, length)) { - ret = -EFAULT; - goto done; - } + if (copy_from_user(req->buf, (void __user *)event->data, length)) + return -EFAULT; req->length = length; dev->intr_busy = 1; ret = usb_ep_queue(dev->ep_intr, req, GFP_KERNEL); if (ret) dev->intr_busy = 0; -done: - mutex_unlock(&dev->intr_mutex); return ret; } @@ -834,22 +782,28 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) struct file *filp = NULL; int ret = -EINVAL; + if (_lock(&dev->ioctl_excl)) + return -EBUSY; + switch (code) { case MTP_SEND_FILE: case MTP_RECEIVE_FILE: { struct mtp_file_range mfr; + struct work_struct *work; spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) { /* report cancelation to userspace */ dev->state = STATE_READY; spin_unlock_irq(&dev->lock); - return -ECANCELED; + ret = -ECANCELED; + goto out; } if (dev->state == STATE_OFFLINE) { spin_unlock_irq(&dev->lock); - return -ENODEV; + ret = -ENODEV; + goto out; } dev->state = STATE_BUSY; spin_unlock_irq(&dev->lock); @@ -858,29 +812,36 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) ret = -EFAULT; goto fail; } + /* hold a reference to the file while we are working with it */ filp = fget(mfr.fd); if (!filp) { ret = -EBADF; goto fail; } - dev->thread_file = filp; - dev->thread_file_offset = mfr.offset; - dev->thread_file_length = mfr.length; + /* write the parameters */ + dev->xfer_file = filp; + dev->xfer_file_offset = mfr.offset; + dev->xfer_file_length = mfr.length; + smp_wmb(); if (code == MTP_SEND_FILE) - dev->thread_command = ANDROID_THREAD_SEND_FILE; + work = &dev->send_file_work; else - dev->thread_command = ANDROID_THREAD_RECEIVE_FILE; + work = &dev->receive_file_work; - /* wake up the thread */ - init_completion(&dev->thread_wait); - wake_up_process(dev->thread); + /* We do the file transfer on a work queue so it will run + * in kernel context, which is necessary for vfs_read and + * vfs_write to use our buffers in the kernel address space. + */ + queue_work(dev->wq, work); + /* wait for operation to complete */ + flush_workqueue(dev->wq); + fput(filp); - /* wait for the thread to complete the command */ - wait_for_completion(&dev->thread_wait); - ret = dev->thread_result; - DBG(dev->cdev, "thread returned %d\n", ret); + /* read the result */ + smp_rmb(); + ret = dev->xfer_result; break; } case MTP_SET_INTERFACE_MODE: @@ -904,21 +865,22 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) * which would interfere with bulk transfer state. */ if (copy_from_user(&event, (void __user *)value, sizeof(event))) - return -EFAULT; + ret = -EFAULT; else - return mtp_send_event(dev, &event); + ret = mtp_send_event(dev, &event); + goto out; } } fail: - if (filp) - fput(filp); spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) ret = -ECANCELED; else if (dev->state != STATE_OFFLINE) dev->state = STATE_READY; spin_unlock_irq(&dev->lock); +out: + _unlock(&dev->ioctl_excl); DBG(dev->cdev, "ioctl returning %d\n", ret); return ret; } @@ -929,10 +891,6 @@ static int mtp_open(struct inode *ip, struct file *fp) if (_lock(&_mtp_dev->open_excl)) return -EBUSY; - _mtp_dev->thread = kthread_create(mtp_thread, _mtp_dev, "f_mtp"); - if (IS_ERR(_mtp_dev->thread)) - return -ENOMEM; - /* clear any error condition */ if (_mtp_dev->state != STATE_OFFLINE) _mtp_dev->state = STATE_READY; @@ -945,14 +903,6 @@ static int mtp_release(struct inode *ip, struct file *fp) { printk(KERN_INFO "mtp_release\n"); - /* tell the thread to quit */ - if (_mtp_dev->thread) { - _mtp_dev->thread_command = ANDROID_THREAD_QUIT; - init_completion(&_mtp_dev->thread_wait); - wake_up_process(_mtp_dev->thread); - wait_for_completion(&_mtp_dev->thread_wait); - } - _unlock(&_mtp_dev->open_excl); return 0; } @@ -1216,13 +1166,18 @@ static int mtp_bind_config(struct usb_configuration *c) } spin_lock_init(&dev->lock); - init_completion(&dev->thread_wait); init_waitqueue_head(&dev->read_wq); init_waitqueue_head(&dev->write_wq); init_waitqueue_head(&dev->intr_wq); atomic_set(&dev->open_excl, 0); + atomic_set(&dev->ioctl_excl, 0); INIT_LIST_HEAD(&dev->tx_idle); - mutex_init(&dev->intr_mutex); + + dev->wq = create_singlethread_workqueue("f_mtp"); + if (!dev->wq) + goto err1; + INIT_WORK(&dev->send_file_work, send_file_work); + INIT_WORK(&dev->receive_file_work, receive_file_work); dev->cdev = c->cdev; dev->function.name = "mtp"; @@ -1254,6 +1209,8 @@ static int mtp_bind_config(struct usb_configuration *c) err2: misc_deregister(&mtp_device); err1: + if (dev->wq) + destroy_workqueue(dev->wq); kfree(dev); printk(KERN_ERR "mtp gadget driver failed to initialize\n"); return ret; diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 30fce0128dd7..642cda89b1e7 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -64,6 +64,11 @@ struct bt_security { #define BT_DEFER_SETUP 7 +#define BT_POWER 8 +struct bt_power { + __u8 force_active; +}; + #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg) #define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg) #define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg) @@ -142,6 +147,7 @@ struct bt_skb_cb { __u8 tx_seq; __u8 retries; __u8 sar; + __u8 force_active; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 1ce134720cfe..95b5f024fb35 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -353,7 +353,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); int hci_conn_change_link_key(struct hci_conn *conn); int hci_conn_switch_role(struct hci_conn *conn, __u8 role); -void hci_conn_enter_active_mode(struct hci_conn *conn); +void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active); void hci_conn_enter_sniff_mode(struct hci_conn *conn); void hci_conn_hold_device(struct hci_conn *conn); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 8f8e648032e8..22885e05a826 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -329,6 +329,7 @@ struct l2cap_pinfo { __u8 role_switch; __u8 force_reliable; __u8 flushable; + __u8 force_active; __u8 conf_req[64]; __u8 conf_len; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 1c8c30d52b53..481e4b1cd981 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -415,7 +415,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, if (acl->state == BT_CONNECTED && (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { acl->power_save = 1; - hci_conn_enter_active_mode(acl); + hci_conn_enter_active_mode(acl, 1); if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) { /* defer SCO setup until mode change completed */ @@ -531,7 +531,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) EXPORT_SYMBOL(hci_conn_switch_role); /* Enter active mode */ -void hci_conn_enter_active_mode(struct hci_conn *conn) +void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) { struct hci_dev *hdev = conn->hdev; @@ -540,7 +540,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn) if (test_bit(HCI_RAW, &hdev->flags)) return; - if (conn->mode != HCI_CM_SNIFF /* || !conn->power_save */) + if (conn->mode != HCI_CM_SNIFF) + goto timer; + + if (!conn->power_save && !force_active) goto timer; if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a49aa2bf97f3..de9127d6b9d3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1507,7 +1507,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev) while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); - hci_conn_enter_active_mode(conn); + hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active); hci_send_frame(skb); hdev->acl_last_tx = jiffies; @@ -1609,7 +1609,7 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) if (conn) { register struct hci_proto *hp; - hci_conn_enter_active_mode(conn); + hci_conn_enter_active_mode(conn, 1); /* Send to upper protocol */ if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) { diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index d527b10f8a05..0f2e1c66ac33 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -366,6 +366,8 @@ static inline void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u1 else flags = ACL_START; + bt_cb(skb)->force_active = 1; + hci_send_acl(conn->hcon, skb, flags); } @@ -412,6 +414,8 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) put_unaligned_le16(fcs, skb_put(skb, 2)); } + bt_cb(skb)->force_active = l2cap_pi(sk)->force_active; + hci_send_acl(pi->conn->hcon, skb, 0); } @@ -908,6 +912,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->role_switch = l2cap_pi(parent)->role_switch; pi->force_reliable = l2cap_pi(parent)->force_reliable; pi->flushable = l2cap_pi(parent)->flushable; + pi->force_active = l2cap_pi(parent)->force_active; } else { pi->imtu = L2CAP_DEFAULT_MTU; pi->omtu = 0; @@ -924,6 +929,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->role_switch = 0; pi->force_reliable = 0; pi->flushable = 0; + pi->force_active = 1; } /* Default config options */ @@ -1452,6 +1458,7 @@ static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb) else flags = ACL_START; + bt_cb(skb)->force_active = pi->force_active; hci_send_acl(hcon, skb, flags); } @@ -2043,6 +2050,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch { struct sock *sk = sock->sk; struct bt_security sec; + struct bt_power pwr; int len, err = 0; u32 opt; @@ -2095,6 +2103,23 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch bt_sk(sk)->defer_setup = opt; break; + case BT_POWER: + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM + && sk->sk_type != SOCK_RAW) { + err = -EINVAL; + break; + } + + pwr.force_active = 1; + + len = min_t(unsigned int, sizeof(pwr), optlen); + if (copy_from_user((char *) &pwr, optval, len)) { + err = -EFAULT; + break; + } + l2cap_pi(sk)->force_active = pwr.force_active; + break; + default: err = -ENOPROTOOPT; break; @@ -2195,6 +2220,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch { struct sock *sk = sock->sk; struct bt_security sec; + struct bt_power pwr; int len, err = 0; BT_DBG("sk %p", sk); @@ -2237,6 +2263,20 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; + case BT_POWER: + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM + && sk->sk_type != SOCK_RAW) { + err = -EINVAL; + break; + } + + pwr.force_active = l2cap_pi(sk)->force_active; + + len = min_t(unsigned int, len, sizeof(pwr)); + if (copy_to_user(optval, (char *) &pwr, len)) + err = -EFAULT; + + break; default: err = -ENOPROTOOPT; break; |