staging: brcm80211: Added support to change scan times from brcmfmac driver
[pandora-kernel.git] / drivers / staging / brcm80211 / brcmfmac / wl_cfg80211.c
index 555b056..450e072 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/firmware.h>
 #include <wl_cfg80211.h>
 
+void sdioh_sdio_set_host_pm_flags(int flag);
+
 static struct sdio_func *cfg80211_sdio_func;
 static struct wl_dev *wl_cfg80211_dev;
 static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
@@ -180,41 +182,34 @@ static void wl_init_prof(struct wl_profile *prof);
 ** cfg80211 connect utilites
 */
 static s32 wl_set_wpa_version(struct net_device *dev,
-                               struct cfg80211_connect_params *sme);
+                       struct cfg80211_connect_params *sme);
 static s32 wl_set_auth_type(struct net_device *dev,
-                             struct cfg80211_connect_params *sme);
+                       struct cfg80211_connect_params *sme);
 static s32 wl_set_set_cipher(struct net_device *dev,
-                              struct cfg80211_connect_params *sme);
+                       struct cfg80211_connect_params *sme);
 static s32 wl_set_key_mgmt(struct net_device *dev,
-                            struct cfg80211_connect_params *sme);
+                       struct cfg80211_connect_params *sme);
 static s32 wl_set_set_sharedkey(struct net_device *dev,
-                                 struct cfg80211_connect_params *sme);
+                       struct cfg80211_connect_params *sme);
 static s32 wl_get_assoc_ies(struct wl_priv *wl);
+static void wl_clear_assoc_ies(struct wl_priv *wl);
 static void wl_ch_to_chanspec(int ch,
        struct wl_join_params *join_params, size_t *join_params_size);
 
 /*
 ** information element utilities
 */
-static void wl_rst_ie(struct wl_priv *wl);
 static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v);
-static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size);
-static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size);
-static u32 wl_get_ielen(struct wl_priv *wl);
-
 static s32 wl_mode_to_nl80211_iftype(s32 mode);
-
 static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface,
-                                         struct device *dev);
+                       struct device *dev);
 static void wl_free_wdev(struct wl_priv *wl);
-
 static s32 wl_inform_bss(struct wl_priv *wl);
 static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
 static s32 wl_update_bss_info(struct wl_priv *wl);
-
 static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
-                          u8 key_idx, const u8 *mac_addr,
-                          struct key_params *params);
+                       u8 key_idx, const u8 *mac_addr,
+                       struct key_params *params);
 
 /*
 ** key indianess swap utilities
@@ -240,7 +235,6 @@ static void *wl_get_drvdata(struct wl_dev *dev);
 ** ibss mode utilities
 */
 static bool wl_is_ibssmode(struct wl_priv *wl);
-static bool wl_is_ibssstarter(struct wl_priv *wl);
 
 /*
 ** dongle up/down , default configuration utilities
@@ -248,7 +242,6 @@ static bool wl_is_ibssstarter(struct wl_priv *wl);
 static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e);
 static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e);
 static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e);
-static void wl_link_up(struct wl_priv *wl);
 static void wl_link_down(struct wl_priv *wl);
 static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype);
 static s32 __wl_cfg80211_up(struct wl_priv *wl);
@@ -266,18 +259,19 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up);
 static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
 static s32 wl_dongle_glom(struct net_device *ndev, u32 glom,
                            u32 dongle_align);
-static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
-                           u32 bcn_timeout);
-static s32 wl_dongle_eventmsg(struct net_device *ndev);
-static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
-                               s32 scan_unassoc_time);
 static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe,
                               s32 arp_ol);
 static s32 wl_pattern_atoh(s8 *src, s8 *dst);
 static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
 static s32 wl_update_wiphybands(struct wl_priv *wl);
 #endif                         /* !EMBEDDED_PLATFORM */
+
+static s32 wl_dongle_eventmsg(struct net_device *ndev);
+static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
+                               s32 scan_unassoc_time, s32 scan_passive_time);
 static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
+static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
+                           u32 bcn_timeout);
 
 /*
 ** iscan handler
@@ -604,10 +598,10 @@ wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
        struct wl_priv *wl = wiphy_to_wl(wiphy);
        struct wireless_dev *wdev;
        s32 infra = 0;
-       s32 ap = 0;
        s32 err = 0;
 
        CHECK_SYS_UP();
+
        switch (type) {
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_WDS:
@@ -616,32 +610,32 @@ wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
                return -EOPNOTSUPP;
        case NL80211_IFTYPE_ADHOC:
                wl->conf->mode = WL_MODE_IBSS;
+               infra = 0;
                break;
        case NL80211_IFTYPE_STATION:
                wl->conf->mode = WL_MODE_BSS;
                infra = 1;
                break;
        default:
-               return -EINVAL;
+               err = -EINVAL;
+               goto done;
        }
+
        infra = cpu_to_le32(infra);
-       ap = cpu_to_le32(ap);
-       wdev = ndev->ieee80211_ptr;
-       wdev->iftype = type;
-       WL_DBG("%s : ap (%d), infra (%d)\n", ndev->name, ap, infra);
        err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
        if (unlikely(err)) {
                WL_ERR("WLC_SET_INFRA error (%d)\n", err);
-               return err;
-       }
-       err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap));
-       if (unlikely(err)) {
-               WL_ERR("WLC_SET_AP error (%d)\n", err);
-               return err;
+               err = -EAGAIN;
+       } else {
+               wdev = ndev->ieee80211_ptr;
+               wdev->iftype = type;
        }
 
-       /* -EINPROGRESS: Call commit handler */
-       return -EINPROGRESS;
+       WL_INFO("IF Type = %s\n",
+               (wl->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra");
+
+done:
+       return err;
 }
 
 static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid)
