net: wireless: bcmdhd: Update to Version 5.90.195.61
Dmitry Shmidt [Tue, 1 May 2012 18:00:21 +0000 (11:00 -0700)]
- Deauth frame from p2p GO to client doesn't go from firmware
  if we do del_virtual_iface immediately. Putting a delay after
  sending deauth frame to allowed FW to send out deauth frame.
- IF_DEL operation was timing out due to wrong status check.
  Fixed it and added few debug prints.
- Sending Provision Discovery directly to GO instead of doing
  an internal scan. Also put the internal scan count to 3 to have
  better timings for GO-NEG.
- Increase beacon timeout only for concurrent mode. For STA only
  operation, use the default beacon timeout value (4).
- If scan abort is due to timeout, aborting the scan in FW is not
  required. Moreover, as this scan_timeout call is coming in timer
  interrupt context, all blocking calls such as fw scan abort will
  result in kernel panic : don’t call abort in Firmware.
- Add p2p_cancel_listen routine. Fix p2p_listen_complete related
  kernel crash seen while turning off WiFi.

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>

drivers/net/wireless/bcmdhd/dhd.h
drivers/net/wireless/bcmdhd/dhd_cfg80211.c
drivers/net/wireless/bcmdhd/dhd_common.c
drivers/net/wireless/bcmdhd/dhd_linux.c
drivers/net/wireless/bcmdhd/dhd_sdio.c
drivers/net/wireless/bcmdhd/include/epivers.h
drivers/net/wireless/bcmdhd/wl_cfg80211.c
drivers/net/wireless/bcmdhd/wl_cfg80211.h
drivers/net/wireless/bcmdhd/wl_cfgp2p.c
drivers/net/wireless/bcmdhd/wl_cfgp2p.h

index d1648b7..3911f33 100644 (file)
  * 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.h 325862 2012-04-04 22:59:48Z $
+ * $Id: dhd.h 328934 2012-04-23 05:15:42Z $
  */
 
-
-
+/****************
+ * Common types *
+ */
 
 #ifndef _dhd_h_
 #define _dhd_h_
@@ -90,6 +91,9 @@ enum dhd_bus_state {
 #define DHD_SCAN_ACTIVE_TIME    40 /* ms : Embedded default Active setting from DHD Driver */
 #define DHD_SCAN_PASSIVE_TIME  130 /* ms: Embedded default Passive setting from DHD Driver */
 
+#define DHD_BEACON_TIMEOUT_NORMAL      4
+#define DHD_BEACON_TIMEOUT_HIGH                10
+
 enum dhd_bus_wake_state {
        WAKE_LOCK_OFF,
        WAKE_LOCK_PRIV,
index 2503f51..183891d 100644 (file)
@@ -41,7 +41,9 @@ static int dhd_dongle_up = FALSE;
 
 static s32 wl_dongle_up(struct net_device *ndev, u32 up);
 
-
+/**
+ * Function implementations
+ */
 
 s32 dhd_cfg80211_init(struct wl_priv *wl)
 {
@@ -70,13 +72,22 @@ s32 dhd_cfg80211_down(struct wl_priv *wl)
 s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val)
 {
        dhd_pub_t *dhd =  (dhd_pub_t *)(wl->pub);
+       int bcn_timeout = DHD_BEACON_TIMEOUT_HIGH;
+       char iovbuf[30];
+
        dhd->op_mode |= val;
        WL_ERR(("Set : op_mode=%d\n", dhd->op_mode));
 
 #ifdef ARP_OFFLOAD_SUPPORT
+       /* IF P2P is enabled, disable arpoe */
        dhd_arp_offload_set(dhd, 0);
        dhd_arp_offload_enable(dhd, false);
-#endif
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+       /* Setup timeout if Beacons are lost and roam is off to report link down */
+       bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
+       dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
 
        return 0;
 }
@@ -84,13 +95,21 @@ s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val)
 s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl)
 {
        dhd_pub_t *dhd =  (dhd_pub_t *)(wl->pub);
+       int bcn_timeout = DHD_BEACON_TIMEOUT_NORMAL;
+       char iovbuf[30];
+
        dhd->op_mode &= ~CONCURENT_MASK;
        WL_ERR(("Clean : op_mode=%d\n", dhd->op_mode));
 
 #ifdef ARP_OFFLOAD_SUPPORT
+       /* IF P2P is disabled, enable arpoe back for STA mode. */
        dhd_arp_offload_set(dhd, dhd_arp_mode);
        dhd_arp_offload_enable(dhd, true);
-#endif
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+       /* Setup timeout if Beacons are lost and roam is off to report link down */
+       bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
+       dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
 
        return 0;
 }
