mirror of
https://github.com/hardkernel/linux.git
synced 2026-04-22 21:40:52 +09:00
net: wireless: bcm4329: Fix Softap start/stop race conditions
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -2437,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))
|
||||
@@ -3264,3 +3279,22 @@ int net_os_wake_unlock(struct net_device *dev)
|
||||
ret = dhd_os_wake_unlock(&dhd->pub);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
spin_lock_irqsave(&dhd->dhd_lock, flags);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags)
|
||||
{
|
||||
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
|
||||
|
||||
if (dhd)
|
||||
spin_unlock_irqrestore(&dhd->dhd_lock, flags);
|
||||
}
|
||||
|
||||
@@ -98,8 +98,10 @@ 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, u8 *mac);
|
||||
#endif
|
||||
@@ -5944,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");
|
||||
|
||||
@@ -5956,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;
|
||||
}
|
||||
|
||||
@@ -5967,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");
|
||||
@@ -5974,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
|
||||
@@ -6218,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;
|
||||
@@ -6557,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, NULL);
|
||||
wl_iw_softap_deassoc_stations(dev, NULL);
|
||||
#else
|
||||
wl_iw_softap_deassoc_stations(ap_net_dev, NULL);
|
||||
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));
|
||||
@@ -6689,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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user