@@ -989,68 +983,137 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
                      struct cfg80211_ibss_params *params)
 {
        struct wl_priv *wl = wiphy_to_wl(wiphy);
-       struct cfg80211_bss *bss;
-       struct ieee80211_channel *chan;
        struct wl_join_params join_params;
-       struct cfg80211_ssid ssid;
-       s32 scan_retry = 0;
+       size_t join_params_size = 0;
        s32 err = 0;
+       s32 wsec = 0;
+       s32 bcnprd;
 
        CHECK_SYS_UP();
-       if (params->bssid) {
-               WL_ERR("Invalid bssid\n");
+
+       if (params->ssid)
+               WL_DBG("SSID: %s\n", params->ssid);
+       else {
+               WL_DBG("SSID: NULL, Not supported\n");
                return -EOPNOTSUPP;
        }
-       bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
-       if (!bss) {
-               memcpy(ssid.ssid, params->ssid, params->ssid_len);
-               ssid.ssid_len = params->ssid_len;
-               do {
-                       if (unlikely
-                           (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
-                            -EBUSY)) {
-                               wl_delay(150);
-                       } else {
-                               break;
-                       }
-               } while (++scan_retry < WL_SCAN_RETRY_MAX);
-               rtnl_unlock();  /* to allow scan_inform to paropagate
-                                        to cfg80211 plane */
-               schedule_timeout_interruptible(4 * HZ); /* wait 4 secons
-                                                till scan done.... */
-               rtnl_lock();
-               bss = cfg80211_get_ibss(wiphy, NULL,
-                                       params->ssid, params->ssid_len);
+
+       if (params->bssid)
+               WL_DBG("BSSID: %02X %02X %02X %02X %02X %02X\n",
+               params->bssid[0], params->bssid[1], params->bssid[2],
+               params->bssid[3], params->bssid[4], params->bssid[5]);
+       else
+               WL_DBG("No BSSID specified\n");
+
+       if (params->channel)
+               WL_DBG("channel: %d\n", params->channel->center_freq);
+       else
+               WL_DBG("no channel specified\n");
+
+       if (params->channel_fixed)
+               WL_DBG("fixed channel required\n");
+       else
+               WL_DBG("no fixed channel required\n");
+
+       if (params->ie && params->ie_len)
+               WL_DBG("ie len: %d\n", params->ie_len);
+       else
+               WL_DBG("no ie specified\n");
+
+       if (params->beacon_interval)
+               WL_DBG("beacon interval: %d\n", params->beacon_interval);
+       else
+               WL_DBG("no beacon interval specified\n");
+
+       if (params->basic_rates)
+               WL_DBG("basic rates: %08X\n", params->basic_rates);
+       else
+               WL_DBG("no basic rates specified\n");
+
+       if (params->privacy)
+               WL_DBG("privacy required\n");
+       else
+               WL_DBG("no privacy required\n");
+
+       /* Configure Privacy for starter */
+       if (params->privacy)
+               wsec |= WEP_ENABLED;
+
+       err = wl_dev_intvar_set(dev, "wsec", wsec);
+       if (unlikely(err)) {
+               WL_ERR("wsec failed (%d)\n", err);
+               goto done;
+       }
+
+       /* Configure Beacon Interval for starter */
+       if (params->beacon_interval)
+               bcnprd = cpu_to_le32(params->beacon_interval);
+       else
+               bcnprd = cpu_to_le32(100);
+
+       err = wl_dev_ioctl(dev, WLC_SET_BCNPRD, &bcnprd, sizeof(bcnprd));
+       if (unlikely(err)) {
+               WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
+               goto done;
        }
-       if (bss) {
-               wl->ibss_starter = false;
-               WL_DBG("Found IBSS\n");
+
+       /* Configure required join parameter */
+       memset(&join_params, 0, sizeof(wl_join_params_t));
+
+       /* SSID */
+       join_params.ssid.SSID_len =
+                       (params->ssid_len > 32) ? 32 : params->ssid_len;
+       memcpy(join_params.ssid.SSID, params->ssid, join_params.ssid.SSID_len);
+       join_params.ssid.SSID_len = cpu_to_le32(join_params.ssid.SSID_len);
+       join_params_size = sizeof(join_params.ssid);
+       wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
+
+       /* BSSID */
+       if (params->bssid) {
+               memcpy(join_params.params.bssid, params->bssid, ETH_ALEN);
+               join_params_size =
+                       sizeof(join_params.ssid) + WL_ASSOC_PARAMS_FIXED_SIZE;
        } else {
-               wl->ibss_starter = true;
+               memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
        }
-       chan = params->channel;
-       if (chan)
-               wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
-       /*
-        ** Join with specific BSSID and cached SSID
-        ** If SSID is zero join based on BSSID only
-        */
-       memset(&join_params, 0, sizeof(join_params));
-       memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
-              params->ssid_len);
-       join_params.ssid.SSID_len = cpu_to_le32(params->ssid_len);
-       if (params->bssid)
-               memcpy(&join_params.params.bssid, params->bssid,
-                      ETH_ALEN);
-       else
-               memset(&join_params.params.bssid, 0, ETH_ALEN);
+       wl_update_prof(wl, NULL, &join_params.params.bssid, WL_PROF_BSSID);
+
+       /* Channel */
+       if (params->channel) {
+               u32 target_channel;
+
+               wl->channel =
+                       ieee80211_frequency_to_channel(
+                               params->channel->center_freq);
+               if (params->channel_fixed) {
+                       /* adding chanspec */
+                       wl_ch_to_chanspec(wl->channel,
+                               &join_params, &join_params_size);
+               }
+
+               /* set channel for starter */
+               target_channel = cpu_to_le32(wl->channel);
+               err = wl_dev_ioctl(dev, WLC_SET_CHANNEL,
+                       &target_channel, sizeof(target_channel));
+               if (unlikely(err)) {
+                       WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
+                       goto done;
+               }
+       } else
+               wl->channel = 0;
+
+       wl->ibss_starter = false;
+
 
-       err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params,
-                       sizeof(join_params));
+       err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size);
        if (unlikely(err)) {
-               WL_ERR("Error (%d)\n", err);
-               return err;
+               WL_ERR("WLC_SET_SSID failed (%d)\n", err);
+               goto done;
        }
+
+       set_bit(WL_STATUS_CONNECTING, &wl->status);
+
+done:
        return err;
 }
 
@@ -1333,10 +1396,12 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                return -EOPNOTSUPP;
        }
        if (chan) {
-               wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
+               wl->channel =
+                       ieee80211_frequency_to_channel(chan->center_freq);
                WL_DBG("channel (%d), center_req (%d)\n",
-                      wl->channel, chan->center_freq);
-       }
+                       wl->channel, chan->center_freq);
+       } else
+               wl->channel = 0;
        WL_DBG("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
        err = wl_set_wpa_version(dev, sme);
        if (unlikely(err))
@@ -1370,15 +1435,18 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
        join_params.ssid.SSID_len = cpu_to_le32(join_params.ssid.SSID_len);
        wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
-       memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
 
-       wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
-       WL_DBG("join_param_size %zu\n", join_params_size);
+       if (sme->bssid)
+               memcpy(join_params.params.bssid, sme->bssid, ETH_ALEN);
+       else
+               memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
 
        if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
                WL_DBG("ssid \"%s\", len (%d)\n",
                       join_params.ssid.SSID, join_params.ssid.SSID_len);
        }