index 1e7a067..d9810ac 100644 (file)
@@ -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: dhd_common.c 319098 2012-03-07 01:05:20Z $
+ * $Id: dhd_common.c 329682 2012-04-26 09:20:38Z $
  */
 #include <typedefs.h>
 #include <osl.h>
@@ -1001,6 +1001,9 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
        datalen = ntoh32_ua((void *)&event->datalen);
        evlen = datalen + sizeof(bcm_event_t);
 
+       DHD_TRACE(("RX: event_type:%d flags:%d status:%d reason:%d \n",
+                                                               type, flags, status, reason));
+
        switch (type) {
 #ifdef PROP_TXSTATUS
        case WLC_E_FIFO_CREDIT_MAP:
@@ -1728,6 +1731,7 @@ fail:
 
 /*
  * returns = TRUE if associated, FALSE if not associated
+ * third paramter retval can return error from error
  */
 bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
 {
@@ -1896,7 +1900,7 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
                DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__));
                return ret;
        }
-#endif
+#endif /* !WL_SCHED_SCAN */
 
        /* Enable/disable PNO */
        if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) {
index 9873897..320ce59 100644 (file)
@@ -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 325862 2012-04-04 22:59:48Z $
+ * $Id: dhd_linux.c 329682 2012-04-26 09:20:38Z $
  */
 
 #include <typedefs.h>
@@ -1473,6 +1473,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
                        */
                        ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++;
                        PKTFREE(dhdp->osh, pktbuf, TRUE);
+                       DHD_TRACE(("RX: wlfc header \n"));
                        continue;
                }
 #endif
@@ -2964,7 +2965,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
        uint power_mode = PM_FAST;
        uint32 dongle_align = DHD_SDALIGN;
        uint32 glom = 0;
-       uint bcn_timeout = 10;
+       uint bcn_timeout = DHD_BEACON_TIMEOUT_NORMAL;
+
        uint retry_max = 3;
 #if defined(ARP_OFFLOAD_SUPPORT)
        int arpoe = 1;
index 3086bb3..954d829 100644 (file)
@@ -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: dhd_sdio.c 325395 2012-04-03 03:57:43Z $
+ * $Id: dhd_sdio.c 326662 2012-04-10 06:38:08Z $
  */
 
 #include <typedefs.h>
@@ -4616,8 +4616,7 @@ clkwait:
                int ret, i;
                uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
 
