net: wireless: bcmdhd: Fix P2P interface removal
authorDmitry Shmidt <dimitrysh@google.com>
Fri, 16 Dec 2011 20:54:51 +0000 (12:54 -0800)
committerDmitry Shmidt <dimitrysh@google.com>
Mon, 19 Dec 2011 21:22:49 +0000 (13:22 -0800)
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
drivers/net/wireless/bcmdhd/dhd_linux.c
drivers/net/wireless/bcmdhd/wl_cfg80211.c
drivers/net/wireless/bcmdhd/wl_cfg80211.h

index 37caa1054963081726ad093789c98bebca20385a..d4cc56f4043208d33c30d6164d46623ca786b342 100644 (file)
@@ -1032,6 +1032,9 @@ dhd_op_if(dhd_if_t *ifp)
        if (ret < 0) {
                ifp->set_multicast = FALSE;
                if (ifp->net) {
+#ifdef WL_CFG80211
+                       wl_cfg80211_post_del((void*)(ifp->net));
+#endif
                        free_netdev(ifp->net);
                }
                dhd->iflist[ifp->idx] = NULL;
index 3ca4df7faedf06e5acb13e642ac6bdf402444cd1..32241d52adde1e5cb70906b78af4dae766d6168c 100644 (file)
@@ -16,7 +16,7 @@
  * the license of that module.  An independent module is a module which is not
  * derived from this software.  The special exception does not apply to any
  * modifications of the software.
- * 
+ *
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
@@ -589,7 +589,7 @@ static const u32 __wl_cipher_suites[] = {
        WLAN_CIPHER_SUITE_WEP104,
        WLAN_CIPHER_SUITE_TKIP,
        WLAN_CIPHER_SUITE_CCMP,
-       WLAN_CIPHER_SUITE_AES_CMAC,
+       WLAN_CIPHER_SUITE_AES_CMAC
 };
 
 /* There isn't a lot of sense in it, but you can transmit anything you like */
@@ -844,8 +844,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                wl_set_p2p_status(wl, IF_ADD);
                err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
 
-               if (unlikely(err))
+               if (unlikely(err)) {
+                       WL_ERR((" virtual iface add failed (%d) \n", err));
                        return ERR_PTR(-ENOMEM);
+               }
 
                timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
                        (wl_get_p2p_status(wl, IF_ADD) == false),
@@ -860,7 +862,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                        }
                        vwdev->wiphy = wl->wdev->wiphy;
                        WL_INFO((" virtual interface(%s) is created memalloc done \n",
-                       wl->p2p->vir_ifname));
+                               wl->p2p->vir_ifname));
                        index = alloc_idx_vwdev(wl);
                        wl->vwdev[index] = vwdev;
                        vwdev->iftype =
@@ -873,6 +875,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                        wl_set_drv_status(wl, READY);
                        wl->p2p->vif_created = true;
                        set_mode_by_netdev(wl, _ndev, mode);
+                       WL_DBG((" virtual interface(%s) wl->wdev %p wl->wdev->netdev %p vwdev %p vwdev->netdev %p\n",
+                               wl->p2p->vir_ifname, wl->wdev, wl->wdev->netdev, vwdev, vwdev->netdev));
                        net_attach =  wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION);
                        if (rtnl_is_locked()) {
                                rtnl_unlock();
@@ -927,10 +931,14 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
                        * ifconfig <inter> down and up sequnce, which will reload the fw
                        * however we should cleanup the linux network virtual interfaces
                        */
-                               dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
-                               WL_ERR(("Firmware returned an error from p2p_ifdel\n"));
-                               WL_ERR(("try to remove linux virtual interface %s\n", dev->name));
-                               dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev));
+                       /* Request framework to RESET and clean up */
+                               struct net_device *ndev = wl_to_prmry_ndev(wl);
+                               WL_ERR(("Firmware returned an error (%d) from p2p_ifdel"
+                                       "HANG Notification sent to %s dev %p wdev %p ndev %p\n", ret, ndev->name, dev, wl->wdev, wl_to_prmry_ndev(wl)));
+                               wl_cfg80211_hang(ndev, WLAN_REASON_UNSPECIFIED);
+                       }
+                       else {
+                               WL_ERR(("Firmware success from p2p_ifdel dev %p wdev %p ndev %p", dev, wl->wdev, wl_to_prmry_ndev(wl)));
                        }
 
                        /* Wait for any pending scan req to get aborted from the sysioc context */