+
+       wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
        err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size);
        if (unlikely(err)) {
                WL_ERR("error (%d)\n", err);
@@ -1395,23 +1463,22 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
 {
        struct wl_priv *wl = wiphy_to_wl(wiphy);
        scb_val_t scbval;
-       bool act = false;
        s32 err = 0;
 
        WL_DBG("Reason %d\n", reason_code);
        CHECK_SYS_UP();
-       act = *(bool *) wl_read_prof(wl, WL_PROF_ACT);
-       if (likely(act)) {
-               scbval.val = reason_code;
-               memcpy(&scbval.ea, &wl->bssid, ETH_ALEN);
-               scbval.val = cpu_to_le32(scbval.val);
-               err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval,
-                               sizeof(scb_val_t));
-               if (unlikely(err)) {
-                       WL_ERR("error (%d)\n", err);
-                       return err;
-               }
-       }
+
+       clear_bit(WL_STATUS_CONNECTED, &wl->status);
+
+       scbval.val = reason_code;
+       memcpy(&scbval.ea, wl_read_prof(wl, WL_PROF_BSSID), ETH_ALEN);
+       scbval.val = cpu_to_le32(scbval.val);
+       err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval,
+                       sizeof(scb_val_t));
+       if (unlikely(err))
+               WL_ERR("error (%d)\n", err);
+
+       wl->link_up = false;
 
        return err;
 }
@@ -1614,6 +1681,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        s32 val;
        s32 wsec;
        s32 err = 0;
+       u8 keybuf[8];
 
        WL_DBG("key index (%d)\n", key_idx);
        CHECK_SYS_UP();
@@ -1642,6 +1710,9 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                WL_DBG("WLAN_CIPHER_SUITE_WEP104\n");
                break;
        case WLAN_CIPHER_SUITE_TKIP:
+               memcpy(keybuf, &key.data[24], sizeof(keybuf));
+               memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
+               memcpy(&key.data[16], keybuf, sizeof(keybuf));
                key.algo = CRYPTO_ALGO_TKIP;
                WL_DBG("WLAN_CIPHER_SUITE_TKIP\n");
                break;
@@ -1963,32 +2034,91 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
 
 static s32 wl_cfg80211_resume(struct wiphy *wiphy)
 {
-       s32 err = 0;
+       struct wl_priv *wl = wiphy_to_wl(wiphy);
+       struct net_device *ndev = wl_to_ndev(wl);
 
-       CHECK_SYS_UP();
-       wl_invoke_iscan(wiphy_to_wl(wiphy));
+       /*
+        * Check for WL_STATUS_READY before any function call which
+        * could result is bus access. Don't block the resume for
+        * any driver error conditions
+        */
 
-       return err;
+#if defined(CONFIG_PM_SLEEP)
+       atomic_set(&dhd_mmc_suspend, false);
+#endif /*  defined(CONFIG_PM_SLEEP) */
+
+       if (test_bit(WL_STATUS_READY, &wl->status)) {
+               /* Turn on Watchdog timer */
+               wl_os_wd_timer(ndev, dhd_watchdog_ms);
+               wl_invoke_iscan(wiphy_to_wl(wiphy));
+       }
+
+       return 0;
 }
 
 static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
 {
        struct wl_priv *wl = wiphy_to_wl(wiphy);
        struct net_device *ndev = wl_to_ndev(wl);
-       s32 err = 0;
+
+
+       /*
+        * Check for WL_STATUS_READY before any function call which
+        * could result is bus access. Don't block the suspend for
+        * any driver error conditions
+        */
+
+       /*
+        * While going to suspend if associated with AP disassociate
+        * from AP to save power while system is in suspended state
+        */
+       if (test_bit(WL_STATUS_CONNECTED, &wl->status) &&
+               test_bit(WL_STATUS_READY, &wl->status)) {
+               WL_INFO("Disassociating from AP"
+                       " while entering suspend state\n");
+               wl_link_down(wl);
+
+               /*
+                * Make sure WPA_Supplicant receives all the event
+                * generated due to DISASSOC call to the fw to keep
+                * the state fw and WPA_Supplicant state consistent
+                */
+               rtnl_unlock();
+               wl_delay(500);
+               rtnl_lock();
+       }
 
        set_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
-       wl_term_iscan(wl);
+       if (test_bit(WL_STATUS_READY, &wl->status))
+               wl_term_iscan(wl);
+
        if (wl->scan_request) {
-               cfg80211_scan_done(wl->scan_request, true);     /* true means
-                                                                abort */
-               wl_set_mpc(ndev, 1);
+               /* Indidate scan abort to cfg80211 layer */
+               WL_INFO("Terminating scan in progress\n");
+               cfg80211_scan_done(wl->scan_request, true);
                wl->scan_request = NULL;
        }
        clear_bit(WL_STATUS_SCANNING, &wl->status);
        clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
+       clear_bit(WL_STATUS_CONNECTING, &wl->status);
+       clear_bit(WL_STATUS_CONNECTED, &wl->status);
 
-       return err;
+       /* Inform SDIO stack not to switch off power to the chip */
+       sdioh_sdio_set_host_pm_flags(MMC_PM_KEEP_POWER);
+
+       /* Turn off watchdog timer */
+       if (test_bit(WL_STATUS_READY, &wl->status)) {
+               WL_INFO("Terminate watchdog timer and enable MPC\n");
+               wl_set_mpc(ndev, 1);
+               wl_os_wd_timer(ndev, 0);
+       }
+
+#if defined(CONFIG_PM_SLEEP)
+       atomic_set(&dhd_mmc_suspend, true);
+#endif /*  defined(CONFIG_PM_SLEEP) */
+
+
+       return 0;
 }
 
 static __used s32
@@ -2245,89 +2375,133 @@ static s32 wl_inform_bss(struct wl_priv *wl)
        return err;
 }
 