-               if (((bus->sih->chip == BCM4329_CHIP_ID) ||   /* limit to 4329 & 4330 for now  */
-                        (bus->sih->chip == BCM4330_CHIP_ID)) && (*frame_seq != bus->tx_seq)) {
+               if (*frame_seq != bus->tx_seq) {
                        DHD_INFO(("%s IOCTL frame seq lag detected!"
                                " frm_seq:%d != bus->tx_seq:%d, corrected\n",
                                __FUNCTION__, *frame_seq, bus->tx_seq));
index b3560bd..3bff73e 100644 (file)
 
 #define        EPI_RC_NUMBER           195
 
-#define        EPI_INCREMENTAL_NUMBER  53
+#define        EPI_INCREMENTAL_NUMBER  61
 
 #define        EPI_BUILD_NUMBER        0
 
-#define        EPI_VERSION             5, 90, 195, 53
+#define        EPI_VERSION             5, 90, 195, 61
 
-#define        EPI_VERSION_NUM         0x055ac335
+#define        EPI_VERSION_NUM         0x055ac33d
 
 #define EPI_VERSION_DEV                5.90.195
 
 
-#define        EPI_VERSION_STR         "5.90.195.53"
+#define        EPI_VERSION_STR         "5.90.195.61"
 
 #endif 
index f717f8f..98e498d 100644 (file)
@@ -100,7 +100,10 @@ static const struct ieee80211_regdomain brcm_regdom = {
                 * we need cfg80211 to allow it (reg_flags = 0); so that
                 * hostapd could request auto channel by sending down ch 14
                 */
-               REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
+               REG_RULE(2484-10, 2484+10, 20, 6, 20,
+               NL80211_RRF_PASSIVE_SCAN |
+               NL80211_RRF_NO_IBSS |
+               NL80211_RRF_NO_OFDM),
                /* IEEE 802.11a, channel 36..64 */
                REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
                /* IEEE 802.11a, channel 100..165 */
@@ -735,7 +738,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
        s32 mode = 0;
 #if defined(WL_ENABLE_P2P_IF)
        s32 dhd_mode = 0;
-#endif
+#endif /* (WL_ENABLE_P2P_IF) */
        chanspec_t chspec;
        struct wl_priv *wl = wiphy_priv(wiphy);
        struct net_device *_ndev;
@@ -807,7 +810,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                                return ERR_PTR(-EAGAIN);
                        }
                }
-               if (!p2p_is_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
+               if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
                        p2p_on(wl) = true;
                        wl_cfgp2p_set_firm_p2p(wl);
                        wl_cfgp2p_init_discovery(wl);
@@ -819,7 +822,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                memset(wl->p2p->vir_ifname, 0, IFNAMSIZ);
                strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
 
-
+               wldev_iovar_setint(_ndev, "mpc", 0);
+               wl_notify_escan_complete(wl, _ndev, true, true);
                /* In concurrency case, STA may be already associated in a particular channel.
                 * so retrieve the current channel of primary interface and then start the virtual
                 * interface on that.
@@ -874,8 +878,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                                else if (type == NL80211_IFTYPE_P2P_GO)
                                        dhd_mode = P2P_GO_ENABLED;
                                DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode));
-#endif
-
+#endif /* (WL_ENABLE_P2P_IF) */
+                               /* Start the P2P I/F with PM disabled. Enable PM from
+                                * the framework
+                                */
                                 if ((type == NL80211_IFTYPE_P2P_CLIENT) || (
                                         type == NL80211_IFTYPE_P2P_GO))
                                        vwdev->ps = NL80211_PS_DISABLED;
@@ -920,7 +926,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
        if (wl->p2p_supported) {
                memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
                if (wl->p2p->vif_created) {
-                       if (wl->scan_request) {
+                       if (wl_get_drv_status(wl, SCANNING, dev)) {
                                wl_notify_escan_complete(wl, dev, true, true);
                        }
                        wldev_iovar_setint(dev, "mpc", 1);
@@ -948,7 +954,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
                                WL_DBG(("IFDEL operation done\n"));
 #if  defined(WL_ENABLE_P2P_IF)
                                DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl));
-#endif
+#endif /*  (WL_ENABLE_P2P_IF)) */
                        } else {
                                WL_ERR(("IFDEL didn't complete properly\n"));
                        }
@@ -972,7 +978,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
        chanspec_t chspec;
        struct wl_priv *wl = wiphy_priv(wiphy);
 
-       WL_DBG(("Enter \n"));
+       WL_DBG(("Enter type %d\n", type));
        switch (type) {
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_WDS:
@@ -1003,8 +1009,10 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
                wl_set_mode_by_netdev(wl, ndev, mode);
                if (wl->p2p_supported && wl->p2p->vif_created) {
                        WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created,
-                       p2p_on(wl)));
+                               p2p_on(wl)));
                        wldev_iovar_setint(ndev, "mpc", 0);
