summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/common/Kconfig8
-rw-r--r--arch/arm/common/fiq_debugger.c6
-rw-r--r--drivers/net/wireless/bcm4329/Makefile1
-rw-r--r--drivers/net/wireless/bcm4329/dhd.h2
-rw-r--r--drivers/net/wireless/bcm4329/dhd_linux.c120
-rw-r--r--drivers/net/wireless/bcm4329/dhd_sdio.c11
-rw-r--r--drivers/net/wireless/bcm4329/include/epivers.h10
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/bcmevent.h11
-rw-r--r--drivers/net/wireless/bcm4329/wl_iw.c421
-rw-r--r--drivers/net/wireless/bcm4329/wl_iw.h24
-rw-r--r--drivers/usb/gadget/f_mtp.c233
-rw-r--r--include/net/bluetooth/bluetooth.h6
-rw-r--r--include/net/bluetooth/hci_core.h2
-rw-r--r--include/net/bluetooth/l2cap.h1
-rw-r--r--net/bluetooth/hci_conn.c9
-rw-r--r--net/bluetooth/hci_core.c4
-rw-r--r--net/bluetooth/l2cap.c40
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;