wifi: update bcmdhd.1.579.77.41.1.cn from ampak[3/3]
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.1.579.77.41.1.cn / wl_android_ext.c
index 2d9e1997fa6ac9a77e219bbe778b7354cb0d5b06..bf901eab419dabd409e195833bc0d0eb34915a20 100644 (file)
@@ -1,5 +1,4 @@
 
-
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <net/netlink.h>
@@ -15,7 +14,9 @@
 #include <linux/if_arp.h>
 #include <asm/uaccess.h>
 #include <linux/wireless.h>
+#if defined(WL_WIRELESS_EXT)
 #include <wl_iw.h>
+#endif
 #include <wldev_common.h>
 #include <wlioctl.h>
 #include <bcmutils.h>
@@ -27,6 +28,9 @@
 #ifdef WL_CFG80211
 #include <wl_cfg80211.h>
 #endif
+#ifdef WL_ESCAN
+#include <wl_escan.h>
+#endif
 
 #ifndef WL_CFG80211
 #define htod32(i) i
@@ -56,6 +60,7 @@
 #define CMD_SET_SUSPEND_BCN_LI_DTIM            "SET_SUSPEND_BCN_LI_DTIM"
 
 #ifdef WL_EXT_IAPSTA
+#include <net/rtnetlink.h>
 #define CMD_IAPSTA_INIT                        "IAPSTA_INIT"
 #define CMD_IAPSTA_CONFIG              "IAPSTA_CONFIG"
 #define CMD_IAPSTA_ENABLE              "IAPSTA_ENABLE"
@@ -64,6 +69,7 @@
 #define CMD_ISAM_CONFIG                        "ISAM_CONFIG"
 #define CMD_ISAM_ENABLE                        "ISAM_ENABLE"
 #define CMD_ISAM_DISABLE               "ISAM_DISABLE"
+#define CMD_ISAM_STATUS                        "ISAM_STATUS"
 #ifdef PROP_TXSTATUS
 #ifdef PROP_TXSTATUS_VSDB
 #include <dhd_wlfc.h>
@@ -75,6 +81,7 @@ extern int disable_proptx;
 #define CMD_DHCPC_ENABLE       "DHCPC_ENABLE"
 #define CMD_DHCPC_DUMP         "DHCPC_DUMP"
 #endif
+#define CMD_AUTOCHANNEL                "AUTOCHANNEL"
 #define CMD_WL         "WL"
 
 int wl_ext_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
@@ -134,9 +141,109 @@ int wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name,
 }
 
 #ifdef WL_EXT_IAPSTA
-static int wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len);
+typedef enum IF_STATE {
+       IF_STATE_INIT = 1,
+       IF_STATE_DISALBE,
+       IF_STATE_ENABLE
+} if_state_t;
+
+typedef enum APSTAMODE {
+       ISTAONLY_MODE = 1,
+       IAPONLY_MODE,
+       IAPSTA_MODE,
+       IDUALAP_MODE,
+       ISTAAPAP_MODE,
+       IMESHONLY_MODE,
+       IMESHSTA_MODE,
+       IMESHAP_MODE,
+       IMESHAPSTA_MODE,
+       IMESHAPAP_MODE,
+       IGOSTA_MODE
+} apstamode_t;
+
+typedef enum IFMODE {
+       ISTA_MODE = 1,
+       IAP_MODE,
+       IMESH_MODE
+} ifmode_t;
+
+typedef enum BGNMODE {
+       IEEE80211B = 1,
+       IEEE80211G,
+       IEEE80211BG,
+       IEEE80211BGN,
+       IEEE80211BGNAC
+} bgnmode_t;
+
+typedef enum AUTHMODE {
+       AUTH_OPEN,
+       AUTH_SHARED,
+       AUTH_WPAPSK,
+       AUTH_WPA2PSK,
+       AUTH_WPAWPA2PSK,
+       AUTH_SAE
+} authmode_t;
+
+typedef enum ENCMODE {
+       ENC_NONE,
+       ENC_WEP,
+       ENC_TKIP,
+       ENC_AES,
+       ENC_TKIPAES
+} encmode_t;
+
+enum wl_if_list {
+       IF_PIF,
+       IF_VIF,
+       IF_VIF2,
+       MAX_IF_NUM
+};
+
+typedef enum WL_PRIO {
+       PRIO_AP,
+       PRIO_MESH,
+       PRIO_STA
+}wl_prio_t;
+
+typedef struct wl_if_info {
+       struct net_device *dev;
+       if_state_t ifstate;
+       ifmode_t ifmode;
+       char prefix;
+       wl_prio_t prio;
+       int ifidx;
+       uint8 bssidx;
+       char ifname[IFNAMSIZ+1];
+       char ssid[DOT11_MAX_SSID_LEN];
+       struct ether_addr bssid;
+       bgnmode_t bgnmode;
+       int hidden;
+       int maxassoc;
+       uint16 channel;
+       authmode_t amode;
+       encmode_t emode;
+       char key[100];
+} wl_if_info_t;
+
+#define CSA_FW_BIT             (1<<0)
+#define CSA_DRV_BIT            (1<<1)
+
+typedef struct wl_apsta_params {
+       struct wl_if_info if_info[MAX_IF_NUM];
+       int ioctl_ver;
+       bool init;
+       bool rsdb;
+       bool vsdb;
+       uint csa;
+       apstamode_t apstamode;
+       bool netif_change;
+       wait_queue_head_t netif_change_event;
+} wl_apsta_params_t;
+
+static int wl_ext_enable_iface(struct net_device *dev, char *ifname);
 int wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name,
-       void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
+       void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx,
+       struct mutex* buf_sync)
 {
        int ret;
 
@@ -147,19 +254,6 @@ int wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name,
 
        return ret;
 }
-
-int wl_ext_iovar_getbuf_bsscfg(struct net_device *dev, s8 *iovar_name,
-       void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
-{
-       int ret;
-
-       ret = wldev_iovar_getbuf_bsscfg(dev, iovar_name, param, paramlen,
-               buf, buflen, bsscfg_idx, buf_sync);
-       if (ret < 0)
-               ANDROID_ERROR(("%s: iovar_name=%s ret=%d\n", __FUNCTION__, iovar_name, ret));
-
-       return ret;
-}
 #endif
 
 /* Return a legacy chanspec given a new chanspec
@@ -228,6 +322,55 @@ wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec)
        return chanspec;
 }
 
+#if defined(WL_EXT_IAPSTA) || defined(WL_CFG80211) || defined(WL_ESCAN)
+static chanspec_t
+wl_ext_chspec_from_legacy(chanspec_t legacy_chspec)
+{
+       chanspec_t chspec;
+
+       /* get the channel number */
+       chspec = LCHSPEC_CHANNEL(legacy_chspec);
+
+       /* convert the band */
+       if (LCHSPEC_IS2G(legacy_chspec)) {
+               chspec |= WL_CHANSPEC_BAND_2G;
+       } else {
+               chspec |= WL_CHANSPEC_BAND_5G;
+       }
+
+       /* convert the bw and sideband */
+       if (LCHSPEC_IS20(legacy_chspec)) {
+               chspec |= WL_CHANSPEC_BW_20;
+       } else {
+               chspec |= WL_CHANSPEC_BW_40;
+               if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
+                       chspec |= WL_CHANSPEC_CTL_SB_L;
+               } else {
+                       chspec |= WL_CHANSPEC_CTL_SB_U;
+               }
+       }
+
+       if (wf_chspec_malformed(chspec)) {
+               ANDROID_ERROR(("wl_ext_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
+                       chspec));
+               return INVCHANSPEC;
+       }
+
+       return chspec;
+}
+
+static chanspec_t
+wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec)
+{
+       chanspec = dtohchanspec(chanspec);
+       if (ioctl_ver == 1) {
+               chanspec = wl_ext_chspec_from_legacy(chanspec);
+       }
+
+       return chanspec;
+}
+#endif
+
 static int
 wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver)
 {
@@ -252,7 +395,8 @@ wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver)
 }
 
 static int
-wl_ext_set_chanspec(struct net_device *dev, uint16 channel, chanspec_t *ret_chspec)
+wl_ext_set_chanspec(struct net_device *dev, int ioctl_ver,
+       uint16 channel, chanspec_t *ret_chspec)
 {
        s32 _chan = channel;
        chanspec_t chspec = 0;
@@ -266,13 +410,11 @@ wl_ext_set_chanspec(struct net_device *dev, uint16 channel, chanspec_t *ret_chsp
                u32 bw_cap;
        } param = {0, 0};
        uint band;
-       int ioctl_ver = 0;
 
        if (_chan <= CH_MAX_2G_CHANNEL)
                band = IEEE80211_BAND_2GHZ;
        else
                band = IEEE80211_BAND_5GHZ;
-       wl_ext_get_ioctl_ver(dev, &ioctl_ver);
 
        if (band == IEEE80211_BAND_5GHZ) {
                param.band = WLC_BAND_5G;
@@ -314,11 +456,14 @@ set_channel:
                                wl_ext_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), 1);
                                printf("%s: channel %d\n", __FUNCTION__, _chan);
                        } else if (err) {
-                               ANDROID_ERROR(("%s: failed to set chanspec error %d\n", __FUNCTION__, err));
+                               ANDROID_ERROR(("%s: failed to set chanspec error %d\n",
+                                       __FUNCTION__, err));
                        } else
-                               printf("%s: channel %d, 0x%x\n", __FUNCTION__, channel, chspec);
+                               printf("%s: %s channel %d, 0x%x\n", __FUNCTION__,
+                                       dev->name, channel, chspec);
                } else {
-                       ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n", __FUNCTION__));
+                       ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n",
+                               __FUNCTION__));
                        err = BCME_ERROR;
                }
        } else {
@@ -347,19 +492,23 @@ wl_ext_channel(struct net_device *dev, char* command, int total_len)
        channel_info_t ci;
        int bytes_written = 0;
        chanspec_t fw_chspec;
+       int ioctl_ver = 0;
 
        ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
 
        sscanf(command, "%*s %d", &channel);
 
        if (channel > 0) {
-               ret = wl_ext_set_chanspec(dev, channel, &fw_chspec);
+               wl_ext_get_ioctl_ver(dev, &ioctl_ver);
+               ret = wl_ext_set_chanspec(dev, ioctl_ver, channel, &fw_chspec);
        } else {
-               if (!(ret = wldev_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t), FALSE))) {
+               if (!(ret = wldev_ioctl(dev, WLC_GET_CHANNEL, &ci,
+                               sizeof(channel_info_t), FALSE))) {
                        ANDROID_TRACE(("hw_channel %d\n", ci.hw_channel));
                        ANDROID_TRACE(("target_channel %d\n", ci.target_channel));
                        ANDROID_TRACE(("scan_channel %d\n", ci.scan_channel));
-                       bytes_written = snprintf(command, sizeof(channel_info_t)+2, "channel %d", ci.hw_channel);
+                       bytes_written = snprintf(command, sizeof(channel_info_t)+2,
+                               "channel %d", ci.hw_channel);
                        ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
                        ret = bytes_written;
                }
@@ -381,13 +530,15 @@ wl_ext_channels(struct net_device *dev, char* command, int total_len)
        memset(valid_chan_list, 0, sizeof(valid_chan_list));
        list = (wl_uint32_list_t *)(void *) valid_chan_list;
        list->count = htod32(WL_NUMCHANNELS);
-       ret = wldev_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list, sizeof(valid_chan_list), 0);
+       ret = wldev_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list,
+               sizeof(valid_chan_list), 0);
        if (ret<0) {
                ANDROID_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, ret));
        } else {
                bytes_written = snprintf(command, total_len, "channels");
                for (i = 0; i < dtoh32(list->count); i++) {
-                       bytes_written += snprintf(command+bytes_written, total_len, " %d", dtoh32(list->element[i]));
+                       bytes_written += snprintf(command+bytes_written, total_len, " %d",
+                               dtoh32(list->element[i]));
                        printf("%d ", dtoh32(list->element[i]));
                }
                printf("\n");
@@ -409,23 +560,29 @@ wl_ext_roam_trigger(struct net_device *dev, char* command, int total_len)
 
        if (roam_trigger[0]) {
                roam_trigger[1] = WLC_BAND_ALL;
-               ret = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 1);
+               ret = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
+                       sizeof(roam_trigger), 1);
                if (ret)
-                       ANDROID_ERROR(("WLC_SET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
+                       ANDROID_ERROR(("WLC_SET_ROAM_TRIGGER ERROR %d ret=%d\n",
+                               roam_trigger[0], ret));
        } else {
                roam_trigger[1] = WLC_BAND_2G;
-               ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0);
+               ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
+                       sizeof(roam_trigger), 0);
                if (!ret)
                        trigger[0] = roam_trigger[0];
                else
-                       ANDROID_ERROR(("2G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
+                       ANDROID_ERROR(("2G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n",
+                               roam_trigger[0], ret));
 
                roam_trigger[1] = WLC_BAND_5G;
-               ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0);
+               ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
+                       sizeof(roam_trigger), 0);
                if (!ret)
                        trigger[1] = roam_trigger[0];
                else
-                       ANDROID_ERROR(("5G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
+                       ANDROID_ERROR(("5G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n",
+                               roam_trigger[0], ret));
 
                ANDROID_TRACE(("roam_trigger %d %d\n", trigger[0], trigger[1]));
                bytes_written = snprintf(command, total_len, "%d %d", trigger[0], trigger[1]);
@@ -491,7 +648,8 @@ wl_ext_keep_alive(struct net_device *dev, char *command, int total_len)
        } else {
                if (id < 0)
                        id = 0;
-               ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf, sizeof(buf), NULL);
+               ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf,
+                       sizeof(buf), NULL);
                if (ret) {
                        goto exit;
                } else {
@@ -508,10 +666,12 @@ wl_ext_keep_alive(struct net_device *dev, char *command, int total_len)
                        }
                        printf("\n");
                }