+
 static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
 {
        struct wiphy *wiphy = wl_to_wiphy(wl);
-       struct ieee80211_mgmt *mgmt;
-       struct ieee80211_channel *channel;
+       struct ieee80211_channel *notify_channel;
+       struct cfg80211_bss *bss;
        struct ieee80211_supported_band *band;
-       struct wl_cfg80211_bss_info *notif_bss_info;
-       struct wl_scan_req *sr = wl_to_sr(wl);
-       struct beacon_proberesp *beacon_proberesp;
-       s32 mgmt_type;
-       u32 signal;
-       u32 freq;
        s32 err = 0;
+       u16 channel;
+       u32 freq;
+       u64 notify_timestamp;
+       u16 notify_capability;
+       u16 notify_interval;
+       u8 *notify_ie;
+       size_t notify_ielen;
+       s32 notify_signal;
 
        if (unlikely(le32_to_cpu(bi->length) > WL_BSS_INFO_MAX)) {
-               WL_DBG("Beacon is larger than buffer. Discarding\n");
-               return err;
-       }
-       notif_bss_info =
-           kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) +
-                   WL_BSS_INFO_MAX, GFP_KERNEL);
-       if (unlikely(!notif_bss_info)) {
-               WL_ERR("notif_bss_info alloc failed\n");
-               return -ENOMEM;
+               WL_ERR("Bss info is larger than buffer. Discarding\n");
+               return 0;
        }
-       mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
-       notif_bss_info->channel =
-               bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec);
 
-       if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
+       channel = bi->ctl_ch ? bi->ctl_ch :
+                               CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+
+       if (channel <= CH_MAX_2G_CHANNEL)
                band = wiphy->bands[IEEE80211_BAND_2GHZ];
        else
                band = wiphy->bands[IEEE80211_BAND_5GHZ];
-       notif_bss_info->rssi = bi->RSSI;
-       memcpy(mgmt->bssid, &bi->BSSID, ETH_ALEN);
-       mgmt_type = wl->active_scan ?
-               IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
-       if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
-               mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                                       mgmt_type);
-       }
-       beacon_proberesp = wl->active_scan ?
-               (struct beacon_proberesp *)&mgmt->u.probe_resp :
-               (struct beacon_proberesp *)&mgmt->u.beacon;
-       beacon_proberesp->timestamp = 0;
-       beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
-       beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
-       wl_rst_ie(wl);
-       /*
-       * wl_add_ie is not necessary because it can only add duplicated
-       * SSID, rate information to frame_buf
-       */
-       /*
-       * wl_add_ie(wl, WLAN_EID_SSID, bi->SSID_len, bi->SSID);
-       * wl_add_ie(wl, WLAN_EID_SUPP_RATES, bi->rateset.count,
-       * bi->rateset.rates);
-       */
-       wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
-       wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX -
-                offsetof(struct wl_cfg80211_bss_info, frame_buf));
-       notif_bss_info->frame_len =
-           offsetof(struct ieee80211_mgmt,
-                    u.beacon.variable) + wl_get_ielen(wl);
-       freq = ieee80211_channel_to_frequency(notif_bss_info->channel,
-                                             band->band);
-
-       channel = ieee80211_get_channel(wiphy, freq);
-
-       WL_DBG("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n",
-              bi->SSID,
-              notif_bss_info->rssi, notif_bss_info->channel,
-              mgmt->u.beacon.capab_info, &bi->BSSID);
-
-       signal = notif_bss_info->rssi * 100;
-       if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
-                                               le16_to_cpu
-                                               (notif_bss_info->frame_len),
-                                               signal, GFP_KERNEL))) {
+
+       freq = ieee80211_channel_to_frequency(channel, band->band);
+       notify_channel = ieee80211_get_channel(wiphy, freq);
+
+       notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
+       notify_capability = le16_to_cpu(bi->capability);
+       notify_interval = le16_to_cpu(bi->beacon_period);
+       notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
+       notify_ielen = le16_to_cpu(bi->ie_length);
+       notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
+
+       WL_DBG("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+                       bi->BSSID[0], bi->BSSID[1], bi->BSSID[2],
+                       bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]);
+       WL_DBG("Channel: %d(%d)\n", channel, freq);
+       WL_DBG("Capability: %X\n", notify_capability);
+       WL_DBG("Beacon interval: %d\n", notify_interval);
+       WL_DBG("Signal: %d\n", notify_signal);
+       WL_DBG("notify_timestamp: %#018llx\n", notify_timestamp);
+
+       bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
+               notify_timestamp, notify_capability, notify_interval, notify_ie,
+               notify_ielen, notify_signal, GFP_KERNEL);
+
+       if (unlikely(!bss)) {
                WL_ERR("cfg80211_inform_bss_frame error\n");
-               kfree(notif_bss_info);
                return -EINVAL;
        }
-       kfree(notif_bss_info);
+
+       return err;
+}
+
+static s32
+wl_inform_ibss(struct wl_priv *wl, struct net_device *dev, const u8 *bssid)
+{
+       struct wiphy *wiphy = wl_to_wiphy(wl);
+       struct ieee80211_channel *notify_channel;
+       struct wl_bss_info *bi = NULL;
+       struct ieee80211_supported_band *band;
+       u8 *buf = NULL;
+       s32 err = 0;
+       u16 channel;
+       u32 freq;
+       u64 notify_timestamp;
+       u16 notify_capability;
+       u16 notify_interval;
+       u8 *notify_ie;
+       size_t notify_ielen;
+       s32 notify_signal;
+
+       buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+       if (buf == NULL) {
+               WL_ERR("kzalloc() failed\n");
+               err = -ENOMEM;
+               goto CleanUp;
+       }
+
+       *(u32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
+
+       err = wl_dev_ioctl(dev, WLC_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
+       if (unlikely(err)) {
+               WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
+               goto CleanUp;
+       }
+
+       bi = (wl_bss_info_t *)(buf + 4);
+
+       channel = bi->ctl_ch ? bi->ctl_ch :
+                               CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+
+       if (channel <= CH_MAX_2G_CHANNEL)
+               band = wiphy->bands[IEEE80211_BAND_2GHZ];
+       else
+               band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+       freq = ieee80211_channel_to_frequency(channel, band->band);
+       notify_channel = ieee80211_get_channel(wiphy, freq);
+
+       notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
+       notify_capability = le16_to_cpu(bi->capability);
+       notify_interval = le16_to_cpu(bi->beacon_period);
+       notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
+       notify_ielen = le16_to_cpu(bi->ie_length);
+       notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
+
+       WL_DBG("channel: %d(%d)\n", channel, freq);
+       WL_DBG("capability: %X\n", notify_capability);
+       WL_DBG("beacon interval: %d\n", notify_interval);
+       WL_DBG("signal: %d\n", notify_signal);
+       WL_DBG("notify_timestamp: %#018llx\n", notify_timestamp);
+
+       cfg80211_inform_bss(wiphy, notify_channel, bssid,
+               notify_timestamp, notify_capability, notify_interval,
+               notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
+
+CleanUp:
+
+       kfree(buf);
 
        return err;
 }
@@ -2335,17 +2509,12 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
 static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e)
 {
        u32 event = be32_to_cpu(e->event_type);
-       u16 flags = be16_to_cpu(e->flags);
+       u32 status = be32_to_cpu(e->status);
 
-       if (event == WLC_E_LINK) {
-               if (flags & WLC_EVENT_MSG_LINK) {
-                       if (wl_is_ibssmode(wl)) {
-                               if (wl_is_ibssstarter(wl)) {
-                               }
-                       } else {
-                               return true;
-                       }
-               }
+       if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) {
+               WL_DBG("Processing set ssid\n");
+               wl->link_up = true;
+               return true;
        }
 
        return false;
@@ -2356,13 +2525,10 @@ static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e)
        u32 event = be32_to_cpu(e->event_type);
        u16 flags = be16_to_cpu(e->flags);
 
-       if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
+       if (event == WLC_E_LINK && (!(flags & WLC_EVENT_MSG_LINK))) {
+               WL_DBG("Processing link down\n");
                return true;
-       } else if (event == WLC_E_LINK) {
-               if (!(flags & WLC_EVENT_MSG_LINK))
-                       return true;
        }
-
        return false;
 }
 
@@ -2370,10 +2536,17 @@ static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e)
 {
        u32 event = be32_to_cpu(e->event_type);
        u32 status = be32_to_cpu(e->status);
+       u16 flags = be16_to_cpu(e->flags);
+
+       if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) {
+               WL_DBG("Processing Link %s & no network found\n",
+                               flags & WLC_EVENT_MSG_LINK ? "up" : "down");
+               return true;
+       }
 