+                       wl_notify_escan_complete(wl, ndev, true, true);
+
                        /* In concurrency case, STA may be already associated in a particular
                         * channel. so retrieve the current channel of primary interface and
                         * then start the virtual interface on that.
@@ -1121,6 +1129,7 @@ wl_cfg80211_ifdel_ops(struct net_device *ndev)
                WL_DBG(("index : %d\n", index));
 
        }
+
        /* Wake up any waiting thread */
        wake_up_interruptible(&wl->netif_change_event);
 
@@ -2007,7 +2016,11 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
        WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
 
        if (is_wps_conn(sme)) {
-               err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
+               if (sme->privacy)
+                       err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
+               else
+                       /* WPS-2.0 allowes no security */
+                       err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx);
        } else {
                WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
                err = wldev_iovar_setint_bsscfg(dev, "wsec",
@@ -2847,7 +2860,6 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
                err = -ENODEV;
                if (!wl_get_drv_status(wl, CONNECTED, dev) ||
                        (dhd_is_associated(dhd, NULL, &err) == FALSE)) {
-
                        WL_ERR(("NOT assoc: %d\n", err));
                        goto get_station_err;
                }
@@ -3168,7 +3180,7 @@ wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
 
        /* Our scan params have 1 channel and 0 ssids */
        params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
-       (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
+               (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
 
        *out_params_size = params_size; /* rtn size to the caller */
        return params;
@@ -3195,7 +3207,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
                ndev = dev;
        }
 
-       if (wl->scan_request) {
+       if (wl_get_drv_status(wl, SCANNING, ndev)) {
                wl_notify_escan_complete(wl, ndev, true, true);
        }
        target_channel = ieee80211_frequency_to_channel(channel->center_freq);
@@ -3207,7 +3219,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
        *cookie = id;
        cfg80211_ready_on_channel(dev, *cookie, channel,
                channel_type, duration, GFP_KERNEL);
-       if (!p2p_is_on(wl)) {
+       if (wl->p2p && !wl->p2p->on) {
                get_primary_mac(wl, &primary_mac);
                wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
 
@@ -3331,7 +3343,11 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
        struct ieee80211_channel *channel, bool offchan,
        enum nl80211_channel_type channel_type,
        bool channel_type_valid, unsigned int wait,
-       const u8* buf, size_t len, u64 *cookie)
+       const u8* buf, size_t len,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
+       bool no_cck,
+#endif
+       u64 *cookie)
 {
        wl_action_frame_t *action_frame;
        wl_af_params_t *af_params;
@@ -3418,6 +3434,10 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
                        WL_DBG(("Disconnect STA : %s scb_val.val %d\n",
                                bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf),
                                scb_val.val));
+                       /* Wait for the deauth event to come, supplicant will do the delete iface immediately
+                        * and we will have problem in sending deauth frame if we delete the bss in firmware
+                        */
+                       wl_delay(400);
                        cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
                        goto exit;
 
@@ -3521,7 +3541,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        if (IS_P2P_SOCIAL(af_params->channel) &&
-               (IS_P2P_PUB_ACT_REQ(act_frm, action_frame->len) ||
+               (IS_P2P_PUB_ACT_REQ(act_frm, &act_frm->elts[0], action_frame->len) ||
                IS_GAS_REQ(sd_act_frm, action_frame->len)) &&
                wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) {
                /* channel offload require P2P IE for Probe request
@@ -3534,7 +3554,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
        } else {
                ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
                if (!ack) {
-                               for (retry = 1; retry < WL_CHANNEL_SYNC_RETRY; retry++) {
+                               for (retry = 1; retry < retry_cnt; retry++) {
                                        ack = (wl_cfgp2p_tx_action_frame(wl, dev,
                                                af_params, bssidx)) ? false : true;
                                        if (ack)
@@ -4774,17 +4794,24 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
        bool act;
        s32 err = 0;
        u32 event = ntoh32(e->event_type);
+       u32 reason;
 
        if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
                wl_notify_connect_status_ap(wl, ndev, e, data);
        } else {
                WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n",
                        ntoh32(e->event_type), ntoh32(e->status), ndev));
+               if((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DISASSOC_IND)) {
+                       reason = ntoh32(e->reason);
+                       wl->deauth_reason = reason;
+                       WL_ERR(("Received %s event with reason code: %d\n", (event == WLC_E_DEAUTH_IND)? "WLC_E_DEAUTH_IND":"WLC_E_DISASSOC_IND", reason));
+               }
                if (wl_is_linkup(wl, e, ndev)) {
                        wl_link_up(wl);
                        act = true;
                        wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT);
                        wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
+                       wl->deauth_reason = 0;
                        if (wl_is_ibssmode(wl, ndev)) {
                                printk("cfg80211_ibss_joined\n");
                                cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
@@ -4812,7 +4839,6 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
                        if (wl_get_drv_status(wl, CONNECTED, ndev)) {
                                scb_val_t scbval;
                                u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
-                               printk("link down, call cfg80211_disconnected\n");
                                wl_clr_drv_status(wl, CONNECTED, ndev);
                                if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) {
                                        /* To make sure disconnect, explictly send dissassoc
@@ -4824,7 +4850,8 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
                                        scbval.val = htod32(scbval.val);
                                        wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
                                                sizeof(scb_val_t), true);
-                                       cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
+                                       WL_ERR(("link down, calling cfg80211_disconnected with deauth_reason:%d\n", wl->deauth_reason));
+                                       cfg80211_disconnected(ndev, wl->deauth_reason , NULL, 0, GFP_KERNEL);
                                        wl_link_down(wl);
                                        wl_init_prof(wl, ndev);
                                }
@@ -5824,7 +5851,7 @@ static void wl_scan_timeout(unsigned long data)
        if (wl->scan_request) {
                WL_ERR(("timer expired\n"));
                if (wl->escan_on)
-                       wl_notify_escan_complete(wl, wl->escan_info.ndev, false, true);
+                       wl_notify_escan_complete(wl, wl->escan_info.ndev, true, false);
                else
                        wl_notify_iscan_complete(wl_to_iscan(wl), true);
        }
@@ -5880,7 +5907,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
        struct wl_priv *wl = wlcfg_drv_priv;
 
        WL_DBG(("Enter \n"));
-       if (!wdev || dev == wl_to_prmry_ndev(wl))
+       if (!wdev || !wl || dev == wl_to_prmry_ndev(wl))
                return NOTIFY_DONE;
        switch (state) {
                case NETDEV_UNREGISTER:
@@ -5945,7 +5972,7 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl,
                        }
                }
        }
-       if (!in_atomic())
+       if (timer_pending(&wl->scan_timeout))
                del_timer_sync(&wl->scan_timeout);
        spin_lock_irqsave(&wl->cfgdrv_lock, flags);
 
@@ -5987,7 +6014,6 @@ static s32 wl_escan_handler(struct wl_priv *wl,
        wl_scan_results_t *list;
        u32 bi_length;
        u32 i;
-       u8 *p2p_dev_addr = NULL;
 
        WL_DBG((" enter event type : %d, status : %d \n",
                ntoh32(e->event_type), ntoh32(e->status)));
@@ -6036,8 +6062,7 @@ static s32 wl_escan_handler(struct wl_priv *wl,
                }
 
                if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
-                       p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
-                       if (p2p_dev_addr && !memcmp(p2p_dev_addr,
+                       if (!memcmp(bi->BSSID.octet,
                                wl->afx_hdl->pending_tx_dst_addr.octet, ETHER_ADDR_LEN)) {
                                s32 channel = CHSPEC_CHANNEL(dtohchanspec(bi->chanspec));
                                WL_DBG(("ACTION FRAME SCAN : Peer found, channel : %d\n", channel));
@@ -6190,6 +6215,7 @@ static s32 wl_init_priv(struct wl_priv *wl)
        wl->iscan_kickstart = false;
        wl->active_scan = true;
        wl->rf_blocked = false;
+       wl->deauth_reason = 0;
        spin_lock_init(&wl->cfgdrv_lock);
        mutex_init(&wl->ioctl_buf_sync);
        init_waitqueue_head(&wl->netif_change_event);
@@ -6714,12 +6740,16 @@ s32 wl_update_wiphybands(struct wl_priv *wl)
                }
                if ((index >= 0) && nmode) {
                        wiphy->bands[index]->ht_cap.cap =
-                       IEEE80211_HT_CAP_DSSSCCK40
-                       | IEEE80211_HT_CAP_MAX_AMSDU | IEEE80211_HT_CAP_RX_STBC;
+                               IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40 |
+                               IEEE80211_HT_CAP_MAX_AMSDU;
                        wiphy->bands[index]->ht_cap.ht_supported = TRUE;
-                       wiphy->bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K;
+                       wiphy->bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
                        wiphy->bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
                }
+
+               if ((index >= 0) && bw_40) {
+                       wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+               }
        }
 
        wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
@@ -7046,7 +7076,8 @@ static void wl_init_eq_lock(struct wl_priv *wl)
 
 static void wl_delay(u32 ms)
 {
-       if (in_atomic() || ms < 1000 / HZ) {
+       if (ms < 1000 / HZ) {
+               cond_resched();
                mdelay(ms);
        } else {
                msleep(ms);
index 818eff5..fba8531 100644 (file)
@@ -131,8 +131,8 @@ do {                                                                        \
 #define IFACE_MAX_CNT          2
 
 #define WL_SCAN_TIMER_INTERVAL_MS      8000 /* Scan timeout */
-#define WL_CHANNEL_SYNC_RETRY  1
-#define WL_ACT_FRAME_RETRY 5
+#define WL_CHANNEL_SYNC_RETRY  3
+#define WL_ACT_FRAME_RETRY 4
 
 #define WL_INVALID             -1
 
@@ -449,6 +449,7 @@ struct wl_priv {
 #endif /* WL_SCHED_SCAN */
        bool sched_scan_running;        /* scheduled scan req status */
        u16 hostapd_chan;            /* remember chan requested by framework for hostapd  */
+       u16 deauth_reason;           /* Place holder to save deauth/disassoc reasons */
 };
 
 static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss)
index 880123e..cfa5ac3 100644 (file)
@@ -105,6 +105,7 @@ bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len)
 
        return false;
 }
+
 bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
 {
 
@@ -128,6 +129,7 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
                return false;
 
 }
+
 void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len)
 {
        wifi_p2p_pub_act_frame_t *pact_frm;
@@ -271,7 +273,6 @@ wl_cfgp2p_init_priv(struct wl_priv *wl)
        wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
        wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL;
        wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0;
-       spin_lock_init(&wl->p2p->timer_lock);
        return BCME_OK;
 
 }
@@ -318,7 +319,7 @@ wl_cfgp2p_set_firm_p2p(struct wl_priv *wl)
        ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
                sizeof(null_eth_addr), wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync);
        if (ret && ret != BCME_UNSUPPORTED) {
-               CFGP2P_ERR(("failed to update device address\n"));
+               CFGP2P_ERR(("failed to update device address ret %d\n", ret));
        }
        return ret;
 }