-               bytes_written = snprintf(command, total_len, "mkeep_alive_period_msec %d ", dtoh32(mkeep_alive_pktp->period_msec));
+               bytes_written = snprintf(command, total_len, "mkeep_alive_period_msec %d ",
+                       dtoh32(mkeep_alive_pktp->period_msec));
                bytes_written += snprintf(command+bytes_written, total_len, "0x");
                for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
-                       bytes_written += snprintf(command+bytes_written, total_len, "%x", mkeep_alive_pktp->data[i]);
+                       bytes_written += snprintf(command+bytes_written, total_len, "%x",
+                               mkeep_alive_pktp->data[i]);
                }
                ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
                ret = bytes_written;
@@ -695,33 +855,98 @@ wl_ext_set_bgnmode(struct wl_if_info *cur_if)
        return 0;
 }
 
+static void
+wl_ext_get_amode(struct wl_if_info *cur_if, char *amode)
+{
+       struct net_device *dev = cur_if->dev;
+       int auth=-1, wpa_auth=-1;
+
+       wl_ext_iovar_getint(dev, "auth", &auth);
+       wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
+
+       if (cur_if->ifmode == IMESH_MODE) {
+               if (auth == 0 && wpa_auth == 0) {
+                       strcpy(amode, "open");
+               } else if (auth == 0 && wpa_auth == 128) {
+                       strcpy(amode, "sae");
+               }
+       } else if (auth == 0 && wpa_auth == 0) {
+               strcpy(amode, "open");
+       } else if (auth == 1 && wpa_auth == 0) {
+               strcpy(amode, "shared");
+       } else if (auth == 0 && wpa_auth == 4) {
+               strcpy(amode, "wpapsk");
+       } else if (auth == 0 && wpa_auth == 128) {
+               strcpy(amode, "wpa2psk");
+       } else if (auth == 0 && wpa_auth == 132) {
+               strcpy(amode, "wpawpa2psk");
+       }
+}
+
+static void
+wl_ext_get_emode(struct wl_if_info *cur_if, char *emode)
+{
+       struct net_device *dev = cur_if->dev;
+       int wsec=0;
+
+       wl_ext_iovar_getint(dev, "wsec", &wsec);
+
+       if (cur_if->ifmode == IMESH_MODE) {
+               if (wsec == 0) {
+                       strcpy(emode, "none");
+               } else {
+                       strcpy(emode, "sae");
+               }
+       } else if (wsec == 0) {
+               strcpy(emode, "none");
+       } else if (wsec == 1) {
+               strcpy(emode, "wep");
+       } else if (wsec == 2 || wsec == 10) {
+               strcpy(emode, "tkip");
+       } else if (wsec == 4 || wsec == 12) {
+               strcpy(emode, "aes");
+       } else if (wsec == 6 || wsec == 14) {
+               strcpy(emode, "tkipaes");
+       }
+}
+
 static int
-wl_ext_set_amode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params)
+wl_ext_set_amode(struct wl_if_info *cur_if)
 {
        struct net_device *dev = cur_if->dev;
        authmode_t amode = cur_if->amode;
        int auth=0, wpa_auth=0;
 
-       if (amode == AUTH_OPEN) {
+       if (cur_if->ifmode == IMESH_MODE) {
+               if (amode == AUTH_SAE) {
+                       auth = 0;
+                       wpa_auth = 128;
+                       ANDROID_INFO(("%s: Authentication: SAE\n", __FUNCTION__));
+               } else {
+                       auth = 0;
+                       wpa_auth = 0;
+                       ANDROID_INFO(("%s: Authentication: Open System\n", __FUNCTION__));
+               }
+       } else if (amode == AUTH_OPEN) {
                auth = 0;
                wpa_auth = 0;
-               ANDROID_TRACE(("%s: Authentication: Open System\n", __FUNCTION__));
+               ANDROID_INFO(("%s: Authentication: Open System\n", __FUNCTION__));
        } else if (amode == AUTH_SHARED) {
                auth = 1;
                wpa_auth = 0;
-               ANDROID_TRACE(("%s: Authentication: Shared Key\n", __FUNCTION__));
+               ANDROID_INFO(("%s: Authentication: Shared Key\n", __FUNCTION__));
        } else if (amode == AUTH_WPAPSK) {
                auth = 0;
                wpa_auth = 4;
-               ANDROID_TRACE(("%s: Authentication: WPA-PSK\n", __FUNCTION__));
+               ANDROID_INFO(("%s: Authentication: WPA-PSK\n", __FUNCTION__));
        } else if (amode == AUTH_WPA2PSK) {
                auth = 0;
                wpa_auth = 128;
-               ANDROID_TRACE(("%s: Authentication: WPA2-PSK\n", __FUNCTION__));
+               ANDROID_INFO(("%s: Authentication: WPA2-PSK\n", __FUNCTION__));
        } else if (amode == AUTH_WPAWPA2PSK) {
                auth = 0;
                wpa_auth = 132;
-               ANDROID_TRACE(("%s: Authentication: WPA/WPA2-PSK\n", __FUNCTION__));
+               ANDROID_INFO(("%s: Authentication: WPA/WPA2-PSK\n", __FUNCTION__));
        }
        if (cur_if->ifmode == IMESH_MODE) {
                s32 val = WL_BSSTYPE_MESH;
@@ -748,44 +973,59 @@ wl_ext_set_emode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params
        encmode_t emode = cur_if->emode;
        char *key = cur_if->key;
        s8 iovar_buf[WLC_IOCTL_SMLEN];
+       struct dhd_pub *dhd = dhd_get_pub(dev);
 
        memset(&wsec_key, 0, sizeof(wsec_key));
        memset(&psk, 0, sizeof(psk));
-       if (emode == ENC_NONE) {
+
+       if (cur_if->ifmode == IMESH_MODE) {
+               if (amode == AUTH_SAE) {
+                       wsec = 4;
+                       ANDROID_INFO(("%s: Encryption: AES\n", __FUNCTION__));
+               } else {
+                       wsec = 0;
+                       ANDROID_INFO(("%s: Encryption: No securiy\n", __FUNCTION__));
+               }
+       } else if (emode == ENC_NONE) {
                wsec = 0;
-               ANDROID_TRACE(("%s: Encryption: No securiy\n", __FUNCTION__));
+               ANDROID_INFO(("%s: Encryption: No securiy\n", __FUNCTION__));
        } else if (emode == ENC_WEP) {
                wsec = 1;
                wl_ext_parse_wep(key, &wsec_key);
-               ANDROID_TRACE(("%s: Encryption: WEP\n", __FUNCTION__));
-               ANDROID_TRACE(("%s: Key: \"%s\"\n", __FUNCTION__, wsec_key.data));
+               ANDROID_INFO(("%s: Encryption: WEP\n", __FUNCTION__));
+               ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, wsec_key.data));
        } else if (emode == ENC_TKIP) {
                wsec = 2;
                psk.key_len = strlen(key);
                psk.flags = WSEC_PASSPHRASE;
                memcpy(psk.key, key, strlen(key));
-               ANDROID_TRACE(("%s: Encryption: TKIP\n", __FUNCTION__));
-               ANDROID_TRACE(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
-       } else if (emode == ENC_AES) {
+               ANDROID_INFO(("%s: Encryption: TKIP\n", __FUNCTION__));
+               ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
+       } else if (emode == ENC_AES || amode == AUTH_SAE) {
                wsec = 4;
                psk.key_len = strlen(key);
                psk.flags = WSEC_PASSPHRASE;
                memcpy(psk.key, key, strlen(key));
-               ANDROID_TRACE(("%s: Encryption: AES\n", __FUNCTION__));
-               ANDROID_TRACE(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
+               ANDROID_INFO(("%s: Encryption: AES\n", __FUNCTION__));
+               ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
        } else if (emode == ENC_TKIPAES) {
                wsec = 6;
                psk.key_len = strlen(key);
                psk.flags = WSEC_PASSPHRASE;
                memcpy(psk.key, key, strlen(key));
-               ANDROID_TRACE(("%s: Encryption: TKIP/AES\n", __FUNCTION__));
-               ANDROID_TRACE(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
+               ANDROID_INFO(("%s: Encryption: TKIP/AES\n", __FUNCTION__));
+               ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, psk.key));
+       }
+       if (dhd->conf->chip == BCM43430_CHIP_ID && cur_if->ifidx > 0 && wsec >= 2 &&
+                       apsta_params->apstamode == IAPSTA_MODE) {
+               wsec |= 0x8; // terence 20180628: fix me, this is a workaround
        }
 
        wl_ext_iovar_setint(dev, "wsec", wsec);
 
        if (cur_if->ifmode == IMESH_MODE) {
-               if (amode == AUTH_WPA2PSK && emode == ENC_AES) {
+               if (amode == AUTH_SAE) {
+                       ANDROID_INFO(("%s: Key: \"%s\"\n", __FUNCTION__, key));
                        wl_ext_iovar_setint(dev, "mesh_auth_proto", 1);
                        wl_ext_iovar_setint(dev, "mfp", WL_MFP_REQUIRED);
                        wl_ext_iovar_setbuf(dev, "sae_password", key, strlen(key),
@@ -809,6 +1049,105 @@ wl_ext_set_emode(struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params
        return 0;
 }
 
+static uint16
+wl_ext_get_chan(struct net_device *dev)
+{
+       struct wl_apsta_params *apsta_params = &g_apsta_params;
+       int ret = 0;
+       uint16 chan = 0, ctl_chan;
+       struct ether_addr bssid;
+       u32 chanspec = 0;
+       
+       ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
+       if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
+               if (wldev_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
+                       chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec);
+                       ctl_chan = wf_chspec_ctlchan(chanspec);
+                       chan = (u16)(ctl_chan & 0x00FF);
+                       ANDROID_INFO(("%s: cur_chan=%d(0x%x)\n", __FUNCTION__,
+                               chan, chanspec));
+                       return chan;
+               }
+       }
+
+       return 0;
+}
+
+static chanspec_t
+wl_ext_get_chanspec(struct wl_apsta_params *apsta_params,
+       struct net_device *dev, uint16 channel)
+{
+       s32 _chan = channel;
+       chanspec_t chspec = 0;
+       chanspec_t fw_chspec = 0;
+       u32 bw = WL_CHANSPEC_BW_20;
+       s32 err = BCME_OK;
+       s32 bw_cap = 0;
+       s8 iovar_buf[WLC_IOCTL_SMLEN];
+       struct {
+               u32 band;
+               u32 bw_cap;
+       } param = {0, 0};
+       uint band;
+
+       if (_chan <= CH_MAX_2G_CHANNEL)
+               band = IEEE80211_BAND_2GHZ;
+       else
+               band = IEEE80211_BAND_5GHZ;
+
+       if (band == IEEE80211_BAND_5GHZ) {
+               param.band = WLC_BAND_5G;
+               err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               if (err) {
+                       if (err != BCME_UNSUPPORTED) {
+                               ANDROID_ERROR(("bw_cap failed, %d\n", err));
+                               return err;
+                       } else {
+                               err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
+                               if (err) {
+                                       ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err));
+                               }
+                               if (bw_cap != WLC_N_BW_20ALL)
+                                       bw = WL_CHANSPEC_BW_40;
+                       }
+               } else {
+                       if (WL_BW_CAP_80MHZ(iovar_buf[0]))
+                               bw = WL_CHANSPEC_BW_80;
+                       else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
+                               bw = WL_CHANSPEC_BW_40;
+                       else
+                               bw = WL_CHANSPEC_BW_20;
+               }
+       }
+       else if (band == IEEE80211_BAND_2GHZ)
+               bw = WL_CHANSPEC_BW_20;
+
+set_channel:
+       chspec = wf_channel2chspec(_chan, bw);
+       if (wf_chspec_valid(chspec)) {
+               fw_chspec = wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver, chspec);
+               if (fw_chspec == INVCHANSPEC) {
+                       ANDROID_ERROR(("%s: failed to convert host chanspec to fw chanspec\n",
+                               __FUNCTION__));
+                       fw_chspec = 0;
+               }
+       } else {
+               if (bw == WL_CHANSPEC_BW_80)
+                       bw = WL_CHANSPEC_BW_40;
+               else if (bw == WL_CHANSPEC_BW_40)
+                       bw = WL_CHANSPEC_BW_20;
+               else
+                       bw = 0;
+               if (bw)
+                       goto set_channel;
+               ANDROID_ERROR(("%s: Invalid chanspec 0x%x\n", __FUNCTION__, chspec));
+               err = BCME_ERROR;
+       }
+
+       return fw_chspec;
+}
+
 static void
 wl_ext_ch_to_chanspec(int ch, struct wl_join_params *join_params,
         size_t *join_params_size)
@@ -845,53 +1184,6 @@ wl_ext_ch_to_chanspec(int ch, struct wl_join_params *join_params,
        }
 }
 
-static chanspec_t
-wl_ext_chspec_from_legacy(chanspec_t legacy_chspec)
-{
-       chanspec_t chspec;
-
-       /* get the channel number */
-       chspec = LCHSPEC_CHANNEL(legacy_chspec);
-
-       /* convert the band */
-       if (LCHSPEC_IS2G(legacy_chspec)) {
-               chspec |= WL_CHANSPEC_BAND_2G;
-       } else {
-               chspec |= WL_CHANSPEC_BAND_5G;
-       }
-
-       /* convert the bw and sideband */
-       if (LCHSPEC_IS20(legacy_chspec)) {
-               chspec |= WL_CHANSPEC_BW_20;
-       } else {
-               chspec |= WL_CHANSPEC_BW_40;
-               if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
-                       chspec |= WL_CHANSPEC_CTL_SB_L;
-               } else {
-                       chspec |= WL_CHANSPEC_CTL_SB_U;
-               }
-       }
-
-       if (wf_chspec_malformed(chspec)) {
-               ANDROID_ERROR(("wl_ext_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
-                       chspec));
-               return INVCHANSPEC;
-       }
-
-       return chspec;
-}
-
-static chanspec_t
-wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec)
-{
-       chanspec = dtohchanspec(chanspec);
-       if (ioctl_ver == 1) {
-               chanspec = wl_ext_chspec_from_legacy(chanspec);
-       }
-
-       return chanspec;
-}
-
 static s32
 wl_ext_connect(struct wl_if_info *cur_if)
 {
@@ -918,7 +1210,8 @@ wl_ext_connect(struct wl_if_info *cur_if)
                err = -ENOMEM;
                goto exit;
        }