-       if (event == WLC_E_SET_SSID || event == WLC_E_LINK) {
-               if (status == WLC_E_STATUS_NO_NETWORKS)
-                       return true;
+       if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) {
+               WL_DBG("Processing connecting & no network found\n");
+               return true;
        }
 
        return false;
@@ -2383,30 +2556,39 @@ static s32
 wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
                         const wl_event_msg_t *e, void *data)
 {
-       bool act;
        s32 err = 0;
 
        if (wl_is_linkup(wl, e)) {
-               wl_link_up(wl);
+               WL_DBG("Linkup\n");
                if (wl_is_ibssmode(wl)) {
-                       cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
-                                            GFP_KERNEL);
-                       WL_DBG("joined in IBSS network\n");
-               } else {
+                       wl_update_prof(wl, NULL, (void *)e->addr,
+                               WL_PROF_BSSID);
+                       wl_inform_ibss(wl, ndev, e->addr);
+                       cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
+                       clear_bit(WL_STATUS_CONNECTING, &wl->status);
+                       set_bit(WL_STATUS_CONNECTED, &wl->status);
+               } else
                        wl_bss_connect_done(wl, ndev, e, data, true);
-                       WL_DBG("joined in BSS network \"%s\"\n",
-                              ((struct wlc_ssid *)
-                               wl_read_prof(wl, WL_PROF_SSID))->SSID);
-               }
-               act = true;
-               wl_update_prof(wl, e, &act, WL_PROF_ACT);
        } else if (wl_is_linkdown(wl, e)) {
-               cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
-               clear_bit(WL_STATUS_CONNECTED, &wl->status);
-               wl_link_down(wl);
+               WL_DBG("Linkdown\n");
+               if (wl_is_ibssmode(wl)) {
+                       if (test_and_clear_bit(WL_STATUS_CONNECTED,
+                               &wl->status))
+                               wl_link_down(wl);
+               } else {
+                       if (test_and_clear_bit(WL_STATUS_CONNECTED,
+                               &wl->status)) {
+                               cfg80211_disconnected(ndev, 0, NULL, 0,
+                                       GFP_KERNEL);
+                               wl_link_down(wl);
+                       }
+               }
                wl_init_prof(wl->profile);
        } else if (wl_is_nonetwork(wl, e)) {
-               wl_bss_connect_done(wl, ndev, e, data, false);
+               if (wl_is_ibssmode(wl))
+                       clear_bit(WL_STATUS_CONNECTING, &wl->status);
+               else
+                       wl_bss_connect_done(wl, ndev, e, data, false);
        }
 
        return err;
@@ -2416,12 +2598,16 @@ static s32
 wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
                         const wl_event_msg_t *e, void *data)
 {
-       bool act;
        s32 err = 0;
+       u32 event = be32_to_cpu(e->event_type);
+       u32 status = be32_to_cpu(e->status);
 
-       wl_bss_roaming_done(wl, ndev, e, data);
-       act = true;
-       wl_update_prof(wl, e, &act, WL_PROF_ACT);
+       if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) {
+               if (test_bit(WL_STATUS_CONNECTED, &wl->status))
+                       wl_bss_roaming_done(wl, ndev, e, data);
+               else
+                       wl_bss_connect_done(wl, ndev, e, data, true);
+       }
 
        return err;
 }
@@ -2468,6 +2654,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl)
        u32 resp_len;
        s32 err = 0;
 
+       wl_clear_assoc_ies(wl);
+
        err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
                                WL_ASSOC_INFO_MAX);
        if (unlikely(err)) {
@@ -2511,6 +2699,19 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl)
        return err;
 }
 