@@ -539,7 +540,7 @@ wl_cfgp2p_init_discovery(struct wl_priv *wl)
 
        /* Set the initial discovery state to SCAN */
        ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
-               wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
+               wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
 
        if (unlikely(ret != 0)) {
                CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
@@ -690,7 +691,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
 #define P2PAPI_SCAN_NPROBES 1
 #define P2PAPI_SCAN_DWELL_TIME_MS 50
 #define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
-#define P2PAPI_SCAN_HOME_TIME_MS 10
+#define P2PAPI_SCAN_HOME_TIME_MS 60
        struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
        wl_set_p2p_status(wl, SCANNING);
        /* Allocate scan params which need space for 3 channels and 0 ssids */
@@ -1180,12 +1181,15 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev,
        s32 ret = BCME_OK;
 
        CFGP2P_DBG((" Enter\n"));
+
+       /* If p2p_info is de-initialized, do nothing  */
+       if (!wl->p2p)
+               return ret;
+
        if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) {
                wl_set_p2p_status(wl, LISTEN_EXPIRED);
                if (timer_pending(&wl->p2p->listen_timer)) {
-                       spin_lock_bh(&wl->p2p->timer_lock);
                        del_timer_sync(&wl->p2p->listen_timer);
-                       spin_unlock_bh(&wl->p2p->timer_lock);
                }
                cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, &wl->remain_on_chan,
                    wl->remain_on_chan_type, GFP_KERNEL);