-       ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), strlen(cur_if->ssid));
+       ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID),
+               strlen(cur_if->ssid));
        memcpy(&ext_join_params->ssid.SSID, cur_if->ssid, ext_join_params->ssid.SSID_len);
        ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
        /* increate dwell time to receive probe response or detect Beacon
@@ -958,8 +1251,8 @@ wl_ext_connect(struct wl_if_info *cur_if)
                        ext_join_params->ssid.SSID_len));
        }
 
-       err = wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "join", ext_join_params, join_params_size,
-               iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL);
+       err = wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "join", ext_join_params,
+               join_params_size, iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL);
 
        printf("Connecting with " MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n",
                MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)), cur_if->channel,
@@ -1006,10 +1299,23 @@ exit:
 
 }
 
+static void
+wl_ext_wait_netif_change(struct wl_apsta_params *apsta_params,
+       bool need_rtnl_unlock)
+{
+       if (need_rtnl_unlock)
+               rtnl_unlock();
+       wait_event_interruptible_timeout(apsta_params->netif_change_event,
+               apsta_params->netif_change, msecs_to_jiffies(1500));
+       if (need_rtnl_unlock)
+               rtnl_lock();
+}
+
 static void
 wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_params)
 {
        struct dhd_pub *dhd;
+       apstamode_t apstamode = apsta_params->apstamode;
        wl_interface_create_t iface;
        struct wl_if_info *cur_if;
        wlc_ssid_t ssid = { 0, {0} };
@@ -1017,50 +1323,81 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para
        wl_country_t cspec = {{0}, 0, {0}};
        wl_p2p_if_t ifreq;
        s32 val = 0;
-       int i, dfs = 1;
+       int i, dfs = 1, pm = 0;
 
        dhd = dhd_get_pub(dev);
 
-       if (!strlen(apsta_params->if_info[IF_VIF].ifname))
-               strcpy(apsta_params->if_info[IF_VIF].ifname, "wlan1");
-       if (!strlen(apsta_params->if_info[IF_VIF2].ifname))
-               strcpy(apsta_params->if_info[IF_VIF2].ifname, "wlan2");
-
        for (i=0; i<MAX_IF_NUM; i++) {
                cur_if = &apsta_params->if_info[i];
+               if (i == 1 && !strlen(cur_if->ifname))
+                       strcpy(cur_if->ifname, "wlan1");
+               if (i == 2 && !strlen(cur_if->ifname))
+                       strcpy(cur_if->ifname, "wlan2");
                if (cur_if->ifmode == ISTA_MODE) {
                        cur_if->channel = 0;
                        cur_if->maxassoc = -1;
                        cur_if->ifstate = IF_STATE_INIT;
-                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt%d_sta", i);
+                       cur_if->prio = PRIO_STA;
+                       cur_if->prefix = 'S';
+                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
                } else if (cur_if->ifmode == IAP_MODE) {
                        cur_if->channel = 1;
                        cur_if->maxassoc = -1;
                        cur_if->ifstate = IF_STATE_INIT;
-                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt%d_ap", i);
+                       cur_if->prio = PRIO_AP;
+                       cur_if->prefix = 'A';
+                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
                        dfs = 0;
                } else if (cur_if->ifmode == IMESH_MODE) {
                        cur_if->channel = 1;
                        cur_if->maxassoc = -1;
                        cur_if->ifstate = IF_STATE_INIT;
-                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt%d_mesh", i);
+                       cur_if->prio = PRIO_MESH;
+                       cur_if->prefix = 'M';
+                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
                        dfs = 0;
                }
        }
-       if (dfs == 0) {
+
+       if (!dfs && !apsta_params->vsdb) {
                dhd_conf_get_country(dhd, &cspec);
-               if (!dhd_conf_map_country_list(dhd, &cspec, 1)) {
+               if (!dhd_conf_map_country_list(dhd, &cspec)) {
                        dhd_conf_set_country(dhd, &cspec);
                        dhd_bus_country_set(dev, &cspec, TRUE);
                }
+               wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+               wl_ext_iovar_setint(dev, "dfs_chan_disable", 1);
+               wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+       }
+
+       if (FW_SUPPORTED(dhd, rsdb)) {
+               if (apstamode == IDUALAP_MODE)
+                       apsta_params->rsdb = TRUE;
+               else if (apstamode == ISTAAPAP_MODE)
+                       apsta_params->rsdb = FALSE;
+               if (apstamode == IDUALAP_MODE || apstamode == ISTAAPAP_MODE ||
+                       apstamode == IMESHONLY_MODE || apstamode == IMESHSTA_MODE ||
+                       apstamode == IMESHAP_MODE || apstamode == IMESHAPSTA_MODE ||
+                       apstamode == IMESHAPAP_MODE) {
+                       wl_config_t rsdb_mode_cfg = {0, 0};
+                       if (apsta_params->rsdb)
+                               rsdb_mode_cfg.config = 1;
+                       printf("%s: set rsdb_mode %d\n", __FUNCTION__, rsdb_mode_cfg.config);
+                       wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+                       wl_ext_iovar_setbuf(dev, "rsdb_mode", &rsdb_mode_cfg,
+                               sizeof(rsdb_mode_cfg), iovar_buf, sizeof(iovar_buf), NULL);
+                       wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+               }
+       } else {
+               apsta_params->rsdb = FALSE;
        }
 
-       if (apsta_params->apstamode == ISTAONLY_MODE) {
+       if (apstamode == ISTAONLY_MODE) {
                wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
                wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
                // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
                wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
-       } else if (apsta_params->apstamode == IAPONLY_MODE) {
+       } else if (apstamode == IAPONLY_MODE) {
                wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
 #ifdef ARP_OFFLOAD_SUPPORT
                /* IF SoftAP is enabled, disable arpoe */
@@ -1084,26 +1421,25 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para
 #endif
 #endif /* PROP_TXSTATUS_VSDB */
        }
-       else if (apsta_params->apstamode == IAPSTA_MODE) {
+       else if (apstamode == IAPSTA_MODE) {
                wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
                wl_ext_iovar_setint(dev, "mpc", 0);
                wl_ext_iovar_setint(dev, "apsta", 1);
                wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+               apsta_params->netif_change = FALSE;
                if (FW_SUPPORTED(dhd, rsdb)) {
                        bzero(&iface, sizeof(wl_interface_create_t));
                        iface.ver = WL_INTERFACE_CREATE_VER;
                        iface.flags = WL_INTERFACE_CREATE_AP;
-                       wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
-                               iovar_buf, WLC_IOCTL_SMLEN, 1, NULL);
+                       wl_ext_iovar_getbuf(dev, "interface_create", &iface,
+                               sizeof(iface), iovar_buf, WLC_IOCTL_SMLEN, NULL);
                } else {
-                       wl_ext_iovar_setbuf_bsscfg(dev, "ssid", &ssid, sizeof(ssid), iovar_buf,
-                               WLC_IOCTL_SMLEN, 1, NULL);
+                       wl_ext_iovar_setbuf_bsscfg(dev, "ssid", &ssid, sizeof(ssid),
+                               iovar_buf, WLC_IOCTL_SMLEN, 1, NULL);
                }
-               apsta_params->netif_change = FALSE;
-               wait_event_interruptible_timeout(apsta_params->netif_change_event,
-                       apsta_params->netif_change, msecs_to_jiffies(1500));
+               wl_ext_wait_netif_change(apsta_params, TRUE);
        }
-       else if (apsta_params->apstamode == IDUALAP_MODE) {
+       else if (apstamode == IDUALAP_MODE) {
                wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
                /* IF SoftAP is enabled, disable arpoe or wlan1 will ping fail */
 #ifdef ARP_OFFLOAD_SUPPORT
@@ -1112,6 +1448,7 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para
                dhd_arp_offload_enable(dhd, FALSE);
 #endif /* ARP_OFFLOAD_SUPPORT */
                wl_ext_iovar_setint(dev, "mpc", 0);
+               wl_ext_iovar_setint(dev, "mbcn", 1);
                wl_ext_iovar_setint(dev, "apsta", 0);
                wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
                val = 1;
@@ -1119,106 +1456,140 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para
                bzero(&iface, sizeof(wl_interface_create_t));
                iface.ver = WL_INTERFACE_CREATE_VER;
                iface.flags = WL_INTERFACE_CREATE_AP;
-               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
-                       iovar_buf, WLC_IOCTL_SMLEN, 1, NULL);
                apsta_params->netif_change = FALSE;
-               wait_event_interruptible_timeout(apsta_params->netif_change_event,
-                       apsta_params->netif_change, msecs_to_jiffies(1500));
+               wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               wl_ext_wait_netif_change(apsta_params, TRUE);
        }
-       else if (apsta_params->apstamode == IMESHONLY_MODE) {
+       else if (apstamode == ISTAAPAP_MODE) {
+               u8 rand_bytes[2] = {0, };
+               get_random_bytes(&rand_bytes, sizeof(rand_bytes));
                wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
                wl_ext_iovar_setint(dev, "mpc", 0);
+               wl_ext_iovar_setint(dev, "mbss", 1);
                wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
-               // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
-       }
-       else if (apsta_params->apstamode == IMESHSTA_MODE) {
-               wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
-               wl_ext_iovar_setint(dev, "mpc", 0);
-               wl_ext_iovar_setint(dev, "apsta", 1);
                wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+               // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
                bzero(&iface, sizeof(wl_interface_create_t));
                iface.ver = WL_INTERFACE_CREATE_VER;
-               iface.flags = WL_INTERFACE_CREATE_STA;
-               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
-                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
+               iface.flags = WL_INTERFACE_CREATE_AP | WL_INTERFACE_MAC_USE;
+               memcpy(&iface.mac_addr, dev->dev_addr, ETHER_ADDR_LEN);
+               iface.mac_addr.octet[0] |= 0x02;
+               iface.mac_addr.octet[5] += 0x01;
+               memcpy(&iface.mac_addr.octet[3], rand_bytes, sizeof(rand_bytes));
                apsta_params->netif_change = FALSE;
-               wait_event_interruptible_timeout(apsta_params->netif_change_event,
-                       apsta_params->netif_change, msecs_to_jiffies(1500));
-       }
-       else if (apsta_params->apstamode == IMESHAP_MODE) {
+               wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               wl_ext_wait_netif_change(apsta_params, TRUE);
+               bzero(&iface, sizeof(wl_interface_create_t));
+               iface.ver = WL_INTERFACE_CREATE_VER;
+               iface.flags = WL_INTERFACE_CREATE_AP | WL_INTERFACE_MAC_USE;
+               memcpy(&iface.mac_addr, dev->dev_addr, ETHER_ADDR_LEN);
+               iface.mac_addr.octet[0] |= 0x02;
+               iface.mac_addr.octet[5] += 0x02;
+               memcpy(&iface.mac_addr.octet[3], rand_bytes, sizeof(rand_bytes));
+               apsta_params->netif_change = FALSE;
+               wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               wl_ext_wait_netif_change(apsta_params, TRUE);
+       }
+       else if (apstamode == IMESHONLY_MODE) {
+               wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+               wl_ext_iovar_setint(dev, "mpc", 0);
+               wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
+               wl_ext_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), 1);
+               wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+               // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
+       }
+       else if (apstamode == IMESHSTA_MODE) {
                wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
                wl_ext_iovar_setint(dev, "mpc", 0);
+               wl_ext_iovar_setint(dev, "mbcn", 1);
+               wl_ext_iovar_setint(dev, "apsta", 1);
+               wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
+               bzero(&iface, sizeof(wl_interface_create_t));
+               iface.ver = WL_INTERFACE_CREATE_VER;
+               iface.flags = WL_INTERFACE_CREATE_STA;
+               apsta_params->netif_change = FALSE;
+               wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               wl_ext_wait_netif_change(apsta_params, TRUE);
+       }
+       else if (apstamode == IMESHAP_MODE) {
+               wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
+               wl_ext_iovar_setint(dev, "mpc", 0);
+               wl_ext_iovar_setint(dev, "mbcn", 1);
                wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
+               wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
                // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
                bzero(&iface, sizeof(wl_interface_create_t));
                iface.ver = WL_INTERFACE_CREATE_VER;
                iface.flags = WL_INTERFACE_CREATE_AP;
-               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
-                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
                apsta_params->netif_change = FALSE;
-               wait_event_interruptible_timeout(apsta_params->netif_change_event,
-                       apsta_params->netif_change, msecs_to_jiffies(1500));
+               wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               wl_ext_wait_netif_change(apsta_params, TRUE);
        }