+static void wl_clear_assoc_ies(struct wl_priv *wl)
+{
+       struct wl_connect_info *conn_info = wl_to_conn(wl);
+
+       kfree(conn_info->req_ie);
+       conn_info->req_ie = NULL;
+       conn_info->req_ie_len = 0;
+       kfree(conn_info->resp_ie);
+       conn_info->resp_ie = NULL;
+       conn_info->resp_ie_len = 0;
+}
+
+
 static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params,
        size_t *join_params_size)
 {
@@ -2520,7 +2721,7 @@ static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params,
                join_params->params.chanspec_num = 1;
                join_params->params.chanspec_list[0] = ch;
 
-               if (join_params->params.chanspec_list[0])
+               if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
                        chanspec |= WL_CHANSPEC_BAND_2G;
                else
                        chanspec |= WL_CHANSPEC_BAND_5G;
@@ -2546,7 +2747,6 @@ static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params,
 
 static s32 wl_update_bss_info(struct wl_priv *wl)
 {
-       struct cfg80211_bss *bss;
        struct wl_bss_info *bi;
        struct wlc_ssid *ssid;
        struct bcm_tlv *tim;
@@ -2560,63 +2760,46 @@ static s32 wl_update_bss_info(struct wl_priv *wl)
                return err;
 
        ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID);
-       bss =
-           cfg80211_get_bss(wl_to_wiphy(wl), NULL, (s8 *)&wl->bssid,
-                            ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
-                            WLAN_CAPABILITY_ESS);
-
-       rtnl_lock();
-       if (unlikely(!bss)) {
-               WL_DBG("Could not find the AP\n");
-               *(u32 *) wl->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
-               err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_BSS_INFO,
-                               wl->extra_buf, WL_EXTRA_BUF_MAX);
-               if (unlikely(err)) {
-                       WL_ERR("Could not get bss info %d\n", err);
-                       goto update_bss_info_out;
-               }
-               bi = (struct wl_bss_info *)(wl->extra_buf + 4);
-               if (unlikely(memcmp(&bi->BSSID, &wl->bssid, ETH_ALEN))) {
-                       err = -EIO;
-                       goto update_bss_info_out;
-               }
-               err = wl_inform_single_bss(wl, bi);
-               if (unlikely(err))
-                       goto update_bss_info_out;
 
-               ie = ((u8 *)bi) + bi->ie_offset;
-               ie_len = bi->ie_length;
-               beacon_interval = cpu_to_le16(bi->beacon_period);
-       } else {
-               WL_DBG("Found the AP in the list - BSSID %pM\n", bss->bssid);
-               ie = bss->information_elements;
-               ie_len = bss->len_information_elements;
-               beacon_interval = bss->beacon_interval;
-               cfg80211_put_bss(bss);
+       *(u32 *)wl->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
+       err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_BSS_INFO,
+                       wl->extra_buf, WL_EXTRA_BUF_MAX);
+       if (unlikely(err)) {
+               WL_ERR("Could not get bss info %d\n", err);
+               goto update_bss_info_out;
        }
 
+       bi = (struct wl_bss_info *)(wl->extra_buf + 4);
+       err = wl_inform_single_bss(wl, bi);
+       if (unlikely(err))
+               goto update_bss_info_out;
+
+       ie = ((u8 *)bi) + bi->ie_offset;
+       ie_len = bi->ie_length;
+       beacon_interval = cpu_to_le16(bi->beacon_period);
+
        tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
-       if (tim) {
+       if (tim)
                dtim_period = tim->data[1];
-       else {
+       else {
                /*
                * active scan was done so we could not get dtim
                * information out of probe response.
                * so we speficially query dtim information to dongle.
                */
-               err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_DTIMPRD,
-                       &dtim_period, sizeof(dtim_period));
+               u32 var;
+               err = wl_dev_intvar_get(wl_to_ndev(wl), "dtim_assoc", &var);
                if (unlikely(err)) {
-                       WL_ERR("WLC_GET_DTIMPRD error (%d)\n", err);
+                       WL_ERR("wl dtim_assoc failed (%d)\n", err);
                        goto update_bss_info_out;
                }
+               dtim_period = (u8)var;
        }
 
        wl_update_prof(wl, NULL, &beacon_interval, WL_PROF_BEACONINT);
        wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
 
 update_bss_info_out:
-       rtnl_unlock();
        return err;
 }
 
@@ -2628,10 +2811,11 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
        s32 err = 0;
 
        wl_get_assoc_ies(wl);
-       memcpy(&wl->bssid, &e->addr, ETH_ALEN);
+       wl_update_prof(wl, NULL, &e->addr, WL_PROF_BSSID);
        wl_update_bss_info(wl);
+
        cfg80211_roamed(ndev,
-                       (u8 *)&wl->bssid,
+                       (u8 *)wl_read_prof(wl, WL_PROF_BSSID),
                        conn_info->req_ie, conn_info->req_ie_len,
                        conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
        WL_DBG("Report roaming result\n");
@@ -2648,30 +2832,26 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
        struct wl_connect_info *conn_info = wl_to_conn(wl);
        s32 err = 0;
 
-       wl_get_assoc_ies(wl);
-       memcpy(&wl->bssid, &e->addr, ETH_ALEN);
-       wl_update_bss_info(wl);
+
        if (test_and_clear_bit(WL_STATUS_CONNECTING, &wl->status)) {
+               if (completed) {
+                       wl_get_assoc_ies(wl);
+                       wl_update_prof(wl, NULL, &e->addr, WL_PROF_BSSID);
+                       wl_update_bss_info(wl);
+               }
                cfg80211_connect_result(ndev,
-                                       (u8 *)&wl->bssid,
+                                       (u8 *)wl_read_prof(wl, WL_PROF_BSSID),
                                        conn_info->req_ie,
                                        conn_info->req_ie_len,
                                        conn_info->resp_ie,
                                        conn_info->resp_ie_len,
                                        completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT,
                                        GFP_KERNEL);
+               if (completed)
+                       set_bit(WL_STATUS_CONNECTED, &wl->status);
                WL_DBG("Report connect result - connection %s\n",
-                      completed ? "succeeded" : "failed");
-       } else {
-               cfg80211_roamed(ndev,
-                               (u8 *)&wl->bssid,
-                               conn_info->req_ie, conn_info->req_ie_len,
-                               conn_info->resp_ie, conn_info->resp_ie_len,
-                               GFP_KERNEL);
-               WL_DBG("Report roaming result\n");
+                               completed ? "succeeded" : "failed");
        }
-       set_bit(WL_STATUS_CONNECTED, &wl->status);
-
        return err;
 }
 
@@ -2773,12 +2953,7 @@ static void wl_init_eloop_handler(struct wl_event_loop *el)
 {
        memset(el, 0, sizeof(*el));
        el->handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
-       el->handler[WLC_E_JOIN] = wl_notify_connect_status;
        el->handler[WLC_E_LINK] = wl_notify_connect_status;
-       el->handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
-       el->handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
-       el->handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
-       el->handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
        el->handler[WLC_E_ROAM] = wl_notify_roaming_status;
        el->handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
        el->handler[WLC_E_SET_SSID] = wl_notify_connect_status;
@@ -3370,7 +3545,6 @@ struct sdio_func *wl_cfg80211_get_sdio_func(void)
 static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype)
 {
        s32 infra = 0;
-       s32 ap = 0;
        s32 err = 0;
 
        switch (iftype) {
@@ -3381,6 +3555,7 @@ static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype)
                err = -EINVAL;
                return err;
        case NL80211_IFTYPE_ADHOC:
+               infra = 0;
                break;
        case NL80211_IFTYPE_STATION:
                infra = 1;
@@ -3391,20 +3566,13 @@ static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype)
                return err;
        }
        infra = cpu_to_le32(infra);
-       ap = cpu_to_le32(ap);
-       WL_DBG("%s ap (%d), infra (%d)\n", ndev->name, ap, infra);
        err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
        if (unlikely(err)) {
                WL_ERR("WLC_SET_INFRA error (%d)\n", err);
                return err;
        }
