net: wireless: bcmdhd: Fix race conditions for sysioc_thread
Dmitry Shmidt [Tue, 14 Jun 2011 00:33:26 +0000 (17:33 -0700)]
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>

drivers/net/wireless/bcmdhd/dhd_linux.c
drivers/net/wireless/bcmdhd/wl_iw.c

index 854da51..7d78bae 100644 (file)
@@ -407,7 +407,7 @@ typedef struct dhd_info {
        struct wake_lock wl_rxwake; /* Wifi rx wakelock */
 #endif
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
+#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
        spinlock_t wakelock_spinlock;
@@ -1205,6 +1205,7 @@ _dhd_sysioc_thread(void *data)
                        break;
                }
 
+               dhd_os_start_lock(&dhd->pub);
 
                for (i = 0; i < DHD_MAX_IFS; i++) {
                        if (dhd->iflist[i]) {
@@ -1249,6 +1250,8 @@ _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(&tsk->completed, 0);
@@ -2563,6 +2566,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
        dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
 
        /* Attach and link in the protocol */
@@ -3961,24 +3967,26 @@ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec)
 }
 
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
 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
 }
 
-#endif 
 
 #ifdef SOFTAP
 unsigned long dhd_os_spin_lock(dhd_pub_t *pub)
index ef713ee..0af6073 100644 (file)
@@ -130,7 +130,6 @@ wl_iw_extra_params_t        g_wl_iw_params;
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
 
-static struct mutex    wl_start_lock;
 static struct mutex    wl_cache_lock;
 static struct mutex    wl_softap_lock;
 
@@ -1633,6 +1632,7 @@ int
 wl_control_wl_start(struct net_device *dev)
 {
        int ret = 0;
+       wl_iw_t *iw;
 
        WL_TRACE(("Enter %s \n", __FUNCTION__));
 
@@ -1640,8 +1640,15 @@ wl_control_wl_start(struct net_device *dev)
                WL_ERROR(("%s: dev is null\n", __FUNCTION__));
                return -1;
        }
-       
-       DHD_OS_MUTEX_LOCK(&wl_start_lock);
+
+       iw = *(wl_iw_t **)netdev_priv(dev);
+
+       if (!iw) {
+               WL_ERROR(("%s: wl is null\n", __FUNCTION__));
+               return -1;
+       }
+
+       dhd_os_start_lock(iw->pub);
 
        if (g_onoff == G_WLAN_SET_OFF) {
                dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
@@ -1662,7 +1669,7 @@ wl_control_wl_start(struct net_device *dev)
        }
        WL_TRACE(("Exited %s\n", __FUNCTION__));
 
-       DHD_OS_MUTEX_UNLOCK(&wl_start_lock);
+       dhd_os_start_unlock(iw->pub);
        return ret;
 }
 
@@ -1674,6 +1681,7 @@ wl_iw_control_wl_off(
 )
 {
        int ret = 0;
+       wl_iw_t *iw;
 
        WL_TRACE(("Enter %s\n", __FUNCTION__));
 
@@ -1682,7 +1690,14 @@ wl_iw_control_wl_off(
                return -1;
        }
 
-       DHD_OS_MUTEX_LOCK(&wl_start_lock);
+       iw = *(wl_iw_t **)netdev_priv(dev);
+
+       if (!iw) {
+               WL_ERROR(("%s: wl is null\n", __FUNCTION__));
+               return -1;
+       }
+
+       dhd_os_start_lock(iw->pub);
 
 #ifdef SOFTAP
        ap_cfg_running = FALSE;
@@ -1718,7 +1733,6 @@ wl_iw_control_wl_off(
                sdioh_stop(NULL);
 #endif
 
-               
                net_os_set_dtim_skip(dev, 0);
 
                dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
@@ -1726,7 +1740,7 @@ wl_iw_control_wl_off(
                wl_iw_send_priv_event(dev, "STOP");
        }
 
-       DHD_OS_MUTEX_UNLOCK(&wl_start_lock);
+       dhd_os_start_unlock(iw->pub);
 
        WL_TRACE(("Exited %s\n", __FUNCTION__));
 
@@ -8475,7 +8489,6 @@ wl_iw_attach(struct net_device *dev, void * dhdp)
 #endif
 
        DHD_OS_MUTEX_INIT(&wl_cache_lock);
-       DHD_OS_MUTEX_INIT(&wl_start_lock);
        DHD_OS_MUTEX_INIT(&wl_softap_lock);
 
 #if defined(WL_IW_USE_ISCAN)