-       else if (apsta_params->apstamode == IMESHAPSTA_MODE) {
+       else if (apstamode == IMESHAPSTA_MODE) {
                wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
                wl_ext_iovar_setint(dev, "mpc", 0);
+               wl_ext_iovar_setint(dev, "mbcn", 1);
                wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
+               wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
                // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
                bzero(&iface, sizeof(wl_interface_create_t));
                iface.ver = WL_INTERFACE_CREATE_VER;
                iface.flags = WL_INTERFACE_CREATE_AP;
-               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
-                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
                apsta_params->netif_change = FALSE;
-               wait_event_interruptible_timeout(apsta_params->netif_change_event,
-                       apsta_params->netif_change, msecs_to_jiffies(1500));
+               wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               wl_ext_wait_netif_change(apsta_params, TRUE);
                bzero(&iface, sizeof(wl_interface_create_t));
                iface.ver = WL_INTERFACE_CREATE_VER;
                iface.flags = WL_INTERFACE_CREATE_STA;
-               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
-                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
                apsta_params->netif_change = FALSE;
-               wait_event_interruptible_timeout(apsta_params->netif_change_event,
-                       apsta_params->netif_change, msecs_to_jiffies(1500));
+               wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               wl_ext_wait_netif_change(apsta_params, TRUE);
        }
-       else if (apsta_params->apstamode == IMESHAPAP_MODE) {
+       else if (apstamode == IMESHAPAP_MODE) {
                wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
                wl_ext_iovar_setint(dev, "mpc", 0);
+               wl_ext_iovar_setint(dev, "mbcn", 1);
                wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
+               wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
                // don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
                bzero(&iface, sizeof(wl_interface_create_t));
                iface.ver = WL_INTERFACE_CREATE_VER;
                iface.flags = WL_INTERFACE_CREATE_AP;
-               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
-                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
                apsta_params->netif_change = FALSE;
-               wait_event_interruptible_timeout(apsta_params->netif_change_event,
-                       apsta_params->netif_change, msecs_to_jiffies(1500));
+               wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               wl_ext_wait_netif_change(apsta_params, TRUE);
                bzero(&iface, sizeof(wl_interface_create_t));
                iface.ver = WL_INTERFACE_CREATE_VER;
                iface.flags = WL_INTERFACE_CREATE_AP;
-               wl_ext_iovar_getbuf_bsscfg(dev, "interface_create", &iface, sizeof(iface),
-                       iovar_buf, WLC_IOCTL_SMLEN, 0, NULL);
                apsta_params->netif_change = FALSE;
-               wait_event_interruptible_timeout(apsta_params->netif_change_event,
-                       apsta_params->netif_change, msecs_to_jiffies(1500));
+               wl_ext_iovar_getbuf(dev, "interface_create", &iface, sizeof(iface),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               wl_ext_wait_netif_change(apsta_params, TRUE);
        }
-       else if (apsta_params->apstamode == IGOSTA_MODE) {
+       else if (apstamode == IGOSTA_MODE) {
                wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
                wl_ext_iovar_setint(dev, "apsta", 1);
                wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
                bzero(&ifreq, sizeof(wl_p2p_if_t));
                ifreq.type = htod32(WL_P2P_IF_GO);
+               apsta_params->netif_change = FALSE;
                wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq),
                        iovar_buf, WLC_IOCTL_SMLEN, NULL);
-               apsta_params->netif_change = FALSE;
-               wait_event_interruptible_timeout(apsta_params->netif_change_event,
-                       apsta_params->netif_change, msecs_to_jiffies(1500));
+               wl_ext_wait_netif_change(apsta_params, TRUE);
        }
 
        wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver);
        apsta_params->init = TRUE;
-       printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode);
+
+       printf("%s: apstamode=%d\n", __FUNCTION__, apstamode);
 }
 
 static int
@@ -1254,15 +1625,22 @@ wl_ext_isam_init(struct net_device *dev, char *command, int total_len)
                                        apsta_params->apstamode = IAPSTA_MODE;
                                } else if (!strcmp(pick_tmp2, "ap-ap")) {
                                        apsta_params->apstamode = IDUALAP_MODE;
+                               } else if (!strcmp(pick_tmp2, "sta-ap-ap")) {
+                                       apsta_params->apstamode = ISTAAPAP_MODE;
                                } else if (!strcmp(pick_tmp2, "mesh")) {
                                        apsta_params->apstamode = IMESHONLY_MODE;
-                               } else if (!strcmp(pick_tmp2, "mesh-sta")) {
+                               } else if (!strcmp(pick_tmp2, "mesh-sta") ||
+                                               !strcmp(pick_tmp2, "sta-mesh")) {
                                        apsta_params->apstamode = IMESHSTA_MODE;
-                               } else if (!strcmp(pick_tmp2, "mesh-ap")) {
+                               } else if (!strcmp(pick_tmp2, "mesh-ap") ||
+                                               !strcmp(pick_tmp2, "ap-mesh")) {
                                        apsta_params->apstamode = IMESHAP_MODE;
-                               } else if (!strcmp(pick_tmp2, "mesh-ap-sta")) {
+                               } else if (!strcmp(pick_tmp2, "mesh-ap-sta") ||
+                                               !strcmp(pick_tmp2, "sta-ap-mesh") ||
+                                               !strcmp(pick_tmp2, "sta-mesh-ap")) {
                                        apsta_params->apstamode = IMESHAPSTA_MODE;
-                               } else if (!strcmp(pick_tmp2, "mesh-ap-ap")) {
+                               } else if (!strcmp(pick_tmp2, "mesh-ap-ap") ||
+                                               !strcmp(pick_tmp2, "ap-ap-mesh")) {
                                        apsta_params->apstamode = IMESHAPAP_MODE;
                                } else if (!strcmp(pick_tmp2, "apsta")) {
                                        apsta_params->apstamode = IAPSTA_MODE;
@@ -1289,11 +1667,29 @@ wl_ext_isam_init(struct net_device *dev, char *command, int total_len)
                                                apsta_params->if_info[i].ifmode = ISTA_MODE;
                                        else if (!strcmp(pch, "ap"))
                                                apsta_params->if_info[i].ifmode = IAP_MODE;
-                                       else if (!strcmp(pch, "mesh"))
+                                       else if (!strcmp(pch, "mesh")) {
+                                               if (dhd->conf->fw_type != FW_TYPE_MESH) {
+                                                       ANDROID_ERROR(("%s: wrong fw type\n", __FUNCTION__));
+                                                       return -1;
+                                               }
                                                apsta_params->if_info[i].ifmode = IMESH_MODE;
+                                       }
                                        pch = bcmstrtok(&pick_tmp2, " -", 0);
                                }
                        }
+               }
+               else if (!strcmp(param, "rsdb")) {
+                       pch = bcmstrtok(&pick_tmp, " ", 0);
+                       if (pch) {
+                               if (!strcmp(pch, "y")) {
+                                       apsta_params->rsdb = TRUE;
+                               } else if (!strcmp(pch, "n")) {
+                                       apsta_params->rsdb = FALSE;
+                               } else {
+                                       ANDROID_ERROR(("%s: rsdb [y|n]\n", __FUNCTION__));
+                                       return -1;
+                               }
+                       }
                } else if (!strcmp(param, "vsdb")) {
                        pch = bcmstrtok(&pick_tmp, " ", 0);
                        if (pch) {
@@ -1306,6 +1702,11 @@ wl_ext_isam_init(struct net_device *dev, char *command, int total_len)
                                        return -1;
                                }
                        }