-       err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap));
-       if (unlikely(err)) {
-               WL_ERR("WLC_SET_AP error (%d)\n", err);
-               return err;
-       }
 
-       return -EINPROGRESS;
+       return 0;
 }
 
 #ifndef EMBEDDED_PLATFORM
@@ -3464,116 +3632,6 @@ dongle_glom_out:
        return err;
 }
 
-static s32
-wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
-{
-       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];   /*  Room for "event_msgs" +
-                                                '\0' + bitvec  */
-       s32 err = 0;
-
-       /* Setup timeout if Beacons are lost and roam is
-                off to report link down */
-       if (roamvar) {
-               bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
-                           sizeof(iovbuf));
-               err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-               if (unlikely(err)) {
-                       WL_ERR("bcn_timeout error (%d)\n", err);
-                       goto dongle_rom_out;
-               }
-       }
-       /* Enable/Disable built-in roaming to allow supplicant
-                to take care of roaming */
-       bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
-       err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-       if (unlikely(err)) {
-               WL_ERR("roam_off error (%d)\n", err);
-               goto dongle_rom_out;
-       }
-dongle_rom_out:
-       return err;
-}
-
-static s32 wl_dongle_eventmsg(struct net_device *ndev)
-{
-
-       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];   /*  Room for "event_msgs" +
-                                                '\0' + bitvec  */
-       s8 eventmask[WL_EVENTING_MASK_LEN];
-       s32 err = 0;
-
-       /* Setup event_msgs */
-       bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
-                   sizeof(iovbuf));
-       err = wl_dev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
-       if (unlikely(err)) {
-               WL_ERR("Get event_msgs error (%d)\n", err);
-               goto dongle_eventmsg_out;
-       }
-       memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
-
-       setbit(eventmask, WLC_E_SET_SSID);
-       setbit(eventmask, WLC_E_PRUNE);
-       setbit(eventmask, WLC_E_AUTH);
-       setbit(eventmask, WLC_E_REASSOC);
-       setbit(eventmask, WLC_E_REASSOC_IND);
-       setbit(eventmask, WLC_E_DEAUTH_IND);
-       setbit(eventmask, WLC_E_DISASSOC_IND);
-       setbit(eventmask, WLC_E_DISASSOC);
-       setbit(eventmask, WLC_E_JOIN);
-       setbit(eventmask, WLC_E_ASSOC_IND);
-       setbit(eventmask, WLC_E_PSK_SUP);
-       setbit(eventmask, WLC_E_LINK);
-       setbit(eventmask, WLC_E_NDIS_LINK);
-       setbit(eventmask, WLC_E_MIC_ERROR);
-       setbit(eventmask, WLC_E_PMKID_CACHE);
-       setbit(eventmask, WLC_E_TXFAIL);
-       setbit(eventmask, WLC_E_JOIN_START);
-       setbit(eventmask, WLC_E_SCAN_COMPLETE);
-
-       bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
-                   sizeof(iovbuf));
-       err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-       if (unlikely(err)) {
-               WL_ERR("Set event_msgs error (%d)\n", err);
-               goto dongle_eventmsg_out;
-       }
-
-dongle_eventmsg_out:
-       return err;
-}
-
-static s32
-wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
-                  s32 scan_unassoc_time)
-{
-       s32 err = 0;
-
-       err = wl_dev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
-                       sizeof(scan_assoc_time));
-       if (err) {
-               if (err == -EOPNOTSUPP) {
-                       WL_INFO("Scan assoc time is not supported\n");
-               } else {
-                       WL_ERR("Scan assoc time error (%d)\n", err);
-               }
-               goto dongle_scantime_out;
-       }
-       err = wl_dev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
-                       sizeof(scan_unassoc_time));
-       if (err) {
-               if (err == -EOPNOTSUPP) {
-                       WL_INFO("Scan unassoc time is not supported\n");
-               } else {
-                       WL_ERR("Scan unassoc time error (%d)\n", err);
-               }
-               goto dongle_scantime_out;
-       }
-
-dongle_scantime_out:
-       return err;
-}
-
 static s32
 wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
 {
@@ -3722,6 +3780,151 @@ dongle_filter_out:
 }
 #endif                         /* !EMBEDDED_PLATFORM */
 
