net: wireless: bcmdhd: Fix P2P GO hang issue
authorNeeraj Kumar Garg <neerajkg@broadcom.com>
Mon, 9 Jul 2012 19:18:39 +0000 (12:18 -0700)
committerDmitry Shmidt <dimitrysh@google.com>
Thu, 12 Jul 2012 17:45:50 +0000 (10:45 -0700)
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
drivers/net/wireless/bcmdhd/include/wlioctl.h
drivers/net/wireless/bcmdhd/wl_cfg80211.c

index 891d15c03c927fe45ea679b9b3be8eab91bc3085..e543bfa6d17591571ebcecee67292afa70b4385a 100644 (file)
@@ -180,6 +180,7 @@ typedef struct wlc_ssid {
        uchar       SSID[32];
 } wlc_ssid_t;
 
+#define WL_BSS_FLAGS_FROM_BEACON    0x01
 
 #define WL_BSSTYPE_INFRA 1
 #define WL_BSSTYPE_INDEP 0
index 5e61aa42739ad1c72836601ff545e56fe72abc12..7049d77f24d3122c0f47e8f6cb2666d00e7a1e92 100644 (file)
@@ -781,8 +781,6 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                WL_ERR(("name is NULL\n"));
                return NULL;
        }
-       if (wl->iface_cnt == IFACE_MAX_CNT)
-               return ERR_PTR(-ENOMEM);
        if (wl->p2p_supported && (wlif_type != -1)) {
                if (wl_get_p2p_status(wl, IF_DELETING)) {
                        /* wait till IF_DEL is complete
@@ -810,6 +808,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                                WL_ERR(("timeount < 0, return -EAGAIN\n"));
                                return ERR_PTR(-EAGAIN);
                        }
+                       /* It should be now be safe to put this check here since we are sure
+                        * by now netdev_notifier (unregister) would have been called */
+                       if (wl->iface_cnt == IFACE_MAX_CNT)
+                               return ERR_PTR(-ENOMEM);
                }
                if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
                        p2p_on(wl) = true;
@@ -1100,7 +1102,7 @@ wl_cfg80211_notify_ifdel(void)
 
        WL_DBG(("Enter \n"));
        wl_clr_p2p_status(wl, IF_DELETING);
-
+       wake_up_interruptible(&wl->netif_change_event);
        return 0;
 }
 
@@ -1578,6 +1580,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
        /* Arm scan timeout timer */
        mod_timer(&wl->scan_timeout, jiffies + WL_SCAN_TIMER_INTERVAL_MS * HZ / 1000);
        iscan_req = false;
+       wl->scan_request = request;
        if (request) {          /* scan bss */
                ssids = request->ssids;
                if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) {
@@ -1658,7 +1661,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                /* we don't do iscan in ibss */
                ssids = this_ssid;
        }
-       wl->scan_request = request;
        wl_set_drv_status(wl, SCANNING, ndev);
        if (iscan_req) {
                err = wl_do_iscan(wl, request);
@@ -1722,7 +1724,12 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
 
 scan_out:
        wl_clr_drv_status(wl, SCANNING, ndev);
-       wl->scan_request = NULL;
+       if (wl->scan_request) {
+               if (timer_pending(&wl->scan_timeout))
+                       del_timer_sync(&wl->scan_timeout);
+               cfg80211_scan_done(wl->scan_request, true);
+               wl->scan_request = NULL;
+       }
        return err;
 }
 
@@ -4731,29 +4738,6 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
 
        signal = notif_bss_info->rssi * 100;
 
-#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
-       if (wl->p2p && wl->p2p_net && wl->scan_request &&
-               ((wl->scan_request->dev == wl->p2p_net) ||
-               (wl->scan_request->dev == wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)))){
-#else
-       if (p2p_is_on(wl) && ( p2p_scan(wl) ||
-               (wl->scan_request->dev == wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)))) {
-#endif
-               /* find the P2PIE, if we do not find it, we will discard this frame */
-               wifi_p2p_ie_t * p2p_ie;
-               if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)beacon_proberesp->variable,
-                       wl_get_ielen(wl))) == NULL) {
-                       WL_ERR(("Couldn't find P2PIE in probe response/beacon\n"));
-                       kfree(notif_bss_info);
-                       return err;
-               }
-               else if( wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO) == NULL)
-               {
-                       WL_DBG(("Couldn't find P2P_SEID_DEV_INFO in probe response/beacon\n"));
-                       kfree(notif_bss_info);
-                       return err;
-               }
-       }
        if (!mgmt->u.probe_resp.timestamp) {
                struct timeval tv;
 
@@ -5700,6 +5684,13 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
                        WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
                        wl_clr_p2p_status(wl, GO_NEG_PHASE);
                }
+
+               if (act_frm && (act_frm->subtype == P2P_PAF_GON_RSP)) {
+                       /* Cancel the dwell time of req frame */
+                       WL_DBG(("P2P: Received GO NEG Resp frame, cancelling the dwell time\n"));
+                       wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
+                               wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
+               }
        } else {
                mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
        }
@@ -6337,6 +6328,7 @@ static s32 wl_escan_handler(struct wl_priv *wl,
        wl_scan_results_t *list;
        u32 bi_length;
        u32 i;
+       wifi_p2p_ie_t * p2p_ie;
        u8 *p2p_dev_addr = NULL;
        WL_DBG((" enter event type : %d, status : %d \n",
                ntoh32(e->event_type), ntoh32(e->status)));
@@ -6403,6 +6395,22 @@ static s32 wl_escan_handler(struct wl_priv *wl,
                                WL_ERR(("Buffer is too small: ignoring\n"));
                                goto exit;
                        }
+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+                       if (wl->p2p_net && wl->scan_request &&
+                               wl->scan_request->dev == wl->p2p_net) {
+#else
+                       if (p2p_is_on(wl) && p2p_scan(wl)) {
+#endif
+                               /* p2p scan && allow only probe response */
+                               if (bi->flags & WL_BSS_FLAGS_FROM_BEACON)
+                                       goto exit;
+                               if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset,
+                                       bi->ie_length)) == NULL) {
+                                               WL_ERR(("Couldn't find P2PIE in probe"
+                                                       " response/beacon\n"));
+                                               goto exit;
+                               }
+                       }
 #define WLC_BSS_RSSI_ON_CHANNEL 0x0002
                        for (i = 0; i < list->count; i++) {
                                bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))