@@ -1035,7 +1043,7 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
                WL_ERR(("net is NULL\n"));
                return 0;
        }
-       if (wl->p2p_supported) {
+       if (wl->p2p_supported && wl_get_p2p_status(wl, IF_ADD)) {
                WL_DBG(("IF_ADD event called from dongle, old interface name: %s,"
                        "new name: %s\n", ndev->name, wl->p2p->vir_ifname));
                /* Assign the net device to CONNECT BSSCFG */
@@ -1047,6 +1055,8 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
                wl_clr_p2p_status(wl, IF_ADD);
 
                wake_up_interruptible(&wl->dongle_event_wait);
+       } else {
+               ret = BCME_NOTREADY;
        }
        return ret;
 }
@@ -1063,7 +1073,8 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev)
                return 0;
        }
 
-       if (p2p_is_on(wl) && wl->p2p->vif_created) {
+       if (p2p_is_on(wl) && wl->p2p->vif_created &&
+               wl_get_p2p_status(wl, IF_DELETING)) {
                if (wl->scan_request) {
                        /* Abort any pending scan requests */
                        wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
@@ -1096,6 +1107,18 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev)
        return 0;
 }
 
+s32 wl_cfg80211_post_del(void* ndev)
+{
+       int index;
+       struct wl_priv *wl = wlcfg_drv_priv;
+       index = get_idx_vwdev_by_netdev(wl, (struct net_device *)ndev);
+       WL_DBG(("index : %d\n", index));
+       if (index >= 0) {
+               free_vwdev_by_index(wl, index);
+       }
+       return 0;
+}
+
 s32
 wl_cfg80211_is_progress_ifadd(void)
 {
index 262335ef99c20d2a4ce0e05d728f3e798a0929f7..232db1b1f830b29b4044ce1b301c30b7e8bd9a0d 100644 (file)
@@ -2,13 +2,13 @@
  * Linux cfg80211 driver
  *
  * Copyright (C) 1999-2011, Broadcom Corporation
- * 
+ *
  *         Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
  * under the terms of the GNU General Public License version 2 (the "GPL"),
  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  * following added to such license:
- * 
+ *
  *      As a special exception, the copyright holders of this software give you
  * permission to link this software with independent modules, and to copy and
  * distribute the resulting executable under terms of your choice, provided that
@@ -16,7 +16,7 @@
  * the license of that module.  An independent module is a module which is not
  * derived from this software.  The special exception does not apply to any
  * modifications of the software.
- * 
+ *
  *      Notwithstanding the above, under no circumstances may you combine this
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
@@ -452,6 +452,7 @@ static inline s32 alloc_idx_vwdev(struct wl_priv *wl)
                if (wl->vwdev[i] == NULL)
                                return i;
        }
+       WL_ERR((" *********alloc_idx_vwdev failed (%d) \n", -1));
        return -1;
 }
 
@@ -462,6 +463,7 @@ static inline s32 get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device
                if ((wl->vwdev[i] != NULL) && (wl->vwdev[i]->netdev == ndev))
                                return i;
        }
+       WL_ERR((" *********get_idx_vwdev_by_netdev failed (%d) \n", -1));
        return -1;
 }
 
@@ -531,6 +533,7 @@ extern s32 wl_cfg80211_down(void);  /* dongle down */
 extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx,
 int (*_net_attach)(dhd_pub_t *dhdp, int ifidx));
 extern s32 wl_cfg80211_notify_ifdel(struct net_device *ndev);
+extern s32 wl_cfg80211_post_del(void *ndev);
 extern s32 wl_cfg80211_is_progress_ifadd(void);
 extern s32 wl_cfg80211_is_progress_ifchange(void);
 extern s32 wl_cfg80211_is_progress_ifadd(void);