+static s32 wl_dongle_eventmsg(struct net_device *ndev)
+{
+       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];   /*  Room for "event_msgs" +
+                                                '\0' + bitvec  */
+       s8 eventmask[WL_EVENTING_MASK_LEN];
+       s32 err = 0;
+
+       /* Setup event_msgs */
+       bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+                   sizeof(iovbuf));
+       err = wl_dev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
+       if (unlikely(err)) {
+               WL_ERR("Get event_msgs error (%d)\n", err);
+               goto dongle_eventmsg_out;
+       }
+       memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
+
+       setbit(eventmask, WLC_E_SET_SSID);
+       setbit(eventmask, WLC_E_ROAM);
+       setbit(eventmask, WLC_E_PRUNE);
+       setbit(eventmask, WLC_E_AUTH);
+       setbit(eventmask, WLC_E_REASSOC);
+       setbit(eventmask, WLC_E_REASSOC_IND);
+       setbit(eventmask, WLC_E_DEAUTH_IND);
+       setbit(eventmask, WLC_E_DISASSOC_IND);
+       setbit(eventmask, WLC_E_DISASSOC);
+       setbit(eventmask, WLC_E_JOIN);
+       setbit(eventmask, WLC_E_ASSOC_IND);
+       setbit(eventmask, WLC_E_PSK_SUP);
+       setbit(eventmask, WLC_E_LINK);
+       setbit(eventmask, WLC_E_NDIS_LINK);
+       setbit(eventmask, WLC_E_MIC_ERROR);
+       setbit(eventmask, WLC_E_PMKID_CACHE);
+       setbit(eventmask, WLC_E_TXFAIL);
+       setbit(eventmask, WLC_E_JOIN_START);
+       setbit(eventmask, WLC_E_SCAN_COMPLETE);
+
+       bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+                   sizeof(iovbuf));
+       err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+       if (unlikely(err)) {
+               WL_ERR("Set event_msgs error (%d)\n", err);
+               goto dongle_eventmsg_out;
+       }
+
+dongle_eventmsg_out:
+       return err;
+}
+
+static s32
+wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
+{
+       s8 iovbuf[32];
+       s32 roamtrigger[2];
+       s32 roam_delta[2];
+       s32 err = 0;
+
+       /*
+        * Setup timeout if Beacons are lost and roam is
+        * off to report link down
+        */
+       if (roamvar) {
+               bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout,
+                       sizeof(bcn_timeout), iovbuf, sizeof(iovbuf));
+               err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+               if (unlikely(err)) {
+                       WL_ERR("bcn_timeout error (%d)\n", err);
+                       goto dongle_rom_out;
+               }
+       }
+
+       /*
+        * Enable/Disable built-in roaming to allow supplicant
+        * to take care of roaming
+        */
+       WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
+       bcm_mkiovar("roam_off", (char *)&roamvar,
+                               sizeof(roamvar), iovbuf, sizeof(iovbuf));
+       err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+       if (unlikely(err)) {
+               WL_ERR("roam_off error (%d)\n", err);
+               goto dongle_rom_out;
+       }
+
+       roamtrigger[0] = WL_ROAM_TRIGGER_LEVEL;
+       roamtrigger[1] = WLC_BAND_ALL;
+       err = wl_dev_ioctl(ndev, WLC_SET_ROAM_TRIGGER,
+                       (void *)roamtrigger, sizeof(roamtrigger));
+       if (unlikely(err)) {
+               WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
+               goto dongle_rom_out;
+       }
+
+       roam_delta[0] = WL_ROAM_DELTA;
+       roam_delta[1] = WLC_BAND_ALL;
+       err = wl_dev_ioctl(ndev, WLC_SET_ROAM_DELTA,
+                               (void *)roam_delta, sizeof(roam_delta));
+       if (unlikely(err)) {
+               WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
+               goto dongle_rom_out;
+       }
+
+dongle_rom_out:
+       return err;
+}
+
+static s32
+wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
+               s32 scan_unassoc_time, s32 scan_passive_time)
+{
+       s32 err = 0;
+
+       err = wl_dev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
+                       sizeof(scan_assoc_time));
+       if (err) {
+               if (err == -EOPNOTSUPP)
+                       WL_INFO("Scan assoc time is not supported\n");
+               else
+                       WL_ERR("Scan assoc time error (%d)\n", err);
+               goto dongle_scantime_out;
+       }
+       err = wl_dev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
+                       sizeof(scan_unassoc_time));
+       if (err) {
+               if (err == -EOPNOTSUPP)
+                       WL_INFO("Scan unassoc time is not supported\n");
+               else
+                       WL_ERR("Scan unassoc time error (%d)\n", err);
+               goto dongle_scantime_out;
+       }
+
+       err = wl_dev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME, &scan_passive_time,
+                       sizeof(scan_passive_time));
+       if (err) {
+               if (err == -EOPNOTSUPP)
+                       WL_INFO("Scan passive time is not supported\n");
+               else
+                       WL_ERR("Scan passive time error (%d)\n", err);
+               goto dongle_scantime_out;
+       }
+
+dongle_scantime_out:
+       return err;
+}
+
 s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
 {
 #ifndef DHD_SDALIGN
@@ -3750,20 +3953,22 @@ s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
        if (unlikely(err))
                goto default_conf_out;
        err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
-       if (unlikely(err))
-               goto default_conf_out;
-       err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3);
-       if (unlikely(err))
-               goto default_conf_out;
-       err = wl_dongle_eventmsg(ndev);
        if (unlikely(err))
                goto default_conf_out;
 
-       wl_dongle_scantime(ndev, 40, 80);
        wl_dongle_offload(ndev, 1, 0xf);
        wl_dongle_filter(ndev, 1);
-#endif                         /* !EMBEDDED_PLATFORM */
+#endif /* !EMBEDDED_PLATFORM */
+
+       wl_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
+                       WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
 
+       err = wl_dongle_eventmsg(ndev);
+       if (unlikely(err))
+               goto default_conf_out;
+       err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
+       if (unlikely(err))
+               goto default_conf_out;
        err = wl_dongle_mode(ndev, wdev->iftype);
        if (unlikely(err && err != -EINPROGRESS))
                goto default_conf_out;
@@ -3966,18 +4171,6 @@ static bool wl_is_ibssmode(struct wl_priv *wl)
        return wl->conf->mode == WL_MODE_IBSS;
 }
 
-static bool wl_is_ibssstarter(struct wl_priv *wl)
-{
-       return wl->ibss_starter;
-}
-
-static void wl_rst_ie(struct wl_priv *wl)
-{
-       struct wl_ie *ie = wl_to_ie(wl);
-
-       ie->offset = 0;
-}
-
 static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v)
 {
        struct wl_ie *ie = wl_to_ie(wl);
@@ -3995,58 +4188,22 @@ static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v)
        return err;
 }
 
-static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size)
-{
-       struct wl_ie *ie = wl_to_ie(wl);
-       s32 err = 0;
 
-       if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
-               WL_ERR("ei_stream crosses buffer boundary\n");
-               return -ENOSPC;
-       }
-       memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
-       ie->offset += ie_size;
-
-       return err;
-}
-
-static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size)
+static void wl_link_down(struct wl_priv *wl)
 {
-       struct wl_ie *ie = wl_to_ie(wl);
+       struct net_device *dev = NULL;
        s32 err = 0;
 
-       if (unlikely(ie->offset > dst_size)) {
-               WL_ERR("dst_size is not enough\n");
-               return -ENOSPC;
-       }
-       memcpy(dst, &ie->buf[0], ie->offset);
-
-       return err;
-}
-
-static u32 wl_get_ielen(struct wl_priv *wl)
-{
-       struct wl_ie *ie = wl_to_ie(wl);
-
-       return ie->offset;
-}
-
-static void wl_link_up(struct wl_priv *wl)
-{
-       wl->link_up = true;
-}
-
-static void wl_link_down(struct wl_priv *wl)
-{
-       struct wl_connect_info *conn_info = wl_to_conn(wl);
+       clear_bit(WL_STATUS_CONNECTED, &wl->status);
 
-       wl->link_up = false;
-       kfree(conn_info->req_ie);
-       conn_info->req_ie = NULL;
-       conn_info->req_ie_len = 0;
-       kfree(conn_info->resp_ie);
-       conn_info->resp_ie = NULL;
-       conn_info->resp_ie_len = 0;
+       if (wl->link_up) {
+               dev = wl_to_ndev(wl);
+               WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
+               err = wl_dev_ioctl(dev, WLC_DISASSOC, NULL, 0);
+               if (unlikely(err))
+                       WL_ERR("WLC_DISASSOC failed (%d)\n", err);
+               wl->link_up = false;
+       }
 }
 
 static void wl_lock_eq(struct wl_priv *wl)