+               } else if (!strcmp(param, "csa")) {
+                       pch = bcmstrtok(&pick_tmp, " ", 0);
+                       if (pch) {
+                               apsta_params->csa = (int)simple_strtol(pch, NULL, 0);
+                       }
                } else if (!strcmp(param, "ifname")) {
                        pch = NULL;
                        pick_tmp2 = bcmstrtok(&pick_tmp, " ", 0);
@@ -1342,7 +1743,7 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
 {
        char *pch, *pick_tmp;
        char name[20], data[100];
-       int i, j;
+       int i, j, len;
        char *ifname_head = NULL;
 
        typedef struct config_map_t {
@@ -1350,7 +1751,7 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
                char *head;
                char *tail;
        } config_map_t;
-       
+
        config_map_t config_map [] = {
                {" ifname ",    NULL, NULL},
                {" ssid ",              NULL, NULL},
@@ -1368,14 +1769,14 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
        pick_tmp = command;
 
        // reset head and tail
-       for (i = 0;  i < sizeof(config_map)/sizeof(config_map[0]); i++) {
+       for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
                row = &config_map[i];
                row->head = NULL;
                row->tail = pick_tmp + strlen(pick_tmp);
        }
 
        // pick head
-       for (i = 0;  i < sizeof(config_map)/sizeof(config_map[0]); i++) {
+       for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
                row = &config_map[i];
                pch = strstr(pick_tmp, row->name);
                if (pch) {
@@ -1384,9 +1785,9 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
        }
 
        // sort by head
-       for (i = 0;  i < sizeof(config_map)/sizeof(config_map[0]) - 1;  i++) {
+       for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
                row_prev = &config_map[i];
-               for (j = i+1;  j < sizeof(config_map)/sizeof(config_map[0]);  j++) {
+               for (j = i+1; j < sizeof(config_map)/sizeof(config_map[0]); j++) {
                        row = &config_map[j];
                        if (row->head < row_prev->head) {
                                strcpy(name, row_prev->name);
@@ -1400,7 +1801,7 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
        }
 
        // pick tail
-       for (i = 0;  i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
+       for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
                row_prev = &config_map[i];
                row = &config_map[i+1];
                if (row_prev->head) {
@@ -1409,7 +1810,7 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
        }
 
        // remove name from head
-       for (i = 0;  i < sizeof(config_map)/sizeof(config_map[0]); i++) {
+       for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
                row = &config_map[i];
                if (row->head) {
                        if (!strcmp(row->name, " ifname ")) {
@@ -1420,11 +1821,11 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
                }
        }
 
-       for (i = 0;  i < sizeof(config_map)/sizeof(config_map[0]); i++) {
+       for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
                row = &config_map[i];
                if (row->head) {
                        memset(data, 0, sizeof(data));
-                       if (row->tail) {
+                       if (row->tail && row->tail > row->head) {
                                strncpy(data, row->head, row->tail-row->head);
                        } else {
                                strcpy(data, row->head);
@@ -1434,7 +1835,12 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
                        if (!strcmp(row->name, " ifname ")) {
                                break;
                        } else if (!strcmp(row->name, " ssid ")) {
-                               strcpy(cur_if->ssid, pick_tmp);
+                               len = strlen(pick_tmp);
+                               memset(cur_if->ssid, 0, sizeof(cur_if->ssid));
+                               if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"')
+                                       strncpy(cur_if->ssid, &pick_tmp[1], len-2);
+                               else
+                                       strcpy(cur_if->ssid, pick_tmp);
                        } else if (!strcmp(row->name, " bssid ")) {
                                pch = bcmstrtok(&pick_tmp, ": ", 0);
                                for (j=0; j<6 && pch; j++) {
@@ -1480,6 +1886,8 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
                                        cur_if->amode = AUTH_WPA2PSK;
                                else if (!strcmp(pick_tmp, "wpawpa2psk"))
                                        cur_if->amode = AUTH_WPAWPA2PSK;
+                               else if (!strcmp(pick_tmp, "sae"))
+                                       cur_if->amode = AUTH_SAE;
                                else {
                                        ANDROID_ERROR(("%s: amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]\n",
                                                __FUNCTION__));
@@ -1502,7 +1910,12 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
                                        return -1;
                                }
                        } else if (!strcmp(row->name, " key ")) {
-                               strcpy(cur_if->key, pick_tmp);
+                               len = strlen(pick_tmp);
+                               memset(cur_if->key, 0, sizeof(cur_if->key));
+                               if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"')
+                                       strncpy(cur_if->key, &pick_tmp[1], len-2);
+                               else
+                                       strcpy(cur_if->key, pick_tmp);
                        }
                }
        }
@@ -1514,11 +1927,11 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
 static int
 wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len)
 {
-       int ret=0;
+       int ret=0, i;
        char *pch, *pch2, *pick_tmp, *pick_next=NULL, *param;
        struct wl_apsta_params *apsta_params = &g_apsta_params;
        char ifname[IFNAMSIZ+1];
-       struct wl_if_info *cur_if = &apsta_params->if_info[IF_PIF];
+       struct wl_if_info *cur_if = NULL;
 
        if (!apsta_params->init) {
                ANDROID_ERROR(("%s: please init first\n", __FUNCTION__));
@@ -1541,15 +1954,16 @@ wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len)
                                ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
                                return -1;
                        }
-                       if (!strcmp(apsta_params->if_info[IF_PIF].dev->name, ifname)) {
-                               cur_if = &apsta_params->if_info[IF_PIF];
-                       } else if (!strcmp(apsta_params->if_info[IF_VIF].ifname, ifname)) {
-                               cur_if = &apsta_params->if_info[IF_VIF];
-                       } else if (!strcmp(apsta_params->if_info[IF_VIF2].ifname, ifname)) {
-                               cur_if = &apsta_params->if_info[IF_VIF2];
-                       } else {
-                               ANDROID_ERROR(("%s: wrong ifname=%s in apstamode=%d\n", __FUNCTION__,
-                                       ifname, apsta_params->apstamode));
+                       for (i=0; i<MAX_IF_NUM; i++) {
+                               if (apsta_params->if_info[i].dev &&
+                                               !strcmp(apsta_params->if_info[i].dev->name, ifname)) {
+                                       cur_if = &apsta_params->if_info[i];
+                                       break;
+                               }
+                       }
+                       if (!cur_if) {
+                               ANDROID_ERROR(("%s: wrong ifname=%s in apstamode=%d\n",
+                                       __FUNCTION__, ifname, apsta_params->apstamode));
                                return -1;
                        }
                        ret = wl_ext_parse_config(cur_if, pick_tmp, &pick_next);
@@ -1566,6 +1980,131 @@ wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len)
        return 0;
 }
 
+static int
+wl_ext_isam_status(struct net_device *dev)
+{
+       struct wl_apsta_params *apsta_params = &g_apsta_params;
+       int i;
+       bool now_if;
+       struct wl_if_info *tmp_if;
+       uint16 chan = 0;
+       wlc_ssid_t ssid = { 0, {0} };
+       char amode[16], emode[16];
+
+       if (apsta_params->init == FALSE) {
+               return 0;
+       }
+
+       printf("****************************\n");
+       printf("%s: apstamode=%d\n", __FUNCTION__, apsta_params->apstamode);
+       for (i=0; i<MAX_IF_NUM; i++) {
+               now_if = FALSE;
+               memset(&ssid, 0, sizeof(ssid));
+               memset(amode, 0, sizeof(amode));
+               memset(emode, 0, sizeof(emode));
+               tmp_if = &apsta_params->if_info[i];
+               if (dev == tmp_if->dev)
+                       now_if = TRUE;
+               if (tmp_if->dev) {
+                       chan = wl_ext_get_chan(tmp_if->dev);
+                       if (chan) {
+                               wl_ext_ioctl(tmp_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
+                               wl_ext_get_amode(tmp_if, amode);
+                               wl_ext_get_emode(tmp_if, emode);
+                       }
+                       if (chan) {
+                               printf("%s[%c-%c%s]: chan %3d, amode %s, emode %s, SSID \"%s\"\n",
+                                       tmp_if->ifname, tmp_if->prefix, chan?'E':'D',
+                                       now_if?"*":" ", chan, amode, emode, ssid.SSID);
+                       } else {
+                               printf("%s[%c-%c%s]:\n",
+                                       tmp_if->ifname, tmp_if->prefix, chan?'E':'D',
+                                       now_if?"*":" ");
+                       }
+               }
+       }
+       printf("****************************\n");
+
+       return 0;
+}
+
+static int
+wl_ext_if_down(struct wl_if_info *cur_if)
+{
+       s8 iovar_buf[WLC_IOCTL_SMLEN];
+       scb_val_t scbval;
+       struct {
+               s32 cfg;
+               s32 val;
+       } bss_setbuf;
+       apstamode_t apstamode = g_apsta_params.apstamode;
+
+       printf("%s: %s[%c] Turning off\n", __FUNCTION__, cur_if->ifname, cur_if->prefix);
+
+       if (cur_if->ifmode == ISTA_MODE) {
+               wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
+       } else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
+               // deauthenticate all STA first
+               memcpy(scbval.ea.octet, &ether_bcast, ETHER_ADDR_LEN);
+               wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1);
+       }
+
+       if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) {
+               wl_ext_ioctl(cur_if->dev, WLC_DOWN, NULL, 0, 1);
+       } else {
+               bss_setbuf.cfg = 0xffffffff;
+               bss_setbuf.val = htod32(0);
+               wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+       }
+
+       return 0;
+}
+
+static int
+wl_ext_if_up(struct wl_if_info *cur_if)
+{
+       s8 iovar_buf[WLC_IOCTL_SMLEN];
+       struct {
+               s32 cfg;
+               s32 val;
+       } bss_setbuf;
+       struct wl_apsta_params *apsta_params = &g_apsta_params;
+       apstamode_t apstamode = apsta_params->apstamode;
+       chanspec_t fw_chspec;
+
+       if (cur_if->ifmode != IAP_MODE) {
+               ANDROID_ERROR(("%s: Wrong ifmode on %s[%c]\n", __FUNCTION__,
+                       cur_if->ifname, cur_if->prefix));
+               return 0;
+       }
+
+       if (cur_if->channel >= 52 && cur_if->channel <= 148) {
+               printf("%s: %s[%c] skip DFS channel %d\n", __FUNCTION__,
+                       cur_if->ifname, cur_if->prefix, cur_if->channel);
+               return 0;
+       }
+
+       printf("%s: %s[%c] Turning on\n", __FUNCTION__, cur_if->ifname, cur_if->prefix);
+       wl_ext_isam_status(cur_if->dev);
+
+       wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver, cur_if->channel,
+               &fw_chspec);
+
+       if (apstamode == IAPONLY_MODE) {
+               wl_ext_ioctl(cur_if->dev, WLC_UP, NULL, 0, 1);
+       } else {
+               bss_setbuf.cfg = 0xffffffff;    
+               bss_setbuf.val = htod32(1);
+               wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf,
+                       sizeof(bss_setbuf), iovar_buf, WLC_IOCTL_SMLEN, NULL);
+       }
+
+       OSL_SLEEP(500);
+
+       return 0;
+}
+
 static int
 wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
 {
@@ -1574,7 +2113,6 @@ wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
        wlc_ssid_t ssid = { 0, {0} };
        scb_val_t scbval;
        struct {
-               s32 tmp;
                s32 cfg;
                s32 val;
        } bss_setbuf;
@@ -1621,6 +2159,8 @@ wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
                return -1;
        }
 
+       printf("%s: %s[%c] Disabling\n", __FUNCTION__, ifname, cur_if->prefix);
+
        if (cur_if->ifmode == ISTA_MODE) {
                wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
        } else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
@@ -1635,9 +2175,7 @@ wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
                wl_ext_iovar_setint(dev, "mpc", 1);
        } else if ((apstamode==IAPSTA_MODE || apstamode==IGOSTA_MODE) &&
                        cur_if->ifmode == IAP_MODE) {
-               // if_info[IF_VIF] is AP mode
-               bss_setbuf.tmp = 0xffffffff;
-               bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down
+               bss_setbuf.cfg = 0xffffffff;
                bss_setbuf.val = htod32(0);
                wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
                        iovar_buf, WLC_IOCTL_SMLEN, NULL);
@@ -1658,16 +2196,16 @@ wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
                }
 #endif 
 #endif /* PROP_TXSTATUS_VSDB */
-       } else if (apstamode == IDUALAP_MODE) {
-               bss_setbuf.tmp = 0xffffffff;
-               bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down
+       }
+       else if (apstamode == IDUALAP_MODE) {
+               bss_setbuf.cfg = 0xffffffff;
                bss_setbuf.val = htod32(0);
                wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
                        iovar_buf, WLC_IOCTL_SMLEN, NULL);
        } else if (apstamode == IMESHSTA_MODE || apstamode == IMESHAP_MODE ||
-                       apstamode == IMESHAPSTA_MODE || apstamode == IMESHAPAP_MODE) {
-               bss_setbuf.tmp = 0xffffffff;
-               bss_setbuf.cfg = 0; // must be 0, or wlan1 can not be down
+                       apstamode == IMESHAPSTA_MODE || apstamode == IMESHAPAP_MODE ||
+                       apstamode == ISTAAPAP_MODE) {
+               bss_setbuf.cfg = 0xffffffff;
                bss_setbuf.val = htod32(0);
                wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
                        iovar_buf, WLC_IOCTL_SMLEN, NULL);
@@ -1675,153 +2213,176 @@ wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
 
        cur_if->ifstate = IF_STATE_DISALBE;
 
-       printf("%s: ifname=%s, mode=%d\n", __FUNCTION__, ifname, cur_if->ifmode);
+       printf("%s: %s[%c] disabled\n", __FUNCTION__, ifname, cur_if->prefix);
 
        return 0;
 }
 
-static bool
-wl_ext_iapsta_diff_band(uint16 channel1, uint16 channel2)
-{
-       ANDROID_TRACE(("%s: cur_chan=%d, channel=%d\n", __FUNCTION__, channel1, channel2));
-       if ((channel1 <= CH_MAX_2G_CHANNEL && channel2 > CH_MAX_2G_CHANNEL) ||
-               (channel1 > CH_MAX_2G_CHANNEL && channel2 <= CH_MAX_2G_CHANNEL)) {
-               return TRUE;
-       } else {
-               return FALSE;
-       }
-}
-
 static uint16
-wl_ext_iapsta_is_vsdb(struct net_device *dev,
-       struct wl_if_info *cur_if, struct wl_if_info *another_if)
+wl_ext_get_vsdb_chan(struct net_device *dev,
+       struct wl_if_info *cur_if, struct wl_if_info *target_if)
 {
        struct wl_apsta_params *apsta_params = &g_apsta_params;
-       int ret = 0, cur_chan = 0;
-       uint16 another_chan = 0, ctl_chan;
+       uint16 target_chan = 0, cur_chan = cur_if->channel;
        struct dhd_pub *dhd;
-       struct ether_addr bssid;
-       u32 chanspec = 0;
 
        dhd = dhd_get_pub(dev);
-       
-       ret = wldev_ioctl(another_if->dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
-       if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
-               if (wldev_iovar_getint(another_if->dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
-                       ANDROID_TRACE(("%s: chanspec=0x%x\n", __FUNCTION__, chanspec));
-                       chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec);
-                       ctl_chan = wf_chspec_ctlchan(chanspec);
-                       another_chan = (u16)(ctl_chan & 0x00FF);
-                       cur_chan = cur_if->channel;
-                       if (wl_ext_iapsta_diff_band(another_chan, cur_chan)) {
-                               // different band
-                               if (!FW_SUPPORTED(dhd, rsdb))
-                                       return another_chan;
-                       } else {
-                               // same band
-                               if (another_chan != cur_chan)
-                                       return another_chan;
-                       }
+
+       target_chan = wl_ext_get_chan(target_if->dev);
+       if (target_chan) {
+               ANDROID_INFO(("%s: cur_chan=%d, target_chan=%d\n", __FUNCTION__,
+                       cur_chan, target_chan));
+               if ((cur_chan <= CH_MAX_2G_CHANNEL && target_chan > CH_MAX_2G_CHANNEL) ||
+                               (cur_chan > CH_MAX_2G_CHANNEL && target_chan <= CH_MAX_2G_CHANNEL)) {
+                       // different band
+                       if (!FW_SUPPORTED(dhd, rsdb) || !apsta_params->rsdb)
+                               return target_chan;
+               } else {
+                       // same band
+                       if (target_chan != cur_chan)
+                               return target_chan;
                }
        }
 
        return 0;
 }
 
-static void
-wl_ext_iapsta_change_channel(struct wl_if_info *cur_if, uint16 chan)
+static int
+wl_ext_triger_csa(struct wl_if_info *cur_if)
 {
-       if (chan) {
-               char cmd[50] = "";
-               printf("%s: deauthenticate all STA and move to chan=%d on %s\n",
-                       __FUNCTION__, chan, cur_if->ifname);
-               snprintf(cmd, 50, "%s %s", "isam_disable ifname", cur_if->ifname);
-               wl_ext_iapsta_disable(cur_if->dev, cmd, strlen(cmd));
-               cur_if->channel = chan;
-               snprintf(cmd, 50, "%s %s", "isam_enable ifname", cur_if->ifname);
-               wl_ext_iapsta_enable(cur_if->dev, cmd, strlen(cmd));
+       struct wl_apsta_params *apsta_params = &g_apsta_params;
+       s8 iovar_buf[WLC_IOCTL_SMLEN];
+
+       if (apsta_params->csa & CSA_DRV_BIT &&
+                       (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE)) {
+               if (!cur_if->channel) {
+                       printf("%s: %s[%c] skip channel %d\n", __FUNCTION__,
+                               cur_if->ifname, cur_if->prefix, cur_if->channel);
+               } else if (cur_if->channel >= 52 && cur_if->channel <= 148) {
+                       printf("%s: %s[%c] skip DFS channel %d\n", __FUNCTION__,
+                               cur_if->ifname, cur_if->prefix, cur_if->channel);
+                       wl_ext_if_down(cur_if);
+               } else {
+                       wl_chan_switch_t csa_arg;
+                       memset(&csa_arg, 0, sizeof(csa_arg));
+                       csa_arg.mode = 1;
+                       csa_arg.count = 3;
+                       csa_arg.chspec = wl_ext_get_chanspec(apsta_params, cur_if->dev,
+                               cur_if->channel);
+                       if (csa_arg.chspec) {
+                               printf("%s: Trigger CSA to channel %d(0x%x)\n", __FUNCTION__,
+                                       cur_if->channel, csa_arg.chspec);
+                               wl_ext_iovar_setbuf(cur_if->dev, "csa", &csa_arg, sizeof(csa_arg),
+                                       iovar_buf, sizeof(iovar_buf), NULL);
+                               OSL_SLEEP(500);
+                               wl_ext_isam_status(cur_if->dev);
+                       } else {
+                               printf("%s: fail to get chanspec\n", __FUNCTION__);
+                       }
+               }
        }
+
+       return 0;
 }
 
-static void
-wl_ext_iapsta_change_cur_iface_channel(struct net_device *dev,
+static uint16
+wl_ext_move_cur_channel(struct net_device *dev,
        struct wl_if_info *cur_if)
 {
        struct wl_apsta_params *apsta_params = &g_apsta_params;
-       struct wl_if_info *another_if, *final_if = NULL;
-       uint16 new_chan = 0;
+       struct wl_if_info *tmp_if, *target_if = NULL;
+       uint16 tmp_chan, target_chan = 0;
+       wl_prio_t max_prio;
        int i;
 
-       if (cur_if->ifmode == IAP_MODE) {
-               for (i=MAX_IF_NUM-1; i>=0; i--) {
-                       another_if = &apsta_params->if_info[i];
-                       if (another_if->ifmode == ISTA_MODE) {
-                               new_chan = wl_ext_iapsta_is_vsdb(dev, cur_if, another_if);
-                               if (new_chan) {
-                                       final_if = another_if;
-                                       break;
-                               }
-                       }
-               }
-       } else if (cur_if->ifmode == IMESH_MODE) {
-               for (i=MAX_IF_NUM-1; i>=0; i--) {
-                       another_if = &apsta_params->if_info[i];
-                       if (another_if->ifmode == ISTA_MODE || another_if->ifmode == IAP_MODE) {
-                               new_chan = wl_ext_iapsta_is_vsdb(dev, cur_if, another_if);
-                               if (new_chan) {
-                                       final_if = another_if;
-                                       break;
-                               }
+       if (apsta_params->vsdb) {
+               target_chan = cur_if->channel;
+               goto exit;
+       }
+
+       // find the max prio
+       max_prio = cur_if->prio;
+       for (i=0; i<MAX_IF_NUM; i++) {
+               tmp_if = &apsta_params->if_info[i];
+               if (tmp_if->ifstate >= IF_STATE_INIT && cur_if != tmp_if &&
+                               tmp_if->prio > max_prio) {
+                       tmp_chan = wl_ext_get_vsdb_chan(dev, cur_if, tmp_if);
+                       if (tmp_chan) {
+                               target_if = tmp_if;
+                               target_chan = tmp_chan;
+                               max_prio = tmp_if->prio;
                        }
                }
        }
-       if (new_chan && !apsta_params->vsdb) {
-               cur_if->channel = new_chan;
-               printf("%s: %s ifmode=%d, %s ifmode=%d, channel=%d\n", __FUNCTION__,
-                       cur_if->ifname, cur_if->ifmode, final_if->ifname, final_if->ifmode,
-                       cur_if->channel);
+
+       if (target_chan) {
+               printf("%s: %s channel=%d => %s channel=%d\n", __FUNCTION__,
+                       cur_if->ifname, cur_if->channel, target_if->ifname, target_chan);
+               cur_if->channel = target_chan;
+       }
+exit:
+       if ((cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) &&
+                       (cur_if->channel >= 52 && cur_if->channel <= 148)) {
+               printf("%s: %s[%c] skip DFS channel %d\n", __FUNCTION__,
+                       cur_if->ifname, cur_if->prefix, cur_if->channel);
+               cur_if->channel = 0;
        }
 
+       return cur_if->channel;
 }
 
 static void
-wl_ext_iapsta_change_other_iface_channel(struct net_device *dev,
+wl_ext_move_other_channel(struct net_device *dev,
        struct wl_if_info *cur_if)
 {
        struct wl_apsta_params *apsta_params = &g_apsta_params;
-       struct wl_if_info *another_if;
-       uint16 new_chan = 0;
+       struct wl_if_info *tmp_if, *target_if=NULL;
+       uint16 tmp_chan, target_chan = 0;
+       wl_prio_t max_prio = 0, cur_prio;
        int i;
 
-       if (cur_if->ifmode == ISTA_MODE) {
-               for (i=MAX_IF_NUM-1; i>=0; i--) {
-                       another_if = &apsta_params->if_info[i];
-                       if (another_if->ifmode == IAP_MODE || another_if->ifmode == IMESH_MODE) {
-                               new_chan = wl_ext_iapsta_is_vsdb(dev, cur_if, another_if);
-                               if (new_chan && !apsta_params->vsdb) {
-                                       wl_ext_iapsta_change_channel(another_if, cur_if->channel);
-                               }
+       if (apsta_params->vsdb || !cur_if->channel) {
+               return;
+       }
+
+       // find the max prio, but lower than cur_if
+       cur_prio = cur_if->prio;
+       for (i=0; i<MAX_IF_NUM; i++) {
+               tmp_if = &apsta_params->if_info[i];
+               if (tmp_if->ifstate >= IF_STATE_INIT && cur_if != tmp_if &&
+                               tmp_if->prio >= max_prio && tmp_if->prio <= cur_prio) {
+                       tmp_chan = wl_ext_get_vsdb_chan(dev, cur_if, tmp_if);
+                       if (tmp_chan) {
+                               target_if = tmp_if;
+                               target_chan = tmp_chan;
+                               max_prio = tmp_if->prio;
                        }
                }
-       } else if (cur_if->ifmode == IAP_MODE) {
-               for (i=0; i<MAX_IF_NUM; i++) {
-                       another_if = &apsta_params->if_info[i];
-                       if (another_if->ifmode == IMESH_MODE) {
-                               new_chan = wl_ext_iapsta_is_vsdb(dev, cur_if, another_if);
-                               if (new_chan && !apsta_params->vsdb) {
-                                       wl_ext_iapsta_change_channel(another_if, cur_if->channel);
-                               }
+       }
+
+       if (target_if) {
+               printf("%s: %s channel=%d => %s channel=%d\n", __FUNCTION__,
+                       target_if->ifname, target_chan, cur_if->ifname, cur_if->channel);
+               target_if->channel = cur_if->channel;
+               if (apsta_params->csa == 0) {
+                       wl_ext_if_down(target_if);
+                       wl_ext_move_other_channel(dev, target_if);
+                       if (target_if->ifmode == ISTA_MODE || target_if->ifmode == IMESH_MODE) {
+                               wl_ext_enable_iface(target_if->dev, target_if->ifname);
+                       } else if (target_if->ifmode == IAP_MODE) {
+                               wl_ext_if_up(target_if);
                        }
+               } else {
+                       wl_ext_triger_csa(target_if);
                }
        }
 
 }
 
 static int
-wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
+wl_ext_enable_iface(struct net_device *dev, char *ifname)
 {
-       int ret = 0, i;
-       char *pick_tmp, *param;
+       int i;
        s8 iovar_buf[WLC_IOCTL_SMLEN];
        wlc_ssid_t ssid = { 0, {0} };
        chanspec_t fw_chspec;
@@ -1834,9 +2395,7 @@ wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
        struct wl_apsta_params *apsta_params = &g_apsta_params;
        apstamode_t apstamode = apsta_params->apstamode;
        struct wl_if_info *cur_if = NULL;
-       char cmd[128];
        struct dhd_pub *dhd;
-       struct ether_addr bssid;
        uint16 cur_chan;
 
        dhd = dhd_get_pub(dev);
@@ -1853,38 +2412,34 @@ wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
                return -1;
        }
 
-       wl_ext_iapsta_change_cur_iface_channel(dev, cur_if);
+       printf("%s: %s[%c] Enabling\n", __FUNCTION__, ifname, cur_if->prefix);
 
-       if ((apstamode == IMESHSTA_MODE || apstamode == IMESHAP_MODE ||
-                       apstamode == IMESHAPSTA_MODE || apstamode == IMESHAPAP_MODE) &&
-                       cur_if == &apsta_params->if_info[IF_PIF] &&
-                       cur_if->ifstate == IF_STATE_INIT &&
-                       FW_SUPPORTED(dhd, rsdb)) {
-               wl_config_t rsdb_mode_cfg = {1, 0};
-               // mesh-ap must set rsdb_mode=1 in same channel or AP mode not easy to be found
-               printf("%s: set rsdb_mode %d\n", __FUNCTION__, rsdb_mode_cfg.config);
-               wl_ext_iovar_setbuf(dev, "rsdb_mode", &rsdb_mode_cfg,
-                       sizeof(rsdb_mode_cfg), iovar_buf, sizeof(iovar_buf), NULL);
-       }
+       wl_ext_isam_status(cur_if->dev);
 
-       ret = wldev_ioctl(cur_if->dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
-       if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
-               ANDROID_INFO(("%s: Associated! ret %d\n", __FUNCTION__, ret));
+       wl_ext_move_cur_channel(dev, cur_if);
+       if (!cur_if->channel && cur_if->ifmode != ISTA_MODE) {
                return 0;
        }
 
-       ssid.SSID_len = strlen(cur_if->ssid);
-       memcpy(ssid.SSID, cur_if->ssid, ssid.SSID_len);
-       ANDROID_TRACE(("%s: apstamode=%d, bssidx=%d\n", __FUNCTION__, apstamode, cur_if->bssidx));
+       cur_chan = wl_ext_get_chan(cur_if->dev);
+       if (cur_chan) {
+               ANDROID_INFO(("%s: Associated!\n", __FUNCTION__));
+               if (cur_chan != cur_if->channel) {
+                       wl_ext_triger_csa(cur_if);
+               }
+               return 0;
+       }
 
-       wl_ext_iapsta_change_other_iface_channel(dev, cur_if);
+       wl_ext_move_other_channel(dev, cur_if);
 
-       if (cur_if == &apsta_params->if_info[IF_VIF] || cur_if == &apsta_params->if_info[IF_VIF2]) {
+       if (cur_if->ifidx > 0) {
                wl_ext_iovar_setbuf(cur_if->dev, "cur_etheraddr", (u8 *)cur_if->dev->dev_addr,
                        ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
        }
 
        // set ssid for AP
+       ssid.SSID_len = strlen(cur_if->ssid);
+       memcpy(ssid.SSID, cur_if->ssid, ssid.SSID_len);
        if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
                wl_ext_iovar_setint(dev, "mpc", 0);
                if (apstamode == IAPONLY_MODE) {
@@ -1897,10 +2452,12 @@ wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
 
        if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
                wl_ext_set_bgnmode(cur_if);
-               cur_chan = cur_if->channel;
-               if (!cur_chan) {
-                       cur_chan = 1;
+               if (!cur_if->channel) {
 #ifdef WL_CFG80211
+                       char *pick_tmp, *param;
+                       char cmd[128];
+                       uint16 cur_chan;
+                       cur_chan = 1;
                        snprintf(cmd, 128, "get_best_channels");
                        wl_cfg80211_get_best_channels(dev, cmd, strlen(cmd));
                        pick_tmp = cmd;
@@ -1913,12 +2470,16 @@ wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
                                }
                                param = bcmstrtok(&pick_tmp, " ", 0);
                        }
+                       cur_if->channel = cur_chan;
+#else
+                       cur_if->channel = 1;
 #endif
                }
-               wl_ext_set_chanspec(cur_if->dev, cur_chan, &fw_chspec);
+               wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver, cur_if->channel,
+                       &fw_chspec);
        }
 
-       wl_ext_set_amode(cur_if, apsta_params);
+       wl_ext_set_amode(cur_if);
        wl_ext_set_emode(cur_if, apsta_params);
 
        if (cur_if->ifmode == IAP_MODE) {
@@ -1926,8 +2487,10 @@ wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
                        wl_ext_iovar_setint(dev, "maxassoc", cur_if->maxassoc);
                // terence: fix me, hidden does not work in dualAP mode
                if (cur_if->hidden > 0) {
-                       wl_ext_ioctl(cur_if->dev, WLC_SET_CLOSED, &cur_if->hidden, sizeof(cur_if->hidden), 1);
-                       printf("%s: Broadcast SSID: %s\n", __FUNCTION__, cur_if->hidden ? "OFF":"ON");
+                       wl_ext_ioctl(cur_if->dev, WLC_SET_CLOSED, &cur_if->hidden,
+                               sizeof(cur_if->hidden), 1);
+                       printf("%s: Broadcast SSID: %s\n", __FUNCTION__,
+                               cur_if->hidden ? "OFF":"ON");
                }
        }
 
@@ -1945,8 +2508,8 @@ wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
                        } else {
                                bss_setbuf.cfg = htod32(cur_if->bssidx);
                                bss_setbuf.val = htod32(1);
-                               wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
-                                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+                               wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf,
+                                       sizeof(bss_setbuf), iovar_buf, WLC_IOCTL_SMLEN, NULL);
                        }
 #ifdef ARP_OFFLOAD_SUPPORT
                        /* IF SoftAP is enabled, disable arpoe */
@@ -1969,6 +2532,14 @@ wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
        }
        else if (apstamode == IDUALAP_MODE) {
                wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
+       } else if (apstamode == ISTAAPAP_MODE) {
+               if (cur_if->ifmode == ISTA_MODE) {
+                       wl_ext_connect(cur_if);
+               } else if (cur_if->ifmode == IAP_MODE) {
+                       wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
+               } else {
+                       printf("%s: wrong ifmode %d\n", __FUNCTION__, cur_if->ifmode);
+               }
        } else if (apstamode == IMESHONLY_MODE ||
                        apstamode == IMESHSTA_MODE || apstamode == IMESHAP_MODE ||
                        apstamode == IMESHAPSTA_MODE || apstamode == IMESHAPAP_MODE) {
@@ -1978,10 +2549,9 @@ wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
                        wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
                } else if (cur_if->ifmode == IMESH_MODE) {
                        // need to up before setting ssid
-                       wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
                        memset(&join_params, 0, sizeof(join_params));
                        join_params.ssid.SSID_len = strlen(cur_if->ssid);
-                       memcpy((void *)join_params.ssid.SSID, cur_if->ssid, ssid.SSID_len);
+                       memcpy((void *)join_params.ssid.SSID, cur_if->ssid, strlen(cur_if->ssid));
                        join_params.params.chanspec_list[0] = fw_chspec;
                        join_params.params.chanspec_num = 1;
                        join_params_size = sizeof(join_params);
@@ -1991,8 +2561,10 @@ wl_ext_iapsta_enable_iface(struct net_device *dev, char *ifname)
                }
        }
 
-       printf("%s: ifname=%s, mode=%d, SSID: \"%s\"\n", __FUNCTION__,
-               ifname, cur_if->ifmode, cur_if->ssid);
+       OSL_SLEEP(500);
+       printf("%s: %s[%c] enabled with SSID: \"%s\"\n", __FUNCTION__,
+               ifname, cur_if->prefix, cur_if->ssid);
+       wl_ext_isam_status(cur_if->dev);
 
        cur_if->ifstate = IF_STATE_ENABLE;
 
@@ -2022,11 +2594,9 @@ wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len)
                        pch = bcmstrtok(&pick_tmp, " ", 0);
                        if (pch) {
                                strcpy(ifname, pch);
-                               ret = wl_ext_iapsta_enable_iface(dev, ifname);
+                               ret = wl_ext_enable_iface(dev, ifname);
                                if (ret)
                                        return ret;
-                               else
-                                       OSL_SLEEP(1000);
                        } else {
                                ANDROID_ERROR(("%s: ifname [wlanX]\n", __FUNCTION__));
                                return -1;
@@ -2042,6 +2612,8 @@ int
 wl_ext_iapsta_alive_preinit(struct net_device *dev)
 {
        struct wl_apsta_params *apsta_params = &g_apsta_params;
+       struct wl_if_info *cur_if;
+       int i;
 
        if (apsta_params->init == TRUE) {
                ANDROID_ERROR(("%s: don't init twice\n", __FUNCTION__));
@@ -2050,21 +2622,35 @@ wl_ext_iapsta_alive_preinit(struct net_device *dev)
 
        ANDROID_TRACE(("%s: Enter\n", __FUNCTION__));
 
-       strcpy(apsta_params->if_info[IF_PIF].ssid, "tttp");
-       apsta_params->if_info[IF_PIF].maxassoc = -1;
-       apsta_params->if_info[IF_PIF].channel = 1;
-
-       if (!strlen(apsta_params->if_info[IF_VIF].ifname))
-               strcpy(apsta_params->if_info[IF_VIF].ifname, "wlan1");
-       strcpy(apsta_params->if_info[IF_VIF].ssid, "tttv");
-       apsta_params->if_info[IF_VIF].maxassoc = -1;
-       apsta_params->if_info[IF_VIF].channel = 1;
-
-       if (!strlen(apsta_params->if_info[IF_VIF2].ifname))
-               strcpy(apsta_params->if_info[IF_VIF2].ifname, "wlan2");
-       strcpy(apsta_params->if_info[IF_VIF2].ssid, "tttv2");
-       apsta_params->if_info[IF_VIF2].maxassoc = -1;
-       apsta_params->if_info[IF_VIF2].channel = 161;
+       for (i=0; i<MAX_IF_NUM; i++) {
+               cur_if = &apsta_params->if_info[i];
+               if (i == 1 && !strlen(cur_if->ifname))
+                       strcpy(cur_if->ifname, "wlan1");
+               if (i == 2 && !strlen(cur_if->ifname))
+                       strcpy(cur_if->ifname, "wlan2");
+               if (cur_if->ifmode == ISTA_MODE) {
+                       cur_if->channel = 0;
+                       cur_if->maxassoc = -1;
+                       cur_if->ifstate = IF_STATE_INIT;
+                       cur_if->prio = PRIO_STA;
+                       cur_if->prefix = 'S';
+                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
+               } else if (cur_if->ifmode == IAP_MODE) {
+                       cur_if->channel = 1;
+                       cur_if->maxassoc = -1;
+                       cur_if->ifstate = IF_STATE_INIT;
+                       cur_if->prio = PRIO_AP;
+                       cur_if->prefix = 'A';
+                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
+               } else if (cur_if->ifmode == IMESH_MODE) {
+                       cur_if->channel = 1;
+                       cur_if->maxassoc = -1;
+                       cur_if->ifstate = IF_STATE_INIT;
+                       cur_if->prio = PRIO_MESH;
+                       cur_if->prefix = 'M';
+                       snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
+               }
+       }
 
        apsta_params->init = TRUE;
 
@@ -2095,6 +2681,7 @@ wl_ext_iapsta_alive_postinit(struct net_device *dev)
        return op_mode;
 }
 
+#if defined(WL_WIRELESS_EXT)
 static bool
 wl_ext_conn_status_str(uint32 event_type,
        uint32 status, uint32 reason, char* stringBuf, uint buflen)
@@ -2136,17 +2723,17 @@ wl_ext_conn_status_str(uint32 event_type,
 
        return FALSE;
 }
+#endif /* WL_WIRELESS_EXT */
 
 int
 wl_ext_iapsta_event(struct net_device *dev, wl_event_msg_t *e, void* data)
 {
        struct wl_apsta_params *apsta_params = &g_apsta_params;
        struct wl_if_info *cur_if = NULL;
-       char extra[IW_CUSTOM_MAX + 1];
        int i;
 #if defined(WL_WIRELESS_EXT)
+       char extra[IW_CUSTOM_MAX + 1];
        union iwreq_data wrqu;
-       int cmd = 0;
 #endif
        uint32 event_type = ntoh32(e->event_type);
        uint32 status =  ntoh32(e->status);
@@ -2159,7 +2746,7 @@ wl_ext_iapsta_event(struct net_device *dev, wl_event_msg_t *e, void* data)
        }
 
        for (i=0; i<MAX_IF_NUM; i++) {
-               if (apsta_params->if_info[i].bssidx == e->ifidx) {
+               if (apsta_params->if_info[i].ifidx == e->ifidx) {
                        cur_if = &apsta_params->if_info[i];
                        break;
                }
@@ -2170,138 +2757,166 @@ wl_ext_iapsta_event(struct net_device *dev, wl_event_msg_t *e, void* data)
                return -1;
        }
 
-       memset(extra, 0, sizeof(extra));
-#if defined(WL_WIRELESS_EXT)
-       memset(&wrqu, 0, sizeof(wrqu));
-       memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
-       wrqu.addr.sa_family = ARPHRD_ETHER;
-#endif
-
        if (cur_if->ifmode == ISTA_MODE) {
-               switch (event_type) {
-                       case WLC_E_LINK:
-                               if (!(flags & WLC_EVENT_MSG_LINK)) {
-                                       printf("%s: %s Link Down with BSSID="MACSTR"\n", __FUNCTION__,
-                                               cur_if->ifname, MAC2STR((u8 *)&e->addr));
-                               } else {
-                                       printf("%s: %s Link UP with BSSID="MACSTR"\n", __FUNCTION__,
-                                               cur_if->ifname, MAC2STR((u8 *)&e->addr));
-                               }
-                               break;
-                       default:
-                               /* Cannot translate event */
-                               break;
+               if (event_type == WLC_E_LINK) {
+                       if (!(flags & WLC_EVENT_MSG_LINK)) {
+                               printf("%s: %s[%c] Link Down with %pM\n", __FUNCTION__,
+                                       cur_if->ifname, cur_if->prefix, &e->addr);
+                       } else {
+                               printf("%s: %s[%c] Link UP with %pM\n", __FUNCTION__,
+                                       cur_if->ifname, cur_if->prefix, &e->addr);
+                       }
                }
-       } else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
-               if (((event_type == WLC_E_ASSOC_IND) || (event_type == WLC_E_REASSOC_IND)) &&
-                       reason == DOT11_SC_SUCCESS) {
-                       printf("%s: %s connected device "MACDBG"\n", __FUNCTION__,
-                               cur_if->ifname, MAC2STRDBG(e->addr.octet));
+       }
+       else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
+               if ((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
+                               (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
+                               reason == WLC_E_REASON_INITIAL_ASSOC)) {
+                       printf("%s: %s[%c] Link up\n", __FUNCTION__,
+                               cur_if->ifname, cur_if->prefix);
+               } else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
+                               (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
+                               reason == WLC_E_REASON_DEAUTH)) {
+                       printf("%s: %s[%c] Link down\n", __FUNCTION__,
+                               cur_if->ifname, cur_if->prefix);
+               }
+               else if ((event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) &&
+                               reason == DOT11_SC_SUCCESS) {
+                       printf("%s: %s[%c] connected device %pM\n", __FUNCTION__,
+                               cur_if->ifname, cur_if->prefix, &e->addr);
                } else if (event_type == WLC_E_DISASSOC_IND) {
-                       printf("%s: %s disassociated device "MACDBG"\n", __FUNCTION__,
-                               cur_if->ifname, MAC2STRDBG(e->addr.octet));
-               } else if ((event_type == WLC_E_DEAUTH_IND) ||
-                       ((event_type == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED))) {
-                       printf("%s: %s deauthenticated device "MACDBG"\n", __FUNCTION__,
-                               cur_if->ifname, MAC2STRDBG(e->addr.octet));
-               } else {
-                       ANDROID_TRACE(("%s: %s event %d "MACDBG"\n", __FUNCTION__,
-                               cur_if->ifname, event_type, MAC2STRDBG(e->addr.octet)));
+                       printf("%s: %s[%c] disassociated device %pM\n", __FUNCTION__,
+                               cur_if->ifname, cur_if->prefix, &e->addr);
+               } else if (event_type == WLC_E_DEAUTH_IND ||
+                               (event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
+                       printf("%s: %s[%c] deauthenticated device %pM\n", __FUNCTION__,
+                               cur_if->ifname, cur_if->prefix, &e->addr);
                }
        }
 
-       if (wl_ext_conn_status_str(event_type, status, reason, extra, sizeof(extra))) {
 #if defined(WL_WIRELESS_EXT)
-               cmd = IWEVCUSTOM;
+       memset(extra, 0, sizeof(extra));
+       memset(&wrqu, 0, sizeof(wrqu));
+       memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
+       wrqu.addr.sa_family = ARPHRD_ETHER;
+       if (wl_ext_conn_status_str(event_type, status, reason, extra, sizeof(extra))) {
                wrqu.data.length = strlen(extra);
-               wireless_send_event(cur_if->dev, cmd, &wrqu, extra);
+               wireless_send_event(cur_if->dev, IWEVCUSTOM, &wrqu, extra);
+               ANDROID_INFO(("%s: %s[%c] event=%d, status=%d, reason=%d, flags=%d sent up\n",
+                       __FUNCTION__, cur_if->ifname, cur_if->prefix, event_type, status,
+                       reason, flags));
+       } else
 #endif /* WL_WIRELESS_EXT */
-               ANDROID_TRACE(("%s: %s event=%d, status=%d, reason=%d sent up\n", __FUNCTION__,
-                       cur_if->ifname, event_type, status, reason));
-       } else {
-               ANDROID_TRACE(("%s: %s event=%d, status=%d, reason=%d\n", __FUNCTION__,
-                       cur_if->ifname, event_type, status, reason));
+       {
+               ANDROID_INFO(("%s: %s[%c] event=%d, status=%d, reason=%d, flags=%d\n",
+                       __FUNCTION__, cur_if->ifname, cur_if->prefix, event_type, status,
+                       reason, flags));
        }
 
        return 0;
 }
 
-void
-wl_ext_iapsta_disconnect_sta(struct net_device *dev, u32 channel)
+u32
+wl_ext_iapsta_update_channel(struct net_device *dev, u32 channel)
 {
        struct wl_apsta_params *apsta_params = &g_apsta_params;
-       struct wl_if_info *cur_if = NULL;
+       struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
        int i;
 
        for (i=0; i<MAX_IF_NUM; i++) {
-               if (apsta_params->if_info[i].dev == dev) {
-                       cur_if = &apsta_params->if_info[i];
-                       cur_if->channel = channel;
-                       wl_ext_iapsta_change_other_iface_channel(apsta_params->if_info[IF_PIF].dev, cur_if);
+               tmp_if = &apsta_params->if_info[i];
+               if (tmp_if->dev && tmp_if->dev == dev) {
+                       cur_if = tmp_if;
+                       break;
                }
        }
 
+       if (cur_if) {
+               wl_ext_isam_status(cur_if->dev);
+               cur_if->channel = channel;
+               channel = wl_ext_move_cur_channel(apsta_params->if_info[IF_PIF].dev, cur_if);
+               if (channel)
+                       wl_ext_move_other_channel(apsta_params->if_info[IF_PIF].dev, cur_if);
+       }
+
+       return channel;
 }
 
 int
-wl_ext_iapsta_attach_name(struct net_device *net, uint8 bssidx)
+wl_ext_iapsta_attach_name(struct net_device *net, int ifidx)
 {
        struct wl_apsta_params *apsta_params = &g_apsta_params;
+       struct dhd_pub *dhd;
+       struct wl_if_info *cur_if = NULL;
 
-       ANDROID_TRACE(("%s: bssidx=%d, %s\n", __FUNCTION__, bssidx, net->name));
-       if (bssidx == 1 && apsta_params->if_info[IF_VIF].ifstate == IF_STATE_INIT) {
-               strcpy(apsta_params->if_info[IF_VIF].ifname, net->name);
-       } else if (bssidx == 2 && apsta_params->if_info[IF_VIF2].ifstate == IF_STATE_INIT) {
-               strcpy(apsta_params->if_info[IF_VIF2].ifname, net->name);
+       dhd = dhd_get_pub(net);
+
+       ANDROID_TRACE(("%s: ifidx=%d, %s\n", __FUNCTION__, ifidx, net->name));
+       if (ifidx < MAX_IF_NUM) {
+               cur_if = &apsta_params->if_info[ifidx];
+       }
+       if (ifidx == 0) {
+               if (dhd->conf->fw_type == FW_TYPE_MESH) {
+                       apsta_params->rsdb = TRUE;
+                       apsta_params->csa = CSA_FW_BIT | CSA_DRV_BIT;
+               }
+               strcpy(cur_if->ifname, net->name);
+       } else if (cur_if && cur_if->ifstate == IF_STATE_INIT) {
+               strcpy(cur_if->ifname, net->name);
+               apsta_params->netif_change = TRUE;
+               wake_up_interruptible(&apsta_params->netif_change_event);
        }
 
        return 0;
 }
 
 int
-wl_ext_iapsta_attach_netdev(struct net_device *net, uint8 bssidx)
+wl_ext_iapsta_attach_netdev(struct net_device *net, int ifidx, uint8 bssidx)
 {
        struct wl_apsta_params *apsta_params = &g_apsta_params;
+       struct dhd_pub *dhd;
+       struct wl_if_info *cur_if = NULL, *primary_if;
 
-       printf("%s: bssidx=%d\n", __FUNCTION__, bssidx);
-       if (bssidx == 0) {
+       dhd = dhd_get_pub(net);
+
+       printf("%s: ifidx=%d, bssidx=%d\n", __FUNCTION__, ifidx, bssidx);
+       if (ifidx < MAX_IF_NUM) {
+               cur_if = &apsta_params->if_info[ifidx];
+       }
+       if (ifidx == 0) {
                memset(apsta_params, 0, sizeof(struct wl_apsta_params));
                apsta_params->vsdb = FALSE;
-               apsta_params->if_info[IF_PIF].dev = net;
-               apsta_params->if_info[IF_PIF].bssidx = bssidx;
-               strcpy(apsta_params->if_info[IF_PIF].ifname, net->name);
+               cur_if->dev = net;
+               cur_if->ifidx = ifidx;
+               cur_if->bssidx = bssidx;
+               strcpy(cur_if->ifname, net->name);
                init_waitqueue_head(&apsta_params->netif_change_event);
-       } else if (bssidx == 1 && apsta_params->if_info[IF_VIF].ifstate == IF_STATE_INIT) {
-               apsta_params->if_info[IF_VIF].dev = net;
-               apsta_params->if_info[IF_VIF].bssidx = bssidx;
-               if (strlen(apsta_params->if_info[IF_VIF].ifname)) {
+       } else if (cur_if && cur_if->ifstate == IF_STATE_INIT) {
+               primary_if = &apsta_params->if_info[IF_PIF];
+               cur_if->dev = net;
+               cur_if->ifidx = ifidx;
+               cur_if->bssidx = bssidx;
+               if (strlen(cur_if->ifname)) {
                        memset(net->name, 0, sizeof(IFNAMSIZ));
-                       strcpy(net->name, apsta_params->if_info[IF_VIF].ifname);
+                       strcpy(net->name, cur_if->ifname);
                        net->name[IFNAMSIZ-1] = '\0';
                }
-               if (apsta_params->if_info[IF_PIF].dev) {
-                       memcpy(net->dev_addr, apsta_params->if_info[IF_PIF].dev->dev_addr, ETHER_ADDR_LEN);
+               if (apsta_params->apstamode != ISTAAPAP_MODE) {
+                       memcpy(net->dev_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN);
                        net->dev_addr[0] |= 0x02;
+                       if (ifidx >= 2) {
+                               net->dev_addr[4] ^= 0x80;
+                               net->dev_addr[4] += ifidx;
+                               net->dev_addr[5] += (ifidx-1);
+                       }
                }
-               apsta_params->netif_change = TRUE;
-               wake_up_interruptible(&apsta_params->netif_change_event);
-       } else if (bssidx == 2 && apsta_params->if_info[IF_VIF2].ifstate == IF_STATE_INIT) {
-               apsta_params->if_info[IF_VIF2].dev = net;
-               apsta_params->if_info[IF_VIF2].bssidx = bssidx;
-               if (strlen(apsta_params->if_info[IF_VIF2].ifname)) {
-                       memset(net->name, 0, sizeof(IFNAMSIZ));
-                       strcpy(net->name, apsta_params->if_info[IF_VIF2].ifname);
-                       net->name[IFNAMSIZ-1] = '\0';
-               }
-               if (apsta_params->if_info[IF_PIF].dev) {
-                       memcpy(net->dev_addr, apsta_params->if_info[IF_PIF].dev->dev_addr, ETHER_ADDR_LEN);
-                       net->dev_addr[0] |= 0x02;
-                       net->dev_addr[4] ^= 0x80;
-                       net->dev_addr[4] += bssidx;
-                       net->dev_addr[5] += bssidx;
+               if (cur_if->ifmode == ISTA_MODE) {
+                       wl_ext_iovar_setint(net, "roam_off", dhd->conf->roam_off);
+                       wl_ext_iovar_setint(net, "bcn_timeout", dhd->conf->bcn_timeout);
+               } else if (cur_if->ifmode == IMESH_MODE) {
+                       int pm = 0;
+                       wl_ext_ioctl(net, WLC_SET_PM, &pm, sizeof(pm), 1);
                }
-               apsta_params->netif_change = TRUE;
-               wake_up_interruptible(&apsta_params->netif_change_event);
        }
 
        return 0;
@@ -2367,7 +2982,6 @@ wl_ext_dhcpc_enable(struct net_device *dev, char *command, int total_len)
 int
 wl_ext_dhcpc_dump(struct net_device *dev, char *command, int total_len)
 {
-
        int ret = 0;
        int bytes_written = 0;
        uint32 ip_addr;
@@ -2469,8 +3083,8 @@ wl_ext_iovar(struct net_device *dev, char *command, int total_len)
        return ret;
 }
 
-int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len,
-               int *bytes_written)
+int wl_android_ext_priv_cmd(struct net_device *net, char *command,
+       int total_len, int *bytes_written)
 {
        int ret = 0;
 
@@ -2522,6 +3136,9 @@ int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len
        else if (strnicmp(command, CMD_ISAM_DISABLE, strlen(CMD_ISAM_DISABLE)) == 0) {
                *bytes_written = wl_ext_iapsta_disable(net, command, total_len);
        }
+       else if (strnicmp(command, CMD_ISAM_STATUS, strlen(CMD_ISAM_STATUS)) == 0) {
+               *bytes_written = wl_ext_isam_status(net);
+       }
 #endif
 #ifdef IDHCP
        else if (strnicmp(command, CMD_DHCPC_ENABLE, strlen(CMD_DHCPC_ENABLE)) == 0) {
@@ -2530,6 +3147,16 @@ int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len
        else if (strnicmp(command, CMD_DHCPC_DUMP, strlen(CMD_DHCPC_DUMP)) == 0) {
                *bytes_written = wl_ext_dhcpc_dump(net, command, total_len);
        }
+#endif
+#ifdef WL_CFG80211
+       else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) {
+               *bytes_written = wl_cfg80211_autochannel(net, command, total_len);
+       }
+#endif
+#ifdef WL_ESCAN
+       else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) {
+               *bytes_written = wl_escan_autochannel(net, command, total_len);
+       }
 #endif
        else if (strnicmp(command, CMD_WL, strlen(CMD_WL)) == 0) {
                *bytes_written = wl_ext_iovar(net, command, total_len);
@@ -2540,6 +3167,198 @@ int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len
        return ret;
 }
 
+#if defined(WL_CFG80211) || defined(WL_ESCAN)
+int
+wl_ext_get_distance(struct net_device *net, u32 band)
+{
+       u32 bw = WL_CHANSPEC_BW_20;
+       s32 bw_cap = 0, distance = 0;
+       struct {
+               u32 band;
+               u32 bw_cap;
+       } param = {0, 0};
+       char buf[WLC_IOCTL_SMLEN]="\0";
+       s32 err = BCME_OK;
+
+       param.band = band;
+       err = wldev_iovar_getbuf(net, "bw_cap", &param, sizeof(param), buf,
+               sizeof(buf), NULL);
+       if (err) {
+               if (err != BCME_UNSUPPORTED) {
+                       ANDROID_ERROR(("bw_cap failed, %d\n", err));
+                       return err;
+               } else {
+                       err = wl_ext_iovar_getint(net, "mimo_bw_cap", &bw_cap);
+                       if (err) {
+                               ANDROID_ERROR(("error get mimo_bw_cap (%d)\n", err));
+                       }
+                       if (bw_cap != WLC_N_BW_20ALL)
+                               bw = WL_CHANSPEC_BW_40;
+               }
+       } else {
+               if (WL_BW_CAP_80MHZ(buf[0]))
+                       bw = WL_CHANSPEC_BW_80;
+               else if (WL_BW_CAP_40MHZ(buf[0]))
+                       bw = WL_CHANSPEC_BW_40;
+               else
+                       bw = WL_CHANSPEC_BW_20;
+       }
+
+       if (bw == WL_CHANSPEC_BW_20)
+               distance = 2;
+       else if (bw == WL_CHANSPEC_BW_40)
+               distance = 4;
+       else if (bw == WL_CHANSPEC_BW_80)
+               distance = 8;
+       else
+               distance = 16;
+       ANDROID_INFO(("%s: bw=0x%x, distance=%d\n", __FUNCTION__, bw, distance));
+
+       return distance;
+}
+
+int
+wl_ext_get_best_channel(struct net_device *net,
+#if defined(BSSCACHE)
+       wl_bss_cache_ctrl_t *bss_cache_ctrl,
+#else
+       struct wl_scan_results *bss_list,
+#endif
+       int ioctl_ver, int *best_2g_ch, int *best_5g_ch
+)
+{
+       struct wl_bss_info *bi = NULL;  /* must be initialized */
+       s32 i, j;
+#if defined(BSSCACHE)
+       wl_bss_cache_t *node;
+#endif
+       int b_band[CH_MAX_2G_CHANNEL]={0}, a_band1[4]={0}, a_band4[5]={0};
+       s32 cen_ch, distance, distance_2g, distance_5g, ch, min_ap=999;
+       u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
+       wl_uint32_list_t *list;
+       int ret;
+       chanspec_t chanspec;
+
+       memset(b_band, -1, sizeof(b_band));
+       memset(a_band1, -1, sizeof(a_band1));
+       memset(a_band4, -1, sizeof(a_band4));
+
+       memset(valid_chan_list, 0, sizeof(valid_chan_list));
+       list = (wl_uint32_list_t *)(void *) valid_chan_list;
+       list->count = htod32(WL_NUMCHANNELS);
+       ret = wldev_ioctl(net, WLC_GET_VALID_CHANNELS, valid_chan_list,
+               sizeof(valid_chan_list), 0);
+       if (ret<0) {
+               ANDROID_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, ret));
+               return 0;
+       } else {
+               for (i = 0; i < dtoh32(list->count); i++) {
+                       ch = dtoh32(list->element[i]);
+                       if (ch < CH_MAX_2G_CHANNEL)
+                               b_band[ch-1] = 0;
+                       else if (ch <= 48)
+                               a_band1[(ch-36)/4] = 0;
+                       else if (ch >= 149 && ch <= 161)
+                               a_band4[(ch-149)/4] = 0;
+               }
+       }
+
+       distance_2g = wl_ext_get_distance(net, WLC_BAND_2G);
+       distance_5g = wl_ext_get_distance(net, WLC_BAND_5G);
+
+#if defined(BSSCACHE)
+       node = bss_cache_ctrl->m_cache_head;
+       for (i=0; node && i<256; i++)
+#else
+       for (i=0; i < bss_list->count; i++)
+#endif
+       {
+#if defined(BSSCACHE)
+               bi = node->results.bss_info;
+#else
+               bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info;
+#endif
+               chanspec = wl_ext_chspec_driver_to_host(ioctl_ver, bi->chanspec);
+               cen_ch = CHSPEC_CHANNEL(bi->chanspec);
+               distance = 0;
+               if (CHSPEC_IS20(chanspec))
+                       distance += 2;
+               else if (CHSPEC_IS40(chanspec))
+                       distance += 4;
+               else if (CHSPEC_IS80(chanspec))
+                       distance += 8;
+               else
+                       distance += 16;
+
+               if (CHSPEC_IS2G(chanspec)) {
+                       distance += distance_2g;
+                       for (j=0; j<ARRAYSIZE(b_band); j++) {
+                               if (b_band[j] >= 0 && abs(cen_ch-(1+j)) <= distance)
+                               b_band[j] += 1;
+                       }
+               } else {
+                       distance += distance_5g;
+                       if (cen_ch <= 48) {
+                               for (j=0; j<ARRAYSIZE(a_band1); j++) {
+                                       if (a_band1[j] >= 0 && abs(cen_ch-(36+j*4)) <= distance)
+                                               a_band1[j] += 1;
+                               }
+                       } else if (cen_ch >= 149) {
+                               for (j=0; j<ARRAYSIZE(a_band4); j++) {
+                                       if (a_band4[j] >= 0 && abs(cen_ch-(149+j*4)) <= distance)
+                                               a_band4[j] += 1;
+                               }
+                       }
+               }
+#if defined(BSSCACHE)
+               node = node->next;
+#endif
+       }
+
+       *best_2g_ch = 0;
+       min_ap = 999;
+       for (i=0; i<CH_MAX_2G_CHANNEL; i++) {
+               if(b_band[i] < min_ap && b_band[i] >= 0) {
+                       min_ap = b_band[i];
+                       *best_2g_ch = i+1;
+               }
+       }
+       *best_5g_ch = 0;
+       min_ap = 999;
+       for (i=0; i<ARRAYSIZE(a_band1); i++) {
+               if(a_band1[i] < min_ap && a_band1[i] >= 0) {
+                       min_ap = a_band1[i];
+                       *best_5g_ch = i*4 + 36;
+               }
+       }
+       for (i=0; i<ARRAYSIZE(a_band4); i++) {
+               if(a_band4[i] < min_ap && a_band4[i] >= 0) {
+                       min_ap = a_band4[i];
+                       *best_5g_ch = i*4 + 149;
+               }
+       }
+
+       if (android_msg_level&ANDROID_INFO_LEVEL) {
+               printf("%s: b_band: ", __FUNCTION__);
+               for (j=0; j<ARRAYSIZE(b_band); j++)
+                       printf("%d, ", b_band[j]);
+               printf("\n");
+               printf("%s: a_band1: ", __FUNCTION__);
+               for (j=0; j<ARRAYSIZE(a_band1); j++)
+                       printf("%d, ", a_band1[j]);
+               printf("\n");
+               printf("%s: a_band4: ", __FUNCTION__);
+               for (j=0; j<ARRAYSIZE(a_band4); j++)
+                       printf("%d, ", a_band4[j]);
+               printf("\n");
+               printf("%s: best_2g_ch=%d, best_5g_ch=%d\n", __FUNCTION__,
+                       *best_2g_ch, *best_5g_ch);
+       }
+
+       return 0;
+}
+#endif
+
 #if defined(RSSIAVG)
 void
 wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
@@ -2600,7 +3419,8 @@ wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
 }
 
 void
-wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, u8 *bssid)
+wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
+       u8 *bssid)
 {
        wl_rssi_cache_t *node, *prev, **rssi_head;
        int i = -1, tmp = 0;
@@ -2650,13 +3470,15 @@ wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
 }
 
 int
-wl_update_connected_rssi_cache(struct net_device *net, wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg)
+wl_update_connected_rssi_cache(struct net_device *net,
+       wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg)
 {
        wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
        int j, k=0;
        int rssi, error=0;
        struct ether_addr bssid;
        struct timeval now, timeout;
+       scb_val_t scbval;
 
        if (!g_wifi_on)
                return 0;
@@ -2669,11 +3491,12 @@ wl_update_connected_rssi_cache(struct net_device *net, wl_rssi_cache_ctrl_t *rss
        if (error) {
                ANDROID_ERROR(("Could not get bssid (%d)\n", error));
        }
-       error = wldev_get_rssi(net, &rssi);
+       error = wldev_get_rssi(net, &scbval);
        if (error) {
                ANDROID_ERROR(("Could not get rssi (%d)\n", error));
                return error;
        }
+       rssi = scbval.val;
 
        do_gettimeofday(&now);
        timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
@@ -2734,7 +3557,8 @@ exit:
 }
 
 void
-wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list)
+wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
+       wl_scan_results_t *ss_list)
 {
        wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
        wl_bss_info_t *bi = NULL;
@@ -2921,7 +3745,8 @@ wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
 }
 
 void
-wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, u8 *bssid)
+wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
+       u8 *bssid)
 {
        wl_bss_cache_t *node, *prev, **bss_head;
        int i = -1, tmp = 0;
@@ -2987,7 +3812,8 @@ void dump_bss_cache(
                rssi = dtoh16(node->results.bss_info->RSSI);
 #endif
                ANDROID_TRACE(("%s: dump %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
-                       __FUNCTION__, k, &node->results.bss_info->BSSID, rssi, node->results.bss_info->SSID));
+                       __FUNCTION__, k, &node->results.bss_info->BSSID, rssi,
+                       node->results.bss_info->SSID));
                k++;
                node = node->next;
        }
@@ -3077,7 +3903,8 @@ wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
 #endif
                        for (;node;) {
 #if defined(RSSIAVG)
-                               rssi_node = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID);
+                               rssi_node = wl_get_avg_rssi(rssi_cache_ctrl,
+                                       &node->results.bss_info->BSSID);
 #else
                                rssi_node = dtoh16(node->results.bss_info->RSSI);
 #endif