@@ -1213,6 +1217,33 @@ wl_cfgp2p_listen_expired(unsigned long data)
 }
 
 /*
+ *  Routine for cancelling the P2P LISTEN
+ */
+s32
+wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev,
+                         bool notify)
+{
+       WL_DBG(("Enter \n"));
+
+       /* Irrespective of whether timer is running or not, reset
+        * the LISTEN state.
+        */
+       wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
+               wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
+
+       if (timer_pending(&wl->p2p->listen_timer)) {
+               del_timer_sync(&wl->p2p->listen_timer);
+
+               if (notify)
+                       cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id,
+                               &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL);
+       }
+
+
+       return 0;
+}
+
+/*
  * Do a P2P Listen on the given channel for the given duration.
  * A listen consists of sitting idle and responding to P2P probe requests
  * with a P2P probe response.
@@ -1531,8 +1562,10 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev)
 s32
 wl_cfgp2p_down(struct wl_priv *wl)
 {
-       if (timer_pending(&wl->p2p->listen_timer))
-               del_timer_sync(&wl->p2p->listen_timer);
+
+       wl_cfgp2p_cancel_listen(wl,
+               wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE);
+
        wl_cfgp2p_deinit_priv(wl);
        return 0;
 }
index 1e5b119..be497c3 100644 (file)
@@ -77,7 +77,6 @@ struct p2p_info {
        wl_p2p_sched_t noa;
        wl_p2p_ops_t ops;
        wlc_ssid_t ssid;
-       spinlock_t timer_lock;
 };
 
 /* dongle status */
@@ -268,14 +267,16 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl);
 #define WL_P2P_INTERFACE_PREFIX "p2p"
 #define WL_P2P_TEMP_CHAN "11"
 
+/* If the provision discovery is for JOIN operations, then we need not do an internal scan to find GO */
+#define IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len) (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL )
 
 #define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \
                                        ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \
                                        (frame->action == P2PSD_ACTION_ID_GAS_CREQ)))
-#define IS_P2P_PUB_ACT_REQ(frame, len) (wl_cfgp2p_is_pub_action(frame, len) && \
+#define IS_P2P_PUB_ACT_REQ(frame, p2p_ie, len) (wl_cfgp2p_is_pub_action(frame, len) && \
                                                ((frame->subtype == P2P_PAF_GON_REQ) || \
                                                (frame->subtype == P2P_PAF_INVITE_REQ) || \
-                                               (frame->subtype == P2P_PAF_PROVDIS_REQ)))
+                                               ((frame->subtype == P2P_PAF_PROVDIS_REQ) && IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len))))
 #define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3))
 #define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0)
 #endif                         /* _wl_cfgp2p_h_ */