wifi: dhd load fw change to request firmware [2/3]
authorjiabin.chen <jiabin.chen@amlogic.com>
Sun, 11 Sep 2022 03:26:33 +0000 (11:26 +0800)
committerBruno Martins <bgcngm@gmail.com>
Thu, 25 Apr 2024 09:21:58 +0000 (10:21 +0100)
PD#SWPL-95664

Problem:
dhd 515 driver is not ok

Solution:
update driver and change request firmware

Verify:
t7

Change-Id: I05f7a7856e4b0832ebcc6bff0b4523eb49d124e1
Signed-off-by: jiabin.chen <jiabin.chen@amlogic.com>
75 files changed:
bcmdhd.101.10.361.x/Makefile
bcmdhd.101.10.361.x/bcmbloom.c
bcmdhd.101.10.361.x/bcmevent.c
bcmdhd.101.10.361.x/bcmsdh_linux.c
bcmdhd.101.10.361.x/bcmsdh_sdmmc.c
bcmdhd.101.10.361.x/bcmsdh_sdmmc_linux.c
bcmdhd.101.10.361.x/bcmutils.c
bcmdhd.101.10.361.x/bcmxtlv.c
bcmdhd.101.10.361.x/dbus.c
bcmdhd.101.10.361.x/dbus_usb.c
bcmdhd.101.10.361.x/dbus_usb_linux.c
bcmdhd.101.10.361.x/dhd.h
bcmdhd.101.10.361.x/dhd_bus.h
bcmdhd.101.10.361.x/dhd_ccode.c
bcmdhd.101.10.361.x/dhd_cdc.c
bcmdhd.101.10.361.x/dhd_common.c
bcmdhd.101.10.361.x/dhd_config.c
bcmdhd.101.10.361.x/dhd_config.h
bcmdhd.101.10.361.x/dhd_flowring.c
bcmdhd.101.10.361.x/dhd_flowring.h
bcmdhd.101.10.361.x/dhd_fwtrace.c
bcmdhd.101.10.361.x/dhd_gpio.c
bcmdhd.101.10.361.x/dhd_linux.c
bcmdhd.101.10.361.x/dhd_linux.h
bcmdhd.101.10.361.x/dhd_linux_exportfs.c
bcmdhd.101.10.361.x/dhd_linux_pktdump.c
bcmdhd.101.10.361.x/dhd_linux_pktdump.h
bcmdhd.101.10.361.x/dhd_linux_platdev.c
bcmdhd.101.10.361.x/dhd_macdbg.c
bcmdhd.101.10.361.x/dhd_msgbuf.c
bcmdhd.101.10.361.x/dhd_pcie.c
bcmdhd.101.10.361.x/dhd_pcie_linux.c
bcmdhd.101.10.361.x/dhd_pktlog.c
bcmdhd.101.10.361.x/dhd_plat.h
bcmdhd.101.10.361.x/dhd_proto.h
bcmdhd.101.10.361.x/dhd_sdio.c
bcmdhd.101.10.361.x/dhd_static_buf.c
bcmdhd.101.10.361.x/dhd_wlfc.c
bcmdhd.101.10.361.x/include/bcmdefs.h
bcmdhd.101.10.361.x/include/bcmevent.h
bcmdhd.101.10.361.x/include/bcmsdh.h
bcmdhd.101.10.361.x/include/bcmsdh_sdmmc.h
bcmdhd.101.10.361.x/include/bcmwifi_channels.h
bcmdhd.101.10.361.x/include/dbus.h
bcmdhd.101.10.361.x/include/epivers.h
bcmdhd.101.10.361.x/include/linux_osl.h
bcmdhd.101.10.361.x/include/linuxver.h
bcmdhd.101.10.361.x/include/wlioctl.h
bcmdhd.101.10.361.x/linux_osl.c
bcmdhd.101.10.361.x/wl_android.c
bcmdhd.101.10.361.x/wl_android.h
bcmdhd.101.10.361.x/wl_android_ext.c
bcmdhd.101.10.361.x/wl_android_ext.h
bcmdhd.101.10.361.x/wl_bam.c
bcmdhd.101.10.361.x/wl_cfg80211.c
bcmdhd.101.10.361.x/wl_cfg80211.h
bcmdhd.101.10.361.x/wl_cfgnan.h
bcmdhd.101.10.361.x/wl_cfgp2p.c
bcmdhd.101.10.361.x/wl_cfgp2p.h
bcmdhd.101.10.361.x/wl_cfgscan.c
bcmdhd.101.10.361.x/wl_cfgscan.h
bcmdhd.101.10.361.x/wl_cfgvendor.c
bcmdhd.101.10.361.x/wl_cfgvendor.h
bcmdhd.101.10.361.x/wl_cfgvif.c
bcmdhd.101.10.361.x/wl_cfgvif.h
bcmdhd.101.10.361.x/wl_escan.c
bcmdhd.101.10.361.x/wl_escan.h
bcmdhd.101.10.361.x/wl_event.c
bcmdhd.101.10.361.x/wl_iapsta.c
bcmdhd.101.10.361.x/wl_iapsta.h
bcmdhd.101.10.361.x/wl_iw.c
bcmdhd.101.10.361.x/wl_roam.c
bcmdhd.101.10.361.x/wl_timer.c [new file with mode: 0755]
bcmdhd.101.10.361.x/wl_timer.h [new file with mode: 0755]
bcmdhd.101.10.361.x/wldev_common.c

index 2884d7fa8c5f6f618dbedb79c67b0dd315ed5be8..92f46e6af303e0ab4376f5367b85acb5d1c7cd0c 100755 (executable)
@@ -32,12 +32,17 @@ CONFIG_DHD_USE_STATIC_BUF := y
 #CONFIG_BCMDHD_STATIC_BUF_IN_DHD := y
 CONFIG_BCMDHD_AUTO_SELECT := y
 CONFIG_BCMDHD_DEBUG := y
+#CONFIG_BCMDHD_RECONNECT := y
 #CONFIG_BCMDHD_TIMESTAMP := y
 #CONFIG_BCMDHD_WAPI := y
 #CONFIG_BCMDHD_RANDOM_MAC := y
-#CONFIG_BCMDHD_MULTIPLE_DRIVER := y
+CONFIG_BCMDHD_REQUEST_FW := y
+#CONFIG_BCMDHD_DWDS := y
 CONFIG_BCMDHD_TPUT := y
 
+#CONFIG_BCMDHD_MULTIPLE_DRIVER := y
+#CONFIG_BCMDHD_ADAPTER_INDEX := 0
+
 CONFIG_MACH_PLATFORM := y
 #CONFIG_BCMDHD_DTS := y
 
@@ -47,30 +52,33 @@ endif
 
 DHDCFLAGS = -Wall -Wstrict-prototypes -Wno-date-time                      \
        -Dlinux -DLINUX -DBCMDRIVER                                           \
-       -Wno-unknown-warning-option -Wno-unused-but-set-variable              \
-       -Wno-uninitialized -Wno-error -Wno-format-security                    \
-       -Wno-implicit-fallthrough                                             \
+       -Wno-unused-but-set-variable                                          \
+       -Wno-maybe-uninitialized -Wno-error -Wno-format-security                 \
+       -Wno-unknown-warning-option -Wno-sometimes-uninitialized              \
+       -Wno-parentheses-equality -Wno-implicit-fallthrough                   \
        -DBCMDONGLEHOST -DBCMDMA32 -DBCMFILEIMAGE                             \
        -DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DGET_OTP_MAC_ENABLE            \
        -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY             \
+       -DPKTPRIO_OVERRIDE                                                    \
        -DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DDHDTCPACK_SUPPRESS                \
        -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DOEM_ANDROID             \
        -DMULTIPLE_SUPPLICANT -DTSQ_MULTIPLIER -DMFP -DDHD_8021X_DUMP         \
        -DPOWERUP_MAX_RETRY=1 -DIFACE_HANG_FORCE_DEV_CLOSE -DWAIT_DEQUEUE     \
        -DUSE_NEW_RSPEC_DEFS                                                  \
        -DWL_EXT_IAPSTA -DWL_ESCAN -DCCODE_LIST -DSUSPEND_EVENT               \
-       -DEAPOL_RESEND -DEAPOL_DYNAMATIC_RESEND                               \
+       -DKEY_INSTALL_CHECK                                                   \
        -DENABLE_INSMOD_NO_FW_LOAD
 
-DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o   \
+DHDOFILES = aiutils.o siutils.o sbutils.o                                 \
+       bcmutils.o bcmwifi_channels.o bcmxtlv.o bcm_app_utils.o bcmstdlib_s.o \
        dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o           \
        dhd_common.o dhd_ip.o dhd_linux_wq.o dhd_custom_gpio.o                \
        bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o           \
        dhd_debug_linux.o dhd_debug.o dhd_mschdbg.o dhd_dbg_ring.o            \
-       hnd_pktq.o hnd_pktpool.o bcmxtlv.o linux_pkt.o bcmstdlib_s.o frag.o   \
+       hnd_pktq.o hnd_pktpool.o linux_pkt.o frag.o                           \
        dhd_linux_exportfs.o dhd_linux_pktdump.o dhd_mschdbg.o                \
        dhd_config.o dhd_ccode.o wl_event.o wl_android_ext.o                  \
-       wl_iapsta.o wl_escan.o
+       wl_iapsta.o wl_escan.o wl_timer.o
 
 ifneq ($(CONFIG_WIRELESS_EXT),)
        DHDOFILES += wl_iw.o
@@ -79,7 +87,7 @@ endif
 ifneq ($(CONFIG_CFG80211),)
        DHDOFILES += wl_cfg80211.o wl_cfgscan.o wl_cfgp2p.o
        DHDOFILES += wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o
-       DHDOFILES += dhd_cfg80211.o wl_cfgvif.o
+       DHDOFILES += dhd_cfg80211.o wl_cfgvif.o wl_roam.o
        DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT
        DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
        DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10
@@ -88,27 +96,27 @@ ifneq ($(CONFIG_CFG80211),)
        DHDCFLAGS += -DESCAN_RESULT_PATCH -DESCAN_BUF_OVERFLOW_MGMT
        DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
        DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8
-       DHDCFLAGS += -DWL_VIRTUAL_APSTA
+       DHDCFLAGS += -DWL_VIRTUAL_APSTA -DSTA_MGMT
        DHDCFLAGS += -DPNO_SUPPORT -DEXPLICIT_DISCIF_CLEANUP
        DHDCFLAGS += -DDHD_USE_SCAN_WAKELOCK
        DHDCFLAGS += -DSPECIFIC_MAC_GEN_SCHEME
        DHDCFLAGS += -DWL_IFACE_MGMT
-       DHDCFLAGS += -DWLFBT
-       DHDCFLAGS += -DWL_EXT_RECONNECT
-       DHDCFLAGS += -DDHD_LOSSLESS_ROAMING
+       DHDCFLAGS += -DWLFBT -DWL_GCMP_SUPPORT
+       DHDCFLAGS += -DROAM_CHANNEL_CACHE -DDHD_LOSSLESS_ROAMING -DWL_ROAM_WAR
        DHDCFLAGS += -DGTK_OFFLOAD_SUPPORT
+       DHDCFLAGS += -DRESTART_AP_WAR
        DHDCFLAGS += -DWL_STATIC_IF
        DHDCFLAGS += -DWL_CLIENT_SAE -DWL_OWE
 endif
 
 #BCMDHD_SDIO
 ifneq ($(CONFIG_BCMDHD_SDIO),)
-BUS_TYPE := "sdio"
+BUS_TYPE := sdio
 DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DMMC_SW_RESET -DBCMLXSDMMC       \
        -DUSE_SDIOFIFO_IOVAR -DSDTEST                                         \
        -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256                \
-       -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DRXFRAME_THREAD              \
-       -DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS                               \
+       -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DBCMSDIOH_STATIC_COPY_BUF    \
+       -DRXFRAME_THREAD -DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS              \
        -DBCMSDIO_RXLIM_POST -DBCMSDIO_TXSEQ_SYNC -DCONSOLE_DPC               \
        -DBCMSDIO_INTSTATUS_WAR
 ifeq ($(CONFIG_BCMDHD_OOB),y)
@@ -125,7 +133,7 @@ endif
 
 #BCMDHD_PCIE
 ifneq ($(CONFIG_BCMDHD_PCIE),)
-BUS_TYPE := "pcie"
+BUS_TYPE := pcie
 DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1    \
        -DDONGLE_ENABLE_ISOLATION
 DHDCFLAGS += -DDHD_LB -DDHD_LB_RXP -DDHD_LB_STATS -DDHD_LB_TXP
@@ -149,10 +157,15 @@ endif
 
 #BCMDHD_USB
 ifneq ($(CONFIG_BCMDHD_USB),)
-BUS_TYPE := "usb"
+BUS_TYPE := usb
 DHDCFLAGS += -DUSBOS_TX_THREAD -DBCMDBUS -DBCMTRXV2 -DDBUS_USB_LOOPBACK   \
        -DBDC
-DHDCFLAGS += -DBCM_REQUEST_FW -DEXTERNAL_FW_PATH
+DHDCFLAGS += -DINSMOD_FW_LOAD
+DHDCFLAGS += -DBCM_REQUEST_FW
+DHDCFLAGS += -DSHOW_LOGTRACE
+ifneq ($(CONFIG_BCMDHD_REQUEST_FW),y)
+       DHDCFLAGS += -DEXTERNAL_FW_PATH
+endif
 CONFIG_BCMDHD_NO_POWER_OFF := y
 ifneq ($(CONFIG_BCMDHD_CUSB),)
        DHDCFLAGS += -DBCMUSBDEV_COMPOSITE
@@ -168,9 +181,17 @@ endif
 
 ifeq ($(CONFIG_BCMDHD_MULTIPLE_DRIVER),y)
        DHDCFLAGS += -DBCMDHD_MDRIVER
+ifneq ($(CONFIG_BCMDHD_ADAPTER_INDEX),)
+       CONFIG_BCMDHD_STATIC_BUF_IN_DHD := y
+       MODULE_NAME := dhd$(BUS_TYPE)_$(CONFIG_BCMDHD_ADAPTER_INDEX)
+       DHDCFLAGS += -DADAPTER_IDX=$(CONFIG_BCMDHD_ADAPTER_INDEX)
+       DHDCFLAGS += -DBUS_TYPE=\"-$(BUS_TYPE)-$(CONFIG_BCMDHD_ADAPTER_INDEX)\"
+       DHDCFLAGS += -DDHD_LOG_PREFIX=\"[dhd-$(BUS_TYPE)-$(CONFIG_BCMDHD_ADAPTER_INDEX)]\"
+else
+       MODULE_NAME := dhd$(BUS_TYPE)
        DHDCFLAGS += -DBUS_TYPE=\"-$(BUS_TYPE)\"
        DHDCFLAGS += -DDHD_LOG_PREFIX=\"[dhd-$(BUS_TYPE)]\"
-       MODULE_NAME := dhd$(BUS_TYPE)
+endif
 else
        DHDCFLAGS += -DBUS_TYPE=\"\"
 endif
@@ -202,14 +223,15 @@ endif
 ifneq ($(CONFIG_BCMDHD_ANDROID_VERSION),)
        DHDCFLAGS += -DANDROID_VERSION=$(CONFIG_BCMDHD_ANDROID_VERSION)
        DHDCFLAGS += -DDHD_NOTIFY_MAC_CHANGED
+       DHDCFLAGS += -DANDROID_BKPORT
 ifneq ($(CONFIG_CFG80211),)
        DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT -DLINKSTAT_SUPPORT
        DHDCFLAGS += -DCUSTOM_COUNTRY_CODE -DDHD_GET_VALID_CHANNELS
        DHDCFLAGS += -DDEBUGABILITY -DDBG_PKT_MON
        DHDCFLAGS += -DDHD_LOG_DUMP -DDHD_FW_COREDUMP
        DHDCFLAGS += -DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT
-       DHDCFLAGS += -DDHD_WAKE_STATUS
-       DHDOFILES += dhd_rtt.o bcm_app_utils.o
+       DHDCFLAGS += -DDHD_WAKE_STATUS -DWL_LATENCY_MODE
+       DHDOFILES += dhd_rtt.o
 endif
 else
        DHDCFLAGS += -DANDROID_VERSION=0
@@ -253,18 +275,40 @@ endif
        DHDCFLAGS :=$(filter-out -DWL_STATIC_IF,$(DHDCFLAGS))
 endif
 
+# EasyMesh
 ifeq ($(CONFIG_BCMDHD_EASYMESH),y)
        DHDCFLAGS :=$(filter-out -DDHD_FW_COREDUMP,$(DHDCFLAGS))
        DHDCFLAGS :=$(filter-out -DDHD_LOG_DUMP,$(DHDCFLAGS))
-       DHDCFLAGS += -DWLEASYMESH -DWL_STATIC_IF -DWLDWDS -DFOURADDR_AUTO_BRG
+       DHDCFLAGS += -DWLEASYMESH
+       CONFIG_BCMDHD_DWDS := y
 endif
 
-#CSI_SUPPORT
+# DWDS
+ifeq ($(CONFIG_BCMDHD_DWDS),y)
+ifneq ($(CONFIG_CFG80211),)
+       DHDCFLAGS += -DWLDWDS -DFOURADDR_AUTO_BRG
+ifneq ($(CONFIG_BCMDHD_SDIO),)
+       DHDCFLAGS += -DRXF_DEQUEUE_ON_BUSY
+endif
+       DHDCFLAGS += -DWL_STATIC_IF
+endif
+endif
+
+# CSI_SUPPORT
 ifeq ($(CONFIG_CSI_SUPPORT),y)
        DHDCFLAGS += -DCSI_SUPPORT
        DHDOFILES += dhd_csi.o
 endif
 
+# For CONNECTION_IMPROVE
+ifeq ($(CONFIG_BCMDHD_RECONNECT),y)
+       DHDCFLAGS += -DEAPOL_RESEND -DEAPOL_RESEND_M4
+ifneq ($(CONFIG_CFG80211),)
+       DHDCFLAGS += -DWL_EXT_RECONNECT -DWL_REASSOC_BCAST
+       DHDCFLAGS += -DWL_EXT_DISCONNECT_RECONNECT
+endif 
+endif
+
 # For TPUT_IMPROVE
 ifeq ($(CONFIG_BCMDHD_TPUT),y)
        DHDCFLAGS += -DDHD_TPUT_PATCH
@@ -289,6 +333,9 @@ endif
 # For WAPI
 ifeq ($(CONFIG_BCMDHD_WAPI),y)
        DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI
+ifeq ($(CONFIG_BCMDHD_ANDROID_VERSION),11)
+       DHDCFLAGS += -DCFG80211_WAPI_BKPORT
+endif
 endif
 
 # For scan random mac
@@ -307,6 +354,10 @@ endif
 # For Module auto-selection
 ifeq ($(CONFIG_BCMDHD_AUTO_SELECT),y)
        DHDCFLAGS += -DUPDATE_MODULE_NAME
+ifeq ($(CONFIG_BCMDHD_REQUEST_FW),y)
+#      DHDCFLAGS += -DFW_AMPAK_PATH="\"ampak\""
+       DHDCFLAGS += -DMODULE_PATH
+endif
 ifneq ($(CONFIG_BCMDHD_SDIO),)
        DHDCFLAGS += -DGET_OTP_MODULE_NAME -DCOMPAT_OLD_MODULE
 endif
@@ -331,6 +382,20 @@ endif
 #
 endif
 
+ifeq ($(CONFIG_BCMDHD_REQUEST_FW),y)
+       DHDCFLAGS += -DDHD_LINUX_STD_FW_API
+       DHDCFLAGS += -DDHD_FW_NAME="\"fw_bcmdhd.bin\""
+       DHDCFLAGS += -DDHD_NVRAM_NAME="\"nvram.txt\""
+       DHDCFLAGS += -DDHD_CLM_NAME="\"clm_bcmdhd.blob\""
+else
+       DHDCFLAGS += -DDHD_SUPPORT_VFS_CALL
+ifeq ($(CONFIG_BCMDHD_FW_PATH),)
+       DHDCFLAGS += -DCONFIG_BCMDHD_FW_PATH="\"/system/etc/firmware/fw_bcmdhd.bin\""
+       DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH="\"/system/etc/firmware/nvram.txt\""
+       DHDCFLAGS += -DCONFIG_BCMDHD_CLM_PATH="\"/system/etc/firmware/clm_bcmdhd.blob\""
+endif
+endif
+
 ifeq ($(CONFIG_BCMDHD_AG),y)
        DHDCFLAGS += -DBAND_AG
 endif
@@ -383,7 +448,6 @@ bcmdhd_sdio:
 bcmdhd_usb:
        $(warning "building BCMDHD_USB..........")
        $(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules CONFIG_BCMDHD_USB=y
-       mv dhd.ko dhd_usb.ko
 
 clean:
        $(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(ARCH) clean
index 7660c882b9f665798edcd76e2bb660a954e47aa3..2fe8a4a58511b974a2e48c359ccd70529cffc54d 100755 (executable)
@@ -24,7 +24,9 @@
 #include <typedefs.h>
 #include <bcmdefs.h>
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0))
 #include <stdarg.h>
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) */
 
 #ifdef BCMDRIVER
 #include <osl.h>
index a8cafcb5405a61511e9bf439ff731147cf2cd3be..61009d32fb3cc22e8730aa9d60ff1b8fe5c886e6 100755 (executable)
@@ -241,9 +241,7 @@ static const bcmevent_name_str_t bcmevent_names[] = {
        BCMEVENT_NAME(WLC_E_AUTH_START),
 #endif /* WL_CLIENT_SAE */
 #ifdef WL_TWT
-       BCMEVENT_NAME(WLC_E_TWT_SETUP),
-       BCMEVENT_NAME(WLC_E_TWT_TEARDOWN),
-       BCMEVENT_NAME(WLC_E_TWT_INFO_FRM)
+       BCMEVENT_NAME(WLC_E_TWT),
 #endif /* WL_TWT */
 };
 
index d2971180fdb9a53d48c30553f1dd78f8b4bdab2a..5bd32c5ca49394baa4415187ee9dc6af9b5c5d56 100755 (executable)
@@ -346,6 +346,12 @@ bcmsdh_unregister(void)
        bcmsdh_unregister_client_driver();
 }
 
+void *bcmsdh_get_dev(bcmsdh_info_t *sdh)
+{
+       bcmsdh_os_info_t *bcmsdh_osinfo = sdh->os_cxt;
+       return bcmsdh_osinfo->dev;
+}
+
 void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh)
 {
 #if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
index 596c02f9f20374f0b788698183cf12000621b29a..d0e6abb67546a05a3b076fccf697ca77e4f94236 100755 (executable)
@@ -103,6 +103,8 @@ extern PBCMSDH_SDMMC_INSTANCE gInstance;
 #define CUSTOM_SDIO_F1_BLKSIZE         DEFAULT_SDIO_F1_BLKSIZE
 #endif
 
+#define COPY_BUF_SIZE  (SDPCM_MAXGLOM_SIZE * 1600)
+
 #define MAX_IO_RW_EXTENDED_BLK         511
 
 uint sd_sdmode = SDIOH_MODE_SD4;       /* Use SD4 mode by default */
@@ -209,6 +211,14 @@ sdioh_attach(osl_t *osh, struct sdio_func *func)
                return NULL;
        }
        bzero((char *)sd, sizeof(sdioh_info_t));
+#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF)
+       sd->copy_buf = MALLOC(osh, COPY_BUF_SIZE);
+       if (sd->copy_buf == NULL) {
+               sd_err(("%s: MALLOC of %d-byte copy_buf failed\n",
+                       __FUNCTION__, COPY_BUF_SIZE));
+               goto fail;
+       }
+#endif
        sd->osh = osh;
        sd->fake_func0.num = 0;
        sd->fake_func0.card = func->card;
@@ -273,6 +283,9 @@ sdioh_attach(osl_t *osh, struct sdio_func *func)
        return sd;
 
 fail:
+#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF)
+       MFREE(sd->osh, sd->copy_buf, COPY_BUF_SIZE);
+#endif
        MFREE(sd->osh, sd, sizeof(sdioh_info_t));
        return NULL;
 }
@@ -301,6 +314,9 @@ sdioh_detach(osl_t *osh, sdioh_info_t *sd)
                sd->func[1] = NULL;
                sd->func[2] = NULL;
 
+#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF)
+               MFREE(sd->osh, sd->copy_buf, COPY_BUF_SIZE);
+#endif
                MFREE(sd->osh, sd, sizeof(sdioh_info_t));
        }
        return SDIOH_API_RC_SUCCESS;
@@ -1102,8 +1118,7 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by
        }
 
        if (err_ret) {
-               if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ)
-                       || (err_ret == -EIO))) {
+               if (regaddr == 0x1001F) {
                        /* XXX: Read/Write to SBSDIO_FUNC1_SLEEPCSR could return -110(timeout)
                         *      or -84(CRC) error in case the host tries to wake the device up.
                         *      Skip error log message if err code is -110 or -84 when accessing
@@ -1365,7 +1380,8 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func
                        return SDIOH_API_RC_FAIL;
                }
        }
-       } else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) {
+       }
+       else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) {
                for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
                        ttl_len += PKTLEN(sd->osh, pnext);
                }
@@ -1374,16 +1390,20 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func
                for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
                        uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext);
                        pkt_len = PKTLEN(sd->osh, pnext);
-
                        if (!localbuf) {
+#ifdef BCMSDIOH_STATIC_COPY_BUF
+                               if (ttl_len <= COPY_BUF_SIZE)
+                                       localbuf = sd->copy_buf;
+#else
                                localbuf = (uint8 *)MALLOC(sd->osh, ttl_len);
+#endif
                                if (localbuf == NULL) {
-                                       sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n",
-                                               __FUNCTION__, (write) ? "TX" : "RX"));
+                                       sd_err(("%s: %s localbuf malloc FAILED ttl_len=%d\n",
+                                               __FUNCTION__, (write) ? "TX" : "RX", ttl_len));
+                                       ttl_len -= pkt_len;
                                        goto txglomfail;
                                }
                        }
-
                        bcopy(buf, (localbuf + local_plen), pkt_len);
                        local_plen += pkt_len;
                        if (PKTNEXT(sd->osh, pnext))
@@ -1428,8 +1448,10 @@ txglomfail:
                return SDIOH_API_RC_FAIL;
        }
 
+#ifndef BCMSDIOH_STATIC_COPY_BUF
        if (localbuf)
                MFREE(sd->osh, localbuf, ttl_len);
+#endif
 
 #ifndef PKT_STATICS
        if (sd_msglevel & SDH_COST_VAL)
index 1dfb408fbf1b53fa78cc9d8683e92d9248f5daef..09307fd92dbb1bad8bbce581c7cfa3b152e8ce3d 100755 (executable)
@@ -91,8 +91,12 @@ static int sdioh_probe(struct sdio_func *func)
                adapter->bus_num = host_idx;
                adapter->slot_num = rca;
                adapter->sdio_func = func;
-       } else
+       } else {
                sd_err(("can't find adapter info for this chip\n"));
+#ifdef ADAPTER_IDX
+               goto fail;
+#endif
+       }
 
 #ifdef WL_CFG80211
        wl_cfg80211_set_parent_dev(&func->dev);
index 929056f11c026eaab6948ae77d20b8e9a5b13bd0..63d237e7e648f1183ba293695b8da480e8878237 100755 (executable)
@@ -23,7 +23,9 @@
 
 #include <typedefs.h>
 #include <bcmdefs.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0))
 #include <stdarg.h>
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) */
 #ifdef BCMDRIVER
 #include <osl.h>
 #include <bcmutils.h>
@@ -4930,7 +4932,7 @@ BCMPOSTTRAPFN(bcm_bitcount)(const uint8 *bitmap, uint length)
        return bitcount;
 }
 
-void
+static void
 dump_nvram(char *varbuf, int column, unsigned int n, unsigned int len)
 {
        unsigned int m;
index ddc6351cee185840dc4b643ca88850ef16c6aadf..91d5747f85812b2ed124f34f9c6dc16dd4348ab7 100755 (executable)
@@ -24,7 +24,9 @@
 #include <typedefs.h>
 #include <bcmdefs.h>
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0))
 #include <stdarg.h>
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) */
 
 #ifdef BCMDRIVER
 #include <osl.h>
index f86a86444f43993e2e748e9bed850fd33c72fba2..a3da591abdb1dabdcde686a37cd26357b640304a 100755 (executable)
@@ -31,6 +31,7 @@
  */
 
 
+#include <linux/usb.h>
 #include "osl.h"
 #include "dbus.h"
 #include <bcmutils.h>
 #include <dhd_wlfc.h>
 #endif
 #include <dhd_config.h>
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+#endif
 
+#include <bcmdevs_legacy.h>
 #if defined(BCM_REQUEST_FW)
 #include <bcmsrom_fmt.h>
 #include <trxhdr.h>
@@ -93,7 +99,7 @@ typedef struct dhd_bus {
        bool        txoverride;   /* flow control related */
        bool        rxoff;
        bool        tx_timer_ticking;
-
+       uint ctl_completed;
 
        dbus_irbq_t *rx_q;
        dbus_irbq_t *tx_q;
@@ -113,6 +119,7 @@ typedef struct dhd_bus {
 #endif
        char            *fw_path;               /* module_param: path to firmware image */
        char            *nv_path;               /* module_param: path to nvram vars file */
+       uint64 last_suspend_end_time;
 } dhd_bus_t;
 
 struct exec_parms {
@@ -151,10 +158,11 @@ static void dbus_if_pktfree(void *handle, void *p, bool send);
 static struct dbus_irb *dbus_if_getirb(void *cbarg, bool send);
 static void dbus_if_rxerr_indicate(void *handle, bool on);
 
-void * dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype,
-       uint16 bus_no, uint16 slot, uint32 hdrlen);
-void dhd_dbus_disconnect_cb(void *arg);
-void dbus_detach(dhd_bus_t *pub);
+static int dbus_suspend(void *context);
+static int dbus_resume(void *context);
+static void * dhd_dbus_probe_cb(uint16 bus_no, uint16 slot, uint32 hdrlen);
+static void dhd_dbus_disconnect_cb(void *arg);
+static void dbus_detach(dhd_bus_t *pub);
 
 /** functions in this file that are called by lower DBUS levels, e.g. dbus_usb.c */
 static dbus_intf_callbacks_t dbus_intf_cbs = {
@@ -179,10 +187,6 @@ static dbus_intf_callbacks_t dbus_intf_cbs = {
  * can be called inside disconnect()
  */
 static dbus_intf_t     *g_busintf = NULL;
-static probe_cb_t      probe_cb = NULL;
-static disconnect_cb_t disconnect_cb = NULL;
-static void            *probe_arg = NULL;
-static void            *disc_arg = NULL;
 
 #if defined(BCM_REQUEST_FW)
 int8 *nonfwnvram = NULL; /* stand-alone multi-nvram given with driver load */
@@ -200,9 +204,6 @@ static int   dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size
 static int   dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb);
 static int   dbus_rxirbs_fill(dhd_bus_t *dhd_bus);
 static int   dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info);
-static void  dbus_disconnect(void *handle);
-static void *dbus_probe(void *arg, const char *desc, uint32 bustype,
-       uint16 bus_no, uint16 slot, uint32 hdrlen);
 
 #if defined(BCM_REQUEST_FW)
 extern char * dngl_firmware;
@@ -601,7 +602,7 @@ check_file(osl_t *osh, unsigned char *headers)
 
 #ifdef EXTERNAL_FW_PATH
 static int
-dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path)
+dbus_get_fw_nvram(dhd_bus_t *dhd_bus)
 {
        int bcmerror = -1, i;
        uint len, total_len;
@@ -616,6 +617,8 @@ dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path)
        struct trx_header *hdr;
        uint32 img_offset = 0;
        int offset = 0;
+       char *pfw_path = dhd_bus->fw_path;
+       char *pnv_path = dhd_bus->nv_path;
 
        /* For Get nvram */
        file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
@@ -748,11 +751,11 @@ err:
  * the dongle
  */
 static int
-dbus_do_download(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path)
+dbus_do_download(dhd_bus_t *dhd_bus)
 {
        int err = DBUS_OK;
 
-       err = dbus_get_fw_nvram(dhd_bus, pfw_path, pnv_path);
+       err = dbus_get_fw_nvram(dhd_bus);
        if (err) {
                DBUSERR(("dbus_do_download: fail to get nvram %d\n", err));
                return err;
@@ -860,7 +863,12 @@ dbus_get_nvram(dhd_bus_t *dhd_bus)
                        nvram_words_pad = 4 - dhd_bus->nvram_len % 4;
 
                len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad;
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
+               dhd_bus->image = (uint8*)DHD_OS_PREALLOC(dhd_bus->dhd,
+                       DHD_PREALLOC_MEMDUMP_RAM, len);
+#else
                dhd_bus->image = MALLOC(dhd_bus->pub.osh, len);
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
                dhd_bus->image_len = len;
                if (dhd_bus->image == NULL) {
                        DBUSERR(("%s: malloc failed!\n", __FUNCTION__));
@@ -939,7 +947,7 @@ dbus_do_download(dhd_bus_t *dhd_bus)
 #if defined(BCM_REQUEST_FW)
        dhd_bus->firmware = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid,
                dhd_bus->pub.attrib.chiprev, &dhd_bus->fw, &dhd_bus->fwlen,
-               DBUS_FIRMWARE, 0, 0);
+               DBUS_FIRMWARE, 0, 0, dhd_bus->fw_path);
        if (!dhd_bus->firmware)
                return DBUS_ERR;
 #endif
@@ -965,7 +973,7 @@ dbus_do_download(dhd_bus_t *dhd_bus)
        nonfwnvramlen = 0;
        dhd_bus->nvfile = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid,
                dhd_bus->pub.attrib.chiprev, (void *)&temp_nvram, &temp_len,
-               DBUS_NVFILE, boardtype, boardrev);
+               DBUS_NVFILE, boardtype, boardrev, dhd_bus->nv_path);
        if (dhd_bus->nvfile) {
                int8 *tmp = MALLOC(dhd_bus->pub.osh, temp_len);
                if (tmp) {
@@ -996,7 +1004,11 @@ dbus_do_download(dhd_bus_t *dhd_bus)
                err = DBUS_ERR;
 
        if (dhd_bus->nvram) {
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
+               DHD_OS_PREFREE(dhd_bus->dhd, dhd_bus->image, dhd_bus->image_len);
+#else
                MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len);
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
                dhd_bus->image = dhd_bus->fw;
                dhd_bus->image_len = (uint32)dhd_bus->fwlen;
        }
@@ -1030,16 +1042,6 @@ fail:
 #endif /* EXTERNAL_FW_PATH */
 #endif
 
-/** required for DBUS deregistration */
-static void
-dbus_disconnect(void *handle)
-{
-       DBUSTRACE(("%s\n", __FUNCTION__));
-
-       if (disconnect_cb)
-               disconnect_cb(disc_arg);
-}
-
 /**
  * This function is called when the sent irb times out without a tx response status.
  * DBUS adds reliability by resending timed out IRBs DBUS_TX_RETRY_LIMIT times.
@@ -1371,22 +1373,17 @@ dbus_if_getirb(void *cbarg, bool send)
        return irb;
 }
 
-/**
- * Called as part of DBUS bus registration. Calls back into higher level (e.g. dhd_linux.c) probe
- * function.
+/* Register/Unregister functions are called by the main DHD entry
+ * point (e.g. module insertion) to link with the bus driver, in
+ * order to look for or await the device.
  */
-static void *
-dbus_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no,
-       uint16 slot, uint32 hdrlen)
-{
-       DBUSTRACE(("%s\n", __FUNCTION__));
-       if (probe_cb) {
-               disc_arg = probe_cb(probe_arg, desc, bustype, bus_no, slot, hdrlen);
-               return disc_arg;
-       }
 
-       return (void *)DBUS_ERR;
-}
+static dbus_driver_t dhd_dbus = {
+       dhd_dbus_probe_cb,
+       dhd_dbus_disconnect_cb,
+       dbus_suspend,
+       dbus_resume
+};
 
 /**
  * As part of initialization, higher level (e.g. dhd_linux.c) requests DBUS to prepare for
@@ -1399,12 +1396,7 @@ dhd_bus_register(void)
 
        DBUSTRACE(("%s: Enter\n", __FUNCTION__));
 
-       probe_cb = dhd_dbus_probe_cb;
-       disconnect_cb = dhd_dbus_disconnect_cb;
-       probe_arg = NULL;
-
-       err = dbus_bus_register(0xa5c, 0x48f, dbus_probe, /* call lower DBUS level register function */
-               dbus_disconnect, NULL, &g_busintf, NULL, NULL);
+       err = dbus_bus_register(&dhd_dbus, &g_busintf);
 
        /* Device not detected */
        if (err == DBUS_ERR_NODEVICE)
@@ -1414,11 +1406,10 @@ dhd_bus_register(void)
 }
 
 dhd_pub_t *g_pub = NULL;
+bool net_attached = FALSE;
 void
 dhd_bus_unregister(void)
 {
-       int ret;
-
        DBUSTRACE(("%s\n", __FUNCTION__));
 
        DHD_MUTEX_LOCK();
@@ -1428,11 +1419,8 @@ dhd_bus_unregister(void)
                        dhd_dbus_disconnect_cb(g_pub->bus);
                }
        }
-       probe_cb = NULL;
        DHD_MUTEX_UNLOCK();
-       ret = dbus_bus_deregister();
-       disconnect_cb = NULL;
-       probe_arg = NULL;
+       dbus_bus_deregister();
 }
 
 /** As part of initialization, data structures have to be allocated and initialized */
@@ -1598,7 +1586,7 @@ int dbus_dlneeded(dhd_bus_t *pub)
 }
 
 #if defined(BCM_REQUEST_FW)
-int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path)
+int dbus_download_firmware(dhd_bus_t *pub)
 {
        dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
        int err = DBUS_OK;
@@ -1611,11 +1599,7 @@ int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path)
        DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate));
 
        dhd_bus->pub.busstate = DBUS_STATE_DL_PENDING;
-#ifdef EXTERNAL_FW_PATH
-       err = dbus_do_download(dhd_bus, pfw_path, pnv_path);
-#else
        err = dbus_do_download(dhd_bus);
-#endif /* EXTERNAL_FW_PATH */
        if (err == DBUS_OK) {
                dhd_bus->pub.busstate = DBUS_STATE_DL_DONE;
        } else {
@@ -1716,24 +1700,19 @@ dbus_stop(struct dhd_bus *pub)
        return DBUS_ERR;
 }
 
-int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf)
-{
-       return dbus_send_pkt(dbus, pktbuf, pktbuf /* pktinfo */);
-}
-
 int
 dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info)
 {
        return dbus_send_irb(pub, buf, len, NULL, info);
 }
 
-int
+static int
 dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info)
 {
        return dbus_send_irb(pub, NULL, 0, pkt, info);
 }
 
-int
+static int
 dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len)
 {
        dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
@@ -1754,7 +1733,7 @@ dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len)
        return DBUS_ERR;
 }
 
-int
+static int
 dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len)
 {
        dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
@@ -1766,6 +1745,8 @@ dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len)
                dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
                if (dhd_bus->drvintf && dhd_bus->drvintf->recv_ctl)
                        return dhd_bus->drvintf->recv_ctl(dhd_bus->bus_info, buf, len);
+       } else {
+               DBUSERR(("%s: bustate=%d\n", __FUNCTION__, dhd_bus->pub.busstate));
        }
 
        return DBUS_ERR;
@@ -1804,8 +1785,9 @@ dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx)
        return DBUS_ERR;
 }
 
+#ifdef INTR_EP_ENABLE
 /** only called by dhd_cdc.c (Dec 2012) */
-int
+static int
 dbus_poll_intr(dbus_pub_t *pub)
 {
        dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
@@ -1823,6 +1805,7 @@ dbus_poll_intr(dbus_pub_t *pub)
        }
        return status;
 }
+#endif /* INTR_EP_ENABLE */
 
 /** called by nobody (Dec 2012) */
 void *
@@ -2459,7 +2442,8 @@ dhd_dbus_ctl_complete(void *handle, int type, int status)
                        dhd->tx_ctlerrs++;
        }
 
-       dhd_prot_ctl_complete(dhd);
+       dhd->bus->ctl_completed = TRUE;
+       dhd_os_ioctl_resp_wake(dhd);
 }
 
 static void
@@ -2467,21 +2451,26 @@ dhd_dbus_state_change(void *handle, int state)
 {
        dhd_pub_t *dhd = (dhd_pub_t *)handle;
        unsigned long flags;
+       wifi_adapter_info_t *adapter;
 
        if (dhd == NULL) {
                DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
                return;
        }
+       adapter = (wifi_adapter_info_t *)dhd->adapter;
 
+       if (dhd->busstate == DHD_BUS_SUSPEND && state == DBUS_STATE_DOWN) {
+               DBUSERR(("%s: switch state %d to %d\n", __FUNCTION__, state, DBUS_STATE_SLEEP));
+               state = DBUS_STATE_SLEEP;
+       }
        switch (state) {
-
                case DBUS_STATE_DL_NEEDED:
                        DBUSERR(("%s: firmware request cannot be handled\n", __FUNCTION__));
                        break;
                case DBUS_STATE_DOWN:
-                       DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__));
                        DHD_LINUX_GENERAL_LOCK(dhd, flags);
                        dhd_txflowcontrol(dhd, ALL_INTERFACES, ON);
+                       DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__));
                        dhd->busstate = DHD_BUS_DOWN;
                        DHD_LINUX_GENERAL_UNLOCK(dhd, flags);
                        break;
@@ -2492,13 +2481,6 @@ dhd_dbus_state_change(void *handle, int state)
                        dhd->busstate = DHD_BUS_DATA;
                        DHD_LINUX_GENERAL_UNLOCK(dhd, flags);
                        break;
-               case DBUS_STATE_SLEEP:
-                       DBUSTRACE(("%s: DBUS is suspend\n", __FUNCTION__));
-                       DHD_LINUX_GENERAL_LOCK(dhd, flags);
-                       dhd_txflowcontrol(dhd, ALL_INTERFACES, ON);
-                       dhd->busstate = DHD_BUS_SUSPEND;
-                       DHD_LINUX_GENERAL_UNLOCK(dhd, flags);
-                       break;
                default:
                        break;
        }
@@ -2586,6 +2568,12 @@ dhd_bus_chiprev(struct dhd_bus *bus)
        return bus->pub.attrib.chiprev;
 }
 
+struct device *
+dhd_bus_to_dev(struct dhd_bus *bus)
+{
+       return dbus_get_dev();
+}
+
 void
 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
 {
@@ -2605,7 +2593,91 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pktbuf)
                DBUSTRACE(("txoff\n"));
                return BCME_EPERM;
        }
-       return dbus_send_txdata(&bus->pub, pktbuf);
+       return dbus_send_pkt(&bus->pub, pktbuf, pktbuf);
+}
+
+int
+dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
+{
+       int timeleft = 0;
+       int ret = -1;
+
+       DBUSTRACE(("%s: Enter\n", __FUNCTION__));
+
+       if (bus->dhd->dongle_reset)
+               return -EIO;
+
+       bus->ctl_completed = FALSE;
+       ret = dbus_send_ctl(bus, (void *)msg, msglen);
+       if (ret) {
+               DBUSERR(("%s: dbus_send_ctl error %d\n", __FUNCTION__, ret));
+               return ret;
+       }
+
+       timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed);
+       if ((!timeleft) || (!bus->ctl_completed)) {
+               DBUSERR(("%s: Txctl timeleft %d ctl_completed %d\n",
+                       __FUNCTION__, timeleft, bus->ctl_completed));
+               ret = -1;
+       }
+
+#ifdef INTR_EP_ENABLE
+       /* If the ctl write is successfully completed, wait for an acknowledgement
+       * that indicates that it is now ok to do ctl read from the dongle
+       */
+       if (ret != -1) {
+               bus->ctl_completed = FALSE;
+               if (dbus_poll_intr(bus->pub)) {
+                       DBUSERR(("%s: dbus_poll_intr not submitted\n", __FUNCTION__));
+               } else {
+                       /* interrupt polling is sucessfully submitted. Wait for dongle to send
+                       * interrupt
+                       */
+                       timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed);
+                       if (!timeleft) {
+                               DBUSERR(("%s: intr poll wait timed out\n", __FUNCTION__));
+                       }
+               }
+       }
+#endif /* INTR_EP_ENABLE */
+
+       return ret;
+}
+
+int
+dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
+{
+       int timeleft;
+       int ret = -1;
+
+       DBUSTRACE(("%s: Enter\n", __FUNCTION__));
+
+       if (bus->dhd->dongle_reset)
+               return -EIO;
+
+       bus->ctl_completed = FALSE;
+       ret = dbus_recv_ctl(bus, (uchar*)msg, msglen);
+       if (ret) {
+               DBUSERR(("%s: dbus_recv_ctl error %d\n", __FUNCTION__, ret));
+               goto done;
+       }
+
+       timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed);
+       if ((!timeleft) || (!bus->ctl_completed)) {
+               DBUSERR(("%s: Rxctl timeleft %d ctl_completed %d\n", __FUNCTION__,
+                       timeleft, bus->ctl_completed));
+               ret = -ETIMEDOUT;
+               goto done;
+       }
+
+       /* XXX FIX: Must return cdc_len, not len, because after query_ioctl()
+        * it subtracts sizeof(cdc_ioctl_t);  The other approach is
+        * to have dbus_recv_ctl() return actual len.
+        */
+       ret = msglen;
+
+done:
+       return ret;
 }
 
 static void
@@ -2635,7 +2707,8 @@ dhd_dbus_advertise_bus_remove(dhd_pub_t *dhdp)
        int timeleft;
 
        DHD_LINUX_GENERAL_LOCK(dhdp, flags);
-       dhdp->busstate = DHD_BUS_REMOVE;
+       if (dhdp->busstate != DHD_BUS_SUSPEND)
+               dhdp->busstate = DHD_BUS_REMOVE;
        DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
 
        timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
@@ -2728,27 +2801,160 @@ dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path,
 
 }
 
+static int
+dhd_dbus_sync_dongle(dhd_pub_t *pub, int dlneeded)
+{
+       int ret = 0;
+
+       if (dlneeded == 0) {
+               ret = dbus_up(pub->bus);
+               if (ret) {
+                       DBUSERR(("%s: dbus_up failed!!\n", __FUNCTION__));
+                       goto exit;
+               }
+               ret = dhd_sync_with_dongle(pub);
+               if (ret < 0) {
+                       DBUSERR(("%s: failed with code ret=%d\n", __FUNCTION__, ret));
+                       goto exit;
+               }
+       }
+
+exit:
+       return ret;
+}
+
+static int
+dbus_suspend(void *context)
+{
+       int ret = 0;
+
+#if defined(LINUX)
+       dhd_bus_t *bus = (dhd_bus_t*)context;
+       unsigned long flags;
+
+       DBUSERR(("%s Enter\n", __FUNCTION__));
+       if (bus->dhd == NULL) {
+               DBUSERR(("bus not inited\n"));
+               return BCME_ERROR;
+       }
+       if (bus->dhd->prot == NULL) {
+               DBUSERR(("prot is not inited\n"));
+               return BCME_ERROR;
+       }
+
+       if (bus->dhd->up == FALSE) {
+               return BCME_OK;
+       }
+
+       DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
+       if (bus->dhd->busstate != DHD_BUS_DATA && bus->dhd->busstate != DHD_BUS_SUSPEND) {
+               DBUSERR(("not in a readystate to LPBK  is not inited\n"));
+               DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
+               return BCME_ERROR;
+       }
+       DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
+       if (bus->dhd->dongle_reset) {
+               DBUSERR(("Dongle is in reset state.\n"));
+               return -EIO;
+       }
+
+       DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
+       /* stop all interface network queue. */
+       dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
+       bus->dhd->busstate = DHD_BUS_SUSPEND;
+#if defined(LINUX) || defined(linux)
+       if (DHD_BUS_BUSY_CHECK_IN_TX(bus->dhd)) {
+               DBUSERR(("Tx Request is not ended\n"));
+               bus->dhd->busstate = DHD_BUS_DATA;
+               /* resume all interface network queue. */
+               dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
+               DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
+               return -EBUSY;
+       }
+#endif /* LINUX || linux */
+       DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd);
+       DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
+
+       ret = dhd_os_check_wakelock_all(bus->dhd);
+
+       DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
+       if (ret) {
+               bus->dhd->busstate = DHD_BUS_DATA;
+               /* resume all interface network queue. */
+               dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
+       } else {
+               bus->last_suspend_end_time = OSL_LOCALTIME_NS();
+       }
+       bus->dhd->hostsleep = 2;
+       DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd);
+       dhd_os_busbusy_wake(bus->dhd);
+       DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
+
+#endif /* LINUX */
+       DBUSERR(("%s Exit ret=%d\n", __FUNCTION__, ret));
+       return ret;
+}
+
+static int
+dbus_resume(void *context)
+{
+       dhd_bus_t *bus = (dhd_bus_t*)context;
+       ulong flags;
+       int dlneeded = 0;
+       int ret = 0;
+
+       DBUSERR(("%s Enter\n", __FUNCTION__));
+
+       if (bus->dhd->up == FALSE) {
+               return BCME_OK;
+       }
+       
+       dlneeded = dbus_dlneeded(bus);
+       if (dlneeded == 0) {
+               ret = dbus_up(bus);
+               if (ret) {
+                       DBUSERR(("%s: dbus_up failed!!\n", __FUNCTION__));
+               }
+       }
+
+       DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
+       DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd);
+       DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
+
+       DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
+       DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd);
+       bus->dhd->hostsleep = 0;
+       bus->dhd->busstate = DHD_BUS_DATA;
+       dhd_os_busbusy_wake(bus->dhd);
+       /* resume all interface network queue. */
+       dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
+       DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
+//     dhd_conf_set_suspend_resume(bus->dhd, 0);
+
+       return 0;
+}
+
 /*
  * hdrlen is space to reserve in pkt headroom for DBUS
  */
-void *
-dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype,
-       uint16 bus_no, uint16 slot, uint32 hdrlen)
+static void *
+dhd_dbus_probe_cb(uint16 bus_no, uint16 slot, uint32 hdrlen)
 {
        osl_t *osh = NULL;
        dhd_bus_t *bus = NULL;
        dhd_pub_t *pub = NULL;
        uint rxsz;
-       int dlneeded = 0;
+       int dlneeded = 0, ret = DBUS_OK;
        wifi_adapter_info_t *adapter = NULL;
+       bool net_attach_now = TRUE;
 
        DBUSTRACE(("%s: Enter\n", __FUNCTION__));
 
-       adapter = dhd_wifi_platform_get_adapter(bustype, bus_no, slot);
+       adapter = dhd_wifi_platform_get_adapter(USB_BUS, bus_no, slot);
 
        if (!g_pub) {
                /* Ask the OS interface part for an OSL handle */
-               if (!(osh = osl_attach(NULL, bustype, TRUE))) {
+               if (!(osh = osl_attach(NULL, USB_BUS, TRUE))) {
                        DBUSERR(("%s: OSL attach failed\n", __FUNCTION__));
                        goto fail;
                }
@@ -2775,37 +2981,57 @@ dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype,
                bus->dhd = pub;
 
                dlneeded = dbus_dlneeded(bus);
-               if (dlneeded >= 0) {
-                       if (!g_pub) {
-                               dhd_conf_reset(pub);
-                               dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev);
-                               dhd_conf_preinit(pub);
-                       }
+               if (dlneeded >= 0 && !g_pub) {
+                       dhd_conf_reset(pub);
+                       dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev);
+                       dhd_conf_preinit(pub);
                }
 
-               if (g_pub || dhd_download_fw_on_driverload) {
-                       if (dlneeded == 0) {
+#if defined(BCMDHD_MODULAR) && defined(INSMOD_FW_LOAD)
+               if (1)
+#else
+               if (g_pub || dhd_download_fw_on_driverload)
+#endif
+               {
+                       if (dlneeded == 0)
                                wifi_set_adapter_status(adapter, WIFI_STATUS_FW_READY);
 #ifdef BCM_REQUEST_FW
-                       } else if (dlneeded > 0) {
+                       else if (dlneeded > 0) {
+                               struct dhd_conf *conf = pub->conf;
+                               unsigned long flags;
+                               bool suspended;
                                wifi_clr_adapter_status(adapter, WIFI_STATUS_FW_READY);
+                               suspended = conf->suspended;
                                dhd_set_path(bus->dhd);
-                               if (dbus_download_firmware(bus, bus->fw_path, bus->nv_path) != DBUS_OK)
+                               conf->suspended = suspended;
+                               if (dbus_download_firmware(bus) != DBUS_OK)
                                        goto fail;
-                               bus->dhd->busstate = DHD_BUS_LOAD;
+                               DHD_LINUX_GENERAL_LOCK(pub, flags);
+                               if (bus->dhd->busstate != DHD_BUS_SUSPEND)
+                                       bus->dhd->busstate = DHD_BUS_LOAD;
+                               DHD_LINUX_GENERAL_UNLOCK(pub, flags);
+                       }
 #endif
-                       else {
+                       else {
                                goto fail;
                        }
                }
-       } else {
+       }
+       else {
                DBUSERR(("%s: dbus_attach failed\n", __FUNCTION__));
+               goto fail;
        }
 
-       if (!g_pub) {
-               /* Ok, have the per-port tell the stack we're open for business */
-               if (dhd_attach_net(bus->dhd, TRUE) != 0)
-               {
+#if defined(BCMDHD_MODULAR) && defined(INSMOD_FW_LOAD)
+       if (dlneeded > 0)
+               net_attach_now = FALSE;
+#endif
+
+       if (!net_attached && (net_attach_now || (dlneeded == 0))) {
+               if (dhd_dbus_sync_dongle(pub, dlneeded)) {
+                       goto fail;
+               }
+               if (dhd_attach_net(bus->dhd, TRUE) != 0) {
                        DBUSERR(("%s: Net attach failed!!\n", __FUNCTION__));
                        goto fail;
                }
@@ -2813,14 +3039,31 @@ dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype,
 #if defined(MULTIPLE_SUPPLICANT)
                wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
 #endif
+               net_attached = TRUE;
+       }
+       else if (net_attached && (pub->up == 1) && (dlneeded == 0)) {
+               // kernel resume case
+               pub->hostsleep = 0;
+               ret = dhd_dbus_sync_dongle(pub, dlneeded);
+#ifdef WL_CFG80211
+               __wl_cfg80211_up_resume(pub);
+               wl_cfgp2p_start_p2p_device_resume(pub);
+#endif
+               dhd_conf_set_suspend_resume(pub, 0);
+               if (ret != DBUS_OK)
+                       goto fail;
+       }
+
+       if (!g_pub) {
                g_pub = pub;
        }
 
        DBUSTRACE(("%s: Exit\n", __FUNCTION__));
-       wifi_clr_adapter_status(adapter, WIFI_STATUS_DETTACH);
-       wifi_set_adapter_status(adapter, WIFI_STATUS_ATTACH);
-       wake_up_interruptible(&adapter->status_event);
-       /* This is passed to dhd_dbus_disconnect_cb */
+       if (net_attached) {
+               wifi_set_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED);
+               wake_up_interruptible(&adapter->status_event);
+               /* This is passed to dhd_dbus_disconnect_cb */
+       }
        return bus;
 
 fail:
@@ -2843,7 +3086,7 @@ fail:
        return NULL;
 }
 
-void
+static void
 dhd_dbus_disconnect_cb(void *arg)
 {
        dhd_bus_t *bus = (dhd_bus_t *)arg;
@@ -2869,8 +3112,6 @@ dhd_dbus_disconnect_cb(void *arg)
                dhd_dbus_advertise_bus_remove(bus->dhd);
                dbus_detach(pub->bus);
                pub->bus = NULL;
-               wifi_clr_adapter_status(adapter, WIFI_STATUS_ATTACH);
-               wifi_set_adapter_status(adapter, WIFI_STATUS_DETTACH);
                wake_up_interruptible(&adapter->status_event);
        } else {
                osh = pub->osh;
@@ -2881,6 +3122,8 @@ dhd_dbus_disconnect_cb(void *arg)
                }
                dhd_free(pub);
                g_pub = NULL;
+               net_attached = FALSE;
+               wifi_clr_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED);
                if (MALLOCED(osh)) {
                        DBUSERR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
                }
@@ -2907,6 +3150,7 @@ bcm_dbus_module_exit(void)
 }
 
 EXPORT_SYMBOL(dbus_pnp_sleep);
+EXPORT_SYMBOL(dhd_bus_register);
 EXPORT_SYMBOL(dbus_get_devinfo);
 EXPORT_SYMBOL(dbus_detach);
 EXPORT_SYMBOL(dbus_get_attrib);
@@ -2919,6 +3163,7 @@ EXPORT_SYMBOL(dbus_get_device_speed);
 EXPORT_SYMBOL(dbus_send_pkt);
 EXPORT_SYMBOL(dbus_recv_ctl);
 EXPORT_SYMBOL(dbus_attach);
+EXPORT_SYMBOL(dhd_bus_unregister);
 
 MODULE_LICENSE("GPL");
 
index 5cee418d7868e87dd2a065b77460fbc71c9a0341..96834832cc5a336b1a7c0ee679a09c3695c6aba3 100755 (executable)
@@ -55,6 +55,9 @@ module_param(dbus_msglevel, int, 0);
 #define USB_DLGO_SPINWAIT            100     /* wait after DL_GO (ms) */
 #define TEST_CHIP                    0x4328
 
+/* driver info, initialized when bcmsdh_register is called */
+static dbus_driver_t drvinfo = {NULL, NULL, NULL, NULL};
+
 typedef struct {
        dbus_pub_t  *pub;
 
@@ -147,10 +150,6 @@ const bcm_iovar_t dhdusb_iovars[] = {
  * attach() is not called at probe and detach()
  * can be called inside disconnect()
  */
-static probe_cb_t      probe_cb = NULL;
-static disconnect_cb_t disconnect_cb = NULL;
-static void            *probe_arg = NULL;
-static void            *disc_arg = NULL;
 static dbus_intf_t     *g_dbusintf = NULL;
 static dbus_intf_t     dbus_usb_intf; /** functions called by higher layer DBUS into lower layer */
 
@@ -160,8 +159,7 @@ static dbus_intf_t  dbus_usb_intf; /** functions called by higher layer DBUS into
  */
 static void *dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs);
 static void dbus_usb_detach(dbus_pub_t *pub, void *info);
-static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype,
-       uint16 bus_no, uint16 slot, uint32 hdrlen);
+static void * dbus_usb_probe(uint16 bus_no, uint16 slot, uint32 hdrlen);
 
 /* functions */
 
@@ -170,12 +168,10 @@ static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype,
  * lower level DBUS functions to call (in both dbus_usb.c and dbus_usb_os.c).
  */
 static void *
-dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no,
-       uint16 slot, uint32 hdrlen)
+dbus_usb_probe(uint16 bus_no, uint16 slot, uint32 hdrlen)
 {
        DBUSTRACE(("%s(): \n", __FUNCTION__));
-       if (probe_cb) {
-
+       if (drvinfo.probe) {
                if (g_dbusintf != NULL) {
                        /* First, initialize all lower-level functions as default
                         * so that dbus.c simply calls directly to dbus_usb_os.c.
@@ -191,32 +187,55 @@ dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no,
                        dbus_usb_intf.dlrun = dbus_usb_dlrun;
                }
 
-               disc_arg = probe_cb(probe_arg, "DBUS USB", USB_BUS, bus_no, slot, hdrlen);
-               return disc_arg;
+               return drvinfo.probe(bus_no, slot, hdrlen);
        }
 
        return NULL;
 }
 
+static int
+dbus_usb_suspend(void *handle)
+{
+       DBUSTRACE(("%s(): \n", __FUNCTION__));
+
+       if (drvinfo.suspend)
+               return drvinfo.suspend(handle);
+
+       return BCME_OK;
+}
+
+static int
+dbus_usb_resume(void *handle)
+{
+       DBUSTRACE(("%s(): \n", __FUNCTION__));
+
+       if (drvinfo.resume)
+               drvinfo.resume(handle);
+
+       return 0;
+}
+
+static dbus_driver_t dhd_usb_dbus = {
+       dbus_usb_probe,
+       dbus_usb_disconnect,
+       dbus_usb_suspend,
+       dbus_usb_resume
+};
+
 /**
  * On return, *intf contains this or lower-level DBUS functions to be called by higher
  * level (dbus.c)
  */
 int
-dbus_bus_register(int vid, int pid, probe_cb_t prcb,
-       disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2)
+dbus_bus_register(dbus_driver_t *driver, dbus_intf_t **intf)
 {
        int err;
 
        DBUSTRACE(("%s(): \n", __FUNCTION__));
-       probe_cb = prcb;
-       disconnect_cb = discb;
-       probe_arg = prarg;
-
+       drvinfo = *driver;
        *intf = &dbus_usb_intf;
 
-       err = dbus_bus_osl_register(vid, pid, dbus_usb_probe,
-               dbus_usb_disconnect, NULL, &g_dbusintf, param1, param2);
+       err = dbus_bus_osl_register(&dhd_usb_dbus, &g_dbusintf);
 
        ASSERT(g_dbusintf);
        return err;
@@ -292,8 +311,8 @@ void
 dbus_usb_disconnect(void *handle)
 {
        DBUSTRACE(("%s(): \n", __FUNCTION__));
-       if (disconnect_cb)
-               disconnect_cb(disc_arg);
+       if (drvinfo.remove)
+               drvinfo.remove(handle);
 }
 
 /**
index 0bd71813c9d44cba7a38533d5112db85694c4b1a..3630bfcab5daffe6745b53bcb2c2a620c36adf70 100755 (executable)
@@ -511,6 +511,9 @@ typedef struct {
        struct usb_interface     *intf;
 } probe_info_t;
 
+/* driver info, initialized when bcmsdh_register is called */
+static dbus_driver_t drvinfo = {NULL, NULL, NULL, NULL};
+
 /*
  * USB Linux dbus_intf_t
  */
@@ -588,9 +591,6 @@ static dbus_intf_t dbus_usbos_intf = {
 };
 
 static probe_info_t    g_probe_info;
-static probe_cb_t      probe_cb = NULL;
-static disconnect_cb_t disconnect_cb = NULL;
-static void            *probe_arg = NULL;
 static void            *disc_arg = NULL;
 
 
@@ -1232,26 +1232,46 @@ static int
 dbus_usbos_suspend(struct usb_interface *intf,
             pm_message_t message)
 {
-       DBUSERR(("%s suspend state: %d\n", __FUNCTION__, g_probe_info.suspend_state));
+       usbos_info_t *usbos_info = (usbos_info_t *) g_probe_info.usbos_info;
+       int err = 0;
+
+       printf("%s Enter\n", __FUNCTION__);
+
        /* DHD for full dongle model */
        g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPEND_PENDING;
-       dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_SLEEP);
+       if (drvinfo.suspend && disc_arg)
+               err = drvinfo.suspend(disc_arg);
+       if (err) {
+               printf("%s: err=%d\n", __FUNCTION__, err);
+//             g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
+//             return err;
+       }
+       usbos_info->pub->busstate = DBUS_STATE_SLEEP;
+
        dbus_usbos_cancel_all_urbs((usbos_info_t*)g_probe_info.usbos_info);
        g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPENDED;
 
-       return 0;
+       printf("%s Exit err=%d\n", __FUNCTION__, err);
+       return err;
 }
 
 /**
  * The resume method is called to tell the driver that the device has been resumed and the driver
  * can return to normal operation.  URBs may once more be submitted.
  */
-static int dbus_usbos_resume(struct usb_interface *intf)
+static int
+dbus_usbos_resume(struct usb_interface *intf)
 {
-       DBUSERR(("%s Device resumed\n", __FUNCTION__));
+       usbos_info_t *usbos_info = (usbos_info_t *) g_probe_info.usbos_info;
+
+       printf("%s Enter\n", __FUNCTION__);
 
-       dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_UP);
        g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
+       if (drvinfo.resume && disc_arg)
+               drvinfo.resume(disc_arg);
+       usbos_info->pub->busstate = DBUS_STATE_UP;
+
+       printf("%s Exit\n", __FUNCTION__);
        return 0;
 }
 
@@ -1259,13 +1279,16 @@ static int dbus_usbos_resume(struct usb_interface *intf)
 * This function is directly called by the Linux kernel, when the suspended device has been reset
 * instead of being resumed
 */
-static int dbus_usbos_reset_resume(struct usb_interface *intf)
+static int
+dbus_usbos_reset_resume(struct usb_interface *intf)
 {
-       DBUSERR(("%s Device reset resumed\n", __FUNCTION__));
+       printf("%s Enter\n", __FUNCTION__);
 
-       /* The device may have lost power, so a firmware download may be required */
-       dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_DL_NEEDED);
        g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
+       if (drvinfo.resume && disc_arg)
+               drvinfo.resume(disc_arg);
+
+       printf("%s Exit\n", __FUNCTION__);
        return 0;
 }
 
@@ -1554,8 +1577,8 @@ DBUS_USBOS_PROBE()
                g_probe_info.device_speed = FULL_SPEED;
                DBUSERR(("full speed device detected\n"));
        }
-       if (g_probe_info.dereged == FALSE && probe_cb) {
-               disc_arg = probe_cb(probe_arg, "", USB_BUS, usb->bus->busnum, usb->portnum, 0);
+       if (g_probe_info.dereged == FALSE && drvinfo.probe) {
+               disc_arg = drvinfo.probe(usb->bus->busnum, usb->portnum, 0);
        }
 
        g_probe_info.disc_cb_done = FALSE;
@@ -1616,8 +1639,8 @@ DBUS_USBOS_DISCONNECT()
        if (probe_usb_init_data) {
                usbos_info = (usbos_info_t *) probe_usb_init_data->usbos_info;
                if (usbos_info) {
-                       if ((probe_usb_init_data->dereged == FALSE) && disconnect_cb && disc_arg) {
-                               disconnect_cb(disc_arg);
+                       if ((probe_usb_init_data->dereged == FALSE) && drvinfo.remove && disc_arg) {
+                               drvinfo.remove(disc_arg);
                                disc_arg = NULL;
                                probe_usb_init_data->disc_cb_done = TRUE;
                        }
@@ -2554,18 +2577,11 @@ dbus_usbos_state_change(void *bus, int state)
 }
 
 int
-dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb,
-       disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2)
+dbus_bus_osl_register(dbus_driver_t *driver, dbus_intf_t **intf)
 {
        bzero(&g_probe_info, sizeof(probe_info_t));
 
-       probe_cb = prcb;
-       disconnect_cb = discb;
-       probe_arg = prarg;
-
-       devid_table[0].idVendor = vid;
-       devid_table[0].idProduct = pid;
-
+       drvinfo = *driver;
        *intf = &dbus_usbos_intf;
 
        USB_REGISTER();
@@ -2579,8 +2595,8 @@ dbus_bus_osl_deregister()
        g_probe_info.dereged = TRUE;
 
        DHD_MUTEX_LOCK();
-       if (disconnect_cb && disc_arg && (g_probe_info.disc_cb_done == FALSE)) {
-               disconnect_cb(disc_arg);
+       if (drvinfo.remove && disc_arg && (g_probe_info.disc_cb_done == FALSE)) {
+               drvinfo.remove(disc_arg);
                disc_arg = NULL;
        }
        DHD_MUTEX_UNLOCK();
@@ -3182,8 +3198,10 @@ dbus_request_firmware(const char *name, const struct firmware **firmware)
        return *firmware != NULL ? 0 : -ENOENT;
 }
 
+#ifndef DHD_LINUX_STD_FW_API
 static void *
-dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev)
+dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen,
+       uint16 boardtype, uint16 boardrev, char *path)
 {
        const struct firmware *firmware = NULL;
 #ifndef OEM_ANDROID
@@ -3246,11 +3264,12 @@ dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype
        snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_FW_PATH);
 #endif /* OEM_ANDROID */
 
-       ret = dbus_request_firmware(file_name, &firmware);
+       ret = dbus_request_firmware(path, &firmware);
        if (ret) {
-               DBUSERR(("fail to request firmware %s\n", file_name));
+               DBUSERR(("fail to request firmware %s\n", path));
                return NULL;
-       }
+       } else
+               DBUSERR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, path, firmware->size));
 
        *fwlen = firmware->size;
        *fw = (uint8 *)firmware->data;
@@ -3259,7 +3278,8 @@ dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype
 }
 
 static void *
-dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev)
+dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen,
+       uint16 boardtype, uint16 boardrev, char *path)
 {
        const struct firmware *firmware = NULL;
 #ifndef OEM_ANDROID
@@ -3327,9 +3347,9 @@ dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype
        snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_NVRAM_PATH);
 #endif /* OEM_ANDROID */
 
-       ret = dbus_request_firmware(file_name, &firmware);
+       ret = dbus_request_firmware(path, &firmware);
        if (ret) {
-               DBUSERR(("fail to request nvram %s\n", file_name));
+               DBUSERR(("fail to request nvram %s\n", path));
 
 #ifndef OEM_ANDROID
                /* Load generic nvram file */
@@ -3340,10 +3360,11 @@ dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype
 #endif /* OEM_ANDROID */
 
                if (ret) {
-                       DBUSERR(("fail to request nvram %s\n", file_name));
+                       DBUSERR(("fail to request nvram %s\n", path));
                        return NULL;
                }
-       }
+       } else
+               DBUSERR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, path, firmware->size));
 
        *fwlen = firmware->size;
        *fw = (uint8 *)firmware->data;
@@ -3352,17 +3373,39 @@ dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype
 
 void *
 dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype,
-       uint16 boardrev)
+       uint16 boardrev, char *path)
 {
        switch (type) {
                case DBUS_FIRMWARE:
-                       return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev);
+                       return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev, path);
                case DBUS_NVFILE:
-                       return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev);
+                       return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev, path);
                default:
                        return NULL;
        }
 }
+#else
+void *
+dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype,
+       uint16 boardrev, char *path)
+{
+       const struct firmware *firmware = NULL;
+       int err = DBUS_OK;
+
+       err = dbus_request_firmware(path, &firmware);
+       if (err) {
+               DBUSERR(("fail to request firmware %s\n", path));
+               return NULL;
+       } else {
+               DBUSERR(("%s: %s (%zu bytes) open success\n",
+                       __FUNCTION__, path, firmware->size));
+       }
+
+       *fwlen = firmware->size;
+       *fw = (uint8 *)firmware->data;
+       return (void *)firmware;
+}
+#endif
 
 void
 dbus_release_fw_nvfile(void *firmware)
@@ -3403,3 +3446,10 @@ dbus_usbos_intf_wlan(struct usb_device *usb)
        return intf_wlan;
 }
 #endif /* BCMUSBDEV_COMPOSITE */
+
+#ifdef LINUX
+struct device * dbus_get_dev(void)
+{
+       return &g_probe_info.usb->dev;
+}
+#endif /* LINUX */
\ No newline at end of file
index fd53811725ad90ccd838360a0e715970f28510c5..0832c45e68826d6f4817b6b56baf3b198c602ef0 100755 (executable)
@@ -34,6 +34,7 @@
 #define _dhd_h_
 
 #if defined(LINUX)
+#include <linux/firmware.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -46,6 +47,8 @@
 #include <linux/proc_fs.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
 #include <uapi/linux/sched/types.h>
 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
@@ -1928,6 +1931,9 @@ typedef struct dhd_pub {
        struct dhd_conf *conf;  /* Bus module handle */
        void *adapter;                  /* adapter information, interrupt, fw path etc. */
        void *event_params;
+#ifdef WL_TIMER
+       void *timer_params;
+#endif /* WL_TIMER */
 #ifdef BCMDBUS
        bool dhd_remove;
 #endif /* BCMDBUS */
@@ -2726,6 +2732,8 @@ void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size);
 #endif /* DHD_FW_COREDUMP */
 
 #if defined(linux) || defined(LINUX)
+int dhd_os_get_img_fwreq(const struct firmware **fw, char *file_path);
+void dhd_os_close_img_fwreq(const struct firmware *fw);
 #if defined(DHD_SSSR_DUMP)
 void dhd_write_sssr_dump(dhd_pub_t *dhdp, uint32 dump_mode);
 #endif /* DHD_SSSR_DUMP */
@@ -3697,8 +3705,8 @@ extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags);
 
 #ifdef DBG_PKT_MON
 /* Enable DHD PKT MON spin lock/unlock */
-#define DHD_PKT_MON_LOCK(lock, flags)     (flags) = osl_spin_lock(lock)
-#define DHD_PKT_MON_UNLOCK(lock, flags)   osl_spin_unlock(lock, (flags))
+#define DHD_PKT_MON_LOCK(lock, flags)     (flags) = osl_mutex_lock(lock)
+#define DHD_PKT_MON_UNLOCK(lock, flags)   osl_mutex_unlock(lock, (flags))
 #endif /* DBG_PKT_MON */
 
 #ifdef DHD_PKT_LOGGING
@@ -4649,6 +4657,94 @@ int dhd_awdl_llc_to_eth_hdr(struct dhd_pub *dhd, struct ether_header *eh, void *
 #error "DHD_DEBUGABILITY_LOG_DUMP_RING without DEBUGABILITY"
 #endif /* DEBUGABILITY */
 #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
+
+#if defined(__linux__)
+#ifdef DHD_SUPPORT_VFS_CALL
+static INLINE struct file *dhd_filp_open(const char *filename, int flags, int mode)
+{
+       return filp_open(filename, flags, mode);
+}
+
+static INLINE int dhd_filp_close(void *image, void *id)
+{
+       return filp_close((struct file *)image, id);
+}
+
+static INLINE int dhd_i_size_read(const struct inode *inode)
+{
+       return i_size_read(inode);
+}
+
+static INLINE int dhd_kernel_read_compat(struct file *fp, loff_t pos, void *buf, size_t count)
+{
+       return kernel_read_compat(fp, pos, buf, count);
+}
+
+static INLINE int dhd_vfs_read(struct file *filep, char *buf, size_t size, loff_t *pos)
+{
+       return vfs_read(filep, buf, size, pos);
+}
+
+static INLINE int dhd_vfs_write(struct file *filep, char *buf, size_t size, loff_t *pos)
+{
+       return vfs_write(filep, buf, size, pos);
+}
+
+static INLINE int dhd_vfs_fsync(struct file *filep, int datasync)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+       return vfs_fsync(filep, datasync);
+#else
+       return vfs_fsync(filep, filep->f_path.dentry, 0);
+#endif
+}
+
+static INLINE int dhd_vfs_stat(char *buf, struct kstat *stat)
+{
+       return vfs_stat(buf, stat);
+}
+
+static INLINE int dhd_kern_path(char *name, int flags, struct path *file_path)
+{
+       return kern_path(name, flags, file_path);
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0))
+#define DHD_VFS_INODE(dir) (dir->d_inode)
+#else
+#define DHD_VFS_INODE(dir) d_inode(dir)
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
+#define DHD_VFS_UNLINK(dir, b, c) vfs_unlink(DHD_VFS_INODE(dir), b)
+#else
+#define DHD_VFS_UNLINK(dir, b, c) vfs_unlink(DHD_VFS_INODE(dir), b, c)
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
+
+#else
+#define DHD_VFS_UNLINK(dir, b, c) 0
+
+static INLINE struct file *dhd_filp_open(const char *filename, int flags, int mode)
+       { return NULL; }
+static INLINE int dhd_filp_close(void *image, void *id)
+       { return 0; }
+static INLINE int dhd_i_size_read(const struct inode *inode)
+       { return 0; }
+static INLINE int dhd_kernel_read_compat(struct file *fp, loff_t pos, void *buf, size_t count)
+       { return 0; }
+static INLINE int dhd_vfs_read(struct file *filep, char *buf, size_t size, loff_t *pos)
+       { return 0; }
+static INLINE int dhd_vfs_write(struct file *filep, char *buf, size_t size, loff_t *pos)
+       { return 0; }
+static INLINE int dhd_vfs_fsync(struct file *filep, int datasync)
+       { return 0; }
+static INLINE int dhd_vfs_stat(char *buf, struct kstat *stat)
+       { return 0; }
+static INLINE int dhd_kern_path(char *name, int flags, struct path *file_path)
+       { return 0; }
+#endif /* DHD_SUPPORT_VFS_CALL */
+#endif /* __linux__ */
+
 #ifdef WL_MONITOR
 void dhd_set_monitor(dhd_pub_t *pub, int ifidx, int val);
 #endif /* WL_MONITOR */
index 5618b02067392f727c561f1ad1b57d29519c7e78..295f1babb7f91f80d361405eb9b95cf7492c6440 100755 (executable)
@@ -31,8 +31,6 @@
 
 extern int dbus_up(struct dhd_bus *pub);
 extern int dbus_stop(struct dhd_bus *pub);
-extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len);
-extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len);
 /*
  * Exported from dhd bus module (dhd_usb, dhd_sdio)
  */
@@ -90,6 +88,7 @@ extern int dhd_bus_oob_intr_register(dhd_pub_t *dhdp);
 extern void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp);
 extern void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable);
 extern int dhd_bus_get_oob_irq_num(dhd_pub_t *dhdp);
+extern struct device * dhd_bus_to_dev(struct dhd_bus *bus);
 extern void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub);
 extern void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub);
 extern bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub);
@@ -251,8 +250,6 @@ extern void dhd_bus_aer_config(struct dhd_bus *bus);
 static INLINE void dhd_bus_aer_config(struct dhd_bus *bus) { }
 #endif /* LINUX || linux */
 
-extern struct device * dhd_bus_to_dev(struct dhd_bus *bus);
-
 extern int dhdpcie_cto_init(struct dhd_bus *bus, bool enable);
 extern int dhdpcie_cto_cfg_init(struct dhd_bus *bus, bool enable);
 
@@ -312,7 +309,7 @@ static INLINE bool dhd_bus_check_driver_up(void) { return FALSE; }
 static INLINE void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val) { }
 static INLINE int dhd_bus_get_linkdown(dhd_pub_t *dhdp) { return 0; }
 static INLINE int dhd_bus_get_cto(dhd_pub_t *dhdp) { return 0; }
-extern INLINE int dhd_bus_checkdied(struct dhd_bus *bus, char *data, uint size) { return 0; }
+static INLINE int dhd_bus_checkdied(struct dhd_bus *bus, char *data, uint size) { return 0; }
 #endif /* BCMPCIE */
 
 #if defined(BCMPCIE) && defined(EWP_ETD_PRSRV_LOGS)
index 62b9eec2978f38495c8719bb463421e5444c3526..90d6deaf9986674296856dbd2b85f5dbe21c2ee0 100755 (executable)
@@ -16,7 +16,7 @@
 #define CCODE_4359C0
 #endif
 #if defined(BCMPCIE)
-#define CCODE_4375B4
+//#define CCODE_4375B4
 #endif
 #ifdef BCMDBUS
 #define CCODE_4358U
@@ -232,7 +232,7 @@ const ccode_list_map_t ccode_list_map[] = {
        {BCM4354_CHIP_ID,       2,      ccode_4356a2,   "XZ/11"},
        {BCM4356_CHIP_ID,       2,      ccode_4356a2,   "XZ/11"},
        {BCM4359_CHIP_ID,       9,      ccode_4359c0,   "XZ/11"},
-       {BCM4375_CHIP_ID,       5,      ccode_4375b4,   "XZ/11"},
+       {BCM4375_CHIP_ID,       5,      ccode_4375b4,   ""},
 #endif
 #ifdef BCMDBUS
        {BCM43569_CHIP_ID,      2,      ccode_4358u, "XW/0"},
@@ -264,9 +264,11 @@ dhd_ccode_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec)
                }
        }
 
-       if (bcmerror && ccode_ww && strlen(ccode_ww)>=4) {
-               memcpy(cspec->ccode, ccode_ww, 2);
-               cspec->rev = (int)simple_strtol(ccode_ww+3, NULL, 0);
+       if (dhd->op_mode != DHD_FLAG_MFG_MODE) {
+               if (bcmerror && ccode_ww && strlen(ccode_ww)>=4) {
+                       memcpy(cspec->ccode, ccode_ww, 2);
+                       cspec->rev = (int)simple_strtol(ccode_ww+3, NULL, 0);
+               }
        }
 
        return bcmerror;
index 0152c18c9ccab0c3f1edf509f482c022cc4fe301..a81d49fc8c90036ecfe6cbb309272fc9bd4ce839 100755 (executable)
@@ -71,9 +71,6 @@ typedef struct dhd_prot {
        uint16 reqid;
        uint8 pending;
        uint32 lastcmd;
-#ifdef BCMDBUS
-       uint ctl_completed;
-#endif /* BCMDBUS */
        uint8 bus_header[BUS_HEADER_LEN];
        cdc_ioctl_t msg;
        unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
@@ -89,9 +86,6 @@ dhd_prot_get_ioctl_trans_id(dhd_pub_t *dhdp)
 static int
 dhdcdc_msg(dhd_pub_t *dhd)
 {
-#ifdef BCMDBUS
-       int timeout = 0;
-#endif /* BCMDBUS */
        int err = 0;
        dhd_prot_t *prot = dhd->prot;
        int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t);
@@ -108,46 +102,8 @@ dhdcdc_msg(dhd_pub_t *dhd)
                len = CDC_MAX_MSG_SIZE;
 
        /* Send request */
-#ifdef BCMDBUS
-       prot->ctl_completed = FALSE;
-       err = dbus_send_ctl(dhd->bus, (void *)&prot->msg, len);
-       if (err) {
-               DHD_ERROR(("dbus_send_ctl error=0x%x\n", err));
-               DHD_OS_WAKE_UNLOCK(dhd);
-               return err;
-       }
-#else
        err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
-#endif /* BCMDBUS */
 
-#ifdef BCMDBUS
-       timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed);
-       if ((!timeout) || (!prot->ctl_completed)) {
-               DHD_ERROR(("Txctl timeout %d ctl_completed %d\n",
-                       timeout, prot->ctl_completed));
-               DHD_ERROR(("Txctl wait timed out\n"));
-               err = -1;
-       }
-#endif /* BCMDBUS */
-#if defined(BCMDBUS) && defined(INTR_EP_ENABLE)
-       /* If the ctl write is successfully completed, wait for an acknowledgement
-       * that indicates that it is now ok to do ctl read from the dongle
-       */
-       if (err != -1) {
-               prot->ctl_completed = FALSE;
-               if (dbus_poll_intr(dhd->dbus)) {
-                       DHD_ERROR(("dbus_poll_intr not submitted\n"));
-               } else {
-                       /* interrupt polling is sucessfully submitted. Wait for dongle to send
-                       * interrupt
-                       */
-                       timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed);
-                       if (!timeout) {
-                               DHD_ERROR(("intr poll wait timed out\n"));
-                       }
-               }
-       }
-#endif /* defined(BCMDBUS) && defined(INTR_EP_ENABLE) */
        DHD_OS_WAKE_UNLOCK(dhd);
        return err;
 }
@@ -155,9 +111,6 @@ dhdcdc_msg(dhd_pub_t *dhd)
 static int
 dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
 {
-#ifdef BCMDBUS
-       int timeout = 0;
-#endif /* BCMDBUS */
        int ret;
        int cdc_len = len + sizeof(cdc_ioctl_t);
        dhd_prot_t *prot = dhd->prot;
@@ -165,29 +118,7 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
        DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
        do {
-#ifdef BCMDBUS
-               prot->ctl_completed = FALSE;
-               ret = dbus_recv_ctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
-               if (ret) {
-                       DHD_ERROR(("dbus_recv_ctl error=0x%x(%d)\n", ret, ret));
-                       goto done;
-               }
-               timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed);
-               if ((!timeout) || (!prot->ctl_completed)) {
-                       DHD_ERROR(("Rxctl timeout %d ctl_completed %d\n",
-                               timeout, prot->ctl_completed));
-                       ret = -ETIMEDOUT;
-                       goto done;
-               }
-
-               /* XXX FIX: Must return cdc_len, not len, because after query_ioctl()
-                * it subtracts sizeof(cdc_ioctl_t);  The other approach is
-                * to have dbus_recv_ctl() return actual len.
-                */
-               ret = cdc_len;
-#else
                ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
-#endif /* BCMDBUS */
                if (ret < 0)
                        break;
        } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
@@ -197,9 +128,6 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
                ret = len;
        }
 
-#ifdef BCMDBUS
-done:
-#endif /* BCMDBUS */
        return ret;
 }
 
@@ -403,24 +331,6 @@ done:
        return ret;
 }
 
-#ifdef BCMDBUS
-int
-dhd_prot_ctl_complete(dhd_pub_t *dhd)
-{
-       dhd_prot_t *prot;
-
-       if (dhd == NULL)
-               return BCME_ERROR;
-
-       prot = dhd->prot;
-
-       ASSERT(prot);
-       prot->ctl_completed = TRUE;
-       dhd_os_ioctl_resp_wake(dhd);
-       return 0;
-}
-#endif /* BCMDBUS */
-
 /* XXX: due to overlays this should not be called directly; call dhd_wl_ioctl() instead */
 int
 dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len)
@@ -640,6 +550,17 @@ exit:
        return 0;
 }
 
+#ifdef DHD_LOSSLESS_ROAMING
+int dhd_update_sdio_data_prio_map(dhd_pub_t *dhdp)
+{
+       const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+       bcopy(prio2tid, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
+
+       return BCME_OK;
+}
+#endif // DHD_LOSSLESS_ROAMING
+
 int
 dhd_prot_attach(dhd_pub_t *dhd)
 {
index a8f8ef6b6c74fcfa4e6873f95dbdf6f03c1ce043..7c83e586e774bc19bf3725c43091d976611591f7 100755 (executable)
@@ -5154,16 +5154,11 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data,
                                event_name, reason, bcn_mute_miti_evnt_data->uatbtt_count));
                }
                break;
-
-       case WLC_E_TWT_SETUP:
-               DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
-               break;
-       case WLC_E_TWT_TEARDOWN:
-               DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
-               break;
-       case WLC_E_TWT_INFO_FRM:
-               DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
+#ifdef WL_TWT
+       case WLC_E_TWT:
+               DHD_EVENT(("MACEVENT: %s, type:%d\n", event_name, reason));
                break;
+#endif /* WL_TWT */
        default:
                DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
                       event_name, event_type, eabuf, (int)status, (int)reason,
@@ -7804,6 +7799,82 @@ static int traffic_mgmt_add_dwm_filter(dhd_pub_t *dhd,
 }
 #endif /* BCM_ROUTER_DHD */
 
+#ifdef DHD_LINUX_STD_FW_API
+int dhd_get_download_buffer(dhd_pub_t  *dhd, char *file_path, download_type_t component,
+       char ** buffer, int *length)
+{
+       int ret = BCME_ERROR;
+       const struct firmware *fw = NULL;
+#ifdef SUPPORT_OTA_UPDATE
+       uint8 *buf = NULL;
+       int len = 0;
+       ota_update_info_t *ota_info = &dhd->ota_update_info;
+#endif /* SUPPORT_OTA_UPDATE */
+
+#ifdef SUPPORT_OTA_UPDATE
+       if (component == CLM_BLOB) {
+               if (ota_info->clm_len) {
+                       DHD_ERROR(("Using OTA CLM_BLOB\n"));
+                       buf = ota_info->clm_buf;
+                       len = ota_info->clm_len;
+               }
+       }
+       else if (component == NVRAM) {
+               if (ota_info->nvram_len) {
+                       DHD_ERROR(("Using OTA NVRAM.\n"));
+                       buf = ota_info->nvram_buf;
+                       len = ota_info->nvram_len;
+               }
+       }
+#endif /* SUPPORT_OTA_UPDATE */
+
+#ifdef SUPPORT_OTA_UPDATE
+       if (len) {
+               *buffer = (char *)buf;
+               *length = len;
+       }
+       else
+#endif /* SUPPORT_OTA_UPDATE */
+       {
+               if (file_path) {
+                       ret = dhd_os_get_img_fwreq(&fw, file_path);
+                       if (ret < 0) {
+                               DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n",
+                                       ret));
+                               goto err;
+                       } else {
+                               if ((fw->size <= 0 || fw->size > *length)) {
+                                       DHD_ERROR(("fw->size = %zu, *length = %d\n", fw->size, *length));
+                                       *length = fw->size;
+                                       goto err;
+                               }
+                               *buffer = VMALLOCZ(dhd->osh, fw->size);
+                               if (*buffer == NULL) {
+                                       DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
+                                               __FUNCTION__, (int)fw->size));
+                                       ret = BCME_NOMEM;
+                                       goto err;
+                               }
+                               *length = fw->size;
+                               ret = memcpy_s(*buffer, fw->size, fw->data, fw->size);
+                               if (ret != BCME_OK) {
+                                       DHD_ERROR(("%s: memcpy_s failed, err : %d\n",
+                                                       __FUNCTION__, ret));
+                                       goto err;
+                               }
+                               ret = BCME_OK;
+                       }
+               }
+       }
+err:
+       if (fw) {
+               dhd_os_close_img_fwreq(fw);
+       }
+       return ret;
+}
+
+#else
+
 /* Given filename and download type,  returns a buffer pointer and length
 * for download to f/w. Type can be FW or NVRAM.
 *
@@ -7923,6 +7994,7 @@ err:
 
        return ret;
 }
+#endif /* DHD_LINUX_STD_FW_API */
 
 int
 dhd_download_2_dongle(dhd_pub_t        *dhd, char *iovar, uint16 flag, uint16 dload_type,
@@ -7963,9 +8035,9 @@ dhd_download_blob(dhd_pub_t *dhd, unsigned char *buf,
 
 {
        int chunk_len;
-#if !defined(LINUX) && !defined(linux)
+#if (!defined(LINUX) && !defined(linux)) || defined(DHD_LINUX_STD_FW_API)
        int cumulative_len = 0;
-#endif /* !LINUX && !linux */
+#endif /* !LINUX && !linux || DHD_LINUX_STD_FW_API */
        int size2alloc;
        unsigned char *new_buf;
        int err = 0, data_offset;
@@ -7977,7 +8049,7 @@ dhd_download_blob(dhd_pub_t *dhd, unsigned char *buf,
 
        if ((new_buf = (unsigned char *)MALLOCZ(dhd->osh, size2alloc)) != NULL) {
                do {
-#if !defined(LINUX) && !defined(linux)
+#if (!defined(LINUX) && !defined(linux)) || defined(DHD_LINUX_STD_FW_API)
                        if (len >= MAX_CHUNK_LEN)
                                chunk_len = MAX_CHUNK_LEN;
                        else
@@ -7994,7 +8066,7 @@ dhd_download_blob(dhd_pub_t *dhd, unsigned char *buf,
                                err = BCME_ERROR;
                                goto exit;
                        }
-#endif /* !LINUX && !linux */
+#endif /* !LINUX && !linux || DHD_LINUX_STD_FW_API */
                        if (len - chunk_len == 0)
                                dl_flag |= DL_END;
 
@@ -8005,13 +8077,13 @@ dhd_download_blob(dhd_pub_t *dhd, unsigned char *buf,
 
                        len = len - chunk_len;
                } while ((len > 0) && (err == 0));
-#if !defined(LINUX) && !defined(linux)
+#if (!defined(LINUX) && !defined(linux)) || defined(DHD_LINUX_STD_FW_API)
                MFREE(dhd->osh, new_buf, size2alloc);
 #endif /* !LINUX && !linux */
        } else {
                err = BCME_NOMEM;
        }
-#if defined(LINUX) || defined(linux)
+#if (defined(LINUX) || defined(linux)) && !defined(DHD_LINUX_STD_FW_API)
 exit:
        if (new_buf) {
                MFREE(dhd->osh, new_buf, size2alloc);
@@ -8258,7 +8330,7 @@ int
 dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path)
 {
        char *clm_blob_path;
-       int len;
+       int len = 0, memblock_len = 0;
        char *memblock = NULL;
        int err = BCME_OK;
        char iovbuf[WLC_IOCTL_SMLEN];
@@ -8272,7 +8344,11 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path)
                clm_blob_path = clm_path;
                DHD_TRACE(("clm path from module param:%s\n", clm_path));
        } else {
+#ifdef DHD_LINUX_STD_FW_API
+               clm_blob_path = DHD_CLM_NAME;
+#else
                clm_blob_path = VENDOR_PATH CONFIG_BCMDHD_CLM_PATH;
+#endif /* DHD_LINUX_STD_FW_API */
        }
 
        /* If CLM blob file is found on the filesystem, download the file.
@@ -8280,11 +8356,21 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path)
         * validate the country code before proceeding with the initialization.
         * If country code is not valid, fail the initialization.
         */
-#if !defined(LINUX) && !defined(linux)
+#if (!defined(LINUX) && !defined(linux)) || defined(DHD_LINUX_STD_FW_API)
        len = MAX_CLM_BUF_SIZE;
        dhd_get_download_buffer(dhd, clm_blob_path, CLM_BLOB, &memblock, &len);
+#ifdef DHD_LINUX_STD_FW_API
+       memblock_len = len;
+#else
+       memblock_len = MAX_CLM_BUF_SIZE;
+#endif /* DHD_LINUX_STD_FW_API */
 #else
        memblock = dhd_os_open_image1(dhd, (char *)clm_blob_path);
+       len = dhd_os_get_image_size(memblock);
+       BCM_REFERENCE(memblock_len);
+#endif /* !LINUX && !linux || DHD_LINUX_STD_FW_API */
+
+#if defined(LINUX) || defined(linux)
        if (memblock == NULL) {
                printf("%s: Ignore clm file %s\n", __FUNCTION__, clm_path);
 #if defined(DHD_BLOB_EXISTENCE_CHECK)
@@ -8301,8 +8387,6 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path)
 #endif /* DHD_BLOB_EXISTENCE_CHECK */
                goto exit;
        }
-
-       len = dhd_os_get_image_size(memblock);
 #endif /* !LINUX && !linux */
 
        if ((len > 0) && (len < MAX_CLM_BUF_SIZE) && memblock) {
@@ -8368,10 +8452,10 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path)
 exit:
 
        if (memblock) {
-#if defined(LINUX) || defined(linux)
+#if (defined(LINUX) || defined(linux)) && !defined(DHD_LINUX_STD_FW_API)
                dhd_os_close_image1(dhd, memblock);
 #else
-               dhd_free_download_buffer(dhd, memblock, MAX_CLM_BUF_SIZE);
+               dhd_free_download_buffer(dhd, memblock, memblock_len);
 #endif /* LINUX || linux */
        }
 
@@ -8384,7 +8468,11 @@ void dhd_free_download_buffer(dhd_pub_t  *dhd, void *buffer, int length)
 #ifdef CACHE_FW_IMAGES
        return;
 #endif
+#if defined(DHD_LINUX_STD_FW_API)
+       VMFREE(dhd->osh, buffer, length);
+#else
        MFREE(dhd->osh, buffer, length);
+#endif /* DHD_LINUX_STD_FW_API */
 }
 
 #ifdef REPORT_FATAL_TIMEOUTS
@@ -9063,8 +9151,13 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size,
        int32 i = 0;
        uint8 *pfw_id = NULL;
        uint32 fwid = 0;
+#ifdef DHD_LINUX_STD_FW_API
+       int err = 0;
+       const struct firmware *fw = NULL;
+#else
        void *file = NULL;
        int file_len = 0;
+#endif /* DHD_LINUX_STD_FW_API */
        char fwid_str[FWID_STR_LEN];
        uint32 hdr_logstrs_size = 0;
 
@@ -9097,6 +9190,23 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size,
                         *  both logstrs.bin and fw bin
                         */
 
+#ifdef DHD_LINUX_STD_FW_API
+                       err = dhd_os_get_img_fwreq(&fw, st_str_file_path);
+                       if (err < 0) {
+                               DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n",
+                                       err));
+                               goto error;
+                       }
+                       memset(fwid_str, 0, sizeof(fwid_str));
+                       err = memcpy_s(fwid_str, (sizeof(fwid_str) - 1),
+                               &(fw->data[fw->size - (sizeof(fwid_str) - 1)]),
+                               (sizeof(fwid_str) - 1));
+                       if (err) {
+                               DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n",
+                                       __FUNCTION__, err));
+                               goto error;
+                       }
+#else
                        /* read the FWID from fw bin */
                        file = dhd_os_open_image1(NULL, st_str_file_path);
                        if (!file) {
@@ -9119,6 +9229,7 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size,
                                DHD_ERROR(("%s: read fw file failed !\n", __FUNCTION__));
                                goto error;
                        }
+#endif /* DHD_LINUX_STD_FW_API */
                        pfw_id = (uint8 *)bcmstrnstr(fwid_str, sizeof(fwid_str) - 1,
                                        FWID_STR_1, strlen(FWID_STR_1));
                        if (!pfw_id) {
@@ -9156,9 +9267,15 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size,
                        hdr_logstrs_size = hdr->logstrs_size;
 
 error:
+#ifdef DHD_LINUX_STD_FW_API
+                       if (fw) {
+                               dhd_os_close_img_fwreq(fw);
+                       }
+#else
                        if (file) {
                                dhd_os_close_image1(NULL, file);
                        }
+#endif /* DHD_LINUX_STD_FW_API */
                        if (match_fail) {
                                return BCME_DECERR;
                        }
@@ -9223,6 +9340,101 @@ error:
        return BCME_OK;
 } /* dhd_parse_logstrs_file */
 
+#ifdef DHD_LINUX_STD_FW_API
+int dhd_parse_map_file(osl_t *osh, void *ptr, uint32 *ramstart, uint32 *rodata_start,
+               uint32 *rodata_end)
+{
+       char *raw_fmts =  NULL, *raw_fmts_loc = NULL;
+       uint32 read_size = READ_NUM_BYTES, offset = 0;
+       int error = 0;
+       char * cptr = NULL;
+       char c;
+       uint8 count = 0;
+       uint32 size = 0;
+
+       *ramstart = 0;
+       *rodata_start = 0;
+       *rodata_end = 0;
+       size = (uint32)(((struct firmware *)ptr)->size);
+
+       /* Allocate 1 byte more than read_size to terminate it with NULL */
+       raw_fmts = MALLOCZ(osh, read_size + 1);
+       if (raw_fmts == NULL) {
+               DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", __FUNCTION__));
+               goto fail;
+       }
+
+       /* read ram start, rodata_start and rodata_end values from map  file */
+       while (count != ALL_MAP_VAL)
+       {
+               /* Bound check for size before doing memcpy() */
+               if ((offset + read_size) > size) {
+                       read_size = size - offset;
+               }
+
+               error = memcpy_s(raw_fmts, read_size,
+                       (((char *)((struct firmware *)ptr)->data) + offset), read_size);
+               if (error) {
+                       DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n",
+                               __FUNCTION__, error));
+                       goto fail;
+               }
+               /* End raw_fmts with NULL as strstr expects NULL terminated strings */
+               raw_fmts[read_size] = '\0';
+
+               /* Get ramstart address */
+               raw_fmts_loc = raw_fmts;
+               if (!(count & RAMSTART_BIT) &&
+                       (cptr = bcmstrnstr(raw_fmts_loc, read_size, ramstart_str,
+                       strlen(ramstart_str)))) {
+                       cptr = cptr - BYTES_AHEAD_NUM;
+                       sscanf(cptr, "%x %c text_start", ramstart, &c);
+                       count |= RAMSTART_BIT;
+               }
+
+               /* Get ram rodata start address */
+               raw_fmts_loc = raw_fmts;
+               if (!(count & RDSTART_BIT) &&
+                       (cptr = bcmstrnstr(raw_fmts_loc, read_size, rodata_start_str,
+                       strlen(rodata_start_str)))) {
+                       cptr = cptr - BYTES_AHEAD_NUM;
+                       sscanf(cptr, "%x %c rodata_start", rodata_start, &c);
+                       count |= RDSTART_BIT;
+               }
+
+               /* Get ram rodata end address */
+               raw_fmts_loc = raw_fmts;
+               if (!(count & RDEND_BIT) &&
+                       (cptr = bcmstrnstr(raw_fmts_loc, read_size, rodata_end_str,
+                       strlen(rodata_end_str)))) {
+                       cptr = cptr - BYTES_AHEAD_NUM;
+                       sscanf(cptr, "%x %c rodata_end", rodata_end, &c);
+                       count |= RDEND_BIT;
+               }
+
+               if ((offset + read_size) >= size) {
+                       break;
+               }
+
+               memset(raw_fmts, 0, read_size);
+               offset += (read_size - GO_BACK_FILE_POS_NUM_BYTES);
+       }
+
+fail:
+       if (raw_fmts) {
+               MFREE(osh, raw_fmts, read_size + 1);
+               raw_fmts = NULL;
+       }
+       if (count == ALL_MAP_VAL) {
+               return BCME_OK;
+       }
+       else {
+               DHD_ERROR(("%s: readmap error 0X%x \n", __FUNCTION__,
+                               count));
+               return BCME_ERROR;
+       }
+} /* dhd_parse_map_file */
+#else
 int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart, uint32 *rodata_start,
                uint32 *rodata_end)
 {
@@ -9320,6 +9532,7 @@ fail:
        }
 
 } /* dhd_parse_map_file */
+#endif /* DHD_LINUX_STD_FW_API */
 
 #ifdef PCIE_FULL_DONGLE
 int
index 0c623d663ee145b897338a5d757e3ae48269b4d7..5433abd546ab6cffccac53933b1a93058a061b87 100755 (executable)
@@ -67,6 +67,10 @@ uint dump_msg_level = 0;
 #define MAXSZ_BUF              4096
 #define MAXSZ_CONFIG   8192
 
+extern uint wl_reassoc_support;
+#ifdef BTC_WAR
+extern int btc_war;
+#endif /* BTC_WAR */
 #if defined(BCMSDIO) && defined(DYNAMIC_MAX_HDR_READ)
 extern uint firstread;
 #endif
@@ -140,9 +144,9 @@ const chip_name_map_t chip_name_map[] = {
        {BCM4375_CHIP_ID,       5,      DONT_CARE,      "bcm4375b4_pcie_ag",    "ap6275hh3"},
 #endif
 #ifdef BCMDBUS
-       {BCM43143_CHIP_ID,      2,      DONT_CARE,      "bcm43143b0",           ""},
-       {BCM43242_CHIP_ID,      1,      DONT_CARE,      "bcm43242a1_ag",        ""},
-       {BCM43569_CHIP_ID,      2,      DONT_CARE,      "bcm4358u_ag",          "ap62x8"},
+       {BCM43143_CHIP_ID,      2,      DONT_CARE,      "bcm43143b0",                   ""},
+       {BCM43242_CHIP_ID,      1,      DONT_CARE,      "bcm43242a1_ag",                ""},
+       {BCM43569_CHIP_ID,      2,      DONT_CARE,      "bcm4358u_ag",                  "ap62x8"},
 #endif
 };
 
@@ -213,6 +217,91 @@ const chip_cisaddr_map_t chip_cisaddr_map[] = {
 extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
 #endif
 
+#ifdef WL_CFG80211
+bool
+dhd_conf_legacy_chip_check(dhd_pub_t *dhd)
+{
+       uint chip = dhd->conf->chip;
+
+       if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
+                       chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID ||
+                       chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID ||
+                       chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID ||
+                       chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
+                       chip == BCM4371_CHIP_ID ||
+                       chip == BCM43430_CHIP_ID ||
+                       chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID ||
+                       chip == BCM4359_CHIP_ID ||
+                       chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID ||
+                       chip == BCM43569_CHIP_ID) {
+               return true;
+       }
+
+       return false;
+}
+
+bool
+dhd_conf_new_chip_check(dhd_pub_t *dhd)
+{
+       uint chip = dhd->conf->chip;
+
+       if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
+                       chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID ||
+                       chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID ||
+                       chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID ||
+                       chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
+                       chip == BCM4371_CHIP_ID ||
+                       chip == BCM43430_CHIP_ID ||
+                       chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID ||
+                       chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID ||
+                       chip == BCM43569_CHIP_ID) {
+               return false;
+       }
+
+       return true;
+}
+
+bool
+dhd_conf_extsae_chip(dhd_pub_t *dhd)
+{
+       uint chip = dhd->conf->chip;
+
+       if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
+                       chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID ||
+                       chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID ||
+                       chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID ||
+                       chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
+                       chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID ||
+                       chip == BCM43569_CHIP_ID) {
+               return false;
+       }
+
+       return true;
+}
+#endif
+
+#ifdef BCMSDIO
+bool
+dhd_conf_disable_slpauto(dhd_pub_t *dhd)
+{
+       uint chip = dhd->conf->chip;
+
+       if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
+                       chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID ||
+                       chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID ||
+                       chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID ||
+                       chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
+                       chip == BCM4371_CHIP_ID ||
+                       chip == BCM43430_CHIP_ID ||
+                       chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID ||
+                       chip == BCM4359_CHIP_ID) {
+               return false;
+       }
+
+       return true;
+}
+#endif
+
 void
 dhd_conf_free_chip_nv_path_list(wl_chip_nv_path_list_ctrl_t *chip_nv_list)
 {
@@ -691,7 +780,7 @@ dhd_conf_match_chip(dhd_pub_t *dhd, uint ag_type)
        chiprev = dhd->conf->chiprev;
 
        for (i=0; i<sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) {
-               const chip_name_map_trow = &chip_name_map[i];
+               const chip_name_map_t *row = &chip_name_map[i];
                if (row->chip == chip && row->chiprev == chiprev &&
                                (row->ag_type == ag_type ||
                                        ag_type == DONT_CARE || row->ag_type == DONT_CARE)) {
@@ -724,7 +813,7 @@ dhd_conf_match_module(dhd_pub_t *dhd)
 
 #ifdef BCMSDIO
        for (i=0; i<sizeof(module_name_map)/sizeof(module_name_map[0]); i++) {
-               const module_name_map_trow = &module_name_map[i];
+               const module_name_map_t *row = &module_name_map[i];
                if (row->devid == devid && row->chip == chip && row->chiprev == chiprev &&
                                !strcmp(row->module_name, dhd->conf->module_name)) {
                        return row;
@@ -734,7 +823,7 @@ dhd_conf_match_module(dhd_pub_t *dhd)
 
 #ifdef BCMPCIE
        for (i=0; i<sizeof(module_name_map)/sizeof(module_name_map[0]); i++) {
-               const module_name_map_trow = &module_name_map[i];
+               const module_name_map_t *row = &module_name_map[i];
                if (row->devid == devid && row->chip == chip && row->chiprev == chiprev &&
                                row->svid == svid && row->ssid == ssid) {
                        return row;
@@ -746,21 +835,65 @@ dhd_conf_match_module(dhd_pub_t *dhd)
 }
 #endif
 
-int
-dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
+char *
+dhd_conf_get_chip_name(dhd_pub_t *dhd, int ag_type, bool *chip_map_v2)
 {
 #ifdef UPDATE_MODULE_NAME
-       const module_name_map_t* row_module = NULL;
+       const module_name_map_t *row_module = NULL;
+#endif
+       const chip_name_map_t *row_chip = NULL;
+       char *name = NULL;
+
+       *chip_map_v2 = FALSE;
+#ifdef UPDATE_MODULE_NAME
+       row_module = dhd_conf_match_module(dhd);
+       if (row_module && strlen(row_module->chip_name)) {
+               name = row_module->chip_name;
+       } else
+#endif
+       {
+               row_chip = dhd_conf_match_chip(dhd, ag_type);
+               if (row_chip && strlen(row_chip->chip_name)) {
+                       name = row_chip->chip_name;
+               }
+       }
+
+       return name;
+}
+
+char *
+dhd_conf_get_module_name(dhd_pub_t *dhd, int ag_type)
+{
+#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME)
+       const module_name_map_t *row_module = NULL;
+#endif
+       const chip_name_map_t *row_chip = NULL;
+       char *name = NULL;
+       
+#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME)
+       row_module = dhd_conf_match_module(dhd);
+       if (row_module && strlen(row_module->module_name)) {
+               name = row_module->module_name;
+       } else
 #endif
-       const chip_name_map_t* row_chip = NULL;
+       {
+               row_chip = dhd_conf_match_chip(dhd, ag_type);
+               if (row_chip && strlen(row_chip->module_name)) {
+                       name = row_chip->module_name;
+               }
+       }
+
+       return name;
+}
+
+int
+dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
+{
        int fw_type, ag_type;
-       uint chip, chiprev;
-       char *name_ptr;
+       char *name_ptr, *chip_name = NULL;
+       bool chip_map_v2;
        int i;
 
-       chip = dhd->conf->chip;
-       chiprev = dhd->conf->chiprev;
-
        if (fw_path[0] == '\0') {
 #ifdef CONFIG_BCMDHD_FW_PATH
                bcm_strncpy_s(fw_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1);
@@ -811,36 +944,10 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
                fw_type = FW_TYPE_EZMESH;
 #endif /* WLEASYMESH */
 
-       row_chip = dhd_conf_match_chip(dhd, ag_type);
-       if (row_chip && strlen(row_chip->chip_name)) {
-               strcpy(name_ptr, "fw_");
-               strcat(name_ptr, row_chip->chip_name);
-#ifdef BCMUSBDEV_COMPOSITE
-               strcat(name_ptr, "_cusb");
-#endif
-               if (fw_type == FW_TYPE_APSTA)
-                       strcat(name_ptr, "_apsta.bin");
-               else if (fw_type == FW_TYPE_P2P)
-                       strcat(name_ptr, "_p2p.bin");
-               else if (fw_type == FW_TYPE_MESH)
-                       strcat(name_ptr, "_mesh.bin");
-               else if (fw_type == FW_TYPE_EZMESH)
-                       strcat(name_ptr, "_ezmesh.bin");
-               else if (fw_type == FW_TYPE_ES)
-                       strcat(name_ptr, "_es.bin");
-               else if (fw_type == FW_TYPE_MFG)
-                       strcat(name_ptr, "_mfg.bin");
-               else if (fw_type == FW_TYPE_MINIME)
-                       strcat(name_ptr, "_minime.bin");
-               else
-                       strcat(name_ptr, ".bin");
-       }
-
-#ifdef UPDATE_MODULE_NAME
-       row_module = dhd_conf_match_module(dhd);
-       if (row_module && strlen(row_module->chip_name)) {
+       chip_name = dhd_conf_get_chip_name(dhd, ag_type, &chip_map_v2);
+       if (chip_name) {
                strcpy(name_ptr, "fw_");
-               strcat(name_ptr, row_module->chip_name);
+               strcat(name_ptr, chip_name);
 #ifdef BCMUSBDEV_COMPOSITE
                strcat(name_ptr, "_cusb");
 #endif
@@ -861,7 +968,6 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
                else
                        strcat(name_ptr, ".bin");
        }
-#endif
 
        dhd->conf->fw_type = fw_type;
 
@@ -877,17 +983,10 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
 void
 dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path, int ag_type)
 {
-#ifdef UPDATE_MODULE_NAME
-       const module_name_map_t* row_module = NULL;
-#endif
-       const chip_name_map_t* row_chip = NULL;
-       uint chip, chiprev;
-       char *name_ptr;
+       char *name_ptr, *chip_name = NULL;
+       bool chip_map_v2;
        int i;
 
-       chip = dhd->conf->chip;
-       chiprev = dhd->conf->chiprev;
-
        if (clm_path[0] == '\0') {
                CONFIG_MSG("clm path is null\n");
                return;
@@ -904,34 +1003,21 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path, int ag_type)
        }
        name_ptr = &clm_path[i];
 
-       row_chip = dhd_conf_match_chip(dhd, ag_type);
-       if (row_chip && strlen(row_chip->chip_name)) {
+       chip_name = dhd_conf_get_chip_name(dhd, ag_type, &chip_map_v2);
+       if (chip_name) {
                strcpy(name_ptr, "clm_");
-               strcat(name_ptr, row_chip->chip_name);
+               strcat(name_ptr, chip_name);
                strcat(name_ptr, ".blob");
        }
 
-#ifdef UPDATE_MODULE_NAME
-       row_module = dhd_conf_match_module(dhd);
-       if (row_module && strlen(row_module->chip_name)) {
-               strcpy(name_ptr, "clm_");
-               strcat(name_ptr, row_module->chip_name);
-               strcat(name_ptr, ".blob");
-       }
-#endif
-
        CONFIG_TRACE("clm_path=%s\n", clm_path);
 }
 
 void
 dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type)
 {
-#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME)
-       const module_name_map_t* row_module = NULL;
-#endif
-       const chip_name_map_t* row_chip = NULL;
        uint chip, chiprev;
-       char *name_ptr, nv_name[32];
+       char *name_ptr, *module_name = NULL, nv_name[32];
        int i;
 
        chip = dhd->conf->chip;
@@ -959,10 +1045,10 @@ dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type)
        }
        name_ptr = &nv_path[i];
 
-       row_chip = dhd_conf_match_chip(dhd, ag_type);
-       if (row_chip && strlen(row_chip->module_name)) {
+       module_name = dhd_conf_get_module_name(dhd, ag_type);
+       if (module_name) {
                strcpy(name_ptr, "nvram_");
-               strcat(name_ptr, row_chip->module_name);
+               strcat(name_ptr, module_name);
 #ifdef BCMUSBDEV_COMPOSITE
                strcat(name_ptr, "_cusb");
 #endif
@@ -979,26 +1065,17 @@ dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type)
                if (dhd->conf->chip == BCM4359_CHIP_ID) {
                        struct file *fp;
                        // compatible for AP6398S and AP6398SA
-                       fp = filp_open(nv_path, O_RDONLY, 0);
-                       if (IS_ERR(fp)) {
+                       fp = dhd_filp_open(nv_path, O_RDONLY, 0);
+                       if (IS_ERR(fp) || (fp == NULL)) {
                                strcpy(name_ptr, nv_name);
                        } else {
-                               filp_close((struct file *)fp, NULL);
+                               dhd_filp_close((struct file *)fp, NULL);
                        }
                }
 #endif
        }
 #endif
 
-#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME)
-       row_module = dhd_conf_match_module(dhd);
-       if (row_module && strlen(row_module->module_name)) {
-               strcpy(name_ptr, "nvram_");
-               strcat(name_ptr, row_module->module_name);
-               strcat(name_ptr, ".txt");
-       }
-#endif
-
        for (i=0; i<dhd->conf->nv_by_chip.count; i++) {
                if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip &&
                                chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) {
@@ -1039,17 +1116,10 @@ dhd_conf_copy_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_pat
 void
 dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path)
 {
-#ifdef UPDATE_MODULE_NAME
-       const module_name_map_t* row_module = NULL;
-#endif
-       const chip_name_map_t* row_chip = NULL;
-       uint chip, chiprev;
-       char *name_ptr;
+       char *name_ptr, *chip_name = NULL;
+       bool chip_map_v2;
        int i;
 
-       chip = dhd->conf->chip;
-       chiprev = dhd->conf->chiprev;
-
        if (conf_path[0] == '\0') {
                CONFIG_MSG("config path is null\n");
                return;
@@ -1066,21 +1136,12 @@ dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path)
        }
        name_ptr = &conf_path[i];
 
-       row_chip = dhd_conf_match_chip(dhd, DONT_CARE);
-       if (row_chip && strlen(row_chip->chip_name)) {
-               strcpy(name_ptr, "config_");
-               strcat(name_ptr, row_chip->chip_name);
-               strcat(name_ptr, ".txt");
-       }
-
-#ifdef UPDATE_MODULE_NAME
-       row_module = dhd_conf_match_module(dhd);
-       if (row_module && strlen(row_module->chip_name)) {
+       chip_name = dhd_conf_get_chip_name(dhd, DONT_CARE, &chip_map_v2);
+       if (chip_name) {
                strcpy(name_ptr, "config_");
-               strcat(name_ptr, row_module->chip_name);
+               strcat(name_ptr, chip_name);
                strcat(name_ptr, ".txt");
        }
-#endif
 
        CONFIG_TRACE("config_path=%s\n", conf_path);
 }
@@ -1147,7 +1208,10 @@ dhd_conf_set_tput_patch(dhd_pub_t *dhd)
 
        if (conf->tput_patch) {
                conf->mtu = 1500;
-               conf->pktsetsum = TRUE;
+/* set pktsetsum false by default since this will cause to
+  * the checksum is wrong of downloaded file
+*/
+               conf->pktsetsum = FALSE;
 #ifdef BCMSDIO
                conf->dhd_dpc_prio = 98;
 /* need to check if CPU can support multi-core first,
@@ -1252,6 +1316,70 @@ dhd_conf_dump_tput_patch(dhd_pub_t *dhd)
 }
 #endif /* DHD_TPUT_PATCH */
 
+#ifdef DHD_LINUX_STD_FW_API
+#define FIRMWARE_CLASS_PATH "/sys/module/firmware_class/parameters/path"
+static void
+dhd_conf_get_filename(char *pFilename)
+{
+       const char *pName = NULL;
+
+       if ((pFilename) && (*pFilename)) {
+               // back/reverse search the '/'
+               pName = strrchr(pFilename, '/');
+               if (NULL == pName) {
+                       pName = pFilename;
+               } else {
+                       if (pName[1]) {
+                               pName++;
+                       } else {
+                               pName = NULL;
+                       }
+               }
+       }
+
+       if (pName)
+               strcpy(pFilename, pName);
+
+       return;
+}
+
+static void
+dhd_conf_add_filepath(dhd_pub_t *dhd, char *pFilename)
+{
+       char path[WLC_IOCTL_SMLEN];
+       char *name_ptr, *module_name = NULL;
+
+       if (strlen(pFilename)) {
+               name_ptr = path;
+               strcpy(name_ptr, "");
+#ifdef FW_AMPAK_PATH
+               strcat(name_ptr, "/");
+               strcat(name_ptr, FW_AMPAK_PATH);
+#endif
+#ifdef MODULE_PATH
+#if defined(BCMSDIO) && defined(GET_OTP_MODULE_NAME)
+               if (strlen(dhd->conf->module_name))
+                       module_name = dhd->conf->module_name;
+               else
+#endif
+               {
+                       module_name = dhd_conf_get_module_name(dhd, DONT_CARE);
+               }
+#endif
+               if (module_name) {
+                       strcat(name_ptr, "/");
+                       strcat(name_ptr, module_name);
+               }
+               strcat(name_ptr, "/");
+               strcat(name_ptr, pFilename);
+               strcpy(pFilename, path);
+       }
+
+       return;
+}
+
+#endif /* DHD_LINUX_STD_FW_API */
+
 void
 dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path)
 {
@@ -1260,6 +1388,14 @@ dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path)
        /* External conf takes precedence if specified */
        dhd_conf_preinit(dhd);
 
+#ifdef DHD_LINUX_STD_FW_API
+       // preprocess the filename to only left 'name'
+       dhd_conf_get_filename(fw_path);
+       dhd_conf_get_filename(nv_path);
+       dhd_conf_get_filename(dhd->clm_path);
+       dhd_conf_get_filename(dhd->conf_path);
+#endif
+
        if (dhd->conf_path[0] == '\0') {
                dhd_conf_copy_path(dhd, "config.txt", dhd->conf_path, nv_path);
        }
@@ -1270,11 +1406,6 @@ dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path)
        dhd_conf_set_conf_name_by_chip(dhd, dhd->conf_path);
 #endif
 
-       dhd_conf_read_config(dhd, dhd->conf_path);
-#ifdef DHD_TPUT_PATCH
-       dhd_conf_dump_tput_patch(dhd);
-#endif
-
        ag_type = dhd_conf_set_fw_name_by_chip(dhd, fw_path);
        dhd_conf_set_nv_name_by_chip(dhd, nv_path, ag_type);
        dhd_conf_set_clm_name_by_chip(dhd, dhd->clm_path, ag_type);
@@ -1283,10 +1414,23 @@ dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path)
        dhd_conf_set_nv_name_by_mac(dhd, nv_path);
 #endif
 
+#ifdef DHD_LINUX_STD_FW_API
+       // preprocess the filename to only left 'name'
+       dhd_conf_add_filepath(dhd, fw_path);
+       dhd_conf_add_filepath(dhd, nv_path);
+       dhd_conf_add_filepath(dhd, dhd->clm_path);
+       dhd_conf_add_filepath(dhd, dhd->conf_path);
+#endif
+
        CONFIG_MSG("Final fw_path=%s\n", fw_path);
        CONFIG_MSG("Final nv_path=%s\n", nv_path);
        CONFIG_MSG("Final clm_path=%s\n", dhd->clm_path);
        CONFIG_MSG("Final conf_path=%s\n", dhd->conf_path);
+
+       dhd_conf_read_config(dhd, dhd->conf_path);
+#ifdef DHD_TPUT_PATCH
+       dhd_conf_dump_tput_patch(dhd);
+#endif
 }
 
 int
@@ -1298,17 +1442,17 @@ dhd_conf_set_intiovar(dhd_pub_t *dhd, int ifidx, uint cmd, char *name, int val,
 
        if (val >= def) {
                if (down) {
-                       if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0)
+                       if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, ifidx)) < 0)
                                CONFIG_ERROR("WLC_DOWN setting failed %d\n", ret);
                }
                if (cmd == WLC_SET_VAR) {
                        CONFIG_TRACE("set %s %d\n", name, val);
                        bcm_mkiovar(name, (char *)&val, sizeof(val), iovbuf, sizeof(iovbuf));
-                       if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+                       if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx)) < 0)
                                CONFIG_ERROR("%s setting failed %d\n", name, ret);
                } else {
                        CONFIG_TRACE("set %s %d %d\n", name, cmd, val);
-                       if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0)
+                       if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, ifidx)) < 0)
                                CONFIG_ERROR("%s setting failed %d\n", name, ret);
                }
        }
@@ -1404,13 +1548,147 @@ dhd_conf_get_iovar(dhd_pub_t *dhd, int ifidx, int cmd, char *name,
                } else {
                        CONFIG_ERROR("mkiovar %s failed\n", name);
                }
-       } else {
-               ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, FALSE, 0);
-               if (ret < 0)
-                       CONFIG_ERROR("get iovar %s failed %d\n", name, ret);
+       } else {
+               ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, FALSE, 0);
+               if (ret < 0)
+                       CONFIG_ERROR("get iovar %s failed %d\n", name, ret);
+       }
+
+       return ret;
+}
+
+static int
+dhd_conf_get_ioctl_ver(dhd_pub_t *dhd)
+{
+       int ret = 0;
+       s32 val = 0;
+
+       dhd->conf->ioctl_ver = WLC_IOCTL_VERSION;
+       ret = dhd_conf_get_iovar(dhd, 0, WLC_GET_VERSION, "WLC_GET_VERSION",
+               (char *)&val, sizeof(val));
+       if (ret) {
+               return ret;
+       }
+       val = dtoh32(val);
+       if (val != WLC_IOCTL_VERSION && val != 1) {
+               CONFIG_ERROR("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
+                       val, WLC_IOCTL_VERSION);
+               return BCME_VERSION;
+       }
+       dhd->conf->ioctl_ver = val;
+       CONFIG_TRACE("ioctl_ver=%d\n", dhd->conf->ioctl_ver);
+
+       return ret;
+}
+
+int
+dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec)
+{
+       int bcmerror = -1;
+
+       memset(cspec, 0, sizeof(wl_country_t));
+       bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t));
+       if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t),
+                       FALSE, 0)) < 0)
+               CONFIG_ERROR("country code getting failed %d\n", bcmerror);
+
+       return bcmerror;
+}
+
+int
+dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec)
+{
+       int bcmerror = -1;
+       struct dhd_conf *conf = dhd->conf;
+       country_list_t *country = conf->country_head;
+
+#ifdef CCODE_LIST
+       bcmerror = dhd_ccode_map_country_list(dhd, cspec);
+#endif
+       // **:XZ/11 => return XZ/11 if not found
+       // **:**/0 => return user specified ccode if not found, but set regrev 0
+       while (country != NULL) {
+               if (!strncmp("**", country->cspec.country_abbrev, 2)) {
+                       if (!strncmp("**", country->cspec.ccode, 2)) {
+                               cspec->rev = 0;
+                               bcmerror = 0;
+                               break;
+                       }
+                       memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ);
+                       cspec->rev = country->cspec.rev;
+                       bcmerror = 0;
+                       break;
+               } else if (!strncmp(cspec->country_abbrev,
+                               country->cspec.country_abbrev, 2)) {
+                       memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ);
+                       cspec->rev = country->cspec.rev;
+                       bcmerror = 0;
+                       break;
+               }
+               country = country->next;
+       }
+
+       if (!bcmerror)
+               CONFIG_MSG("%s/%d\n", cspec->ccode, cspec->rev);
+
+       return bcmerror;
+}
+
+int
+dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec)
+{
+       int bcmerror = -1;
+
+       memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t));
+
+       CONFIG_MSG("set country %s, revision %d\n", cspec->ccode, cspec->rev);
+       bcmerror = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "country", (char *)cspec,
+               sizeof(wl_country_t), FALSE);
+       dhd_conf_get_country(dhd, cspec);
+       CONFIG_MSG("Country code: %s (%s/%d)\n",
+               cspec->country_abbrev, cspec->ccode, cspec->rev);
+
+       return bcmerror;
+}
+
+int
+dhd_conf_fix_country(dhd_pub_t *dhd)
+{
+       int bcmerror = -1;
+       int band;
+       wl_uint32_list_t *list;
+       u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
+       wl_country_t cspec;
+
+       if (!(dhd && dhd->conf)) {
+               return bcmerror;
+       }
+
+       memset(valid_chan_list, 0, sizeof(valid_chan_list));
+       list = (wl_uint32_list_t *)(void *) valid_chan_list;
+       list->count = htod32(WL_NUMCHANNELS);
+       if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, valid_chan_list,
+                       sizeof(valid_chan_list), FALSE, 0)) < 0) {
+               CONFIG_ERROR("get channels failed with %d\n", bcmerror);
+       }
+
+       band = dhd_conf_get_band(dhd);
+
+       if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G || band==-1) &&
+                       dtoh32(list->count)<11)) {
+               CONFIG_ERROR("bcmerror=%d, # of channels %d\n",
+                       bcmerror, dtoh32(list->count));
+               dhd_conf_map_country_list(dhd, &dhd->conf->cspec);
+               if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) {
+                       strcpy(cspec.country_abbrev, "US");
+                       cspec.rev = 0;
+                       strcpy(cspec.ccode, "US");
+                       dhd_conf_map_country_list(dhd, &cspec);
+                       dhd_conf_set_country(dhd, &cspec);
+               }
        }
 
-       return ret;
+       return bcmerror;
 }
 
 static int
@@ -1620,6 +1898,34 @@ dhd_conf_scan_mac(dhd_pub_t * dhd, char *cmd, char *buf)
 }
 #endif
 
+int
+dhd_conf_country(dhd_pub_t *dhd, char *cmd, char *buf)
+{
+       wl_country_t cspec = {{0}, 0, {0}};
+       wl_country_t cur_cspec = {{0}, 0, {0}};
+       int err = 0;
+
+       if (buf) {
+               dhd_conf_get_country(dhd, &cur_cspec);
+               strlcpy(cspec.country_abbrev, buf, WL_CCODE_LEN + 1);
+               strlcpy(cspec.ccode, buf, WL_CCODE_LEN + 1);
+               dhd_conf_map_country_list(dhd, &cspec);
+               if (!memcmp(&cspec.ccode, &cur_cspec.ccode, WL_CCODE_LEN + 1) &&
+                               (cspec.rev == cur_cspec.rev)) {
+                       CONFIG_MSG("country code = %s/%d is already configured\n",
+                               cspec.ccode, cspec.rev);
+                       return 0;
+               }
+               err = dhd_conf_set_country(dhd, &cspec);
+               if (!err) {
+                       dhd_conf_fix_country(dhd);
+               }
+               dhd_conf_get_country(dhd, &dhd->dhd_cspec);
+       }
+
+       return err;
+}
+
 typedef int (tpl_parse_t)(dhd_pub_t *dhd, char *name, char *buf);
 
 typedef struct iovar_tpl_t {
@@ -1635,6 +1941,7 @@ const iovar_tpl_t iovar_tpl_list[] = {
 #ifndef SUPPORT_RANDOM_MAC_SCAN
        {WLC_SET_VAR,   "scanmac",              dhd_conf_scan_mac},
 #endif
+       {WLC_SET_VAR,   "country",              dhd_conf_country},
 };
 
 static int iovar_tpl_parse(const iovar_tpl_t *tpl, int tpl_count,
@@ -1725,116 +2032,6 @@ dhd_conf_get_band(dhd_pub_t *dhd)
        return band;
 }
 
-int
-dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec)
-{
-       int bcmerror = -1;
-
-       memset(cspec, 0, sizeof(wl_country_t));
-       bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t));
-       if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t),
-                       FALSE, 0)) < 0)
-               CONFIG_ERROR("country code getting failed %d\n", bcmerror);
-
-       return bcmerror;
-}
-
-int
-dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec)
-{
-       int bcmerror = -1;
-       struct dhd_conf *conf = dhd->conf;
-       country_list_t *country = conf->country_head;
-
-#ifdef CCODE_LIST
-       bcmerror = dhd_ccode_map_country_list(dhd, cspec);
-#endif
-       // **:XZ/11 => return XZ/11 if not found
-       // **:**/0 => return user specified ccode if not found, but set regrev 0
-       while (country != NULL) {
-               if (!strncmp("**", country->cspec.country_abbrev, 2)) {
-                       if (!strncmp("**", country->cspec.ccode, 2)) {
-                               cspec->rev = 0;
-                               bcmerror = 0;
-                               break;
-                       }
-                       memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ);
-                       cspec->rev = country->cspec.rev;
-                       bcmerror = 0;
-                       break;
-               } else if (!strncmp(cspec->country_abbrev,
-                               country->cspec.country_abbrev, 2)) {
-                       memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ);
-                       cspec->rev = country->cspec.rev;
-                       bcmerror = 0;
-                       break;
-               }
-               country = country->next;
-       }
-
-       if (!bcmerror)
-               CONFIG_MSG("%s/%d\n", cspec->ccode, cspec->rev);
-
-       return bcmerror;
-}
-
-int
-dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec)
-{
-       int bcmerror = -1;
-
-       memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t));
-
-       CONFIG_MSG("set country %s, revision %d\n", cspec->ccode, cspec->rev);
-       bcmerror = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "country", (char *)cspec,
-               sizeof(wl_country_t), FALSE);
-       dhd_conf_get_country(dhd, cspec);
-       CONFIG_MSG("Country code: %s (%s/%d)\n",
-               cspec->country_abbrev, cspec->ccode, cspec->rev);
-
-       return bcmerror;
-}
-
-int
-dhd_conf_fix_country(dhd_pub_t *dhd)
-{
-       int bcmerror = -1;
-       int band;
-       wl_uint32_list_t *list;
-       u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
-       wl_country_t cspec;
-
-       if (!(dhd && dhd->conf)) {
-               return bcmerror;
-       }
-
-       memset(valid_chan_list, 0, sizeof(valid_chan_list));
-       list = (wl_uint32_list_t *)(void *) valid_chan_list;
-       list->count = htod32(WL_NUMCHANNELS);
-       if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, valid_chan_list,
-                       sizeof(valid_chan_list), FALSE, 0)) < 0) {
-               CONFIG_ERROR("get channels failed with %d\n", bcmerror);
-       }
-
-       band = dhd_conf_get_band(dhd);
-
-       if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G || band==-1) &&
-                       dtoh32(list->count)<11)) {
-               CONFIG_ERROR("bcmerror=%d, # of channels %d\n",
-                       bcmerror, dtoh32(list->count));
-               dhd_conf_map_country_list(dhd, &dhd->conf->cspec);
-               if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) {
-                       strcpy(cspec.country_abbrev, "US");
-                       cspec.rev = 0;
-                       strcpy(cspec.ccode, "US");
-                       dhd_conf_map_country_list(dhd, &cspec);
-                       dhd_conf_set_country(dhd, &cspec);
-               }
-       }
-
-       return bcmerror;
-}
-
 bool
 dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel)
 {
@@ -1857,39 +2054,39 @@ dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel)
 }
 
 int
-dhd_conf_set_roam(dhd_pub_t *dhd)
+dhd_conf_set_roam(dhd_pub_t *dhd, int ifidx)
 {
        int bcmerror = -1;
        struct dhd_conf *conf = dhd->conf;
        uint wnm_bsstrans_resp = 0;
 
        if (dhd->conf->chip == BCM4359_CHIP_ID) {
-               dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "wnm_bsstrans_resp",
+               dhd_conf_get_iovar(dhd, ifidx, WLC_GET_VAR, "wnm_bsstrans_resp",
                        (char *)&wnm_bsstrans_resp, sizeof(wnm_bsstrans_resp));
                if (wnm_bsstrans_resp == WL_BSSTRANS_POLICY_PRODUCT) {
                        dhd->wbtext_policy = WL_BSSTRANS_POLICY_ROAM_ALWAYS;
-                       dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "wnm_bsstrans_resp",
+                       dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wnm_bsstrans_resp",
                                WL_BSSTRANS_POLICY_ROAM_ALWAYS, 0, FALSE);
                }
        }
 
        dhd_roam_disable = conf->roam_off;
-       dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "roam_off", dhd->conf->roam_off, 0, FALSE);
+       dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "roam_off", dhd->conf->roam_off, 0, FALSE);
 
        if (!conf->roam_off || !conf->roam_off_suspend) {
                CONFIG_MSG("set roam_trigger %d\n", conf->roam_trigger[0]);
-               dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_TRIGGER, "WLC_SET_ROAM_TRIGGER",
+               dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_ROAM_TRIGGER, "WLC_SET_ROAM_TRIGGER",
                        (char *)conf->roam_trigger, sizeof(conf->roam_trigger), FALSE);
 
                CONFIG_MSG("set roam_scan_period %d\n", conf->roam_scan_period[0]);
-               dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_SCAN_PERIOD, "WLC_SET_ROAM_SCAN_PERIOD",
+               dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_ROAM_SCAN_PERIOD, "WLC_SET_ROAM_SCAN_PERIOD",
                        (char *)conf->roam_scan_period, sizeof(conf->roam_scan_period), FALSE);
 
                CONFIG_MSG("set roam_delta %d\n", conf->roam_delta[0]);
-               dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_DELTA, "WLC_SET_ROAM_DELTA",
+               dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_ROAM_DELTA, "WLC_SET_ROAM_DELTA",
                        (char *)conf->roam_delta, sizeof(conf->roam_delta), FALSE);
 
-               dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "fullroamperiod",
+               dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "fullroamperiod",
                        dhd->conf->fullroamperiod, 1, FALSE);
        }
 
@@ -2184,9 +2381,8 @@ dhd_conf_add_pkt_filter(dhd_pub_t *dhd)
         * Case 3: magic pkt and event wake up
         *   1) dhd_master_mode=1
         *   2) pkt_filter_delete=100, 102, 103, 104, 105, 106, 107
-        *   3) pkt_filter_add=141 0 0 0 0xFFFFFFFFFFFF 0x000000000000
-        *   4) magic_pkt_filter_add=141 0 1 12
-        *   5) rekey_offload=1
+        *   3) magic_pkt_filter_add=141 0 1 12
+        *   4) rekey_offload=1
         */
        for(i=0; i<dhd->conf->pkt_filter_add.count; i++) {
                dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i];
@@ -2525,7 +2721,7 @@ int
 dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period,
        char *packet, bool bcast)
 {
-       wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
+       wl_mkeep_alive_pkt_v1_t *mkeep_alive_pktp;
        int ret = 0, len_bytes=0, buf_len=0;
        char *buf = NULL, *iovar_buf = NULL;
        uint8 *pdata;
@@ -2542,8 +2738,8 @@ dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period,
                        CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
                        goto exit;
                }
-               mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf;
-               mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION);
+               mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *)buf;
+               mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION_1);
                mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
                mkeep_alive_pktp->keep_alive_id = id;
                buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
@@ -2786,7 +2982,7 @@ dhd_conf_suspend_resume_sta(dhd_pub_t *dhd, int ifidx, int suspend)
 #endif
        }
        else {
-               dhd_conf_get_iovar(dhd, 0, WLC_GET_PM, "WLC_GET_PM", (char *)&pm, sizeof(pm));
+               dhd_conf_get_iovar(dhd, ifidx, WLC_GET_PM, "WLC_GET_PM", (char *)&pm, sizeof(pm));
                CONFIG_TRACE("PM in suspend = %d\n", pm);
                if (conf->pm >= 0)
                        pm = conf->pm;
@@ -3436,7 +3632,15 @@ dhd_conf_read_roam_params(dhd_pub_t *dhd, char *full_param, uint len_param)
        else if (!strncmp("fullroamperiod=", full_param, len_param)) {
                conf->fullroamperiod = (int)simple_strtol(data, NULL, 10);
                CONFIG_MSG("fullroamperiod = %d\n", conf->fullroamperiod);
-       } else
+       }
+       else if (!strncmp("wl_reassoc_support=", full_param, len_param)) {
+               if (!strncmp(data, "0", 1))
+                       wl_reassoc_support = FALSE;
+               else
+                       wl_reassoc_support = TRUE;
+               CONFIG_MSG("wl_reassoc_support = %d\n", wl_reassoc_support);
+       }
+       else
                return false;
 
        return true;
@@ -3775,11 +3979,10 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
                        dhd_doflow = TRUE;
                CONFIG_MSG("dhd_doflow = %d\n", dhd_doflow);
        }
-       else if (!strncmp("dhd_slpauto=", full_param, len_param) ||
-                       !strncmp("kso_enable=", full_param, len_param)) {
+       else if (!strncmp("dhd_slpauto=", full_param, len_param)) {
                if (!strncmp(data, "0", 1))
                        dhd_slpauto = FALSE;
-               else
+               else if (dhd_conf_disable_slpauto(dhd))
                        dhd_slpauto = TRUE;
                CONFIG_MSG("dhd_slpauto = %d\n", dhd_slpauto);
        }
@@ -3947,6 +4150,10 @@ dhd_conf_read_pcie_params(dhd_pub_t *dhd, char *full_param, uint len_param)
                conf->d2h_intr_control = (int)simple_strtol(data, NULL, 10);
                CONFIG_MSG("d2h_intr_control = %d\n", conf->d2h_intr_control);
        }
+       else if (!strncmp("enq_hdr_pkt=", full_param, len_param)) {
+               conf->enq_hdr_pkt = (int)simple_strtol(data, NULL, 0);
+               CONFIG_MSG("enq_hdr_pkt = 0x%x\n", conf->enq_hdr_pkt);
+       }
        else
                return false;
 
@@ -4189,6 +4396,12 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
                conf->in4way = (int)simple_strtol(data, NULL, 0);
                CONFIG_MSG("in4way = 0x%x\n", conf->in4way);
        }
+#ifdef BTC_WAR
+       else if (!strncmp("btc_war=", full_param, len_param)) {
+               btc_war = (int)simple_strtol(data, NULL, 0);
+               CONFIG_MSG("btc_war = 0x%x\n", btc_war);
+       }
+#endif /* BTC_WAR */
        else if (!strncmp("war=", full_param, len_param)) {
                conf->war = (int)simple_strtol(data, NULL, 0);
                CONFIG_MSG("war = 0x%x\n", conf->war);
@@ -4376,33 +4589,37 @@ int
 dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path)
 {
        int bcmerror = -1, chip_match = -1;
-       uint len = 0, start_pos=0, end_pos=0;
-       void *image = NULL;
+       uint len = 0, memblock_len = 0, start_pos=0, end_pos=0;
        char *memblock = NULL;
        char *bufp, *pick = NULL, *pch;
        bool conf_file_exists;
        uint len_param;
 
+       len = MAXSZ_CONFIG;
+
        conf_file_exists = ((conf_path != NULL) && (conf_path[0] != '\0'));
        if (!conf_file_exists) {
                CONFIG_MSG("config path %s\n", conf_path);
                return (0);
        }
 
-       if (conf_file_exists) {
-               image = dhd_os_open_image1(dhd, conf_path);
-               if (image == NULL) {
-                       CONFIG_MSG("Ignore config file %s\n", conf_path);
-                       goto err;
-               }
-       }
+       if (conf_file_exists)
+               bcmerror = dhd_get_download_buffer(dhd, conf_path, NVRAM, &memblock,
+                       (int *)&len);
+       else
+               bcmerror = dhd_get_download_buffer(dhd, NULL, NVRAM, &memblock, (int *)&len);
 
-       memblock = MALLOC(dhd->osh, MAXSZ_CONFIG);
-       if (memblock == NULL) {
-               CONFIG_ERROR("Failed to allocate memory %d bytes\n", MAXSZ_CONFIG);
+       if (bcmerror != BCME_OK) {
+               CONFIG_MSG("Ignore config file %s\n", conf_path);
                goto err;
        }
 
+#ifdef DHD_LINUX_STD_FW_API
+       memblock_len = len;
+#else
+       memblock_len = MAXSZ_CONFIG;
+#endif /* DHD_LINUX_STD_FW_API */
+
        pick = MALLOC(dhd->osh, MAXSZ_BUF);
        if (!pick) {
                CONFIG_ERROR("Failed to allocate memory %d bytes\n", MAXSZ_BUF);
@@ -4410,9 +4627,6 @@ dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path)
        }
 
        /* Read variables */
-       if (conf_file_exists) {
-               len = dhd_os_get_image_block(memblock, MAXSZ_CONFIG, image);
-       }
        if (len > 0 && len < MAXSZ_CONFIG) {
                bufp = (char *)memblock;
                bufp[len] = 0;
@@ -4496,10 +4710,7 @@ err:
                MFREE(dhd->osh, pick, MAXSZ_BUF);
 
        if (memblock)
-               MFREE(dhd->osh, memblock, MAXSZ_CONFIG);
-
-       if (image)
-               dhd_os_close_image1(dhd, image);
+               dhd_free_download_buffer(dhd, memblock, memblock_len);
 
        return bcmerror;
 }
@@ -4630,7 +4841,7 @@ dhd_conf_compat_vht(dhd_pub_t *dhd)
 int
 dhd_conf_compat_func(dhd_pub_t *dhd)
 {
-       const module_name_map_trow = NULL;
+       const module_name_map_t *row = NULL;
 
        row = dhd_conf_match_module(dhd);
        if (row && row->compat_func) {
@@ -4641,29 +4852,45 @@ dhd_conf_compat_func(dhd_pub_t *dhd)
 }
 #endif
 
+void
+dhd_conf_preinit_ioctls_sta(dhd_pub_t *dhd, int ifidx)
+{
+       struct dhd_conf *conf = dhd->conf;
+       int pm;
+
+       dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE);
+#ifdef NO_POWER_SAVE
+       pm = PM_OFF;
+#else
+       if (conf->pm >= 0)
+               pm = conf->pm;
+       else
+               pm = PM_FAST;
+#endif
+       dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE);
+       dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "assoc_retry_max", 10, 0, FALSE);
+       dhd_conf_set_roam(dhd, ifidx);
+}
+
 void
 dhd_conf_postinit_ioctls(dhd_pub_t *dhd)
 {
        struct dhd_conf *conf = dhd->conf;
-       char wl_preinit[] = "assoc_retry_max=10";
+       char wl_preinit[] = "";
 #ifdef NO_POWER_SAVE
        char wl_no_power_save[] = "mpc=0, 86=0";
        dhd_conf_set_wl_cmd(dhd, wl_no_power_save, FALSE);
 #endif
 
+       dhd_conf_get_ioctl_ver(dhd);
        dhd_conf_set_intiovar(dhd, 0, WLC_UP, "WLC_UP", 0, 0, FALSE);
-       dhd_conf_map_country_list(dhd, &conf->cspec);
-       dhd_conf_set_country(dhd, &conf->cspec);
-       dhd_conf_fix_country(dhd);
-       dhd_conf_get_country(dhd, &dhd->dhd_cspec);
+       dhd_conf_country(dhd, "country", conf->cspec.country_abbrev);
 
        dhd_conf_set_intiovar(dhd, 0, WLC_SET_BAND, "WLC_SET_BAND", conf->band, 0, FALSE);
-       dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE);
-       dhd_conf_set_intiovar(dhd, 0, WLC_SET_PM, "WLC_SET_PM", conf->pm, 0, FALSE);
        dhd_conf_set_intiovar(dhd, 0, WLC_SET_SRL, "WLC_SET_SRL", conf->srl, 0, FALSE);
        dhd_conf_set_intiovar(dhd, 0, WLC_SET_LRL, "WLC_SET_LRL", conf->lrl, 0, FALSE);
        dhd_conf_set_bw_cap(dhd);
-       dhd_conf_set_roam(dhd);
+       dhd_conf_set_roam(dhd, 0);
 
 #if defined(BCMPCIE)
        dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "bus:deepsleep_disable",
@@ -4689,10 +4916,10 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd)
        dhd_conf_set_intiovar(dhd, 0, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG",
                conf->frameburst, 0, FALSE);
 
+       dhd_conf_preinit_ioctls_sta(dhd, 0);
        dhd_conf_set_wl_cmd(dhd, wl_preinit, TRUE);
 #if defined(BCMSDIO)
-       if (conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID ||
-                       conf->chip == BCM4375_CHIP_ID) {
+       if (conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID) {
                char ampdu_mpdu[] = "ampdu_mpdu=32";
                dhd_conf_set_wl_cmd(dhd, ampdu_mpdu, TRUE);
        } else {
@@ -4720,6 +4947,12 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd)
                char txack_alive[] = "txack_alive=0";
                dhd_conf_set_wl_cmd(dhd, txack_alive, TRUE);
        }
+#ifdef WLDWDS
+       {
+               char dwds[] = "dwds=1";
+               dhd_conf_set_wl_cmd(dhd, dwds, TRUE);
+       }
+#endif /* WLDWDS */
 #if defined(WLEASYMESH)
        if (conf->fw_type == FW_TYPE_EZMESH) {
                if (conf->chip == BCM4359_CHIP_ID) {
@@ -4759,13 +4992,11 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd)
 
 }
 
-int
-dhd_conf_preinit(dhd_pub_t *dhd)
+void
+dhd_conf_free_preinit(dhd_pub_t *dhd)
 {
        struct dhd_conf *conf = dhd->conf;
 
-       CONFIG_TRACE("Enter\n");
-
 #ifdef SET_FWNV_BY_MAC
        dhd_conf_free_mac_list(&conf->fw_by_mac);
        dhd_conf_free_mac_list(&conf->nv_by_mac);
@@ -4795,13 +5026,24 @@ dhd_conf_preinit(dhd_pub_t *dhd)
                kfree(conf->vndr_ie_assocreq);
                conf->vndr_ie_assocreq = NULL;
        }
+}
+
+int
+dhd_conf_preinit(dhd_pub_t *dhd)
+{
+       struct dhd_conf *conf = dhd->conf;
+
+       CONFIG_TRACE("Enter\n");
+
+       dhd_conf_free_preinit(dhd);
        conf->band = -1;
        memset(&conf->bw_cap, -1, sizeof(conf->bw_cap));
        if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) {
                strcpy(conf->cspec.country_abbrev, "ALL");
                strcpy(conf->cspec.ccode, "ALL");
                conf->cspec.rev = 0;
-       } else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||
+       }
+       else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||
                        conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
                        conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||
                        conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID ||
@@ -4809,12 +5051,14 @@ dhd_conf_preinit(dhd_pub_t *dhd)
                strcpy(conf->cspec.country_abbrev, "CN");
                strcpy(conf->cspec.ccode, "CN");
                conf->cspec.rev = 38;
-       } else {
+       }
+       else {
                strcpy(conf->cspec.country_abbrev, "CN");
                strcpy(conf->cspec.ccode, "CN");
                conf->cspec.rev = 0;
        }
        memset(&conf->channels, 0, sizeof(wl_channel_list_t));
+       conf->ioctl_ver = WLC_IOCTL_VERSION;
        conf->roam_off = 1;
        conf->roam_off_suspend = 1;
        conf->roam_trigger[0] = -65;
@@ -4879,6 +5123,7 @@ dhd_conf_preinit(dhd_pub_t *dhd)
        conf->flow_ring_queue_threshold = FLOW_RING_QUEUE_THRESHOLD;
        conf->d2h_intr_method = -1;
        conf->d2h_intr_control = -1;
+       conf->enq_hdr_pkt = 0;
 #endif
        conf->dpc_cpucore = -1;
        conf->rxf_cpucore = -1;
@@ -5058,9 +5303,7 @@ dhd_conf_preinit(dhd_pub_t *dhd)
        init_waitqueue_head(&conf->event_complete);
 
 #if defined(BCMSDIO) && defined(CUSTOMER_HW_AMLOGIC)
-       if (conf->chip != BCM43752_CHIP_ID) {
-               dhd_slpauto = FALSE;
-       }
+       dhd_slpauto = dhd_conf_disable_slpauto(dhd);
        conf->txglom_mode = SDPCM_TXGLOM_CPY;
        conf->rekey_offload = TRUE;
 #endif
@@ -5073,35 +5316,7 @@ dhd_conf_reset(dhd_pub_t *dhd)
 {
        struct dhd_conf *conf = dhd->conf;
 
-#ifdef SET_FWNV_BY_MAC
-       dhd_conf_free_mac_list(&conf->fw_by_mac);
-       dhd_conf_free_mac_list(&conf->nv_by_mac);
-#endif
-       dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
-       dhd_conf_free_country_list(conf);
-       dhd_conf_free_mchan_list(conf);
-#ifdef PKT_FILTER_SUPPORT
-       if (conf->magic_pkt_filter_add) {
-               kfree(conf->magic_pkt_filter_add);
-               conf->magic_pkt_filter_add = NULL;
-       }
-#endif
-       if (conf->wl_preinit) {
-               kfree(conf->wl_preinit);
-               conf->wl_preinit = NULL;
-       }
-       if (conf->wl_suspend) {
-               kfree(conf->wl_suspend);
-               conf->wl_suspend = NULL;
-       }
-       if (conf->wl_resume) {
-               kfree(conf->wl_resume);
-               conf->wl_resume = NULL;
-       }
-       if (conf->vndr_ie_assocreq) {
-               kfree(conf->vndr_ie_assocreq);
-               conf->vndr_ie_assocreq = NULL;
-       }
+       dhd_conf_free_preinit(dhd);
        memset(conf, 0, sizeof(dhd_conf_t));
        return 0;
 }
@@ -5141,35 +5356,7 @@ dhd_conf_detach(dhd_pub_t *dhd)
 
        CONFIG_TRACE("Enter\n");
        if (dhd->conf) {
-#ifdef SET_FWNV_BY_MAC
-               dhd_conf_free_mac_list(&conf->fw_by_mac);
-               dhd_conf_free_mac_list(&conf->nv_by_mac);
-#endif
-               dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
-               dhd_conf_free_country_list(conf);
-               dhd_conf_free_mchan_list(conf);
-#ifdef PKT_FILTER_SUPPORT
-               if (conf->magic_pkt_filter_add) {
-                       kfree(conf->magic_pkt_filter_add);
-                       conf->magic_pkt_filter_add = NULL;
-               }
-#endif
-               if (conf->wl_preinit) {
-                       kfree(conf->wl_preinit);
-                       conf->wl_preinit = NULL;
-               }
-               if (conf->wl_suspend) {
-                       kfree(conf->wl_suspend);
-                       conf->wl_suspend = NULL;
-               }
-               if (conf->wl_resume) {
-                       kfree(conf->wl_resume);
-                       conf->wl_resume = NULL;
-               }
-               if (conf->vndr_ie_assocreq) {
-                       kfree(conf->vndr_ie_assocreq);
-                       conf->vndr_ie_assocreq = NULL;
-               }
+               dhd_conf_free_preinit(dhd);
                MFREE(dhd->osh, conf, sizeof(dhd_conf_t));
        }
        dhd->conf = NULL;
index 306c2b8d008d35cfc0b51a66631fcd03d0eac64f..b7153b2258560d73762f808a289598bdd017d4bf 100755 (executable)
 #define FW_TYPE_AG      1
 
 #define FW_PATH_AUTO_SELECT 1
+#ifdef BCMDHD_MDRIVER
 #define CONFIG_PATH_AUTO_SELECT
+#else
+#define CONFIG_PATH_AUTO_SELECT
+#endif
 extern char firmware_path[MOD_PARAM_PATHLEN];
 #if defined(BCMSDIO) || defined(BCMPCIE)
 extern uint dhd_rxbound;
@@ -63,9 +67,10 @@ typedef struct wl_chip_nv_path_list_ctrl {
        struct wl_chip_nv_path *m_chip_nv_path_head;
 } wl_chip_nv_path_list_ctrl_t;
 
+#define MAX_CTRL_CHANSPECS 256
 typedef struct wl_channel_list {
        uint32 count;
-       uint32 channel[WL_NUMCHANNELS];
+       uint32 channel[MAX_CTRL_CHANSPECS];
 } wl_channel_list_t;
 
 typedef struct wmes_param {
@@ -181,9 +186,17 @@ enum conn_state {
        CONN_STATE_4WAY_M2 = 19,
        CONN_STATE_4WAY_M3 = 20,
        CONN_STATE_4WAY_M4 = 21,
-       CONN_STATE_CONNECTED = 22,
-       CONN_STATE_GROUPKEY_M1 = 23,
-       CONN_STATE_GROUPKEY_M2 = 24,
+       CONN_STATE_ADD_KEY = 22,
+       CONN_STATE_CONNECTED = 23,
+       CONN_STATE_GROUPKEY_M1 = 24,
+       CONN_STATE_GROUPKEY_M2 = 25,
+};
+
+enum enq_pkt_type {
+       ENQ_PKT_TYPE_EAPOL      = (1 << (0)),
+       ENQ_PKT_TYPE_ARP        = (1 << (1)),
+       ENQ_PKT_TYPE_DHCP       = (1 << (2)),
+       ENQ_PKT_TYPE_ICMP       = (1 << (3)),
 };
 
 typedef struct dhd_conf {
@@ -205,6 +218,7 @@ typedef struct dhd_conf {
 #endif
        wl_chip_nv_path_list_ctrl_t nv_by_chip;
        country_list_t *country_head;
+       int ioctl_ver;
        int band;
        int bw_cap[2];
        wl_country_t cspec;
@@ -283,6 +297,7 @@ typedef struct dhd_conf {
        int flow_ring_queue_threshold;
        int d2h_intr_method;
        int d2h_intr_control;
+       int enq_hdr_pkt;
 #endif
        int dpc_cpucore;
        int rxf_cpucore;
@@ -386,17 +401,20 @@ void dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable);
 int dhd_conf_get_otp(dhd_pub_t *dhd, si_t *sih);
 bool dhd_conf_legacy_msi_chip(dhd_pub_t *dhd);
 #endif
+#ifdef WL_CFG80211
+bool dhd_conf_legacy_chip_check(dhd_pub_t *dhd);
+bool dhd_conf_new_chip_check(dhd_pub_t *dhd);
+bool dhd_conf_extsae_chip(dhd_pub_t *dhd);
+#endif
 void dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path);
 int dhd_conf_set_intiovar(dhd_pub_t *dhd, int ifidx, uint cmd, char *name,
        int val, int def, bool down);
 int dhd_conf_get_band(dhd_pub_t *dhd);
-int dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec);
+int dhd_conf_country(dhd_pub_t *dhd, char *cmd, char *buf);
 int dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec);
-int dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec);
 #ifdef CCODE_LIST
 int dhd_ccode_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec);
 #endif
-int dhd_conf_fix_country(dhd_pub_t *dhd);
 bool dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel);
 void dhd_conf_set_wme(dhd_pub_t *dhd, int ifidx, int mode);
 void dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int go, int source);
@@ -408,6 +426,7 @@ int dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev);
 uint dhd_conf_get_chip(void *context);
 uint dhd_conf_get_chiprev(void *context);
 int dhd_conf_get_pm(dhd_pub_t *dhd);
+int dhd_conf_reg2args(dhd_pub_t *dhd, char *cmd, bool set, uint32 index, uint32 *val);
 int dhd_conf_check_hostsleep(dhd_pub_t *dhd, int cmd, void *buf, int len,
        int *hostsleep_set, int *hostsleep_val, int *ret);
 void dhd_conf_get_hostsleep(dhd_pub_t *dhd,
@@ -426,6 +445,9 @@ void dhd_conf_tput_monitor(dhd_pub_t *dhd);
 uint dhd_conf_get_insuspend(dhd_pub_t *dhd, uint mask);
 int dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend);
 void dhd_conf_postinit_ioctls(dhd_pub_t *dhd);
+#ifdef WL_STATIC_IF
+void dhd_conf_preinit_ioctls_sta(dhd_pub_t *dhd, int ifidx);
+#endif /* WL_STATIC_IF */
 int dhd_conf_preinit(dhd_pub_t *dhd);
 int dhd_conf_reset(dhd_pub_t *dhd);
 int dhd_conf_attach(dhd_pub_t *dhd);
index 08411767a90ee49e029080c87aebcae5577ece26..12218c260ce7251189ad334ed49435c83a2bb2dd 100755 (executable)
@@ -210,6 +210,39 @@ done:
        return ret;
 }
 
+int BCMFASTPATH
+(dhd_flow_queue_enqueue_head)(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt)
+{
+       int ret = BCME_OK;
+
+       ASSERT(queue != NULL);
+
+       if (dhd_flow_queue_throttle(queue)) {
+               queue->failures++;
+               ret = (*queue->cb)(queue, pkt);
+               goto done;
+       }
+
+       if (queue->head) {
+               FLOW_QUEUE_PKT_SETNEXT(pkt, queue->head);
+               queue->head = pkt;
+
+       } else {
+               queue->head = pkt;
+               FLOW_QUEUE_PKT_SETNEXT(pkt, NULL);
+               queue->tail = pkt; /* at tail */
+       }
+
+       queue->len++;
+       /* increment parent's cummulative length */
+       DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_CLEN_PTR(queue));
+       /* increment grandparent's cummulative length */
+       DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_L2CLEN_PTR(queue));
+
+done:
+       return ret;
+}
+
 /** Dequeue an 802.3 packet from a flow ring's queue, from head (FIFO) */
 void *
 BCMFASTPATH(dhd_flow_queue_dequeue)(dhd_pub_t *dhdp, flow_queue_t *queue)
index 873ca68a121303d25a7712b7eb59b5a5726d0f5d..404ea4c0e370abdbe5c6d015a54263a59b9a25ad 100755 (executable)
@@ -307,6 +307,7 @@ extern void dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max);
 extern void dhd_flow_queue_reinit(dhd_pub_t *dhdp, flow_queue_t *queue, int max);
 extern void dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb);
 extern int  dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt);
+extern int  dhd_flow_queue_enqueue_head(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt);
 extern void * dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue);
 extern void dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt);
 
index 4737b43bfa00f903c28e33e5a77d20593f1a8302..4ff2551d36a23066ffb066dcd77ae3244b864e04 100755 (executable)
@@ -105,7 +105,7 @@ dhd_fwtrace_detach(dhd_pub_t *dhdp)
 
        /* close the file if valid */
        if (!(IS_ERR_OR_NULL(dhdp->fwtrace_info->fw_trace_fp))) {
-               (void) filp_close(dhdp->fwtrace_info->fw_trace_fp, 0);
+               (void) dhd_filp_close(dhdp->fwtrace_info->fw_trace_fp, 0);
        }
 
        mutex_destroy(&dhdp->fwtrace_info->fwtrace_lock);
@@ -229,7 +229,7 @@ fwtrace_write_to_file(uint8 *buf, uint16 buf_len, dhd_pub_t *dhdp)
        // Get the file size
        // if the size + buf_len > TRACE_FILE_SIZE, then write to a different file.
        //
-       error = vfs_stat(fwtrace_info->trace_file, &stat);
+       error = dhd_vfs_stat(fwtrace_info->trace_file, &stat);
        if (error) {
                DHD_ERROR(("vfs_stat has failed with error code = %d\n", error));
                goto done;
@@ -243,7 +243,7 @@ fwtrace_write_to_file(uint8 *buf, uint16 buf_len, dhd_pub_t *dhdp)
 
        pos = fwtrace_info->fw_trace_fp->f_pos;
        /* Write buf to file */
-       ret_val_1 = vfs_write(fwtrace_info->fw_trace_fp,
+       ret_val_1 = dhd_vfs_write(fwtrace_info->fw_trace_fp,
                              (char *) buf, (uint32) buf_len, &pos);
        if (ret_val_1 < 0) {
                DHD_ERROR(("write file error, err = %d\n", ret_val_1));
@@ -253,7 +253,7 @@ fwtrace_write_to_file(uint8 *buf, uint16 buf_len, dhd_pub_t *dhdp)
        fwtrace_info->fw_trace_fp->f_pos = pos;
 
        /* Sync file from filesystem to physical media */
-       ret_val_1 = vfs_fsync(fwtrace_info->fw_trace_fp, 0);
+       ret_val_1 = dhd_vfs_fsync(fwtrace_info->fw_trace_fp, 0);
        if (ret_val_1 < 0) {
                DHD_ERROR(("sync file error, error = %d\n", ret_val_1));
                ret_val = BCME_ERROR;
@@ -330,7 +330,7 @@ fwtrace_open_file(uint32 fw_trace_enabled, dhd_pub_t *dhdp)
 
        if (fw_trace_enabled) {
                if (!(IS_ERR_OR_NULL(fwtrace_info->fw_trace_fp))) {
-                       (void) filp_close(fwtrace_info->fw_trace_fp, 0);
+                       (void) dhd_filp_close(fwtrace_info->fw_trace_fp, 0);
                }
 
                DHD_INFO((" *** Creating the trace file \n"));
@@ -348,9 +348,9 @@ fwtrace_open_file(uint32 fw_trace_enabled, dhd_pub_t *dhdp)
                         ts_str);
 
                fwtrace_info->fw_trace_fp =
-                       filp_open(fwtrace_info->trace_file, file_mode, 0664);
+                       dhd_filp_open(fwtrace_info->trace_file, file_mode, 0664);
 
-               if (IS_ERR(fwtrace_info->fw_trace_fp)) {
+               if (IS_ERR(fwtrace_info->fw_trace_fp) || (fwtrace_info->fw_trace_fp == NULL)) {
                        DHD_ERROR(("Unable to create the fw trace file file: %s\n",
                                   fwtrace_info->trace_file));
                        ret_val = BCME_ERROR;
@@ -368,7 +368,7 @@ fwtrace_close_file(dhd_pub_t *dhdp)
        int ret_val = BCME_OK;
 
        if (!(IS_ERR_OR_NULL(dhdp->fwtrace_info->fw_trace_fp))) {
-               (void) filp_close(dhdp->fwtrace_info->fw_trace_fp, 0);
+               (void) dhd_filp_close(dhdp->fwtrace_info->fw_trace_fp, 0);
        }
 
        dhdp->fwtrace_info->fw_trace_fp = NULL;
index 60c04bedc08c36e568697668b28a4fbcf0ecf71e..26d68241f809aa69c853617b9754e0f35bdf5c1b 100755 (executable)
@@ -15,7 +15,7 @@
 extern int dhd_static_buf_init(void);
 extern void dhd_static_buf_exit(void);
 #endif /* DHD_STATIC_IN_DRIVER */
-#ifdef BCMDHD_MDRIVER
+#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER)
 extern void *bcmdhd_mem_prealloc(uint bus_type, int index,
        int section, unsigned long size);
 #else
@@ -77,8 +77,8 @@ dhd_wlan_set_power(int on, wifi_adapter_info_t *adapter)
                }
 #ifdef CUSTOMER_HW_AMLOGIC
 #ifdef BCMSDIO
-               extern_wifi_set_enable(0);
-               mdelay(200);
+//             extern_wifi_set_enable(0);
+//             mdelay(200);
                extern_wifi_set_enable(1);
                mdelay(200);
 //             sdio_reinit();
@@ -174,12 +174,14 @@ dhd_wlan_set_power(int on, wifi_adapter_info_t *adapter)
        return err;
 }
 
-static int dhd_wlan_set_reset(int onoff)
+static int
+dhd_wlan_set_reset(int onoff)
 {
        return 0;
 }
 
-static int dhd_wlan_set_carddetect(int present)
+static int
+dhd_wlan_set_carddetect(int present)
 {
        int err = 0;
 
@@ -203,8 +205,8 @@ static int dhd_wlan_set_carddetect(int present)
                err = sdhci_force_presence_change(&sdmmc_channel, 0);
 #endif /* CUSTOMER_HW_PLATFORM */
 #ifdef CUSTOMER_HW_AMLOGIC
-               extern_wifi_set_enable(0);
-               mdelay(200);
+//             extern_wifi_set_enable(0);
+//             mdelay(200);
 #endif
 #elif defined(BCMPCIE)
                printf("======== Card detection to remove PCIE card! ========\n");
@@ -219,7 +221,8 @@ static int dhd_wlan_set_carddetect(int present)
        return err;
 }
 
-static int dhd_wlan_get_mac_addr(unsigned char *buf, int ifidx)
+static int
+dhd_wlan_get_mac_addr(unsigned char *buf, int ifidx)
 {
        int err = 0;
 
@@ -338,7 +341,8 @@ struct wifi_platform_data dhd_wlan_control = {
        .get_country_code = dhd_wlan_get_country_code,
 };
 
-int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
+static int
+dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
 {
 #ifdef BCMDHD_DTS
        char wlan_node[32];
@@ -375,7 +379,7 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
 
 #ifdef CUSTOMER_HW_AMLOGIC
 #if defined(BCMPCIE)
-       printf("======== Card detection to detect PCIE card! ========\n");
+//     printf("======== Card detection to detect PCIE card! ========\n");
 //     pci_remove_reinit(0x14e4, 0x43ec, 1);
 #endif
 #endif
@@ -383,8 +387,8 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
        if (gpio_wl_reg_on >= 0) {
                err = gpio_request(gpio_wl_reg_on, "WL_REG_ON");
                if (err < 0) {
-                       printf("%s: gpio_request(%d) for WL_REG_ON failed\n",
-                               __FUNCTION__, gpio_wl_reg_on);
+                       printf("%s: gpio_request(%d) for WL_REG_ON failed %d\n",
+                               __FUNCTION__, gpio_wl_reg_on, err);
                        gpio_wl_reg_on = -1;
                }
        }
@@ -394,22 +398,22 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
        if (gpio_wl_host_wake >= 0) {
                err = gpio_request(gpio_wl_host_wake, "bcmdhd");
                if (err < 0) {
-                       printf("%s: gpio_request(%d) for WL_HOST_WAKE failed\n",
-                               __FUNCTION__, gpio_wl_host_wake);
+                       printf("%s: gpio_request(%d) for WL_HOST_WAKE failed %d\n",
+                               __FUNCTION__, gpio_wl_host_wake, err);
                        return -1;
                }
                adapter->gpio_wl_host_wake = gpio_wl_host_wake;
                err = gpio_direction_input(gpio_wl_host_wake);
                if (err < 0) {
-                       printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed\n",
-                               __FUNCTION__, gpio_wl_host_wake);
+                       printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed %d\n",
+                               __FUNCTION__, gpio_wl_host_wake, err);
                        gpio_free(gpio_wl_host_wake);
                        return -1;
                }
                host_oob_irq = gpio_to_irq(gpio_wl_host_wake);
                if (host_oob_irq < 0) {
-                       printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed\n",
-                               __FUNCTION__, gpio_wl_host_wake);
+                       printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed %d\n",
+                               __FUNCTION__, gpio_wl_host_wake, host_oob_irq);
                        gpio_free(gpio_wl_host_wake);
                        return -1;
                }
@@ -450,7 +454,8 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
        return 0;
 }
 
-static void dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter)
+static void
+dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter)
 {
        int gpio_wl_reg_on = adapter->gpio_wl_reg_on;
 #ifdef CUSTOMER_OOB
@@ -471,25 +476,68 @@ static void dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter)
 #endif /* CUSTOMER_OOB */
 }
 
-int dhd_wlan_init_plat_data(wifi_adapter_info_t *adapter)
+#if defined(BCMDHD_MDRIVER)
+static void
+dhd_wlan_init_adapter(wifi_adapter_info_t *adapter)
+{
+#ifdef ADAPTER_IDX
+       if (ADAPTER_IDX == 0) {
+               adapter->bus_num = 1;
+               adapter->slot_num = 1;
+       } else if (ADAPTER_IDX == 1) {
+               adapter->bus_num = 2;
+               adapter->slot_num = 1;
+       }
+       adapter->index = ADAPTER_IDX;
+#ifdef BCMSDIO
+       adapter->bus_type = SDIO_BUS;
+#elif defined(BCMPCIE)
+       adapter->bus_type = PCI_BUS;
+#elif defined(BCMDBUS)
+       adapter->bus_type = USB_BUS;
+#endif
+       printf("bus_type=%d, bus_num=%d, slot_num=%d\n",
+               adapter->bus_type, adapter->bus_num, adapter->slot_num);
+#endif /* ADAPTER_IDX */
+
+#ifdef DHD_STATIC_IN_DRIVER
+       adapter->index = 0;
+#elif !defined(ADAPTER_IDX)
+#ifdef BCMSDIO
+       adapter->index = 0;
+#elif defined(BCMPCIE)
+       adapter->index = 1;
+#elif defined(BCMDBUS)
+       adapter->index = 2;
+#endif
+#endif /* DHD_STATIC_IN_DRIVER */
+}
+#endif /* BCMDHD_MDRIVER */
+
+int
+dhd_wlan_init_plat_data(wifi_adapter_info_t *adapter)
 {
        int err = 0;
 
-       printf("======== %s ========\n", __FUNCTION__);
-       if (adapter->index == -1) {
-               adapter->index = 0;
-       }
+#ifdef BCMDHD_MDRIVER
+       dhd_wlan_init_adapter(adapter);
+#endif /* BCMDHD_MDRIVER */
+
        err = dhd_wlan_init_gpio(adapter);
+       if (err)
+               goto exit;
 
 #ifdef DHD_STATIC_IN_DRIVER
-       dhd_static_buf_init();
+       err = dhd_static_buf_init();
 #endif
+
+exit:
        return err;
 }
 
-void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter)
+void
+dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter)
 {
-       printf("======== %s ========\n", __FUNCTION__);
 #ifdef DHD_STATIC_IN_DRIVER
        dhd_static_buf_exit();
 #endif
index 732399c1a0122cd7bf774f9525b0e4bad4f6b58b..d8dc1d7491f23677c8193ef48788db230d8eb4cf 100755 (executable)
@@ -636,8 +636,8 @@ extern void dhd_netdev_free(struct net_device *ndev);
 static dhd_if_t * dhd_get_ifp_by_ndev(dhd_pub_t *dhdp, struct net_device *ndev);
 
 #if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG)
-static void dhd_bridge_dev_set(dhd_info_t * dhd, int ifidx, struct net_device * dev);
-#endif /* defiend(WLDWDS) && defined(FOURADDR_AUTO_BRG) */
+static void dhd_bridge_dev_set(dhd_info_t *dhd, int ifidx, struct net_device *sdev);
+#endif /* WLDWDS && FOURADDR_AUTO_BRG */
 
 #if (defined(DHD_WET) || defined(DHD_MCAST_REGEN) || defined(DHD_L2_FILTER))
 /* update rx_pkt_chainable state of dhd interface */
@@ -840,20 +840,19 @@ module_param(tpoweron_scale, uint, 0644);
 #endif /* FORCE_TPOWERON */
 
 #ifdef SHOW_LOGTRACE
-#if defined(CUSTOMER_HW4_DEBUG)
-#define WIFI_PATH "/etc/wifi/"
-static char *logstrs_path = VENDOR_PATH WIFI_PATH"logstrs.bin";
-char *st_str_file_path = VENDOR_PATH WIFI_PATH"rtecdc.bin";
-static char *map_file_path = VENDOR_PATH WIFI_PATH"rtecdc.map";
-static char *rom_st_str_file_path = VENDOR_PATH WIFI_PATH"roml.bin";
-static char *rom_map_file_path = VENDOR_PATH WIFI_PATH"roml.map";
+#ifdef DHD_LINUX_STD_FW_API
+static char *logstrs_path = "logstrs.bin";
+char *st_str_file_path = "rtecdc.bin";
+static char *map_file_path = "rtecdc.map";
+static char *rom_st_str_file_path = "roml.bin";
+static char *rom_map_file_path = "roml.map";
 #else
 static char *logstrs_path = PLATFORM_PATH"logstrs.bin";
 char *st_str_file_path = PLATFORM_PATH"rtecdc.bin";
 static char *map_file_path = PLATFORM_PATH"rtecdc.map";
 static char *rom_st_str_file_path = PLATFORM_PATH"roml.bin";
 static char *rom_map_file_path = PLATFORM_PATH"roml.map";
-#endif /* CUSTOMER_HW4_DEBUG */
+#endif /* DHD_LINUX_STD_FW_API */
 
 static char *ram_file_str = "rtecdc";
 static char *rom_file_str = "roml";
@@ -1182,6 +1181,9 @@ static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, voi
                        dhd_conf_set_suspend_resume(dhd, suspend);
                DHD_OS_WAKE_LOCK_RESTORE(dhd);
        } else {
+#ifdef BCMDBUS
+               if (dhd->busstate == DHD_BUS_DATA) {
+#endif
                if (suspend_mode == PM_NOTIFIER || suspend_mode == SUSPEND_MODE_2)
                        dhd_conf_set_suspend_resume(dhd, suspend);
 #if defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS)
@@ -1189,6 +1191,11 @@ static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, voi
 #endif /* defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) */
                if (suspend_mode == PM_NOTIFIER)
                        dhd_suspend_resume_helper(dhdinfo, suspend, 0);
+#ifdef BCMDBUS
+               } else {
+                       printf("%s: skip resume since bus suspeneded\n", __FUNCTION__);
+               }
+#endif
        }
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
@@ -3075,7 +3082,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr, bool skip_stop)
                        dhd_ifname(&dhd->pub, ifidx), addr, ret));
                goto exit;
        } else {
-               memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
+               dev_addr_set(dhd->iflist[ifidx]->net, addr);
                if (ifidx == 0)
                        memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
                WL_MSG(dhd_ifname(&dhd->pub, ifidx), "MACID %pM is overwritten\n", addr);
@@ -3265,7 +3272,7 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
        struct wl_if_event_info info;
 #if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG)
        struct net_device *ndev = NULL;
-#endif
+#endif /* WLDWDS && FOURADDR_AUTO_BRG */
 #else
        struct net_device *ndev;
 #endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
@@ -3318,13 +3325,13 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
                        mac_addr = NULL;
                }
 
-#ifdef WLEASYMESH
+#if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG)
                if ((ndev = wl_cfg80211_post_ifcreate(dhd->pub.info->iflist[0]->net,
                        &info, mac_addr, if_event->name, true)) == NULL)
 #else
                if (wl_cfg80211_post_ifcreate(dhd->pub.info->iflist[0]->net,
                        &info, mac_addr, NULL, true) == NULL)
-#endif
+#endif /* WLDWDS && FOURADDR_AUTO_BRG */
                {
                        /* Do the post interface create ops */
                        DHD_ERROR(("Post ifcreate ops failed. Returning \n"));
@@ -3366,6 +3373,10 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
        }
 #endif /* PCIE_FULL_DONGLE */
 
+#if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG)
+       dhd_bridge_dev_set(dhd, ifidx, ndev);
+#endif /* WLDWDS && FOURADDR_AUTO_BRG */
+
 done:
 #ifdef DHD_AWDL
        if (ret != BCME_OK && is_awdl_iface) {
@@ -3374,11 +3385,6 @@ done:
 #endif /* DHD_AWDL */
 
        MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
-#if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG)
-       if (dhd->pub.info->iflist[ifidx]) {
-               dhd_bridge_dev_set(dhd, ifidx, ndev);
-    }
-#endif /* defiend(WLDWDS) && defined(FOURADDR_AUTO_BRG) */
 
        DHD_OS_WAKE_UNLOCK(&dhd->pub);
        dhd_net_if_unlock_local(dhd);
@@ -3411,17 +3417,15 @@ dhd_ifdel_event_handler(void *handle, void *event_info, u8 event)
 
        ifidx = if_event->event.ifidx;
        DHD_TRACE(("Removing interface with idx %d\n", ifidx));
-#if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG)
-       if (dhd->pub.info->iflist[ifidx]) {
-               dhd_bridge_dev_set(dhd, ifidx, NULL);
-    }
-#endif /* defiend(WLDWDS) && defined(FOURADDR_AUTO_BRG) */
 
        if (!dhd->pub.info->iflist[ifidx]) {
                /* No matching netdev found */
                DHD_ERROR(("Netdev not found! Do nothing.\n"));
                goto done;
        }
+#if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG)
+       dhd_bridge_dev_set(dhd, ifidx, NULL);
+#endif /* WLDWDS && FOURADDR_AUTO_BRG */
 #if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
        if (if_event->event.ifidx > 0) {
                /* Do the post interface del ops */
@@ -3522,7 +3526,7 @@ int dhd_op_if_update(dhd_pub_t *dhdpub, int ifidx)
                           (unsigned char)buf[3], (unsigned char)buf[4], (unsigned char)buf[5]));
                memcpy(dhdinfo->iflist[ifp->idx]->mac_addr, buf, ETHER_ADDR_LEN);
                if (dhdinfo->iflist[ifp->idx]->net) {
-                   memcpy(dhdinfo->iflist[ifp->idx]->net->dev_addr, buf, ETHER_ADDR_LEN);
+                       dev_addr_set(dhdinfo->iflist[ifp->idx]->net, buf);
                }
        }
 
@@ -3665,7 +3669,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr)
                         * available). Store the address and return. macaddr will be applied
                         * from interface create context.
                         */
-                       (void)memcpy_s(dev->dev_addr, ETH_ALEN, dhdif->mac_addr, ETH_ALEN);
+                       dev_addr_set(dev, dhdif->mac_addr);
 #ifdef DHD_NOTIFY_MAC_CHANGED
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0))
                        dev_open(dev, NULL);
@@ -4764,6 +4768,11 @@ dhd_bus_wakeup_work(dhd_pub_t *dhdp)
 static void
 __dhd_txflowcontrol(dhd_pub_t *dhdp, struct net_device *net, bool state)
 {
+
+       if (net->reg_state != NETREG_REGISTERED) {
+               return;
+       }
+
        if (state == ON) {
                if (!netif_queue_stopped(net)) {
                        DHD_INFO(("%s: Stop Netif Queue\n", __FUNCTION__));
@@ -5670,7 +5679,7 @@ dhd_check_shinfo_nrfrags(dhd_pub_t *dhdp, void *pktbuf,
        shinfo = skb_shinfo(skb);
 
        if (shinfo->nr_frags) {
-#ifdef CONFIG_64BIT
+#ifdef BCMDMA64OSL
                DHD_ERROR(("!!Invalid nr_frags: %u pa.loaddr: 0x%llx pa.hiaddr: 0x%llx "
                        "skb: 0x%llx skb_data: 0x%llx skb_head: 0x%llx skb_tail: 0x%llx "
                        "skb_end: 0x%llx skb_len: %u shinfo: 0x%llx pktid: %u\n",
@@ -9081,14 +9090,14 @@ dhd_check_filesystem_is_up(void)
 {
        struct file *fp;
        const char *clm = VENDOR_PATH CONFIG_BCMDHD_CLM_PATH;
-       fp = filp_open(clm, O_RDONLY, 0);
 
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(clm, O_RDONLY, 0);
+       if (IS_ERR(fp) || (fp == NULL)) {
                DHD_ERROR(("%s: filp_open(%s) failed(%d) schedule wl_accel_work\n",
                                __FUNCTION__, clm, (int)IS_ERR(fp)));
                return FALSE;
        }
-       filp_close(fp, NULL);
+       dhd_filp_close(fp, NULL);
 
        return TRUE;
 }
@@ -9467,7 +9476,7 @@ dhd_open(struct net_device *net)
 #endif
 
                /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */
-               memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
+               dev_addr_set(net, dhd->pub.mac.octet);
 
 #ifdef TOE
                /* Get current TOE mode from dongle */
@@ -9592,15 +9601,16 @@ dhd_open(struct net_device *net)
 
 exit:
        mutex_unlock(&dhd->pub.ndev_op_sync);
+       if (ret) {
+               dhd_stop(net);
+       } else {
 #if defined(ENABLE_INSMOD_NO_FW_LOAD) && defined(NO_POWER_OFF_AFTER_OPEN)
-       dhd_download_fw_on_driverload = TRUE;
-       dhd_driver_init_done = TRUE;
+               dhd_download_fw_on_driverload = TRUE;
+               dhd_driver_init_done = TRUE;
 #elif defined(ENABLE_INSMOD_NO_FW_LOAD) && defined(ENABLE_INSMOD_NO_POWER_OFF)
-       dhd_download_fw_on_driverload = FALSE;
-       dhd_driver_init_done = TRUE;
+               dhd_download_fw_on_driverload = FALSE;
+               dhd_driver_init_done = TRUE;
 #endif
-       if (ret) {
-               dhd_stop(net);
        }
 
        DHD_OS_WAKE_UNLOCK(&dhd->pub);
@@ -10463,15 +10473,22 @@ dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock)
                                        unregister_netdev(ifp->net);
                                else
                                        unregister_netdevice(ifp->net);
+#if defined(WLDWDS) && defined(WL_EXT_IAPSTA)
+                               if (ifp->dwds) {
+                                       wl_ext_iapsta_dettach_dwds_netdev(ifp->net, ifidx, ifp->bssidx);
+                               } else
+#endif /* WLDWDS && WL_EXT_IAPSTA */
+                               {
 #ifdef WL_EXT_IAPSTA
-                               wl_ext_iapsta_dettach_netdev(ifp->net, ifidx);
+                                       wl_ext_iapsta_dettach_netdev(ifp->net, ifidx);
 #endif /* WL_EXT_IAPSTA */
 #ifdef WL_ESCAN
-                               wl_escan_event_dettach(ifp->net, ifidx);
+                                       wl_escan_event_dettach(ifp->net, ifidx);
 #endif /* WL_ESCAN */
 #ifdef WL_EVENT
-                               wl_ext_event_dettach_netdev(ifp->net, ifidx);
+                                       wl_ext_event_dettach_netdev(ifp->net, ifidx);
 #endif /* WL_EVENT */
+                               }
                        }
                        ifp->net = NULL;
                        DHD_GENERAL_LOCK(dhdpub, flags);
@@ -10594,7 +10611,7 @@ dhd_os_write_file_posn(void *fp, unsigned long *posn, void *buf,
        if (!fp || !buf || buflen == 0)
                return -1;
 
-       if (vfs_write((struct file *)fp, buf, buflen, &wr_posn) < 0)
+       if (dhd_vfs_write((struct file *)fp, buf, buflen, &wr_posn) < 0)
                return -1;
 
        *posn = wr_posn;
@@ -10610,7 +10627,7 @@ dhd_os_read_file(void *file, char *buf, uint32 size)
        if (!file || !buf)
                return -1;
 
-       return vfs_read(filep, buf, size, &filep->f_pos);
+       return dhd_vfs_read(filep, buf, size, &filep->f_pos);
 }
 
 int
@@ -10626,46 +10643,269 @@ dhd_os_seek_file(void *file, int64 offset)
        return 0;
 }
 
+#ifdef DHD_COREDUMP
+#define PC_FOUND_BIT 0x01
+#define LR_FOUND_BIT 0x02
+#define ALL_ADDR_VAL (PC_FOUND_BIT | LR_FOUND_BIT)
+#define READ_NUM_BYTES 1000
+#define DHD_FUNC_STR_LEN 80
 static int
-dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp)
+dhd_lookup_map(osl_t *osh, char *fname, uint32 pc, char *pc_fn,
+               uint32 lr, char *lr_fn)
 {
+#ifdef DHD_LINUX_STD_FW_API
+       const struct firmware *fw = NULL;
+       uint32 size = 0, mem_offset = 0;
+#else
        struct file *filep = NULL;
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
-       struct kstat stat;
        mm_segment_t fs;
-       int error = 0;
 #endif
-       char *raw_fmts =  NULL;
-       int logstrs_size = 0;
+#endif /* DHD_LINUX_STD_FW_API */
+       char *raw_fmts = NULL, *raw_fmts_loc = NULL, *cptr = NULL;
+       uint32 read_size = READ_NUM_BYTES;
+       int err = BCME_ERROR;
+       uint32 addr = 0, addr1 = 0, addr2 = 0;
+       char type = '?', type1 = '?', type2 = '?';
+       char func[DHD_FUNC_STR_LEN] = "\0";
+       char func1[DHD_FUNC_STR_LEN] = "\0";
+       char func2[DHD_FUNC_STR_LEN] = "\0";
+       uint8 count = 0;
+       int num, len = 0, offset;
 
-       if (control_logtrace != LOGTRACE_PARSED_FMT) {
-               DHD_ERROR_NO_HW4(("%s : turned off logstr parsing\n", __FUNCTION__));
+       DHD_TRACE(("%s: fname %s pc 0x%x lr 0x%x \n",
+               __FUNCTION__, fname, pc, lr));
+       if (fname == NULL) {
+               DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__));
+               return BCME_ERROR;
+       }
+
+       /* Allocate 1 byte more than read_size to terminate it with NULL */
+       raw_fmts = MALLOCZ(osh, read_size + 1);
+       if (raw_fmts == NULL) {
+               DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n",
+                       __FUNCTION__));
                return BCME_ERROR;
        }
 
+#ifdef DHD_LINUX_STD_FW_API
+       err = dhd_os_get_img_fwreq(&fw, fname);
+       if (err < 0) {
+               DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n",
+                       err));
+               goto fail;
+       }
+       size = fw->size;
+#else
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
        fs = get_fs();
        set_fs(KERNEL_DS);
 #endif
 
-       filep = filp_open(logstrs_path, O_RDONLY, 0);
-
-       if (IS_ERR(filep)) {
-               DHD_ERROR_NO_HW4(("%s: Failed to open the file %s \n", __FUNCTION__, logstrs_path));
+       filep = dhd_filp_open(fname, O_RDONLY, 0);
+       if (IS_ERR(filep) || (filep == NULL)) {
+               DHD_ERROR(("%s: Failed to open %s \n",  __FUNCTION__, fname));
                goto fail;
        }
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
-       error = vfs_stat(logstrs_path, &stat);
-       if (error) {
-               DHD_ERROR_NO_HW4(("%s: Failed to stat file %s \n", __FUNCTION__, logstrs_path));
-               goto fail;
+#endif /* DHD_LINUX_STD_FW_API */
+
+       if (pc_fn == NULL) {
+               count |= PC_FOUND_BIT;
        }
-       logstrs_size = (int) stat.size;
+       if (lr_fn == NULL) {
+               count |= LR_FOUND_BIT;
+       }
+       while (count != ALL_ADDR_VAL)
+       {
+#ifdef DHD_LINUX_STD_FW_API
+               /* Bound check for size before doing memcpy() */
+               if ((mem_offset + read_size) > size) {
+                       read_size = size - mem_offset;
+               }
+
+               err = memcpy_s(raw_fmts, read_size,
+                       ((char *)(fw->data) + mem_offset), read_size);
+               if (err) {
+                       DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n",
+                               __FUNCTION__, err));
+                       goto fail;
+               }
 #else
-       logstrs_size = dhd_os_get_image_size(filep);
+               err = dhd_os_read_file(filep, raw_fmts, read_size);
+               if (err < 0) {
+                       DHD_ERROR(("%s: map file read failed err:%d \n",
+                               __FUNCTION__, err));
+                       goto fail;
+               }
+
+#endif /* DHD_LINUX_STD_FW_API */
+               /* End raw_fmts with NULL as strstr expects NULL terminated
+               * strings
+               */
+               raw_fmts[read_size] = '\0';
+               raw_fmts_loc = raw_fmts;
+               offset = 0;
+
+               while ((count != ALL_ADDR_VAL) && (offset < read_size))
+               {
+                       cptr = bcmstrtok(&raw_fmts_loc, "\n", 0);
+                       if (cptr == NULL) {
+                               DHD_TRACE(("%s: cptr is NULL, offset %d"
+                                       " raw_fmts_loc %s \n",
+                                       __FUNCTION__, offset, raw_fmts_loc));
+                               break;
+                       }
+                       DHD_TRACE(("%s: %s \n", __FUNCTION__, cptr));
+                       if ((type2 == 'A') ||
+                               (type2 == 'T') ||
+                               (type2 == 'W')) {
+                               addr1 = addr2;
+                               type1 = type2;
+                               (void)memcpy_s(func1, DHD_FUNC_STR_LEN,
+                                       func2, DHD_FUNC_STR_LEN);
+                               DHD_TRACE(("%s: %x %c %s \n",
+                                       __FUNCTION__, addr1, type1, func1));
+                       }
+                       len = strlen(cptr);
+                       num = sscanf(cptr, "%x %c %79s", &addr, &type, func);
+                       DHD_TRACE(("%s: num %d addr %x type %c func %s \n",
+                               __FUNCTION__, num, addr, type, func));
+                       if (num == 3) {
+                               addr2 = addr;
+                               type2 = type;
+                               (void)memcpy_s(func2, DHD_FUNC_STR_LEN,
+                                       func, DHD_FUNC_STR_LEN);
+                       }
+
+                       if (!(count & PC_FOUND_BIT) &&
+                               (pc >= addr1 && pc < addr2)) {
+                               if ((cptr = strchr(func1, '$')) != NULL) {
+                                       (void)strncpy(func, cptr + 1,
+                                               DHD_FUNC_STR_LEN - 1);
+                               } else {
+                                       (void)memcpy_s(func, DHD_FUNC_STR_LEN,
+                                               func1, DHD_FUNC_STR_LEN);
+                               }
+                               if ((cptr = strstr(func, "__bcmromfn"))
+                                       != NULL) {
+                                       *cptr = 0;
+                               }
+                               if (pc > addr1) {
+                                       sprintf(pc_fn, "%.68s+0x%x",
+                                               func, pc - addr1);
+                               } else {
+                                       (void)memcpy_s(pc_fn, DHD_FUNC_STR_LEN,
+                                               func, DHD_FUNC_STR_LEN);
+                               }
+                               count |= PC_FOUND_BIT;
+                               DHD_INFO(("%s: found addr1 %x pc %x"
+                                       " addr2 %x \n",
+                                       __FUNCTION__, addr1, pc, addr2));
+                       }
+                       if (!(count & LR_FOUND_BIT) &&
+                               (lr >= addr1 && lr < addr2)) {
+                               if ((cptr = strchr(func1, '$')) != NULL) {
+                                       (void)strncpy(func, cptr + 1,
+                                               DHD_FUNC_STR_LEN - 1);
+                               } else {
+                                       (void)memcpy_s(func, DHD_FUNC_STR_LEN,
+                                               func1, DHD_FUNC_STR_LEN);
+                               }
+                               if ((cptr = strstr(func, "__bcmromfn"))
+                                       != NULL) {
+                                       *cptr = 0;
+                               }
+                               if (lr > addr1) {
+                                       sprintf(lr_fn, "%.68s+0x%x",
+                                               func, lr - addr1);
+                               } else {
+                                       (void)memcpy_s(lr_fn, DHD_FUNC_STR_LEN,
+                                               func, DHD_FUNC_STR_LEN);
+                               }
+                               count |= LR_FOUND_BIT;
+                               DHD_INFO(("%s: found addr1 %x lr %x"
+                                       " addr2 %x \n",
+                                       __FUNCTION__, addr1, lr, addr2));
+                       }
+                       offset += (len + 1);
+               }
+#ifdef DHD_LINUX_STD_FW_API
+               if ((mem_offset + read_size) >= size) {
+                       break;
+               }
+
+               memset(raw_fmts, 0, read_size);
+               mem_offset += (read_size -(len + 1));
+#else
+               if (err < (int)read_size) {
+                       /*
+                       * since we reset file pos back to earlier pos by
+                       * bytes of one line we won't reach EOF.
+                       * The reason for this is if string is spreaded across
+                       * bytes, the read function should not miss it.
+                       * So if ret value is less than read_size, reached EOF
+                       * don't read further
+                       */
+                       break;
+               }
+               memset(raw_fmts, 0, read_size);
+               /*
+               * go back to bytes of one line so that we won't miss
+               * the string and addr even if it comes as splited in next read.
+               */
+               dhd_os_seek_file(filep, -(len + 1));
+#endif /* DHD_LINUX_STD_FW_API */
+               DHD_TRACE(("%s: seek %d \n", __FUNCTION__, -(len + 1)));
+       }
+
+fail:
+#ifdef DHD_LINUX_STD_FW_API
+       if (fw) {
+               dhd_os_close_img_fwreq(fw);
+       }
+#else
+       if (!IS_ERR(filep))
+               dhd_filp_close(filep, NULL);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
+       set_fs(fs);
 #endif
-       if (logstrs_size <= 0) {
-               DHD_ERROR(("%s: get file size fails %d! \n", __FUNCTION__, logstrs_size));
+
+#endif /* DHD_LINUX_STD_FW_API */
+       if (!(count & PC_FOUND_BIT)) {
+               sprintf(pc_fn, "0x%08x", pc);
+       }
+       if (!(count & LR_FOUND_BIT)) {
+               sprintf(lr_fn, "0x%08x", lr);
+       }
+       return err;
+}
+#endif /* DHD_COREDUMP */
+
+#ifdef DHD_LINUX_STD_FW_API
+static int
+dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp)
+{
+       char *raw_fmts =  NULL;
+       int logstrs_size = 0;
+       int error = 0;
+       const struct firmware *fw = NULL;
+
+       if (control_logtrace != LOGTRACE_PARSED_FMT) {
+               DHD_ERROR_NO_HW4(("%s : turned off logstr parsing\n", __FUNCTION__));
+               return BCME_ERROR;
+       }
+
+       error = dhd_os_get_img_fwreq(&fw, logstrs_path);
+       if (error < 0) {
+               DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n",
+                       error));
+               goto fail;
+       }
+
+       logstrs_size = (int)fw->size;
+       if (logstrs_size == 0) {
+               DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__));
                goto fail;
        }
 
@@ -10678,22 +10918,22 @@ dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp)
                        goto fail;
                }
        }
-
-       if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) !=   logstrs_size) {
-               DHD_ERROR_NO_HW4(("%s: Failed to read file %s\n", __FUNCTION__, logstrs_path));
+       error = memcpy_s(raw_fmts, logstrs_size, (char *)(fw->data), logstrs_size);
+       if (error) {
+               DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n",
+                       __FUNCTION__, error));
                goto fail;
        }
-
-       if (dhd_parse_logstrs_file(osh, raw_fmts, logstrs_size, temp)
-                               == BCME_OK) {
-               filp_close(filep, NULL);
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
-               set_fs(fs);
-#endif
+       if (dhd_parse_logstrs_file(osh, raw_fmts, logstrs_size, temp) == BCME_OK) {
+               dhd_os_close_img_fwreq(fw);
+               DHD_ERROR(("%s: return ok\n", __FUNCTION__));
                return BCME_OK;
        }
 
 fail:
+       if (fw) {
+               dhd_os_close_img_fwreq(fw);
+       }
        if (raw_fmts) {
                MFREE(osh, raw_fmts, logstrs_size);
        }
@@ -10701,13 +10941,6 @@ fail:
                MFREE(osh, temp->fmts, temp->num_fmts * sizeof(char *));
        }
 
-fail1:
-       if (!IS_ERR(filep))
-               filp_close(filep, NULL);
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
-       set_fs(fs);
-#endif
        temp->fmts = NULL;
        temp->raw_fmts = NULL;
 
@@ -10717,15 +10950,149 @@ fail1:
 static int
 dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start,
                uint32 *rodata_end)
+{
+       int err = BCME_ERROR;
+       const struct firmware *fw = NULL;
+
+       if (fname == NULL) {
+               DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__));
+               return BCME_ERROR;
+       }
+
+       err = dhd_os_get_img_fwreq(&fw, fname);
+       if (err < 0) {
+               DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n",
+                       err));
+               goto fail;
+       }
+
+       if ((err = dhd_parse_map_file(osh, (struct firmware *)fw, ramstart,
+                       rodata_start, rodata_end)) < 0) {
+               goto fail;
+       }
+
+fail:
+       if (fw) {
+               dhd_os_close_img_fwreq(fw);
+       }
+
+       return err;
+}
+
+static int
+dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, char *map_file)
+{
+       char *raw_fmts =  NULL;
+       uint32 logstrs_size = 0;
+       int error = 0;
+       uint32 ramstart = 0;
+       uint32 rodata_start = 0;
+       uint32 rodata_end = 0;
+       uint32 logfilebase = 0;
+       const struct firmware *fw = NULL;
+
+       error = dhd_read_map(osh, map_file, &ramstart, &rodata_start, &rodata_end);
+       if (error != BCME_OK) {
+               DHD_ERROR(("readmap Error!! \n"));
+               /* don't do event log parsing in actual case */
+               if (strstr(str_file, ram_file_str) != NULL) {
+                       temp->raw_sstr = NULL;
+               } else if (strstr(str_file, rom_file_str) != NULL) {
+                       temp->rom_raw_sstr = NULL;
+               }
+               return error;
+       }
+       DHD_ERROR(("ramstart: 0x%x, rodata_start: 0x%x, rodata_end:0x%x\n",
+               ramstart, rodata_start, rodata_end));
+
+       /* Full file size is huge. Just read required part */
+       logstrs_size = rodata_end - rodata_start;
+       logfilebase = rodata_start - ramstart;
+
+       if (logstrs_size == 0) {
+               DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__));
+               goto fail1;
+       }
+
+       if (strstr(str_file, ram_file_str) != NULL && temp->raw_sstr != NULL) {
+               raw_fmts = temp->raw_sstr;      /* reuse already malloced raw_fmts */
+       } else if (strstr(str_file, rom_file_str) != NULL && temp->rom_raw_sstr != NULL) {
+               raw_fmts = temp->rom_raw_sstr;  /* reuse already malloced raw_fmts */
+       } else {
+               raw_fmts = MALLOC(osh, logstrs_size);
+
+               if (raw_fmts == NULL) {
+                       DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", __FUNCTION__));
+                       goto fail;
+               }
+       }
+
+       error = dhd_os_get_img_fwreq(&fw, str_file);
+       if (error < 0 || (fw == NULL) || (fw->size < logfilebase)) {
+               DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n",
+                       error));
+               goto fail;
+       }
+
+       error = memcpy_s(raw_fmts, logstrs_size, (char *)((fw->data) + logfilebase),
+               logstrs_size);
+       if (error) {
+               DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n",
+                       __FUNCTION__, error));
+               goto fail;
+       }
+
+       if (strstr(str_file, ram_file_str) != NULL) {
+               temp->raw_sstr = raw_fmts;
+               temp->raw_sstr_size = logstrs_size;
+               temp->rodata_start = rodata_start;
+               temp->rodata_end = rodata_end;
+       } else if (strstr(str_file, rom_file_str) != NULL) {
+               temp->rom_raw_sstr = raw_fmts;
+               temp->rom_raw_sstr_size = logstrs_size;
+               temp->rom_rodata_start = rodata_start;
+               temp->rom_rodata_end = rodata_end;
+       }
+
+       if (fw) {
+               dhd_os_close_img_fwreq(fw);
+       }
+
+       return BCME_OK;
+
+fail:
+       if (raw_fmts) {
+               MFREE(osh, raw_fmts, logstrs_size);
+       }
+
+fail1:
+       if (fw) {
+               dhd_os_close_img_fwreq(fw);
+       }
+
+       if (strstr(str_file, ram_file_str) != NULL) {
+               temp->raw_sstr = NULL;
+       } else if (strstr(str_file, rom_file_str) != NULL) {
+               temp->rom_raw_sstr = NULL;
+       }
+
+       return error;
+} /* dhd_init_static_strs_array */
+#else
+static int
+dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp)
 {
        struct file *filep = NULL;
+       struct kstat stat;
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
        mm_segment_t fs;
 #endif
-       int err = BCME_ERROR;
+       char *raw_fmts =  NULL;
+       int logstrs_size = 0;
+       int error = 0;
 
-       if (fname == NULL) {
-               DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__));
+       if (control_logtrace != LOGTRACE_PARSED_FMT) {
+               DHD_ERROR_NO_HW4(("%s : turned off logstr parsing\n", __FUNCTION__));
                return BCME_ERROR;
        }
 
@@ -10734,63 +11101,82 @@ dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start,
        set_fs(KERNEL_DS);
 #endif
 
-       filep = filp_open(fname, O_RDONLY, 0);
-       if (IS_ERR(filep)) {
-               DHD_ERROR_NO_HW4(("%s: Failed to open %s \n",  __FUNCTION__, fname));
+       filep = dhd_filp_open(logstrs_path, O_RDONLY, 0);
+
+       if (IS_ERR(filep) || (filep == NULL)) {
+               DHD_ERROR_NO_HW4(("%s: Failed to open the file %s \n",
+                       __FUNCTION__, logstrs_path));
                goto fail;
        }
+       error = dhd_vfs_stat(logstrs_path, &stat);
+       if (error) {
+               DHD_ERROR_NO_HW4(("%s: Failed to stat file %s \n", __FUNCTION__, logstrs_path));
+               goto fail;
+       }
+       logstrs_size = (int) stat.size;
 
-       if ((err = dhd_parse_map_file(osh, filep, ramstart,
-                       rodata_start, rodata_end)) < 0)
+       if (logstrs_size == 0) {
+               DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__));
+               goto fail1;
+       }
+
+       if (temp->raw_fmts != NULL) {
+               raw_fmts = temp->raw_fmts;         /* reuse already malloced raw_fmts */
+       } else {
+               raw_fmts = MALLOC(osh, logstrs_size);
+               if (raw_fmts == NULL) {
+                       DHD_ERROR(("%s: Failed to allocate memory \n", __FUNCTION__));
+                       goto fail;
+               }
+       }
+
+       if (dhd_vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) != logstrs_size) {
+               DHD_ERROR_NO_HW4(("%s: Failed to read file %s\n", __FUNCTION__, logstrs_path));
                goto fail;
+       }
 
-fail:
+       if (dhd_parse_logstrs_file(osh, raw_fmts, logstrs_size, temp)
+                       == BCME_OK) {
+               dhd_filp_close(filep, NULL);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
+               set_fs(fs);
+#endif
+               return BCME_OK;
+       }
+
+       fail:
+       if (raw_fmts) {
+               MFREE(osh, raw_fmts, logstrs_size);
+       }
+       if (temp->fmts != NULL) {
+               MFREE(osh, temp->fmts, temp->num_fmts * sizeof(char *));
+       }
+
+       fail1:
        if (!IS_ERR(filep))
-               filp_close(filep, NULL);
+               dhd_filp_close(filep, NULL);
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
        set_fs(fs);
 #endif
+       temp->fmts = NULL;
+       temp->raw_fmts = NULL;
 
-       return err;
+       return BCME_ERROR;
 }
-#ifdef DHD_COREDUMP
-#define PC_FOUND_BIT 0x01
-#define LR_FOUND_BIT 0x02
-#define ALL_ADDR_VAL (PC_FOUND_BIT | LR_FOUND_BIT)
-#define READ_NUM_BYTES 1000
-#define DHD_FUNC_STR_LEN 80
+
 static int
-dhd_lookup_map(osl_t *osh, char *fname, uint32 pc, char *pc_fn,
-               uint32 lr, char *lr_fn)
+dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start,
+               uint32 *rodata_end)
 {
        struct file *filep = NULL;
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
        mm_segment_t fs;
 #endif
-       char *raw_fmts = NULL, *raw_fmts_loc = NULL, *cptr = NULL;
-       uint32 read_size = READ_NUM_BYTES;
        int err = BCME_ERROR;
-       uint32 addr = 0, addr1 = 0, addr2 = 0;
-       char type = '?', type1 = '?', type2 = '?';
-       char func[DHD_FUNC_STR_LEN] = "\0";
-       char func1[DHD_FUNC_STR_LEN] = "\0";
-       char func2[DHD_FUNC_STR_LEN] = "\0";
-       uint8 count = 0;
-       int num, len = 0, offset;
-
-       DHD_TRACE(("%s: fname %s pc 0x%x lr 0x%x \n",
-               __FUNCTION__, fname, pc, lr));
-       if (fname == NULL) {
-               DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__));
-               return BCME_ERROR;
-       }
 
-       /* Allocate 1 byte more than read_size to terminate it with NULL */
-       raw_fmts = MALLOCZ(osh, read_size + 1);
-       if (raw_fmts == NULL) {
-               DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n",
-                       __FUNCTION__));
+       if (fname == NULL) {
+               DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__));
                return BCME_ERROR;
        }
 
@@ -10799,155 +11185,26 @@ dhd_lookup_map(osl_t *osh, char *fname, uint32 pc, char *pc_fn,
        set_fs(KERNEL_DS);
 #endif
 
-       filep = filp_open(fname, O_RDONLY, 0);
-       if (IS_ERR(filep)) {
-               DHD_ERROR(("%s: Failed to open %s \n",  __FUNCTION__, fname));
+       filep = dhd_filp_open(fname, O_RDONLY, 0);
+       if (IS_ERR(filep) || (filep == NULL)) {
+               DHD_ERROR_NO_HW4(("%s: Failed to open %s \n",  __FUNCTION__, fname));
                goto fail;
        }
 
-       if (pc_fn == NULL) {
-               count |= PC_FOUND_BIT;
-       }
-       if (lr_fn == NULL) {
-               count |= LR_FOUND_BIT;
-       }
-       while (count != ALL_ADDR_VAL)
-       {
-               err = dhd_os_read_file(filep, raw_fmts, read_size);
-               if (err < 0) {
-                       DHD_ERROR(("%s: map file read failed err:%d \n",
-                               __FUNCTION__, err));
-                       goto fail;
-               }
-
-               /* End raw_fmts with NULL as strstr expects NULL terminated
-               * strings
-               */
-               raw_fmts[read_size] = '\0';
-               raw_fmts_loc = raw_fmts;
-               offset = 0;
-
-               while ((count != ALL_ADDR_VAL) && (offset < read_size))
-               {
-                       cptr = bcmstrtok(&raw_fmts_loc, "\n", 0);
-                       if (cptr == NULL) {
-                               DHD_TRACE(("%s: cptr is NULL, offset %d"
-                                       " raw_fmts_loc %s \n",
-                                       __FUNCTION__, offset, raw_fmts_loc));
-                               break;
-                       }
-                       DHD_TRACE(("%s: %s \n", __FUNCTION__, cptr));
-                       if ((type2 == 'A') ||
-                               (type2 == 'T') ||
-                               (type2 == 'W')) {
-                               addr1 = addr2;
-                               type1 = type2;
-                               (void)memcpy_s(func1, DHD_FUNC_STR_LEN,
-                                       func2, DHD_FUNC_STR_LEN);
-                               DHD_TRACE(("%s: %x %c %s \n",
-                                       __FUNCTION__, addr1, type1, func1));
-                       }
-                       len = strlen(cptr);
-                       num = sscanf(cptr, "%x %c %79s", &addr, &type, func);
-                       DHD_TRACE(("%s: num %d addr %x type %c func %s \n",
-                               __FUNCTION__, num, addr, type, func));
-                       if (num == 3) {
-                               addr2 = addr;
-                               type2 = type;
-                               (void)memcpy_s(func2, DHD_FUNC_STR_LEN,
-                                       func, DHD_FUNC_STR_LEN);
-                       }
-
-                       if (!(count & PC_FOUND_BIT) &&
-                               (pc >= addr1 && pc < addr2)) {
-                               if ((cptr = strchr(func1, '$')) != NULL) {
-                                       (void)strncpy(func, cptr + 1,
-                                               DHD_FUNC_STR_LEN - 1);
-                               } else {
-                                       (void)memcpy_s(func, DHD_FUNC_STR_LEN,
-                                               func1, DHD_FUNC_STR_LEN);
-                               }
-                               if ((cptr = strstr(func, "__bcmromfn"))
-                                       != NULL) {
-                                       *cptr = 0;
-                               }
-                               if (pc > addr1) {
-                                       sprintf(pc_fn, "%.68s+0x%x",
-                                               func, pc - addr1);
-                               } else {
-                                       (void)memcpy_s(pc_fn, DHD_FUNC_STR_LEN,
-                                               func, DHD_FUNC_STR_LEN);
-                               }
-                               count |= PC_FOUND_BIT;
-                               DHD_INFO(("%s: found addr1 %x pc %x"
-                                       " addr2 %x \n",
-                                       __FUNCTION__, addr1, pc, addr2));
-                       }
-                       if (!(count & LR_FOUND_BIT) &&
-                               (lr >= addr1 && lr < addr2)) {
-                               if ((cptr = strchr(func1, '$')) != NULL) {
-                                       (void)strncpy(func, cptr + 1,
-                                               DHD_FUNC_STR_LEN - 1);
-                               } else {
-                                       (void)memcpy_s(func, DHD_FUNC_STR_LEN,
-                                               func1, DHD_FUNC_STR_LEN);
-                               }
-                               if ((cptr = strstr(func, "__bcmromfn"))
-                                       != NULL) {
-                                       *cptr = 0;
-                               }
-                               if (lr > addr1) {
-                                       sprintf(lr_fn, "%.68s+0x%x",
-                                               func, lr - addr1);
-                               } else {
-                                       (void)memcpy_s(lr_fn, DHD_FUNC_STR_LEN,
-                                               func, DHD_FUNC_STR_LEN);
-                               }
-                               count |= LR_FOUND_BIT;
-                               DHD_INFO(("%s: found addr1 %x lr %x"
-                                       " addr2 %x \n",
-                                       __FUNCTION__, addr1, lr, addr2));
-                       }
-                       offset += (len + 1);
-               }
-
-               if (err < (int)read_size) {
-                       /*
-                       * since we reset file pos back to earlier pos by
-                       * bytes of one line we won't reach EOF.
-                       * The reason for this is if string is spreaded across
-                       * bytes, the read function should not miss it.
-                       * So if ret value is less than read_size, reached EOF
-                       * don't read further
-                       */
-                       break;
-               }
-               memset(raw_fmts, 0, read_size);
-               /*
-               * go back to bytes of one line so that we won't miss
-               * the string and addr even if it comes as splited in next read.
-               */
-               dhd_os_seek_file(filep, -(len + 1));
-               DHD_TRACE(("%s: seek %d \n", __FUNCTION__, -(len + 1)));
-       }
+       if ((err = dhd_parse_map_file(osh, filep, ramstart,
+                       rodata_start, rodata_end)) < 0)
+               goto fail;
 
 fail:
        if (!IS_ERR(filep))
-               filp_close(filep, NULL);
+               dhd_filp_close(filep, NULL);
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
        set_fs(fs);
 #endif
 
-       if (!(count & PC_FOUND_BIT)) {
-               sprintf(pc_fn, "0x%08x", pc);
-       }
-       if (!(count & LR_FOUND_BIT)) {
-               sprintf(lr_fn, "0x%08x", lr);
-       }
        return err;
 }
-#endif /* DHD_COREDUMP */
 
 static int
 dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, char *map_file)
@@ -10983,8 +11240,8 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch
        set_fs(KERNEL_DS);
 #endif
 
-       filep = filp_open(str_file, O_RDONLY, 0);
-       if (IS_ERR(filep)) {
+       filep = dhd_filp_open(str_file, O_RDONLY, 0);
+       if (IS_ERR(filep) || (filep == NULL)) {
                DHD_ERROR(("%s: Failed to open the file %s \n",  __FUNCTION__, str_file));
                goto fail;
        }
@@ -11021,7 +11278,7 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch
                }
        }
 
-       error = vfs_read(filep, raw_fmts, logstrs_size, (&filep->f_pos));
+       error = dhd_vfs_read(filep, raw_fmts, logstrs_size, (&filep->f_pos));
        if (error != logstrs_size) {
                DHD_ERROR(("%s: %s read failed %d \n", __FUNCTION__, str_file, error));
                goto fail;
@@ -11039,7 +11296,7 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch
                temp->rom_rodata_end = rodata_end;
        }
 
-       filp_close(filep, NULL);
+       dhd_filp_close(filep, NULL);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
        set_fs(fs);
 #endif
@@ -11053,7 +11310,7 @@ fail:
 
 fail1:
        if (!IS_ERR(filep))
-               filp_close(filep, NULL);
+               dhd_filp_close(filep, NULL);
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
        set_fs(fs);
@@ -11067,7 +11324,7 @@ fail1:
 
        return error;
 } /* dhd_init_static_strs_array */
-
+#endif /* DHD_LINUX_STD_FW_API */
 #endif /* SHOW_LOGTRACE */
 
 #ifdef BT_OVER_PCIE
@@ -11463,6 +11720,12 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen
                goto fail;
        }
 #endif /* WL_EVENT */
+#ifdef WL_TIMER
+       if (wl_timer_attach(net) != 0) {
+               DHD_ERROR(("wl_ext_timer_attach failed\n"));
+               goto fail;
+       }
+#endif /* WL_TIMER */
 #ifdef WL_ESCAN
        /* Attach and link in the escan */
        if (wl_escan_attach(net) != 0) {
@@ -11517,7 +11780,11 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen
        dhd_os_start_logging(&dhd->pub, BT_LOG_RING_NAME, 3, 0, 0, 0);
 #endif /* !OEM_ANDROID && BTLOG */
 #ifdef DBG_PKT_MON
-       dhd->pub.dbg->pkt_mon_lock = osl_spin_lock_init(dhd->pub.osh);
+       dhd->pub.dbg->pkt_mon_lock = osl_mutex_lock_init(dhd->pub.osh);
+       if (!dhd->pub.dbg->pkt_mon_lock) {
+               DHD_ERROR(("%s: pkt_mon_lock init failed !\n", __FUNCTION__));
+               goto fail;
+       }
 #ifdef DBG_PKT_MON_INIT_DEFAULT
        dhd_os_dbg_attach_pkt_monitor(&dhd->pub);
 #endif /* DBG_PKT_MON_INIT_DEFAULT */
@@ -11625,13 +11892,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen
        }
 #endif /* DHD_PCIE_RUNTIMEPM */
 
-#ifdef SHOW_LOGTRACE
-       skb_queue_head_init(&dhd->evt_trace_queue);
-
-       /* Create ring proc entries */
-       dhd_dbg_ring_proc_create(&dhd->pub);
-#endif /* SHOW_LOGTRACE */
-
 #ifdef BTLOG
        skb_queue_head_init(&dhd->bt_log_queue);
 #endif /* BTLOG */
@@ -11664,6 +11924,13 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen
        }
 #endif /* !BCMDBUS */
 
+#ifdef SHOW_LOGTRACE
+       skb_queue_head_init(&dhd->evt_trace_queue);
+
+       /* Create ring proc entries */
+       dhd_dbg_ring_proc_create(&dhd->pub);
+#endif /* SHOW_LOGTRACE */
+
        dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
 
 #if defined(CONFIG_PM_SLEEP)
@@ -12019,12 +12286,17 @@ bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo)
 
        /* set default firmware and nvram path for built-in type driver */
 //     if (!dhd_download_fw_on_driverload) {
+#ifdef DHD_LINUX_STD_FW_API
+               fw = DHD_FW_NAME;
+               nv = DHD_NVRAM_NAME;
+#else
 #ifdef CONFIG_BCMDHD_FW_PATH
                fw = VENDOR_PATH CONFIG_BCMDHD_FW_PATH;
 #endif /* CONFIG_BCMDHD_FW_PATH */
 #ifdef CONFIG_BCMDHD_NVRAM_PATH
                nv = VENDOR_PATH CONFIG_BCMDHD_NVRAM_PATH;
 #endif /* CONFIG_BCMDHD_NVRAM_PATH */
+#endif /* DHD_LINUX_STD_FW_API */
 //     }
 
        /* check if we need to initialize the path */
@@ -13098,7 +13370,7 @@ static int dhd_preinit_config(dhd_pub_t *dhd, int ifidx)
 
        old_fs = get_fs();
        set_fs(get_ds());
-       if ((ret = vfs_stat(config_path, &stat))) {
+       if ((ret = dhd_vfs_stat(config_path, &stat))) {
                set_fs(old_fs);
                printk(KERN_ERR "%s: Failed to get information (%d)\n",
                        config_path, ret);
@@ -13561,12 +13833,8 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd)
        else {
                bcmstrtok(&ptr, "\n", 0);
                /* Print fw version info */
-               DHD_ERROR(("Firmware version = %s\n", buf));
                strncpy(fw_version, buf, FW_VER_STR_LEN);
                fw_version[FW_VER_STR_LEN-1] = '\0';
-#if defined(BCMSDIO) || defined(BCMPCIE)
-               dhd_set_version_info(dhd, buf);
-#endif /* BCMSDIO || BCMPCIE */
        }
 
        /* query for 'wlc_ver' to get version info from firmware */
@@ -13581,14 +13849,12 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd)
                dhd->wlc_ver_major = wlc_ver.wlc_ver_major;
                dhd->wlc_ver_minor = wlc_ver.wlc_ver_minor;
        }
-#ifdef BOARD_HIKEY
        /* Set op_mode as MFG_MODE if WLTEST is present in "wl ver" */
        if (strstr(fw_version, "WLTEST") != NULL) {
                DHD_ERROR(("%s: wl ver has WLTEST, setting op_mode as DHD_FLAG_MFG_MODE\n",
                        __FUNCTION__));
                op_mode = DHD_FLAG_MFG_MODE;
        }
-#endif /* BOARD_HIKEY */
        /* get a capabilities from firmware */
        ret = dhd_get_fw_capabilities(dhd);
 
@@ -13745,6 +14011,7 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd)
 
        DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n",
                dhd->op_mode, MAC2STRDBG(dhd->mac.octet)));
+       dhd_set_version_info(dhd, fw_version);
 #if defined(DHD_BLOB_EXISTENCE_CHECK)
        if (!dhd->is_blob)
 #endif /* DHD_BLOB_EXISTENCE_CHECK */
@@ -13937,6 +14204,10 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd)
        dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_LLR_MAP);
 #endif /* defined(BCMPCIE) && defined(EAPOL_PKT_PRIO) */
 
+#if defined(BCMSDIO) && defined(DHD_LOSSLESS_ROAMING)
+       dhd_update_sdio_data_prio_map(dhd);
+#endif /* BCMSDIO && DHD_LOSSLESS_ROAMING */
+
 #ifdef ARP_OFFLOAD_SUPPORT
        DHD_ERROR(("arp_enable:%d arp_ol:%d\n",
                dhd->arpoe_enable, dhd->arpol_configured));
@@ -13948,60 +14219,64 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd)
         */
 #ifdef PKT_FILTER_SUPPORT
        /* Setup default defintions for pktfilter , enable in suspend */
-       dhd->pktfilter_count = 6;
-       dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL;
-       if (!FW_SUPPORTED(dhd, pf6)) {
-               dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL;
-               dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
-       } else {
-               /* Immediately pkt filter TYPE 6 Discard IPv4/IPv6 Multicast Packet */
-               dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = DISCARD_IPV4_MCAST;
-               dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = DISCARD_IPV6_MCAST;
-       }
-       /* apply APP pktfilter */
-       dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806";
+       if (dhd_master_mode) {
+               dhd->pktfilter_count = 6;
+               dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL;
+               if (!FW_SUPPORTED(dhd, pf6)) {
+                       dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL;
+                       dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
+               } else {
+                       /* Immediately pkt filter TYPE 6 Discard IPv4/IPv6 Multicast Packet */
+                       dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = DISCARD_IPV4_MCAST;
+                       dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = DISCARD_IPV6_MCAST;
+               }
+               /* apply APP pktfilter */
+               dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806";
 
 #ifdef BLOCK_IPV6_PACKET
-       /* Setup filter to allow only IPv4 unicast frames */
-       dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 "
-               HEX_PREF_STR UNI_FILTER_STR ZERO_ADDR_STR ETHER_TYPE_STR IPV6_FILTER_STR
-               " "
-               HEX_PREF_STR ZERO_ADDR_STR ZERO_ADDR_STR ETHER_TYPE_STR ZERO_TYPE_STR;
+               /* Setup filter to allow only IPv4 unicast frames */
+               dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 "
+                       HEX_PREF_STR UNI_FILTER_STR ZERO_ADDR_STR ETHER_TYPE_STR IPV6_FILTER_STR
+                       " "
+                       HEX_PREF_STR ZERO_ADDR_STR ZERO_ADDR_STR ETHER_TYPE_STR ZERO_TYPE_STR;
 #else
-       /* Setup filter to allow only unicast */
-       dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00";
+               /* Setup filter to allow only unicast */
+               dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00";
 #endif /* BLOCK_IPV6_PACKET */
 
 #ifdef PASS_IPV4_SUSPEND
-       /* XXX customer want to get IPv4 multicast packets */
-       dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFF 0x01005E";
+               /* XXX customer want to get IPv4 multicast packets */
+               dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFF 0x01005E";
 #else
-       /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
-       dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL;
+               /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
+               dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL;
 #endif /* PASS_IPV4_SUSPEND */
-       if (FW_SUPPORTED(dhd, pf6)) {
-               /* Immediately pkt filter TYPE 6 Dicard Broadcast IP packet */
-               dhd->pktfilter[DHD_IP4BCAST_DROP_FILTER_NUM] = DISCARD_IPV4_BCAST;
-               /* Immediately pkt filter TYPE 6 Dicard Cisco STP packet */
-               dhd->pktfilter[DHD_LLC_STP_DROP_FILTER_NUM] = DISCARD_LLC_STP;
-               /* Immediately pkt filter TYPE 6 Dicard Cisco XID protocol */
-               dhd->pktfilter[DHD_LLC_XID_DROP_FILTER_NUM] = DISCARD_LLC_XID;
-               /* Immediately pkt filter TYPE 6 Dicard NETBIOS packet(port 137) */
-               dhd->pktfilter[DHD_UDPNETBIOS_DROP_FILTER_NUM] = DISCARD_UDPNETBIOS;
-               dhd->pktfilter_count = 11;
-       }
+               if (FW_SUPPORTED(dhd, pf6)) {
+                       /* Immediately pkt filter TYPE 6 Dicard Broadcast IP packet */
+                       dhd->pktfilter[DHD_IP4BCAST_DROP_FILTER_NUM] = DISCARD_IPV4_BCAST;
+                       /* Immediately pkt filter TYPE 6 Dicard Cisco STP packet */
+                       dhd->pktfilter[DHD_LLC_STP_DROP_FILTER_NUM] = DISCARD_LLC_STP;
+                       /* Immediately pkt filter TYPE 6 Dicard Cisco XID protocol */
+                       dhd->pktfilter[DHD_LLC_XID_DROP_FILTER_NUM] = DISCARD_LLC_XID;
+                       /* Immediately pkt filter TYPE 6 Dicard NETBIOS packet(port 137) */
+                       dhd->pktfilter[DHD_UDPNETBIOS_DROP_FILTER_NUM] = DISCARD_UDPNETBIOS;
+                       dhd->pktfilter_count = 11;
+               }
 
 #ifdef GAN_LITE_NAT_KEEPALIVE_FILTER
-       dhd->pktfilter_count = 4;
-       /* Setup filter to block broadcast and NAT Keepalive packets */
-       /* discard all broadcast packets */
-       dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0xffffff 0xffffff";
-       /* discard NAT Keepalive packets */
-       dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "102 0 0 36 0xffffffff 0x11940009";
-       /* discard NAT Keepalive packets */
-       dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "104 0 0 38 0xffffffff 0x11940009";
-       dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
+               dhd->pktfilter_count = 4;
+               /* Setup filter to block broadcast and NAT Keepalive packets */
+               /* discard all broadcast packets */
+               dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0xffffff 0xffffff";
+               /* discard NAT Keepalive packets */
+               dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "102 0 0 36 0xffffffff 0x11940009";
+               /* discard NAT Keepalive packets */
+               dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "104 0 0 38 0xffffffff 0x11940009";
+               dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
 #endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */
+       } else
+               dhd_conf_discard_pkt_filter(dhd);
+       dhd_conf_add_pkt_filter(dhd);
 
 #if defined(SOFTAP)
        if (ap_fw_loaded) {
@@ -14243,6 +14518,7 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd)
        dhd_set_bandlock(dhd);
 
 done:
+       dhd_conf_postinit_ioctls(dhd);
        if (iov_buf) {
                MFREE(dhd->osh, iov_buf, WLC_IOCTL_SMLEN);
        }
@@ -14511,14 +14787,12 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd)
                fw_version[FW_VER_STR_LEN-1] = '\0';
        }
 
-#ifdef BOARD_HIKEY
        /* Set op_mode as MFG_MODE if WLTEST is present in "wl ver" */
        if (strstr(fw_version, "WLTEST") != NULL) {
                DHD_ERROR(("%s: wl ver has WLTEST, setting op_mode as DHD_FLAG_MFG_MODE\n",
                        __FUNCTION__));
                op_mode = DHD_FLAG_MFG_MODE;
        }
-#endif /* BOARD_HIKEY */
 
        if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
                (op_mode == DHD_FLAG_MFG_MODE)) {
@@ -15074,7 +15348,7 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd)
        }
 
 #else /* OEM_ANDROID */
-       if ((ret = dhd_apply_default_clm(dhd, clm_path)) < 0) {
+       if ((ret = dhd_apply_default_clm(dhd, dhd->clm_path)) < 0) {
                DHD_ERROR(("%s: CLM set failed. Abort initialization.\n", __FUNCTION__));
                goto done;
        }
@@ -15466,6 +15740,10 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd)
        dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_LLR_MAP);
 #endif /* defined(BCMPCIE) && defined(EAPOL_PKT_PRIO) */
 
+#if defined(BCMSDIO) && defined(DHD_LOSSLESS_ROAMING)
+       dhd_update_sdio_data_prio_map(dhd);
+#endif /* BCMSDIO && DHD_LOSSLESS_ROAMING */
+
 #ifdef RSSI_MONITOR_SUPPORT
        setbit(mask, WLC_E_RSSI_LQM);
 #endif /* RSSI_MONITOR_SUPPORT */
@@ -15502,9 +15780,10 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd)
        setbit(mask, WLC_E_ADDTS_IND);
        setbit(mask, WLC_E_DELTS_IND);
 #endif /* WL_BCNRECV */
-#ifdef CUSTOMER_HW6
        setbit(mask, WLC_E_COUNTRY_CODE_CHANGED);
-#endif /* CUSTOMER_HW6 */
+#if defined(WL_TWT) || defined(WL_TWT_HAL_IF)
+       setbit(mask, WLC_E_TWT);
+#endif /* WL_TWT || WL_TWT_HAL_IF */
 
        /* Write updated Event mask */
        eventmask_msg->ver = EVENTMSGS_VER;
@@ -16694,7 +16973,7 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
         * XXX Linux 2.6.25 does not like a blank MAC address, so use a
         * dummy address until the interface is brought up.
         */
-       memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
+       dev_addr_set(net, temp_addr);
 
        if (ifidx == 0)
                printf("%s\n", dhd_version);
@@ -16734,16 +17013,23 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
        }
 #endif /* BCM_ROUTER_DHD && HNDCTF */
 
+#if defined(WLDWDS) && defined(WL_EXT_IAPSTA)
+       if (ifp->dwds) {
+               wl_ext_iapsta_attach_dwds_netdev(net, ifidx, ifp->bssidx);
+       } else
+#endif /* WLDWDS && WL_EXT_IAPSTA */
+       {
 #ifdef WL_EVENT
-       wl_ext_event_attach_netdev(net, ifidx, ifp->bssidx);
+               wl_ext_event_attach_netdev(net, ifidx, ifp->bssidx);
 #endif /* WL_EVENT */
 #ifdef WL_ESCAN
-       wl_escan_event_attach(net, ifidx);
+               wl_escan_event_attach(net, ifidx);
 #endif /* WL_ESCAN */
 #ifdef WL_EXT_IAPSTA
-       wl_ext_iapsta_attach_netdev(net, ifidx, ifp->bssidx);
-       wl_ext_iapsta_attach_name(net, ifidx);
+               wl_ext_iapsta_attach_netdev(net, ifidx, ifp->bssidx);
+               wl_ext_iapsta_attach_name(net, ifidx);
 #endif /* WL_EXT_IAPSTA */
+       }
 
 #if defined(CONFIG_TIZEN)
        net_stat_tizen_register(net);
@@ -17002,6 +17288,9 @@ void dhd_detach(dhd_pub_t *dhdp)
 #ifdef WL_ESCAN
        wl_escan_detach(dev);
 #endif /* WL_ESCAN */
+#ifdef WL_TIMER
+       wl_timer_dettach(dhdp);
+#endif /* WL_TIMER */
 #ifdef WL_EVENT
        wl_ext_event_dettach(dhdp);
 #endif /* WL_EVENT */
@@ -17189,7 +17478,7 @@ void dhd_detach(dhd_pub_t *dhdp)
        if (dhdp->dbg) {
 #ifdef DBG_PKT_MON
                dhd_os_dbg_detach_pkt_monitor(dhdp);
-               osl_spin_lock_deinit(dhd->pub.osh, dhd->pub.dbg->pkt_mon_lock);
+               osl_mutex_lock_deinit(dhd->pub.osh, dhd->pub.dbg->pkt_mon_lock);
 #endif /* DBG_PKT_MON */
        }
 #endif /* DEBUGABILITY */
@@ -18122,20 +18411,44 @@ exit:
 
 #endif /* DHD_PCIE_RUNTIMEPM */
 
+#ifdef DHD_LINUX_STD_FW_API
+int
+dhd_os_get_img_fwreq(const struct firmware **fw, char *file_path)
+{
+       int ret = BCME_ERROR;
+
+       ret = request_firmware(fw, file_path, dhd_bus_to_dev(g_dhd_pub->bus));
+       if (ret < 0) {
+               DHD_ERROR(("%s: request_firmware %s err: %d\n", __FUNCTION__, file_path, ret));
+               /* convert to BCME_NOTFOUND error for error handling */
+               ret = BCME_NOTFOUND;
+       } else
+                DHD_ERROR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, file_path, (*fw)->size));
+
+       return ret;
+}
+
+void
+dhd_os_close_img_fwreq(const struct firmware *fw)
+{
+       release_firmware(fw);
+}
+#endif /* DHD_LINUX_STD_FW_API */
+
 void *
 dhd_os_open_image1(dhd_pub_t *pub, char *filename)
 {
        struct file *fp;
        int size;
 
-       fp = filp_open(filename, O_RDONLY, 0);
+       fp = dhd_filp_open(filename, O_RDONLY, 0);
        /*
-        * 2.6.11 (FC4) supports filp_open() but later revs don't?
+        * 2.6.11 (FC4) supports dhd_filp_open() but later revs don't?
         * Alternative:
         * fp = open_namei(AT_FDCWD, filename, O_RD, 0);
         * ???
         */
-        if (IS_ERR(fp)) {
+        if (IS_ERR(fp) || (fp == NULL)) {
                 fp = NULL;
                 goto err;
         }
@@ -18146,7 +18459,7 @@ dhd_os_open_image1(dhd_pub_t *pub, char *filename)
                 goto err;
         }
 
-        size = i_size_read(file_inode(fp));
+        size = dhd_i_size_read(file_inode(fp));
         if (size <= 0) {
                 DHD_ERROR(("%s: %s file size invalid %d\n", __FUNCTION__, filename, size));
                 fp = NULL;
@@ -18170,8 +18483,8 @@ dhd_os_get_image_block(char *buf, int len, void *image)
                return 0;
        }
 
-       size = i_size_read(file_inode(fp));
-       rdlen = kernel_read_compat(fp, fp->f_pos, buf, MIN(len, size));
+       size = dhd_i_size_read(file_inode(fp));
+       rdlen = dhd_kernel_read_compat(fp, fp->f_pos, buf, MIN(len, size));
 
        if (len >= size && size != rdlen) {
                return -EIO;
@@ -18196,7 +18509,7 @@ dhd_os_gets_image(dhd_pub_t *pub, char *str, int len, void *image)
        if (!image)
                return 0;
 
-       rd_len = kernel_read_compat(fp, fp->f_pos, str, len);
+       rd_len = dhd_kernel_read_compat(fp, fp->f_pos, str, len);
        str_end = strnchr(str, len, '\n');
        if (str_end == NULL) {
                goto err;
@@ -18221,7 +18534,7 @@ dhd_os_get_image_size(void *image)
                return 0;
        }
 
-       size = i_size_read(file_inode(fp));
+       size = dhd_i_size_read(file_inode(fp));
 
        return size;
 }
@@ -18230,7 +18543,7 @@ void
 dhd_os_close_image1(dhd_pub_t *pub, void *image)
 {
        if (image) {
-               filp_close((struct file *)image, NULL);
+               dhd_filp_close((struct file *)image, NULL);
        }
 }
 
@@ -18905,10 +19218,6 @@ dhd_dev_get_feature_set(struct net_device *dev)
        feature_set |= WIFI_FEATURE_LINKSTAT;
 #endif /* LINKSTAT_SUPPORT */
 
-#ifdef CUSTOMER_HW_AMLOGIC
-       feature_set |= WIFI_FEATURE_SET_LATENCY_MODE;
-#endif
-
 #if defined(PNO_SUPPORT) && !defined(DISABLE_ANDROID_PNO)
        if (dhd_is_pno_supported(dhd)) {
                feature_set |= WIFI_FEATURE_PNO;
@@ -20575,14 +20884,14 @@ int write_file(const char * file_name, uint32 flags, uint8 *buf, int size)
 #endif
 
        /* open file to write */
-       fp = filp_open(file_name, flags, 0664);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(file_name, flags, 0664);
+       if (IS_ERR(fp) || (fp == NULL)) {
                DHD_ERROR(("open file error, err = %ld\n", PTR_ERR(fp)));
                goto exit;
        }
 
        /* Write buf to file */
-       ret = vfs_write(fp, buf, size, &pos);
+       ret = dhd_vfs_write(fp, buf, size, &pos);
        if (ret < 0) {
                DHD_ERROR(("write file error, err = %d\n", ret));
                goto exit;
@@ -20590,7 +20899,7 @@ int write_file(const char * file_name, uint32 flags, uint8 *buf, int size)
 
        /* Sync file from filesystem to physical media */
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
-       ret = vfs_fsync(fp, 0);
+       ret = dhd_vfs_fsync(fp, 0);
 #else
        ret = vfs_fsync(fp, fp->f_path.dentry, 0);
 #endif
@@ -20603,7 +20912,7 @@ int write_file(const char * file_name, uint32 flags, uint8 *buf, int size)
 exit:
        /* close file before return */
        if (!IS_ERR(fp))
-               filp_close(fp, current->files);
+               dhd_filp_close(fp, current->files);
 
        /* restore previous address limit */
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
@@ -20795,14 +21104,14 @@ write_dump_to_file(dhd_pub_t *dhd, uint8 *buf, int size, char *fname)
         */
        file_mode = O_CREAT | O_WRONLY | O_SYNC;
        {
-               struct file *fp = filp_open(memdump_path, file_mode, 0664);
+               struct file *fp = dhd_filp_open(memdump_path, file_mode, 0664);
                /* Check if it is live Brix image having /installmedia, else use /data */
-               if (IS_ERR(fp)) {
+               if (IS_ERR(fp) || (fp == NULL)) {
                        DHD_ERROR(("open file %s, try /data/\n", memdump_path));
                        snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_" "%s",
                                "/data/", fname, memdump_type,  dhd->debug_dump_time_str);
                } else {
-                       filp_close(fp, NULL);
+                       dhd_filp_close(fp, NULL);
                }
        }
 #else
@@ -21663,7 +21972,7 @@ void dhd_set_version_info(dhd_pub_t *dhdp, char *fw)
                return;
 
        i = snprintf(&info_string[i], sizeof(info_string) - i,
-               "\n  Chip: %x Rev %x", dhd_conf_get_chip(dhdp),
+               "\n%s  Chip: %x Rev %x", DHD_LOG_PREFIXS, dhd_conf_get_chip(dhdp),
                dhd_conf_get_chiprev(dhdp));
 }
 
@@ -22162,8 +22471,8 @@ dhd_get_rnd_info(dhd_pub_t *dhd)
        loff_t pos = 0;
 
        /* Read memdump info from the file */
-       fp = filp_open(filepath, file_mode, 0);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(filepath, file_mode, 0);
+       if (IS_ERR(fp) || (fp == NULL)) {
                DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
 #if defined(CONFIG_X86) && defined(OEM_ANDROID)
                /* Check if it is Live Brix Image */
@@ -22173,8 +22482,8 @@ dhd_get_rnd_info(dhd_pub_t *dhd)
                /* Try if it is Installed Brix Image */
                filepath = RNDINFO_INST".in";
                DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath));
-               fp = filp_open(filepath, file_mode, 0);
-               if (IS_ERR(fp)) {
+               fp = dhd_filp_open(filepath, file_mode, 0);
+               if (IS_ERR(fp) || (fp == NULL)) {
                        DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
                        goto err1;
                }
@@ -22187,7 +22496,7 @@ dhd_get_rnd_info(dhd_pub_t *dhd)
        set_fs(KERNEL_DS);
 
        /* Handle success case */
-       ret = vfs_read(fp, (char *)&dhd->rnd_len, sizeof(dhd->rnd_len), &pos);
+       ret = dhd_vfs_read(fp, (char *)&dhd->rnd_len, sizeof(dhd->rnd_len), &pos);
        if (ret < 0) {
                DHD_ERROR(("%s: rnd_len read error, ret=%d\n", __FUNCTION__, ret));
                goto err2;
@@ -22199,14 +22508,14 @@ dhd_get_rnd_info(dhd_pub_t *dhd)
                goto err2;
        }
 
-       ret = vfs_read(fp, (char *)dhd->rnd_buf, dhd->rnd_len, &pos);
+       ret = dhd_vfs_read(fp, (char *)dhd->rnd_buf, dhd->rnd_len, &pos);
        if (ret < 0) {
                DHD_ERROR(("%s: rnd_buf read error, ret=%d\n", __FUNCTION__, ret));
                goto err3;
        }
 
        set_fs(old_fs);
-       filp_close(fp, NULL);
+       dhd_filp_close(fp, NULL);
 
        DHD_ERROR(("%s: RND read from %s\n", __FUNCTION__, filepath));
        return BCME_OK;
@@ -22216,7 +22525,7 @@ err3:
        dhd->rnd_buf = NULL;
 err2:
        set_fs(old_fs);
-       filp_close(fp, NULL);
+       dhd_filp_close(fp, NULL);
 err1:
        return BCME_ERROR;
 }
@@ -22232,8 +22541,8 @@ dhd_dump_rnd_info(dhd_pub_t *dhd, uint8 *rnd_buf, uint32 rnd_len)
        loff_t pos = 0;
 
        /* Read memdump info from the file */
-       fp = filp_open(filepath, file_mode, 0664);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(filepath, file_mode, 0664);
+       if (IS_ERR(fp) || (fp == NULL)) {
                DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
 #if defined(CONFIG_X86) && defined(OEM_ANDROID)
                /* Check if it is Live Brix Image */
@@ -22243,8 +22552,8 @@ dhd_dump_rnd_info(dhd_pub_t *dhd, uint8 *rnd_buf, uint32 rnd_len)
                /* Try if it is Installed Brix Image */
                filepath = RNDINFO_INST".out";
                DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath));
-               fp = filp_open(filepath, file_mode, 0664);
-               if (IS_ERR(fp)) {
+               fp = dhd_filp_open(filepath, file_mode, 0664);
+               if (IS_ERR(fp) || (fp == NULL)) {
                        DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
                        goto err1;
                }
@@ -22257,26 +22566,26 @@ dhd_dump_rnd_info(dhd_pub_t *dhd, uint8 *rnd_buf, uint32 rnd_len)
        set_fs(KERNEL_DS);
 
        /* Handle success case */
-       ret = vfs_write(fp, (char *)&rnd_len, sizeof(rnd_len), &pos);
+       ret = dhd_vfs_write(fp, (char *)&rnd_len, sizeof(rnd_len), &pos);
        if (ret < 0) {
                DHD_ERROR(("%s: rnd_len write error, ret=%d\n", __FUNCTION__, ret));
                goto err2;
        }
 
-       ret = vfs_write(fp, (char *)rnd_buf, rnd_len, &pos);
+       ret = dhd_vfs_write(fp, (char *)rnd_buf, rnd_len, &pos);
        if (ret < 0) {
                DHD_ERROR(("%s: rnd_buf write error, ret=%d\n", __FUNCTION__, ret));
                goto err2;
        }
 
        set_fs(old_fs);
-       filp_close(fp, NULL);
+       dhd_filp_close(fp, NULL);
        DHD_ERROR(("%s: RND written to %s\n", __FUNCTION__, filepath));
        return BCME_OK;
 
 err2:
        set_fs(old_fs);
-       filp_close(fp, NULL);
+       dhd_filp_close(fp, NULL);
 err1:
        return BCME_ERROR;
 
@@ -24194,8 +24503,8 @@ do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type)
        else
                file_mode = O_CREAT | O_RDWR | O_SYNC;
 
-       fp = filp_open(dump_path, file_mode, 0664);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(dump_path, file_mode, 0664);
+       if (IS_ERR(fp) || (fp == NULL)) {
                /* If android installed image, try '/data' directory */
 #if defined(CONFIG_X86) && defined(OEM_ANDROID)
                DHD_ERROR(("%s: File open error on Installed android image, trying /data...\n",
@@ -24206,8 +24515,8 @@ do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type)
                                sizeof(dump_path) - strlen(dump_path),
                                "_%s", dhdp->debug_dump_time_str);
                }
-               fp = filp_open(dump_path, file_mode, 0664);
-               if (IS_ERR(fp)) {
+               fp = dhd_filp_open(dump_path, file_mode, 0664);
+               if (IS_ERR(fp) || (fp == NULL)) {
                        ret = PTR_ERR(fp);
                        DHD_ERROR(("open file error, err = %d\n", ret));
                        goto exit2;
@@ -24221,7 +24530,7 @@ do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type)
        }
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
-       ret = vfs_stat(dump_path, &stat);
+       ret = dhd_vfs_stat(dump_path, &stat);
        if (ret < 0) {
                DHD_ERROR(("file stat error, err = %d\n", ret));
                goto exit2;
@@ -24390,7 +24699,7 @@ do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type)
 
 exit2:
        if (!IS_ERR(fp) && fp != NULL) {
-               filp_close(fp, NULL);
+               dhd_filp_close(fp, NULL);
                DHD_ERROR(("%s: Finished writing log dump to file - '%s' \n",
                                __FUNCTION__, dump_path));
        }
@@ -24425,7 +24734,7 @@ dhd_export_debug_data(void *mem_buf, void *fp, const void *user_buf, uint32 buf_
        int ret = BCME_OK;
 
        if (fp) {
-               ret = vfs_write(fp, mem_buf, buf_len, (loff_t *)pos);
+               ret = dhd_vfs_write(fp, mem_buf, buf_len, (loff_t *)pos);
                if (ret < 0) {
                        DHD_ERROR(("write file error, err = %d\n", ret));
                        goto exit;
@@ -26326,8 +26635,8 @@ dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path)
        struct file *fp;
        char *filepath = VENDOR_PATH CONFIG_BCMDHD_CLM_PATH;
 
-       fp = filp_open(filepath, O_RDONLY, 0);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(filepath, O_RDONLY, 0);
+       if (IS_ERR(fp) || (fp == NULL)) {
                DHD_ERROR(("%s: ----- blob file doesn't exist (%s) -----\n", __FUNCTION__,
                        filepath));
                dhdp->is_blob = FALSE;
@@ -26339,7 +26648,7 @@ dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path)
 #else
                BCM_REFERENCE(fw_path);
 #endif /* SKIP_CONCATE_BLOB */
-               filp_close(fp, NULL);
+               dhd_filp_close(fp, NULL);
        }
 }
 #endif /* DHD_BLOB_EXISTENCE_CHECK */
@@ -26496,14 +26805,14 @@ dhd_write_file(const char *filepath, char *buf, int buf_len)
 #endif
 
        /* File is always created. */
-       fp = filp_open(filepath, O_RDWR | O_CREAT, 0664);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(filepath, O_RDWR | O_CREAT, 0664);
+       if (IS_ERR(fp) || (fp == NULL)) {
                DHD_ERROR(("%s: Couldn't open file '%s' err %ld\n",
                        __FUNCTION__, filepath, PTR_ERR(fp)));
                ret = BCME_ERROR;
        } else {
                if (fp->f_mode & FMODE_WRITE) {
-                       ret = vfs_write(fp, buf, buf_len, &fp->f_pos);
+                       ret = dhd_vfs_write(fp, buf, buf_len, &fp->f_pos);
                        if (ret < 0) {
                                DHD_ERROR(("%s: Couldn't write file '%s'\n",
                                        __FUNCTION__, filepath));
@@ -26512,7 +26821,7 @@ dhd_write_file(const char *filepath, char *buf, int buf_len)
                                ret = BCME_OK;
                        }
                }
-               filp_close(fp, NULL);
+               dhd_filp_close(fp, NULL);
        }
 
        /* restore previous address limit */
@@ -26538,8 +26847,8 @@ dhd_read_file(const char *filepath, char *buf, int buf_len)
        set_fs(KERNEL_DS);
 #endif
 
-       fp = filp_open(filepath, O_RDONLY, 0);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(filepath, O_RDONLY, 0);
+       if (IS_ERR(fp) || (fp == NULL)) {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
                set_fs(old_fs);
 #endif
@@ -26547,8 +26856,8 @@ dhd_read_file(const char *filepath, char *buf, int buf_len)
                return BCME_ERROR;
        }
 
-       ret = kernel_read_compat(fp, 0, buf, buf_len);
-       filp_close(fp, NULL);
+       ret = dhd_kernel_read_compat(fp, 0, buf, buf_len);
+       dhd_filp_close(fp, NULL);
 
        /* restore previous address limit */
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
@@ -27361,7 +27670,11 @@ dhd_print_kirqstats(dhd_pub_t *dhd, unsigned int irq_num)
        char tmp_buf[KIRQ_PRINT_BUF_LEN];
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0))
+       desc = irq_data_to_desc(irq_get_irq_data(irq_num));
+#else
        desc = irq_to_desc(irq_num);
+#endif // (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0))
        if (!desc) {
                DHD_ERROR(("%s : irqdesc is not found \n", __FUNCTION__));
                return;
@@ -29344,27 +29657,15 @@ dhd_ring_whole_unlock(void *_ring)
 }
 /* END of DHD RING */
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0))
-#define DHD_VFS_INODE(dir) (dir->d_inode)
-#else
-#define DHD_VFS_INODE(dir) d_inode(dir)
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) */
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
-#define DHD_VFS_UNLINK(dir, b, c) vfs_unlink(DHD_VFS_INODE(dir), b)
-#else
-#define DHD_VFS_UNLINK(dir, b, c) vfs_unlink(DHD_VFS_INODE(dir), b, c)
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
-
 #if ((defined DHD_DUMP_MNGR) || (defined DNGL_AXI_ERROR_LOGGING))
 int
 dhd_file_delete(char *path)
 {
-       struct path file_path;
+       struct path file_path = {.dentry = 0};
        int err;
        struct dentry *dir;
 
-       err = kern_path(path, 0, &file_path);
+       err = dhd_kern_path(path, 0, &file_path);
 
        if (err < 0) {
                DHD_ERROR(("Failed to get kern-path delete file: %s error: %d\n", path, err));
@@ -29823,65 +30124,69 @@ bool dhd_os_wd_timer_enabled(void *bus)
 
 #if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG)
 /* This function is to automatically add/del interface to the bridged dev that priamy dev is in */
-static void dhd_bridge_dev_set(dhd_info_t *dhd, int ifidx, struct net_device *dev)
+static void
+dhd_bridge_dev_set(dhd_info_t *dhd, int ifidx, struct net_device *sdev)
 {
-       struct net_device *primary_ndev = NULL, *br_dev = NULL;
-       int cmd;
-       struct ifreq ifr;
+       struct net_device *pdev = NULL, *br_dev = NULL;
+       int i, err = 0;
 
-       /* add new interface to bridge dev */
-       if (dev) {
-               int found = 0, i;
-               DHD_ERROR(("bssidx %d\n", dhd->pub.info->iflist[ifidx]->bssidx));
-               for (i = 0 ; i < ifidx; i++) {
-                       DHD_ERROR(("bssidx %d %d\n", i, dhd->pub.info->iflist[i]->bssidx));
-                       /* search the primary interface */
-                       if (dhd->pub.info->iflist[i]->bssidx == dhd->pub.info->iflist[ifidx]->bssidx) {
-                               primary_ndev = dhd->pub.info->iflist[i]->net;
-                               DHD_ERROR(("%dst is primary dev %s\n", i, primary_ndev->name));
-                               found = 1;
+       if (sdev) {
+               /* search the primary interface wlan1(wl0.1) with same bssidx */
+               for (i = 0; i < ifidx; i++) {
+                       if (dhd->iflist[i]->bssidx == dhd->iflist[ifidx]->bssidx) {
+                               pdev = dhd->pub.info->iflist[i]->net;
+                               WL_MSG(sdev->name, "found primary dev %s\n", pdev->name);
                                break;
                        }
                }
-               if (found == 0) {
-                       DHD_ERROR(("Can not find primary dev %s\n", dev->name));
+               if (!pdev) {
+                       WL_MSG(sdev->name, "can not find primary dev\n");
                        return;
                }
-               cmd = SIOCBRADDIF;
-               ifr.ifr_ifindex = dev->ifindex;
-       } else { /* del interface from bridge dev */
-               primary_ndev = dhd->pub.info->iflist[ifidx]->net;
-               cmd = SIOCBRDELIF;
-               ifr.ifr_ifindex = primary_ndev->ifindex;
+       } else {
+               pdev = dhd->iflist[ifidx]->net;
        }
+
        /* if primary net device is bridged */
-       if (primary_ndev->priv_flags & IFF_BRIDGE_PORT) {
+       if (pdev->priv_flags & IFF_BRIDGE_PORT) {
                rtnl_lock();
                /* get bridge device */
-               br_dev = netdev_master_upper_dev_get(primary_ndev);
+               br_dev = netdev_master_upper_dev_get(pdev);
                if (br_dev) {
                        const struct net_device_ops *ops = br_dev->netdev_ops;
-                       DHD_ERROR(("br %s pri %s\n", br_dev->name, primary_ndev->name));
                        if (ops) {
-                               if (cmd == SIOCBRADDIF) {
-                                       DHD_ERROR(("br call ndo_add_slave\n"));
-                                       ops->ndo_add_slave(br_dev, dev);
+                               if (sdev) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+                                       err = ops->ndo_add_slave(br_dev, sdev, NULL);
+#else
+                                       err = ops->ndo_add_slave(br_dev, sdev);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */
+                                       if (err)
+                                               WL_MSG(sdev->name, "add to %s failed %d\n", br_dev->name, err);
+                                       else
+                                               WL_MSG(sdev->name, "slave added to %s\n", br_dev->name);
                                        /* Also bring wds0.x interface up automatically */
-                                       dev_change_flags(dev, dev->flags | IFF_UP);
-                               }
-                               else {
-                                       DHD_ERROR(("br call ndo_del_slave\n"));
-                                       ops->ndo_del_slave(br_dev, primary_ndev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0))
+                                       dev_change_flags(sdev, sdev->flags | IFF_UP, NULL);
+#else
+                                       dev_change_flags(sdev, sdev->flags | IFF_UP);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) */
+                               } else {
+                                       err = ops->ndo_del_slave(br_dev, pdev);
+                                       if (err)
+                                               WL_MSG(pdev->name, "del from %s failed %d\n", br_dev->name, err);
+                                       else
+                                               WL_MSG(pdev->name, "slave deleted from %s\n", br_dev->name);
                                }
                        }
                }
                else {
-                       DHD_ERROR(("no br dev\n"));
+                       WL_MSG(pdev->name, "not bridged\n");
                }
                rtnl_unlock();
        }
        else {
-               DHD_ERROR(("device %s is not bridged\n", primary_ndev->name));
+               WL_MSG(pdev->name, "not bridged\n");
        }
 }
-#endif /* defiend(WLDWDS) && defined(FOURADDR_AUTO_BRG) */
+#endif /* WLDWDS && FOURADDR_AUTO_BRG */
index 531505d6bd04eed18f07948fbac797b7a1a0ded0..565b1a47ac3784f708fd53518bbe485ced3afc6a 100755 (executable)
@@ -67,9 +67,8 @@
 /* dongle status */
 enum wifi_adapter_status {
        WIFI_STATUS_POWER_ON = 0,
-       WIFI_STATUS_ATTACH,
        WIFI_STATUS_FW_READY,
-       WIFI_STATUS_DETTACH
+       WIFI_STATUS_NET_ATTACHED
 };
 #define wifi_chk_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status))
 #define wifi_get_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status))
@@ -407,6 +406,9 @@ typedef struct dhd_if {
        bool recv_reassoc_evt;
        bool post_roam_evt;
 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
+#ifdef WLDWDS
+       bool dwds;      /* DWDS interface */
+#endif /* WLDWDS */
 #ifdef WLEASYMESH
        uint8 _1905_al_ucast[ETHER_ADDR_LEN];
        uint8 _1905_al_mcast[ETHER_ADDR_LEN];
index ef5b0cc794bd3311446eac78395207947b910b14..7377f4ed347be963431aa18cc6b0b8d8f7b4a273 100755 (executable)
@@ -177,6 +177,7 @@ dhd_dbg_ring_proc_destroy(dhd_pub_t *dhdp)
  * -----------------------------------------------------------------------------
  */
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
 #if defined(DHD_TRACE_WAKE_LOCK)
 extern atomic_t trace_wklock_onoff;
 
@@ -1030,6 +1031,7 @@ done:
        return ret;
 }
 #endif /* PWRSTATS_SYSFS */
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
 
 /*
  * Generic Attribute Structure for DHD.
@@ -1046,6 +1048,7 @@ struct dhd_attr {
        ssize_t(*store)(struct dhd_info *, const char *, size_t count);
 };
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
 #if defined(DHD_TRACE_WAKE_LOCK)
 static struct dhd_attr dhd_attr_wklock =
        __ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff);
@@ -1119,10 +1122,12 @@ static struct dhd_attr dhd_attr_nvram_path =
 static struct dhd_attr dhd_attr_pwrstats_path =
        __ATTR(power_stats, 0660, show_pwrstats_path, NULL);
 #endif /* PWRSTATS_SYSFS */
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
 
 #define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj)
 #define to_attr(a) container_of(a, struct dhd_attr, attr)
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
 #ifdef DHD_MAC_ADDR_EXPORT
 struct ether_addr sysfs_mac_addr;
 static ssize_t
@@ -1154,6 +1159,7 @@ set_mac_addr(struct dhd_info *dev, const char *buf, size_t count)
 static struct dhd_attr dhd_attr_macaddr =
        __ATTR(mac_addr, 0660, show_mac_addr, set_mac_addr);
 #endif /* DHD_MAC_ADDR_EXPORT */
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
 
 #ifdef DHD_FW_COREDUMP
 /*
@@ -1185,8 +1191,8 @@ get_mem_val_from_file(void)
        int ret = 0;
 
        /* Read memdump info from the file */
-       fp = filp_open(filepath, O_RDONLY, 0);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(filepath, O_RDONLY, 0);
+       if (IS_ERR(fp) || (fp == NULL)) {
                DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
 #if defined(CONFIG_X86) && defined(OEM_ANDROID)
                /* Check if it is Live Brix Image */
@@ -1196,8 +1202,8 @@ get_mem_val_from_file(void)
                /* Try if it is Installed Brix Image */
                filepath = MEMDUMPINFO_INST;
                DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath));
-               fp = filp_open(filepath, O_RDONLY, 0);
-               if (IS_ERR(fp)) {
+               fp = dhd_filp_open(filepath, O_RDONLY, 0);
+               if (IS_ERR(fp) || (fp == NULL)) {
                        DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
                        goto done;
                }
@@ -1207,10 +1213,10 @@ get_mem_val_from_file(void)
        }
 
        /* Handle success case */
-       ret = kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32));
+       ret = dhd_kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32));
        if (ret < 0) {
                DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
-               filp_close(fp, NULL);
+               dhd_filp_close(fp, NULL);
                goto done;
        }
 
@@ -1218,7 +1224,7 @@ get_mem_val_from_file(void)
        p_mem_val[sizeof(uint32) - 1] = '\0';
        mem_val = bcm_atoi(p_mem_val);
 
-       filp_close(fp, NULL);
+       dhd_filp_close(fp, NULL);
 
 done:
        return mem_val;
@@ -1262,6 +1268,7 @@ void dhd_get_memdump_info(dhd_pub_t *dhd)
        DHD_ERROR(("%s: MEMDUMP ENABLED = %u\n", __FUNCTION__, dhd->memdump_enabled));
 }
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
 #ifdef DHD_EXPORT_CNTL_FILE
 static ssize_t
 show_memdump_info(struct dhd_info *dev, char *buf)
@@ -1303,6 +1310,7 @@ set_memdump_info(struct dhd_info *dev, const char *buf, size_t count)
 static struct dhd_attr dhd_attr_memdump =
        __ATTR(memdump, 0660, show_memdump_info, set_memdump_info);
 #endif /* DHD_EXPORT_CNTL_FILE */
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
 #endif /* DHD_FW_COREDUMP */
 
 #ifdef BCMASSERT_LOG
@@ -1327,11 +1335,11 @@ get_assert_val_from_file(void)
         * 2: Trigger Kernel crash by BUG()
         * File doesn't exist: Keep default value (1).
         */
-       fp = filp_open(filepath, O_RDONLY, 0);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(filepath, O_RDONLY, 0);
+       if (IS_ERR(fp) || (fp == NULL)) {
                DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
        } else {
-               int ret = kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32));
+               int ret = dhd_kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32));
                if (ret < 0) {
                        DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret));
                } else {
@@ -1340,7 +1348,7 @@ get_assert_val_from_file(void)
                        mem_val = bcm_atoi(p_mem_val);
                        DHD_ERROR(("%s: ASSERT ENABLED = %d\n", __FUNCTION__, mem_val));
                }
-               filp_close(fp, NULL);
+               dhd_filp_close(fp, NULL);
        }
 
 #ifdef CUSTOMER_HW4_DEBUG
@@ -1362,6 +1370,7 @@ void dhd_get_assert_info(dhd_pub_t *dhd)
 #endif /* !DHD_EXPORT_CNTL_FILE */
 }
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
 #ifdef DHD_EXPORT_CNTL_FILE
 static ssize_t
 show_assert_info(struct dhd_info *dev, char *buf)
@@ -1396,8 +1405,10 @@ set_assert_info(struct dhd_info *dev, const char *buf, size_t count)
 static struct dhd_attr dhd_attr_assert =
        __ATTR(assert, 0660, show_assert_info, set_assert_info);
 #endif /* DHD_EXPORT_CNTL_FILE */
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
 #endif /* BCMASSERT_LOG */
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
 #ifdef DHD_EXPORT_CNTL_FILE
 #if defined(WRITE_WLANINFO)
 static ssize_t
@@ -1889,10 +1900,12 @@ store_adps_bam_list(struct dhd_info *dev, const char *buf, size_t count)
 static struct dhd_attr dhd_attr_adps_bam =
        __ATTR(bad_ap_list, 0660, show_adps_bam_list, store_adps_bam_list);
 #endif /* DHD_ADPS_BAM_EXPORT && WL_BAM */
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
 
-#ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
 uint32 report_hang_privcmd_err = 1;
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
+#ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
 static ssize_t
 show_hang_privcmd_err(struct dhd_info *dev, char *buf)
 {
@@ -2350,6 +2363,7 @@ static struct attribute *default_file_attrs[] = {
 #endif /* AGG_H2D_DB */
        NULL
 };
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
 
 /*
  * wifi kobject show function, the "attr" attribute specifices to which
@@ -2406,7 +2420,9 @@ static struct sysfs_ops dhd_sysfs_ops = {
 
 static struct kobj_type dhd_ktype = {
        .sysfs_ops = &dhd_sysfs_ops,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
        .default_attrs = default_file_attrs,
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
 };
 
 #ifdef CSI_SUPPORT
@@ -2436,6 +2452,7 @@ static struct bin_attribute dhd_attr_csi = {
  * sysfs for dhd_lb
  */
 #ifdef DHD_LB
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
 #if defined(DHD_LB_TXP)
 static ssize_t
 show_lbtxp(struct dhd_info *dev, char *buf)
@@ -2830,6 +2847,7 @@ static struct attribute *debug_lb_attrs[] = {
        &dhd_tx_cpu.attr,
        NULL
 };
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
 
 #define to_dhd_lb(k) container_of(k, struct dhd_info, dhd_lb_kobj)
 
@@ -2888,7 +2906,9 @@ static struct sysfs_ops dhd_sysfs_lb_ops = {
 
 static struct kobj_type dhd_lb_ktype = {
        .sysfs_ops = &dhd_sysfs_lb_ops,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
        .default_attrs = debug_lb_attrs,
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */
 };
 #endif /* DHD_LB */
 
index 66e0b44614f38afbe52d575954b61ab515f46e14..028bc762a5260d9f1881917014bba39b48cefff3 100755 (executable)
@@ -1047,13 +1047,34 @@ dhd_check_dhcp(uint8 *pktdata)
        return TRUE;
 }
 
-#ifdef DHD_DHCP_DUMP
 #define BOOTP_CHADDR_LEN               16
 #define BOOTP_SNAME_LEN                        64
 #define BOOTP_FILE_LEN                 128
 #define BOOTP_MIN_DHCP_OPT_LEN         312
 #define BOOTP_MAGIC_COOKIE_LEN         4
 
+typedef struct bootp_fmt {
+       struct ipv4_hdr iph;
+       struct bcmudp_hdr udph;
+       uint8 op;
+       uint8 htype;
+       uint8 hlen;
+       uint8 hops;
+       uint32 transaction_id;
+       uint16 secs;
+       uint16 flags;
+       uint32 client_ip;
+       uint32 assigned_ip;
+       uint32 server_ip;
+       uint32 relay_ip;
+       uint8 hw_address[BOOTP_CHADDR_LEN];
+       uint8 server_name[BOOTP_SNAME_LEN];
+       uint8 file_name[BOOTP_FILE_LEN];
+       uint8 options[BOOTP_MIN_DHCP_OPT_LEN];
+} PACKED_STRUCT bootp_fmt_t;
+static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 };
+
+#ifdef DHD_DHCP_DUMP
 #define DHCP_MSGTYPE_DISCOVER          1
 #define DHCP_MSGTYPE_OFFER             2
 #define DHCP_MSGTYPE_REQUEST           3
@@ -1077,27 +1098,6 @@ dhd_check_dhcp(uint8 *pktdata)
                } \
        } while (0)
 
-typedef struct bootp_fmt {
-       struct ipv4_hdr iph;
-       struct bcmudp_hdr udph;
-       uint8 op;
-       uint8 htype;
-       uint8 hlen;
-       uint8 hops;
-       uint32 transaction_id;
-       uint16 secs;
-       uint16 flags;
-       uint32 client_ip;
-       uint32 assigned_ip;
-       uint32 server_ip;
-       uint32 relay_ip;
-       uint8 hw_address[BOOTP_CHADDR_LEN];
-       uint8 server_name[BOOTP_SNAME_LEN];
-       uint8 file_name[BOOTP_FILE_LEN];
-       uint8 options[BOOTP_MIN_DHCP_OPT_LEN];
-} PACKED_STRUCT bootp_fmt_t;
-
-static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 };
 static char dhcp_ops[][10] = {
        "NA", "REQUEST", "REPLY"
 };
@@ -1576,3 +1576,160 @@ dhd_trx_pkt_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen, bool
        }
 }
 #endif /* DHD_RX_DUMP */
+
+#ifdef BCMPCIE
+static bool
+dhd_is_eapol_pkt(dhd_pub_t *dhd, uint8 *pktdata, uint32 pktlen)
+{
+       eapol_header_t *eapol_hdr = (eapol_header_t *)pktdata;
+
+       eapol_hdr = (eapol_header_t *)pktdata;
+
+       if (eapol_hdr->type == EAP_PACKET) {
+               return TRUE;
+       } else if (eapol_hdr->type == EAPOL_START) {
+               return TRUE;
+       } else if (eapol_hdr->type == EAPOL_KEY) {
+               return TRUE;
+       } else {
+               return TRUE;
+       }
+       return FALSE;
+}
+
+static bool
+dhd_is_arp_pkt(dhd_pub_t *dhdp, uint8 *pktdata)
+{
+       uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN];
+       struct bcmarp *arph = (struct bcmarp *)pkt;
+       uint16 opcode;
+
+       /* validation check */
+       if (arph->htype != hton16(HTYPE_ETHERNET) ||
+               arph->hlen != ETHER_ADDR_LEN ||
+               arph->plen != 4) {
+               return FALSE;
+       }
+
+       opcode = ntoh16(arph->oper);
+       if (opcode == ARP_OPC_REQUEST) {
+               return TRUE;
+       } else if (opcode == ARP_OPC_REPLY) {
+               return TRUE;
+       } else {
+               return TRUE;
+       }
+       return FALSE;
+}
+
+static bool
+dhd_is_dhcp_pkt(dhd_pub_t *dhdp, uint8 *pktdata)
+{
+       bootp_fmt_t *b = (bootp_fmt_t *)&pktdata[ETHER_HDR_LEN];
+       struct ipv4_hdr *iph = &b->iph;
+       uint8 *ptr, *opt, *end = (uint8 *) b + ntohs(b->iph.tot_len);
+       int len, opt_len;
+
+       /* check IP header */
+       if ((IPV4_HLEN(iph) < IPV4_HLEN_MIN) ||
+               IP_VER(iph) != IP_VER_4 ||
+               IPV4_PROT(iph) != IP_PROT_UDP) {
+               return FALSE;
+       }
+
+       /* check UDP port for bootp (67, 68) */
+       if (b->udph.src_port != htons(DHCP_PORT_SERVER) &&
+               b->udph.src_port != htons(DHCP_PORT_CLIENT) &&
+               b->udph.dst_port != htons(DHCP_PORT_SERVER) &&
+               b->udph.dst_port != htons(DHCP_PORT_CLIENT)) {
+               return FALSE;
+       }
+
+       /* check header length */
+       if (ntohs(iph->tot_len) < ntohs(b->udph.len) + sizeof(struct bcmudp_hdr)) {
+               return FALSE;
+       }
+
+       len = ntohs(b->udph.len) - sizeof(struct bcmudp_hdr);
+       opt_len = len - (sizeof(*b) - sizeof(struct ipv4_hdr) -
+               sizeof(struct bcmudp_hdr) - sizeof(b->options));
+
+       /* parse bootp options */
+       if (opt_len >= BOOTP_MAGIC_COOKIE_LEN &&
+               !memcmp(b->options, bootp_magic_cookie, BOOTP_MAGIC_COOKIE_LEN)) {
+               ptr = &b->options[BOOTP_MAGIC_COOKIE_LEN];
+               while (ptr < end && *ptr != 0xff) {
+                       opt = ptr++;
+                       if (*opt == 0) {
+                               continue;
+                       }
+                       ptr += *ptr + 1;
+                       if (ptr >= end) {
+                               break;
+                       }
+                       if (*opt == DHCP_OPT_MSGTYPE) {
+                               if (opt[1]) {
+                                       return TRUE;
+                               }
+                       }
+               }
+       }
+
+       return FALSE;
+}
+
+static bool
+dhd_is_icmp_pkt(dhd_pub_t *dhd, uint8 *pktdata, uint32 pktlen)
+{
+       uint8 *pkt;
+       struct ipv4_hdr *iph;
+
+       pkt = (uint8 *)&pktdata[ETHER_HDR_LEN];
+       iph = (struct ipv4_hdr *)pkt;
+
+       /* check IP header */
+       if ((IPV4_HLEN(iph) < IPV4_HLEN_MIN) ||
+               IP_VER(iph) != IP_VER_4 ||
+               IPV4_PROT(iph) != IP_PROT_ICMP) {
+               return FALSE;
+       }
+
+       /* check header length */
+       if (ntohs(iph->tot_len) - IPV4_HLEN(iph) < sizeof(struct bcmicmp_hdr)) {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+bool
+dhd_match_pkt_type(dhd_pub_t *dhd, uint8 *pktdata, uint32 pktlen)
+{
+       struct ether_header *eh;
+       uint16 ether_type;
+       bool match = FALSE;
+
+       if (!pktdata || pktlen < ETHER_HDR_LEN) {
+               return match;
+       }
+
+       eh = (struct ether_header *)pktdata;
+       ether_type = ntoh16(eh->ether_type);
+       if ((dhd->conf->enq_hdr_pkt & ENQ_PKT_TYPE_EAPOL) &&
+                       ether_type == ETHER_TYPE_802_1X) {
+               match = dhd_is_eapol_pkt(dhd, pktdata, pktlen);
+       }
+       else if ((dhd->conf->enq_hdr_pkt & ENQ_PKT_TYPE_ARP) &&
+                       ntoh16(eh->ether_type) == ETHER_TYPE_ARP) {
+               match = dhd_is_arp_pkt(dhd, pktdata);
+       }
+       else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
+               if (dhd->conf->enq_hdr_pkt & ENQ_PKT_TYPE_ICMP)
+                       match = dhd_is_icmp_pkt(dhd, pktdata, pktlen);
+               if (!match && dhd->conf->enq_hdr_pkt & ENQ_PKT_TYPE_DHCP)
+                       match = dhd_is_dhcp_pkt(dhd, pktdata);
+       }
+
+       return match;
+}
+#endif /* BCMPCIE */
index 7d7ce72b4ff6a23dd44029c7ec10cc0e771b8afb..96a160ae33fafe85f9d776b6919d70109e8a50a2 100755 (executable)
@@ -59,6 +59,9 @@ enum pkt_type {
 extern msg_eapol_t dhd_is_4way_msg(uint8 *pktdata);
 extern void dhd_dump_pkt(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
        uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate);
+#ifdef BCMPCIE
+extern bool dhd_match_pkt_type(dhd_pub_t *dhd, uint8 *pktdata, uint32 pktlen);
+#endif /* BCMPCIE */
 #ifdef DHD_PKTDUMP_ROAM
 extern void dhd_dump_mod_pkt_timer(dhd_pub_t *dhdp, uint16 rsn);
 extern void dhd_dump_pkt_init(dhd_pub_t *dhdp);
index 8410748920646fda97f2b5b5187c075b582753f0..8d2eb8d9bdb504738925ddfee3a4bb6be307f2c8 100755 (executable)
@@ -42,9 +42,6 @@
 #else
 #include <dhd_plat.h>
 #endif /* CONFIG_WIFI_CONTROL_FUNC */
-#ifdef BCMDBUS
-#include <dbus.h>
-#endif
 #ifdef CONFIG_DTS
 #include<linux/regulator/consumer.h>
 #include<linux/of_gpio.h>
@@ -170,7 +167,7 @@ void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned
                return NULL;
        plat_data = adapter->wifi_plat_data;
        if (plat_data->mem_prealloc) {
-#ifdef BCMDHD_MDRIVER
+#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER)
                alloc_ptr = plat_data->mem_prealloc(adapter->bus_type, adapter->index, section, size);
 #else
                alloc_ptr = plat_data->mem_prealloc(section, size);
@@ -569,16 +566,7 @@ static int wifi_ctrlfunc_register_drv(void)
                return -ENOMEM;
        }
        adapter->name = "DHD generic adapter";
-       adapter->index = -1;
-#ifdef BCMDHD_MDRIVER
-#ifdef BCMSDIO
        adapter->index = 0;
-#elif defined(BCMPCIE)
-       adapter->index = 1;
-#elif defined(BCMDBUS)
-       adapter->index = 2;
-#endif
-#endif
        adapter->bus_type = -1;
        adapter->bus_num = -1;
        adapter->slot_num = -1;
@@ -771,10 +759,11 @@ static int dhd_wifi_platform_load_pcie(void)
                err = dhd_bus_register();
        } else {
 #ifdef DHD_SUPPORT_HDM
-               if (dhd_download_fw_on_driverload || hdm_trigger_init) {
+               if (dhd_download_fw_on_driverload || hdm_trigger_init)
 #else
-               if (dhd_download_fw_on_driverload) {
+               if (dhd_download_fw_on_driverload)
 #endif /* DHD_SUPPORT_HDM */
+               {
                        /* power up all adapters */
                        for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
                                int retry = POWERUP_MAX_RETRY;
@@ -896,7 +885,9 @@ static int dhd_wifi_platform_load_sdio(void)
        for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
                bool chip_up = FALSE;
                int retry = POWERUP_MAX_RETRY;
+#ifndef DHD_INSMOD_NOWAIT
                struct semaphore dhd_chipup_sem;
+#endif
 
                adapter = &dhd_wifi_platdata->adapters[i];
 
@@ -907,6 +898,18 @@ static int dhd_wifi_platform_load_sdio(void)
                        adapter->bus_type, adapter->bus_num, adapter->slot_num));
 
                do {
+#ifdef DHD_INSMOD_NOWAIT
+                       err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY);
+                       if (err) {
+                               DHD_ERROR(("%s: wifi pwr on error ! \n", __FUNCTION__));
+                               wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
+                               continue;
+                       } else {
+                               wifi_platform_bus_enumerate(adapter, TRUE);
+                               chip_up = TRUE;
+                               break;
+                       }
+#else
 #ifndef CUSTOMER_HW_AMLOGIC
                        sema_init(&dhd_chipup_sem, 0);
                        err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem);
@@ -946,6 +949,7 @@ static int dhd_wifi_platform_load_sdio(void)
                        dhd_bus_unreg_sdio_notify();
                        wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
                        wifi_platform_bus_enumerate(adapter, FALSE);
+#endif
                } while (retry--);
 
                if (!chip_up) {
@@ -962,6 +966,7 @@ static int dhd_wifi_platform_load_sdio(void)
                goto fail;
        }
 
+#ifndef DHD_INSMOD_NOWAIT
        /*
         * Wait till MMC sdio_register_driver callback called and made driver attach.
         * It's needed to make sync up exit from dhd insmod  and
@@ -973,6 +978,7 @@ static int dhd_wifi_platform_load_sdio(void)
                dhd_bus_unregister();
                goto fail;
        }
+#endif
 
        return err;
 
@@ -1005,7 +1011,6 @@ static int dhd_wifi_platform_load_usb(void)
        wifi_adapter_info_t *adapter;
        s32 timeout = -1;
        int i;
-       enum wifi_adapter_status wait_status;
 #endif
 
 #if !defined(DHD_PRELOAD)
@@ -1014,7 +1019,7 @@ static int dhd_wifi_platform_load_usb(void)
                adapter = &dhd_wifi_platdata->adapters[i];
                wifi_platform_set_power(adapter, FALSE, 0);
                if (err) {
-                       DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name));
+                       DHD_ERROR(("failed to wifi_platform_set_power off %s\n", adapter->name));
                        goto exit;
                }
        }
@@ -1041,12 +1046,8 @@ static int dhd_wifi_platform_load_usb(void)
                        DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name));
                        goto fail;
                }
-               if (dhd_download_fw_on_driverload)
-                       wait_status = WIFI_STATUS_ATTACH;
-               else
-                       wait_status = WIFI_STATUS_DETTACH;
                timeout = wait_event_interruptible_timeout(adapter->status_event,
-                       wifi_get_adapter_status(adapter, wait_status),
+                       wifi_get_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED),
                        msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT));
                if (timeout <= 0) {
                        err = -1;
index dd145dffbf1504cfb7b2be830b455788ffafc944..6085bcd2a9177798b12ec4161d6625396221bd7c 100755 (executable)
 #include "dhdioctl.h"
 #include <sdiovar.h>
 
-#ifdef BCMDBUS
-#include <dbus.h>
-#define BUS_IOVAR_OP(a, b, c, d, e, f, g) dbus_iovar_op(a->dbus, b, c, d, e, f, g)
-#else
 #include <dhd_bus.h>
 #define BUS_IOVAR_OP dhd_bus_iovar_op
-#endif
 
 typedef struct _macdbg_info_t {
        dhd_pub_t *dhdp;
index 12eb4e0f814e02fa9aec31ea1faa0acefeeb2648..1b6b7ceaaef27834d5407e9b1b721c47cd2b8630 100755 (executable)
 #include <dhd.h>
 #include <dhd_proto.h>
 
-#ifdef BCMDBUS
-#include <dbus.h>
-#else
 #include <dhd_bus.h>
-#endif /* BCMDBUS */
 
 #include <dhd_dbg.h>
 #include <siutils.h>
index f69951d59ad5d9996f3b6b877ef1b4f7ce4e13dc..96bc798dbd9612caa4045d6cd58864bcc85d68b9 100755 (executable)
 #if defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON)
 #include <dhd_linux_priv.h>
 #endif /* DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */
+#include <dhd_linux_pktdump.h>
 
 #define EXTENDED_PCIE_DEBUG_DUMP 1     /* Enable Extended pcie registers dump */
 
@@ -3991,6 +3992,118 @@ exit:
 }
 #endif /* BCMINTERNAL */
 
+#ifdef DHD_LINUX_STD_FW_API
+static int
+dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path)
+{
+       int bcmerror = BCME_ERROR;
+       int offset = 0;
+       int len = 0;
+       bool store_reset;
+       int offset_end = bus->ramsize;
+       const struct firmware *fw = NULL;
+       int buf_offset = 0, residual_len = 0;
+#ifdef CHECK_DOWNLOAD_FW
+       uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct
+#endif
+
+#if defined(DHD_FW_MEM_CORRUPTION)
+       if (dhd_bus_get_fw_mode(bus->dhd) == DHD_FLAG_MFG_MODE) {
+               dhd_tcm_test_enable = TRUE;
+       } else {
+               dhd_tcm_test_enable = FALSE;
+       }
+#endif /* DHD_FW_MEM_CORRUPTION */
+       DHD_ERROR(("%s: dhd_tcm_test_enable %u\n", __FUNCTION__, dhd_tcm_test_enable));
+       /* TCM check */
+       if (dhd_tcm_test_enable && !dhd_bus_tcm_test(bus)) {
+               DHD_ERROR(("dhd_bus_tcm_test failed\n"));
+               bcmerror = BCME_ERROR;
+               goto err;
+       }
+
+       DHD_ERROR(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
+
+       /* check if CR4/CA7 */
+       store_reset = (si_setcore(bus->sih, ARMCR4_CORE_ID, 0) ||
+                       si_setcore(bus->sih, ARMCA7_CORE_ID, 0));
+
+       bcmerror = dhd_os_get_img_fwreq(&fw, bus->fw_path);
+       if (bcmerror < 0) {
+               DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n",
+                       bcmerror));
+               goto err;
+       }
+#ifdef CHECK_DOWNLOAD_FW
+       if (bus->dhd->conf->fwchk) {
+               memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
+               if (memptr_tmp == NULL) {
+                       DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
+                       goto err;
+               }
+       }
+#endif
+       residual_len = fw->size;
+       while (residual_len) {
+               len = MIN(residual_len, MEMBLOCK);
+
+               /* if address is 0, store the reset instruction to be written in 0 */
+               if (store_reset) {
+                       ASSERT(offset == 0);
+                       bus->resetinstr = *(((uint32*)fw->data + buf_offset));
+                       /* Add start of RAM address to the address given by user */
+                       offset += bus->dongle_ram_base;
+                       offset_end += offset;
+                       store_reset = FALSE;
+               }
+
+               bcmerror = dhdpcie_bus_membytes(bus, TRUE, offset,
+                       (uint8 *)fw->data + buf_offset, len);
+               if (bcmerror) {
+                       DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
+                               __FUNCTION__, bcmerror, MEMBLOCK, offset));
+                       goto err;
+               }
+#ifdef CHECK_DOWNLOAD_FW
+               if (bus->dhd->conf->fwchk) {
+                       bcmerror = dhdpcie_bus_membytes(bus, FALSE, offset, memptr_tmp, len);
+                       if (bcmerror) {
+                               DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
+                                       __FUNCTION__, bcmerror, MEMBLOCK, offset));
+                               goto err;
+                       }
+                       if (memcmp(memptr_tmp, (uint8 *)fw->data + buf_offset, len)) {
+                               DHD_ERROR(("%s: Downloaded image is corrupted at 0x%08x\n", __FUNCTION__, offset));
+                               bcmerror = BCME_ERROR;
+                               goto err;
+                       } else
+                               DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
+               }
+#endif
+               offset += MEMBLOCK;
+
+               if (offset >= offset_end) {
+                       DHD_ERROR(("%s: invalid address access to %x (offset end: %x)\n",
+                               __FUNCTION__, offset, offset_end));
+                       bcmerror = BCME_ERROR;
+                       goto err;
+               }
+               residual_len -= len;
+               buf_offset += len;
+       }
+err:
+#ifdef CHECK_DOWNLOAD_FW
+       if (memptr_tmp)
+               MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN);
+#endif
+       if (fw) {
+               dhd_os_close_img_fwreq(fw);
+       }
+       return bcmerror;
+} /* dhdpcie_download_code_file */
+
+#else
+
 /**
  * Downloads a file containing firmware into dongle memory. In case of a .bea file, the DHD
  * is updated with the event logging partitions within that file as well.
@@ -4197,6 +4310,7 @@ err:
 
        return bcmerror;
 } /* dhdpcie_download_code_file */
+#endif /* DHD_LINUX_STD_FW_API */
 
 #ifdef CUSTOMER_HW4_DEBUG
 #define MIN_NVRAMVARS_SIZE 128
@@ -4206,7 +4320,7 @@ static int
 dhdpcie_download_nvram(struct dhd_bus *bus)
 {
        int bcmerror = BCME_ERROR;
-       uint len;
+       uint len, memblock_len = 0;
        char * memblock = NULL;
        char *bufp;
        char *pnv_path;
@@ -4253,6 +4367,11 @@ dhdpcie_download_nvram(struct dhd_bus *bus)
        } else {
                nvram_uefi_exists = TRUE;
        }
+#ifdef DHD_LINUX_STD_FW_API
+       memblock_len = len;
+#else
+       memblock_len = MAX_NVRAMBUF_SIZE;
+#endif /* DHD_LINUX_STD_FW_API */
 
        DHD_ERROR(("%s: dhd_get_download_buffer len %d\n", __FUNCTION__, len));
 
@@ -4313,7 +4432,7 @@ err:
                if (local_alloc) {
                        MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
                } else {
-                       dhd_free_download_buffer(bus->dhd, memblock, MAX_NVRAMBUF_SIZE);
+                       dhd_free_download_buffer(bus->dhd, memblock, memblock_len);
                }
        }
 
@@ -5689,6 +5808,7 @@ BCMFASTPATH(dhd_bus_txdata)(struct dhd_bus *bus, void *txp, uint8 ifidx)
        void *ntxp = NULL;
        uint8 prio = PKTPRIO(txp);
 #endif
+       uint8 *pktdata = (uint8 *)PKTDATA(bus->dhd->osh, txp);
 
        if (!bus->dhd->flowid_allocator) {
                DHD_ERROR(("%s: Flow ring not intited yet  \n", __FUNCTION__));
@@ -5777,6 +5897,10 @@ BCMFASTPATH(dhd_bus_txdata)(struct dhd_bus *bus, void *txp, uint8 ifidx)
                }
        }
 #else  /* !(defined(BCM_ROUTER_DHD) && defined(HNDCTF)) */
+       if (dhd_match_pkt_type(bus->dhd, pktdata, (uint32)PKTLEN(bus->dhd->osh, txp))) {
+               if ((ret = dhd_flow_queue_enqueue_head(bus->dhd, queue, txp)) != BCME_OK)
+                       txp_pend = txp;
+       } else
        if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp)) != BCME_OK)
                txp_pend = txp;
 #endif /* defined(BCM_ROUTER_DHD) && defined(HNDCTF */
@@ -5814,6 +5938,13 @@ BCMFASTPATH(dhd_bus_txdata)(struct dhd_bus *bus, void *txp, uint8 ifidx)
                        }
                }
 #else  /* !(defined(BCM_ROUTER_DHD) && defined(HNDCTF)) */
+               if (dhd_match_pkt_type(bus->dhd, pktdata, (uint32)PKTLEN(bus->dhd->osh, txp))) {
+                       if ((ret = dhd_flow_queue_enqueue_head(bus->dhd, queue, txp_pend)) != BCME_OK) {
+                               DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+                               txp = txp_pend;
+                               goto toss;
+                       }
+               } else
                if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp_pend)) != BCME_OK) {
                        DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
                        txp = txp_pend;
@@ -9571,7 +9702,7 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state)
                        /* Got D3 Ack. Suspend the bus */
 #ifdef OEM_ANDROID
                        if (active) {
-                               DHD_ERROR(("%s():Suspend failed because of wakelock"
+                               DHD_ERROR(("%s():Suspend failed because of wakelock "
                                        "restoring Dongle to D0\n", __FUNCTION__));
 
                                if (bus->dhd->dhd_watchdog_ms_backup) {
index 2a18c7cecd87ccd966a886c2355cf76bde285d5f..dbeab688d5140679a60d62a0362b21253c68f87d 100755 (executable)
@@ -268,7 +268,7 @@ static const struct dev_pm_ops dhdpcie_pm_ops = {
 
 static struct pci_driver dhdpcie_driver = {
        node:           {&dhdpcie_driver.node, &dhdpcie_driver.node},
-       name:           "pcieh",
+       name:           "pcieh"BUS_TYPE,
        id_table:       dhdpcie_pci_devid,
        probe:          dhdpcie_pci_probe,
        remove:         dhdpcie_pci_remove,
@@ -1737,7 +1737,7 @@ dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info)
 {
        dhd_bus_t *bus = dhdpcie_info->bus;
        struct pci_dev *pdev = dhdpcie_info->bus->dev;
-       int host_irq_disabled;
+       int host_irq_disabled, err = 0;
 
        if (!bus->irq_registered) {
                snprintf(dhdpcie_info->pciname, sizeof(dhdpcie_info->pciname),
@@ -1752,13 +1752,14 @@ dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info)
                }
 
                if (bus->d2h_intr_method == PCIE_MSI)
-                       printf("%s: MSI enabled\n", __FUNCTION__);
+                       printf("%s: MSI enabled, irq=%d\n", __FUNCTION__, pdev->irq);
                else
-                       printf("%s: INTx enabled\n", __FUNCTION__);
+                       printf("%s: INTx enabled, irq=%d\n", __FUNCTION__, pdev->irq);
 
-               if (request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED,
-                       dhdpcie_info->pciname, bus) < 0) {
-                       DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__));
+               err = request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED,
+                       dhdpcie_info->pciname, bus);
+               if (err < 0) {
+                       DHD_ERROR(("%s: request_irq() failed with %d\n", __FUNCTION__, err));
                        if (bus->d2h_intr_method == PCIE_MSI) {
                                dhdpcie_disable_msi(pdev);
                        }
@@ -2050,8 +2051,12 @@ int dhdpcie_init(struct pci_dev *pdev)
                        adapter->bus_num = pdev->bus->number;
                        adapter->slot_num = PCI_SLOT(pdev->devfn);
                        adapter->pci_dev = pdev;
-               } else
+               } else {
                        DHD_ERROR(("%s: can't find adapter info for this chip\n", __FUNCTION__));
+#ifdef ADAPTER_IDX
+                       break;
+#endif
+               }
                osl_static_mem_init(osh, adapter);
 
                /*  allocate linux spcific pcie structure here */
@@ -2286,7 +2291,8 @@ int dhdpcie_init(struct pci_dev *pdev)
 
        if (dhdpcie_info)
                dhdpcie_detach(dhdpcie_info);
-       pci_disable_device(pdev);
+       if (adapter)
+               pci_disable_device(pdev);
        if (osh)
                osl_detach(osh);
        if (adapter != NULL) {
@@ -2406,7 +2412,13 @@ dhdpcie_enable_irq(dhd_bus_t *bus)
 int
 dhdpcie_irq_disabled(dhd_bus_t *bus)
 {
-       struct irq_desc *desc = irq_to_desc(bus->dev->irq);
+       struct irq_desc *desc = NULL;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0))
+       desc = irq_data_to_desc(irq_get_irq_data(bus->dev->irq));
+#else
+       desc = irq_to_desc(bus->dev->irq);
+#endif // (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0))
        /* depth will be zero, if enabled */
        return desc->depth;
 }
@@ -3345,7 +3357,9 @@ dhd_dongle_mem_dump(void)
        dhd_bus_mem_dump(g_dhd_bus->dhd);
        return 0;
 }
+#ifndef BCMDHD_MDRIVER
 EXPORT_SYMBOL(dhd_dongle_mem_dump);
+#endif
 #endif /* DHD_FW_COREDUMP */
 
 #ifdef CONFIG_ARCH_MSM
@@ -3376,4 +3390,6 @@ dhd_bus_check_driver_up(void)
 
        return isup;
 }
+#ifndef BCMDHD_MDRIVER
 EXPORT_SYMBOL(dhd_bus_check_driver_up);
+#endif
index 0d573444c593ace118828f54ecf5e718abbb9aa1..d491cd0bdc9338cb52369ae626d4377ce13923b5 100755 (executable)
@@ -1204,8 +1204,8 @@ dhd_pktlog_dump_write_file(dhd_pub_t *dhdp)
        set_fs(KERNEL_DS);
        file_mode = O_CREAT | O_WRONLY;
 
-       w_pcap_fp = filp_open(pktlogdump_path, file_mode, 0664);
-       if (IS_ERR(w_pcap_fp)) {
+       w_pcap_fp = dhd_filp_open(pktlogdump_path, file_mode, 0664);
+       if (IS_ERR(w_pcap_fp) || (w_pcap_fp == NULL)) {
                DHD_ERROR(("%s: Couldn't open file '%s' err %ld\n",
                        __FUNCTION__, pktlogdump_path, PTR_ERR(w_pcap_fp)));
                ret = BCME_ERROR;
@@ -1219,14 +1219,14 @@ dhd_pktlog_dump_write_file(dhd_pub_t *dhdp)
        }
 
        /* Sync file from filesystem to physical media */
-       ret = vfs_fsync(w_pcap_fp, 0);
+       ret = dhd_vfs_fsync(w_pcap_fp, 0);
        if (ret < 0) {
                DHD_ERROR(("%s(): sync pcap file error, err = %d\n", __FUNCTION__, ret));
                goto fail;
        }
 fail:
        if (!IS_ERR(w_pcap_fp)) {
-               filp_close(w_pcap_fp, NULL);
+               dhd_filp_close(w_pcap_fp, NULL);
        }
 
        set_fs(old_fs);
index 8c07b5b0f3568e9f3cbc50ba7837bbe1ebfd86db..d9cd04f69d3a906ef12ee7d12f9ddbaa0f5a4e6d 100755 (executable)
@@ -38,7 +38,7 @@ struct wifi_platform_data {
 #ifdef DHD_COREDUMP
        int (*set_coredump)(const char *buf, int buf_len, const char *info);
 #endif /* DHD_COREDUMP */
-#ifdef BCMDHD_MDRIVER
+#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER)
        void *(*mem_prealloc)(uint bus_type, int index, int section, unsigned long size);
 #else
        void *(*mem_prealloc)(int section, unsigned long size);
index 7f0b1216c0b941520edffaa3901afb058a2cdc08..b7640eec9080ffc8c595ded82347b35d1184af41 100755 (executable)
@@ -121,6 +121,10 @@ extern uint dhd_prot_hdrlen(dhd_pub_t *, void *txp);
 /* Remove any protocol-specific data header. */
 extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len);
 
+#ifdef DHD_LOSSLESS_ROAMING
+extern int dhd_update_sdio_data_prio_map(dhd_pub_t *dhdp);
+#endif // DHD_LOSSLESS_ROAMING
+
 /* Use protocol to issue ioctl to dongle */
 extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len);
 
index 6fdb0e90fcb4b7fb90aba5f5d043fbee114318ad..5de437e9a0ce235ef9b63ad2cf98d6326b1998a9 100755 (executable)
@@ -69,6 +69,7 @@
 #include <dhd_dbg.h>
 #include <dhdioctl.h>
 #include <sdiovar.h>
+#include <wl_android.h>
 #include <dhd_config.h>
 #ifdef DHD_PKTDUMP_TOFW
 #include <dhd_linux_pktdump.h>
@@ -1198,14 +1199,14 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
        int err = 0;
        int try_cnt = 0, try_max = CUSTOM_MAX_KSO_ATTEMPTS;
        struct dhd_conf *conf = bus->dhd->conf;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) && !defined(ANDROID13_KERNEL515_BKPORT)
        wifi_adapter_info_t *adapter = NULL;
        uint32 bus_type = -1, bus_num = -1, slot_num = -1;
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) */
 
        KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) && !defined(ANDROID13_KERNEL515_BKPORT)
        dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num);
        adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
        sdio_retune_crc_disable(adapter->sdio_func);
@@ -1334,7 +1335,7 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
 #endif /* !defined(NDIS) */
 
 exit:
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) && !defined(ANDROID13_KERNEL515_BKPORT)
        if (on)
                sdio_retune_release(adapter->sdio_func);
        sdio_retune_crc_enable(adapter->sdio_func);
@@ -1968,6 +1969,9 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
 #if defined(BCMSDIOH_STD)
        uint32 sd3_tuning_disable = FALSE;
 #endif /* BCMSDIOH_STD */
+#if defined(WL_EXT_IAPSTA) && defined(DHD_LOSSLESS_ROAMING)
+       int state;
+#endif /* WL_EXT_IAPSTA && DHD_LOSSLESS_ROAMING */
 
        DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
                 (sleep ? "SLEEP" : "WAKE"),
@@ -1990,6 +1994,13 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
                if (bus->dpc_sched || bus->rxskip || pktq_n_pkts_tot(&bus->txq))
 #endif /* DHD_USE_IDLECOUNT */
                        return BCME_BUSY;
+#if defined(WL_EXT_IAPSTA) && defined(DHD_LOSSLESS_ROAMING)
+               state = wl_ext_any_sta_handshaking(bus->dhd);
+               if (state) {
+                       DHD_ERROR(("handshaking %d\n", state));
+                       return BCME_BUSY;
+               }
+#endif /* WL_EXT_IAPSTA && DHD_LOSSLESS_ROAMING */
 
 #ifdef BT_OVER_SDIO
                /*
@@ -2718,7 +2729,7 @@ static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt)
        /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
        frame = (uint8*)PKTDATA(osh, pkt);
 
-       DHD_INFO(("%s PKTLEN before postprocess %d",
+       DHD_INFO(("%s PKTLEN before postprocess %d\n",
                __FUNCTION__, PKTLEN(osh, pkt)));
 
        /* PKTLEN still includes tail_padding, so exclude it.
@@ -3857,6 +3868,57 @@ xfer_done:
        return bcmerror;
 }
 
+#if defined(BCMSDIO_RXLIM_POST) || defined(BCMSDIO_TXSEQ_SYNC)
+static void
+dhdsdio_txseq_sync(dhd_bus_t *bus, sdpcm_shared_t *sh)
+{
+       struct dhd_conf *conf = bus->dhd->conf;
+
+       if (sh->flags & SDPCM_SHARED_RXLIM_POST) {
+#ifdef BCMSDIO_RXLIM_POST
+               if (conf->rxlim_en) {
+                       if (sh->msgtrace_addr) {
+                               bus->rxlim_en = TRUE;
+                               bus->rxlim_addr = sh->msgtrace_addr;
+                               DHD_INFO(("%s: RXLIM_POST enabled with rxlim_addr=0x%x\n",
+                                       __FUNCTION__, bus->rxlim_addr));
+                       } else {
+                               DHD_INFO(("%s: RXLIM_POST not enabled in fw\n", __FUNCTION__));
+                       }
+               } else
+#endif /* BCMSDIO_RXLIM_POST */
+#ifdef BCMSDIO_TXSEQ_SYNC
+               if (conf->txseq_sync) {
+                       uint8 val = 0;
+                       sh->txseq_sync_addr = ltoh32(sh->txseq_sync_addr);
+                       DHD_INFO(("%s: TXSEQ_SYNC enabled\n", __FUNCTION__));
+                       if (0 == dhdsdio_membytes(bus, FALSE, sh->txseq_sync_addr, (uint8 *)&val, 1)) {
+                               if (bus->tx_seq != val) {
+                                       DHD_INFO(("%s: Sync tx_seq from %d to %d\n",
+                                               __FUNCTION__, bus->tx_seq, val));
+                                       bus->tx_seq = val;
+                                       bus->tx_max = bus->tx_seq + 4;
+                               }
+                       }
+               } else
+#endif /* BCMSDIO_TXSEQ_SYNC */
+               {
+                       DHD_INFO(("%s: rxlim_en and txseq_sync not enabled in config.txt\n", __FUNCTION__));
+               }
+               sh->flags &= ~SDPCM_SHARED_RXLIM_POST;
+       }
+       else {
+#ifdef BCMSDIO_RXLIM_POST
+               bus->rxlim_en = 0;
+#endif /* BCMSDIO_RXLIM_POST */
+#ifdef BCMSDIO_TXSEQ_SYNC
+               conf->txseq_sync = FALSE;
+#endif /* BCMSDIO_TXSEQ_SYNC */
+               DHD_INFO(("%s: TXSEQ_SYNC and RXLIM_POST not supported in fw\n", __FUNCTION__));
+       }
+}
+#endif /* BCMSDIO_RXLIM_POST || BCMSDIO_TXSEQ_SYNC */
+
 static int
 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
 {
@@ -3923,41 +3985,9 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
        sh->console_addr = ltoh32(sh->console_addr);
        sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
 
-#ifdef BCMSDIO_RXLIM_POST
-       if (sh->flags & SDPCM_SHARED_RXLIM_POST) {
-               if (bus->dhd->conf->rxlim_en)
-                       bus->rxlim_en = !!sh->msgtrace_addr;
-               bus->rxlim_addr = sh->msgtrace_addr;
-               DHD_INFO(("%s: rxlim_en=%d, rxlim enable=%d, rxlim_addr=%d\n",
-                       __FUNCTION__,
-                       bus->dhd->conf->rxlim_en, bus->rxlim_en, bus->rxlim_addr));
-               sh->flags &= ~SDPCM_SHARED_RXLIM_POST;
-       } else {
-               bus->rxlim_en = 0;
-               DHD_INFO(("%s: FW has no rx limit post support\n", __FUNCTION__));
-       }
-#endif /* BCMSDIO_RXLIM_POST */
-
-#ifdef BCMSDIO_TXSEQ_SYNC
-       if (bus->dhd->conf->txseq_sync) {
-               sh->txseq_sync_addr = ltoh32(sh->txseq_sync_addr);
-               if (sh->flags & SDPCM_SHARED_TXSEQ_SYNC) {
-                       uint8 val = 0;
-                       DHD_INFO(("%s: TXSEQ_SYNC enabled in fw\n", __FUNCTION__));
-                       if (0 == dhdsdio_membytes(bus, FALSE, sh->txseq_sync_addr, (uint8 *)&val, 1)) {
-                               if (bus->tx_seq != val) {
-                                       DHD_INFO(("%s: Sync tx_seq from %d to %d\n",
-                                               __FUNCTION__, bus->tx_seq, val));
-                                       bus->tx_seq = val;
-                                       bus->tx_max = bus->tx_seq + 4;
-                               }
-                       }
-                       sh->flags &= ~SDPCM_SHARED_TXSEQ_SYNC;
-               } else {
-                       bus->dhd->conf->txseq_sync = FALSE;
-               }
-       }
-#endif /* BCMSDIO_TXSEQ_SYNC */
+#if defined(BCMSDIO_RXLIM_POST) || defined(BCMSDIO_TXSEQ_SYNC)
+       dhdsdio_txseq_sync(bus, sh);
+#endif
 
        /*
         * XXX - Allow a sdpcm_shared_t version mismatch between dhd structure
@@ -8019,7 +8049,11 @@ clkwait:
        } else if (bus->clkstate == CLK_PENDING) {
                /* Awaiting I_CHIPACTIVE; don't resched */
        } else if (bus->intstatus || bus->ipend ||
-                       (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
+                       (!bus->fcstate && (pktq_mlen(&bus->txq, ((~bus->flowcontrol)
+#ifdef DHD_LOSSLESS_ROAMING
+                       & bus->dhd->dequeue_prec_map
+#endif /* DHD_LOSSLESS_ROAMING */
+                       ))) && DATAOK(bus)) ||
                        PKT_AVAILABLE(bus, bus->intstatus)) {  /* Read multiple frames */
                resched = TRUE;
        }
@@ -8594,6 +8628,13 @@ int dhd_bus_get_oob_irq_num(dhd_pub_t *dhdp)
        return irq_num;
 }
 
+#ifdef LINUX
+struct device *dhd_bus_to_dev(struct dhd_bus *bus)
+{
+       return (struct device *)bcmsdh_get_dev(bus->sdh);
+}
+#endif /* LINUX */
+
 void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub)
 {
 #ifdef LINUX
@@ -10042,6 +10083,7 @@ dhdsdio_suspend(void *context)
                /* resume all interface network queue. */
                dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
        }
+       bus->dhd->hostsleep = 2;
        DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd);
        dhd_os_busbusy_wake(bus->dhd);
        DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
@@ -10073,6 +10115,7 @@ dhdsdio_resume(void *context)
 
        DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
        DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd);
+       bus->dhd->hostsleep = 0;
        bus->dhd->busstate = DHD_BUS_DATA;
        dhd_os_busbusy_wake(bus->dhd);
        /* resume all interface network queue. */
@@ -10213,6 +10256,144 @@ err:
 }
 #endif /* BCMEMBEDIMAGE */
 
+#ifdef DHD_LINUX_STD_FW_API
+static int
+dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
+{
+       int bcmerror = -1;
+       int offset = 0;
+       int len;
+       uint8 *memblock = NULL, *memptr;
+#ifdef CHECK_DOWNLOAD_FW
+       uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct
+#endif
+       uint memblock_size = MEMBLOCK;
+#ifdef DHD_DEBUG_DOWNLOADTIME
+       unsigned long initial_jiffies = 0;
+       uint firmware_sz = 0;
+#endif
+       int offset_end = bus->ramsize;
+       const struct firmware *fw = NULL;
+       int buf_offset = 0, residual_len = 0;
+
+       DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
+
+       /* XXX: Should succeed in opening image if it is actually given through registry
+        * entry or in module param.
+        */
+       bcmerror = dhd_os_get_img_fwreq(&fw, bus->fw_path);
+       if (bcmerror < 0) {
+               DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n",
+                       bcmerror));
+               goto err;
+       }
+       residual_len = fw->size;
+
+       /* Update the dongle image download block size depending on the F1 block size */
+#ifndef NDIS
+       if (sd_f1_blocksize == 512)
+               memblock_size = MAX_MEMBLOCK;
+#endif /* !NDIS */
+
+       memptr = memblock = MALLOC(bus->dhd->osh, memblock_size + DHD_SDALIGN);
+       if (memblock == NULL) {
+               DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
+                       memblock_size));
+               goto err;
+       }
+       if ((uint32)(uintptr)memblock % DHD_SDALIGN)
+               memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
+
+#ifdef CHECK_DOWNLOAD_FW
+               if (bus->dhd->conf->fwchk) {
+                       memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
+                       if (memptr_tmp == NULL) {
+                               DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
+                               goto err;
+                       }
+               }
+#endif
+
+#ifdef DHD_DEBUG_DOWNLOADTIME
+       initial_jiffies = jiffies;
+#endif
+
+       /* Download image */
+       while (residual_len) {
+               len = MIN(residual_len, memblock_size);
+               bcopy((uint8 *)fw->data + buf_offset, (uint8 *)memptr, len);
+               /* check if CR4 */
+               if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
+                       /* if address is 0, store the reset instruction to be written in 0 */
+
+                       if (offset == 0) {
+                               bus->resetinstr = *(((uint32*)memptr));
+                               /* Add start of RAM address to the address given by user */
+                               offset += bus->dongle_ram_base;
+                               offset_end += offset;
+                       }
+               }
+
+               bcmerror = dhdsdio_membytes(bus, TRUE, offset, (uint8 *)memptr, len);
+               if (bcmerror) {
+                       DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
+                               __FUNCTION__, bcmerror, memblock_size, offset));
+                       goto err;
+               }
+
+#ifdef CHECK_DOWNLOAD_FW
+               if (bus->dhd->conf->fwchk) {
+                       bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len);
+                       if (bcmerror) {
+                               DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
+                                       __FUNCTION__, bcmerror, MEMBLOCK, offset));
+                               goto err;
+                       }
+                       if (memcmp(memptr_tmp, memptr, len)) {
+                               DHD_ERROR(("%s: Downloaded image is corrupted at 0x%08x\n", __FUNCTION__, offset));
+                               bcmerror = BCME_ERROR;
+                               goto err;
+                       } else
+                               DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
+               }
+#endif
+
+               offset += memblock_size;
+#ifdef DHD_DEBUG_DOWNLOADTIME
+               firmware_sz += len;
+#endif
+               if (offset >= offset_end) {
+                       DHD_ERROR(("%s: invalid address access to %x (offset end: %x)\n",
+                               __FUNCTION__, offset, offset_end));
+                       bcmerror = BCME_ERROR;
+                       goto err;
+               }
+               residual_len -= len;
+               buf_offset += len;
+       }
+
+#ifdef DHD_DEBUG_DOWNLOADTIME
+       DHD_ERROR(("Firmware download time for %u bytes: %u ms\n",
+                       firmware_sz, jiffies_to_msecs(jiffies - initial_jiffies)));
+#endif
+
+err:
+       if (memblock)
+               MFREE(bus->dhd->osh, memblock, memblock_size + DHD_SDALIGN);
+#ifdef CHECK_DOWNLOAD_FW
+       if (bus->dhd->conf->fwchk) {
+               if (memptr_tmp)
+                       MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN);
+       }
+#endif
+
+       if (fw) {
+               dhd_os_close_img_fwreq(fw);
+       }
+
+       return bcmerror;
+}
+#else
 static int
 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
 {
@@ -10253,6 +10434,9 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
                        memblock_size));
                goto err;
        }
+       if ((uint32)(uintptr)memblock % DHD_SDALIGN)
+               memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
+
 #ifdef CHECK_DOWNLOAD_FW
        if (bus->dhd->conf->fwchk) {
                memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
@@ -10262,8 +10446,6 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
                }
        }
 #endif
-       if ((uint32)(uintptr)memblock % DHD_SDALIGN)
-               memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
 
 #ifdef DHD_DEBUG_DOWNLOADTIME
        initial_jiffies = jiffies;
@@ -10345,6 +10527,7 @@ err:
 
        return bcmerror;
 }
+#endif /* DHD_LINUX_STD_FW_API */
 
 #ifdef DHD_UCODE_DOWNLOAD
 /* Currently supported only for the chips in which ucode RAM is AXI addressable */
@@ -10480,8 +10663,7 @@ static int
 dhdsdio_download_nvram(struct dhd_bus *bus)
 {
        int bcmerror = -1;
-       uint len;
-       void * image = NULL;
+       uint len, memblock_len = 0;
        char * memblock = NULL;
        char *bufp;
        char *pnv_path;
@@ -10491,24 +10673,21 @@ dhdsdio_download_nvram(struct dhd_bus *bus)
 
        nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
 
-       /* For Get nvram from UEFI */
-       if (nvram_file_exists) {
-               image = dhd_os_open_image1(bus->dhd, pnv_path);
-               if (image == NULL) {
-                       printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
-                       goto err;
-               }
-       }
+       len = MAX_NVRAMBUF_SIZE;
+       if (nvram_file_exists)
+               bcmerror = dhd_get_download_buffer(bus->dhd, pnv_path, NVRAM, &memblock,
+                       (int *)&len);
+       else
+               bcmerror = dhd_get_download_buffer(bus->dhd, NULL, NVRAM, &memblock, (int *)&len);
 
-       memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
-       if (memblock == NULL) {
-               DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
-                          __FUNCTION__, MAX_NVRAMBUF_SIZE));
+       if (bcmerror != BCME_OK)
                goto err;
-       }
 
-       /* For Get nvram from image or UEFI (when image == NULL ) */
-       len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
+#ifdef DHD_LINUX_STD_FW_API
+       memblock_len = len;
+#else
+       memblock_len = MAX_NVRAMBUF_SIZE;
+#endif /* DHD_LINUX_STD_FW_API */
 
        if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
                bufp = (char *)memblock;
@@ -10533,10 +10712,7 @@ dhdsdio_download_nvram(struct dhd_bus *bus)
 
 err:
        if (memblock)
-               MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
-
-       if (image)
-               dhd_os_close_image1(bus->dhd, image);
+               dhd_free_download_buffer(bus->dhd, memblock, memblock_len);
 
        return bcmerror;
 }
index 4ff7e042563325a5f6184399dc8d60668829883d..699b7c4f6c7e312c743b6683ec352306b334d2bd 100755 (executable)
@@ -1,8 +1,22 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
- * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * drivers/amlogic/wifi/dhd_static_buf.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
  */
 
+#define pr_fmt(fmt)    "Wifi: %s: " fmt, __func__
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/skbuff.h>
-#include <linux/amlogic/wlan_plat.h>
+#include <linux/wlan_plat.h>
 #include <linux/amlogic/dhd_buf.h>
 
-#define        DHD_STATIC_VERSION_STR          "101.10.361.16 (wlan=r892223-20220401-1)"
+#define        DHD_STATIC_VERSION_STR          "101.10.361.18 (wlan=r892223-20220519-1)"
 #define STATIC_ERROR_LEVEL     (1 << 0)
 #define STATIC_TRACE_LEVEL     (1 << 1)
 #define STATIC_MSG_LEVEL       (1 << 0)
@@ -179,21 +193,21 @@ void *wlan_static_dhd_event_ring_buf[MAX_NUM_ADAPTERS] = {NULL};
 void *wlan_static_nan_event_ring_buf[MAX_NUM_ADAPTERS] = {NULL};
 
 #if defined(BCMDHD_SDIO) || defined(BCMDHD_PCIE)
-static struct sk_buff *wlan_static_skb[MAX_NUM_ADAPTERS][WLAN_SKB_BUF_NUM];
+static struct sk_buff *wlan_static_skb[MAX_NUM_ADAPTERS][WLAN_SKB_BUF_NUM] = {NULL};
 #endif /* BCMDHD_SDIO | BCMDHD_PCIE */
 
 void *
 bcmdhd_mem_prealloc(
-#ifdef BCMDHD_MDRIVER
+#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER)
        uint bus_type, int index,
 #endif
        int section, unsigned long size)
 {
-#ifndef BCMDHD_MDRIVER
+#if !defined(BCMDHD_MDRIVER) || defined(DHD_STATIC_IN_DRIVER)
        int index = 0;
 #endif
 
-#ifdef BCMDHD_MDRIVER
+#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER)
        DHD_STATIC_MSG("bus_type %d, index %d, sectoin %d, size %ld\n",
                bus_type, index, section, size);
 #else
@@ -348,7 +362,9 @@ bcmdhd_mem_prealloc(
 
        return NULL;
 }
+#ifndef DHD_STATIC_IN_DRIVER
 EXPORT_SYMBOL(bcmdhd_mem_prealloc);
+#endif
 
 static void
 dhd_deinit_wlan_mem(int index)
@@ -612,9 +628,9 @@ err_mem_alloc:
 #ifdef DHD_STATIC_IN_DRIVER
 int
 #else
-static int __init
+int
 #endif
-bcmdhd_init_wlan_mem(unsigned int all_buf))
+bcmdhd_init_wlan_mem(unsigned int all_buf)
 {
        int i, ret = 0;
 
@@ -631,7 +647,7 @@ bcmdhd_init_wlan_mem(unsigned int all_buf))
                        dhd_deinit_wlan_mem(i);
        }
 
-       return 0;
+       return ret;
 }
 
 #ifdef DHD_STATIC_IN_DRIVER
index 11283aa94db82442889f93663c1a5ea8996338cf..0256ff697712c3ea108343c1e6987fe840ec7f04 100755 (executable)
@@ -1059,6 +1059,9 @@ _dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint
        dhdp = (dhd_pub_t *)ctx->dhdp;
        ASSERT(dhdp);
 
+       if (if_id >= WLFC_MAX_IFNUM)
+               return;
+
        if (dhdp->skip_fc && dhdp->skip_fc((void *)dhdp, if_id))
                return;
 
index 58e1ca37ea6006dd690c131b4ad3612553e157b4..e8b14c44f74156115d1bc2772f93b9fddda5de99 100755 (executable)
 #ifndef        _bcmdefs_h_
 #define        _bcmdefs_h_
 
+#ifndef BCM_FLEX_ARRAY
+#define BCM_FLEX_ARRAY  (1)
+#endif /* BCM_FLEX_ARRAY */
+
 /*
  * One doesn't need to include this file explicitly, gets included automatically if
  * typedefs.h is included.
index e7876c7f68a9671ff5a33b6e09c2908d0c4e1c8a..a2fbbd63d6747b909c7fcfef97441e6779d5c91f 100755 (executable)
@@ -313,11 +313,10 @@ typedef union bcm_event_msg_u {
 #define WLC_E_AP_BCN_DRIFT             192     /* Beacon Drift event */
 #define WLC_E_PFN_SCAN_ALLGONE_EXT     193     /* last found PFN network gets lost. */
 #define WLC_E_AUTH_START               194     /* notify upper layer to start auth */
-#define WLC_E_TWT_TEARDOWN             195     /* TWT Teardown Complete Event */
-#define WLC_E_TWT_INFO_FRM             196     /* TWT Info Event Notification */
-#define WLC_E_LAST                     197     /* highest val + 1 for range checking */
-#if (WLC_E_LAST > 197)
-#error "WLC_E_LAST: Invalid value for last event; must be <= 197."
+#define WLC_E_TWT                      195     /* TWT event */
+#define WLC_E_LAST                     196     /* highest val + 1 for range checking */
+#if (WLC_E_LAST > 196)
+#error "WLC_E_LAST: Invalid value for last event; must be <= 196."
 #endif /* WLC_E_LAST */
 
 /* define an API for getting the string name of an event */
@@ -1229,6 +1228,35 @@ typedef struct {
        uint8 data[];   /* type specific data; could be empty */
 } wl_event_fbt_t;
 
+/* TWT Setup Completion is designed to notify the user of TWT Setup process
+ * status. When 'status' field is value of BCME_OK, the user must check the
+ * 'setup_cmd' field value in 'wl_twt_sdesc_t' structure that at the end of
+ * the event data to see the response from the TWT Responding STA; when
+ * 'status' field is value of BCME_ERROR or non BCME_OK, user must not use
+ * anything from 'wl_twt_sdesc_t' structure as it is the TWT Requesting STA's
+ * own TWT parameter.
+ */
+
+#define WL_TWT_EVENT_HDR_LEN (SIZE_OF(wl_twt_event_t, version) + SIZE_OF(wl_twt_event_t, length))
+#define WL_TWT_EVENT_BASE_LEN  sizeof(wl_twt_event_t)
+typedef enum wl_twt_event_type {
+       WL_TWT_EVENT_SETUP              = 1,
+       WL_TWT_EVENT_TEARDOWN           = 2,
+       WL_TWT_EVENT_INFOFRM            = 3,
+       WL_TWT_EVENT_NOTIFY             = 4
+} wl_twt_event_type_t;
+
+#define WL_TWT_EVENT_VER       0u
+
+/* WLC_E_TWT event Main-event */
+typedef struct wl_twt_event {
+       uint16 version;
+       uint16 length;  /* the byte count of fields from 'event_type' onwards */
+       uint8 event_type;       /* See sub event types in wl_twt_event_type_t */
+       uint8 PAD[3];
+       uint8 event_info[];
+} wl_twt_event_t;
+
 /* TWT Setup Completion is designed to notify the user of TWT Setup process
  * status. When 'status' field is value of BCME_OK, the user must check the
  * 'setup_cmd' field value in 'wl_twt_sdesc_t' structure that at the end of
@@ -1242,12 +1270,13 @@ typedef struct {
 
 /* TWT Setup Reason code */
 typedef enum wl_twt_setup_rc {
-       WL_TWT_SETUP_RC_ACCEPT  = 0,    /* TWT Setup Accepted */
-       WL_TWT_SETUP_RC_REJECT  = 1,    /* TWT Setup Rejected */
-       WL_TWT_SETUP_RC_TIMEOUT = 2,    /* TWT Setup Time-out */
-       WL_TWT_SETUP_RC_IE      = 3,    /* TWT Setup IE Validation failed */
-       WL_TWT_SETUP_RC_PARAMS  = 4,    /* TWT Setup IE Params invalid */
-       WL_TWT_SETUP_RC_ERROR   = 5,    /* Generic Error cases */
+       WL_TWT_SETUP_RC_ACCEPT  = 0u,   /* TWT Setup Accepted */
+       WL_TWT_SETUP_RC_REJECT  = 1u,   /* TWT Setup Rejected */
+       WL_TWT_SETUP_RC_TIMEOUT = 2u,   /* TWT Setup Time-out */
+       WL_TWT_SETUP_RC_IE      = 3u,   /* TWT Setup IE Validation failed */
+       WL_TWT_SETUP_RC_PARAMS  = 4u,   /* TWT Setup IE Params invalid */
+       /* Any new reason code add before this */
+       WL_TWT_SETUP_RC_ERROR   = 255u, /* Generic Error cases */
 } wl_twt_setup_rc_t;
 
 /* TWT Setup Completion event data */
@@ -1256,7 +1285,8 @@ typedef struct wl_twt_setup_cplt {
        uint16 length;  /* the byte count of fields from 'dialog' onwards */
        uint8 dialog;   /* Setup frame dialog token */
        uint8 reason_code;      /* see WL_TWT_SETUP_RC_XXXX */
-       uint8 pad[2];
+       uint8 configID; /* TWT Configuration ID */
+       uint8 pad[1];
        int32 status;
        /* wl_twt_sdesc_t desc; - defined in wlioctl.h */
 } wl_twt_setup_cplt_t;
@@ -1265,24 +1295,25 @@ typedef struct wl_twt_setup_cplt {
 
 /* TWT teardown Reason code */
 typedef enum wl_twt_td_rc {
-       WL_TWT_TD_RC_SUCCESS    = 0,    /* Teardown complete Successful */
-       WL_TWT_TD_RC_HOST       = 1,    /* Teardown triggered by Host */
-       WL_TWT_TD_RC_PEER       = 2,    /* Peer initiated teardown */
-       WL_TWT_TD_RC_MCHAN      = 3,    /* Teardown due to MCHAN Active */
-       WL_TWT_TD_RC_MCNX       = 4,    /* Teardown due to MultiConnection */
-       WL_TWT_TD_RC_SETUP_FAIL = 5, /* Setup fail midway. Teardown all connections */
-       WL_TWT_TD_RC_SCHED      = 6,    /* Teardown by TWT Scheduler */
-       WL_TWT_TD_RC_CSA        = 7,    /* Teardown due to CSA */
-       WL_TWT_TD_RC_BTCX       = 8,    /* Teardown due to BTCX */
-       WL_TWT_TD_RC_ERROR      = 9,    /* Generic Error cases */
+       WL_TWT_TD_RC_HOST       = 0u,   /* Teardown triggered by Host */
+       WL_TWT_TD_RC_PEER       = 1u,   /* Peer initiated teardown */
+       WL_TWT_TD_RC_MCHAN      = 2u,   /* Teardown due to MCHAN Active */
+       WL_TWT_TD_RC_MCNX       = 3u,   /* Teardown due to MultiConnection */
+       WL_TWT_TD_RC_CSA        = 4u,   /* Teardown due to CSA */
+       WL_TWT_TD_RC_BTCX       = 5u,   /* Teardown due to BTCX */
+       WL_TWT_TD_RC_SETUP_FAIL = 6u, /* Setup fail midway. Teardown all connections */
+       WL_TWT_TD_RC_SCHED      = 7u,   /* Teardown by TWT Scheduler */
+       /* Any new reason code add before this */
+       WL_TWT_TD_RC_ERROR      = 255u, /* Generic Error cases */
 } wl_twt_td_rc_t;
 
 /* TWT Teardown complete event data */
 typedef struct wl_twt_teardown_cplt {
        uint16 version;
-       uint16 length;  /* the byte count of fields from 'reason_code' onwards */
+       uint16 length;          /* the byte count of fields from 'reason_code' onwards */
        uint8 reason_code;      /* WL_TWT_TD_RC_XXXX */
-       uint8 pad[3];
+       uint8 configID;         /* TWT Configuration ID */
+       uint8 pad[2];
        int32 status;
        /* wl_twt_teardesc_t; - defined in wlioctl.h */
 } wl_twt_teardown_cplt_t;
@@ -1291,21 +1322,39 @@ typedef struct wl_twt_teardown_cplt {
 
 /* TWT Info Reason code */
 typedef enum wl_twt_info_rc {
-       WL_TWT_INFO_RC_HOST     = 0,    /* Host initiated Info complete */
-       WL_TWT_INFO_RC_PEER     = 1,    /* Peer initiated TWT Info */
-       WL_TWT_INFO_RC_ERROR    = 2,    /* generic error conditions */
+       WL_TWT_INFO_RC_HOST     = 0u,   /* Host initiated Info complete */
+       WL_TWT_INFO_RC_PEER     = 1u,   /* Peer initiated TWT Info */
+       /* Any new reason code add before this */
+       WL_TWT_INFO_RC_ERROR    = 255u, /* generic error conditions */
 } wl_twt_info_rc_t;
 
 /* TWT Info complete event data */
 typedef struct wl_twt_info_cplt {
        uint16 version;
        uint16 length;          /* the byte count of fields from 'reason_code' onwards */
-       uint8 reason_code;              /* WL_TWT_INFO_RC_XXXX */
-       uint8 pad[3];
+       uint8 reason_code;      /* WL_TWT_INFO_RC_XXXX */
+       uint8 configID;         /* TWT Configuration ID */
+       uint8 pad[2];
        int32 status;
        /* wl_twt_infodesc_t; - defined in wlioctl.h */
 } wl_twt_info_cplt_t;
 
+#define WL_TWT_NOTIFY_VER      0u
+#define WL_TWT_NOTIFY_LEN sizeof(wl_twt_notify_t)
+#define WL_TWT_NOTIFY_HDR_LEN (SIZE_OF(wl_twt_notify_t, version) + SIZE_OF(wl_twt_notify_t, length))
+
+typedef enum wl_twt_notification {
+       WL_TWT_NOTIF_ALLOW_TWT  = 1,    /* Dongle indication of allowing TWT setup */
+} wl_twt_notification_t;
+
+/* TWT notification event */
+typedef struct wl_twt_notify {
+       uint16 version;
+       uint16 length;          /* the byte count of fields from 'reason_code' onwards */
+       uint8 notification;
+       uint8 PAD[3];
+} wl_twt_notify_t;
+
 #define WL_INVALID_IE_EVENT_VERSION    0
 
 /* Invalid IE Event data */
index 81c3438993c2229fd47d0b8a5c06ea8c03764a96..3ed679b049d287943c4fc396ed5529e8a91f4775 100755 (executable)
@@ -256,6 +256,7 @@ extern void bcmsdh_oob_intr_unregister(bcmsdh_info_t *sdh);
 extern void bcmsdh_oob_intr_set(bcmsdh_info_t *sdh, bool enable);
 extern int bcmsdh_get_oob_intr_num(bcmsdh_info_t *bcmsdh);
 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
+extern void *bcmsdh_get_dev(bcmsdh_info_t *sdh);
 extern void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *sdh);
 extern void bcmsdh_dev_relax(bcmsdh_info_t *sdh);
 extern bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *sdh);
index d9a67e073a802be174ef0d381ff084f4e40dcdbb..c204ac5aa0bfc51b57a2a0fe3e94ed0dcb3cc184 100755 (executable)
@@ -24,7 +24,6 @@
 #ifndef __BCMSDH_SDMMC_H__
 #define __BCMSDH_SDMMC_H__
 
-#ifdef BCMDBG
 #define sd_err(x)      do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0)
 #define sd_trace(x)    do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0)
 #define sd_info(x)     do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0)
 #define sd_data(x)     do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0)
 #define sd_ctrl(x)     do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0)
 #define sd_cost(x)     do { if (sd_msglevel & SDH_COST_VAL) printf x; } while (0)
-#else
-#define sd_err(x)      do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0)
-#define sd_trace(x)
-#define sd_info(x)
-#define sd_debug(x)
-#define sd_data(x)
-#define sd_ctrl(x)
-#define sd_cost(x)     do { if (sd_msglevel & SDH_COST_VAL) printf x; } while (0)
-#endif
 
 #define sd_sync_dma(sd, read, nbytes)
 #define sd_init_dma(sd)
@@ -95,6 +85,9 @@ struct sdioh_info {
        struct sdio_func        *func[SDIOD_MAX_IOFUNCS];
        uint            sd_clk_rate;
        uint    txglom_mode;            /* Txglom mode: 0 - copy, 1 - multi-descriptor */
+#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF)
+       uint8   *copy_buf;
+#endif
 #ifdef PKT_STATICS
        uint32  sdio_spent_time_us;
 #endif
index d3744de83b74143a6b8a2c9d32b135278c3b4a01..2b417231eecf6cd32ddda33ba31dbd9e78135ccf 100755 (executable)
@@ -356,7 +356,7 @@ uint wf_chspec_first_20_sb(chanspec_t chspec);
        ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \
        (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40))
 
-#ifdef WL_BAND6G
+#ifdef WL_6G_BAND
 #define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS2G(chspec) ? WLC_BAND_2G : CHSPEC_IS5G(chspec) ? \
        WLC_BAND_5G : WLC_BAND_6G)
 #else
index 7761dffe9fe7e3a3886322c6b1f9926eaf3a5a59..f6c878b8e139feb53a7591c46cfb2202cf0dfc0c 100755 (executable)
@@ -68,6 +68,10 @@ enum {
        DBUS_ERR_RXZLP
 };
 
+#define BCM_OTP_SIZE_43236  84 /* number of 16 bit values */
+#define BCM_OTP_SW_RGN_43236   24  /* start offset of SW config region */
+#define BCM_OTP_ADDR_43236 0x18000800 /* address of otp base */
+
 #define ERR_CBMASK_TXFAIL              0x00000001
 #define ERR_CBMASK_RXFAIL              0x00000002
 #define ERR_CBMASK_ALL                 0xFFFFFFFF
@@ -316,9 +320,9 @@ typedef struct dbus_pub {
  *  For NDIS60, param2 is WdfDevice
  * Under Linux, param1 and param2 are NULL;
  */
-extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg,
-       void *param1, void *param2);
-extern int dbus_deregister(void);
+//extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg,
+//     void *param1, void *param2);
+//extern int dbus_deregister(void);
 
 //extern int dbus_download_firmware(dbus_pub_t *pub);
 //extern int dbus_up(struct dhd_bus *pub);
@@ -327,13 +331,13 @@ extern int dbus_down(dbus_pub_t *pub);
 extern int dbus_shutdown(dbus_pub_t *pub);
 extern void dbus_flowctrl_rx(dbus_pub_t *pub, bool on);
 
-extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf);
+//extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf);
 extern int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info);
-extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info);
+//extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info);
 //extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len);
 //extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len);
-extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx);
-extern int dbus_poll_intr(dbus_pub_t *pub);
+//extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx);
+//extern int dbus_poll_intr(dbus_pub_t *pub);
 extern int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats);
 extern int dbus_get_device_speed(dbus_pub_t *pub);
 extern int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config);
@@ -407,6 +411,18 @@ typedef struct dbus_intf_callbacks {
        void (*rxerr_indicate)(void *cbarg, bool on);
 } dbus_intf_callbacks_t;
 
+/* callback functions */
+typedef struct {
+       /* probe the device */
+       void *(*probe)(uint16 bus, uint16 slot, uint32 hdrlen);
+       /* remove the device */
+       void (*remove)(void *context);
+       /* can we suspend now */
+       int (*suspend)(void *context);
+       /* resume from suspend */
+       int (*resume)(void *context);
+} dbus_driver_t;
+
 /*
  * Porting: To support new bus, port these functions below
  */
@@ -415,8 +431,7 @@ typedef struct dbus_intf_callbacks {
  * Bus specific Interface
  * Implemented by dbus_usb.c/dbus_sdio.c
  */
-extern int dbus_bus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg,
-       dbus_intf_t **intf, void *param1, void *param2);
+extern int dbus_bus_register(dbus_driver_t *driver, dbus_intf_t **intf);
 extern int dbus_bus_deregister(void);
 extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp);
 
@@ -424,8 +439,7 @@ extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp);
  * Bus-specific and OS-specific Interface
  * Implemented by dbus_usb_[linux/ndis].c/dbus_sdio_[linux/ndis].c
  */
-extern int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb,
-       void *prarg, dbus_intf_t **intf, void *param1, void *param2);
+extern int dbus_bus_osl_register(dbus_driver_t *driver, dbus_intf_t **intf);
 extern int dbus_bus_osl_deregister(void);
 
 /*
@@ -439,7 +453,7 @@ extern int dbus_bus_osl_hw_deregister(void);
 extern uint usbdev_bulkin_eps(void);
 #if defined(BCM_REQUEST_FW)
 extern void *dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type,
-  uint16 boardtype, uint16 boardrev);
+  uint16 boardtype, uint16 boardrev, char *path);
 extern void dbus_release_fw_nvfile(void *firmware);
 #endif  /* #if defined(BCM_REQUEST_FW) */
 
@@ -624,4 +638,7 @@ void optimize_submit_rx_request(const dbus_pub_t *pub, int epn, struct ehci_qtd
 #endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */
 
 void  dbus_flowctrl_tx(void *dbi, bool on);
+#ifdef LINUX
+struct device * dbus_get_dev(void);
+#endif /* LINUX */
 #endif /* __DBUS_H__ */
index 2bd2901ad304009e27aafea681cedf619b0d5624..dd72dc396ce255d1003cab353535c6c5e4a09ea5 100755 (executable)
@@ -45,7 +45,7 @@
 #elif (defined (BCMDBG_ASSERT) && !defined (BCMDBG_ASSERT_DISABLED))
 #define EPI_VERSION_STR                "101.10.361 (wlan=r892223 ASSRT)"
 #else
-#define EPI_VERSION_STR                "101.10.361.17 (wlan=r892223-20220415-1)(20220705-1)"
+#define EPI_VERSION_STR                "101.10.361.24 (wlan=r892223-20220913-1)"
 #endif /* BCMINTERNAL */
 
 #endif /* _epivers_h_ */
index a0a0937bcdf247bbf10e8054dbf255bee0da190a..f9bd6c88e913b319253e9c3a1ca8f64721e5d563 100755 (executable)
 #define DECLSPEC_ALIGN(x)      __attribute__ ((aligned(x)))
 
 /* Linux Kernel: File Operations: start */
-extern void * osl_os_open_image(char * filename);
-extern int osl_os_get_image_block(char * buf, int len, void * image);
-extern void osl_os_close_image(void * image);
-extern int osl_os_image_size(void *image);
+static INLINE void * osl_os_open_image(char * filename)
+       { return NULL; }
+static INLINE void osl_os_close_image(void * image)
+       { return; }
+static INLINE int osl_os_get_image_block(char * buf, int len, void * image)
+       { return 0; }
+static INLINE int osl_os_image_size(void *image)
+       { return 0; }
 /* Linux Kernel: File Operations: end */
 
 #ifdef BCMDRIVER
index 44f32cedd4890d64ff4418e719280fdbc8ebed77..e69734957dfd1668e692ca7e694ec44d12d1361e 100755 (executable)
@@ -941,5 +941,28 @@ int kernel_read_compat(struct file *file, loff_t offset, char *addr, unsigned lo
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
 #define netdev_tx_t int
 #endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0))
+#define complete_and_exit(a, b) kthread_complete_and_exit(a, b)
+#else
+#define        dev_addr_set(net, addr) memcpy(net->dev_addr, addr, ETHER_ADDR_LEN)
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(5, 17, 0) */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0))
+#define netif_rx_ni(skb) netif_rx(skb)
+#define pci_free_consistent(a, b, c, d) dma_free_coherent(&((struct pci_dev *)a)->dev, b, c, d)
+#define pci_map_single(a, b, c, d) dma_map_single(&((struct pci_dev *)a)->dev, b, c, d)
+#define pci_unmap_single(a, b, c, d) dma_unmap_single(&((struct pci_dev *)a)->dev, b, c, d)
+#define pci_dma_mapping_error(a, b) dma_mapping_error(&((struct pci_dev *)a)->dev, b)
+#ifndef PCI_DMA_TODEVICE
+#define        PCI_DMA_TODEVICE        1
+#define        PCI_DMA_FROMDEVICE      2
+#endif
+#endif
+
+#ifdef ANDROID_BKPORT
+#if (ANDROID_VERSION >= 13) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 41))
+#define ANDROID13_KERNEL515_BKPORT
+#define CFG80211_BKPORT_MLO
+#endif /* ANDROID_VERSION >= 13 && KERNEL >= 5.15.41 */
+#endif /* ANDROID_BKPORT */
 
 #endif /* _linuxver_h_ */
index 97f0148fbe6f42536fd3e785f8c0aab879124d41..72c9d9fb67c5a4a99ad2ad61b4bd05b7891ea24a 100755 (executable)
@@ -713,7 +713,7 @@ typedef struct wl_extdscan_params {
 
 #define WL_SCAN_PARAMS_SSID_MAX                10
 
-struct wl_scan_params {
+typedef struct wl_scan_params_v1 {
        wlc_ssid_t ssid;                /**< default: {0, ""} */
        struct ether_addr bssid;        /**< default: bcast */
        int8 bss_type;                  /**< default: any,
@@ -744,8 +744,13 @@ struct wl_scan_params {
                                         * parameter portion is assumed, otherwise ssid in
                                         * the fixed portion is ignored
                                         */
-       uint16 channel_list[1];         /**< list of chanspecs */
-};
+       uint16 channel_list[BCM_FLEX_ARRAY];
+} wl_scan_params_v1_t;
+
+/** size of wl_scan_params_v1 not including variable length array */
+#define WL_SCAN_PARAMS_V1_FIXED_SIZE   (OFFSETOF(wl_scan_params_v1_t, channel_list))
+#define WL_MAX_ROAMSCAN_V1_DATSZ \
+       (WL_SCAN_PARAMS_V1_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16)))
 
 /* changes in wl_scan_params_v2 as comapred to wl_scan_params (v1)
 * unit8 scantype to uint32
@@ -857,16 +862,16 @@ typedef struct wl_scan_params_v3 {
 #define WL_MAX_ROAMSCAN_V3_DATSZ \
        (WL_SCAN_PARAMS_V3_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16)))
 
-#define ISCAN_REQ_VERSION 1
+#define ISCAN_REQ_VERSION_V1 1
 #define ISCAN_REQ_VERSION_V2 2
 
 /** incremental scan struct */
-struct wl_iscan_params {
+typedef struct wl_iscan_params_v1 {
        uint32 version;
        uint16 action;
        uint16 scan_duration;
-       struct wl_scan_params params;
-};
+       struct wl_scan_params_v1 params;
+} wl_iscan_params_v1_t;
 
 /** incremental scan struct */
 typedef struct wl_iscan_params_v2 {
@@ -895,8 +900,9 @@ typedef struct wl_scan_results_v109 {
        uint32 buflen;
        uint32 version;
        uint32 count;
-       wl_bss_info_v109_t bss_info[1];
+       wl_bss_info_v109_t bss_info[BCM_FLEX_ARRAY];
 } wl_scan_results_v109_t;
+#define WL_SCAN_RESULTS_V109_FIXED_SIZE (OFFSETOF(wl_scan_results_v109_t, bss_info))
 
 typedef struct wl_scan_results_v2 {
        uint32 buflen;
@@ -920,15 +926,15 @@ typedef struct iscan_buf {
 } iscan_buf_t;
 #endif /* SIMPLE_ISCAN */
 #define ESCAN_REQ_VERSION 1
+#define ESCAN_REQ_VERSION_V1 1
 #define ESCAN_REQ_VERSION_V2 2
 
-/** event scan reduces amount of SOC memory needed to store scan results */
-struct wl_escan_params {
+typedef struct wl_escan_params_v1 {
        uint32 version;
        uint16 action;
        uint16 sync_id;
-       struct wl_scan_params params;
-};
+       struct wl_scan_params_v1 params;
+} wl_escan_params_v1_t;
 
 typedef struct wl_escan_params_v2 {
        uint32 version;
@@ -944,7 +950,7 @@ typedef struct wl_escan_params_v3 {
        wl_scan_params_v3_t params;
 } wl_escan_params_v3_t;
 
-#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t))
+#define WL_ESCAN_PARAMS_V1_FIXED_SIZE (OFFSETOF(wl_escan_params_v1_t, params) + sizeof(wlc_ssid_t))
 #define WL_ESCAN_PARAMS_V2_FIXED_SIZE (OFFSETOF(wl_escan_params_v2_t, params) + sizeof(wlc_ssid_t))
 #define WL_ESCAN_PARAMS_V3_FIXED_SIZE (OFFSETOF(wl_escan_params_v3_t, params) + sizeof(wlc_ssid_t))
 /* New scan version is defined then change old version of scan to
@@ -967,9 +973,9 @@ typedef struct wl_escan_params_v2   wl_escan_params_t;
 typedef struct wl_iscan_params_v2      wl_iscan_params_t;
 #define WL_SCAN_PARAMS_FIXED_SIZE      (OFFSETOF(wl_scan_params_t, channel_list))
 #else
-typedef struct wl_scan_params wl_scan_params_t;
-typedef struct wl_escan_params wl_escan_params_t;
-typedef struct wl_iscan_params wl_iscan_params_t;
+typedef struct wl_scan_params_v1 wl_scan_params_t;
+typedef struct wl_escan_params_v1 wl_escan_params_t;
+typedef struct wl_iscan_params_v1 wl_iscan_params_t;
 #define WL_SCAN_PARAMS_FIXED_SIZE      64
 #endif /* WL_SCAN_PARAMS_V3 */
 
@@ -979,8 +985,9 @@ typedef struct wl_escan_result_v109 {
        uint32 version;
        uint16 sync_id;
        uint16 bss_count;
-       wl_bss_info_v109_t bss_info[1];
+       wl_bss_info_v109_t bss_info[BCM_FLEX_ARRAY];
 } wl_escan_result_v109_t;
+#define WL_ESCAN_RESULTS_V109_FIXED_SIZE (OFFSETOF(wl_escan_result_v109_t, bss_info))
 
 /** event scan reduces amount of SOC memory needed to store scan results */
 typedef struct wl_escan_result_v2 {
@@ -2306,6 +2313,7 @@ typedef struct sta_info_v7 {
 
 #define WL_STA_VER_4           4
 #define WL_STA_VER_5           5
+#define WL_STA_VER_6           6u
 /* FIXME: the user/branch should make the selection! */
 #define WL_STA_VER             WL_STA_VER_4
 
@@ -6230,6 +6238,15 @@ typedef struct wl_icmp_ipv6_cfg {
 #define WL_ICMP_CFG_IPV6_LEN(count)    (WL_ICMP_CFG_IPV6_FIXED_LEN + \
                                        ((count) * sizeof(struct ipv6_addr)))
 
+typedef struct wl_mkeep_alive_pkt_v1 {
+       uint16  version; /* Version for mkeep_alive */
+       uint16  length; /* length of fixed parameters in the structure */
+       uint32  period_msec; /* high bit on means immediate send */
+       uint16  len_bytes;
+       uint8   keep_alive_id; /* 0 - 3 for N = 4 */
+       uint8   data[BCM_FLEX_ARRAY];
+} wl_mkeep_alive_pkt_v1_t;
+
 typedef struct wl_mkeep_alive_pkt {
        uint16  version; /* Version for mkeep_alive */
        uint16  length; /* length of fixed parameters in the structure */
@@ -6239,6 +6256,7 @@ typedef struct wl_mkeep_alive_pkt {
        uint8   data[1];
 } wl_mkeep_alive_pkt_t;
 
+#define WL_MKEEP_ALIVE_VERSION_1       1u
 #define WL_MKEEP_ALIVE_VERSION         1
 #define WL_MKEEP_ALIVE_FIXED_LEN       OFFSETOF(wl_mkeep_alive_pkt_t, data)
 /* 1/2 second precision since idle time is a seconds counter anyway */
@@ -21227,6 +21245,13 @@ typedef struct wl_hwa_cnts_v1 {
  */
 
 /* TWT Setup descriptor */
+
+/* Any change to wl_twt_sdesc is not possible without affecting this ROMed structure
+ * in various current branches. Hence to use new updated structure wl_twt_sdesc_v1
+ * typecast it to wl_twt_sdesc_t and define WL_TWT_SDESC_TYPEDEF_HAS_ALIAS
+ * in required branches
+ */
+#ifndef  WL_TWT_SDESC_TYPEDEF_HAS_ALIAS
 typedef struct wl_twt_sdesc {
        /* Setup Command. */
        uint8 setup_cmd;                /* See TWT_SETUP_CMD_XXXX in 802.11ah.h */
@@ -21248,6 +21273,7 @@ typedef struct wl_twt_sdesc {
        /* deprecated - to be removed */
        uint16 li;
 } wl_twt_sdesc_t;
+#endif /* WL_TWT_SDESC_TYPEDEF_HAS_ALIAS */
 
 #define WL_TWT_SETUP_DESC_VER  1u
 
@@ -21283,7 +21309,9 @@ typedef struct wl_twt_cdesc {
        uint16 version;         /* structure version */
        uint16 length;          /* data length (starting after this field) */
        uint8 negotiation_type; /* Negotiation Type: See macros TWT_NEGO_TYPE_X */
-       uint8 PAD[3];
+       uint8 configID;         /* TWT Configuration ID */
+       uint8 flow_flags;       /* Flow Flags Configuration. See WL_TWT_FLOW_FLAG_XXXX */
+       uint8 PAD;
        uint32 wake_time_h;     /* target wake time - BSS TSF (us) */
        uint32 wake_time_l;
        uint32 wake_dur;        /* target wake duration in unit of microseconds */
@@ -21293,6 +21321,7 @@ typedef struct wl_twt_cdesc {
        uint32 wake_dur_min;    /* Min. wake duration allowed for TWT Setup */
        uint32 wake_dur_max;    /* Max. wake duration allowed for TWT Setup */
        uint32 avg_pkt_num;     /* Average Number of Packets per interval */
+       uint32 avg_pkt_size;    /* Average packet size for TWT SP */
 } wl_twt_cdesc_t;
 
 /* Flow flags */
@@ -21316,6 +21345,14 @@ typedef struct wl_twt_cdesc {
 
 #define WL_TWT_INV_BCAST_ID    0xFFu
 #define WL_TWT_INV_FLOW_ID     0xFFu
+#define WL_TWT_INV_CONFIG_ID   0xFFu
+#define WL_TWT_ALL_TWT_CONFIG_ID 0u    /* ConfigID 0 corresponds to All TWT */
+
+#define WL_TWT_INV_WAKE_DUR    0xFFFFFFFFu
+#define WL_TWT_INV_WAKE_INT    0xFFFFFFFFu
+#define WL_TWT_INV_PKT_NUM     0xFFFFFFFFu
+#define WL_TWT_INV_PKT_SIZE    0xFFFFFFFFu
+#define WL_TWT_INV_WAKE_TIME   0xFFFFFFFFu
 
 /* auto flow_id */
 #define WL_TWT_SETUP_FLOW_ID_AUTO      0xFFu
@@ -21332,10 +21369,11 @@ typedef struct wl_twt_cdesc {
 #define WL_TWT_STATS_MAX_BTWT  WL_TWT_MAX_BTWT
 #define WL_TWT_STATS_MAX_ITWT  WL_TWT_MAX_ITWT
 
+/* TWT States */
 #define WL_TWT_INACTIVE                0u      /* Resource is not allotted */
-#define WL_TWT_RESERVED                1u      /* Resource is allotted but HEB is not yet programmed */
-#define WL_TWT_ACTIVE          2u      /* Resource is allotted and HEB is programmed */
-#define WL_TWT_SUSPEND         3u      /* Resource is suspended and HEB released */
+#define WL_TWT_ACTIVE          1u      /* Resource is allotted and HEB is programmed */
+#define WL_TWT_SUSPEND         2u      /* Resource is suspended and HEB released */
+#define WL_TWT_RESERVED                3u      /* Resource is allotted but HEB is not yet programmed */
 
 /* Wake type */
 /* TODO: not yet finalized */
@@ -21356,7 +21394,13 @@ typedef struct wl_twt_setup {
        uint16 length;  /* data length (starting after this field) */
        struct ether_addr peer; /* Peer address - leave it all 0s' for AP */
        uint8 pad[2];
+#ifndef WL_TWT_SDESC_TYPEDEF_HAS_ALIAS /* Use either legacy structure or
+                                        * the new versioned structure
+                                        */
        wl_twt_sdesc_t desc;    /* Setup Descriptor */
+#else
+       struct wl_twt_sdesc_v1 desc;
+#endif /* WL_TWT_SDESC_TYPEDEF_HAS_ALIAS */
        uint16 dialog;          /* Deprecated - to be removed */
        uint8 pad1[2];
 } wl_twt_setup_t;
@@ -21392,11 +21436,13 @@ typedef struct wl_twt_teardown {
        struct ether_addr peer; /* leave it all 0s' for AP */
        wl_twt_teardesc_t teardesc;     /* Teardown descriptor */
 
-       /* deprecated - to be removed */
+       /* deprecated - to be removed - Start here */
        uint8 flow_flags;
        uint8 flow_id;
        uint8 bid;
-       uint8 pad;
+       /* deprecated - to be removed - End here */
+
+       uint8 configID; /* TWT Configuration ID */
 } wl_twt_teardown_t;
 
 /* twt information descriptor */
@@ -21430,7 +21476,8 @@ typedef struct wl_twt_info {
        uint16 length;  /* data length (starting after this field) */
        /* peer address */
        struct ether_addr peer; /* leave it all 0s' for AP */
-       uint8 pad[2];
+       uint8 configID; /* TWT Configuration ID */
+       uint8 pad[1];
        wl_twt_infodesc_t infodesc;     /* information descriptor */
        /* deprecated - to be removed */
        wl_twt_idesc_t desc;
@@ -21446,10 +21493,19 @@ typedef struct wl_twt_info {
 typedef struct wl_twt_status {
        uint8   state;          /* TWT State */
        uint8   heb_id;         /* HEB ID */
-       uint8   PAD[2];
+       uint8   configID;               /* TWT Configuration ID */
+       uint8   PAD[1];
        struct  ether_addr peer;
        uint8   PAD[2];
-       wl_twt_sdesc_t desc;    /* TWT Descriptor */
+       uint32  avg_pkt_num;    /* Average Packet number per TWT SP Interval */
+       uint32  avg_pkt_size;   /* Average Packet size for TWT SP */
+#ifndef WL_TWT_SDESC_TYPEDEF_HAS_ALIAS /* Use either legacy structure or
+                                        * the new versioned structure
+                                        */
+       wl_twt_sdesc_t desc;    /* Setup Descriptor */
+#else
+       struct wl_twt_sdesc_v1 desc;
+#endif /* WL_TWT_SDESC_TYPEDEF_HAS_ALIAS */
 } wl_twt_status_t;
 
 /* wl twt status output */
@@ -21468,7 +21524,8 @@ typedef struct wl_twt_status_cmd_v1 {
        uint16  version;
        uint16  length;
        struct  ether_addr peer;
-       uint8   PAD[2];
+       uint8   configID;
+       uint8   PAD;
 } wl_twt_status_cmd_v1_t;
 
 #define WL_TWT_PEER_STATS_VERSION_1    1u
@@ -21501,6 +21558,40 @@ typedef struct wl_twt_stats_v1 {
        wl_twt_peer_stats_v1_t  peer_stats_list[];
 } wl_twt_stats_v1_t;
 
+#define WL_TWT_PEER_STATS_VERSION_2    2u
+typedef struct wl_twt_peer_stats_v2 {
+       uint16  version;
+       uint16  length;
+       struct  ether_addr peer;
+       uint8   id;             /* TWT session ID */
+       uint8   flow_flags;
+       uint8   configID;               /* TWT Configuration ID */
+       uint8   PAD[3];
+       uint32  sp_seq;         /* sequence number of the service period */
+       uint32  tx_ucast_pkts;  /* Number of unicast Tx packets in TWT SPs */
+       uint32  tx_pkts_min;    /* Minimum number of Tx packets in a TWT SP */
+       uint32  tx_pkts_max;    /* Maximum number of Tx packets in a TWT SP */
+       uint32  tx_pkts_avg;    /* Average number of Tx packets in each TWT SP */
+       uint32  tx_failures;    /* Tx packets failure count */
+       uint32  rx_ucast_pkts;  /* Number of unicast Rx packets in TWT SPs */
+       uint32  rx_pkts_min;    /* Minimum number of Rx packets in a TWT SP */
+       uint32  rx_pkts_max;    /* Maximum number of Rx packets in a TWT SP */
+       uint32  rx_pkts_avg;    /* Average number of Rx packets in each TWT SP */
+       uint32  rx_pkts_retried;        /* retried Rx packets count */
+       uint32  tx_pkt_sz_avg;  /* Average Tx packet size in TWT SPs */
+       uint32  rx_pkt_sz_avg;  /* Average Rx Packet size in TWT SPs */
+       uint32  eosp_dur_avg;   /* Average Wake duration in SPs ended due to EOSP */
+       uint32  eosp_count;     /* Count of TWT SPs ended due to EOSP */
+} wl_twt_peer_stats_v2_t;
+
+#define WL_TWT_STATS_VERSION_2         2u
+typedef struct wl_twt_stats_v2 {
+       uint16  version;
+       uint16  length;
+       uint32  num_stats;      /* number of peer stats in the peer_stats_list */
+       wl_twt_peer_stats_v2_t  peer_stats_list[];
+} wl_twt_stats_v2_t;
+
 #define WL_TWT_STATS_CMD_VERSION_1     1
 #define WL_TWT_STATS_CMD_FLAGS_RESET   (1u << 0u)
 /* HE TWT stats command */
@@ -21508,7 +21599,8 @@ typedef struct wl_twt_stats_cmd_v1 {
        uint16  version;
        uint16  length;
        struct ether_addr peer;
-       uint8   PAD[2];
+       uint8   configID;               /* TWT Configuration ID */
+       uint8   PAD;
        uint16  flags;          /* see WL_TWT_STATS_CMD_FLAGS */
        uint8   num_fid;
        uint8   num_bid;
index 4e7607c5a9cb0cd45bd6d204bdf5c813a6d6fbd6..6af48120e491afcf8ed86fe5b4072ce73adef0ba 100755 (executable)
@@ -281,14 +281,15 @@ osl_error(int bcmerror)
        /* Array bounds covered by ASSERT in osl_attach */
        return linuxbcmerrormap[-bcmerror];
 }
-#ifdef SHARED_OSL_CMN
-osl_t *
-osl_attach(void *pdev, uint bustype, bool pkttag, void **osl_cmn)
-{
-#else
+
 osl_t *
-osl_attach(void *pdev, uint bustype, bool pkttag)
+osl_attach(void *pdev, uint bustype, bool pkttag
+#ifdef SHARED_OSL_CMN
+       , void **osl_cmn
+#endif /* SHARED_OSL_CMN */
+)
 {
+#ifndef SHARED_OSL_CMN
        void **osl_cmn = NULL;
 #endif /* SHARED_OSL_CMN */
        osl_t *osh;
@@ -1734,71 +1735,6 @@ osl_rand(void)
        return rand;
 }
 
-/* Linux Kernel: File Operations: start */
-void *
-osl_os_open_image(char *filename)
-{
-       struct file *fp;
-
-       fp = filp_open(filename, O_RDONLY, 0);
-       /*
-        * 2.6.11 (FC4) supports filp_open() but later revs don't?
-        * Alternative:
-        * fp = open_namei(AT_FDCWD, filename, O_RD, 0);
-        * ???
-        */
-       if (IS_ERR(fp)) {
-               printf("ERROR %ld: Unable to open file %s\n", PTR_ERR(fp), filename);
-               fp = NULL;
-       }
-
-       return fp;
-}
-
-int
-osl_os_get_image_block(char *buf, int len, void *image)
-{
-       struct file *fp = (struct file *)image;
-       int rdlen;
-
-       if (fp == NULL) {
-               return 0;
-       }
-
-       rdlen = kernel_read_compat(fp, fp->f_pos, buf, len);
-       if (rdlen > 0) {
-               fp->f_pos += rdlen;
-       }
-
-       return rdlen;
-}
-
-void
-osl_os_close_image(void *image)
-{
-       struct file *fp = (struct file *)image;
-
-       if (fp != NULL) {
-               filp_close(fp, NULL);
-       }
-}
-
-int
-osl_os_image_size(void *image)
-{
-       int len = 0, curroffset;
-
-       if (image) {
-               /* store the current offset */
-               curroffset = generic_file_llseek(image, 0, 1);
-               /* goto end of file to get length */
-               len = generic_file_llseek(image, 0, 2);
-               /* restore back the offset */
-               generic_file_llseek(image, curroffset, 0);
-       }
-       return len;
-}
-
 /* Linux Kernel: File Operations: end */
 
 #if defined(AXI_TIMEOUTS_NIC)
@@ -1955,7 +1891,11 @@ osl_timer_del(osl_t *osh, osl_timer_t *t)
 int
 kernel_read_compat(struct file *file, loff_t offset, char *addr, unsigned long count)
 {
+#ifdef DHD_SUPPORT_VFS_CALL
        return (int)kernel_read(file, addr, (size_t)count, &offset);
+#else
+       return 0;
+#endif /* DHD_SUPPORT_VFS_CALL */
 }
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) */
 
index 7a60390d9d623704f75c4dc373499287d4b891f9..6fe9efb1c9873f999fe3750103f1c3c5b3d44b24 100755 (executable)
@@ -88,8 +88,6 @@
 #define WL_BSSIDX_MAX  16
 #endif /* WL_STATIC_IF */
 
-uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL;
-
 #define ANDROID_ERROR_MSG(x, args...) \
        do { \
                if (android_msg_level & ANDROID_ERROR_LEVEL) { \
@@ -728,8 +726,24 @@ static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
 #define CMD_TWT_SETUP          "TWT_SETUP"
 #define CMD_TWT_TEARDOWN       "TWT_TEARDOWN"
 #define CMD_TWT_INFO           "TWT_INFO_FRM"
-#define CMD_TWT_STATUS_QUERY   "TWT_STATUS"
-#define CMD_TWT_CAPABILITY     "TWT_CAP"
+#define CMD_TWT_STATUS_QUERY   "GET_TWT_STATUS"
+#define CMD_TWT_CAPABILITY     "GET_TWT_CAP"
+#define CMD_TWT_GET_STATS      "GET_TWT_STATISTICS"
+#define CMD_TWT_CLR_STATS      "CLEAR_TWT_STATISTICS"
+#define WL_TWT_CMD_INVAL       255
+
+/* setup command name to value conversion */
+static struct {
+       const char *name;
+       uint8 val;
+} setup_cmd_val[] = {
+       {"request", TWT_SETUP_CMD_REQUEST_TWT},
+       {"suggest", TWT_SETUP_CMD_SUGGEST_TWT},
+       {"demand", TWT_SETUP_CMD_DEMAND_TWT},
+       {"accept", TWT_SETUP_CMD_ACCEPT_TWT},
+       {"alternate", TWT_SETUP_CMD_ALTER_TWT},
+       {"reject", TWT_SETUP_CMD_REJECT_TWT}
+};
 #endif /* WL_TWT */
 
 /* drv command info structure */
@@ -896,7 +910,9 @@ static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
        char *command, int total_len);
 static int wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
        uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size);
+#ifdef WES_SUPPORT
 static int wl_android_wbtext_enable(struct net_device *dev, int mode);
+#endif // WES_SUPPORT
 #endif /* WBTEXT */
 #ifdef WES_SUPPORT
 /* wl_roam.c */
@@ -1677,14 +1693,6 @@ wl_android_set_band(struct net_device *dev, char *command)
 
 #ifdef CUSTOMER_HW4_PRIVATE_CMD
 #ifdef ROAM_API
-#ifdef WBTEXT
-static bool wl_android_check_wbtext_support(struct net_device *dev)
-{
-       dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
-       return dhdp->wbtext_support;
-}
-#endif /* WBTEXT */
-
 static bool
 wl_android_check_wbtext_policy(struct net_device *dev)
 {
@@ -4290,6 +4298,13 @@ static int wl_android_wbtext(struct net_device *dev, char *command, int total_le
        return error;
 }
 
+#ifdef WES_SUPPORT
+static bool wl_android_check_wbtext_support(struct net_device *dev)
+{
+       dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
+       return dhdp->wbtext_support;
+}
+
 static int
 wl_android_wbtext_enable(struct net_device *dev, int mode)
 {
@@ -4308,6 +4323,7 @@ wl_android_wbtext_enable(struct net_device *dev, int mode)
 
        return error;
 }
+#endif /* WES_SUPPORT */
 
 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
        char *command, int total_len)
@@ -4901,10 +4917,10 @@ int wl_android_wifi_on(struct net_device *dev)
                        dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
 #ifdef BCMSDIO
                        ret = dhd_net_bus_resume(dev, 0);
+                       if (ret)
+                               goto retry_power;
 #endif /* BCMSDIO */
-#ifdef BCMPCIE
                        ret = dhd_net_bus_devreset(dev, FALSE);
-#endif /* BCMPCIE */
 #ifdef WBRC
                        if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ONCE) {
                                ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n",
@@ -4921,14 +4937,30 @@ int wl_android_wifi_on(struct net_device *dev)
                                ret = BCME_ERROR;
                        }
 #endif /* WBRC */
+                       if (ret)
+                               goto retry_power;
+#if defined(BCMSDIO) || defined(BCMDBUS)
+#ifdef BCMSDIO
+                       dhd_net_bus_resume(dev, 1);
+#endif /* BCMSDIO */
+                       ret = dhd_dev_init_ioctl(dev);
+                       if (ret < 0) {
+                               goto retry_bus;
+                       }
+#endif /* BCMSDIO || BCMDBUS */
                        if (ret == 0) {
                                break;
                        }
+#if defined(BCMSDIO) || defined(BCMDBUS)
+retry_bus:
+#ifdef BCMSDIO
+                       dhd_net_bus_suspend(dev);
+#endif /* BCMSDIO */
+#endif /* BCMSDIO || BCMDBUS */
+retry_power:
                        ANDROID_ERROR(("failed to power up wifi chip, retry again (%d left) **\n\n",
                                retry));
-#ifdef BCMPCIE
                        dhd_net_bus_devreset(dev, TRUE);
-#endif /* BCMPCIE */
                        dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
 #ifdef WBRC
                        /* Inform BT reset which will internally wait till BT reset is done */
@@ -4944,41 +4976,16 @@ int wl_android_wifi_on(struct net_device *dev)
 #endif /* BCM_DETECT_TURN_ON_FAILURE */
                        goto exit;
                }
-#if defined(BCMSDIO) || defined(BCMDBUS)
-               ret = dhd_net_bus_devreset(dev, FALSE);
-               if (ret)
-                       goto err;
-#ifdef BCMSDIO
-               dhd_net_bus_resume(dev, 1);
-#endif /* BCMSDIO */
-#endif /* BCMSDIO || BCMDBUS */
-#if defined(BCMSDIO) || defined(BCMDBUS)
-               if (!ret) {
-                       if (dhd_dev_init_ioctl(dev) < 0) {
-                               ret = -EFAULT;
-                               goto err;
-                       }
-               }
-#endif /* BCMSDIO || BCMDBUS */
                g_wifi_on = TRUE;
        }
 
 exit:
-       WL_MSG(dev->name, "Success\n");
-       dhd_net_if_unlock(dev);
-       return ret;
-
-#if defined(BCMSDIO) || defined(BCMDBUS)
-err:
-       dhd_net_bus_devreset(dev, TRUE);
-#ifdef BCMSDIO
-       dhd_net_bus_suspend(dev);
-#endif /* BCMSDIO */
-       dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
-       WL_MSG(dev->name, "Failed\n");
+       if (ret)
+               WL_MSG(dev->name, "Failed %d\n", ret);
+       else
+               WL_MSG(dev->name, "Success\n");
        dhd_net_if_unlock(dev);
        return ret;
-#endif /* BCMSDIO || BCMDBUS */
 }
 
 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
@@ -10275,8 +10282,17 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
 exit:
 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
        if (ret) {
-               /* Avoid incrementing priv_cmd_errors in case of unsupported feature */
-               if (ret != BCME_UNSUPPORTED) {
+               /* Avoid incrementing priv_cmd_errors in case of unsupported feature
+               * or BUSY state specific to TWT commands
+               */
+               if (
+#ifdef WL_TWT
+                       ((ret != BCME_BUSY) &&
+                       ((strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) ||
+                       (strnicmp(command, CMD_TWT_TEARDOWN, strlen(CMD_TWT_TEARDOWN)) == 0) ||
+                       (strnicmp(command, CMD_TWT_INFO, strlen(CMD_TWT_INFO)) == 0))) ||
+#endif /* WL_TWT */
+                       (ret != BCME_UNSUPPORTED)) {
                        wl_android_check_priv_cmd_errors(net);
                }
        } else {
@@ -11156,18 +11172,31 @@ wl_android_enable_p2p_6g(struct net_device *dev, int enable)
 
 #ifdef WL_TWT
 
+static uint8
+wl_twt_cmd2val(const char *name)
+{
+       uint i;
+
+       for (i = 0; i < ARRAYSIZE(setup_cmd_val); i ++) {
+               if (strcmp(name, setup_cmd_val[i].name) == 0) {
+                       return setup_cmd_val[i].val;
+               }
+       }
+
+       return WL_TWT_CMD_INVAL;
+}
+
 static int
 wl_android_twt_setup(struct net_device *ndev, char *command, int total_len)
 {
-       wl_twt_config_t val;
-       s32 bw;
+       wl_twt_setup_t val;
+       s32 bw = 0;
        char *token, *pos;
        u8 mybuf[WLC_IOCTL_SMLEN] = {0};
        u8 resp_buf[WLC_IOCTL_SMLEN] = {0};
-       u64 twt;
        uint8 *rem = mybuf;
        uint16 rem_len = sizeof(mybuf);
-       int32 val32;
+       uint8 tmp;
 
        WL_DBG_MEM(("Enter. cmd:%s\n", command));
 
@@ -11181,126 +11210,129 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len)
        val.version = WL_TWT_SETUP_VER;
        val.length = sizeof(val.version) + sizeof(val.length);
 
-       /* Default values, Overide Below */
-       val.desc.wake_time_h = 0xFFFFFFFF;
-       val.desc.wake_time_l = 0xFFFFFFFF;
-       val.desc.wake_int_min = 0xFFFFFFFF;
-       val.desc.wake_int_max = 0xFFFFFFFF;
-       val.desc.wake_dur_min = 0xFFFFFFFF;
-       val.desc.wake_dur_max = 0xFFFFFFFF;
-       val.desc.avg_pkt_num  = 0xFFFFFFFF;
+       val.desc.bid = WL_TWT_INV_BCAST_ID;
+       val.desc.flow_id = WL_TWT_INV_FLOW_ID;
+       val.desc.btwt_persistence = WL_TWT_INFINITE_BTWT_PERSIST;
+       val.desc.wake_type = WL_TWT_TIME_TYPE_AUTO;
 
        pos = command + sizeof(CMD_TWT_SETUP);
 
-       /* negotiation_type */
+       /* setup_cmd */
        token = strsep((char**)&pos, " ");
        if (!token) {
-               ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
+               ANDROID_ERROR(("Mandaory param setup_cmd not present\n"));
                bw = -EINVAL;
                goto exit;
        }
-       val.desc.negotiation_type  = htod32((u32)bcm_atoi(token));
 
-       /* Wake Duration */
-       token = strsep((char**)&pos, " ");
-       if (!token) {
-               ANDROID_ERROR(("Mandatory param wake Duration not present\n"));
-               bw = -EINVAL;
-               goto exit;
+       val.desc.setup_cmd = wl_twt_cmd2val(token);
+       if (val.desc.setup_cmd == WL_TWT_CMD_INVAL) {
+               ANDROID_ERROR(("Unrecognized TWT Setup command '%s'\n", token));
        }
-       val.desc.wake_dur = htod32((u32)bcm_atoi(token));
+       ANDROID_INFO(("TWT_SETUP val.desc.setup_cmd %s\n", token));
 
-       /* Wake interval */
+       /* negotiation_type */
        token = strsep((char**)&pos, " ");
        if (!token) {
-               ANDROID_ERROR(("Mandaory param Wake Interval not present\n"));
+               ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
                bw = -EINVAL;
                goto exit;
        }
-       val.desc.wake_int = htod32((u32)bcm_atoi(token));
-
-       /* Wake Time parameter */
-       token = strsep((char**)&pos, " ");
-       if (!token) {
-               ANDROID_ERROR(("No Wake Time parameter provided, using default\n"));
-       } else {
-               twt = (u64)bcm_atoi(token);
-               val32 = htod32((u32)(twt >> 32));
-               if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) {
-                       val.desc.wake_time_h = htod32((u32)(twt >> 32));
-                       val.desc.wake_time_l = htod32((u32)twt);
-               }
-       }
+       val.desc.negotiation_type = htod32((u32)bcm_atoi(token));
+       ANDROID_INFO(("TWT_SETUP val.desc.negotiation_type %d\n", val.desc.negotiation_type));
 
-       /* Minimum allowed Wake interval */
-       token = strsep((char**)&pos, " ");
-       if (!token) {
-               ANDROID_ERROR(("No Minimum allowed Wake interval provided, using default\n"));
-       } else {
-               val32 = htod32((u32)bcm_atoi(token));
-               if (val32 != -1) {
-                       val.desc.wake_int_min = htod32((u32)bcm_atoi(token));
-               }
-       }
-
-       /* Max Allowed Wake interval */
-       token = strsep((char**)&pos, " ");
-       if (!token) {
-               ANDROID_ERROR(("Maximum allowed Wake interval not provided, using default\n"));
-       } else {
-               val32 = htod32((u32)bcm_atoi(token));
-               if (val32 != -1) {
-                       val.desc.wake_int_max = htod32((u32)bcm_atoi(token));
-               }
-       }
-
-       /* Minimum allowed Wake duration */
-       token = strsep((char**)&pos, " ");
-       if (!token) {
-               ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n"));
-       } else {
-               val32 = htod32((u32)bcm_atoi(token));
-               if (val32 != -1) {
-                       val.desc.wake_dur_min = htod32((u32)bcm_atoi(token));
-               }
-       }
-
-       /* Maximum allowed Wake duration */
-       token = strsep((char**)&pos, " ");
-       if (!token) {
-               ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n"));
-       } else {
-               val32 = htod32((u32)bcm_atoi(token));
-               if (val32 != -1) {
-                       val.desc.wake_dur_max = htod32((u32)bcm_atoi(token));
-               }
-       }
+       if (pos != NULL) {
+               ANDROID_INFO(("TWT_SETUP string %s\n", pos));
+               while ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
+                       ANDROID_INFO(("TWT_SETUP token is %s\n", token));
 
-       /* Average number of packets */
-       token = strsep((char**)&pos, " ");
-       if (!token) {
-               ANDROID_ERROR(("Average number of packets not provided, using default\n"));
-       } else {
-               val32 = htod32((u32)bcm_atoi(token));
-               if (val32 != -1) {
-                       val.desc.avg_pkt_num  = htod32((u32)bcm_atoi(token));
-               }
-       }
-
-       /* a peer_address */
-       token = strsep((char**)&pos, " ");
-       if (!token) {
-               ANDROID_ERROR(("Average number of packets not provided, using default\n"));
-       } else {
-               /* get peer mac */
-               if (!bcm_ether_atoe(token, &val.peer)) {
-                       ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
-                       bw = BCME_ERROR;
-                       goto exit;
+                       if (!strnicmp(token, "u", 1)) {
+                               val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNANNOUNCED;
+                       }
+                       else if (!strnicmp(token, "t", 1)) {
+                               val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER;
+                       }
+                       else if (!strnicmp(token, "n", 1)) {
+                               val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNSOLICITED;
+                       }
+                       else if (!strnicmp(token, "p", 1)) {
+                               token++;
+                               val.desc.btwt_persistence = (int)simple_strtol(token, NULL, 0);
+                               ANDROID_INFO(("TWT_SETUP broadcast persistence %d\n",
+                                       val.desc.btwt_persistence));
+                       }
+                       /* Wake Duration */
+                       else if (!strnicmp(token, "-d", 2)) {
+                               if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
+                                       val.desc.wake_dur = (int)simple_strtol(token, NULL, 0);
+                                       ANDROID_INFO(("TWT_SETUP val.desc.wake_dur %d\n",
+                                               val.desc.wake_dur));
+                               }
+                       }
+                       /* Wake Interval */
+                       else if (!strnicmp(token, "-i", 2)) {
+                               if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
+                                       val.desc.wake_int = (int)simple_strtol(token, NULL, 0);
+                                       ANDROID_INFO(("TWT_SETUP val.desc.wake_int %d\n",
+                                               val.desc.wake_int));
+                               }
+                       }
+                       /* flow id */
+                       else if (!strnicmp(token, "-f", 2)) {
+                               if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
+                                       val.desc.flow_id = (int)simple_strtol(token, NULL, 0);
+                                       ANDROID_INFO(("TWT_SETUP val.desc.flow_id %d\n",
+                                               val.desc.flow_id));
+                               }
+                       }
+                       else if (!strnicmp(token, "-b", 2)) {
+                               if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
+                                       val.desc.bid = (int)simple_strtol(token, NULL, 0);
+                                       ANDROID_INFO(("TWT_SETUP val.desc.bid %d\n", val.desc.bid));
+                               }
+                       }
+                       else if (!strnicmp(token, "-r", 2)) {
+                               if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
+                                       tmp = (int)simple_strtol(token, NULL, 0);
+                                       if (tmp > TWT_BCAST_FRAME_RECOMM_3) {
+                                               bw = -EINVAL;
+                                               goto exit;
+                                       }
+                                       val.desc.bid = tmp;
+                                       ANDROID_INFO(("TWT_SETUP frame recommendation %d\n",
+                                               val.desc.frame_recomm));
+                               }
+                       }
+                       else if (!strnicmp(token, "-s", 2)) {
+                               if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
+                                       val.desc.duty_cycle_min =
+                                               (int)simple_strtol(token, NULL, 0);
+                                       ANDROID_INFO(("TWT_SETUP duty_cycle_min %d\n",
+                                               val.desc.duty_cycle_min));
+                               }
+                       }
+                       else if (!strnicmp(token, "-v", 2)) {
+                               if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
+                                       val.desc.wake_int_max = (int)simple_strtol(token, NULL, 0);
+                                       ANDROID_INFO(("TWT_SETUP wake_int_max %d\n",
+                                               val.desc.wake_int_max));
+                               }
+                       }
+                       /* a peer_address */
+                       else if (!strnicmp(token, "-a", 2)) {
+                               if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
+                                       if (!bcm_ether_atoe(token, &val.peer)) {
+                                               ANDROID_ERROR(("%s : Malformed peer addr\n",
+                                                       __FUNCTION__));
+                                               bw = -EINVAL;
+                                               goto exit;
+                                       }
+                               }
+                       }
                }
        }
 
-       bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG,
+       bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_SETUP,
                        sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
        if (bw != BCME_OK) {
                goto exit;
@@ -11309,7 +11341,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len)
        bw = wldev_iovar_setbuf(ndev, "twt",
                mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL);
        if (bw < 0) {
-               ANDROID_ERROR(("twt config set failed. ret:%d\n", bw));
+               ANDROID_ERROR(("twt setup failed. ret:%d\n", bw));
        }
 exit:
        return bw;
@@ -11918,6 +11950,116 @@ wl_android_twt_teardown(struct net_device *ndev, char *command, int total_len)
 exit:
        return bw;
 }
+
+/* wl twt stats result display version 2 */
+static int
+wl_android_twt_stats_display_v2(wl_twt_stats_v2_t *stats, char *command, int total_len)
+{
+       u32 i;
+       wl_twt_peer_stats_v2_t *peer_stats;
+       int rem_len = 0, bytes_written = 0;
+
+       rem_len = total_len;
+       for (i = 0; i < stats->num_stats; i++) {
+               peer_stats = &stats->peer_stats_list[i];
+
+               bytes_written = scnprintf(command, rem_len,
+                       "%u %u %u %u %u",
+                       peer_stats->eosp_dur_avg, peer_stats->tx_pkts_avg, peer_stats->rx_pkts_avg,
+                       peer_stats->tx_pkt_sz_avg, peer_stats->rx_pkt_sz_avg);
+               CHECK_SCNPRINTF_RET_VAL(bytes_written);
+               command += bytes_written;
+               rem_len -= bytes_written;
+       }
+
+       if ((total_len - rem_len) > 0) {
+               return (total_len - rem_len);
+       } else {
+               return BCME_ERROR;
+       }
+}
+
+static int
+wl_android_twt_stats(struct net_device *ndev, char *command, int total_len)
+{
+       wl_twt_stats_cmd_v1_t query;
+       wl_twt_stats_v2_t stats_v2;
+       int ret = BCME_OK;
+       char iovbuf[WLC_IOCTL_SMLEN] = {0, };
+       uint8 *pxtlv = NULL;
+       uint8 *iovresp = NULL;
+       char *token, *pos;
+       uint16 buflen = 0, bufstart = 0;
+       struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
+
+       WL_DBG_MEM(("Enter. cmd:%s\n", command));
+
+       bzero(&query, sizeof(query));
+       query.version = WL_TWT_STATS_CMD_VERSION_1;
+       query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer);
+
+       /* Default values, Overide Below */
+       query.num_bid = 0xFF;
+       query.num_fid = 0xFF;
+
+       if (!(strnicmp(command, CMD_TWT_CLR_STATS, strlen(CMD_TWT_CLR_STATS)))) {
+               query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET;
+               pos = command + sizeof(CMD_TWT_CLR_STATS);
+       } else if (!(strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)))) {
+               pos = command + sizeof(CMD_TWT_GET_STATS);
+       }
+
+       /* Config ID */
+       token = strsep((char**)&pos, " ");
+       if (!token) {
+               ANDROID_ERROR(("Mandatory param config ID not present\n"));
+               ret = -EINVAL;
+               goto exit;
+       }
+       query.configID = (u8)bcm_atoi(token);
+
+       iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
+       if (iovresp == NULL) {
+               ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
+               goto exit;
+       }
+
+       buflen = bufstart = WLC_IOCTL_SMLEN;
+       pxtlv = (uint8 *)iovbuf;
+       ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS,
+                       sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32);
+       if (ret != BCME_OK) {
+               ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
+               goto exit;
+       }
+
+       if ((ret = wldev_iovar_getbuf(ndev, "twt", iovbuf, bufstart-buflen,
+               iovresp, WLC_IOCTL_MEDLEN, NULL))) {
+               ANDROID_ERROR(("twt status failed with err=%d \n", ret));
+               goto exit;
+       }
+
+       (void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2));
+
+       if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) {
+               if (!(strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)))) {
+                       ANDROID_ERROR(("stats query ver %d, \n", dtoh16(stats_v2.version)));
+                       ret = wl_android_twt_stats_display_v2((wl_twt_stats_v2_t*)iovresp,
+                               command, total_len);
+               }
+       } else {
+               ret = BCME_UNSUPPORTED;
+               ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version)));
+               goto exit;
+       }
+
+exit:
+       if (iovresp) {
+               MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
+       }
+
+       return ret;
+}
 #endif /* WL_TWT */
 
 int
@@ -12885,6 +13027,10 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
        else if (strnicmp(command, CMD_TWT_CAPABILITY, strlen(CMD_TWT_CAPABILITY)) == 0) {
                bytes_written = wl_android_twt_cap(net, command, priv_cmd.total_len);
        }
+       else if ((strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)) == 0) ||
+               (strnicmp(command, CMD_TWT_CLR_STATS, strlen(CMD_TWT_CLR_STATS)) == 0)) {
+               bytes_written = wl_android_twt_stats(net, command, priv_cmd.total_len);
+       }
 #endif /* WL_TWT */
 #ifdef WL_P2P_6G
        else if (strnicmp(command, CMD_ENABLE_6G_P2P, strlen(CMD_ENABLE_6G_P2P)) == 0) {
@@ -13372,7 +13518,7 @@ wl_cfg80211_static_if_open(struct net_device *net)
        if (cfg->static_ndev_state[static_ifidx] != NDEV_STATE_FW_IF_CREATED) {
 #ifdef CUSTOM_MULTI_MAC
                if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1))
-                       memcpy(net->dev_addr, hw_ether, ETHER_ADDR_LEN);
+                       dev_addr_set(net, hw_ether);
 #endif
                wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, net->dev_addr);
                if (!wdev) {
@@ -13424,7 +13570,7 @@ wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
                wdev = new_ndev->ieee80211_ptr;
                ASSERT(wdev);
                wdev->iftype = iface_type;
-               (void)memcpy_s(new_ndev->dev_addr, ETH_ALEN, addr, ETH_ALEN);
+               dev_addr_set(new_ndev, addr);
        }
 
        cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_CREATED;
index b08a18b32cdf815067ea355e1edfa4ed6f5c5110..a93a52019a9d302f3d2038983b94e2d8d1e00817 100755 (executable)
 #include <wldev_common.h>
 #include <dngl_stats.h>
 #include <dhd.h>
+#include <wl_android_ext.h>
 #ifdef WL_EXT_IAPSTA
-#ifdef WL_ESCAN
-#include <wl_escan.h>
-#endif /* WL_ESCAN */
 #include <wl_iapsta.h>
 #endif /* WL_IAPSTA */
 #if defined(WL_EXT_IAPSTA) || defined(USE_IW) || defined(WL_ESCAN) || \
@@ -42,7 +40,7 @@
 #endif
 #include <wl_event.h>
 #endif
-#include <wl_android_ext.h>
+#include <wl_timer.h>
 
 /* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL
  * automatically
@@ -82,6 +80,9 @@ typedef struct _compat_android_wifi_priv_cmd {
 #define ANDROID_SCAN_LEVEL     (1 << 3)
 #define ANDROID_DBG_LEVEL      (1 << 4)
 #define ANDROID_TPUT_LEVEL     (1 << 8)
+#define ANDROID_AMPDU_LEVEL    (1 << 9)
+#define ANDROID_TVPM_LEVEL     (1 << 10)
+#define ANDROID_BTC_LEVEL      (1 << 11)
 #define ANDROID_MSG_LEVEL      (1 << 0)
 
 #define WL_MSG(name, arg1, args...) \
@@ -249,4 +250,11 @@ extern int wl_android_bcnrecv_event(struct net_device *ndev,
 #define WLC_ACS_BAND_INVALID   0xffffu
 #endif /* WL_SUPPORT_AUTO_CHANNEL */
 #define WL_PRIV_CMD_LEN 64
+#define CHECK_SCNPRINTF_RET_VAL(ret) \
+       { \
+               if (ret < 0) { \
+                               WL_ERR(("scnprintf failed %d\n", ret)); \
+                               return BCME_ERROR; \
+               } \
+       }
 #endif /* _wl_android_ */
index 789936507fd4d55997ba6becfc353a939a772ad0..1c43178c1aa64aec6db451d9dde4cc42105576e2 100755 (executable)
@@ -32,6 +32,8 @@
 #include <wl_escan.h>
 #endif /* WL_ESCAN */
 
+uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL;
+
 #define AEXT_ERROR(name, arg1, args...) \
        do { \
                if (android_msg_level & ANDROID_ERROR_LEVEL) { \
@@ -80,6 +82,9 @@
 #define CMD_ROAM_TRIGGER               "ROAM_TRIGGER"
 #define CMD_PM                                 "PM"
 #define CMD_MONITOR                            "MONITOR"
+#ifdef BTC_WAR
+#define CMD_BTC_WAR                    "BTC_WAR"
+#endif /* BTC_WAR */
 #define CMD_SET_SUSPEND_BCN_LI_DTIM            "SET_SUSPEND_BCN_LI_DTIM"
 #define CMD_WLMSGLEVEL                 "WLMSGLEVEL"
 #ifdef WL_EXT_IAPSTA
@@ -179,7 +184,7 @@ const auth_name_map_t auth_name_map[] = {
        {WL_AUTH_SAE_KEY,               WPA3_AUTH_SAE_PSK|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK,   "wpa3sae/psk/sha256"},
        {WL_AUTH_OPEN_SYSTEM,   0x20|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK,        "wpa3/psk/sha256"},
        {WL_AUTH_SAE_KEY,               0x20|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK,        "wpa3sae/psk/sha256"},
-       {WL_AUTH_OPEN_SYSTEM,   WPA3_AUTH_OWE,  "wpa3/owe"},
+       {WL_AUTH_OPEN_SYSTEM,   WPA3_AUTH_OWE,  "owe"},
 };
 
 typedef struct wsec_name_map_t {
@@ -317,9 +322,9 @@ wl_ext_chspec_to_legacy(chanspec_t chspec)
 }
 
 chanspec_t
-wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec)
+wl_ext_chspec_host_to_driver(struct dhd_pub *dhd, chanspec_t chanspec)
 {
-       if (ioctl_ver == 1) {
+       if (dhd->conf->ioctl_ver == 1) {
                chanspec = wl_ext_chspec_to_legacy(chanspec);
                if (chanspec == INVCHANSPEC) {
                        return chanspec;
@@ -331,7 +336,7 @@ wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec)
 }
 
 static void
-wl_ext_ch_to_chanspec(int ioctl_ver, int ch,
+wl_ext_ch_to_chanspec(struct dhd_pub *dhd, int ch,
        struct wl_join_params *join_params, size_t *join_params_size)
 {
        chanspec_t chanspec = 0;
@@ -354,7 +359,7 @@ wl_ext_ch_to_chanspec(int ioctl_ver, int ch,
                join_params->params.chanspec_list[0]  &= WL_CHANSPEC_CHAN_MASK;
                join_params->params.chanspec_list[0] |= chanspec;
                join_params->params.chanspec_list[0] =
-                       wl_ext_chspec_host_to_driver(ioctl_ver,
+                       wl_ext_chspec_host_to_driver(dhd,
                                join_params->params.chanspec_list[0]);
 
                join_params->params.chanspec_num =
@@ -399,10 +404,10 @@ wl_ext_chspec_from_legacy(chanspec_t legacy_chspec)
 }
 
 chanspec_t
-wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec)
+wl_ext_chspec_driver_to_host(struct dhd_pub *dhd, chanspec_t chanspec)
 {
        chanspec = dtohchanspec(chanspec);
-       if (ioctl_ver == 1) {
+       if (dhd->conf->ioctl_ver == 1) {
                chanspec = wl_ext_chspec_from_legacy(chanspec);
        }
 
@@ -410,6 +415,30 @@ wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec)
 }
 #endif /* WL_EXT_IAPSTA || WL_CFG80211 || WL_ESCAN */
 
+chanspec_band_t
+wl_ext_wlcband_to_chanspec_band(int band)
+{
+       chanspec_band_t chanspec_band = INVCHANSPEC;
+
+       switch (band) {
+#ifdef WL_6G_BAND
+               case WLC_BAND_6G:
+                       chanspec_band = WL_CHANSPEC_BAND_6G;
+                       break;
+#endif /* WL_6G_BAND */
+               case WLC_BAND_5G:
+                       chanspec_band = WL_CHANSPEC_BAND_5G;
+                       break;
+               case WLC_BAND_2G:
+                       chanspec_band = WL_CHANSPEC_BAND_2G;
+                       break;
+               default:
+                       AEXT_ERROR("wlan", "Invalid Frequency Band\n");
+                       break;
+       }
+       return chanspec_band;
+}
+
 bool
 wl_ext_check_scan(struct net_device *dev, dhd_pub_t *dhdp)
 {
@@ -526,28 +555,6 @@ wl_ext_wait_event_complete(struct dhd_pub *dhd, int ifidx)
        }
 }
 
-int
-wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver)
-{
-       int ret = 0;
-       s32 val = 0;
-
-       val = 1;
-       ret = wl_ext_ioctl(dev, WLC_GET_VERSION, &val, sizeof(val), 0);
-       if (ret) {
-               return ret;
-       }
-       val = dtoh32(val);
-       if (val != WLC_IOCTL_VERSION && val != 1) {
-               AEXT_ERROR(dev->name, "Version mismatch, please upgrade. Got %d, expected %d or 1\n",
-                       val, WLC_IOCTL_VERSION);
-               return BCME_VERSION;
-       }
-       *ioctl_ver = val;
-
-       return ret;
-}
-
 void
 wl_ext_bss_iovar_war(struct net_device *ndev, s32 *val)
 {
@@ -585,10 +592,11 @@ wl_ext_bss_iovar_war(struct net_device *ndev, s32 *val)
 }
 
 int
-wl_ext_set_chanspec(struct net_device *dev, int ioctl_ver,
-       uint16 channel, chanspec_t *ret_chspec)
+wl_ext_set_chanspec(struct net_device *dev, struct wl_chan_info *chan_info,
+       chanspec_t *ret_chspec)
 {
-       s32 _chan = channel;
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       s32 _chan = chan_info->chan;
        chanspec_t chspec = 0;
        chanspec_t fw_chspec = 0;
        u32 bw = WL_CHANSPEC_BW_20;
@@ -599,53 +607,54 @@ wl_ext_set_chanspec(struct net_device *dev, int ioctl_ver,
                u32 band;
                u32 bw_cap;
        } param = {0, 0};
-       uint band;
+       chanspec_band_t chanspec_band = 0;
 
-       if (_chan <= CH_MAX_2G_CHANNEL)
-               band = IEEE80211_BAND_2GHZ;
-       else
-               band = IEEE80211_BAND_5GHZ;
+       if ((chan_info->band != WLC_BAND_2G) && (chan_info->band != WLC_BAND_5G) &&
+                       (chan_info->band != WLC_BAND_6G)) {
+               AEXT_ERROR(dev->name, "bad band %d\n", chan_info->band);
+               return BCME_BADBAND;
+       }
 
-       if (band == IEEE80211_BAND_5GHZ) {
-               param.band = WLC_BAND_5G;
-               err = wl_ext_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
-                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
-               if (err) {
-                       if (err != BCME_UNSUPPORTED) {
-                               AEXT_ERROR(dev->name, "bw_cap failed, %d\n", err);
-                               return err;
-                       } else {
-                               err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
-                               if (bw_cap != WLC_N_BW_20ALL)
-                                       bw = WL_CHANSPEC_BW_40;
-                       }
+       param.band = chan_info->band;
+       err = wl_ext_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
+               iovar_buf, WLC_IOCTL_SMLEN, NULL);
+       if (err) {
+               if (err != BCME_UNSUPPORTED) {
+                       AEXT_ERROR(dev->name, "bw_cap failed, %d\n", err);
+                       return err;
                } else {
-                       if (WL_BW_CAP_80MHZ(iovar_buf[0]))
-                               bw = WL_CHANSPEC_BW_80;
-                       else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
+                       err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
+                       if (bw_cap != WLC_N_BW_20ALL)
                                bw = WL_CHANSPEC_BW_40;
-                       else
-                               bw = WL_CHANSPEC_BW_20;
-
                }
+       } 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);
+       chanspec_band = wl_ext_wlcband_to_chanspec_band(chan_info->band);
+       chspec = wf_create_chspec_from_primary(chan_info->chan, bw, chanspec_band);
        if (wf_chspec_valid(chspec)) {
-               fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec);
+               fw_chspec = wl_ext_chspec_host_to_driver(dhd, chspec);
                if (fw_chspec != INVCHANSPEC) {
                        if ((err = wl_ext_iovar_setint(dev, "chanspec", fw_chspec)) == BCME_BADCHAN) {
                                if (bw == WL_CHANSPEC_BW_80)
                                        goto change_bw;
                                err = wl_ext_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), 1);
-                               WL_MSG(dev->name, "channel %d\n", _chan);
+                               WL_MSG(dev->name, "channel %s-%d\n", CHSPEC2BANDSTR(chspec), _chan);
                        } else if (err) {
                                AEXT_ERROR(dev->name, "failed to set chanspec error %d\n", err);
                        } else
-                               WL_MSG(dev->name, "channel %d, 0x%x\n", channel, chspec);
+                               WL_MSG(dev->name, "channel %s-%d(0x%x %sMHz)\n",
+                                       CHSPEC2BANDSTR(chspec), chan_info->chan, chspec,
+                                       CHSPEC_IS20(chspec)?"20":
+                                       CHSPEC_IS40(chspec)?"40":
+                                       CHSPEC_IS80(chspec)?"80":"160");
                } else {
                        AEXT_ERROR(dev->name, "failed to convert host chanspec to fw chanspec\n");
                        err = BCME_ERROR;
@@ -671,20 +680,39 @@ change_bw:
 static int
 wl_ext_channel(struct net_device *dev, char* command, int total_len)
 {
+       struct wl_chan_info chan_info;
        int ret;
-       int channel=0;
+       char band[16]="";
+       int channel = 0;
        channel_info_t ci;
        int bytes_written = 0;
        chanspec_t fw_chspec;
-       int ioctl_ver = 0;
 
        AEXT_TRACE(dev->name, "cmd %s", command);
 
-       sscanf(command, "%*s %d", &channel);
+       sscanf(command, "%*s %d %s", &channel, band);
+       if (strnicmp(band, "band=auto", strlen("band=auto")) == 0) {
+               chan_info.band = WLC_BAND_AUTO;
+       }
+#ifdef WL_6G_BAND
+       else if (strnicmp(band, "band=6g", strlen("band=6g")) == 0) {
+               chan_info.band = WLC_BAND_6G;
+       }
+#endif /* WL_6G_BAND */
+       else if (strnicmp(band, "band=5g", strlen("band=5g")) == 0) {
+               chan_info.band = WLC_BAND_5G;
+       }
+       else if (strnicmp(band, "band=2g", strlen("band=2g")) == 0) {
+               chan_info.band = WLC_BAND_2G;
+       }
+       else if (channel <= CH_MAX_2G_CHANNEL)
+               chan_info.band = WLC_BAND_2G;
+       else
+               chan_info.band = WLC_BAND_5G;
 
        if (channel > 0) {
-               wl_ext_get_ioctl_ver(dev, &ioctl_ver);
-               ret = wl_ext_set_chanspec(dev, ioctl_ver, channel, &fw_chspec);
+               chan_info.chan = channel;
+               ret = wl_ext_set_chanspec(dev, &chan_info, &fw_chspec);
        } else {
                if (!(ret = wl_ext_ioctl(dev, WLC_GET_CHANNEL, &ci,
                                sizeof(channel_info_t), FALSE))) {
@@ -825,6 +853,30 @@ wl_ext_monitor(struct net_device *dev, char *command, int total_len)
        return ret;
 }
 
+#ifdef BTC_WAR
+extern int btc_war;
+static int
+wl_ext_btc_war(struct net_device *dev, char *command, int total_len)
+{
+       int user_btc_war = 0;
+       bool enable = FALSE;
+
+       sscanf(command, "%*s %d", &user_btc_war);
+
+       AEXT_TRACE(dev->name, "btc_war=%d, user_btc_war=%d\n",
+               btc_war, user_btc_war);
+
+       if (btc_war >= 0) {
+               btc_war = user_btc_war;
+               if (btc_war > 0)
+                       enable = TRUE;
+               wl_ext_btc_config(dev, enable);
+       }
+
+       return 0;
+}
+#endif /* BTC_WAR */
+
 s32
 wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info)
 {
@@ -835,11 +887,8 @@ wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info)
        s32 err = 0;
        u32 chan_cnt = 0;
        s8 *iovar_buf = NULL;
-       int ioctl_ver = 0;
        char sec[64];
 
-       wl_ext_get_ioctl_ver(dev, &ioctl_ver);
-
        if (dhd->conf->chip == BCM43362_CHIP_ID)
                goto set_ssid;
 
@@ -895,7 +944,7 @@ wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info)
                ext_join_params->assoc.chanspec_list[0]  &= WL_CHANSPEC_CHAN_MASK;
                ext_join_params->assoc.chanspec_list[0] |= chspec;
                ext_join_params->assoc.chanspec_list[0] =
-                       wl_ext_chspec_host_to_driver(ioctl_ver,
+                       wl_ext_chspec_host_to_driver(dhd,
                                ext_join_params->assoc.chanspec_list[0]);
        }
        ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
@@ -932,7 +981,7 @@ set_ssid:
        else
                memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
 
-       wl_ext_ch_to_chanspec(ioctl_ver, conn_info->channel, &join_params, &join_params_size);
+       wl_ext_ch_to_chanspec(dhd, conn_info->channel, &join_params, &join_params_size);
        AEXT_TRACE(dev->name, "join_param_size %zu\n", join_params_size);
 
        if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
@@ -1042,18 +1091,43 @@ wl_ext_get_sec(struct net_device *dev, int ifmode, char *sec, int total_len, boo
 }
 
 bool
-wl_ext_dfs_chan(uint16 chan)
+wl_ext_dfs_chan(struct wl_chan_info *chan_info)
 {
-       if (chan >= 52 && chan <= 144)
+       if (chan_info->band == WLC_BAND_5G && chan_info->chan >= 52 && chan_info->chan <= 144)
                return TRUE;
        return FALSE;
 }
 
+bool
+wl_ext_passive_chan(struct net_device *dev, struct wl_chan_info *chan_info)
+{
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       u32 chanspec;
+       s32 ret = BCME_OK;
+
+       chanspec = wf_create_chspec_from_primary(chan_info->chan,
+               WL_CHANSPEC_BW_20, wl_ext_wlcband_to_chanspec_band(chan_info->band));
+
+       chanspec = wl_ext_chspec_host_to_driver(dhd, chanspec);
+
+       ret = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
+       if (!ret) {
+               if (chanspec & WL_CHAN_PASSIVE)
+                       return TRUE;
+       } else {
+               if (chan_info->band == WLC_BAND_5G && chan_info->chan >= 52 && chan_info->chan <= 144)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
 uint16
 wl_ext_get_default_chan(struct net_device *dev,
        uint16 *chan_2g, uint16 *chan_5g, bool nodfs)
 {
        struct dhd_pub *dhd = dhd_get_pub(dev);
+       struct wl_chan_info chan_info;
        uint16 chan_tmp = 0, chan = 0;
        wl_uint32_list_t *list;
        u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
@@ -1075,7 +1149,11 @@ wl_ext_get_default_chan(struct net_device *dev,
                        if (chan_tmp <= 13 && !*chan_2g) {
                                *chan_2g = chan_tmp;
                        } else if (chan_tmp >= 36 && chan_tmp <= 161 && !*chan_5g) {
-                               if (wl_ext_dfs_chan(chan_tmp) && nodfs)
+                               chan_info.band = WLC_BAND_5G;
+                               chan_info.chan = chan_tmp;
+                               if (wl_ext_dfs_chan(&chan_info) && nodfs)
+                                       continue;
+                               else if (wl_ext_passive_chan(dev, &chan_info))
                                        continue;
                                else
                                        *chan_5g = chan_tmp;
@@ -1157,69 +1235,6 @@ wl_ext_wlmsglevel(struct net_device *dev, char *command, int total_len)
        return ret;
 }
 
-#ifdef WL_CFG80211
-bool
-wl_legacy_chip_check(struct net_device *net)
-{
-       struct dhd_pub *dhd = dhd_get_pub(net);
-       uint chip;
-
-       chip = dhd_conf_get_chip(dhd);
-
-       if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
-               chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID ||
-               chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID ||
-               chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID ||
-               chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
-               chip == BCM4371_CHIP_ID ||
-               chip == BCM43430_CHIP_ID ||
-               chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID ||
-               chip == BCM4359_CHIP_ID ||
-               chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID ||
-               chip == BCM43569_CHIP_ID) {
-               return true;
-       }
-
-       return false;
-}
-
-bool
-wl_new_chip_check(struct net_device *net)
-{
-       struct dhd_pub *dhd = dhd_get_pub(net);
-       uint chip;
-
-       chip = dhd_conf_get_chip(dhd);
-
-       if (chip == BCM4359_CHIP_ID || chip == BCM43012_CHIP_ID ||
-                       chip == BCM43751_CHIP_ID || chip == BCM43752_CHIP_ID) {
-               return true;
-       }
-
-       return false;
-}
-
-bool
-wl_extsae_chip(struct dhd_pub *dhd)
-{
-       uint chip;
-
-       chip = dhd_conf_get_chip(dhd);
-
-       if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
-               chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID ||
-               chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID ||
-               chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID ||
-               chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
-               chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID ||
-               chip == BCM43569_CHIP_ID) {
-               return false;
-       }
-
-       return true;
-}
-#endif
-
 #ifdef WLEASYMESH
 #define CMD_EASYMESH "EASYMESH"
 //Set map 4 and dwds 1 on wlan0 interface
@@ -1434,7 +1449,7 @@ wl_ext_mkeep_alive(struct net_device *dev, char *data, char *command,
        int total_len)
 {
        struct dhd_pub *dhd = dhd_get_pub(dev);
-       wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
+       wl_mkeep_alive_pkt_v1_t *mkeep_alive_pktp;
        int ret = -1, i, ifidx, id, period=-1;
        char *packet = NULL, *buf = NULL;
        int bytes_written = 0;
@@ -1462,7 +1477,7 @@ wl_ext_mkeep_alive(struct net_device *dev, char *data, char *command,
                        ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf,
                                total_len, NULL);
                        if (!ret) {
-                               mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) buf;
+                               mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *) buf;
                                bytes_written += snprintf(command+bytes_written, total_len,
                                        "Id            :%d\n"
                                        "Period (msec) :%d\n"
@@ -1670,25 +1685,23 @@ static int
 wl_ext_recal(struct net_device *dev, char *data, char *command,
        int total_len)
 {
+       struct dhd_pub *dhd = dhd_get_pub(dev);
        int ret = 0, i, nchan, nssid = 0;
-       int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
-       wl_scan_params_t *params = NULL;
-       int ioctl_ver;
+       int params_size = WL_SCAN_PARAMS_V1_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
+       wl_scan_params_v1_t *params = NULL;
        char *p;
 
        AEXT_TRACE(dev->name, "Enter\n");
 
        if (data) {
                params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
-               params = (wl_scan_params_t *) kzalloc(params_size, GFP_KERNEL);
+               params = (wl_scan_params_v1_t *) kzalloc(params_size, GFP_KERNEL);
                if (params == NULL) {
                        ret = -ENOMEM;
                        goto exit;
                }
                memset(params, 0, params_size);
 
-               wl_ext_get_ioctl_ver(dev, &ioctl_ver);
-
                memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
                params->bss_type = DOT11_BSSTYPE_ANY;
                params->scan_type = 0;
@@ -1709,7 +1722,7 @@ wl_ext_recal(struct net_device *dev, char *data, char *command,
                params->home_time = htod32(params->home_time);
 
                for (i = 0; i < nchan; i++) {
-                       wl_ext_chspec_host_to_driver(ioctl_ver, params->channel_list[i]);
+                       wl_ext_chspec_host_to_driver(dhd, params->channel_list[i]);
                }
 
                p = (char*)params->channel_list + nchan * sizeof(uint16);
@@ -2485,22 +2498,6 @@ typedef struct csi_list {
        csi_config_t configs[1];
 } csi_list_t;
 
-static int
-wl_ether_atoe(const char *a, struct ether_addr *n)
-{
-       char *c = NULL;
-       int i = 0;
-
-       memset(n, 0, ETHER_ADDR_LEN);
-       for (;;) {
-               n->octet[i++] = (uint8)strtoul(a, &c, 16);
-               if (!*c++ || i == ETHER_ADDR_LEN)
-                       break;
-               a = c;
-       }
-       return (i == ETHER_ADDR_LEN);
-}
-
 static int
 wl_ext_csi(struct net_device *dev, char *data, char *command, int total_len)
 {
@@ -2520,7 +2517,7 @@ wl_ext_csi(struct net_device *dev, char *data, char *command, int total_len)
 
        if (data) {
                sscanf(data, "%s %d", mac, &period);
-               ret = wl_ether_atoe(mac, &ea);
+               ret = bcm_ether_atoe(mac, &ea);
                if (!ret) {
                        AEXT_ERROR(dev->name, "rejecting mac=%s, ret=%d\n", mac, ret);
                        goto exit;
@@ -2618,6 +2615,34 @@ wl_ext_get_country(struct net_device *dev, char *data, char *command,
        return bytes_written;
 }
 
+static int
+wl_ext_disable_5g_band(struct net_device *dev, char *data, char *command,
+       int total_len)
+{
+#ifdef WL_CFG80211
+       struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
+#endif
+       int ret = -1;
+       int val;
+
+       if (data) {
+               val = (int)simple_strtol(data, NULL, 0);
+               ret = wl_ext_iovar_setint(dev, "disable_5g_band", val);
+#ifdef WL_CFG80211
+               if (!ret)
+                       wl_update_wiphybands(cfg, true);
+#endif
+       } else {
+               ret = wl_ext_iovar_getint(dev, "disable_5g_band", &val);
+               if (!ret) {
+                       ret = snprintf(command, total_len, "%d", val);
+                       AEXT_TRACE(dev->name, "command result is %s\n", command);
+               }
+       }
+
+       return ret;
+}
+
 typedef int (wl_ext_tpl_parse_t)(struct net_device *dev, char *data, char *command,
        int total_len);
 
@@ -2670,6 +2695,7 @@ const wl_ext_iovar_tpl_t wl_ext_iovar_tpl_list[] = {
        {WLC_GET_VAR,   WLC_SET_VAR,    "csi",                          wl_ext_csi},
 #endif /* CSI_SUPPORT */
        {WLC_GET_VAR,   WLC_SET_VAR,    "country",                      wl_ext_get_country},
+       {WLC_GET_VAR,   WLC_SET_VAR,    "disable_5g_band",      wl_ext_disable_5g_band},
 };
 
 /*
@@ -2811,6 +2837,11 @@ wl_android_ext_priv_cmd(struct net_device *net, char *command,
        else if (strnicmp(command, CMD_MONITOR, strlen(CMD_MONITOR)) == 0) {
                *bytes_written = wl_ext_monitor(net, command, total_len);
        }
+#ifdef BTC_WAR
+       else if (strnicmp(command, CMD_BTC_WAR, strlen(CMD_BTC_WAR)) == 0) {
+               *bytes_written = wl_ext_btc_war(net, command, total_len);
+       }
+#endif /* BTC_WAR */
        else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) {
                int bcn_li_dtim;
                bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10);
@@ -2886,6 +2917,85 @@ wl_android_ext_priv_cmd(struct net_device *net, char *command,
        return ret;
 }
 
+#define CH_MIN_5G_CHANNEL 34
+int
+wl_construct_ctl_chanspec_list(struct net_device *dev, wl_uint32_list_t *chan_list)
+{
+       void *list;
+       u32 i, channel;
+       chanspec_t chspec = 0;
+       s32 err = BCME_OK;
+       bool legacy_chan_info = FALSE;
+       u16 list_count;
+
+#define LOCAL_BUF_LEN 4096
+       list = kmalloc(LOCAL_BUF_LEN, GFP_KERNEL);
+       if (list == NULL) {
+               WL_ERR(("failed to allocate local buf\n"));
+               return -ENOMEM;
+       }
+
+       err = wldev_iovar_getbuf(dev, "chan_info_list", NULL,
+               0, list, LOCAL_BUF_LEN, NULL);
+       if (err == BCME_UNSUPPORTED) {
+               err = wl_ext_iovar_getbuf(dev, "chanspecs", NULL,
+                       0, list, LOCAL_BUF_LEN, NULL);
+               if (err != BCME_OK) {
+                       WL_ERR(("get chanspecs err(%d)\n", err));
+                       kfree(list);
+                       return err;
+               }
+               /* Update indicating legacy chan info usage */
+               legacy_chan_info = TRUE;
+       } else if (err != BCME_OK) {
+               WL_ERR(("get chan_info_list err(%d)\n", err));
+               kfree(list);
+               return err;
+       }
+
+       list_count = legacy_chan_info ? ((wl_uint32_list_t *)list)->count :
+               ((wl_chanspec_list_v1_t *)list)->count;
+       for (i = 0; i < dtoh32(list_count); i++) {
+               if (legacy_chan_info) {
+                       chspec = (chanspec_t)dtoh32(((wl_uint32_list_t *)list)->element[i]);
+               } else {
+                       chspec = (chanspec_t)dtoh32
+                       (((wl_chanspec_list_v1_t *)list)->chspecs[i].chanspec);
+               }
+               chspec = wl_chspec_driver_to_host(chspec);
+               channel = wf_chspec_ctlchan(chspec);
+
+               if (!CHSPEC_IS20(chspec)) {
+                       continue;
+               }
+               if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) &&
+                               (channel <= CH_MAX_2G_CHANNEL)) {
+                       chan_list->element[chan_list->count] = chspec;
+                       chan_list->count++;
+               }
+#ifdef WL_6G_BAND
+               else if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) &&
+                               (channel <= CH_MAX_6G_CHANNEL)) {
+                       if (channel == 2)
+                               continue;
+                       chan_list->element[chan_list->count] = chspec;
+                       chan_list->count++;
+               }
+#endif /* WL_6G_BAND */
+               else if (CHSPEC_IS5G(chspec) && (channel >= CH_MIN_5G_CHANNEL) &&
+                               (channel <= 165)) {
+                       chan_list->element[chan_list->count] = chspec;
+                       chan_list->count++;
+               } else {
+                       continue;
+               }
+       }
+
+       kfree(list);
+#undef LOCAL_BUF_LEN
+       return err;
+}
+
 #if defined(WL_CFG80211) || defined(WL_ESCAN)
 int
 wl_ext_get_distance(struct net_device *net, u32 band)
@@ -2938,52 +3048,86 @@ wl_ext_get_best_channel(struct net_device *net,
 #if defined(BSSCACHE)
        wl_bss_cache_ctrl_t *bss_cache_ctrl,
 #else
-       wl_scan_results_t *bss_list,
+       wl_scan_results_v109_t *bss_list,
 #endif /* BSSCACHE */
-       int ioctl_ver, int *best_2g_ch, int *best_5g_ch
-)
+       int *best_2g_ch, int *best_5g_ch, int *best_6g_ch)
 {
+       struct dhd_pub *dhd = dhd_get_pub(net);
        struct wl_bss_info *bi = NULL;  /* must be initialized */
+       struct wl_chan_info chan_info;
        s32 i, j;
 #if defined(BSSCACHE)
        wl_bss_cache_t *node;
 #endif /* BSSCACHE */
        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)];
+#ifdef WL_6G_BAND
+       int six_g_band5[24]={0}, six_g_band6[5]={0}, six_g_band7[18]={0}, six_g_band8[13]={0};
+       s32 distance_6g;
+#endif /* WL_6G_BAND */
+       s32 cen_ch, distance, distance_2g, distance_5g, chanspec, min_ap=999;
+       u8 valid_chan_list[sizeof(u32)*(MAX_CTRL_CHANSPECS + 1)];
        wl_uint32_list_t *list;
        int ret;
-       chanspec_t chanspec;
-       struct dhd_pub *dhd = dhd_get_pub(net);
+       chanspec_t chspec;
+       u32 channel;
 
        memset(b_band, -1, sizeof(b_band));
        memset(a_band1, -1, sizeof(a_band1));
        memset(a_band4, -1, sizeof(a_band4));
+#ifdef WL_6G_BAND
+       memset(six_g_band5, -1, sizeof(six_g_band5));
+       memset(six_g_band6, -1, sizeof(six_g_band6));
+       memset(six_g_band7, -1, sizeof(six_g_band7));
+       memset(six_g_band8, -1, sizeof(six_g_band8));
+#endif /* WL_6G_BAND */
 
        memset(valid_chan_list, 0, sizeof(valid_chan_list));
        list = (wl_uint32_list_t *)(void *) valid_chan_list;
-       list->count = htod32(WL_NUMCHANNELS);
-       ret = wl_ext_ioctl(net, WLC_GET_VALID_CHANNELS, &valid_chan_list,
-               sizeof(valid_chan_list), 0);
-       if (ret<0) {
+
+       ret = wl_construct_ctl_chanspec_list(net, list);
+       if (ret < 0) {
                AEXT_ERROR(net->name, "get channels failed with %d\n", ret);
                return 0;
        } else {
-               for (i = 0; i < dtoh32(list->count); i++) {
-                       ch = dtoh32(list->element[i]);
-                       if (!dhd_conf_match_channel(dhd, ch))
+               for (i = 0; i < list->count; i++) {
+                       chspec = list->element[i];
+                       channel = wf_chspec_ctlchan(chspec);
+                       chan_info.band = CHSPEC2WLC_BAND(chspec);
+                       chan_info.chan = channel;
+                       if (wl_ext_passive_chan(net, &chan_info)) {
                                continue;
-                       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;
+                       }
+                       if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) &&
+                                       (channel <= CH_MAX_2G_CHANNEL)) {
+                               b_band[channel-1] = 0;
+                       }
+#ifdef WL_6G_BAND
+                       else if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) &&
+                                       (channel <= CH_MAX_6G_CHANNEL)) {
+                               if (channel <= 93)
+                                       six_g_band5[(channel-1)/4] = 0;
+                               else if (channel >= 97 && channel <= 109)
+                                       six_g_band6[(channel-97)/4] = 0;
+                               else if (channel >= 117 && channel <= 181)
+                                       six_g_band7[(channel-117)/4] = 0;
+                               else if (channel >= 189 && channel <= 221)
+                                       six_g_band8[(channel-189)/4] = 0;
+                       }
+#endif /* WL_6G_BAND */
+                       else if (CHSPEC_IS5G(chspec) && channel >= CH_MIN_5G_CHANNEL) {
+                               if (channel <= 48)
+                                       a_band1[(channel-36)/4] = 0;
+                               else if (channel >= 149 && channel <= 161)
+                                       a_band4[(channel-149)/4] = 0;
+                       }
                }
        }
 
        distance_2g = wl_ext_get_distance(net, WLC_BAND_2G);
        distance_5g = wl_ext_get_distance(net, WLC_BAND_5G);
+#ifdef WL_6G_BAND
+       distance_6g = wl_ext_get_distance(net, WLC_BAND_6G);
+#endif /* WL_6G_BAND */
 
 #if defined(BSSCACHE)
        node = bss_cache_ctrl->m_cache_head;
@@ -2995,9 +3139,9 @@ wl_ext_get_best_channel(struct net_device *net,
 #if defined(BSSCACHE)
                bi = node->results.bss_info;
 #else
-               bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info;
+               bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info;
 #endif /* BSSCACHE */
-               chanspec = wl_ext_chspec_driver_to_host(ioctl_ver, bi->chanspec);
+               chanspec = wl_ext_chspec_driver_to_host(dhd, bi->chanspec);
                cen_ch = CHSPEC_CHANNEL(bi->chanspec);
                distance = 0;
                if (CHSPEC_IS20(chanspec))
@@ -3015,14 +3159,45 @@ wl_ext_get_best_channel(struct net_device *net,
                                if (b_band[j] >= 0 && abs(cen_ch-(1+j)) <= distance)
                                        b_band[j] += 1;
                        }
-               } else {
+               }
+#ifdef WL_6G_BAND
+               else if (CHSPEC_IS6G(chanspec)) {
+                       distance += distance_6g;
+                       if (cen_ch <= 93) {
+                               for (j=0; j<ARRAYSIZE(six_g_band5); j++) {
+                                       if (six_g_band5[j] >= 0 && abs(cen_ch-(93+j*4)) <= distance)
+                                               six_g_band5[j] += 1;
+                               }
+                       }
+                       else if (channel >= 97 && channel <= 109) {
+                               for (j=0; j<ARRAYSIZE(six_g_band6); j++) {
+                                       if (six_g_band6[j] >= 0 && abs(cen_ch-(97+j*4)) <= distance)
+                                               six_g_band6[j] += 1;
+                               }
+                       }
+                       else if (channel >= 117 && channel <= 181) {
+                               for (j=0; j<ARRAYSIZE(six_g_band7); j++) {
+                                       if (six_g_band7[j] >= 0 && abs(cen_ch-(117+j*4)) <= distance)
+                                               six_g_band7[j] += 1;
+                               }
+                       }
+                       else if (channel >= 189 && channel <= 221) {
+                               for (j=0; j<ARRAYSIZE(six_g_band8); j++) {
+                                       if (six_g_band8[j] >= 0 && abs(cen_ch-(189+j*4)) <= distance)
+                                               six_g_band8[j] += 1;
+                               }
+                       }
+               }
+#endif /* WL_6G_BAND */
+               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) {
+                       }
+                       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;
@@ -3056,27 +3231,80 @@ wl_ext_get_best_channel(struct net_device *net,
                        *best_5g_ch = i*4 + 149;
                }
        }
+#ifdef WL_6G_BAND
+       *best_6g_ch = 0;
+       min_ap = 999;
+       for (i=0; i<ARRAYSIZE(six_g_band5); i++) {
+               if(six_g_band5[i] < min_ap && six_g_band5[i] >= 0) {
+                       min_ap = six_g_band5[i];
+                       *best_6g_ch = i*4 + 1;
+               }
+       }
+       for (i=0; i<ARRAYSIZE(six_g_band6); i++) {
+               if(six_g_band6[i] < min_ap && six_g_band6[i] >= 0) {
+                       min_ap = six_g_band6[i];
+                       *best_6g_ch = i*4 + 97;
+               }
+       }
+       for (i=0; i<ARRAYSIZE(six_g_band7); i++) {
+               if(six_g_band7[i] < min_ap && six_g_band7[i] >= 0) {
+                       min_ap = six_g_band7[i];
+                       *best_6g_ch = i*4 + 117;
+               }
+       }
+       for (i=0; i<ARRAYSIZE(six_g_band8); i++) {
+               if(six_g_band8[i] < min_ap && six_g_band8[i] >= 0) {
+                       min_ap = six_g_band8[i];
+                       *best_6g_ch = i*4 + 189;
+               }
+       }
+#endif /* WL_6G_BAND */
 
        if (android_msg_level & ANDROID_INFO_LEVEL) {
                struct bcmstrbuf strbuf;
                char *tmp_buf = NULL;
-               tmp_buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
+               tmp_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
                if (tmp_buf == NULL) {
                        AEXT_ERROR(net->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
                        goto exit;
                }
-               bcm_binit(&strbuf, tmp_buf, WLC_IOCTL_SMLEN);
+               bcm_binit(&strbuf, tmp_buf, WLC_IOCTL_MEDLEN);
+               bcm_bprintf(&strbuf, "2g: ");
                for (j=0; j<ARRAYSIZE(b_band); j++)
                        bcm_bprintf(&strbuf, "%d/%d, ", b_band[j], 1+j);
                bcm_bprintf(&strbuf, "\n");
+               bcm_bprintf(&strbuf, "5g band 1: ");
                for (j=0; j<ARRAYSIZE(a_band1); j++)
                        bcm_bprintf(&strbuf, "%d/%d, ", a_band1[j], 36+j*4);
                bcm_bprintf(&strbuf, "\n");
+               bcm_bprintf(&strbuf, "5g band 4: ");
                for (j=0; j<ARRAYSIZE(a_band4); j++)
                        bcm_bprintf(&strbuf, "%d/%d, ", a_band4[j], 149+j*4);
                bcm_bprintf(&strbuf, "\n");
-               bcm_bprintf(&strbuf, "best_2g_ch=%d, best_5g_ch=%d\n",
+#ifdef WL_6G_BAND
+               bcm_bprintf(&strbuf, "6g band 5: ");
+               for (j=0; j<ARRAYSIZE(six_g_band5); j++)
+                       bcm_bprintf(&strbuf, "%d/%d, ", six_g_band5[j], 1+j*4);
+               bcm_bprintf(&strbuf, "\n");
+               bcm_bprintf(&strbuf, "6g band 6: ");
+               for (j=0; j<ARRAYSIZE(six_g_band6); j++)
+                       bcm_bprintf(&strbuf, "%d/%d, ", six_g_band6[j], 97+j*4);
+               bcm_bprintf(&strbuf, "\n");
+               bcm_bprintf(&strbuf, "6g band 7: ");
+               for (j=0; j<ARRAYSIZE(six_g_band7); j++)
+                       bcm_bprintf(&strbuf, "%d/%d, ", six_g_band7[j], 117+j*4);
+               bcm_bprintf(&strbuf, "\n");
+               bcm_bprintf(&strbuf, "6g band 8: ");
+               for (j=0; j<ARRAYSIZE(six_g_band8); j++)
+                       bcm_bprintf(&strbuf, "%d/%d, ", six_g_band8[j], 189+j*4);
+               bcm_bprintf(&strbuf, "\n");
+#endif /* WL_6G_BAND */
+               bcm_bprintf(&strbuf, "best_2g_ch=%d, best_5g_ch=%d",
                        *best_2g_ch, *best_5g_ch);
+#ifdef WL_6G_BAND
+               bcm_bprintf(&strbuf, ", best_6g_ch=%d", *best_6g_ch);
+#endif /* WL_6G_BAND */
+               bcm_bprintf(&strbuf, "\n");
                AEXT_INFO(net->name, "\n%s", strbuf.origbuf);
                if (tmp_buf) {
                        kfree(tmp_buf);
@@ -3096,6 +3324,7 @@ wl_ext_fw_apcs(struct net_device *dev, uint32 band)
        int channel = 0, chosen = 0, retry = 0, ret = 0, spect = 0;
        u8 *reqbuf = NULL;
        uint32 buf_size;
+       chanspec_band_t acs_band = WLC_BAND_INVALID;
 
        ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
        if (ret) {
@@ -3118,35 +3347,20 @@ wl_ext_fw_apcs(struct net_device *dev, uint32 band)
        }
        memset(reqbuf, 0, CHANSPEC_BUF_SIZE);
 
-       if (band == WLC_BAND_AUTO) {
-               AEXT_INFO(dev->name, "ACS full channel scan \n");
-               reqbuf[0] = htod32(0);
-       } else if (band == WLC_BAND_5G) {
-               AEXT_INFO(dev->name, "ACS 5G band scan \n");
-               ret = wl_android_get_band_chanspecs(dev, (void *)reqbuf, CHANSPEC_BUF_SIZE,
-                       WL_CHANSPEC_BAND_5G, false);
-               if (ret < 0) {
-                       AEXT_ERROR(dev->name, "ACS 5g chanspec retreival failed! \n");
-                       goto done;
-               }
-       } else if (band == WLC_BAND_2G) {
-               /*
-                * If channel argument is not provided/ argument 20 is provided,
-                * Restrict channel to 2GHz, 20MHz BW, No SB
-                */
-               AEXT_INFO(dev->name, "ACS 2G band scan \n");
-               ret = wl_android_get_band_chanspecs(dev, (void *)reqbuf, CHANSPEC_BUF_SIZE,
-                       WL_CHANSPEC_BAND_2G, false);
-               if (ret < 0) {
-                       AEXT_ERROR(dev->name, "ACS 2g chanspec retreival failed! \n");
-                       goto done;
-               }
-       } else {
-               AEXT_ERROR(dev->name, "ACS: No band chosen\n");
+       acs_band = wl_ext_wlcband_to_chanspec_band(band);
+       if (acs_band == INVCHANSPEC) {
+               acs_band = WL_CHANSPEC_BAND_2G;
+       }
+
+       if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE,
+                       acs_band, true)) < 0) {
+               WL_ERR(("ACS chanspec retrieval failed!\n"));
                goto done;
        }
 
-       buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE;
+       AEXT_INFO(dev->name, "ACS chanspec band 0x%x\n", acs_band);
+
+       buf_size = CHANSPEC_BUF_SIZE;
        ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
                buf_size);
        if (ret < 0) {
@@ -3156,7 +3370,7 @@ wl_ext_fw_apcs(struct net_device *dev, uint32 band)
        }
 
        /* Wait for auto channel selection, max 3000 ms */
-       if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G)) {
+       if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G) || (band == WLC_BAND_6G)) {
                OSL_SLEEP(500);
        } else {
                /*
@@ -3176,24 +3390,12 @@ wl_ext_fw_apcs(struct net_device *dev, uint32 band)
                        chosen = dtoh32(chosen);
                }
 
-               if (chosen) {
-                       int chosen_band;
-                       int apcs_band;
-#ifdef D11AC_IOTYPES
-                       if (wl_cfg80211_get_ioctl_version() == 1) {
-                               channel = LCHSPEC_CHANNEL((chanspec_t)chosen);
-                       } else {
-                               channel = CHSPEC_CHANNEL((chanspec_t)chosen);
-                       }
-#else
-                       channel = CHSPEC_CHANNEL((chanspec_t)chosen);
-#endif /* D11AC_IOTYPES */
-                       apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band;
-                       chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G;
-                       if (apcs_band == chosen_band) {
-                               WL_MSG(dev->name, "selected channel = %d\n", channel);
-                               break;
-                       }
+               if (wf_chspec_valid((chanspec_t)chosen)) {
+                       channel = wf_chspec_ctlchan((chanspec_t)chosen);
+                       acs_band = CHSPEC_BAND((chanspec_t)chosen);
+                       WL_MSG(dev->name, "selected channel = %d(band %d)\n",
+                               channel, CHSPEC2WLC_BAND((chanspec_t)chosen));
+                       break;
                }
                AEXT_INFO(dev->name, "%d tried, ret = %d, chosen = 0x%x\n",
                        (APCS_MAX_RETRY - retry), ret, chosen);
@@ -3230,18 +3432,35 @@ wl_ext_drv_scan(struct net_device *dev, uint32 band, bool fast_scan)
        }
        memset(&scan_info, 0, sizeof(wl_scan_info_t));
        if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) {
-               for (i=0; i<13; i++)
-                       scan_info.channels.channel[i] = i + 1;
+               for (i=0; i<13; i++) {
+                       scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(i+1,
+                               WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G);
+               }
                cnt += 13;
        }
        if (band == WLC_BAND_5G || band == WLC_BAND_AUTO) {
-               for (i=0; i<4; i++)
-                       scan_info.channels.channel[i+cnt] = 36 + i*4;
+               for (i=0; i<4; i++) {
+                       scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(36+i*4,
+                               WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G);
+               }
                cnt += 4;
-               for (i=0; i<4; i++)
-                       scan_info.channels.channel[i+cnt] = 149 + i*4;
+               for (i=0; i<4; i++) {
+                       scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(149+i*4,
+                               WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G);
+               }
                cnt += 4;
        }
+#ifdef WL_6G_BAND
+       if (band == WLC_BAND_6G || band == WLC_BAND_AUTO) {
+               for (i=0; i<59; i++) {
+                       scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(1+i*4,
+                               WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_6G);
+               }
+               cnt += 59;
+       }
+#endif /* WL_6G_BAND */
+       if (band == WLC_BAND_2G)
+               fast_scan = FALSE;
        scan_info.channels.count = cnt;
        if (fast_scan)
                scan_info.scan_time = 40;
@@ -3281,6 +3500,10 @@ wl_ext_drv_apcs(struct net_device *dev, uint32 band)
                if (escan->escan_state == ESCAN_STATE_IDLE) {
                        if (band == WLC_BAND_5G)
                                channel = escan->best_5g_ch;
+#ifdef WL_6G_BAND
+                       else if (band == WLC_BAND_6G)
+                               channel = escan->best_6g_ch;
+#endif /* WL_6G_BAND */
                        else
                                channel = escan->best_2g_ch;
                        WL_MSG(dev->name, "selected channel = %d\n", channel);
@@ -3531,10 +3754,10 @@ exit:
 
 void
 wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
-       wl_scan_results_t *ss_list)
+       wl_scan_results_v109_t *ss_list)
 {
        wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
-       wl_bss_info_t *bi = NULL;
+       wl_bss_info_v109_t *bi = NULL;
        int i, j, k;
        struct osl_timespec now, timeout;
 
@@ -3560,7 +3783,7 @@ wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
                node = *rssi_head;
                prev = NULL;
                k = 0;
-               bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
+               bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
                for (;node;) {
                        if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
                                AEXT_INFO("wlan", "Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
@@ -3886,11 +4109,11 @@ wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
 #if defined(RSSIAVG)
        wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
 #endif /* RSSIAVG */
-       wl_scan_results_t *ss_list)
+       wl_scan_results_v109_t *ss_list)
 {
        wl_bss_cache_t *node, *node_target = NULL, *prev, *leaf, **bss_head;
        wl_bss_cache_t *node_rssi_prev = NULL, *node_rssi = NULL;
-       wl_bss_info_t *bi = NULL;
+       wl_bss_info_v109_t *bi = NULL;
        int i, k=0, bss_num = 0;
        struct osl_timespec now, timeout;
        int16 rssi_min;
@@ -3925,7 +4148,7 @@ wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
                prev = NULL;
                node_target = NULL;
                node_rssi_prev = NULL;
-               bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
+               bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
 
                // find the bss with same BSSID
                for (;node;) {
index 1ebc33acacbd0f4a395f1d7409cf9c076ef4fab8..12590d2082cbbea781749617fd6fb80d57b6d815 100755 (executable)
@@ -1,6 +1,12 @@
 
 #ifndef _wl_android_ext_
 #define _wl_android_ext_
+
+typedef struct wl_chan_info {
+       uint band;
+       uint16 chan;
+} wl_chan_info_t;
+
 typedef struct bcol_gtk_para {
        int enable;
        int ptk_len;
@@ -10,6 +16,7 @@ typedef struct bcol_gtk_para {
 #define ACS_FW_BIT             (1<<0)
 #define ACS_DRV_BIT            (1<<1)
 int wl_ext_autochannel(struct net_device *dev, uint acs, uint32 band);
+chanspec_band_t wl_ext_wlcband_to_chanspec_band(int band);
 int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len,
        int *bytes_written);
 void wl_ext_get_sec(struct net_device *dev, int ifmode, char *sec, int total_len, bool dump);
@@ -19,6 +26,7 @@ int wl_ext_set_scan_time(struct net_device *dev, int scan_time,
 void wl_ext_wait_event_complete(struct dhd_pub *dhd, int ifidx);
 int wl_ext_add_del_ie(struct net_device *dev, uint pktflag, char *ie_data, const char* add_del_cmd);
 #ifdef WL_ESCAN
+int wl_construct_ctl_chanspec_list(struct net_device *dev, wl_uint32_list_t *chan_list);
 int wl_ext_drv_scan(struct net_device *dev, uint band, bool fast_scan);
 #endif
 #ifdef WL_EXT_GENL
@@ -39,23 +47,19 @@ int wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name,
 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);
-chanspec_t wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec);
-chanspec_t wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec);
-bool wl_ext_dfs_chan(uint16 chan);
+chanspec_t wl_ext_chspec_driver_to_host(struct dhd_pub *dhd, chanspec_t chanspec);
+chanspec_t wl_ext_chspec_host_to_driver(struct dhd_pub *dhd, chanspec_t chanspec);
+bool wl_ext_dfs_chan(struct wl_chan_info *chan_info);
+bool wl_ext_passive_chan(struct net_device *dev, struct wl_chan_info *chan_info);
 uint16 wl_ext_get_default_chan(struct net_device *dev,
        uint16 *chan_2g, uint16 *chan_5g, bool nodfs);
-int wl_ext_set_chanspec(struct net_device *dev, int ioctl_ver,
-       uint16 channel, chanspec_t *ret_chspec);
+int wl_ext_set_chanspec(struct net_device *dev, struct wl_chan_info *chan_info,
+       chanspec_t *ret_chspec);
 int wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver);
 #endif
 #if defined(WL_CFG80211) || defined(WL_ESCAN)
 void wl_ext_user_sync(struct dhd_pub *dhd, int ifidx, bool lock);
 #endif
-#if defined(WL_CFG80211)
-bool wl_legacy_chip_check(struct net_device *net);
-bool wl_new_chip_check(struct net_device *net);
-bool wl_extsae_chip(struct dhd_pub *dhd);
-#endif
 #if defined(WL_EXT_IAPSTA) || defined(WL_CFG80211)
 void wl_ext_bss_iovar_war(struct net_device *dev, s32 *val);
 #endif /* WL_EXT_IAPSTA ||WL_CFG80211 */
@@ -117,7 +121,7 @@ void wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl);
 void 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);
 void wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl);
-void wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list);
+void wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_v109_t *ss_list);
 int wl_update_connected_rssi_cache(struct net_device *net, wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg);
 int16 wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr);
 #endif
@@ -145,7 +149,7 @@ typedef struct wl_bss_cache {
        struct wl_bss_cache *next;
        int dirty;
        struct osl_timespec tv;
-       wl_scan_results_t results;
+       wl_scan_results_v109_t results;
 } wl_bss_cache_t;
 
 typedef struct wl_bss_cache_ctrl {
@@ -161,15 +165,27 @@ void wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
 #if defined(RSSIAVG)
        wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
 #endif
-       wl_scan_results_t *ss_list);
+       wl_scan_results_v109_t *ss_list);
 void wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl);
 #endif
 int wl_ext_get_best_channel(struct net_device *net,
 #if defined(BSSCACHE)
        wl_bss_cache_ctrl_t *bss_cache_ctrl,
 #else
-       wl_scan_results_t *bss_list,
+       wl_scan_results_v109_t *bss_list,
 #endif
-       int ioctl_ver, int *best_2g_ch, int *best_5g_ch
+       int *best_2g_ch, int *best_5g_ch, int *best_6g_ch
 );
+
+#ifdef WL_6G_BAND
+#define CHSPEC2BANDSTR(chspec) ((chspec && CHSPEC_IS2G(chspec)) ? "2g" : CHSPEC_IS5G(chspec) ? \
+       "5g" : CHSPEC_IS6G(chspec) ? "6g" : "0g")
+#define WLCBAND2STR(band) ((band == WLC_BAND_2G) ? "2g" : (band == WLC_BAND_5G) ? \
+       "5g" : (band == WLC_BAND_6G) ? "6g" : "0g")
+#else
+#define CHSPEC2BANDSTR(chspec) ((chspec && CHSPEC_IS2G(chspec)) ? "2g" : CHSPEC_IS5G(chspec) ? \
+       "5g" : "0g")
+#define WLCBAND2STR(band) ((band == WLC_BAND_2G) ? "2g" : (band == WLC_BAND_5G) ? \
+       "5g" : "0g")
+#endif /* WL_6G_BAND */
 #endif
index ec9e91ca3383ae103ff6c6d7dc9a1b2ab668780d..21d2bf523066df2764c5270d1231d7a442fc6f95 100755 (executable)
@@ -160,7 +160,7 @@ wl_bad_ap_mngr_fparse(struct bcm_cfg80211 *cfg, struct file *fp)
                return BCME_NOMEM;
        }
 
-       ret = vfs_read(fp, buf, WL_BAD_AP_MAX_BUF_SIZE, &fp->f_pos);
+       ret = dhd_vfs_read(fp, buf, WL_BAD_AP_MAX_BUF_SIZE, &fp->f_pos);
        if (ret  < 0) {
                WL_ERR(("%s: file read failed (%d)\n", __FUNCTION__, ret));
                goto fail;
@@ -236,8 +236,8 @@ wl_bad_ap_mngr_fread(struct bcm_cfg80211 *cfg, const char *fname)
        fs = get_fs();
        set_fs(KERNEL_DS);
 
-       fp = filp_open(fname, O_RDONLY, 0);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(fname, O_RDONLY, 0);
+       if (IS_ERR(fp) || (fp == NULL)) {
                fp = NULL;
                WL_ERR(("%s: file open failed(%d)\n", __FUNCTION__, ret));
                goto fail;
@@ -248,7 +248,7 @@ wl_bad_ap_mngr_fread(struct bcm_cfg80211 *cfg, const char *fname)
        }
 fail:
        if (fp) {
-               filp_close(fp, NULL);
+               dhd_filp_close(fp, NULL);
        }
        set_fs(fs);
 
@@ -283,8 +283,8 @@ wl_bad_ap_mngr_fwrite(struct bcm_cfg80211 *cfg, const char *fname)
        fs = get_fs();
        set_fs(KERNEL_DS);
 
-       fp = filp_open(fname, O_CREAT | O_RDWR | O_TRUNC,  0666);
-       if (IS_ERR(fp)) {
+       fp = dhd_filp_open(fname, O_CREAT | O_RDWR | O_TRUNC,  0666);
+       if (IS_ERR(fp) || (fp == NULL)) {
                ret = PTR_ERR(fp);
                WL_ERR(("%s: file open failed(%d)\n", __FUNCTION__, ret));
                fp = NULL;
@@ -310,13 +310,13 @@ wl_bad_ap_mngr_fwrite(struct bcm_cfg80211 *cfg, const char *fname)
 #pragma GCC diagnostic pop
 #endif
 
-       ret = vfs_write(fp, tmp, len, &fp->f_pos);
+       ret = dhd_vfs_write(fp, tmp, len, &fp->f_pos);
        if (ret < 0) {
                WL_ERR(("%s: file write failed(%d)\n", __FUNCTION__, ret));
                goto fail;
        }
        /* Sync file from filesystem to physical media */
-       ret = vfs_fsync(fp, 0);
+       ret = dhd_vfs_fsync(fp, 0);
        if (ret < 0) {
                WL_ERR(("%s: sync file failed(%d)\n", __FUNCTION__, ret));
                goto fail;
@@ -324,7 +324,7 @@ wl_bad_ap_mngr_fwrite(struct bcm_cfg80211 *cfg, const char *fname)
        ret = BCME_OK;
 fail:
        if (fp) {
-               filp_close(fp, NULL);
+               dhd_filp_close(fp, NULL);
        }
        set_fs(fs);
        mutex_unlock(&cfg->bad_ap_mngr.fs_lock);
index d64605328dab8cc8f158ea1c4ad7aa34f3b916df..d8c92db3248f3cdc36d546cf6901cbc8943bd2c9 100755 (executable)
@@ -475,18 +475,34 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
 #endif /* WL_CFG80211_P2P_DEV_IF */
 static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
        struct net_device *dev,
+#if defined(CFG80211_BKPORT_MLO)
+       int link_id,
+#endif
        u8 key_idx, bool unicast, bool multicast);
 static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+#if defined(CFG80211_BKPORT_MLO)
+       int link_id,
+#endif
        u8 key_idx, bool pairwise, const u8 *mac_addr,
        struct key_params *params);
 static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+#if defined(CFG80211_BKPORT_MLO)
+       int link_id,
+#endif
        u8 key_idx, bool pairwise, const u8 *mac_addr);
 static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+#if defined(CFG80211_BKPORT_MLO)
+       int link_id,
+#endif
        u8 key_idx, bool pairwise, const u8 *mac_addr,
        void *cookie, void (*callback) (void *cookie,
        struct key_params *params));
 static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
-       struct net_device *dev, u8 key_idx);
+       struct net_device *dev,
+#if defined(CFG80211_BKPORT_MLO)
+       int link_id,
+#endif
+       u8 key_idx);
 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
 static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
        bcm_struct_cfgdev *cfgdev, u64 cookie);
@@ -579,10 +595,8 @@ static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
        bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
 static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        const wl_event_msg_t *e, void *data, bool completed);
-#ifdef DHD_LOSSLESS_ROAMING
 static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        const wl_event_msg_t *e, void *data);
-#endif /* DHD_LOSSLESS_ROAMING */
 static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
        const wl_event_msg_t *e, void *data);
 #ifdef BT_WIFI_HANDOVER
@@ -2291,7 +2305,7 @@ _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg)
 
        WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__, filename));
 
-       fp = filp_open(filename, O_RDONLY, 0);
+       fp = dhd_filp_open(filename, O_RDONLY, 0);
 
        if (IS_ERR(fp) || (fp == NULL)) {
                WL_ERR(("%s: Couldn't read the file, err %ld,File [%s]  No previous axi error \n",
@@ -2299,8 +2313,8 @@ _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg)
                return ret;
        }
 
-       kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t));
-       filp_close(fp, NULL);
+       dhd_kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t));
+       dhd_filp_close(fp, NULL);
 
        /* Delete axi error info file */
        if (dhd_file_delete(filename) < 0) {
@@ -3182,7 +3196,7 @@ wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
 
        if (addr) {
                ifflags |= WL_INTERFACE_MAC_USE;
-               if (wl_legacy_chip_check(ndev)) {
+               if (dhd_conf_legacy_chip_check(cfg->pub)) {
                        iface.flags = ifflags;
                        memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
                }
@@ -3195,7 +3209,7 @@ wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
 #endif /* WLEASYMESH */
 
        /* Pass ver = 0 for fetching the interface_create iovar version */
-       if (wl_legacy_chip_check(ndev)) {
+       if (dhd_conf_legacy_chip_check(cfg->pub)) {
                bzero(&iface_v0, sizeof(iface_v0));
                iface_v0.ver = WL_INTERFACE_CREATE_VER_0;
                iface_v0.flags = iftype | ifflags;
@@ -3719,15 +3733,19 @@ wl_cfg80211_post_ifcreate(struct net_device *ndev,
 #ifdef WLDWDS
                /* set wds0.x to 4addr interface here */
                if (event->role == WLC_E_IF_ROLE_WDS) {
-                       WL_MSG(ndev->name, "set vwdev 4addr to %s\n", event->name);
+                       struct dhd_if *ifp = dhd_get_ifp(cfg->pub, event->ifidx);
+                       ifp->dwds = TRUE;
+                       WL_MSG(event->name, "set to 4addr\n");
                        wdev->use_4addr = true;
                }
 #endif /* WLDWDS */
                SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
 
-               memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
+               dev_addr_set(new_ndev, addr);
 #ifdef WL_EXT_IAPSTA
-               wl_ext_iapsta_ifadding(new_ndev, event->ifidx);
+               if (event->role != WLC_E_IF_ROLE_WDS) {
+                       wl_ext_iapsta_ifadding(new_ndev, event->ifidx);
+               }
 #endif /* WL_EXT_IAPSTA */
                if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd)
                        != BCME_OK) {
@@ -4206,20 +4224,12 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
        chan = params->channel;
 #endif /* WL_CFG80211_P2P_DEV_IF */
        if (chan) {
-               u16 center_freq = chan->center_freq;
 #ifdef WL_EXT_IAPSTA
-               enum nl80211_band band;
-               s32 _chan;
-               _chan = ieee80211_frequency_to_channel(center_freq);
+               chanspec = wl_freq_to_chanspec(chan->center_freq);
                wl_ext_iapsta_update_iftype(dev, WL_IF_TYPE_IBSS);
-               _chan = wl_ext_iapsta_update_channel(dev, _chan);
-               if (CHANNEL_IS_5G(_chan))
-                       band = NL80211_BAND_5GHZ;
-               else
-                       band = NL80211_BAND_2GHZ;
-               center_freq = ieee80211_channel_to_frequency(_chan, band);
+               chanspec = wl_ext_iapsta_update_channel(dev, chanspec);
 #endif /* WL_EXT_IAPSTA */
-               cfg->channel = wl_freq_to_chanspec(center_freq);
+               cfg->channel = chanspec;
        }
        if (wl_get_drv_status(cfg, CONNECTED, dev)) {
                struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
@@ -6216,14 +6226,16 @@ wl_conn_debug_info(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc
                if (!err)
                        cur_rssi = dtoh32(scb_val.val);
                WL_MSG(dev->name, "Reconnecting with " MACDBG " ssid \"%s\", len (%d), "
-                       "channel=%d(chan_cnt=%d), sec=%s, rssi=%d => %d\n",
+                       "channel=%s-%d(chan_cnt=%d), sec=%s, rssi=%d => %d\n",
                        MAC2STRDBG((u8*)(&info->bssid)), info->ssid, info->ssid_len,
-                       wf_chspec_ctlchan(chanspec), chan_cnt, sec_info, cur_rssi, target_rssi);
+                       CHSPEC2BANDSTR(chanspec), wf_chspec_ctlchan(chanspec), chan_cnt,
+                       sec_info, cur_rssi, target_rssi);
        } else {
                WL_MSG(dev->name, "Connecting with " MACDBG " ssid \"%s\", len (%d), "
-                       "channel=%d(chan_cnt=%d), sec=%s, rssi=%d\n",
+                       "channel=%s-%d(chan_cnt=%d), sec=%s, rssi=%d\n",
                        MAC2STRDBG((u8*)(&info->bssid)), info->ssid, info->ssid_len,
-                       wf_chspec_ctlchan(chanspec), chan_cnt, sec_info, target_rssi);
+                       CHSPEC2BANDSTR(chanspec), wf_chspec_ctlchan(chanspec), chan_cnt,
+                       sec_info, target_rssi);
        }
        if (wl_dbg_level & WL_DBG_DBG) {
                WL_MSG(dev->name, "akm:0x%x auth:0x%x wpaver:0x%x pwise:0x%x gwise:0x%x\n",
@@ -6276,7 +6288,7 @@ wl_handle_join(struct bcm_cfg80211 *cfg,
        }
 
 #ifdef WL_EXT_IAPSTA
-       wl_ext_iapsta_update_channel(dev, wf_chspec_ctlchan(assoc_info->chanspecs[0]));
+       wl_ext_iapsta_update_channel(dev, assoc_info->chanspecs[0]);
 #endif
        /* print relevant info for debug purpose */
        wl_conn_debug_info(cfg, dev, assoc_info);
@@ -6329,7 +6341,7 @@ wl_handle_reassoc(struct bcm_cfg80211 *cfg, struct net_device *dev,
        reassoc_params->chanspec_num = htod32(chan_cnt);
 
 #ifdef WL_EXT_IAPSTA
-       wl_ext_iapsta_update_channel(dev, wf_chspec_ctlchan(chanspec));
+       wl_ext_iapsta_update_channel(dev, chanspec);
 #endif
        /* print relevant info for debug purpose */
        wl_conn_debug_info(cfg, dev, info);
@@ -6385,6 +6397,9 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 
        if (assoc_info.reassoc) {
                /* Handle roam to same ESS */
+#ifdef DHD_LOSSLESS_ROAMING
+               wl_ext_send_event_msg(dev, WLC_E_ROAM_PREP, WLC_E_STATUS_SUCCESS, WLC_E_REASON_LOW_RSSI);
+#endif
                if ((err = wl_handle_reassoc(cfg, dev, &assoc_info)) != BCME_OK) {
                        goto fail;
                }
@@ -6539,7 +6554,16 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
                        WL_TRACE_HW4(("Aborting the scan! \n"));
                        wl_cfgscan_cancel_scan(cfg);
                }
-               if (conn_in_progress || connected || wdev->ssid_len) {
+               if (conn_in_progress || connected ||
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+                               wdev->u.client.ssid_len
+#else
+                               wdev->ssid_len
+#endif
+               ) {
+#ifdef WL_EXT_IAPSTA
+                               wl_ext_in4way_sync(dev, 0, WL_EXT_STATUS_PRE_DISCONNECTING, NULL);
+#endif
                                scbval.val = reason_code;
                                memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
                                scbval.val = htod32(scbval.val);
@@ -6584,7 +6608,13 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
                 * and issue disconnect indication if required.
                 */
 
-               if (wdev->current_bss || wdev->ssid_len) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+               // terence 20220911: fix me
+               if (wdev->links[0].client.current_bss || wdev->u.client.ssid_len)
+#else
+               if (wdev->current_bss || wdev->ssid_len)
+#endif
+               {
                        WL_INFORM_MEM(("report disconnect event\n"));
                        CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
                }
@@ -6689,6 +6719,9 @@ wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
 
 static s32
 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
+#if defined(CFG80211_BKPORT_MLO)
+       int link_id,
+#endif
        u8 key_idx, bool unicast, bool multicast)
 {
        struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
@@ -6733,7 +6766,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
        s32 bssidx;
        s32 mode = wl_get_mode_by_netdev(cfg, dev);
 
-       WL_MSG(dev->name, "key index (%d)\n", key_idx);
+       WL_MSG(dev->name, "key index (%d) for %pM\n", key_idx, mac_addr);
        if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
                return BCME_ERROR;
@@ -6900,6 +6933,9 @@ wl_cfg80211_block_arp(struct net_device *dev, int enable)
 
 static s32
 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+#if defined(CFG80211_BKPORT_MLO)
+       int link_id,
+#endif
        u8 key_idx, bool pairwise, const u8 *mac_addr,
        struct key_params *params)
 {
@@ -7099,6 +7135,9 @@ exit:
 
 static s32
 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+#if defined(CFG80211_BKPORT_MLO)
+       int link_id,
+#endif
        u8 key_idx, bool pairwise, const u8 *mac_addr)
 {
        struct wl_wsec_key key;
@@ -7162,6 +7201,9 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 /* NOTE : this function cannot work as is and is never called */
 static s32
 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+#if defined(CFG80211_BKPORT_MLO)
+       int link_id,
+#endif
        u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
        void (*callback) (void *cookie, struct key_params * params))
 {
@@ -7236,7 +7278,11 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 
 static s32
 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
-       struct net_device *dev, u8 key_idx)
+       struct net_device *dev,
+#if defined(CFG80211_BKPORT_MLO)
+       int link_id,
+#endif
+       u8 key_idx)
 {
 #ifdef MFP
        /* Firmware seems to use hard coded index for Group Mgmt Key.
@@ -10220,6 +10266,34 @@ exit:
 }
 #endif /* WL_SUPPORT_ACS */
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+static int
+wl_cfg80211_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+       unsigned int link_id,
+#endif
+       struct cfg80211_chan_def *chandef)
+{
+       struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+       u32 chanspec = 0;
+       int ret = 0;
+
+       RETURN_EIO_IF_NOT_UP(cfg);
+       if (NULL == wdev->netdev) {
+               /* the P2P interface may temporary use wdev without ndev */
+               return -EINVAL;
+       }
+
+       if ((ret = wldev_iovar_getint(wdev->netdev, "chanspec", (s32 *)&chanspec) != BCME_OK)) {
+               return ret;
+       }
+       if (!chandef || (wl_chspec_chandef(chanspec, chandef, wiphy) != BCME_OK)) {
+               return BCME_ERROR;
+       }
+       return 0;
+}
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0) */
+
 static struct cfg80211_ops wl_cfg80211_ops = {
        .add_virtual_intf = wl_cfg80211_add_virtual_iface,
        .del_virtual_intf = wl_cfg80211_del_virtual_iface,
@@ -10317,6 +10391,9 @@ static struct cfg80211_ops wl_cfg80211_ops = {
        .update_ft_ies = wl_cfg80211_update_ft_ies,
 #endif /* WLFBT */
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0)
+       .get_channel = wl_cfg80211_get_channel,
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0) */
 };
 
 s32 wl_mode_to_nl80211_iftype(s32 mode)
@@ -10341,6 +10418,35 @@ s32 wl_mode_to_nl80211_iftype(s32 mode)
        return err;
 }
 
+static bool
+wl_is_ccode_change_allowed(struct net_device *net)
+{
+       struct wireless_dev *wdev = ndev_to_wdev(net);
+       struct wiphy *wiphy = wdev->wiphy;
+       struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+       struct net_info *iter, *next;
+
+       /* Country code isn't allowed change on AP/GO, NDP established  */
+       GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
+       for_each_ndev(cfg, iter, next) {
+               GCC_DIAGNOSTIC_POP();
+               if (iter->ndev) {
+                       if (wl_get_drv_status(cfg, AP_CREATED, iter->ndev)) {
+                               WL_ERR(("AP active. skip coutry ccode change\n"));
+                               return false;
+                       }
+               }
+       }
+
+#ifdef WL_NAN
+       if (wl_cfgnan_is_enabled(cfg) && wl_cfgnan_is_dp_active(net)) {
+               WL_ERR(("NDP established. skip coutry ccode change\n"));
+               return false;
+       }
+#endif /* WL_NAN */
+       return true;
+}
+
 static bool
 wl_is_ccode_change_required(struct net_device *net,
        char *country_code, int revinfo)
@@ -10419,6 +10525,73 @@ wl_cfg80211_cleanup_connection(struct net_device *net, bool user_enforced)
 #endif /* WL_NAN */
 }
 
+static int wl_copy_regd(const struct ieee80211_regdomain *regd_orig,
+       struct ieee80211_regdomain *regd_copy)
+{
+       int i;
+
+       if (memcpy_s(regd_copy, sizeof(*regd_copy), regd_orig, sizeof(*regd_orig))) {
+               return BCME_ERROR;
+       }
+       for (i = 0; i < regd_orig->n_reg_rules; i++) {
+               if (memcpy_s(&regd_copy->reg_rules[i], sizeof(regd_copy->reg_rules[i]),
+                       &regd_orig->reg_rules[i], sizeof(regd_orig->reg_rules[i]))) {
+                       return BCME_ERROR;
+               }
+       }
+       return BCME_OK;
+}
+
+static void wl_notify_regd(struct wiphy *wiphy, char *country_code)
+{
+       struct ieee80211_regdomain *regd_copy = NULL;
+       int regd_len;
+       struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+       regd_len = sizeof(brcm_regdom) + (brcm_regdom.n_reg_rules *
+                       sizeof(struct ieee80211_reg_rule));
+
+       regd_copy = (struct ieee80211_regdomain *)MALLOCZ(cfg->osh, regd_len);
+       if (!regd_copy) {
+               WL_ERR(("failed to alloc regd_copy\n"));
+               return;
+       }
+
+       /* the upper layer function below requires non-const type */
+       if (wl_copy_regd(&brcm_regdom, regd_copy)) {
+               WL_ERR(("failed to copy new regd\n"));
+               goto exit;
+       }
+
+       if (country_code) {
+               if (memcpy_s(regd_copy->alpha2, sizeof(regd_copy->alpha2),
+                       country_code, WL_CCODE_LEN)) {
+                       WL_ERR(("failed to copy new ccode:%s\n", country_code));
+                       goto exit;
+               }
+       }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+       if (rtnl_is_locked()) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
+               wiphy_lock(wiphy);
+               regulatory_set_wiphy_regd_sync(wiphy, regd_copy);
+               wiphy_unlock(wiphy);
+#else
+               regulatory_set_wiphy_regd_sync_rtnl(wiphy, regd_copy);
+#endif /* LINUX_VERSION > 5.12.0 */
+       } else {
+               regulatory_set_wiphy_regd(wiphy, regd_copy);
+       }
+#else
+       wiphy_apply_custom_regulatory(wiphy, regd_copy);
+#endif /* LINUX_VERSION > 4.0.0 */
+
+exit:
+       MFREE(cfg->osh, regd_copy, regd_len);
+       return;
+}
+
 s32
 wl_cfg80211_set_country_code(struct net_device *net, char *country_code,
        bool notify, bool user_enforced, int revinfo)
@@ -10440,12 +10613,25 @@ wl_cfg80211_set_country_code(struct net_device *net, char *country_code,
                goto exit;
        }
 
+       if (wl_is_ccode_change_allowed(net) == false) {
+               WL_ERR(("country code change isn't allowed during AP role/NAN connected\n"));
+               ret = BCME_EPERM;
+               goto exit;
+       }
+
        wl_cfg80211_cleanup_connection(net, user_enforced);
 
+       /* Store before applying - so that if event comes earlier that is handled properly */
+       if (strlcpy(cfg->country, country_code, WL_CCODE_LEN) >= WLC_CNTRY_BUF_SZ) {
+               WL_ERR(("country code copy failed :%d\n", ret));
+               goto exit;
+       }
+
        ret = wldev_set_country(net, country_code,
                notify, revinfo);
        if (ret < 0) {
                WL_ERR(("set country Failed :%d\n", ret));
+               bzero(cfg->country, sizeof(cfg->country));
                goto exit;
        }
 
@@ -10455,10 +10641,12 @@ wl_cfg80211_set_country_code(struct net_device *net, char *country_code,
         */
        if (!IS_REGDOM_SELF_MANAGED(wiphy)) {
                regulatory_hint(wiphy, country_code);
+       } else {
+               wl_notify_regd(wiphy, country_code);
        }
 
 exit:
-       return ret;
+       return OSL_ERROR(ret);
 }
 
 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
@@ -10546,12 +10734,10 @@ static
 void wl_config_custom_regulatory(struct wiphy *wiphy)
 {
 
-#if defined(WL_SELF_MANAGED_REGDOM) && \
-       (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+#if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
        /* Use self managed regulatory domain */
        wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED |
                        REGULATORY_IGNORE_STALE_KICKOFF;
-       wiphy->regd = &brcm_regdom;
        WL_DBG(("Self managed regdom\n"));
        return;
 #else /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
@@ -10565,7 +10751,7 @@ void wl_config_custom_regulatory(struct wiphy *wiphy)
 #else /* KERNEL VER >= 3.14 */
        wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
-       wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
+       wl_notify_regd(wiphy, NULL);
        WL_DBG(("apply custom regulatory\n"));
 #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
 }
@@ -10778,13 +10964,6 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
        wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS;
 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */
 
-       /* Now we can register wiphy with cfg80211 module */
-       err = wiphy_register(wdev->wiphy);
-       if (unlikely(err < 0)) {
-               WL_ERR(("Couldn not register wiphy device (%d)\n", err));
-               wiphy_free(wdev->wiphy);
-       }
-
 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
        (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
        /* Workaround for a cfg80211 bug */
@@ -10798,7 +10977,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) */
 
 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
-       if (wl_extsae_chip(dhd))
+       if (dhd_conf_extsae_chip(dhd))
                wdev->wiphy->features |= NL80211_FEATURE_SAE;
 #endif /* WL_SAE || WL_CLIENT_SAE */
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE)
@@ -10816,6 +10995,23 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
        wdev->wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN;
 #endif /* WL_SCAN_TYPE */
 
+       /* Now we can register wiphy with cfg80211 module */
+       err = wiphy_register(wdev->wiphy);
+       if (unlikely(err < 0)) {
+               WL_ERR(("Couldn not register wiphy device (%d)\n", err));
+               wiphy_free(wdev->wiphy);
+               return err;
+       }
+
+       /* set wiphy->regd through reg_process_self_managed_hints
+        * need to call it after wiphy_register
+        * since wiphy_register adds rdev to cfg80211_rdev_list
+        */
+       if (IS_REGDOM_SELF_MANAGED(wdev->wiphy)) {
+               rtnl_lock();
+               wl_notify_regd(wdev->wiphy, NULL);
+               rtnl_unlock();
+       }
        return err;
 }
 
@@ -10840,8 +11036,7 @@ static void wl_free_wdev(struct bcm_cfg80211 *cfg)
                wdev->wiphy->wowlan = NULL;
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
-#if defined(WL_SELF_MANAGED_REGDOM) && \
-                       (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+#if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
                /* Making regd ptr NULL, to avoid reference/freeing by regulatory unregister */
                wiphy->regd = NULL;
 #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
@@ -12135,7 +12330,7 @@ wl_handle_assoc_fail(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as, bool compl
                memcpy(&emsg, as->event_msg, sizeof(wl_event_msg_t));
                ret = wl_ext_in4way_sync(ndev, STA_REASSOC_RETRY,
                        WL_EXT_STATUS_RECONNECT, &emsg);
-               if (ret)
+               if (ret == BCME_ERROR)
                        return 0;
        }
        wl_ext_iapsta_enable_master_if(ndev, FALSE);
@@ -12291,7 +12486,13 @@ wl_handle_link_down(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
                memcpy(&emsg, as->event_msg, sizeof(wl_event_msg_t));
                ret = wl_ext_in4way_sync(ndev, STA_REASSOC_RETRY,
                        WL_EXT_STATUS_RECONNECT, &emsg);
-               if (ret)
+               if (ret == BCME_BADADDR) {
+                       u8 *curbssid = NULL;
+                       curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+                       if (curbssid)
+                               (void)memcpy_s(as->addr, ETH_ALEN, curbssid, ETH_ALEN);
+               }
+               else if (ret == BCME_ERROR)
                        return 0;
        }
 #endif
@@ -12668,6 +12869,22 @@ wl_notify_connect_status_sta(struct bcm_cfg80211 *cfg,
                goto exit;
        }
 
+#ifdef WL_ROAM_WAR
+       if (event_type == WLC_E_JOIN)
+               bzero((u8*)&cfg->roaming_bssid, ETHER_ADDR_LEN);
+       else if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+               if (event_type == WLC_E_AUTH && ntoh32(e->status) == WLC_E_STATUS_SUCCESS)
+                       bcopy(&e->addr, &cfg->roaming_bssid, ETHER_ADDR_LEN);
+               else if (event_type == WLC_E_DEAUTH &&
+                               !ETHER_ISNULLADDR(&cfg->roaming_bssid.octet) &&
+                               memcmp(&e->addr, &cfg->roaming_bssid, ETHER_ADDR_LEN)) {
+                       WL_MSG(ndev->name, "skip WLC_E_DEAUTH(%pM), roaming_bssid %pM\n",
+                               &e->addr, &cfg->roaming_bssid);
+                       goto exit;
+               }
+       }
+#endif /* WL_ROAM_WAR */
+
        if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
                assoc_state = WL_STATE_ASSOCIATING;
        } else if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
@@ -13364,7 +13581,6 @@ update_bss_info_out:
        return err;
 }
 
-#ifdef DHD_LOSSLESS_ROAMING
 static s32
 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        const wl_event_msg_t *e, void *data)
@@ -13372,14 +13588,14 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        struct wl_connect_info *conn_info = wl_to_conn(cfg);
        s32 err = 0;
        u8 *curbssid;
-       chanspec_t *chanspec;
+       chanspec_t *chanspec, cur_chanspec;
        scb_val_t scbval;
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
        defined(WL_COMPAT_WIRELESS)
        struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
        struct ieee80211_channel *notify_channel = NULL;
        u32 freq;
-       u32 cur_channel, cur_chanspec, orig_channel;
+       u32 cur_channel, orig_channel;
 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
        (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \
@@ -13420,10 +13636,13 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        cur_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(cur_chanspec));
        orig_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(*chanspec));
        if (dhdp->conf->chip != BCM43569_CHIP_ID) {
-       if ((orig_channel == cur_channel) &&
+       if (((orig_channel == cur_channel) && memcmp(&ether_null, &cfg->last_roamed_addr, ETHER_ADDR_LEN)) &&
                        ((memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) ||
                        (memcmp(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN) == 0))) {
-               WL_DBG(("BSS already present, Skipping roamed event to upper layer\n"));
+               WL_INFORM_MEM(("BSS already present, Skipping roamed event to upper layer\n"));
+               WL_INFORM_MEM(("orig_chan/cur_chan=%d/%d, addr/curbssid/last_roamed_addr=%pM/%pM/%pM\n",
+                       orig_channel, cur_channel,
+                       (const u8*)(&e->addr), curbssid, (const u8*)(&cfg->last_roamed_addr)));
                goto fail;
        }
        }
@@ -13457,13 +13676,15 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        }
        rssi = dtoh32(scbval.val);
 
-       WL_MSG(ndev->name, "%pM(ch:%3d/%sMHz) => %pM(ch:%3d/%sMHz, rssi: %3d)\n",
-               curbssid, orig_channel,
+       WL_MSG(ndev->name, "%pM(chan=%s-%d/%sMHz) => %pM(chan=%s-%d/%sMHz, rssi: %3d)\n",
+               curbssid,
+               CHSPEC2BANDSTR(*chanspec), wf_chspec_ctlchan(*chanspec),
                CHSPEC_IS20(*chanspec)?"20":
                CHSPEC_IS40(*chanspec)?"40":
                CHSPEC_IS80(*chanspec)?"80":
                CHSPEC_IS160(*chanspec)?"160":"??",
-               (const u8*)(&e->addr), cur_channel,
+               (const u8*)(&e->addr),
+               CHSPEC2BANDSTR(cur_chanspec), wf_chspec_ctlchan(cur_chanspec),
                CHSPEC_IS20(cur_chanspec)?"20":
                CHSPEC_IS40(cur_chanspec)?"40":
                CHSPEC_IS80(cur_chanspec)?"80":
@@ -13504,15 +13725,20 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        DHD_STATLOG_CTRL(dhdp, ST(REASSOC_INFORM),
                dhd_net2idx(dhdp->info, ndev), 0);
 #ifdef WL_EXT_IAPSTA
-       wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
+       wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_ROAMED, NULL);
 #endif
 
 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
        (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \
        defined(WL_FILS_ROAM_OFFLD) || defined(CFG80211_ROAM_API_GE_4_12)
        memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+       roam_info.links[0].channel = notify_channel;
+       roam_info.links[0].bssid = curbssid;
+#else
        roam_info.channel = notify_channel;
        roam_info.bssid = curbssid;
+#endif
        roam_info.req_ie = conn_info->req_ie;
        roam_info.req_ie_len = conn_info->req_ie_len;
        roam_info.resp_ie = conn_info->resp_ie;
@@ -13565,12 +13791,15 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        return err;
 
 fail:
+#ifdef WL_EXT_IAPSTA
+       if (err)
+               wl_ext_in4way_sync(ndev, STA_NO_BTC_IN4WAY, WL_EXT_STATUS_DISCONNECTED, NULL);
+#endif
 #ifdef DHD_LOSSLESS_ROAMING
        wl_del_roam_timeout(cfg);
 #endif  /* DHD_LOSSLESS_ROAMING */
        return err;
 }
-#endif /* DHD_LOSSLESS_ROAMING */
 
 static bool
 wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
@@ -13706,10 +13935,21 @@ wl_fillup_resp_params(struct bcm_cfg80211 *cfg, struct net_device *ndev,
 
        resp_params = (struct cfg80211_connect_resp_params *)params;
        resp_params->status = status;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+       resp_params->links[0].bssid = curbssid;
+       resp_params->links[0].bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
+               ssid->SSID, ssid->SSID_len);
+#else
        resp_params->bssid = curbssid;
        resp_params->bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
                ssid->SSID, ssid->SSID_len);
-       if (!resp_params->bss) {
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+       if (!resp_params->links[0].bss)
+#else
+       if (!resp_params->bss)
+#endif
+       {
                WL_ERR(("null bss\n"));
                return BCME_ERROR;
        }
@@ -13819,7 +14059,12 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
                        completed = false;
                        sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
                }
-               if (!ndev->ieee80211_ptr->ssid_len) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+               if (!ndev->ieee80211_ptr->u.client.ssid_len)
+#else
+               if (!ndev->ieee80211_ptr->ssid_len)
+#endif
+               {
                        /* In certain cases, the delayed cfg80211 work from
                                * disconnect context will induce race conditions in
                                * which the ssid_len will be cleared, but dhd is in
@@ -13847,10 +14092,6 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
 
        if (completed) {
                WL_MSG(ndev->name, "Report connect result - connection succeeded\n");
-#ifdef WL_EXT_IAPSTA
-               wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
-               wl_ext_iapsta_enable_master_if(ndev, TRUE);
-#endif
        } else {
                WL_MSG(ndev->name, "Report connect result - connection failed\n");
 #ifdef WL_EXT_IAPSTA
@@ -13900,6 +14141,13 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
 #endif /* WAPI */
        }
 
+#ifdef WL_EXT_IAPSTA
+       if (completed) {
+               wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
+               wl_ext_iapsta_enable_master_if(ndev, TRUE);
+       }
+#endif
+
 exit:
        CLR_TS(cfg, conn_start);
        return err;
@@ -14489,19 +14737,65 @@ exit:
        return err;
 }
 
-#ifdef CUSTOMER_HW6
+static void
+wl_map_brcm_specifc_country_code(char *country_code)
+{
+       /* If country code is default locale, change the domain to world domain
+        * Default locale formats: AA, ZZ, XA-XZ, QM-QZ
+        */
+       if (!strcmp("AA", country_code) || !strcmp("ZZ", country_code) ||
+                       ((country_code[0] == 'X') && (country_code[1] >= 'A') &&
+                       (country_code[1] <= 'Z')) || ((country_code[0] == 'Q') &&
+                       (country_code[1] >= 'M') && (country_code[1] <= 'Z'))) {
+               WL_DBG(("locale mapped to world domain\n"));
+               country_code[0] = '0';
+               country_code[1] = '0';
+       }
+}
+
 static s32
 wl_cfg80211_ccode_evt_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
        const wl_event_msg_t *event, void *data)
 {
+       dhd_pub_t *dhd = cfg->pub;
        s32 err = 0;
+       struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+       char country_str[WLC_CNTRY_BUF_SZ] = { 0 };
+       struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
+
+       if (strlcpy(country_str, data, WL_CCODE_LEN + 1) >= WLC_CNTRY_BUF_SZ) {
+               return -EINVAL;
+       }
+
+       if (strncmp(cfg->country, country_str, WL_CCODE_LEN) == 0) {
+               /* If country code is updated from command context, skip wiphy update */
+               WL_MSG(dev->name, "No change in country (%s)\n", country_str);
+               return BCME_OK;
+       }
+
+       WL_MSG(dev->name, "Updating new country %s\n", country_str);
+       dhd_conf_country(dhd, "country", country_str);
+
        /* Indicate to upper layer for regdom change */
-       WL_INFORM_MEM(("Received country code change event\n"));
        err = wl_update_wiphybands(cfg, true);
+       if (err != BCME_OK) {
+               WL_ERR(("update wiphy bands failed\n"));
+               return err;
+       }
+
+       wl_map_brcm_specifc_country_code(country_str);
+
+       if (!IS_REGDOM_SELF_MANAGED(wiphy)) {
+               err = regulatory_hint(wiphy, country_str);
+               if (err) {
+                       WL_ERR(("update country change failed\n"));
+                       return err;
+               }
+               WL_DBG_MEM(("regulatory hint notified for ccode change\n"));
+       }
 
        return err;
 }
-#endif /* CUSTOMER_HW6 */
 
 static void wl_init_conf(struct wl_conf *conf)
 {
@@ -14605,9 +14899,7 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
        cfg->evt_handler[WLC_E_ADPS] = wl_adps_event_handler;
 #endif /* WL_BAM */
        cfg->evt_handler[WLC_E_PSK_SUP] = wl_cfg80211_sup_event_handler;
-#ifdef CUSTOMER_HW6
        cfg->evt_handler[WLC_E_COUNTRY_CODE_CHANGED] = wl_cfg80211_ccode_evt_handler;
-#endif /* CUSTOMER_HW6 */
 #ifdef WL_BCNRECV
        cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler;
 #endif /* WL_BCNRECV */
@@ -14628,9 +14920,11 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
        cfg->evt_handler[WLC_E_BSS_LOAD] = wl_cfg80211_bssload_report_event_handler;
 #endif /* WL_CHAN_UTIL */
 #ifdef WL_TWT
-       cfg->evt_handler[WLC_E_TWT_SETUP] = wl_notify_twt_event;
-       cfg->evt_handler[WLC_E_TWT_TEARDOWN] = wl_notify_twt_event;
-       cfg->evt_handler[WLC_E_TWT_INFO_FRM] = wl_notify_twt_event;
+       cfg->evt_handler[WLC_E_TWT] = wl_notify_twt_event;
+#else
+#ifdef WL_TWT_HAL_IF
+       cfg->evt_handler[WLC_E_TWT] = wl_cfgvendor_notify_twt_event;
+#endif /* WL_TWT_HAL_IF */
 #endif /* WL_TWT */
 #ifdef WL_CLIENT_SAE
        cfg->evt_handler[WLC_E_JOIN_START] = wl_notify_start_auth;
@@ -15010,7 +15304,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
 
        wdev = ndev_to_wdev(dev);
        if (!wdev) {
-               WL_ERR(("wdev null. Do nothing\n"));
+               WL_DBG(("wdev(%s) null. Do nothing\n", dev->name));
                return NOTIFY_DONE;
        }
 
@@ -15662,7 +15956,7 @@ wl_cfg80211_net_attach(struct net_device *primary_ndev)
        }
 #ifdef WL_STATIC_IF
        /* Register dummy n/w iface. FW init will happen only from dev_open */
-#ifdef WLEASYMESH
+#ifdef WLDWDS
        ntype = NL80211_IFTYPE_AP;
 #else
        ntype = NL80211_IFTYPE_STATION;
@@ -16049,7 +16343,7 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
 
 #ifdef OEM_ANDROID
        if (cfg->event_workq == NULL) {
-               WL_ERR(("Event handler is not created\n"));
+               WL_ERR(("Event handler is not created (%s)\n", bcmevent_get_name(event_type)));
                return;
        }
 #endif /* OEM_ANDROID */
@@ -16888,13 +17182,7 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
        if (notify) {
                if (!IS_REGDOM_SELF_MANAGED(wiphy)) {
                        WL_UPDATE_CUSTOM_REGULATORY(wiphy);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
-                       rtnl_unlock();
-#endif
-                       wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
-                       rtnl_lock();
-#endif
+                       wl_notify_regd(wiphy, NULL);
                }
        }
 
@@ -16955,6 +17243,10 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
        /* Start the event logging */
        wl_add_remove_eventmsg(ndev, WLC_E_TRACE, TRUE);
 #endif /* SHOW_LOGTRACE */
+#if defined(BCMDBUS)
+       if (!dhd->dhd_console_ms)
+               wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE);
+#endif
 
        (void)memcpy_s(wdev->wiphy->perm_addr, ETHER_ADDR_LEN,
                bcmcfg_to_prmry_ndev(cfg)->perm_addr, ETHER_ADDR_LEN);
@@ -17111,6 +17403,77 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
        return err;
 }
 
+#ifdef BCMDBUS
+s32
+__wl_cfg80211_up_resume(dhd_pub_t *dhd)
+{
+       struct net_device *ndev = dhd_linux_get_primary_netdev(dhd);
+       struct bcm_cfg80211 *cfg;
+       struct wireless_dev *wdev;
+       s32 err = 0;
+#ifdef WL_HOST_BAND_MGMT
+       s32 ret = 0;
+#endif /* WL_HOST_BAND_MGMT */
+       u16 wl_iftype = 0;
+       u16 wl_mode = 0;
+
+       WL_DBG(("In\n"));
+
+       if (!ndev)
+               return -EINVAL;
+       cfg = wl_get_cfg(ndev);
+       wdev = ndev->ieee80211_ptr;
+       if (!cfg || !wdev)
+               return -EINVAL;
+
+#if defined(BCMDONGLEHOST)
+       err = dhd_config_dongle(cfg);
+       if (unlikely(err))
+               return err;
+#endif /* defined(BCMDONGLEHOST) */
+
+#ifdef SHOW_LOGTRACE
+       /* Start the event logging */
+       wl_add_remove_eventmsg(ndev, WLC_E_TRACE, TRUE);
+#endif /* SHOW_LOGTRACE */
+#if defined(BCMDBUS)
+       if (!dhd->dhd_console_ms)
+               wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE);
+#endif
+
+       if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
+               return -EINVAL;
+       }
+       if (!dhd->fw_preinit) {
+               err = wl_config_infra(cfg, ndev, wl_iftype);
+               if (unlikely(err && err != -EINPROGRESS)) {
+                       WL_ERR(("wl_config_infra failed\n"));
+                       if (err == -1) {
+                               WL_ERR(("return error %d\n", err));
+                               return err;
+                       }
+               }
+       }
+
+#ifdef WL_HOST_BAND_MGMT
+       /* By default the curr_band is initialized to BAND_AUTO */
+       if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) {
+               if (ret == BCME_UNSUPPORTED) {
+                       /* Don't fail the initialization, lets just
+                        * fall back to the original method
+                        */
+                       WL_ERR(("WL_HOST_BAND_MGMT defined, "
+                               "but roam_band iovar not supported \n"));
+               } else {
+                       WL_ERR(("roam_band failed. ret=%d", ret));
+                       err = -1;
+               }
+       }
+#endif /* WL_HOST_BAND_MGMT */
+       return err;
+}
+#endif /* BCMDBUS */
+
 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
 {
        s32 err = 0;
@@ -17259,7 +17622,12 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
                        struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
                        struct wireless_dev *wdev = ndev->ieee80211_ptr;
                        struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid,
-                               wdev->ssid, wdev->ssid_len);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+                               wdev->u.client.ssid, wdev->u.client.ssid_len
+#else
+                               wdev->ssid, wdev->ssid_len
+#endif
+                       );
 
                        BCM_REFERENCE(bss);
 
@@ -17418,7 +17786,7 @@ s32 wl_cfg80211_up(struct net_device *net)
        if (init_roam_cache(cfg, ioctl_version) == 0) {
                /* Enable support for Roam cache */
                cfg->rcc_enabled = true;
-               WL_ERR(("Roam channel cache enabled\n"));
+               WL_MSG(net->name, "Roam channel cache enabled\n");
        } else {
                WL_ERR(("Failed to enable RCC.\n"));
        }
@@ -19519,7 +19887,7 @@ wl_print_fw_ie_data(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssid
                bssidx, &cfg->ioctl_buf_sync);
        if (ret == BCME_OK) {
                ies = (vndr_ie_buf_t *)cfg->ioctl_buf;
-               WL_INFORM_MEM(("FW IE count:%d ", ies->iecount));
+               WL_INFORM_MEM(("FW IE count:%d\n", ies->iecount));
 #ifdef GET_FW_IE_DATA
                if (wl_dbg_level & WL_DBG_DBG) {
                        int i = 0;
@@ -22759,7 +23127,7 @@ wl_cfg80211_mgmt_auth_tx(struct net_device *dev, bcm_struct_cfgdev *cfgdev,
                ack = false;
        } else {
                err = wldev_iovar_setbuf(dev, "assoc_mgr_cmd", ambuf, param_len,
-                       cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
+                       cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync);
                if (unlikely(err)) {
                        WL_ERR(("Failed to send auth(%d)\n", err));
                        ack = false;
index 52faf2d9a1d9c993304bb2cfaf9550e37154bb0e..626fdc8855a49aba177f007f0a925fc4eef14a0c 100755 (executable)
@@ -332,6 +332,13 @@ extern char *dhd_dbg_get_system_timestamp(void);
 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
 
 #ifdef BCMWAPI_WPI
+#ifdef CFG80211_WAPI_BKPORT
+#define IS_WAPI_VER(version) (version == NL80211_WAPI_VERSION_1)
+#undef WLAN_AKM_SUITE_WAPI_PSK
+#define WLAN_AKM_SUITE_WAPI_PSK                        0x000FAC13
+#undef WLAN_AKM_SUITE_WAPI_CERT
+#define WLAN_AKM_SUITE_WAPI_CERT               0x000FAC14
+#else
 #ifdef OEM_ANDROID
 #undef NL80211_WAPI_VERSION_1
 #define NL80211_WAPI_VERSION_1         0
@@ -354,6 +361,7 @@ extern char *dhd_dbg_get_system_timestamp(void);
 #define NL80211_WAPI_VERSION_1                 1 << 2
 #define IS_WAPI_VER(version) (version & NL80211_WAPI_VERSION_1)
 #endif /* OEM_ANDROID */
+#endif /* CFG80211_WAPI_BKPORT */
 #endif /* BCMWAPI_WPI */
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
@@ -1955,6 +1963,13 @@ struct bcm_cfg80211 {
        bool p2p_6g_enabled;    /* P2P 6G support enabled */
 #endif /* WL_P2P_6G */
        u32 halpid;
+       u8 country[WLC_CNTRY_BUF_SZ];
+#ifdef BCMDBUS
+       bool bus_resuming;
+#endif /* BCMDBUS */
+#ifdef WL_ROAM_WAR
+       struct ether_addr roaming_bssid;
+#endif /* WL_ROAM_WAR */
 #if defined(RSSIAVG)
        wl_rssi_cache_ctrl_t g_rssi_cache_ctrl;
        wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl;
@@ -1965,6 +1980,7 @@ struct bcm_cfg80211 {
        int autochannel;
        int best_2g_ch;
        int best_5g_ch;
+       int best_6g_ch;
 };
 
 /* Max auth timeout allowed in case of EAP is 70sec, additional 5 sec for
@@ -3078,6 +3094,14 @@ extern s32 wl_handle_auth_event(struct bcm_cfg80211 *cfg, struct net_device *nde
 extern bool wl_customer6_legacy_chip_check(struct bcm_cfg80211 *cfg,
        struct net_device *ndev);
 #endif /* CUSTOMER_HW6 */
+#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF)
+extern s32 wl_cfgvendor_notify_twt_event(struct bcm_cfg80211 *cfg,
+       bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
+#endif /* !WL_TWT && WL_TWT_HAL_IF */
+#ifdef BCMDBUS
+s32
+__wl_cfg80211_up_resume(dhd_pub_t *dhd);
+#endif /* BCMDBUS */
 void wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable);
 s32 wl_handle_join(struct bcm_cfg80211 *cfg, struct net_device *dev,
        wlcfg_assoc_info_t *assoc_info);
index be6a717430b49055e05d0be8bea317693892fddd..703e64571433aeb1889c64a35e8c0ce9f13cf5d1 100755 (executable)
 
 #define NAN_RNG_GEOFENCE_MAX_RETRY_CNT 3u
 
+#define NAN_MAX_CHANNEL_INFO_SUPPORTED 4u
 /*
 * Discovery Beacon Interval config,
 * Default value is 128 msec in 2G DW and 176 msec in 2G/5G DW.
@@ -384,6 +385,17 @@ typedef struct nan_mac_list {
        uint8 *list;
 } nan_mac_list_t;
 
+typedef struct nan_channel_info {
+       uint32 channel;
+       uint32 bandwidth;
+       uint32 nss;
+} nan_channel_info_t;
+
+typedef struct nan_ndl_sched_info {
+       uint32 num_channels;
+       nan_channel_info_t channel_info[NAN_MAX_CHANNEL_INFO_SUPPORTED];
+} nan_ndl_sched_info_t;
+
 typedef struct wl_nan_sid_beacon_tune {
        uint8 sid_enable;       /* flag for sending service id in beacon */
        uint8 sid_count;        /* Limit for number of SIDs to be included in Beacons */
@@ -946,7 +958,12 @@ typedef enum {
        NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL         = 224,
        NAN_ATTRIBUTE_NSS                               = 225,
        NAN_ATTRIBUTE_ENABLE_RANGING                    = 226,
-       NAN_ATTRIBUTE_DW_EARLY_TERM                     = 227
+       NAN_ATTRIBUTE_DW_EARLY_TERM                     = 227,
+       NAN_ATTRIBUTE_CHANNEL_INFO                      = 228,
+       NAN_ATTRIBUTE_NUM_CHANNELS                      = 229,
+       NAN_ATTRIBUTE_INSTANT_MODE_ENABLE               = 230,
+       NAN_ATTRIBUTE_INSTANT_COMM_CHAN                 = 231,
+       NAN_ATTRIBUTE_MAX                               = 232
 } NAN_ATTRIBUTE;
 
 enum geofence_suspend_reason {
index 01a04f069ce460e906b88e74c334aba44e7e84fe..aec9646d2c5b19078e99b09c0136b4df0975f067 100755 (executable)
@@ -705,7 +705,12 @@ wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg)
        BCM_REFERENCE(ndev);
        CFGP2P_DBG(("enter\n"));
 
-       if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0) {
+#ifdef BCMDBUS
+       if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0 && !cfg->bus_resuming)
+#else
+       if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0)
+#endif /* BCMDBUS */
+       {
                CFGP2P_ERR(("do nothing, already initialized\n"));
                goto exit;
        }
@@ -732,6 +737,9 @@ wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg)
         * so that time, the ifidx returned in WLC_E_IF should be used for populating
         * the netinfo
         */
+#ifdef BCMDBUS
+       if (!cfg->bus_resuming)
+#endif /* BCMDBUS */
        ret = wl_alloc_netinfo(cfg, NULL, cfg->p2p_wdev, WL_IF_TYPE_STA, 0, bssidx, 0);
        if (unlikely(ret)) {
                goto exit;
@@ -822,7 +830,12 @@ wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev,
        }
 #endif /* WL_IFACE_MGMT */
 
-       if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
+#ifdef BCMDBUS
+       if (!cfg->bus_resuming && (wl_get_p2p_status(cfg, DISCOVERY_ON)))
+#else
+       if (wl_get_p2p_status(cfg, DISCOVERY_ON))
+#endif /* BCMDBUS */
+       {
                CFGP2P_DBG((" DISCOVERY is already initialized, we have nothing to do\n"));
                goto set_ie;
        }
@@ -2403,7 +2416,7 @@ wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg)
 #endif
 
        /* Register with a dummy MAC addr */
-       memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
+       dev_addr_set(net, temp_addr);
 
 #ifndef        WL_NEWCFG_PRIVCMD_SUPPORT
        wdev->wiphy = cfg->wdev->wiphy;
@@ -2622,8 +2635,7 @@ wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg)
 
 #if defined(WL_NEWCFG_PRIVCMD_SUPPORT)
        if (cfg->p2p_net)
-               memcpy(cfg->p2p_net->dev_addr, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE),
-                       ETHER_ADDR_LEN);
+               dev_addr_set(cfg->p2p_net, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE));
 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
 
        /* store p2p wdev ptr for further reference. */
@@ -2671,7 +2683,7 @@ wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
        cfg->p2p_prb_noti = false;
 #endif
 
-       CFGP2P_DBG(("P2P interface started\n"));
+       printf("P2P interface started\n");
 
 exit:
        return ret;
@@ -2719,7 +2731,7 @@ wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
 
        p2p_on(cfg) = false;
 
-       CFGP2P_DBG(("Exit. P2P interface stopped\n"));
+       printf("Exit. P2P interface stopped\n");
 
        return;
 }
@@ -2809,3 +2821,36 @@ wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request)
        }
        return false;
 }
+
+#ifdef BCMDBUS
+int
+wl_cfgp2p_start_p2p_device_resume(dhd_pub_t *dhd)
+{
+       int ret = 0;
+#ifdef WL_CFG80211_P2P_DEV_IF
+       struct net_device *primary_ndev = dhd_linux_get_primary_netdev(dhd);
+       struct bcm_cfg80211 *cfg;
+       struct wiphy *wiphy;
+
+       if (!primary_ndev)
+               return -EINVAL;
+       cfg = wl_get_cfg(primary_ndev);
+       if (!cfg)
+               return -EINVAL;
+
+       RETURN_EIO_IF_NOT_UP(cfg);
+       if (!p2p_on(cfg))
+               return -EINVAL;
+
+       rtnl_lock();
+       wiphy = bcmcfg_to_wiphy(cfg);
+       cfg->bus_resuming = TRUE;
+       ret = wl_cfgp2p_start_p2p_device(wiphy, cfg->wdev);
+       cfg->bus_resuming = FALSE;
+       printf("P2P interface resumed\n");
+       rtnl_unlock();
+#endif
+
+       return ret;
+}
+#endif /* BCMDBUS */
index 58a161a254b5fb02636b85bb49621924dde93498..33a3c1fc251b3beea1011e57c5c6ae6996756488 100755 (executable)
@@ -485,4 +485,9 @@ wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request);
  * instead of channel in actframe iovar.
  */
 #define FW_MAJOR_VER_ACTFRAME_CHSPEC    14
+
+#ifdef BCMDBUS
+int
+wl_cfgp2p_start_p2p_device_resume(dhd_pub_t *dhd);
+#endif /* BCMDBUS */
 #endif                         /* _wl_cfgp2p_h_ */
index 92879408062ecb1879b7213632d23208d47758b8..606f32767ce8061cd353b068a4e3884b468f007e 100755 (executable)
@@ -640,11 +640,11 @@ wl_inform_bss(struct bcm_cfg80211 *cfg)
 
        if (cfg->autochannel && ndev) {
 #if defined(BSSCACHE)
-               wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, ioctl_version,
-                       &cfg->best_2g_ch, &cfg->best_5g_ch);
+               wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl,
+                       &cfg->best_2g_ch, &cfg->best_5g_ch, &cfg->best_6g_ch);
 #else
-               wl_ext_get_best_channel(ndev, bss_list, ioctl_version,
-                       &cfg->best_2g_ch, &cfg->best_5g_ch);
+               wl_ext_get_best_channel(ndev, bss_list,
+                       &cfg->best_2g_ch, &cfg->best_5g_ch, &cfg->best_6g_ch);
 #endif
        }
 
@@ -1576,29 +1576,24 @@ chanspec_t wl_freq_to_chanspec(int freq)
 static void
 wl_cfgscan_populate_scan_channel(struct bcm_cfg80211 *cfg,
        struct ieee80211_channel **channels, u32 n_channels,
-       u16 *channel_list, u32 target_channel)
+       u16 *channel_list, struct wl_chan_info *chan_info)
 {
-       u32 i = 0;
-       u32 chanspec = 0;
-       u32 channel;
+       u32 i, chanspec = 0;
 
        for (i=0; i<n_channels; i++) {
-               channel = ieee80211_frequency_to_channel(channels[i]->center_freq);
-               if (channel != target_channel)
-                       continue;
-               if (!dhd_conf_match_channel(cfg->pub, channel))
-                       return;
-
                chanspec = wl_freq_to_chanspec(channels[i]->center_freq);
                if (chanspec == INVCHANSPEC) {
                        WL_ERR(("Invalid chanspec! Skipping channel\n"));
                        continue;
                }
-
-               channel_list[0] = chanspec;
-               break;
+               if (chan_info->band == CHSPEC2WLC_BAND(chanspec) &&
+                               chan_info->chan == wf_chspec_ctlchan(chanspec)) {
+                       channel_list[0] = chanspec;
+                       break;
+               }
        }
-       WL_SCAN(("chan: %d, chanspec: %x\n", target_channel, chanspec));
+       WL_SCAN(("chan: %s-%d, chanspec: %x\n",
+               WLCBAND2STR(chan_info->band), chan_info->chan, chanspec));
 }
 #endif
 
@@ -1768,6 +1763,7 @@ wl_scan_prep(struct bcm_cfg80211 *cfg, struct net_device *ndev, void *scan_param
        struct cfg80211_scan_request *request)
 {
 #ifdef SCAN_SUPPRESS
+       struct wl_chan_info chan_info;
        u32 channel;
 #endif
        wl_scan_params_t *params = NULL;
@@ -1847,14 +1843,14 @@ wl_scan_prep(struct bcm_cfg80211 *cfg, struct net_device *ndev, void *scan_param
        cur_offset = channel_offset;
        /* Copy channel array if applicable */
 #ifdef SCAN_SUPPRESS
-       channel = wl_ext_scan_suppress(ndev, scan_params, cfg->scan_params_v2);
+       channel = wl_ext_scan_suppress(ndev, scan_params, cfg->scan_params_v2, &chan_info);
        if (channel) {
                n_channels = 1;
                if ((n_channels > 0) && chan_list) {
                        if (len >= (scan_param_size + (n_channels * sizeof(u16)))) {
                                wl_cfgscan_populate_scan_channel(cfg,
                                        request->channels, request->n_channels,
-                                       chan_list, channel);
+                                       chan_list, &chan_info);
                                cur_offset += (n_channels * (sizeof(u16)));
                        }
                }
@@ -2644,8 +2640,14 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
        }
 
 #ifdef WL_EXT_IAPSTA
-       if (wl_ext_in4way_sync(ndev, STA_FAKE_SCAN_IN_CONNECT, WL_EXT_STATUS_SCANNING, NULL)) {
+       err = wl_ext_in4way_sync(ndev, STA_FAKE_SCAN_IN_CONNECT, WL_EXT_STATUS_SCANNING, NULL);
+       if (err) {
+               wl_event_msg_t msg;
                mutex_lock(&cfg->scan_sync);
+               bzero(&msg, sizeof(wl_event_msg_t));
+               msg.event_type = hton32(WLC_E_ESCAN_RESULT);
+               msg.status = hton32(WLC_E_STATUS_SUCCESS);
+               wl_cfg80211_event(ndev, &msg, NULL);
                goto scan_success;
        }
 #endif
@@ -5562,7 +5564,7 @@ wl_get_assoc_channels(struct bcm_cfg80211 *cfg,
        }
 #endif /* ESCAN_CHANNEL_CACHE */
 
-       WL_DBG_MEM(("channel cnt:%d\n", info->chan_cnt));
+       WL_SCAN(("channel cnt:%d\n", info->chan_cnt));
        return BCME_OK;
 }
 
@@ -5584,7 +5586,7 @@ wl_cfgscan_is_dfs_set(wifi_band band)
 
 s32
 wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band,
-       uint16 *list, uint32 *num_channels)
+       uint32 *list, uint32 *num_channels)
 {
        s32 err = BCME_OK;
        uint32 i, freq, list_count, count = 0;
@@ -5606,13 +5608,16 @@ wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band,
        list_count = ((wl_chanspec_list_v1_t *)list)->count;
        for (i = 0; i < list_count; i++) {
                chspec = dtoh32(((wl_chanspec_list_v1_t *)list)->chspecs[i].chanspec);
+               if (!CHSPEC_IS20(chspec)) {
+                       continue;
+               }
                chaninfo = dtoh32(((wl_chanspec_list_v1_t *)list)->chspecs[i].chaninfo);
                freq = wl_channel_to_frequency(wf_chspec_ctlchan(chspec),
                        CHSPEC_BAND(chspec));
                if (((band & WIFI_BAND_BG) && CHSPEC_IS2G(chspec)) ||
                                ((band & WIFI_BAND_6GHZ) && CHSPEC_IS6G(chspec))) {
                        /* add 2g/6g channels */
-                       list[i] = freq;
+                       list[count] = freq;
                        count++;
                }
                /* handle 5g separately */
@@ -5627,7 +5632,7 @@ wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band,
                                continue;
                        }
 
-                       list[i] = freq;
+                       list[count] = freq;
                        count++;
                }
        }
index 74883326a72b43ea6ef744d1061564242f3b5077..edc3e0a264f8a7d0ebd5643bfe02d7d1830e6fd3 100755 (executable)
@@ -173,6 +173,6 @@ typedef enum {
 
 extern bool wl_cfgscan_is_dfs_set(wifi_band band);
 extern s32 wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band,
-        uint16 *list, uint32 *num_channels);
+        uint32 *list, uint32 *num_channels);
 #endif /* DHD_GET_VALID_CHANNELS */
 #endif /* _wl_cfgscan_h_ */
index 62d34963b1b7e9b40bf325169337af9345951d89..ab7e073ad299d72c6f0ccd90e73a256433c088fb 100755 (executable)
@@ -469,7 +469,11 @@ wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
                        iter_cnt_to_send -= cnt;
                        cache->tot_consumed += cnt;
                        /* Push the data to the skb */
+#ifdef ANDROID13_KERNEL515_BKPORT
+                       nla_put_nohdr(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
+#else
                        nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
+#endif
                        if (cache->tot_consumed == cache->tot_count) {
                                cache = cache->next;
                        }
@@ -1210,7 +1214,7 @@ wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
 {
        int err = 0, type, band;
        struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
-       uint16 *reply = NULL;
+       uint32 *reply = NULL;
        uint32 reply_len = 0, num_channels, mem_needed;
        struct sk_buff *skb;
        dhd_pub_t *dhdp;
@@ -2808,7 +2812,7 @@ wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
 
        ret = dhd_cfgvendor_priv_string_handler(cfg, wdev, nlioc, buf);
        if (ret) {
-               WL_ERR(("dhd_cfgvendor returned error %d", ret));
+               WL_ERR(("dhd_cfgvendor returned error %d\n", ret));
                vfree(buf);
                return ret;
        }
@@ -7145,7 +7149,7 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy,
                                dtoh32(cca_result->secs[0].congest_obss),
                                dtoh32(cca_result->secs[0].interference)));
                } else {
-                       WL_TRACE(("cca_get_stats is unsupported \n"));
+                       WL_INFORM(("cca_get_stats is unsupported \n"));
                }
 
                /* If cca_get_stats is unsupported, cca_busy_time has zero value as initial value */
@@ -8520,12 +8524,12 @@ static int wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy *wiphy,
 #endif /* DBG_PKT_MON */
 
 #ifdef KEEP_ALIVE
+/* max size of IP packet for keep alive */
+#define MKEEP_ALIVE_IP_PKT_MAX 256
+
 static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
        const void *data, int len)
 {
-       /* max size of IP packet for keep alive */
-       const int MKEEP_ALIVE_IP_PKT_MAX = 256;
-
        int ret = BCME_OK, rem, type;
        uint8 mkeep_alive_id = 0;
        uint8 *ip_pkt = NULL;
@@ -8645,6 +8649,15 @@ static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_de
 #endif /* KEEP_ALIVE */
 
 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+const struct nla_policy apf_atrribute_policy[APF_ATTRIBUTE_MAX] = {
+       [APF_ATTRIBUTE_VERSION] = { .type = NLA_U32 },
+       [APF_ATTRIBUTE_MAX_LEN] = { .type = NLA_U32 },
+       [APF_ATTRIBUTE_PROGRAM] = { .type = NLA_BINARY },
+       [APF_ATTRIBUTE_PROGRAM_LEN] = { .type = NLA_U32 },
+};
+#endif /* LINUX_VERSION >= 5.3 */
+
 static int
 wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy,
        struct wireless_dev *wdev, const void *data, int len)
@@ -9033,247 +9046,1405 @@ exit:
 }
 #endif /* WL_SAR_TX_POWER */
 
-static struct wiphy_vendor_command wl_vendor_cmds [] = {
-       {
-               {
-                       .vendor_id = OUI_BRCM,
-                       .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_priv_string_handler
-       },
-#ifdef BCM_PRIV_CMD_SUPPORT
-       {
-               {
-                       .vendor_id = OUI_BRCM,
-                       .subcmd = BRCM_VENDOR_SCMD_BCM_STR
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_priv_bcm_handler
-       },
-#endif /* BCM_PRIV_CMD_SUPPORT */
-#if defined(WL_SAE) || defined(WL_CLIENT_SAE)
-       {
-               {
-                       .vendor_id = OUI_BRCM,
-                       .subcmd = BRCM_VENDOR_SCMD_BCM_PSK
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_sae_password
-       },
-#endif /* WL_SAE || WL_CLIENT_SAE */
-       {
-               {
-                       .vendor_id = OUI_BRCM,
-                       .subcmd = BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_connect_params_handler
-       },
-       {
-               {
-                       .vendor_id = OUI_BRCM,
-                       .subcmd = BRCM_VENDOR_SCMD_SET_START_AP_PARAMS
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_start_ap_params_handler
-       },
-#ifdef GSCAN_SUPPORT
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_gscan_get_capabilities
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = GSCAN_SUBCMD_SET_CONFIG
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_scan_cfg
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_batch_scan_cfg
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_initiate_gscan
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_enable_full_scan_result
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = GSCAN_SUBCMD_SET_HOTLIST
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_hotlist_cfg
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_gscan_get_batch_results
-       },
-#endif /* GSCAN_SUPPORT */
-#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_gscan_get_channel_list
-       },
-#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
-#ifdef RTT_SUPPORT
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = RTT_SUBCMD_SET_CONFIG
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_rtt_set_config
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = RTT_SUBCMD_CANCEL_CONFIG
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_rtt_cancel_config
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = RTT_SUBCMD_GETCAPABILITY
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_rtt_get_capability
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = RTT_SUBCMD_GETAVAILCHANNEL
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_rtt_get_responder_info
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = RTT_SUBCMD_SET_RESPONDER
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_rtt_set_responder
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = RTT_SUBCMD_CANCEL_RESPONDER
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_rtt_cancel_responder
-       },
-#endif /* RTT_SUPPORT */
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_get_feature_set
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_get_feature_set_matrix
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = ANDR_WIFI_RANDOM_MAC_OUI
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_rand_mac_oui
-       },
-#ifdef CUSTOM_FORCE_NODFS_FLAG
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = ANDR_WIFI_NODFS_CHANNELS
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_nodfs_flag
-       },
-#endif /* CUSTOM_FORCE_NODFS_FLAG */
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = ANDR_WIFI_SET_COUNTRY
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_country
-       },
-#ifdef LINKSTAT_SUPPORT
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = LSTATS_SUBCMD_GET_INFO
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_lstats_get_info
-       },
-#endif /* LINKSTAT_SUPPORT */
+#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF)
+static int
+wl_cfgvendor_twt_setup(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len)
+{
+       wl_twt_config_t val;
+       s32 bw;
+       s32 type, rem_attr;
+       u8 mybuf[WLC_IOCTL_SMLEN] = {0};
+       u8 resp_buf[WLC_IOCTL_SMLEN] = {0};
+       const struct nlattr *iter;
+       uint8 *rem = mybuf;
+       uint16 rem_len = sizeof(mybuf);
+
+       bzero(&val, sizeof(val));
+       val.version = WL_TWT_SETUP_VER;
+       val.length = sizeof(val.version) + sizeof(val.length);
+
+       /* Default values, Override Below */
+       val.desc.flow_flags = 0;
+       val.desc.wake_time_h = 0xFFFFFFFF;
+       val.desc.wake_time_l = 0xFFFFFFFF;
+       val.desc.wake_int_min = 0xFFFFFFFF;
+       val.desc.wake_int_max = 0xFFFFFFFF;
+       val.desc.wake_dur_min = 0xFFFFFFFF;
+       val.desc.wake_dur_max = 0xFFFFFFFF;
+       val.desc.avg_pkt_num  = 0xFFFFFFFF;
+       val.desc.avg_pkt_size = 0xFFFFFFFF;
+
+       nla_for_each_attr(iter, data, len, rem_attr) {
+               type = nla_type(iter);
+               switch (type) {
+                       case ANDR_TWT_ATTR_CONFIG_ID:
+                               /* Config ID */
+                               val.desc.configID = nla_get_u8(iter);
+                               break;
+                       case ANDR_TWT_ATTR_NEGOTIATION_TYPE:
+                               /* negotiation_type */
+                               val.desc.negotiation_type  = nla_get_u8(iter);
+                               break;
+                       case ANDR_TWT_ATTR_TRIGGER_TYPE:
+                               /* Trigger Type */
+                               if (nla_get_u8(iter) == 1) {
+                                       val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER;
+                               }
+                               break;
+                       case ANDR_TWT_ATTR_WAKE_DURATION:
+                               /* Wake Duration */
+                               val.desc.wake_dur = nla_get_u32(iter);
+                               break;
+                       case ANDR_TWT_ATTR_WAKE_INTERVAL:
+                               /* Wake interval */
+                               val.desc.wake_int = nla_get_u32(iter);
+                               break;
+                       case ANDR_TWT_ATTR_WAKETIME_OFFSET:
+                               /* Wake Time parameter */
+                               val.desc.wake_time_h = 0;
+                               val.desc.wake_time_l = nla_get_u32(iter);
+                               break;
+                       case ANDR_TWT_ATTR_WAKE_INTERVAL_MIN:
+                               /* Minimum allowed Wake interval */
+                               val.desc.wake_int_min = nla_get_u32(iter);
+                               break;
+                       case ANDR_TWT_ATTR_WAKE_INTERVAL_MAX:
+                               /* Max Allowed Wake interval */
+                               val.desc.wake_int_max = nla_get_u32(iter);
+                               break;
+                       case ANDR_TWT_ATTR_WAKE_DURATION_MIN:
+                               /* Minimum allowed Wake duration */
+                               val.desc.wake_dur_min = nla_get_u32(iter);
+                               break;
+                       case ANDR_TWT_ATTR_WAKE_DURATION_MAX:
+                               /* Maximum allowed Wake duration */
+                               val.desc.wake_dur_max = nla_get_u32(iter);
+                               break;
+                       case ANDR_TWT_ATTR_AVG_PKT_NUM:
+                               /* Average number of packets */
+                               val.desc.avg_pkt_num  = nla_get_u32(iter);
+                               break;
+                       case ANDR_TWT_ATTR_AVG_PKT_SIZE:
+                               /* Average packets size */
+                               val.desc.avg_pkt_size = nla_get_u32(iter);
+                               break;
+                       default:
+                               WL_ERR(("Invalid setup attribute type %d\n", type));
+                               break;
+               }
+       }
 
-#ifdef GSCAN_SUPPORT
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_epno_cfg
+       bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG,
+                       sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
+       if (bw != BCME_OK) {
+               goto exit;
+       }
 
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_lazy_roam_cfg
+       bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt",
+               mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL);
+       if (bw < 0) {
+               WL_ERR(("twt config set failed. ret:%d\n", bw));
+       } else {
+               WL_INFORM(("twt config setup succeeded, config ID %d "
+                       "Negotiation type %d flow flags %d\n", val.desc.configID,
+                       val.desc.negotiation_type, val.desc.flow_flags));
+       }
 
-       },
-       {
-               {
-                       .vendor_id = OUI_GOOGLE,
-                       .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM
-               },
-               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+exit:
+       return bw;
+}
+
+static int
+wl_cfgvendor_twt_teardown(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len)
+{
+       wl_twt_teardown_t val;
+       s32 bw;
+       s32 type, rem_attr;
+       u8 mybuf[WLC_IOCTL_SMLEN] = {0};
+       u8 res_buf[WLC_IOCTL_SMLEN] = {0};
+       const struct nlattr *iter;
+       uint8 *rem = mybuf;
+       uint16 rem_len = sizeof(mybuf);
+
+       bzero(&val, sizeof(val));
+       val.version = WL_TWT_TEARDOWN_VER;
+       val.length = sizeof(val.version) + sizeof(val.length);
+
+       /* Default values, Override Below */
+       val.teardesc.flow_id = 0xFF;
+       val.teardesc.bid = 0xFF;
+
+       nla_for_each_attr(iter, data, len, rem_attr) {
+               type = nla_type(iter);
+               switch (type) {
+                       case ANDR_TWT_ATTR_CONFIG_ID:
+                               /* Config ID */
+                               val.configID = nla_get_u8(iter);
+                               break;
+                       case ANDR_TWT_ATTR_NEGOTIATION_TYPE:
+                               /* negotiation_type */
+                               val.teardesc.negotiation_type  = nla_get_u8(iter);
+                               break;
+                       case ANDR_TWT_ATTR_ALL_TWT:
+                               /* all twt */
+                               val.teardesc.alltwt = nla_get_u8(iter);
+                               break;
+                       default:
+                               WL_ERR(("Invalid teardown attribute type %d\n", type));
+                       break;
+               }
+       }
+
+       bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN,
+               sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
+       if (bw != BCME_OK) {
+               goto exit;
+       }
+
+       bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt",
+               mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
+       if (bw < 0) {
+               WL_ERR(("twt teardown failed. ret:%d\n", bw));
+       } else {
+               WL_INFORM(("twt teardown succeeded, config ID %d "
+                       "Negotiation type %d alltwt %d\n", val.configID,
+                       val.teardesc.negotiation_type, val.teardesc.alltwt));
+       }
+
+exit:
+       return bw;
+}
+
+static int
+wl_cfgvendor_twt_info_frame(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len)
+{
+       wl_twt_info_t val;
+       int bw;
+       s32 type, rem_attr;
+       const struct nlattr *iter;
+       u8 mybuf[WLC_IOCTL_SMLEN] = {0};
+       u8 res_buf[WLC_IOCTL_SMLEN] = {0};
+       uint8 *rem = mybuf;
+       uint16 rem_len = sizeof(mybuf);
+       uint32 val32 = 0;
+
+       bzero(&val, sizeof(val));
+       val.version = WL_TWT_INFO_VER;
+       val.length = sizeof(val.version) + sizeof(val.length);
+
+       /* Default values, Override Below */
+       val.infodesc.flow_id = 0xFF;
+       val.desc.next_twt_h = 0xFFFFFFFF;
+       val.desc.next_twt_l = 0xFFFFFFFF;
+
+       nla_for_each_attr(iter, data, len, rem_attr) {
+               type = nla_type(iter);
+               if (type == ANDR_TWT_ATTR_CONFIG_ID) {
+                       /* Config ID */
+                       val.configID = nla_get_u8(iter);
+               } else if (type == ANDR_TWT_ATTR_RESUME_TIME) {
+                       /* Resume offset */
+                       val32 = nla_get_u32(iter);
+                       if (!((val32 == 0) || (val32 == -1))) {
+                               val.infodesc.next_twt_h = 0;
+                               val.infodesc.next_twt_l = val32;
+                               val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME;
+                       }
+               } else if (type == ANDR_TWT_ATTR_ALL_TWT) {
+                       /* all twt */
+                       val32 = (uint32)nla_get_u8(iter);
+                       if (val32) {
+                               val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT;
+                       }
+               } else {
+                       WL_ERR(("Invalid info frame attribute type %d\n", type));
+               }
+       }
+
+       bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO,
+               sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
+       if (bw != BCME_OK) {
+               goto exit;
+       }
+
+       bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt",
+               mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
+       if (bw < 0) {
+               WL_ERR(("twt info frame failed. ret:%d\n", bw));
+       } else {
+               WL_INFORM(("twt info frame succeeded, config ID %d\n", val.configID));
+       }
+
+exit:
+       return bw;
+}
+
+static int
+wl_cfgvendor_twt_stats_update_v2(struct wiphy *wiphy, wl_twt_stats_v2_t *stats)
+{
+       u32 i;
+       wl_twt_peer_stats_v2_t *peer_stats;
+       struct sk_buff *skb;
+       int32 mem_needed;
+       int ret = BCME_OK;
+
+       mem_needed = BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN;
+
+       skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
+       if (unlikely(!skb)) {
+               WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = nla_put_u32(skb, ANDR_TWT_ATTR_NUM_PEER_STATS, stats->num_stats);
+       if (ret < 0) {
+               WL_ERR(("Failed to put ANDR_TWT_ATTR_NUM_PEER_STATS, ret:%d\n", ret));
+               goto fail;
+       }
+
+       for (i = 0; i < stats->num_stats; i++) {
+               peer_stats = &stats->peer_stats_list[i];
+
+               WL_INFORM_MEM(("%u %u %u %u %u",
+                       peer_stats->eosp_dur_avg, peer_stats->tx_pkts_avg, peer_stats->rx_pkts_avg,
+                       peer_stats->tx_pkt_sz_avg, peer_stats->rx_pkt_sz_avg));
+               ret = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, peer_stats->configID);
+               if (ret < 0) {
+                       WL_ERR(("Failed to put ANDR_TWT_ATTR_CONFIG_ID, ret:%d\n", ret));
+                       goto fail;
+               }
+               ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_NUM_TX, peer_stats->tx_pkts_avg);
+               if (ret < 0) {
+                       WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_NUM_TX, ret:%d\n", ret));
+                       goto fail;
+               }
+               ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_SIZE_TX, peer_stats->tx_pkt_sz_avg);
+               if (ret < 0) {
+                       WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_SIZE_TX, ret:%d\n", ret));
+                       goto fail;
+               }
+               ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_NUM_RX, peer_stats->rx_pkts_avg);
+               if (ret < 0) {
+                       WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_NUM_RX, ret:%d\n", ret));
+                       goto fail;
+               }
+               ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_SIZE_RX, peer_stats->rx_pkt_sz_avg);
+               if (ret < 0) {
+                       WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_SIZE_RX, ret:%d\n", ret));
+                       goto fail;
+               }
+               ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_EOSP_DUR, peer_stats->eosp_dur_avg);
+               if (ret < 0) {
+                       WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_EOSP_DUR, ret:%d\n", ret));
+                       goto fail;
+               }
+               ret = nla_put_u32(skb, ANDR_TWT_ATTR_EOSP_CNT, peer_stats->eosp_count);
+               if (ret < 0) {
+                       WL_ERR(("Failed to put ANDR_TWT_ATTR_EOSP_CNT, ret:%d\n", ret));
+                       goto fail;
+               }
+               ret = nla_put_u32(skb, ANDR_TWT_ATTR_NUM_SP, peer_stats->sp_seq);
+               if (ret < 0) {
+                       WL_ERR(("Failed to put ANDR_TWT_ATTR_NUM_SP, ret:%d\n", ret));
+                       goto fail;
+               }
+       }
+
+       ret = cfg80211_vendor_cmd_reply(skb);
+       if (unlikely(ret)) {
+               WL_ERR(("vendor command reply failed, ret=%d\n", ret));
+       }
+       return ret;
+
+fail:
+       /* Free skb for failure cases */
+       if (skb) {
+               kfree_skb(skb);
+       }
+       return ret;
+}
+
+static int
+wl_cfgvendor_twt_stats(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len, bool clear_stats)
+{
+       wl_twt_stats_cmd_v1_t query;
+       wl_twt_stats_v2_t stats_v2;
+       s32 type, rem_attr;
+       const struct nlattr *iter;
+       int ret = BCME_OK;
+       char iovbuf[WLC_IOCTL_SMLEN] = {0, };
+       uint8 *pxtlv = NULL;
+       uint8 *iovresp = NULL;
+       uint16 buflen = 0, bufstart = 0;
+       struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev));
+
+       bzero(&query, sizeof(query));
+       query.version = WL_TWT_STATS_CMD_VERSION_1;
+       query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer);
+
+       /* Default values, Override Below */
+       query.num_bid = 0xFF;
+       query.num_fid = 0xFF;
+
+       if (clear_stats) {
+               query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET;
+       }
+       nla_for_each_attr(iter, data, len, rem_attr) {
+               type = nla_type(iter);
+               if (type == ANDR_TWT_ATTR_CONFIG_ID) {
+                       /* Config ID */
+                       query.configID = nla_get_u8(iter);
+               } else {
+                       WL_ERR(("Invalid TWT stats attribute type %d\n", type));
+               }
+       }
+
+       iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
+       if (iovresp == NULL) {
+               WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
+               goto exit;
+       }
+
+       buflen = bufstart = WLC_IOCTL_SMLEN;
+       pxtlv = (uint8 *)iovbuf;
+       ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS,
+                       sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32);
+       if (ret != BCME_OK) {
+               WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
+               goto exit;
+       }
+
+       if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen,
+               iovresp, WLC_IOCTL_MEDLEN, NULL))) {
+               WL_ERR(("twt status failed with err=%d \n", ret));
+               goto exit;
+       }
+
+       (void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2));
+
+       if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) {
+               if (!clear_stats) {
+                       WL_ERR(("stats query ver %d, \n", dtoh16(stats_v2.version)));
+                       ret = wl_cfgvendor_twt_stats_update_v2(wiphy, (wl_twt_stats_v2_t*)iovresp);
+               }
+       } else {
+               ret = BCME_UNSUPPORTED;
+               WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version)));
+               goto exit;
+       }
+
+exit:
+       if (iovresp) {
+               MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
+       }
+
+       return ret;
+}
+
+static int
+wl_cfgvendor_twt_get_stats(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len)
+{
+       return wl_cfgvendor_twt_stats(wiphy, wdev, data, len, false);
+}
+
+static int
+wl_cfgvendor_twt_clear_stats(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len)
+{
+       return wl_cfgvendor_twt_stats(wiphy, wdev, data, len, true);
+}
+
+static int
+wl_cfgvendor_twt_update_cap(struct wiphy *wiphy, wl_twt_cap_t *result)
+{
+       struct sk_buff *skb;
+       int32 mem_needed;
+       int ret = BCME_OK;
+
+       WL_INFORM_MEM(("TWT Capabilites Device,Peer 0x%04x 0x%04x\n",
+               result->device_cap, result->peer_cap));
+
+       mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
+
+       skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
+       if (unlikely(!skb)) {
+               WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = nla_put_u32(skb, ANDR_TWT_ATTR_DEVICE_CAP, result->device_cap);
+       if (ret < 0) {
+               WL_ERR(("Failed to put ANDR_TWT_ATTR_DEVICE_CAP, ret:%d\n", ret));
+               goto fail;
+       }
+       ret = nla_put_u32(skb, ANDR_TWT_ATTR_PEER_CAP, result->peer_cap);
+       if (ret < 0) {
+               WL_ERR(("Failed to put ANDR_TWT_ATTR_PEER_CAP, ret:%d\n", ret));
+               goto fail;
+       }
+
+       ret = cfg80211_vendor_cmd_reply(skb);
+       if (unlikely(ret)) {
+               WL_ERR(("vendor command reply failed, ret=%d\n", ret));
+       }
+       return ret;
+
+fail:
+       /* Free skb for failure cases */
+       if (skb) {
+               kfree_skb(skb);
+       }
+       return ret;
+}
+
+static int
+wl_cfgvendor_twt_cap(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len)
+{
+       int ret = BCME_OK;
+       char iovbuf[WLC_IOCTL_SMLEN] = {0, };
+       uint8 *pxtlv = NULL;
+       uint8 *iovresp = NULL;
+       wl_twt_cap_cmd_t cmd_cap;
+       wl_twt_cap_t result;
+
+       uint16 buflen = 0, bufstart = 0;
+       struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev));
+
+       bzero(&cmd_cap, sizeof(cmd_cap));
+
+       cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1;
+       cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer);
+
+       iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
+       if (iovresp == NULL) {
+               WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
+               goto exit;
+       }
+
+       buflen = bufstart = WLC_IOCTL_SMLEN;
+       pxtlv = (uint8 *)iovbuf;
+
+       ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP,
+                       sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32);
+       if (ret != BCME_OK) {
+               WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
+               goto exit;
+       }
+
+       if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen,
+               iovresp, WLC_IOCTL_MEDLEN, NULL))) {
+               WL_ERR(("Getting twt status failed with err=%d \n", ret));
+               goto exit;
+       }
+
+       (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
+
+       if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) {
+               WL_ERR(("capability ver %d, \n", dtoh16(result.version)));
+               ret = wl_cfgvendor_twt_update_cap(wiphy, &result);
+               return ret;
+       } else {
+               ret = BCME_UNSUPPORTED;
+               WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
+               goto exit;
+       }
+
+exit:
+       if (iovresp) {
+               MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
+       }
+
+       return ret;
+}
+
+static int
+wl_cfgvendor_twt_update_setup_response(struct sk_buff *skb, void *event_data)
+{
+       s32 err = BCME_OK;
+       const wl_twt_setup_cplt_t *setup_cplt = (wl_twt_setup_cplt_t *)event_data;
+       const wl_twt_sdesc_t *sdesc = (const wl_twt_sdesc_t *)&setup_cplt[1];
+
+       WL_DBG(("TWT_SETUP: status %d, reason %d, configID %d, setup_cmd %d, flow_flags 0x%x,"
+               " flow_id %d, channel %d, negotiation_type %d, wake_time_h %u, wake_time_l %u,"
+               " wake_dur %u, wake_int %u\n",
+               (int)setup_cplt->status, (int)setup_cplt->reason_code, (int)setup_cplt->configID,
+               (int)sdesc->setup_cmd, sdesc->flow_flags, (int)sdesc->flow_id, (int)sdesc->channel,
+               (int)sdesc->negotiation_type, sdesc->wake_time_h, sdesc->wake_time_l,
+               sdesc->wake_dur, sdesc->wake_int));
+
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_SETUP);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, setup_cplt->configID);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, setup_cplt->reason_code);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(setup_cplt->status));
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_NEGOTIATION_TYPE, sdesc->negotiation_type);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NEGOTIATION_TYPE failed\n"));
+               goto fail;
+       }
+       err = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_DURATION, sdesc->wake_dur);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_DURATION failed\n"));
+               goto fail;
+       }
+       err = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_INTERVAL, sdesc->wake_int);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_INTERVAL failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_TRIGGER_TYPE,
+               !!(sdesc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER));
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_TRIGGER_TYPE failed\n"));
+               goto fail;
+       }
+
+fail:
+       return err;
+}
+
+static int
+wl_cfgvendor_twt_update_teardown_response(struct sk_buff *skb, void *event_data)
+{
+       s32 err = BCME_OK;
+       const wl_twt_teardown_cplt_t *td_cplt = (wl_twt_teardown_cplt_t *)event_data;
+       const wl_twt_teardesc_t *teardesc = (const wl_twt_teardesc_t *)&td_cplt[1];
+
+       WL_DBG(("TWT_TEARDOWN: status %d, reason %d, configID %d, flow_id %d, negotiation_type %d,"
+               " bid %d, alltwt %d\n", (int)td_cplt->status, (int)td_cplt->reason_code,
+               (int)td_cplt->configID, (int)teardesc->flow_id, (int)teardesc->negotiation_type,
+               (int)teardesc->bid, (int)teardesc->alltwt));
+
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_TEARDOWN);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, td_cplt->reason_code);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_REASON_CODE failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(td_cplt->status));
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_STATUS failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, td_cplt->configID);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_CONFIG_ID failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_ALL_TWT, teardesc->alltwt);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_ALL_TWT failed\n"));
+               goto fail;
+       }
+
+fail:
+       return err;
+}
+
+static int
+wl_cfgvendor_twt_update_infoframe_response(struct sk_buff *skb, void *event_data)
+{
+       s32 err = BCME_OK;
+       const wl_twt_info_cplt_t *info_cplt = (wl_twt_info_cplt_t *)event_data;
+       const wl_twt_infodesc_t *infodesc = (const wl_twt_infodesc_t *)&info_cplt[1];
+
+       WL_DBG(("TWT_INFOFRM: status %d, reason %d, configID %d, flow_flags 0x%x, flow_id %d,"
+               " next_twt_h %u, next_twt_l %u\n", (int)info_cplt->status,
+               (int)info_cplt->reason_code, (int)info_cplt->configID, infodesc->flow_flags,
+               (int)infodesc->flow_id, infodesc->next_twt_h, infodesc->next_twt_l));
+
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_INFO_FRM);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, info_cplt->reason_code);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(info_cplt->status));
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, info_cplt->configID);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_ALL_TWT,
+                       !!(infodesc->flow_flags & WL_TWT_INFO_FLAG_ALL_TWT));
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_TWT_RESUMED failed\n"));
+               goto fail;
+       }
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_TWT_RESUMED,
+                       !!(infodesc->flow_flags & WL_TWT_INFO_FLAG_RESUME));
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_TWT_RESUMED failed\n"));
+               goto fail;
+       }
+
+fail:
+       return err;
+}
+
+static int
+wl_cfgvendor_twt_update_notify_response(struct sk_buff *skb, void *event_data)
+{
+       s32 err = BCME_OK;
+       const wl_twt_notify_t *notif_cplt = (wl_twt_notify_t *)event_data;
+
+       WL_DBG(("TWT_NOTIFY: notification %d\n", (int)notif_cplt->notification));
+
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_NOTIFY);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
+               goto fail;
+       }
+
+       err = nla_put_u8(skb, ANDR_TWT_ATTR_TWT_NOTIFICATION, notif_cplt->notification);
+       if (unlikely(err)) {
+               WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NOTIFICATION failed\n"));
+               goto fail;
+       }
+
+fail:
+       return err;
+}
+
+s32
+wl_cfgvendor_notify_twt_event(struct bcm_cfg80211 *cfg,
+               bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
+{
+       struct sk_buff *skb = NULL;
+       gfp_t kflags;
+       struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+       int err = BCME_OK;
+       struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+       const wl_twt_event_t *twt_event = (wl_twt_event_t *)data;
+
+       kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+       skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev),
+               BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_TWT, kflags);
+       if (!skb) {
+               WL_ERR(("skb alloc failed"));
+               err = BCME_NOMEM;
+               goto fail;
+       }
+
+       switch (twt_event->event_type) {
+               case WL_TWT_EVENT_SETUP:
+                       err = wl_cfgvendor_twt_update_setup_response(skb,
+                                       (void*)twt_event->event_info);
+                       break;
+               case WL_TWT_EVENT_TEARDOWN:
+                       err = wl_cfgvendor_twt_update_teardown_response(skb,
+                                       (void*)twt_event->event_info);
+                       break;
+               case WL_TWT_EVENT_INFOFRM:
+                       err = wl_cfgvendor_twt_update_infoframe_response(skb,
+                                       (void*)twt_event->event_info);
+                       break;
+               case WL_TWT_EVENT_NOTIFY:
+                       err = wl_cfgvendor_twt_update_notify_response(skb,
+                                       (void*)twt_event->event_info);
+                       break;
+               default:
+                       WL_ERR(("Invalid TWT sub event type %d", twt_event->event_type));
+                       err = BCME_UNSUPPORTED;
+                       break;
+       }
+
+       if (err) {
+               goto fail;
+       }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+       cfg80211_vendor_event(skb, kflags);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
+       WL_ERR(("Successfully sent TWT vendor event type %d\n", twt_event->event_type));
+       return BCME_OK;
+
+fail:
+       /* Free skb for failure cases */
+       if (skb) {
+               kfree_skb(skb);
+       }
+
+       return err;
+}
+#endif /* !WL_TWT && WL_TWT_HAL_IF */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+const struct nla_policy andr_wifi_attr_policy[ANDR_WIFI_ATTRIBUTE_MAX] = {
+       [ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET] = { .type = NLA_U32 },
+       [ANDR_WIFI_ATTRIBUTE_FEATURE_SET] = { .type = NLA_U32 },
+       [ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI] = { .type = NLA_NUL_STRING, .len = 3 },
+       [ANDR_WIFI_ATTRIBUTE_NODFS_SET] = { .type = NLA_U32 },
+       [ANDR_WIFI_ATTRIBUTE_COUNTRY] = { .type = NLA_NUL_STRING, .len = 3 },
+       [ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE] = { .type = NLA_U8 },
+       [ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE] = { .type = NLA_U32 },
+       [ANDR_WIFI_ATTRIBUTE_LATENCY_MODE] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [ANDR_WIFI_ATTRIBUTE_RANDOM_MAC] = { .type = NLA_U32 },
+       [ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO] = { .type = NLA_S8 },
+       [ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION] = { .type = NLA_S8 },
+       [ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW] = { .type = NLA_U32 },
+       [ANDR_WIFI_ATTRIBUTE_VOIP_MODE] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER] = { .type = NLA_U32, .len = sizeof(uint32) },
+};
+
+const struct nla_policy dump_buf_policy[DUMP_BUF_ATTR_MAX] = {
+       [DUMP_BUF_ATTR_MEMDUMP] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_SSSR_C0_D11_BEFORE] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_SSSR_C0_D11_AFTER] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_SSSR_C1_D11_BEFORE] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_SSSR_C1_D11_AFTER] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_SSSR_C2_D11_BEFORE] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_SSSR_C2_D11_AFTER] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_SSSR_DIG_BEFORE] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_SSSR_DIG_AFTER] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_TIMESTAMP] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_GENERAL_LOG] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_ECNTRS] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_SPECIAL_LOG] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_DHD_DUMP] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_EXT_TRAP] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_HEALTH_CHK] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_PRESERVE_LOG] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_COOKIE] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_FLOWRING_DUMP] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_PKTLOG] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_PKTLOG_DEBUG] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_STATUS_LOG] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_AXI_ERROR] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_RTT_LOG] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_SDTC_ETB_DUMP] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_PKTID_MAP_LOG] = { .type = NLA_BINARY },
+       [DUMP_BUF_ATTR_PKTID_UNMAP_LOG] = { .type = NLA_BINARY },
+};
+
+const struct nla_policy brcm_drv_attr_policy[BRCM_ATTR_DRIVER_MAX] = {
+       [BRCM_ATTR_DRIVER_CMD] = { .type = NLA_NUL_STRING },
+       [BRCM_ATTR_DRIVER_KEY_PMK] = { .type = NLA_BINARY, .len = WSEC_MAX_PASSPHRASE_LEN },
+       [BRCM_ATTR_DRIVER_FEATURE_FLAGS] = { .type = NLA_BINARY, .len =
+       ((BRCM_WLAN_VENDOR_FEATURES_MAX / 8) + 1) },
+       [BRCM_ATTR_DRIVER_RAND_MAC] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
+       [BRCM_ATTR_SAE_PWE] = { .type = NLA_U32 },
+};
+
+#ifdef RTT_SUPPORT
+const struct nla_policy rtt_attr_policy[RTT_ATTRIBUTE_MAX] = {
+       [RTT_ATTRIBUTE_TARGET_CNT] = { .type = NLA_U8 },
+       [RTT_ATTRIBUTE_TARGET_INFO] = { .type = NLA_NESTED },
+       [RTT_ATTRIBUTE_TARGET_MAC] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
+       [RTT_ATTRIBUTE_TARGET_TYPE] = { .type = NLA_U8 },
+       [RTT_ATTRIBUTE_TARGET_PEER] = { .type = NLA_U8 },
+       [RTT_ATTRIBUTE_TARGET_CHAN] = { .type = NLA_BINARY },
+       [RTT_ATTRIBUTE_TARGET_PERIOD] = { .type = NLA_U32 },
+       [RTT_ATTRIBUTE_TARGET_NUM_BURST] = { .type = NLA_U32 },
+       [RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST] = { .type = NLA_U32 },
+       [RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM] = { .type = NLA_U32 },
+       [RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR] = { .type = NLA_U32 },
+       [RTT_ATTRIBUTE_TARGET_LCI] = { .type = NLA_U8 },
+       [RTT_ATTRIBUTE_TARGET_LCR] = { .type = NLA_U8 },
+       [RTT_ATTRIBUTE_TARGET_BURST_DURATION] = { .type = NLA_U32 },
+       [RTT_ATTRIBUTE_TARGET_PREAMBLE] = { .type = NLA_U8 },
+       [RTT_ATTRIBUTE_TARGET_BW] = { .type = NLA_U8 },
+       [RTT_ATTRIBUTE_RESULTS_COMPLETE] = { .type = NLA_U32 },
+       [RTT_ATTRIBUTE_RESULTS_PER_TARGET] = { .type = NLA_NESTED },
+       [RTT_ATTRIBUTE_RESULT_CNT] = { .type = NLA_U32 },
+       [RTT_ATTRIBUTE_RESULT] = { .type = NLA_BINARY, .len = sizeof(rtt_result_t) },
+       [RTT_ATTRIBUTE_RESULT_DETAIL] = { .type = NLA_BINARY,
+       .len = sizeof(struct rtt_result_detail) },
+};
+#endif /* RTT_SUPPORT */
+
+#ifdef KEEP_ALIVE
+const struct nla_policy mkeep_alive_attr_policy[MKEEP_ALIVE_ATTRIBUTE_MAX] = {
+       [MKEEP_ALIVE_ATTRIBUTE_ID] = { .type = NLA_U8 },
+       [MKEEP_ALIVE_ATTRIBUTE_IP_PKT] = { .type = NLA_BINARY, .len = MKEEP_ALIVE_IP_PKT_MAX },
+       [MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN] = { .type = NLA_U16 },
+       [MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
+       [MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
+       [MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC] = { .type = NLA_U32 },
+       [MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE] = { .type = NLA_U16 }
+};
+#endif /* KEEP_ALIVE */
+#ifdef WL_NAN
+const struct nla_policy nan_attr_policy[NAN_ATTRIBUTE_MAX] = {
+       [NAN_ATTRIBUTE_2G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_5G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_CLUSTER_LOW] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_CLUSTER_HIGH] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_SID_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SUB_SID_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SDF_2G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SDF_5G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_HOP_COUNT_LIMIT] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RANDOM_TIME] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_MASTER_PREF] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_OUI] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_WARMUP_TIME] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_24G_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_5G_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_CONF_CLUSTER_VAL] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_DWELL_TIME] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SCAN_PERIOD] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_DWELL_TIME_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SCAN_PERIOD_5G] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_AVAIL_BIT_MAP] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_ENTRY_CONTROL] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RSSI_CLOSE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RSSI_MIDDLE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RSSI_PROXIMITY] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RSSI_CLOSE_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RSSI_MIDDLE_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RSSI_PROXIMITY_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RSSI_WINDOW_SIZE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_CIPHER_SUITE_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SCID_LEN] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_SCID] = { .type = NLA_BINARY, .len = MAX_SCID_LEN },
+       [NAN_ATTRIBUTE_2G_AWAKE_DW] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_5G_AWAKE_DW] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_DISC_IND_CFG] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
+       [NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_CMD_USE_NDPE] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_ENABLE_MERGE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_NSS] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_ENABLE_RANGING] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_DW_EARLY_TERM] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_TRANSAC_ID] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_PUBLISH_ID] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO] = { .type = NLA_BINARY, .len =
+       NAN_MAX_SERVICE_SPECIFIC_INFO_LEN },
+       [NAN_ATTRIBUTE_SUBSCRIBE_ID] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_SUBSCRIBE_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_PUBLISH_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_PUBLISH_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_PERIOD] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_TTL] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_SERVICE_NAME_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_SERVICE_NAME] = { .type = NLA_BINARY, .len = WL_NAN_SVC_HASH_LEN },
+       [NAN_ATTRIBUTE_PEER_ID] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_INST_ID] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_SUBSCRIBE_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SUBSCRIBE_MATCH] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_PUBLISH_MATCH] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SERVICERESPONSEFILTER] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_USESERVICERESPONSEFILTER] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_RX_MATCH_FILTER] = { .type = NLA_BINARY, .len = MAX_MATCH_FILTER_LEN },
+       [NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_TX_MATCH_FILTER] = { .type = NLA_BINARY, .len = MAX_MATCH_FILTER_LEN },
+       [NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES] = { .type = NLA_U16, .len = sizeof(uint16) },
+       [NAN_ATTRIBUTE_MAC_ADDR_LIST] = { .type = NLA_BINARY, .len =
+       (NAN_SRF_MAX_MAC*ETHER_ADDR_LEN) },
+       [NAN_ATTRIBUTE_TX_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SDE_CONTROL_SECURITY] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RECV_IND_CFG] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_KEY_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_KEY_LEN] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_KEY_DATA] = { .type = NLA_BINARY, .len = NAN_MAX_PMK_LEN },
+       [NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN] = { .type = NLA_U16, .len =
+       sizeof(uint16) },
+       [NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO] = { .type = NLA_BINARY, .len =
+       MAX_SDEA_SVC_INFO_LEN },
+       [NAN_ATTRIBUTE_SECURITY] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RANGING_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_RANGING_INDICATION] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_SVC_RESPONDER_POLICY] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_NDP_ID] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_IFACE] = { .type = NLA_BINARY, .len = IFNAMSIZ+1 },
+       [NAN_ATTRIBUTE_QOS] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_RSP_CODE] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_INST_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
+       [NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
+       [NAN_ATTRIBUTE_IF_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
+       [NAN_ATTRIBUTE_NO_CONFIG_AVAIL] = { .type = NLA_U8, .len = sizeof(uint8) },
+       [NAN_ATTRIBUTE_CHANNEL_INFO] = { .type = NLA_BINARY, .len =
+       sizeof(nan_channel_info_t) * NAN_MAX_CHANNEL_INFO_SUPPORTED },
+       [NAN_ATTRIBUTE_NUM_CHANNELS] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_INSTANT_MODE_ENABLE] = { .type = NLA_U32, .len = sizeof(uint32) },
+       [NAN_ATTRIBUTE_INSTANT_COMM_CHAN] = { .type = NLA_U32, .len = sizeof(uint32) },
+};
+#endif /* WL_NAN */
+
+const struct nla_policy gscan_attr_policy[GSCAN_ATTRIBUTE_MAX] = {
+       [GSCAN_ATTRIBUTE_BAND] = { .type = NLA_U32 },
+       [GSCAN_ATTRIBUTE_NUM_CHANNELS] = { .type = NLA_U32 },
+       [GSCAN_ATTRIBUTE_CHANNEL_LIST] = { .type = NLA_BINARY },
+       [GSCAN_ATTRIBUTE_WHITELIST_SSID] = { .type = NLA_BINARY, .len = IEEE80211_MAX_SSID_LEN },
+       [GSCAN_ATTRIBUTE_NUM_WL_SSID] = { .type = NLA_U32 },
+       [GSCAN_ATTRIBUTE_WL_SSID_LEN] = { .type = NLA_U32 },
+       [GSCAN_ATTRIBUTE_WL_SSID_FLUSH] = { .type = NLA_U32 },
+       [GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM] = { .type = NLA_NESTED },
+       /* length is sizeof(wl_ssid_whitelist_t) * MAX_SSID_WHITELIST_NUM */
+       [GSCAN_ATTRIBUTE_NUM_BSSID] = { .type = NLA_U32 },
+       [GSCAN_ATTRIBUTE_BSSID_PREF_LIST] = { .type = NLA_NESTED },
+       /* length is sizeof(wl_bssid_pref_list_t) * MAX_BSSID_PREF_LIST_NUM */
+       [GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH] = { .type = NLA_U32 },
+       [GSCAN_ATTRIBUTE_BSSID_PREF] = { .type = NLA_BINARY, .len = ETH_ALEN },
+       [GSCAN_ATTRIBUTE_RSSI_MODIFIER] = { .type = NLA_U32 },
+       [GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH] = { .type = NLA_U32 },
+       [GSCAN_ATTRIBUTE_BLACKLIST_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
+       [GSCAN_ATTRIBUTE_ROAM_STATE_SET] = { .type = NLA_U32 },
+};
+
+#ifdef DHD_WAKE_STATUS
+const struct nla_policy wake_stat_attr_policy[WAKE_STAT_ATTRIBUTE_MAX] = {
+       [WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT] = { .type = NLA_U32 },
+#ifdef CUSTOM_WAKE_REASON_STATS
+       [WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE] = { .type = NLA_BINARY,
+       .len = (MAX_WAKE_REASON_STATS * sizeof(int))},
+#else
+       [WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE] = { .type = NLA_BINARY,
+       .len = (WLC_E_LAST * sizeof(uint))},
+#endif /* CUSTOM_WAKE_REASON_STATS */
+       [WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT_USED] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 },
+       [WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 },
+};
+#endif /* DHD_WAKE_STATUS */
+
+#ifdef RSSI_MONITOR_SUPPORT
+const struct nla_policy rssi_monitor_attr_policy[RSSI_MONITOR_ATTRIBUTE_MAX] = {
+       [RSSI_MONITOR_ATTRIBUTE_MAX_RSSI] = { .type = NLA_U32 },
+       [RSSI_MONITOR_ATTRIBUTE_MIN_RSSI] = { .type = NLA_U32 },
+       [RSSI_MONITOR_ATTRIBUTE_START] = { .type = NLA_U32 }
+};
+#endif /* RSSI_MONITOR_SUPPORT */
+
+
+const struct nla_policy hal_start_attr_policy[SET_HAL_START_ATTRIBUTE_MAX] = {
+       [0] = { .strict_start_type = 0 },
+       [SET_HAL_START_ATTRIBUTE_DEINIT] = { .type = NLA_UNSPEC },
+       [SET_HAL_START_ATTRIBUTE_PRE_INIT] = { .type = NLA_NUL_STRING },
+       [SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID] = { .type = NLA_U32 },
+};
+
+const struct nla_policy andr_dbg_policy[DEBUG_ATTRIBUTE_MAX] = {
+       [DEBUG_ATTRIBUTE_GET_DRIVER] = { .type = NLA_BINARY },
+       [DEBUG_ATTRIBUTE_GET_FW] = { .type = NLA_BINARY },
+       [DEBUG_ATTRIBUTE_RING_ID] = { .type = NLA_U32 },
+       [DEBUG_ATTRIBUTE_RING_NAME] = { .type = NLA_NUL_STRING },
+       [DEBUG_ATTRIBUTE_RING_FLAGS] = { .type = NLA_U32 },
+       [DEBUG_ATTRIBUTE_LOG_LEVEL] = { .type = NLA_U32 },
+       [DEBUG_ATTRIBUTE_LOG_TIME_INTVAL] = { .type = NLA_U32 },
+       [DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE] = { .type = NLA_U32 },
+       [DEBUG_ATTRIBUTE_FW_DUMP_LEN] = { .type = NLA_U32 },
+       [DEBUG_ATTRIBUTE_FW_DUMP_DATA] = { .type = NLA_U64 },
+       [DEBUG_ATTRIBUTE_FW_ERR_CODE] = { .type = NLA_U32 },
+       [DEBUG_ATTRIBUTE_RING_DATA] = { .type = NLA_BINARY },
+       [DEBUG_ATTRIBUTE_RING_STATUS] = { .type = NLA_BINARY },
+       [DEBUG_ATTRIBUTE_RING_NUM] = { .type = NLA_U32 },
+       [DEBUG_ATTRIBUTE_DRIVER_DUMP_LEN] = { .type = NLA_U32 },
+       [DEBUG_ATTRIBUTE_DRIVER_DUMP_DATA] = { .type = NLA_BINARY },
+       [DEBUG_ATTRIBUTE_PKT_FATE_NUM] = { .type = NLA_U32 },
+       [DEBUG_ATTRIBUTE_PKT_FATE_DATA] = { .type = NLA_U64 },
+       [DEBUG_ATTRIBUTE_HANG_REASON] = { .type = NLA_BINARY },
+};
+
+#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF)
+const struct nla_policy andr_twt_attr_policy[ANDR_TWT_ATTR_MAX] = {
+       [ANDR_TWT_ATTR_NONE] = { .strict_start_type = 0 },
+       [ANDR_TWT_ATTR_CONFIG_ID] = { .type = NLA_U8 },
+       [ANDR_TWT_ATTR_NEGOTIATION_TYPE] = { .type = NLA_U8 },
+       [ANDR_TWT_ATTR_TRIGGER_TYPE] = { .type = NLA_U8 },
+       [ANDR_TWT_ATTR_WAKE_DURATION] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_WAKE_INTERVAL] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_WAKE_INTERVAL_MIN] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_WAKE_INTERVAL_MAX] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_WAKE_DURATION_MIN] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_WAKE_DURATION_MAX] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_AVG_PKT_SIZE] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_AVG_PKT_NUM] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_WAKETIME_OFFSET] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_ALL_TWT] = { .type = NLA_U8 },
+       [ANDR_TWT_ATTR_RESUME_TIME] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_AVG_EOSP_DUR] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_EOSP_CNT] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_NUM_SP] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_DEVICE_CAP] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_PEER_CAP] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_STATUS] = { .type = NLA_U8 },
+       [ANDR_TWT_ATTR_REASON_CODE] = { .type = NLA_U8 },
+       [ANDR_TWT_ATTR_TWT_RESUMED] = { .type = NLA_U8 },
+       [ANDR_TWT_ATTR_TWT_NOTIFICATION] = { .type = NLA_U8 },
+       [ANDR_TWT_ATTR_SUB_EVENT] = { .type = NLA_U8 },
+       [ANDR_TWT_ATTR_NUM_PEER_STATS] = { .type = NLA_U8 },
+       [ANDR_TWT_ATTR_AVG_PKT_NUM_TX] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_AVG_PKT_SIZE_TX] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_AVG_PKT_NUM_RX] = { .type = NLA_U32 },
+       [ANDR_TWT_ATTR_AVG_PKT_SIZE_RX] = { .type = NLA_U32 },
+};
+#endif /* !WL_TWT && WL_TWT_HAL_IF */
+
+#endif /* LINUX_VERSION >= 5.3 */
+
+static struct wiphy_vendor_command wl_vendor_cmds [] = {
+       {
+               {
+                       .vendor_id = OUI_BRCM,
+                       .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_priv_string_handler,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = brcm_drv_attr_policy,
+               .maxattr = BRCM_ATTR_DRIVER_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+#ifdef BCM_PRIV_CMD_SUPPORT
+       {
+               {
+                       .vendor_id = OUI_BRCM,
+                       .subcmd = BRCM_VENDOR_SCMD_BCM_STR
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_priv_bcm_handler,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = brcm_drv_attr_policy,
+               .maxattr = BRCM_ATTR_DRIVER_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+#endif /* BCM_PRIV_CMD_SUPPORT */
+#if defined(WL_SAE) || defined(WL_CLIENT_SAE)
+       {
+               {
+                       .vendor_id = OUI_BRCM,
+                       .subcmd = BRCM_VENDOR_SCMD_BCM_PSK
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_set_sae_password
+       },
+#endif /* WL_SAE || WL_CLIENT_SAE */
+       {
+               {
+                       .vendor_id = OUI_BRCM,
+                       .subcmd = BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_connect_params_handler,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = brcm_drv_attr_policy,
+               .maxattr = BRCM_ATTR_DRIVER_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_BRCM,
+                       .subcmd = BRCM_VENDOR_SCMD_SET_START_AP_PARAMS
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_start_ap_params_handler,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = brcm_drv_attr_policy,
+               .maxattr = BRCM_ATTR_DRIVER_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+#ifdef GSCAN_SUPPORT
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_gscan_get_capabilities
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = GSCAN_SUBCMD_SET_CONFIG
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_set_scan_cfg
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_set_batch_scan_cfg
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_initiate_gscan
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_enable_full_scan_result
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = GSCAN_SUBCMD_SET_HOTLIST
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_hotlist_cfg
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_gscan_get_batch_results
+       },
+#endif /* GSCAN_SUPPORT */
+#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_gscan_get_channel_list,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = gscan_attr_policy,
+               .maxattr = GSCAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
+#ifdef RTT_SUPPORT
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = RTT_SUBCMD_SET_CONFIG
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_rtt_set_config,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = rtt_attr_policy,
+               .maxattr = RTT_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = RTT_SUBCMD_CANCEL_CONFIG
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_rtt_cancel_config,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = rtt_attr_policy,
+               .maxattr = RTT_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = RTT_SUBCMD_GETCAPABILITY
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_rtt_get_capability,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = rtt_attr_policy,
+               .maxattr = RTT_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = RTT_SUBCMD_GETAVAILCHANNEL
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_rtt_get_responder_info,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = rtt_attr_policy,
+               .maxattr = RTT_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = RTT_SUBCMD_SET_RESPONDER
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_rtt_set_responder,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = rtt_attr_policy,
+               .maxattr = RTT_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = RTT_SUBCMD_CANCEL_RESPONDER
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_rtt_cancel_responder,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = rtt_attr_policy,
+               .maxattr = RTT_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+#endif /* RTT_SUPPORT */
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_get_feature_set,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_wifi_attr_policy,
+               .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_get_feature_set_matrix,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_wifi_attr_policy,
+               .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_WIFI_RANDOM_MAC_OUI
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_set_rand_mac_oui,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_wifi_attr_policy,
+               .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+#ifdef CUSTOM_FORCE_NODFS_FLAG
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_WIFI_NODFS_CHANNELS
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_set_nodfs_flag,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_wifi_attr_policy,
+               .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+#endif /* CUSTOM_FORCE_NODFS_FLAG */
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_WIFI_SET_COUNTRY
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_set_country,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_wifi_attr_policy,
+               .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+#ifdef LINKSTAT_SUPPORT
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = LSTATS_SUBCMD_GET_INFO
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_lstats_get_info
+       },
+#endif /* LINKSTAT_SUPPORT */
+
+#ifdef GSCAN_SUPPORT
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_epno_cfg
+
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_set_lazy_roam_cfg
+
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
                .doit = wl_cfgvendor_enable_lazy_roam
 
        },
@@ -9294,7 +10465,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_ssid_whitelist
+               .doit = wl_cfgvendor_set_ssid_whitelist,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = gscan_attr_policy,
+               .maxattr = GSCAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
 
        },
        {
@@ -9303,7 +10478,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_bssid_blacklist
+               .doit = wl_cfgvendor_set_bssid_blacklist,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = gscan_attr_policy,
+               .maxattr = GSCAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* GSCAN_SUPPORT || ROAMEXP_SUPPORT */
 #ifdef ROAMEXP_SUPPORT
@@ -9313,7 +10492,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = WIFI_SUBCMD_FW_ROAM_POLICY
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_fw_roaming_state
+               .doit = wl_cfgvendor_set_fw_roaming_state,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = gscan_attr_policy,
+               .maxattr = GSCAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9330,7 +10513,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_GET_VER
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_dbg_get_version
+               .doit = wl_cfgvendor_dbg_get_version,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_dbg_policy,
+               .maxattr = DEBUG_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #ifdef DHD_LOG_DUMP
        {
@@ -9339,7 +10526,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_GET_FILE_DUMP_BUF
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_dbg_file_dump
+               .doit = wl_cfgvendor_dbg_file_dump,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = dump_buf_policy,
+               .maxattr = DUMP_BUF_ATTR_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* DHD_LOG_DUMP */
 
@@ -9358,7 +10549,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_GET_MEM_DUMP
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_dbg_get_mem_dump
+               .doit = wl_cfgvendor_dbg_get_mem_dump,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_dbg_policy,
+               .maxattr = DEBUG_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9366,7 +10561,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_START_LOGGING
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_dbg_start_logging
+               .doit = wl_cfgvendor_dbg_start_logging,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_dbg_policy,
+               .maxattr = DEBUG_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9382,7 +10581,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_GET_RING_STATUS
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_dbg_get_ring_status
+               .doit = wl_cfgvendor_dbg_get_ring_status,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_dbg_policy,
+               .maxattr = DEBUG_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9390,7 +10593,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_GET_RING_DATA
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_dbg_get_ring_data
+               .doit = wl_cfgvendor_dbg_get_ring_data,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_dbg_policy,
+               .maxattr = DEBUG_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* DEBUGABILITY */
        {
@@ -9416,7 +10623,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_GET_TX_PKT_FATES
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_dbg_get_tx_pkt_fates
+               .doit = wl_cfgvendor_dbg_get_tx_pkt_fates,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_dbg_policy,
+               .maxattr = DEBUG_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9424,7 +10635,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_GET_RX_PKT_FATES
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_dbg_get_rx_pkt_fates
+               .doit = wl_cfgvendor_dbg_get_rx_pkt_fates,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_dbg_policy,
+               .maxattr = DEBUG_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* DBG_PKT_MON */
 #ifdef KEEP_ALIVE
@@ -9434,7 +10649,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_start_mkeep_alive
+               .doit = wl_cfgvendor_start_mkeep_alive,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = mkeep_alive_attr_policy,
+               .maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9442,7 +10661,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_stop_mkeep_alive
+               .doit = wl_cfgvendor_stop_mkeep_alive,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = mkeep_alive_attr_policy,
+               .maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* KEEP_ALIVE */
 #ifdef WL_NAN
@@ -9452,7 +10675,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_ENABLE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_start_handler
+               .doit = wl_cfgvendor_nan_start_handler,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9460,7 +10687,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_DISABLE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_stop_handler
+               .doit = wl_cfgvendor_nan_stop_handler,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9468,7 +10699,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_CONFIG
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_config_handler
+               .doit = wl_cfgvendor_nan_config_handler,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9476,7 +10711,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_REQUEST_PUBLISH
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_req_publish
+               .doit = wl_cfgvendor_nan_req_publish,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9484,7 +10723,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_REQUEST_SUBSCRIBE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_req_subscribe
+               .doit = wl_cfgvendor_nan_req_subscribe,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9492,7 +10735,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_CANCEL_PUBLISH
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_cancel_publish
+               .doit = wl_cfgvendor_nan_cancel_publish,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9500,7 +10747,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_CANCEL_SUBSCRIBE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_cancel_subscribe
+               .doit = wl_cfgvendor_nan_cancel_subscribe,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9508,7 +10759,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_TRANSMIT
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_transmit
+               .doit = wl_cfgvendor_nan_transmit,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9525,7 +10780,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_data_path_iface_create
+               .doit = wl_cfgvendor_nan_data_path_iface_create,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9533,7 +10792,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_data_path_iface_delete
+               .doit = wl_cfgvendor_nan_data_path_iface_delete,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9541,7 +10804,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_REQUEST
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_data_path_request
+               .doit = wl_cfgvendor_nan_data_path_request,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9549,7 +10816,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_RESPONSE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_data_path_response
+               .doit = wl_cfgvendor_nan_data_path_response,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9557,7 +10828,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_END
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_data_path_end
+               .doit = wl_cfgvendor_nan_data_path_end,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #ifdef WL_NAN_DISC_CACHE
        {
@@ -9566,7 +10841,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_SEC_INFO
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_data_path_sec_info
+               .doit = wl_cfgvendor_nan_data_path_sec_info,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* WL_NAN_DISC_CACHE */
        {
@@ -9583,7 +10862,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = NAN_WIFI_SUBCMD_ENABLE_MERGE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_nan_enable_merge
+               .doit = wl_cfgvendor_nan_enable_merge,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = nan_attr_policy,
+               .maxattr = NAN_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* WL_NAN */
 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
@@ -9593,7 +10876,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = APF_SUBCMD_GET_CAPABILITIES
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_apf_get_capabilities
+               .doit = wl_cfgvendor_apf_get_capabilities,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = apf_atrribute_policy,
+               .maxattr = APF_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 
        {
@@ -9602,7 +10889,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = APF_SUBCMD_SET_FILTER
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_apf_set_filter
+               .doit = wl_cfgvendor_apf_set_filter,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = apf_atrribute_policy,
+               .maxattr = APF_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* PKT_FILTER_SUPPORT && APF */
 #ifdef NDO_CONFIG_SUPPORT
@@ -9612,7 +10903,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = WIFI_SUBCMD_CONFIG_ND_OFFLOAD
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_configure_nd_offload
+               .doit = wl_cfgvendor_configure_nd_offload,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_wifi_attr_policy,
+               .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* NDO_CONFIG_SUPPORT */
 #ifdef RSSI_MONITOR_SUPPORT
@@ -9622,7 +10917,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_rssi_monitor
+               .doit = wl_cfgvendor_set_rssi_monitor,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = rssi_monitor_attr_policy,
+               .maxattr = RSSI_MONITOR_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* RSSI_MONITOR_SUPPORT */
 #ifdef DHD_WAKE_STATUS
@@ -9632,7 +10931,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_GET_WAKE_REASON_STATS
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_get_wake_reason_stats
+               .doit = wl_cfgvendor_get_wake_reason_stats,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = wake_stat_attr_policy,
+               .maxattr = WAKE_STAT_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* DHD_WAKE_STATUS */
 #ifdef DHDTCPACK_SUPPRESS
@@ -9642,7 +10945,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = WIFI_SUBCMD_CONFIG_TCPACK_SUP
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_tcpack_sup_mode
+               .doit = wl_cfgvendor_set_tcpack_sup_mode,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_wifi_attr_policy,
+               .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* DHDTCPACK_SUPPRESS */
 #if !defined(BCMSUP_4WAY_HANDSHAKE) || (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
@@ -9652,7 +10959,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = BRCM_VENDOR_SCMD_SET_PMK
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_pmk
+               .doit = wl_cfgvendor_set_pmk,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = brcm_drv_attr_policy,
+               .maxattr = BRCM_ATTR_DRIVER_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* !BCMSUP_4WAY_HANDSHAKE || LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */
        {
@@ -9661,7 +10972,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = BRCM_VENDOR_SCMD_GET_FEATURES
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_get_driver_feature
+               .doit = wl_cfgvendor_get_driver_feature,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = brcm_drv_attr_policy,
+               .maxattr = BRCM_ATTR_DRIVER_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT)
        {
@@ -9680,7 +10995,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_SET_HAL_START
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_hal_started
+               .doit = wl_cfgvendor_set_hal_started,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = hal_start_attr_policy,
+               .maxattr = SET_HAL_START_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
        {
                {
@@ -9696,7 +11015,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = DEBUG_SET_HAL_PID
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_hal_pid
+               .doit = wl_cfgvendor_set_hal_pid,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = hal_start_attr_policy,
+               .maxattr = SET_HAL_START_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* WL_CFG80211 */
 #ifdef WL_LATENCY_MODE
@@ -9706,7 +11029,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = WIFI_SUBCMD_SET_LATENCY_MODE
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
-               .doit = wl_cfgvendor_set_latency_mode
+               .doit = wl_cfgvendor_set_latency_mode,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_wifi_attr_policy,
+               .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* WL_LATENCY_MODE */
 #ifdef WL_P2P_RAND
@@ -9716,7 +11043,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = BRCM_VENDOR_SCMD_SET_MAC
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV,
-               .doit = wl_cfgvendor_set_p2p_rand_mac
+               .doit = wl_cfgvendor_set_p2p_rand_mac,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = brcm_drv_attr_policy,
+               .maxattr = BRCM_ATTR_DRIVER_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        },
 #endif /* WL_P2P_RAND */
 #ifdef WL_SAR_TX_POWER
@@ -9726,9 +11057,87 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = {
                        .subcmd = WIFI_SUBCMD_TX_POWER_SCENARIO
                },
                .flags = WIPHY_VENDOR_CMD_NEED_WDEV,
-               .doit = wl_cfgvendor_tx_power_scenario
+               .doit = wl_cfgvendor_tx_power_scenario,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_wifi_attr_policy,
+               .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
+#endif /* LINUX_VERSION >= 5.3 */
        }
 #endif /* WL_SAR_TX_POWER */
+#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF)
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_TWT_SUBCMD_SETUP
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_twt_setup,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_twt_attr_policy,
+               .maxattr = ANDR_TWT_ATTR_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_TWT_SUBCMD_TEARDOWN
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_twt_teardown,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_twt_attr_policy,
+               .maxattr = ANDR_TWT_ATTR_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_TWT_SUBCMD_INFO_FRAME
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_twt_info_frame,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_twt_attr_policy,
+               .maxattr = ANDR_TWT_ATTR_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_TWT_SUBCMD_GET_CAP
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_twt_cap,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_twt_attr_policy,
+               .maxattr = ANDR_TWT_ATTR_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_TWT_SUBCMD_GET_STATS
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_twt_get_stats,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_twt_attr_policy,
+               .maxattr = ANDR_TWT_ATTR_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_TWT_SUBCMD_CLR_STATS
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_twt_clear_stats,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+               .policy = andr_twt_attr_policy,
+               .maxattr = ANDR_TWT_ATTR_MAX
+#endif /* LINUX_VERSION >= 5.3 */
+       },
+#endif /* !WL_TWT && WL_TWT_HAL_IF */
 
 };
 
@@ -9774,7 +11183,8 @@ static const struct  nl80211_vendor_cmd_info wl_vendor_events [] = {
                { OUI_BRCM, BRCM_VENDOR_EVENT_CU},
                { OUI_BRCM, BRCM_VENDOR_EVENT_WIPS},
                { OUI_GOOGLE, NAN_ASYNC_RESPONSE_DISABLED},
-               { OUI_BRCM, BRCM_VENDOR_EVENT_RCC_INFO}
+               { OUI_BRCM, BRCM_VENDOR_EVENT_RCC_INFO},
+               {OUI_BRCM, BRCM_VENDOR_EVENT_TWT}
 };
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
@@ -9786,7 +11196,9 @@ wl_cfgvendor_apply_cmd_policy(struct wiphy *wiphy)
 
        WL_INFORM(("Apply CMD_RAW_DATA policy\n"));
        for (i = 0; i < n_cmds; i++) {
-               wl_vendor_cmds[i].policy = VENDOR_CMD_RAW_DATA;
+               if (wl_vendor_cmds[i].policy == NULL) {
+                       wl_vendor_cmds[i].policy = VENDOR_CMD_RAW_DATA;
+               }
        }
 }
 #endif /* LINUX VER >= 5.3 */
index 581ab112c95209f2a2e166be518712cd123ed3ef..8826e6d69163230a790c9963b64a5fee176c331a 100755 (executable)
@@ -157,6 +157,10 @@ typedef enum {
        ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START =   0x1900,
        ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_END =     0x19FF,
 
+       /* define all TWT related commands between 0x2140 and 0x214F */
+       ANDROID_NL80211_SUBCMD_TWT_START        =       0x2140,
+       ANDROID_NL80211_SUBCMD_TWT_END          =       0x214F,
+
        /* This is reserved for future usage */
 
 } ANDROID_VENDOR_SUB_COMMAND;
@@ -245,6 +249,13 @@ enum andr_vendor_subcmd {
        APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START,
        APF_SUBCMD_SET_FILTER,
        WIFI_SUBCMD_TX_POWER_SCENARIO = ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START,
+
+       ANDR_TWT_SUBCMD_GET_CAP = ANDROID_NL80211_SUBCMD_TWT_START,
+       ANDR_TWT_SUBCMD_SETUP,
+       ANDR_TWT_SUBCMD_TEARDOWN,
+       ANDR_TWT_SUBCMD_INFO_FRAME,
+       ANDR_TWT_SUBCMD_GET_STATS,
+       ANDR_TWT_SUBCMD_CLR_STATS,
        /* Add more sub commands here */
        VENDOR_SUBCMD_MAX
 };
@@ -406,11 +417,13 @@ enum rtt_attributes {
        RTT_ATTRIBUTE_TARGET_BURST_DURATION,
        RTT_ATTRIBUTE_TARGET_PREAMBLE,
        RTT_ATTRIBUTE_TARGET_BW,
-       RTT_ATTRIBUTE_RESULTS_COMPLETE = 30,
+       RTT_ATTRIBUTE_RESULTS_COMPLETE,
        RTT_ATTRIBUTE_RESULTS_PER_TARGET,
        RTT_ATTRIBUTE_RESULT_CNT,
        RTT_ATTRIBUTE_RESULT,
-       RTT_ATTRIBUTE_RESULT_DETAIL
+       RTT_ATTRIBUTE_RESULT_DETAIL,
+       /* Add any new RTT_ATTRIBUTE prior to RTT_ATTRIBUTE_MAX */
+       RTT_ATTRIBUTE_MAX
 };
 
 enum wifi_rssi_monitor_attr {
@@ -419,7 +432,8 @@ enum wifi_rssi_monitor_attr {
 #endif
        RSSI_MONITOR_ATTRIBUTE_MAX_RSSI,
        RSSI_MONITOR_ATTRIBUTE_MIN_RSSI,
-       RSSI_MONITOR_ATTRIBUTE_START
+       RSSI_MONITOR_ATTRIBUTE_START,
+       RSSI_MONITOR_ATTRIBUTE_MAX
 };
 
 enum wifi_sae_key_attr {
@@ -450,7 +464,9 @@ enum debug_attributes {
        DEBUG_ATTRIBUTE_DRIVER_DUMP_DATA,
        DEBUG_ATTRIBUTE_PKT_FATE_NUM,
        DEBUG_ATTRIBUTE_PKT_FATE_DATA,
-       DEBUG_ATTRIBUTE_HANG_REASON
+       DEBUG_ATTRIBUTE_HANG_REASON,
+       /* Please add new attributes from here to sync up old HAL */
+       DEBUG_ATTRIBUTE_MAX
 };
 
 typedef enum {
@@ -521,8 +537,12 @@ typedef enum {
        DUMP_BUF_ATTR_PKTLOG_DEBUG = 21,
        DUMP_BUF_ATTR_STATUS_LOG = 22,
        DUMP_BUF_ATTR_AXI_ERROR = 23,
-       DUMP_BUF_ATTR_RTT_LOG = 24
+       DUMP_BUF_ATTR_RTT_LOG = 24,
+       DUMP_BUF_ATTR_SDTC_ETB_DUMP = 25,
+       DUMP_BUF_ATTR_PKTID_MAP_LOG = 26,
+       DUMP_BUF_ATTR_PKTID_UNMAP_LOG = 27,
        /* Please add new attributes from here to sync up old HAL */
+       DUMP_BUF_ATTR_MAX
 } EWP_DUMP_CMD_ATTRIBUTE;
 
 enum mkeep_alive_attributes {
@@ -535,7 +555,8 @@ enum mkeep_alive_attributes {
        MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
        MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
        MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC,
-       MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE
+       MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE,
+       MKEEP_ALIVE_ATTRIBUTE_MAX
 };
 
 typedef enum wl_vendor_event {
@@ -586,7 +607,9 @@ typedef enum wl_vendor_event {
        BRCM_VENDOR_EVENT_CU                    = 38,
        BRCM_VENDOR_EVENT_WIPS                  = 39,
        NAN_ASYNC_RESPONSE_DISABLED             = 40,
-       BRCM_VENDOR_EVENT_RCC_INFO              = 41
+       BRCM_VENDOR_EVENT_RCC_INFO              = 41,
+       BRCM_VENDOR_EVENT_TWT                   = 43,
+       WL_VENDOR_EVENT_LAST
 } wl_vendor_event_t;
 
 enum andr_wifi_attr {
@@ -602,13 +625,20 @@ enum andr_wifi_attr {
        ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE,
        ANDR_WIFI_ATTRIBUTE_LATENCY_MODE,
        ANDR_WIFI_ATTRIBUTE_RANDOM_MAC,
-       ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO
+       ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO,
+       ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION,
+       ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW,
+       ANDR_WIFI_ATTRIBUTE_VOIP_MODE,
+       ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER,
+       /* Any new ANDR_WIFI attribute add prior to the ANDR_WIFI_ATTRIBUTE_MAX */
+       ANDR_WIFI_ATTRIBUTE_MAX
 };
 enum apf_attributes {
        APF_ATTRIBUTE_VERSION,
        APF_ATTRIBUTE_MAX_LEN,
        APF_ATTRIBUTE_PROGRAM,
-       APF_ATTRIBUTE_PROGRAM_LEN
+       APF_ATTRIBUTE_PROGRAM_LEN,
+       APF_ATTRIBUTE_MAX
 };
 
 typedef enum wl_vendor_gscan_attribute {
@@ -664,7 +694,10 @@ enum wake_stat_attributes {
        WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS,
        WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
        WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
-       WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT
+       WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT,
+       WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO,
+       /* Please add new attributes from here to sync up old HAL */
+       WAKE_STAT_ATTRIBUTE_MAX
 };
 
 typedef struct rx_data_cnt_details_t {
@@ -731,9 +764,91 @@ typedef struct wifi_roaming_capabilities {
 typedef enum {
        SET_HAL_START_ATTRIBUTE_DEINIT = 0x0001,
        SET_HAL_START_ATTRIBUTE_PRE_INIT = 0x0002,
-       SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID = 0x0003
+       SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID = 0x0003,
+       /* Add any new HAL_START attribute prior to SET_HAL_START_ATTRIBUTE_MAX */
+       SET_HAL_START_ATTRIBUTE_MAX
 } SET_HAL_START_ATTRIBUTE;
 
+#ifdef WL_TWT
+typedef enum {
+       WIFI_TWT_EVENT_SETUP    = 1,
+       WIFI_TWT_EVENT_TEARDOWN = 2,
+       WIFI_TWT_EVENT_INFO_FRM = 3,
+       WIFI_TWT_EVENT_NOTIFY   = 4
+} wifi_twt_sub_event;
+
+typedef enum {
+       WIFI_TWT_ATTR_NONE              = 0,
+       WIFI_TWT_ATTR_SUB_EVENT         = 1,
+       WIFI_TWT_ATTR_REASON_CODE       = 2,
+       WIFI_TWT_ATTR_STATUS            = 3,
+       WIFI_TWT_ATTR_SETUP_CMD         = 4,
+       WIFI_TWT_ATTR_FLOW_FLAGS        = 5,
+       WIFI_TWT_ATTR_FLOW_ID           = 6,
+       WIFI_TWT_ATTR_CHANNEL           = 7,
+       WIFI_TWT_ATTR_NEGOTIATION_TYPE  = 8,
+       WIFI_TWT_ATTR_WAKETIME_H        = 9,
+       WIFI_TWT_ATTR_WAKETIME_L        = 10,
+       WIFI_TWT_ATTR_WAKE_DURATION     = 11,
+       WIFI_TWT_ATTR_WAKE_INTERVAL     = 12,
+       WIFI_TWT_ATTR_BID               = 13,
+       WIFI_TWT_ATTR_ALLTWT            = 14,
+       WIFI_TWT_ATTR_NEXT_TWT_H        = 15,
+       WIFI_TWT_ATTR_NEXT_TWT_L        = 16,
+       WIFI_TWT_ATTR_CONFIG_ID         = 17,
+       WIFI_TWT_ATTR_NOTIFICATION      = 18,
+       WIFI_TWT_ATTR_FLOW_TYPE         = 19,
+       WIFI_TWT_ATTR_TRIGGER_TYPE      = 20,
+
+       WIFI_TWT_ATTR_MAX
+} wifi_twt_attribute;
+#endif /* WL_TWT */
+
+#ifdef WL_TWT_HAL_IF
+#define BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN   500
+
+typedef enum {
+       ANDR_TWT_ATTR_NONE              = 0,
+       ANDR_TWT_ATTR_CONFIG_ID         = 1,
+       ANDR_TWT_ATTR_NEGOTIATION_TYPE  = 2,
+       ANDR_TWT_ATTR_TRIGGER_TYPE      = 3,
+       ANDR_TWT_ATTR_WAKE_DURATION     = 4,
+       ANDR_TWT_ATTR_WAKE_INTERVAL     = 5,
+       ANDR_TWT_ATTR_WAKE_INTERVAL_MIN = 6,
+       ANDR_TWT_ATTR_WAKE_INTERVAL_MAX = 7,
+       ANDR_TWT_ATTR_WAKE_DURATION_MIN = 8,
+       ANDR_TWT_ATTR_WAKE_DURATION_MAX = 9,
+       ANDR_TWT_ATTR_AVG_PKT_SIZE      = 10,
+       ANDR_TWT_ATTR_AVG_PKT_NUM       = 11,
+       ANDR_TWT_ATTR_WAKETIME_OFFSET   = 12,
+       ANDR_TWT_ATTR_ALL_TWT           = 13,
+       ANDR_TWT_ATTR_RESUME_TIME       = 14,
+       ANDR_TWT_ATTR_AVG_EOSP_DUR      = 15,
+       ANDR_TWT_ATTR_EOSP_CNT          = 16,
+       ANDR_TWT_ATTR_NUM_SP            = 17,
+       ANDR_TWT_ATTR_DEVICE_CAP        = 18,
+       ANDR_TWT_ATTR_PEER_CAP          = 19,
+       ANDR_TWT_ATTR_STATUS            = 20,
+       ANDR_TWT_ATTR_REASON_CODE       = 21,
+       ANDR_TWT_ATTR_TWT_RESUMED       = 22,
+       ANDR_TWT_ATTR_TWT_NOTIFICATION  = 23,
+       ANDR_TWT_ATTR_SUB_EVENT         = 24,
+       ANDR_TWT_ATTR_NUM_PEER_STATS    = 25,
+       ANDR_TWT_ATTR_AVG_PKT_NUM_TX    = 26,
+       ANDR_TWT_ATTR_AVG_PKT_SIZE_TX   = 27,
+       ANDR_TWT_ATTR_AVG_PKT_NUM_RX    = 28,
+       ANDR_TWT_ATTR_AVG_PKT_SIZE_RX   = 29,
+       ANDR_TWT_ATTR_MAX
+} andr_twt_attribute;
+
+typedef enum {
+       ANDR_TWT_EVENT_SETUP    = 1,
+       ANDR_TWT_EVENT_TEARDOWN = 2,
+       ANDR_TWT_EVENT_INFO_FRM = 3,
+       ANDR_TWT_EVENT_NOTIFY   = 4
+} andr_twt_sub_event;
+#endif /* WL_TWT_HAL_IF */
+
 /* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */
 #define BRCM_VENDOR_SCMD_CAPA  "cap"
 #define MEMDUMP_PATH_LEN       128
index e9a1d76c3161068be9fb215e5d9a29b312e68d16..f5d6910c071a6f9a917d3e481b0756f2bb9cc1ee 100755 (executable)
@@ -1548,37 +1548,32 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
 #if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL)
        dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
 #endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */
-#ifdef WL_EXT_IAPSTA
-       enum nl80211_band band;
-       s32 _chan;
-#endif /* WL_EXT_IAPSTA */
        u16 center_freq = chan->center_freq;
 
        dev = ndev_to_wlc_ndev(dev, cfg);
 #ifdef WL_EXT_IAPSTA
-       _chan = ieee80211_frequency_to_channel(chan->center_freq);
        if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
                        dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
                u16 wl_iftype = 0;
                u16 wl_mode = 0;
+
+               chspec = wl_freq_to_chanspec(chan->center_freq);
                if (cfg80211_to_wl_iftype(dev->ieee80211_ptr->iftype,
                                &wl_iftype, &wl_mode) < 0) {
                        WL_ERR(("Unknown interface type:0x%x\n", dev->ieee80211_ptr->iftype));
                        return -EINVAL;
                }
                wl_ext_iapsta_update_iftype(dev, wl_iftype);
-               _chan = wl_ext_iapsta_update_channel(dev, _chan);
-       }
-       if (CHANNEL_IS_5G(_chan))
-               band = NL80211_BAND_5GHZ;
-       else
-               band = NL80211_BAND_2GHZ;
-       center_freq = ieee80211_channel_to_frequency(_chan, band);
+               chspec = wl_ext_iapsta_update_channel(dev, chspec);
+               center_freq = wl_channel_to_frequency(wf_chspec_primary20_chan(chspec),
+                       CHSPEC_BAND(chspec));
+       } else
 #endif
        chspec = wl_freq_to_chanspec(center_freq);
 
-       WL_MSG(dev->name, "netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
-               dev->ifindex, channel_type, CHSPEC_CHANNEL(chspec));
+       WL_MSG(dev->name, "netdev_ifidx(%d) chan_type(%d) target channel(%s-%d %sMHz)\n",
+               dev->ifindex, channel_type, CHSPEC2BANDSTR(chspec),
+               CHSPEC_CHANNEL(chspec), wf_chspec_to_bw_str(chspec));
 
 #ifdef WL_P2P_6G
        if (!(cfg->p2p_6g_enabled)) {
@@ -2775,7 +2770,7 @@ wl_cfg80211_set_ap_role(
        dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
 #endif /* WLEASYMESH */
 
-       new_chip = wl_new_chip_check(dev);
+       new_chip = dhd_conf_new_chip_check(cfg->pub);
 
        if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
@@ -2806,7 +2801,7 @@ wl_cfg80211_set_ap_role(
        }
 #ifdef WLEASYMESH
        else if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
-               WL_MSG(dev->name, "Getting AP mode ok, set map and dwds");
+               WL_MSG(dev->name, "Getting AP mode ok, set map and dwds\n");
                err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
                if (err < 0) {
                        WL_ERR(("WLC_DOWN error %d\n", err));
@@ -2823,7 +2818,7 @@ wl_cfg80211_set_ap_role(
                        WL_ERR(("wl dwds 1 error %d\n", err));
                        return err;
                }
-               WL_MSG(dev->name, "Get AP %d", (int)ap);
+               WL_MSG(dev->name, "Get AP %d\n", (int)ap);
        }
 #endif /* WLEASYMESH*/
 
@@ -2841,10 +2836,10 @@ wl_cfg80211_set_ap_role(
                        if (wl_get_drv_status_all(cfg, CONNECTED) > 0) {
 #ifdef WLEASYMESH
                                if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
-                                       WL_MSG(dev->name, "do wl down");
+                                       WL_MSG(dev->name, "do wl down\n");
                                } else {
 #endif /* WLEASYMESH */
-                                       WL_ERR(("Concurrent i/f operational. can't do wl down"));
+                                       WL_ERR(("Concurrent i/f operational. can't do wl down\n"));
                                        return BCME_ERROR;
 #ifdef WLEASYMESH
                                }
@@ -2874,7 +2869,7 @@ wl_cfg80211_set_ap_role(
 #ifdef WLEASYMESH
                        //For FrontHaulAP
                        if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
-                               WL_MSG(dev->name, "wl map 2");
+                               WL_MSG(dev->name, "wl map 2\n");
                                err = wldev_iovar_setint(dev, "map", 2);
                                if (err < 0) {
                                        WL_ERR(("wl map 2 error %d\n", err));
@@ -3092,6 +3087,14 @@ wl_cfg80211_bcn_bringup_ap(
                }
 #endif /* SOFTAP_UAPSD_OFF */
 
+#ifdef WLDWDS
+               err = wldev_iovar_setint(dev, "dwds", 1);
+               if (err < 0) {
+                       WL_ERR(("set dwds error %d\n", err));
+                       goto exit;
+               }
+#endif /* WLDWDS */
+
                err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
                if (unlikely(err)) {
                        WL_ERR(("WLC_UP error (%d)\n", err));
@@ -3133,12 +3136,23 @@ wl_cfg80211_bcn_bringup_ap(
                }
                if (dhd->conf->chip == BCM43430_CHIP_ID && bssidx > 0 &&
                                (wsec & (TKIP_ENABLED|AES_ENABLED))) {
+                       struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+                       struct ether_addr bssid;
+                       int ret = 0;
                        wsec |= WSEC_SWFLAG; // terence 20180628: fix me, this is a workaround
                        err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
                        if (err < 0) {
                                WL_ERR(("wsec error %d\n", err));
                                goto exit;
                        }
+                       bzero(&bssid, sizeof(bssid));
+                       ret = wldev_ioctl_get(primary_ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
+                       if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
+                               scb_val_t scbval;
+                               bzero(&scbval, sizeof(scb_val_t));
+                               scbval.val = WLAN_REASON_DEAUTH_LEAVING;
+                               wldev_ioctl_set(primary_ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
+                       }
                }
                if ((wsec == WEP_ENABLED) && cfg->wep_key.len) {
                        WL_DBG(("Applying buffered WEP KEY \n"));
@@ -3665,14 +3679,23 @@ wl_cfg80211_start_ap(
  *      hardcoded values in 'wl_cfg80211_set_channel()'.
  */
 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
-       if (!dev->ieee80211_ptr->preset_chandef.chan) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+       if (!dev->ieee80211_ptr->u.ap.preset_chandef.chan)
+#else
+       if (!dev->ieee80211_ptr->preset_chandef.chan)
+#endif
+       {
                WL_ERR(("chan is NULL\n"));
                err = -EINVAL;
                goto fail;
        }
        if ((err = wl_cfg80211_set_channel(wiphy, dev,
-               dev->ieee80211_ptr->preset_chandef.chan,
-               NL80211_CHAN_HT20) < 0)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+                       dev->ieee80211_ptr->u.ap.preset_chandef.chan,
+#else
+                       dev->ieee80211_ptr->preset_chandef.chan,
+#endif
+                       NL80211_CHAN_HT20) < 0)) {
                WL_ERR(("Set channel failed \n"));
                goto fail;
        }
@@ -3759,11 +3782,18 @@ wl_cfg80211_start_ap(
                }
        }
 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
+#ifdef WL_EXT_IAPSTA
+               wl_ext_in4way_sync(dev, 0, WL_EXT_STATUS_AP_ENABLING, NULL);
+#endif
 fail:
        if (err) {
                WL_ERR(("ADD/SET beacon failed\n"));
                wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+               wl_cfg80211_stop_ap(wiphy, dev, 0);
+#else
                wl_cfg80211_stop_ap(wiphy, dev);
+#endif
                if (dev_role == NL80211_IFTYPE_AP) {
 #ifdef WL_EXT_IAPSTA
                if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
@@ -3804,7 +3834,11 @@ fail:
 s32
 wl_cfg80211_stop_ap(
        struct wiphy *wiphy,
-       struct net_device *dev)
+       struct net_device *dev
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+       , unsigned int link_id
+#endif
+       )
 {
        int err = 0;
        u32 dev_role = 0;
@@ -3854,6 +3888,9 @@ wl_cfg80211_stop_ap(
                err = -EINVAL;
                goto exit;
        }
+#ifdef WL_EXT_IAPSTA
+       wl_ext_in4way_sync(dev, 0, WL_EXT_STATUS_AP_DISABLING, NULL);
+#endif
 
        /* Free up resources */
        wl_cfg80211_cleanup_if(dev);
@@ -4485,8 +4522,10 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
                (reason == WLC_E_REASON_INITIAL_ASSOC) &&
                (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) {
                if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
+                       char chan_str[64];
                        /* AP/GO brought up successfull in firmware */
-                       WL_MSG(ndev->name, "AP/GO Link up\n");
+                       wl_ext_get_chan_str(ndev, chan_str, sizeof(chan_str));
+                       WL_MSG(ndev->name, "AP/GO Link up (%s)\n", chan_str);
                        wl_set_drv_status(cfg, AP_CREATED, ndev);
                        if (delayed_work_pending(&cfg->ap_work)) {
                                cancel_delayed_work_sync(&cfg->ap_work);
@@ -4544,6 +4583,11 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
                wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
                        WL_EXT_STATUS_STA_CONNECTED, (void *)&e->addr);
 #endif
+#ifdef STA_MGMT
+               if (!wl_ext_add_sta_info(ndev, (u8 *)&e->addr)) {
+                       return -EINVAL;
+               }
+#endif /* STA_MGMT */
                cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
 #ifdef WL_WPS_SYNC
                wl_wps_session_update(ndev, WPS_STATE_LINKUP, e->addr.octet);
@@ -4566,6 +4610,11 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
                wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
                        WL_EXT_STATUS_STA_DISCONNECTED, (void *)&e->addr);
 #endif
+#ifdef STA_MGMT
+               if (!wl_ext_del_sta_info(ndev, (u8 *)&e->addr)) {
+                       return -EINVAL;
+               }
+#endif /* STA_MGMT */
                cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
 #ifdef WL_WPS_SYNC
                wl_wps_session_update(ndev, WPS_STATE_LINKDOWN, e->addr.octet);
@@ -5056,44 +5105,42 @@ wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
 }
 #endif /* WL_CFG80211_ACL */
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
 int wl_chspec_chandef(chanspec_t chanspec,
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
-       struct cfg80211_chan_def *chandef,
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
-       struct chan_info *chaninfo,
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
-       struct wiphy *wiphy)
+       struct cfg80211_chan_def *chandef, struct wiphy *wiphy)
 {
        uint16 freq = 0;
-       int chan_type = 0;
-       int channel = 0;
        struct ieee80211_channel *chan;
 
        if (!chandef) {
                return -1;
+       } else {
+               memset(chandef, 0, sizeof(*chandef));
        }
-       channel = CHSPEC_CHANNEL(chanspec);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+       chandef->center_freq1 =  wl_channel_to_frequency(CHSPEC_CHANNEL(chanspec), CHSPEC_BAND(chanspec));
+       freq = wl_channel_to_frequency(wf_chspec_primary20_chan(chanspec), CHSPEC_BAND(chanspec));
+       chandef->chan = ieee80211_get_channel(wiphy, freq);
+       chandef->center_freq2 = 0;
 
        switch (CHSPEC_BW(chanspec)) {
                case WL_CHANSPEC_BW_20:
-                       chan_type = NL80211_CHAN_HT20;
+                       chandef->width = NL80211_CHAN_WIDTH_20;
                        break;
+
                case WL_CHANSPEC_BW_40:
-               {
-                       if (CHSPEC_SB_UPPER(chanspec)) {
-                               channel += CH_10MHZ_APART;
-                       } else {
-                               channel -= CH_10MHZ_APART;
-                       }
-               }
-                       chan_type = NL80211_CHAN_HT40PLUS;
+                       chandef->width = NL80211_CHAN_WIDTH_40;
                        break;
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
                case WL_CHANSPEC_BW_80:
+                       chandef->width = NL80211_CHAN_WIDTH_80;
+                       break;
+
                case WL_CHANSPEC_BW_8080:
                {
+                       /* XXX Left as is but need proper calculation for center_freq2 is used */
+                       int chan_type = 0;
+                       int channel = 0;
                        uint16 sb = CHSPEC_CTL_SB(chanspec);
 
                        if (sb == WL_CHANSPEC_CTL_SB_LL) {
@@ -5111,19 +5158,45 @@ int wl_chspec_chandef(chanspec_t chanspec,
                                chan_type = NL80211_CHAN_HT40MINUS;
                        else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU)
                                chan_type = NL80211_CHAN_HT40PLUS;
-               }
+                       freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chanspec));
+                       chan = ieee80211_get_channel(wiphy, freq);
+                       cfg80211_chandef_create(chandef, chan, chan_type);
+                       return 0;
                        break;
+               }
+
                case WL_CHANSPEC_BW_160:
-                       channel = wf_chspec_primary20_chan(chanspec);
-                       /* Using base chan_type as kernel does not define chan_type for 160 MHz */
-                       chan_type = NL80211_CHAN_HT20;
+                       chandef->width = NL80211_CHAN_WIDTH_160;
                        break;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
                default:
+                       chandef->width = NL80211_CHAN_WIDTH_20;
+                       break;
+       }
+
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && \
+      (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 7, 0)))
+
+       int chan_type = 0;
+       int channel = 0;
+       channel = CHSPEC_CHANNEL(chanspec);
+       switch (CHSPEC_BW(chanspec)) {
+               case WL_CHANSPEC_BW_20:
                        chan_type = NL80211_CHAN_HT20;
                        break;
+               case WL_CHANSPEC_BW_40:
+                       if (CHSPEC_SB_UPPER(chanspec)) {
+                               channel += CH_10MHZ_APART;
+                       } else {
+                               channel -= CH_10MHZ_APART;
+                       }
+                       chan_type = NL80211_CHAN_HT40PLUS;
+                       break;
 
+               default:
+                       chan_type = NL80211_CHAN_HT20;
+                       break;
        }
+
        freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chanspec));
        chan = ieee80211_get_channel(wiphy, freq);
        WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
@@ -5135,24 +5208,19 @@ int wl_chspec_chandef(chanspec_t chanspec,
                return -EINVAL;
        }
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
-       cfg80211_chandef_create(chandef, chan, chan_type);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
-       chaninfo->freq = freq;
-       chaninfo->chan_type = chan_type;
+       chandef->freq = freq;
+       chandef->chan_type = chan_type;
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+
        return 0;
 }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
 void
 wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy)
 {
        u32 freq;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
        struct cfg80211_chan_def chandef;
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
-       struct chan_info chaninfo;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
 
        if (!wiphy) {
                WL_ERR(("wiphy is null\n"));
@@ -5167,21 +5235,21 @@ wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wip
        }
 #endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
-       if (wl_chspec_chandef(chanspec, &chandef, wiphy))
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
-       if (wl_chspec_chandef(chanspec, &chaninfo, wiphy))
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
-       {
+       if (wl_chspec_chandef(chanspec, &chandef, wiphy)) {
                WL_ERR(("chspec_chandef failed\n"));
                return;
        }
+
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
        freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+       cfg80211_ch_switch_notify(dev, &chandef, 0);
+#else
        cfg80211_ch_switch_notify(dev, &chandef);
+#endif
 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
-       freq = chan_info.freq;
-       cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type);
+       freq = chandef.freq;
+       cfg80211_ch_switch_notify(dev, freq, chandef.chan_type);
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
 
        WL_MSG(dev->name, "Channel switch notification for freq: %d chanspec: 0x%x\n",
index 09f63fb362359172c08dcce8a91845c0f2b6b913..e7daeec18374bc1159f3f34bfed0a9001a7f9172 100755 (executable)
@@ -195,7 +195,12 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
        defined(WL_COMPAT_WIRELESS)
 extern s32 wl_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                struct cfg80211_ap_settings *info);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO)
+extern s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
+       unsigned int link_id);
+#else
 extern s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev);
+#endif
 extern s32 wl_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
        struct cfg80211_beacon_data *info);
 #else
@@ -248,4 +253,7 @@ extern bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len);
 #ifdef SUPPORT_AP_BWCTRL
 extern void wl_restore_ap_bw(struct bcm_cfg80211 *cfg);
 #endif /* SUPPORT_AP_BWCTRL */
+
+extern int wl_chspec_chandef(chanspec_t chanspec,
+       struct cfg80211_chan_def *chandef, struct wiphy *wiphy);
 #endif /* _wl_cfgvif_h_ */
index 666a5b2c3837bb4c24645376fd39b2fdae65a8b5..11e6bdc86d594819fa325893ac0aa9a17e8598f2 100755 (executable)
 #define dtohchanspec(i) (i)
 #define WL_EXTRA_BUF_MAX 2048
 
-#define wl_escan_get_buf(a) ((wl_scan_results_t *) (a)->escan_buf)
+#define wl_escan_get_buf(a) ((wl_scan_results_v109_t *) (a)->escan_buf)
 
 #if defined(WL_WIRELESS_EXT)
 extern int wl_iw_handle_scanresults_ies(char **event_p, char *end,
-       struct iw_request_info *info, wl_bss_info_t *bi);
+       struct iw_request_info *info, wl_bss_info_v109_t *bi);
 #define for_each_bss_wext(list, bss, __i)      \
        for (__i = 0; __i < list->count && __i < IW_MAX_AP; __i++, bss = next_bss(list, bss))
 #endif
@@ -205,7 +205,7 @@ wl_ch_host_to_driver(int ioctl_ver, u16 channel)
        return wl_chspec_host_to_driver(ioctl_ver, chanspec);
 }
 
-static inline struct wl_bss_info *next_bss(wl_scan_results_t *list,
+static inline struct wl_bss_info *next_bss(wl_scan_results_v109_t *list,
        struct wl_bss_info *bss)
 {
        return bss = bss ?
@@ -216,7 +216,7 @@ static inline struct wl_bss_info *next_bss(wl_scan_results_t *list,
 #ifndef BSSCACHE
 static void
 wl_escan_dump_bss(struct net_device *dev, struct wl_escan_info *escan,
-       wl_bss_info_t *bi)
+       wl_bss_info_v109_t *bi)
 {
        int16 rssi;
        int channel;
@@ -244,9 +244,9 @@ wl_escan_dump_bss(struct net_device *dev, struct wl_escan_info *escan,
 static s32
 wl_escan_inform_bss(struct net_device *dev, struct wl_escan_info *escan)
 {
-       wl_scan_results_t *bss_list;
+       wl_scan_results_v109_t *bss_list;
 #ifndef BSSCACHE
-       wl_bss_info_t *bi = NULL;       /* must be initialized */
+       wl_bss_info_v109_t *bi = NULL;  /* must be initialized */
        s32 i;
 #endif
        s32 err = 0;
@@ -283,34 +283,34 @@ wl_escan_inform_bss(struct net_device *dev, struct wl_escan_info *escan)
        wl_reset_bss_cache(&escan->g_bss_cache_ctrl);
        if (escan->autochannel)
                wl_ext_get_best_channel(dev, &escan->g_bss_cache_ctrl,
-                       escan->ioctl_ver, &escan->best_2g_ch, &escan->best_5g_ch);
+                       &escan->best_2g_ch, &escan->best_5g_ch, &escan->best_6g_ch);
 #else
        bi = next_bss(bss_list, bi);
        for_each_bss(bss_list, bi, i) {
                wl_escan_dump_bss(dev, escan, bi);
        }
        if (escan->autochannel)
-               wl_ext_get_best_channel(dev, bss_list, escan->ioctl_ver,
-                       &escan->best_2g_ch, &escan->best_5g_ch);
+               wl_ext_get_best_channel(dev, bss_list,
+                       &escan->best_2g_ch, &escan->best_5g_ch, &escan->best_6g_ch);
 #endif
 
        return err;
 }
 #endif /* ESCAN_RESULT_PATCH */
 
-static wl_scan_params_t *
+static wl_scan_params_v1_t *
 wl_escan_alloc_params(struct net_device *dev, struct wl_escan_info *escan,
        int channel, int nprobes, int *out_params_size)
 {
-       wl_scan_params_t *params;
+       wl_scan_params_v1_t *params;
        int params_size;
        int num_chans;
 
        *out_params_size = 0;
 
        /* Our scan params only need space for 1 channel and 0 ssids */
-       params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16);
-       params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL);
+       params_size = WL_SCAN_PARAMS_V1_FIXED_SIZE + 1 * sizeof(uint16);
+       params = (wl_scan_params_v1_t*) kzalloc(params_size, GFP_KERNEL);
        if (params == NULL) {
                ESCAN_ERROR(dev->name, "mem alloc failed (%d bytes)\n", params_size);
                return params;
@@ -343,7 +343,7 @@ wl_escan_alloc_params(struct net_device *dev, struct wl_escan_info *escan,
 static void
 wl_escan_abort(struct net_device *dev, struct wl_escan_info *escan)
 {
-       wl_scan_params_t *params = NULL;
+       wl_scan_params_v1_t *params = NULL;
        s32 params_size = 0;
        s32 err = BCME_OK;
        if (!in_atomic()) {
@@ -416,7 +416,7 @@ wl_escan_notify_complete(struct net_device *dev,
 #ifdef ESCAN_BUF_OVERFLOW_MGMT
 static void
 wl_escan_find_removal_candidate(struct wl_escan_info *escan,
-       wl_bss_info_t *bss, removal_element_t *candidate)
+       wl_bss_info_v109_t *bss, removal_element_t *candidate)
 {
        int idx;
        for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) {
@@ -435,17 +435,17 @@ wl_escan_find_removal_candidate(struct wl_escan_info *escan,
 
 static void
 wl_escan_remove_lowRSSI_info(struct net_device *dev, struct wl_escan_info *escan,
-       wl_scan_results_t *list, removal_element_t *candidate, wl_bss_info_t *bi)
+       wl_scan_results_v109_t *list, removal_element_t *candidate, wl_bss_info_v109_t *bi)
 {
        int idx1, idx2;
        int total_delete_len = 0;
        for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) {
-               int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
-               wl_bss_info_t *bss = NULL;
+               int cur_len = WL_SCAN_RESULTS_V109_FIXED_SIZE;
+               wl_bss_info_v109_t *bss = NULL;
                if (candidate[idx1].RSSI >= bi->RSSI)
                        continue;
                for (idx2 = 0; idx2 < list->count; idx2++) {
-                       bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) :
+                       bss = bss ? (wl_bss_info_v109_t *)((uintptr)bss + dtoh32(bss->length)) :
                                list->bss_info;
                        if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
                                candidate[idx1].RSSI == bss->RSSI &&
@@ -478,16 +478,16 @@ wl_escan_ext_handler(struct net_device *dev, void *argu,
 {
        struct wl_escan_info *escan = (struct wl_escan_info *)argu;
        s32 status = ntoh32(e->status);
-       wl_bss_info_t *bi;
-       wl_escan_result_t *escan_result;
-       wl_bss_info_t *bss = NULL;
-       wl_scan_results_t *list;
+       wl_bss_info_v109_t *bi;
+       wl_escan_result_v109_t *escan_result;
+       wl_bss_info_v109_t *bss = NULL;
+       wl_scan_results_v109_t *list;
        u32 bi_length;
        u32 i;
        u16 channel;
 
        mutex_lock(&escan->usr_sync);
-       escan_result = (wl_escan_result_t *)data;
+       escan_result = (wl_escan_result_v109_t *)data;
 
        if (escan->escan_state != ESCAN_STATE_SCANING) {
                ESCAN_DBG(dev->name, "Not my scan\n");
@@ -514,7 +514,7 @@ wl_escan_ext_handler(struct net_device *dev, void *argu,
                        goto exit;
                }
                bi_length = dtoh32(bi->length);
-               if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) {
+               if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_V109_FIXED_SIZE)) {
                        ESCAN_ERROR(dev->name, "Invalid bss_info length %d: ignoring\n",
                                bi_length);
                        goto exit;
@@ -529,7 +529,7 @@ wl_escan_ext_handler(struct net_device *dev, void *argu,
                /* ----- terence 20130524: skip invalid bss */
 
                {
-                       int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
+                       int cur_len = WL_SCAN_RESULTS_V109_FIXED_SIZE;
 #ifdef ESCAN_BUF_OVERFLOW_MGMT
                        removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT];
                        int remove_lower_rssi = FALSE;
@@ -546,7 +546,7 @@ wl_escan_ext_handler(struct net_device *dev, void *argu,
                        ESCAN_DBG(dev->name, "%s(%pM) RSSI %d flags 0x%x length %d\n",
                                bi->SSID, &bi->BSSID, bi->RSSI, bi->flags, bi->length);
                        for (i = 0; i < list->count; i++) {
-                               bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
+                               bss = bss ? (wl_bss_info_v109_t *)((uintptr)bss + dtoh32(bss->length))
                                        : list->bss_info;
 #ifdef ESCAN_BUF_OVERFLOW_MGMT
                                ESCAN_DBG(dev->name,
@@ -690,17 +690,15 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan,
        wl_uint32_list_t *list, void *scan_params, wl_scan_info_t *scan_info)
 {
        int err = 0;
-       wl_scan_results_t *results;
+       wl_scan_results_v109_t *results;
        char *ptr;
        int i = 0, j = 0;
        wlc_ssid_t ssid_tmp;
        u32 n_channels = 0;
-       uint channel;
        chanspec_t chanspec;
        u32 n_ssids = 0;
-       wl_scan_params_t *params = NULL;
+       wl_scan_params_v1_t *params = NULL;
        wl_scan_params_v2_t *params_v2 = NULL;
-       u32 scan_param_size = 0;
        u32 channel_offset = 0;
        u32 cur_offset;
        uint16 *chan_list = NULL;
@@ -708,7 +706,7 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan,
        results = wl_escan_get_buf(escan);
        results->version = 0;
        results->count = 0;
-       results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
+       results->buflen = WL_SCAN_RESULTS_V109_FIXED_SIZE;
        escan->escan_state = ESCAN_STATE_SCANING;
 
        /* Arm scan timeout timer */
@@ -716,12 +714,10 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan,
 
        if (escan->scan_params_v2) {
                params_v2 = (wl_scan_params_v2_t *)scan_params;
-               scan_param_size = sizeof(wl_scan_params_v2_t);
                channel_offset = offsetof(wl_scan_params_v2_t, channel_list);
        } else {
-               params = (wl_scan_params_t *)scan_params;
-               scan_param_size = sizeof(wl_scan_params_t);
-               channel_offset = offsetof(wl_scan_params_t, channel_list);
+               params = (wl_scan_params_v1_t *)scan_params;
+               channel_offset = offsetof(wl_scan_params_v1_t, channel_list);
        }
 
        if (params_v2) {
@@ -748,7 +744,7 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan,
                params->scan_type = DOT11_SCANTYPE_ACTIVE;
                params->nprobes = htod32(-1);
                if (scan_info->scan_time)
-                       params_v2->active_time = htod32(scan_info->scan_time);
+                       params->active_time = htod32(scan_info->scan_time);
                else
                        params->active_time = htod32(-1);
                params->passive_time = htod32(-1);
@@ -760,29 +756,19 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan,
 
        cur_offset = channel_offset;
 
-       n_channels = dtoh32(list->count);
+       n_channels = list->count;
        /* Copy channel array if applicable */
        ESCAN_SCAN(dev->name, "### List of channelspecs to scan ###\n");
        if (n_channels > 0) {
                for (i = 0; i < n_channels; i++) {
-                       channel = dtoh32(list->element[i]);
-                       if (!dhd_conf_match_channel(escan->pub, channel))
-                               continue;
-                       chanspec = WL_CHANSPEC_BW_20;
+                       chanspec = list->element[i];
                        if (chanspec == INVCHANSPEC) {
                                ESCAN_ERROR(dev->name, "Invalid chanspec! Skipping channel\n");
                                continue;
                        }
-                       if (channel <= CH_MAX_2G_CHANNEL) {
-                               chanspec |= WL_CHANSPEC_BAND_2G;
-                       } else {
-                               chanspec |= WL_CHANSPEC_BAND_5G;
-                       }
-                       chan_list[j] = channel;
-                       chan_list[j] &= WL_CHANSPEC_CHAN_MASK;
-                       chan_list[j] |= chanspec;
+                       chan_list[j] = chanspec;
                        ESCAN_SCAN(dev->name, "Chan : %d, Channel spec: %x\n",
-                               channel, chan_list[j]);
+                               CHSPEC_CHANNEL(chanspec), chanspec);
                        chan_list[j] = wl_chspec_host_to_driver(escan->ioctl_ver,
                                chan_list[j]);
                        j++;
@@ -854,7 +840,7 @@ wl_escan_timeout(unsigned long data)
 {
        wl_event_msg_t msg;
        struct wl_escan_info *escan = (struct wl_escan_info *)data;
-       wl_scan_results_t *bss_list;
+       wl_scan_results_v109_t *bss_list;
        struct wl_bss_info *bi = NULL;
        s32 i;
        u32 channel;
@@ -894,14 +880,13 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info)
        struct dhd_pub *dhdp = dhd_get_pub(dev);
        struct wl_escan_info *escan = dhdp->escan;
        s32 err = BCME_OK;
-       wl_escan_params_t *eparams = NULL;
+       wl_escan_params_v1_t *eparams = NULL;
        wl_escan_params_v2_t *eparams_v2 = NULL;
-       u8 *scan_params = NULL;
+       u8 *scan_params = NULL, *params = NULL;
        s32 params_size;
-       wl_escan_params_t *params = NULL;
        u32 n_channels = 0;
        wl_uint32_list_t *list;
-       u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
+       u8 valid_chan_list[sizeof(u32)*(MAX_CTRL_CHANSPECS + 1)];
 
        mutex_lock(&escan->usr_sync);
        if (escan->escan_state == ESCAN_STATE_DOWN) {
@@ -923,14 +908,14 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info)
                goto exit2;
        }
 
-       ESCAN_TRACE(dev->name, "Enter \n");
+       ESCAN_TRACE(dev->name, "Enter\n");
 
        if (escan->scan_params_v2) {
                params_size = (WL_SCAN_PARAMS_V2_FIXED_SIZE +
                        OFFSETOF(wl_escan_params_v2_t, params));
        } else {
-               params_size = (WL_SCAN_PARAMS_FIXED_SIZE +
-                       OFFSETOF(wl_escan_params_t, params));
+               params_size = (WL_SCAN_PARAMS_V1_FIXED_SIZE +
+                       OFFSETOF(wl_escan_params_v1_t, params));
        }
 
        /* if scan request is not empty parse scan request paramters */
@@ -940,18 +925,16 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info)
        if (scan_info->channels.count) {
                memcpy(list, &scan_info->channels, sizeof(wl_channel_list_t));
        } else {
-               list->count = htod32(WL_NUMCHANNELS);
-               err = wldev_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list,
-                       sizeof(valid_chan_list), false);
+               err = wl_construct_ctl_chanspec_list(dev, list);
                if (err != 0) {
                        ESCAN_ERROR(dev->name, "get channels failed with %d\n", err);
                        goto exit;
                }
        }
 
-       n_channels = dtoh32(list->count);
-       /* Allocate space for populating ssids in wl_escan_params_t struct */
-       if (dtoh32(list->count) % 2)
+       n_channels = list->count;
+       /* Allocate space for populating ssids in wl_escan_params_v1_t struct */
+       if (list->count % 2)
                /* If n_channels is odd, add a padd of u16 */
                params_size += sizeof(u16) * (n_channels + 1);
        else
@@ -960,7 +943,7 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info)
                params_size += sizeof(struct wlc_ssid) * 2;
        }
 
-       params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL);
+       params = kzalloc(params_size, GFP_KERNEL);
        if (params == NULL) {
                ESCAN_ERROR(dev->name, "kzalloc failed\n");
                err = -ENOMEM;
@@ -972,13 +955,14 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info)
                scan_params = (u8 *)&eparams_v2->params;
                eparams_v2->version = htod32(ESCAN_REQ_VERSION_V2);
                eparams_v2->action =  htod16(WL_SCAN_ACTION_START);
+               wl_escan_set_sync_id(eparams_v2->sync_id);
        } else {
-               eparams = (wl_escan_params_t *)params;
+               eparams = (wl_escan_params_v1_t *)params;
                scan_params = (u8 *)&eparams->params;
-               eparams->version = htod32(ESCAN_REQ_VERSION);
+               eparams->version = htod32(ESCAN_REQ_VERSION_V1);
                eparams->action =  htod16(WL_SCAN_ACTION_START);
+               wl_escan_set_sync_id(eparams->sync_id);
        }
-       wl_escan_set_sync_id(params->sync_id);
 
        wl_escan_prep(dev, escan, list, scan_params, scan_info);
 
@@ -1027,7 +1011,7 @@ rssi_to_qual(int rssi)
 
 static int
 wl_escan_merge_scan_results(struct net_device *dev, struct wl_escan_info *escan,
-       struct iw_request_info *info, char *extra, wl_bss_info_t *bi, int *len, int max_size)
+       struct iw_request_info *info, char *extra, wl_bss_info_v109_t *bi, int *len, int max_size)
 {
        s32 err = BCME_OK;
        struct iw_event iwe;
@@ -1150,8 +1134,8 @@ wl_escan_merge_scan_list(struct net_device *dev, u8 *cur_bssid,
        s32 err = BCME_OK;
        int i = 0, cnt = 0;
        int len_prep = 0;
-       wl_bss_info_t *bi = NULL;
-       wl_scan_results_t *bss_list;
+       wl_bss_info_v109_t *bi = NULL;
+       wl_scan_results_v109_t *bss_list;
        __u16 buflen_from_user = dwrq->length;
 
        bss_list = escan->bss_list;
@@ -1187,8 +1171,8 @@ wl_escan_merge_cache_list(struct net_device *dev, u8 *cur_bssid,
        s32 err = BCME_OK;
        int i = 0, cnt = 0;
        int len_prep = 0;
-       wl_bss_info_t *bi = NULL;
-       wl_scan_results_t *bss_list;
+       wl_bss_info_v109_t *bi = NULL;
+       wl_scan_results_v109_t *bss_list;
        __u16 buflen_from_user = dwrq->length;
        wl_bss_cache_t *node;
 
@@ -1232,7 +1216,7 @@ wl_escan_get_scan(struct net_device *dev,
        int cache_cnt = 0;
 #endif
        int len_prep = 0, len_ret = 0;
-       wl_bss_info_t *bi = NULL;
+       wl_bss_info_v109_t *bi = NULL;
        __u16 buflen_from_user = dwrq->length;
        char *buf = NULL;
        struct ether_addr cur_bssid;
@@ -1389,8 +1373,8 @@ wl_escan_mesh_info(struct net_device *dev, struct wl_escan_info *escan,
        struct ether_addr *peer_bssid, struct wl_mesh_params *mesh_info)
 {
        int i = 0;
-       wl_bss_info_t *bi = NULL;
-       wl_scan_results_t *bss_list;
+       wl_bss_info_v109_t *bi = NULL;
+       wl_scan_results_v109_t *bss_list;
        int16 bi_rssi, bi_chan;
        wlc_ssid_t bi_meshid;
        bool is_mesh_peer = FALSE, found = FALSE;
@@ -1461,8 +1445,8 @@ wl_escan_mesh_peer(struct net_device *dev, struct wl_escan_info *escan,
        struct wl_mesh_params *mesh_info)
 {
        int i = 0;
-       wl_bss_info_t *bi = NULL;
-       wl_scan_results_t *bss_list;
+       wl_bss_info_v109_t *bi = NULL;
+       wl_scan_results_v109_t *bss_list;
        int16 bi_rssi, bi_chan, max_rssi = -100;
        uint min_hop_cnt = 255;
        wlc_ssid_t bi_meshid;
index fcd19d976e94a93d025346c87e503608307617aa..9e652ea8a88e6739404f2bc1df68a06f325b5d21 100755 (executable)
@@ -5,8 +5,8 @@
 #if defined(WL_WIRELESS_EXT)
 #include <wl_iw.h>
 #endif /* WL_WIRELESS_EXT */
-#include <wl_iapsta.h>
 #include <wl_android_ext.h>
+#include <wl_iapsta.h>
 #include <dhd_config.h>
 
 #define ESCAN_BUF_SIZE (64 * 1024)
@@ -35,12 +35,13 @@ typedef struct wl_escan_info {
        int escan_state;
        int ioctl_ver;
        u8 escan_buf[ESCAN_BUF_SIZE];
-       wl_scan_results_t *bss_list;
+       wl_scan_results_v109_t *bss_list;
        u8 *escan_ioctl_buf;
        struct mutex usr_sync; /* maily for up/down synchronization */
        int autochannel;
        int best_2g_ch;
        int best_5g_ch;
+       int best_6g_ch;
 #if defined(RSSIAVG)
        wl_rssi_cache_ctrl_t g_rssi_cache_ctrl;
        wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl;
@@ -64,7 +65,7 @@ typedef struct wl_mesh_params {
        uint16 master_channel;
        uint hop_cnt;
        struct ether_addr peer_bssid[MAX_HOP_LIST];
-       uint16 scan_channel;
+       uint32 scan_channel;
 } wl_mesh_params_t;
 bool wl_escan_mesh_info(struct net_device *dev,
        struct wl_escan_info *escan, struct ether_addr *peer_bssid,
index a111b3f16f4c998b55afaa4d0dfd28724563e69f..2d2a999d84af227316b505da2ace18eb62d0de97 100755 (executable)
@@ -312,7 +312,8 @@ wl_ext_event_create_handler(struct wl_event_params *event_params)
 #else
        /* Allocate workqueue for event */
        if (!event_params->event_workq) {
-               event_params->event_workq = alloc_workqueue("ext_eventd", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
+               event_params->event_workq = alloc_workqueue("ext_eventd",
+                       WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0);
        }
 
        if (!event_params->event_workq) {
@@ -386,6 +387,7 @@ wl_ext_event_register(struct net_device *dev, dhd_pub_t *dhd, uint32 event,
                        mutex_unlock(&event_params->event_sync);
                        return -ENOMEM;
                }
+               memset(leaf, 0, sizeof(event_handler_list_t));
                leaf->next = NULL;
                leaf->dev = dev;
                leaf->etype = event;
index aeaef14d2589b75bf1116e5d8f09012ca1cc0880..1113cdabc31b830ea099c46d82e46e13e4191df4 100755 (executable)
@@ -3,15 +3,27 @@
 #include <net/rtnetlink.h>
 #include <bcmendian.h>
 #include <dhd_linux.h>
+#include <wlioctl_utils.h>
 #include <wl_android.h>
 #include <dhd_config.h>
 #ifdef WL_CFG80211
 #include <wl_cfg80211.h>
+#include <wl_cfgscan.h>
 #endif /* WL_CFG80211 */
 #ifdef WL_ESCAN
 #include <wl_escan.h>
 #endif /* WL_ESCAN */
 
+#ifdef BTC_WAR
+/* btc_war:
+ * -1(don't apply btc)
+ *   0(disable btc war): btc_mode=1; txchain=3; rxchain=3
+ *   1(enable btc war): txchain=2; rxchain=2; btc_mode=5
+ */
+int btc_war = -1;
+module_param(btc_war, int, 0644);
+#endif /* BTC_WAR */
+
 #define IAPSTA_ERROR(name, arg1, args...) \
        do { \
                if (android_msg_level & ANDROID_ERROR_LEVEL) { \
@@ -56,14 +68,35 @@ extern int disable_proptx;
 #define CSA_FW_BIT             (1<<0)
 #define CSA_DRV_BIT            (1<<1)
 
+#define WL_DUMP_BUF_LEN (127 * 1024)
+
 #define MAX_AP_LINK_WAIT_TIME   3000
 #define MAX_STA_LINK_WAIT_TIME   15000
 #define STA_LINKDOWN_TIMEOUT   10000
 #define STA_CONNECT_TIMEOUT    10500
+#define STA_CONNECT_FULL_CHAN_TIMEOUT  3000
 #define STA_CONNECT_RETRY_TIMEOUT      600
 #define STA_RECONNECT_RETRY_TIMEOUT    300
+#define STA_DISCONNECT_RECONNECT_TIMEOUT       30000
+#define STA_DISCONNECT_RECONNECT_MAX   3
+#define STA_4WAY_TIMEOUT       1000
+#ifdef EAPOL_RESEND_M4
+#define STA_KEY_INSTALL_INTERVAL       50
+#define STA_KEY_INSTALL_MAX    (STA_4WAY_TIMEOUT/STA_KEY_INSTALL_INTERVAL)
+#else
+#define STA_KEY_INSTALL_INTERVAL       50
+#define STA_KEY_INSTALL_MAX    3
+#endif
 #define STA_EAPOL_TIMEOUT      100
 #define STA_EMPTY_SCAN_MAX     6
+#define AP_RESTART_TIMEOUT     1000
+#define AP_TXBCNFRM_TIMEOUT    10000
+#ifdef RXF0OVFL_REINIT_WAR
+#define RXF0OVFL_POLLING_TIMEOUT       1000
+#define RXF0OVFL_THRESHOLD     100
+#endif /* RXF0OVFL_REINIT_WAR */
+
+#define MAX_DWDS_IF_NUM 4
 
 enum wl_if_list {
        IF_PIF,
@@ -120,6 +153,37 @@ typedef enum ENCMODE {
        ENC_TKIPAES
 } encmode_t;
 
+#ifdef STA_MGMT
+typedef struct wl_sta_info {
+       int ifidx;
+       struct ether_addr bssid;
+       struct list_head list;
+} wl_sta_info_t;
+#endif /* STA_MGMT */
+
+#ifdef TPUT_MONITOR
+typedef struct wl_tput_info {
+       unsigned long last_tx;
+       unsigned long last_rx;
+       struct osl_timespec tput_ts;
+       int32 tput_tx;
+       int32 tput_rx;
+       int32 tput_tx_kb;
+       int32 tput_rx_kb;
+} wl_tput_info_t;
+#endif /* TPUT_MONITOR */
+
+#ifdef WLDWDS
+typedef struct wl_dwds_info {
+       struct net_device *dev;
+       int ifidx;
+       uint8 bssidx;
+#ifdef TPUT_MONITOR
+       struct wl_tput_info tput_info;
+#endif /* TPUT_MONITOR */
+} wl_dwds_info_t;
+#endif /* WLDWDS */
+
 typedef struct wl_if_info {
        struct net_device *dev;
        ifmode_t ifmode;
@@ -134,7 +198,7 @@ typedef struct wl_if_info {
        bgnmode_t bgnmode;
        int hidden;
        int maxassoc;
-       uint16 channel;
+       struct wl_chan_info chan_info;
        authmode_t amode;
        encmode_t emode;
        bool vsdb;
@@ -158,14 +222,14 @@ typedef struct wl_if_info {
        uint conn_state;
        uint16 prev_channel;
        uint16 post_channel;
+       struct osl_timespec sta_disc_ts;
+       struct osl_timespec sta_conn_ts;
+       bool ap_recon_sta;
+       wait_queue_head_t ap_recon_sta_event;
+       struct ether_addr ap_disc_sta_bssid;
+       struct osl_timespec ap_disc_sta_ts;
 #ifdef TPUT_MONITOR
-       unsigned long last_tx;
-       unsigned long last_rx;
-       struct osl_timespec tput_ts;
-       int32 tput_tx;
-       int32 tput_rx;
-       int32 tput_tx_kb;
-       int32 tput_rx_kb;
+       struct wl_tput_info tput_info;
 #endif /* TPUT_MONITOR */
        timer_list_compat_t connect_timer;
 #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
@@ -185,13 +249,32 @@ typedef struct wl_if_info {
        int eapol_resend_intvl;
 #endif /* EAPOL_DYNAMATIC_RESEND */
 #endif /* EAPOL_RESEND */
+#ifdef KEY_INSTALL_CHECK
+       timer_list_compat_t key_install_timer;
+       int key_install_cnt;
+#endif /* KEY_INSTALL_CHECK */
        int empty_scan;
+#ifdef RESTART_AP_WAR
+       timer_list_compat_t restart_ap_timer;
+#endif /* RESTART_AP_WAR */
+#ifdef RESET_AP_WAR
+       timer_list_compat_t reset_ap_timer;
+       uint32 txbcnfrm;
+#endif /* RESET_AP_WAR */
+#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
+#ifdef WL_EXT_DISCONNECT_RECONNECT
+       struct osl_timespec sta_disc_conn_ts;
+       int sta_disc_recon_cnt;
+#endif /* WL_EXT_DISCONNECT_RECONNECT */
+#endif /* WL_EXT_RECONNECT && WL_CFG80211 */
 } wl_if_info_t;
 
 typedef struct wl_apsta_params {
        struct wl_if_info if_info[MAX_IF_NUM];
-       struct dhd_pub *dhd;
-       int ioctl_ver;
+#ifdef WLDWDS
+       struct wl_dwds_info dwds_info[MAX_DWDS_IF_NUM];
+#endif /* WLDWDS */
+       u8 *ioctl_buf;
        bool init;
        int rsdb;
        bool vsdb;
@@ -210,12 +293,6 @@ typedef struct wl_apsta_params {
 #endif /* WLMESH && WL_ESCAN */
        struct mutex in4way_sync;
        int sta_btc_mode;
-       struct osl_timespec sta_disc_ts;
-       struct osl_timespec sta_conn_ts;
-       bool ap_recon_sta;
-       wait_queue_head_t ap_recon_sta_event;
-       struct ether_addr ap_disc_sta_bssid;
-       struct osl_timespec ap_disc_sta_ts;
 #ifdef TPUT_MONITOR
        timer_list_compat_t monitor_timer;
        int32 tput_sum;
@@ -229,6 +306,15 @@ typedef struct wl_apsta_params {
 #ifdef EAPOL_RESEND
        spinlock_t eapol_lock;
 #endif /* EAPOL_RESEND */
+#ifdef STA_MGMT
+       struct list_head sta_list;
+#endif /* STA_MGMT */
+#ifdef RXF0OVFL_REINIT_WAR
+       timer_list_compat_t rxf0ovfl_timer;
+       uint32 rxbeaconmbss;
+       uint32 rxf0ovfl;
+       int war_reason;
+#endif /* RXF0OVFL_REINIT_WAR */
 } wl_apsta_params_t;
 
 enum wifi_isam_status {
@@ -244,7 +330,11 @@ enum wifi_isam_reason {
        ISAM_RC_MESH_ACS = 1,
        ISAM_RC_TPUT_MONITOR = 2,
        ISAM_RC_AP_ACS = 3,
-       ISAM_RC_EAPOL_RESEND = 4
+       ISAM_RC_AP_RESTART = 4,
+       ISAM_RC_AP_RESET = 5,
+       ISAM_RC_EAPOL_RESEND = 6,
+       ISAM_RC_KEY_INSTALL = 7,
+       ISAM_RC_RXF0OVFL_REINIT = 8
 };
 
 #define wl_get_isam_status(cur_if, stat) \
@@ -259,9 +349,6 @@ enum wifi_isam_reason {
 static int wl_ext_enable_iface(struct net_device *dev, char *ifname,
        int wait_up, bool lock);
 static int wl_ext_disable_iface(struct net_device *dev, char *ifname);
-#if defined(WLMESH) && defined(WL_ESCAN)
-static int wl_mesh_escan_attach(dhd_pub_t *dhd, struct wl_if_info *cur_if);
-#endif /* WLMESH && WL_ESCAN */
 
 static struct wl_if_info *
 wl_get_cur_if(struct net_device *dev)
@@ -548,17 +635,17 @@ wl_ext_set_amode(struct wl_if_info *cur_if)
 }
 
 static int
-wl_ext_set_emode(struct wl_apsta_params *apsta_params,
-       struct wl_if_info *cur_if)
+wl_ext_set_emode(struct wl_if_info *cur_if)
 {
        struct net_device *dev = cur_if->dev;
-       int wsec=0;
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        struct wl_wsec_key wsec_key;
        wsec_pmk_t psk;
        authmode_t amode = cur_if->amode;
        encmode_t emode = cur_if->emode;
+       int wsec=0;
        char *key = cur_if->key;
-       struct dhd_pub *dhd = apsta_params->dhd;
 
        memset(&wsec_key, 0, sizeof(wsec_key));
        memset(&psk, 0, sizeof(psk));
@@ -632,18 +719,40 @@ wl_ext_set_emode(struct wl_apsta_params *apsta_params,
        return 0;
 }
 
-static u32
-wl_ext_get_chanspec(struct wl_apsta_params *apsta_params,
-       struct net_device *dev)
+static void
+wl_ext_set_chan_info(struct wl_if_info *cur_if, uint band, uint16 chan)
+{
+       cur_if->chan_info.band = band;
+       cur_if->chan_info.chan = chan;
+}
+
+static bool
+wl_ext_associated(struct net_device *dev)
 {
-       int ret = 0;
        struct ether_addr bssid;
-       u32 chanspec = 0;
+       int ret = 0;
 
        ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
        if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static u32
+wl_ext_get_chanspec(struct net_device *dev, struct wl_chan_info *chan_info)
+{
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       u32 chanspec = 0;
+
+       if (wl_ext_associated(dev)) {
                if (wl_ext_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
-                       chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec);
+                       chanspec = wl_ext_chspec_driver_to_host(dhd, chanspec);
+                       if (chan_info) {
+                               chan_info->band = CHSPEC2WLC_BAND(chanspec);
+                               chan_info->chan = wf_chspec_ctlchan(chanspec);
+                       }
                        return chanspec;
                }
        }
@@ -652,77 +761,82 @@ wl_ext_get_chanspec(struct wl_apsta_params *apsta_params,
 }
 
 static uint16
-wl_ext_get_chan(struct wl_apsta_params *apsta_params, struct net_device *dev)
+wl_ext_get_chan(struct net_device *dev, struct wl_chan_info *chan_info)
 {
-       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 (wl_ext_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);
-                       return chan;
-               }
+       
+       chanspec = wl_ext_get_chanspec(dev, chan_info);
+       if (chanspec) {
+               ctl_chan = wf_chspec_ctlchan(chanspec);
+               chan = (u16)(ctl_chan & 0x00FF);
        }
 
-       return 0;
+       return chan;
+}
+
+void
+wl_ext_get_chan_str(struct net_device *dev, char *chan_str, int total_len)
+{
+       struct wl_chan_info chan_info;
+       int bytes_written=0;
+       u32 chanspec = 0;
+
+       memset(chan_str, 0, total_len);
+       chanspec = wl_ext_get_chanspec(dev, &chan_info);
+       if (chanspec) {
+               bytes_written += snprintf(chan_str+bytes_written, total_len, "%s-%d %sMHz",
+                       WLCBAND2STR(chan_info.band), chan_info.chan,
+                       wf_chspec_to_bw_str(chanspec));
+       }
 }
 
 static chanspec_t
-wl_ext_chan_to_chanspec(struct wl_apsta_params *apsta_params,
-       struct net_device *dev, uint16 channel)
+wl_ext_chan_to_chanspec(struct net_device *dev, struct wl_chan_info *chan_info)
 {
-       s32 _chan = channel;
-       chanspec_t chspec = 0;
-       chanspec_t fw_chspec = 0;
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       chanspec_band_t chanspec_band;
+       chanspec_t chspec = 0, fw_chspec = 0;
        u32 bw = WL_CHANSPEC_BW_20;
-       s32 err = BCME_OK;
-       s32 bw_cap = 0;
+       s32 err = BCME_OK, 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 ((chan_info->band != WLC_BAND_2G) && (chan_info->band != WLC_BAND_5G) &&
+                       (chan_info->band != WLC_BAND_6G)) {
+               IAPSTA_ERROR(dev->name, "bad band %d\n", chan_info->band);
+               return BCME_BADBAND;
+       }
 
-       if (band == IEEE80211_BAND_5GHZ) {
-               param.band = WLC_BAND_5G;
-               err = wl_ext_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
-                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
-               if (err) {
-                       if (err != BCME_UNSUPPORTED) {
-                               IAPSTA_ERROR(dev->name, "bw_cap failed, %d\n", err);
-                               return err;
-                       } else {
-                               err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
-                               if (bw_cap != WLC_N_BW_20ALL)
-                                       bw = WL_CHANSPEC_BW_40;
-                       }
+       param.band = chan_info->band;
+       err = wl_ext_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
+               iovar_buf, WLC_IOCTL_SMLEN, NULL);
+       if (err) {
+               if (err != BCME_UNSUPPORTED) {
+                       IAPSTA_ERROR(dev->name, "bw_cap failed, %d\n", err);
+                       return err;
                } else {
-                       if (WL_BW_CAP_80MHZ(iovar_buf[0]))
-                               bw = WL_CHANSPEC_BW_80;
-                       else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
+                       err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
+                       if (bw_cap != WLC_N_BW_20ALL)
                                bw = WL_CHANSPEC_BW_40;
-                       else
-                               bw = WL_CHANSPEC_BW_20;
                }
+       } 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);
+       chanspec_band = wl_ext_wlcband_to_chanspec_band(chan_info->band);
+       chspec = wf_create_chspec_from_primary(chan_info->chan, bw, chanspec_band);
        if (wf_chspec_valid(chspec)) {
-               fw_chspec = wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver, chspec);
+               fw_chspec = wl_ext_chspec_host_to_driver(dhd, chspec);
                if (fw_chspec == INVCHANSPEC) {
                        IAPSTA_ERROR(dev->name, "failed to convert host chanspec to fw chanspec\n");
                        fw_chspec = 0;
@@ -769,60 +883,98 @@ wl_ext_assoclist(struct net_device *dev, char *data, char *command,
        assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
        ret = wl_ext_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), 0);
        if (ret)
-               return -1;
+               return 0;
        maxassoc = dtoh32(assoc_maclist->count);
-       bytes_written += snprintf(command+bytes_written, total_len,
-               "%2s: %12s",
-               "no", "------addr------");
        for (i=0; i<maxassoc; i++) {
                bytes_written += snprintf(command+bytes_written, total_len,
-                       "\n%2d: %pM", i, &assoc_maclist->ea[i]);
+                       "\n#%02d: %pM", i, &assoc_maclist->ea[i]);
        }
 
        return bytes_written;
 }
 
-static void
-wl_ext_mod_timer(timer_list_compat_t *timer, uint sec, uint msec)
-{
-       uint timeout = sec * 1000 + msec;
-
-       IAPSTA_TRACE("wlan", "timeout=%d\n", timeout);
-
-       if (timer_pending(timer))
-               del_timer_sync(timer);
-
-       if (timeout)
-               mod_timer(timer, jiffies + msecs_to_jiffies(timeout));
-}
-
-static void
-wl_ext_send_event_msg(struct net_device *dev, int event, int status)
+void
+wl_ext_send_event_msg(struct net_device *dev, int event, int status,
+       int reason)
 {
        struct dhd_pub *dhd = dhd_get_pub(dev);
        struct wl_if_info *cur_if;
        wl_event_msg_t msg;
 
-       cur_if = wl_get_cur_if(dev);
-       if (!cur_if)
-               return;
-
-       bzero(&msg, sizeof(wl_event_msg_t));
-
-       msg.ifidx = hton32(dhd_net2idx(dhd->info, dev));
-       msg.event_type = hton32(event);
-       msg.status = hton32(status);
-       memcpy(&msg.addr, &cur_if->bssid, ETHER_ADDR_LEN);
-
+       if (dhd && dhd->up) {
+               cur_if = wl_get_cur_if(dev);
+               if (!cur_if)
+                       return;
+               bzero(&msg, sizeof(wl_event_msg_t));
+               msg.ifidx = dhd_net2idx(dhd->info, dev);
+               msg.event_type = hton32(event);
+               msg.status = hton32(status);
+               msg.reason = hton32(reason);
+               memcpy(&msg.addr, &cur_if->bssid, ETHER_ADDR_LEN);
 #ifdef WL_EVENT
-       wl_ext_event_send(dhd->event_params, &msg, NULL);
-#endif
+               wl_ext_event_send(dhd->event_params, &msg, NULL);
+#endif /* WL_EVENT */
 #ifdef WL_CFG80211
-       if (dhd->up) {
                wl_cfg80211_event(dev, &msg, NULL);
+#endif /* WL_CFG80211 */
+       }
+}
+
+#ifdef BTC_WAR
+bool
+wl_ext_iapsta_if_2g_enabled(struct net_device *net)
+{
+       struct dhd_pub *dhd = dhd_get_pub(net);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       struct wl_if_info *tmp_if;
+       struct wl_chan_info chan_info;
+       bool enabled = FALSE;
+       uint16 cur_chan;
+       int i;
+
+       for (i=0; i<MAX_IF_NUM; i++) {
+               tmp_if = &apsta_params->if_info[i];
+               if (tmp_if && wl_get_isam_status(tmp_if, IF_READY)) {
+                       cur_chan = wl_ext_get_chan(tmp_if->dev, &chan_info);
+                       if (cur_chan && chan_info.band == WLC_BAND_2G) {
+                               enabled = TRUE;
+                               break;
+                       }
+               }
+       }
+
+       return enabled;
+}
+
+void
+wl_ext_btc_config(struct net_device *dev, bool enable)
+{
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       bool enab = FALSE;
+
+       if (dhd->conf->chip == BCM4354_CHIP_ID || dhd->conf->chip == BCM4356_CHIP_ID ||
+                       dhd->conf->chip == BCM43752_CHIP_ID) {
+               IAPSTA_INFO(dev->name, "btc_war=%d, enable=%d\n", btc_war, enable);
+               if (btc_war >= 0) {
+                       if (enable && btc_war > 0) {
+                               if (wl_ext_iapsta_if_2g_enabled(dev))
+                                       enab = TRUE;
+                       }
+                       if (enab) {
+                               IAPSTA_INFO(dev->name, "enable\n");
+                               wl_ext_iovar_setint(dev, "txchain", 2);
+                               wl_ext_iovar_setint(dev, "rxchain", 2);
+                               wl_ext_iovar_setint(dev, "btc_mode", 5);
+                       } else {
+                               IAPSTA_INFO(dev->name, "disable\n");
+                               wl_ext_iovar_setint(dev, "btc_mode", 1);
+                               wl_ext_iovar_setint(dev, "txchain", 3);
+                               wl_ext_iovar_setint(dev, "rxchain", 3);
+                       }
+               }
        }
-#endif /* defined(WL_CFG80211) */
 }
+#endif /* BTC_WAR */
 
 static void
 wl_ext_connect_timeout(unsigned long data)
@@ -843,7 +995,7 @@ wl_ext_connect_timeout(unsigned long data)
        cur_if->assoc_info.reassoc = 0;
 #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
        IAPSTA_ERROR(dev->name, "timer expired\n");
-       wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS);
+       wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WLC_E_STATUS_SUCCESS);
 }
 
 #if defined(WL_CFG80211) || (defined(WLMESH) && defined(WL_ESCAN))
@@ -857,7 +1009,7 @@ wl_ext_if_enabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode)
                tmp_if = &apsta_params->if_info[i];
                if (tmp_if && tmp_if->ifmode == ifmode &&
                                wl_get_isam_status(tmp_if, IF_READY)) {
-                       if (wl_ext_get_chan(apsta_params, tmp_if->dev)) {
+                       if (wl_ext_associated(tmp_if->dev)) {
                                target_if = tmp_if;
                                break;
                        }
@@ -971,7 +1123,7 @@ wl_ext_mesh_peer_status(struct net_device *dev, char *data, char *command,
 }
 
 #ifdef WL_ESCAN
-#define WL_MESH_DELAY_SCAN_TMO 3
+#define WL_MESH_DELAY_SCAN_TMO 3000
 static void
 wl_mesh_timer(unsigned long data)
 {
@@ -989,7 +1141,7 @@ wl_mesh_timer(unsigned long data)
        bzero(&msg, sizeof(wl_event_msg_t));
        IAPSTA_TRACE(dev->name, "timer expired\n");
 
-       msg.ifidx = hton32(dhd_net2idx(dhd->info, dev));
+       msg.ifidx = dhd_net2idx(dhd->info, dev);
        msg.event_type = hton32(WLC_E_RESERVED);
        msg.reason = hton32(ISAM_RC_MESH_ACS);
        wl_ext_event_send(dhd->event_params, &msg, NULL);
@@ -1063,9 +1215,10 @@ exit:
 }
 
 static int
-wl_mesh_clear_mesh_info(struct wl_apsta_params *apsta_params,
-       struct wl_if_info *mesh_if, bool scan)
+wl_mesh_clear_mesh_info(struct wl_if_info *mesh_if, bool scan)
 {
+       struct dhd_pub *dhd = dhd_get_pub(mesh_if->dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
        uchar mesh_oui[]={0x00, 0x22, 0xf4};
        int ret;
@@ -1075,8 +1228,9 @@ wl_mesh_clear_mesh_info(struct wl_apsta_params *apsta_params,
        ret = wl_mesh_clear_vndr_ie(mesh_if->dev, mesh_oui);
        memset(mesh_info, 0, sizeof(struct wl_mesh_params));
        if (scan) {
-               mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev);
-               wl_ext_mod_timer(&mesh_if->delay_scan, 0, 100);
+               mesh_info->scan_channel = wl_ext_get_chan(mesh_if->dev,
+                       &mesh_if->chan_info);
+               wl_timer_mod(dhd, &mesh_if->delay_scan, 100);
        }
 
        return ret;
@@ -1155,7 +1309,7 @@ wl_mesh_update_master_info(struct wl_apsta_params *apsta_params,
        if (sta_if) {
                wldev_ioctl(mesh_if->dev, WLC_GET_BSSID, &mesh_info->master_bssid,
                        ETHER_ADDR_LEN, 0);
-               mesh_info->master_channel = wl_ext_get_chan(apsta_params, mesh_if->dev);
+               mesh_info->master_channel = wl_ext_get_chan(mesh_if->dev, &mesh_if->chan_info);
                mesh_info->hop_cnt = 0;
                memset(mesh_info->peer_bssid, 0, MAX_HOP_LIST*ETHER_ADDR_LEN);
                if (!wl_mesh_update_vndr_ie(apsta_params, mesh_if))
@@ -1231,7 +1385,7 @@ wl_mesh_update_mesh_info(struct wl_apsta_params *apsta_params,
                wl_ext_get_sec(mesh_if->dev, mesh_if->ifmode, sec, sizeof(sec), FALSE);
                if (strnicmp(sec, "sae/sae", strlen("sae/sae")) == 0)
                        sae = TRUE;
-               cur_chan = wl_ext_get_chan(apsta_params, mesh_if->dev);
+               cur_chan = wl_ext_get_chan(mesh_if->dev, &mesh_if->chan_info);
                bss_found = wl_escan_mesh_peer(mesh_if->dev, mesh_if->escan, &cur_ssid, cur_chan,
                        sae, &peer_mesh_info);
 
@@ -1252,63 +1406,105 @@ exit:
 }
 
 static void
-wl_mesh_event_handler(struct wl_apsta_params *apsta_params,
-       struct wl_if_info *mesh_if, const wl_event_msg_t *e, void *data)
+wl_mesh_event_handler(struct wl_if_info *cur_if,
+       const wl_event_msg_t *e, void *data)
 {
+       struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
        uint32 event_type = ntoh32(e->event_type);
        uint32 status = ntoh32(e->status);
        uint32 reason = ntoh32(e->reason);
-       int ret;
+       uint16 flags =  ntoh16(e->flags);
+       struct wl_if_info *mesh_if = NULL, *tmp_if = NULL;
+       int ret, i;
 
-       if (wl_get_isam_status(mesh_if, AP_CREATED) &&
-                       ((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))) {
-               if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
-                       mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev);
-                       wl_ext_mod_timer(&mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO, 0);
-               }
-       }
-       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)) {
-               wl_mesh_clear_mesh_info(apsta_params, mesh_if, FALSE);
-       }
-       else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
-                       (event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) &&
-                       reason == DOT11_SC_SUCCESS) {
-               mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev);
-               wl_ext_mod_timer(&mesh_if->delay_scan, 0, 100);
-       }
-       else if (event_type == WLC_E_DISASSOC_IND || event_type == WLC_E_DEAUTH_IND ||
-                       (event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
-               if (!memcmp(&mesh_info->peer_bssid, &e->addr, ETHER_ADDR_LEN))
-                       wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE);
-       }
-       else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
-                       event_type == WLC_E_RESERVED && reason == ISAM_RC_MESH_ACS) {
-               if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
-                       wl_scan_info_t scan_info;
-                       memset(&scan_info, 0, sizeof(wl_scan_info_t));
-                       wl_ext_ioctl(mesh_if->dev, WLC_GET_SSID, &scan_info.ssid, sizeof(wlc_ssid_t), 0);
-                       scan_info.channels.count = 1;
-                       scan_info.channels.channel[0] = mesh_info->scan_channel;
-                       ret = wl_escan_set_scan(mesh_if->dev, &scan_info);
-                       if (ret)
-                               wl_ext_mod_timer(&mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO, 0);
+       if (cur_if->ifmode == IMESH_MODE)
+               mesh_if = cur_if;
+       else {
+               for (i=0; i<MAX_IF_NUM; i++) {
+                       tmp_if = &apsta_params->if_info[i];
+                       if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE) {
+                               mesh_if = tmp_if;
+                               break;
+                       }
+               }
+       }
+
+       if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
+               if (event_type == WLC_E_LINK) {
+                       if (!(flags & WLC_EVENT_MSG_LINK)) {
+                               if (mesh_if && apsta_params->macs)
+                                       wl_mesh_clear_mesh_info(mesh_if, TRUE);
+                       } else {
+                               if (mesh_if && apsta_params->macs)
+                                       wl_mesh_update_master_info(apsta_params, mesh_if);
+                       }
+               }
+               else if (event_type == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) {
+                       if (mesh_if && apsta_params->macs)
+                               wl_mesh_clear_mesh_info(mesh_if, TRUE);
+               }
+               else if (event_type == WLC_E_DEAUTH || event_type == WLC_E_DEAUTH_IND ||
+                               event_type == WLC_E_DISASSOC || event_type == WLC_E_DISASSOC_IND) {
+                       if (mesh_if && apsta_params->macs)
+                               wl_mesh_clear_mesh_info(mesh_if, TRUE);
                }
        }
-       else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
-                       ((event_type == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) ||
-                       (event_type == WLC_E_ESCAN_RESULT &&
-                       (status == WLC_E_STATUS_ABORT || status == WLC_E_STATUS_NEWSCAN ||
-                       status == WLC_E_STATUS_11HQUIET || status == WLC_E_STATUS_CS_ABORT ||
-                       status == WLC_E_STATUS_NEWASSOC || status == WLC_E_STATUS_TIMEOUT)))) {
-               if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
-                       if (!wl_mesh_update_mesh_info(apsta_params, mesh_if)) {
-                               mesh_info->scan_channel = 0;
-                               wl_ext_mod_timer(&mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO, 0);
+       else if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) {
+               if (wl_get_isam_status(mesh_if, AP_CREATED) &&
+                               ((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))) {
+                       if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
+                               mesh_info->scan_channel = wl_ext_get_chan(&mesh_if->dev,
+                                       mesh_if->chan_info);
+                               wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO);
+                       }
+               }
+               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)) {
+                       wl_mesh_clear_mesh_info(mesh_if, FALSE);
+               }
+               else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
+                               (event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) &&
+                               reason == DOT11_SC_SUCCESS) {
+                       mesh_info->scan_channel = wl_ext_get_chan(mesh_if->dev,
+                               &mesh_if->chan_info);
+                       wl_timer_mod(dhd, &mesh_if->delay_scan, 100);
+               }
+               else if (event_type == WLC_E_DISASSOC_IND || event_type == WLC_E_DEAUTH_IND ||
+                               (event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
+                       if (!memcmp(&mesh_info->peer_bssid, &e->addr, ETHER_ADDR_LEN))
+                               wl_mesh_clear_mesh_info(mesh_if, TRUE);
+               }
+               else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
+                               event_type == WLC_E_RESERVED && reason == ISAM_RC_MESH_ACS) {
+                       if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
+                               wl_scan_info_t scan_info;
+                               memset(&scan_info, 0, sizeof(wl_scan_info_t));
+                               wl_ext_ioctl(mesh_if->dev, WLC_GET_SSID, &scan_info.ssid, sizeof(wlc_ssid_t), 0);
+                               if (mesh_info->scan_channel) {
+                                       scan_info.channels.count = 1;
+                                       scan_info.channels.channel[0] = mesh_info->scan_channel;
+                               }
+                               ret = wl_escan_set_scan(mesh_if->dev, &scan_info);
+                               if (ret)
+                                       wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO);
+                       }
+               }
+               else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
+                               ((event_type == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) ||
+                               (event_type == WLC_E_ESCAN_RESULT &&
+                               (status == WLC_E_STATUS_ABORT || status == WLC_E_STATUS_NEWSCAN ||
+                               status == WLC_E_STATUS_11HQUIET || status == WLC_E_STATUS_CS_ABORT ||
+                               status == WLC_E_STATUS_NEWASSOC || status == WLC_E_STATUS_TIMEOUT)))) {
+                       if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
+                               if (!wl_mesh_update_mesh_info(apsta_params, mesh_if)) {
+                                       mesh_info->scan_channel = 0;
+                                       wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO);
+                               }
                        }
                }
        }
@@ -1318,9 +1514,7 @@ static void
 wl_mesh_escan_detach(dhd_pub_t *dhd, struct wl_if_info *mesh_if)
 {
        IAPSTA_TRACE(mesh_if->dev->name, "Enter\n");
-
-       del_timer_sync(&mesh_if->delay_scan);
-
+       wl_timer_deregister(mesh_if->dev, &mesh_if->delay_scan);
        if (mesh_if->escan) {
                mesh_if->escan = NULL;
        }
@@ -1332,7 +1526,7 @@ wl_mesh_escan_attach(dhd_pub_t *dhd, struct wl_if_info *mesh_if)
        IAPSTA_TRACE(mesh_if->dev->name, "Enter\n");
 
        mesh_if->escan = dhd->escan;
-       init_timer_compat(&mesh_if->delay_scan, wl_mesh_timer, mesh_if->dev);
+       wl_timer_register(mesh_if->dev, &mesh_if->delay_scan, wl_mesh_timer);
 
        return 0;
 }
@@ -1397,7 +1591,6 @@ wl_ext_isam_peer_path(struct net_device *dev, char *command, int total_len)
        struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
        struct wl_if_info *tmp_if;
-       uint16 chan = 0;
        char *dump_buf = NULL;
        int dump_len = WLC_IOCTL_MEDLEN;
        int dump_written = 0;
@@ -1418,8 +1611,7 @@ wl_ext_isam_peer_path(struct net_device *dev, char *command, int total_len)
                for (i=0; i<MAX_IF_NUM; i++) {
                        tmp_if = &apsta_params->if_info[i];
                        if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE && apsta_params->macs) {
-                               chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
-                               if (chan) {
+                               if (wl_ext_associated(tmp_if->dev)) {
                                        dump_written += snprintf(dump_buf+dump_written, dump_len,
                                                DHD_LOG_PREFIXS "[%s-%c] mbssid=%pM, mchan=%d, hop=%d, pbssid=%pM",
                                                tmp_if->ifname, tmp_if->prefix, &mesh_info->master_bssid,
@@ -1488,6 +1680,7 @@ static int
 wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if,
        bool force_enable, int wait_up)
 {
+       struct wl_chan_info *chan_info = &cur_if->chan_info;
        s8 iovar_buf[WLC_IOCTL_SMLEN];
        struct {
                s32 cfg;
@@ -1497,26 +1690,29 @@ wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if,
        chanspec_t fw_chspec;
        u32 timeout;
        wlc_ssid_t ssid = { 0, {0} };
-       uint16 chan = 0;
+       uint32 chanspec = 0;
 
-       if (cur_if->ifmode != IAP_MODE) {
+       if (cur_if->ifmode != IAP_MODE && cur_if->ifmode != IGO_MODE) {
                IAPSTA_ERROR(cur_if->ifname, "Wrong ifmode\n");
                return 0;
        }
 
-       if (wl_ext_dfs_chan(cur_if->channel) && !apsta_params->radar && !force_enable) {
+       if (wl_ext_dfs_chan(chan_info) && !apsta_params->radar && !force_enable) {
                WL_MSG(cur_if->ifname, "[%c] skip DFS channel %d\n",
-                       cur_if->prefix, cur_if->channel);
+                       cur_if->prefix, chan_info->chan);
                return 0;
-       } else if (!cur_if->channel) {
+       } else if (wl_ext_passive_chan(cur_if->dev, chan_info)) {
+               WL_MSG(cur_if->ifname, "[%c] skip PASSIVE channel %d\n",
+                       cur_if->prefix, chan_info->chan);
+               return 0;
+       } else if (!chan_info->chan) {
                WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
                return 0;
        }
 
        WL_MSG(cur_if->ifname, "[%c] Turning on...\n", cur_if->prefix);
 
-       wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver, cur_if->channel,
-               &fw_chspec);
+       wl_ext_set_chanspec(cur_if->dev, chan_info, &fw_chspec);
 
        wl_clr_isam_status(cur_if, AP_CREATED);
        wl_set_isam_status(cur_if, AP_CREATING);
@@ -1543,9 +1739,10 @@ wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if,
        }
 
        wl_ext_ioctl(cur_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
-       chan = wl_ext_get_chan(apsta_params, cur_if->dev);
-       WL_MSG(cur_if->ifname, "[%c] enabled with SSID: \"%s\" on channel %d\n",
-               cur_if->prefix, ssid.SSID, chan);
+       chanspec = wl_ext_get_chanspec(cur_if->dev, chan_info);
+       WL_MSG(cur_if->ifname, "[%c] enabled with SSID: \"%s\" on channel %s-%d(0x%x)\n",
+               cur_if->prefix, ssid.SSID, CHSPEC2BANDSTR(chanspec),
+               chan_info->chan, chanspec);
 
        wl_clr_isam_status(cur_if, AP_CREATING);
 
@@ -1555,22 +1752,34 @@ wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if,
 }
 
 static bool
-wl_ext_diff_band(uint16 chan1, uint16 chan2)
+wl_ext_same_chan(struct wl_chan_info *chan_info_1,
+       struct wl_chan_info *chan_info_2)
+{
+       if (chan_info_1->band == chan_info_2->band &&
+                       chan_info_1->chan == chan_info_2->chan) {
+               return TRUE;
+       }
+       return FALSE;
+}
+
+static bool
+wl_ext_rsdb_band(uint band_1, uint band_2)
 {
-       if ((chan1 <= CH_MAX_2G_CHANNEL && chan2 > CH_MAX_2G_CHANNEL) ||
-               (chan1 > CH_MAX_2G_CHANNEL && chan2 <= CH_MAX_2G_CHANNEL)) {
+       if ((band_1 == WLC_BAND_2G && band_2 != WLC_BAND_2G) ||
+               (band_2 == WLC_BAND_2G && band_1 != WLC_BAND_2G)) {
                return TRUE;
        }
        return FALSE;
 }
 
 static uint16
-wl_ext_same_band(struct wl_apsta_params *apsta_params,
+wl_ext_get_same_band_chan(struct wl_apsta_params *apsta_params,
        struct wl_if_info *cur_if, bool nodfs)
 {
        struct wl_if_info *tmp_if;
-       uint16 tmp_chan, target_chan = 0;
+       struct wl_chan_info chan_info;
        wl_prio_t max_prio;
+       uint16 chan = 0;
        int i;
 
        // find the max prio
@@ -1579,33 +1788,41 @@ wl_ext_same_band(struct wl_apsta_params *apsta_params,
                tmp_if = &apsta_params->if_info[i];
                if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) &&
                                tmp_if->prio > max_prio) {
-                       tmp_chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
-                       if (wl_ext_dfs_chan(tmp_chan) && nodfs)
+                       memset(&chan_info, 0, sizeof(struct wl_chan_info));
+                       wl_ext_get_chan(tmp_if->dev, &chan_info);
+                       if (wl_ext_dfs_chan(&chan_info) && nodfs)
                                continue;
-                       if (tmp_chan && !wl_ext_diff_band(cur_if->channel, tmp_chan)) {
-                               target_chan = tmp_chan;
+                       if (chan_info.chan && (cur_if->chan_info.band == chan_info.band)) {
+                               chan = chan_info.chan;
                                max_prio = tmp_if->prio;
                        }
                }
        }
 
-       return target_chan;
+       return chan;
 }
 
 static uint16
 wl_ext_get_vsdb_chan(struct wl_apsta_params *apsta_params,
-       struct wl_if_info *cur_if, struct wl_if_info *target_if)
+       const struct wl_if_info *cur_if, const struct wl_if_info *target_if)
 {
-       uint16 target_chan = 0, cur_chan = cur_if->channel;
+       struct wl_chan_info chan_info;
+       uint cur_band = cur_if->chan_info.band;
+       uint16 cur_chan = cur_if->chan_info.chan;
+       uint target_band;
+       uint16 target_chan;
 
        if (cur_if->vsdb && target_if->vsdb)
                return 0;
 
-       target_chan = wl_ext_get_chan(apsta_params, target_if->dev);
+       memset(&chan_info, 0, sizeof(struct wl_chan_info));
+       target_chan = wl_ext_get_chan(target_if->dev, &chan_info);
        if (target_chan) {
-               IAPSTA_INFO(cur_if->ifname, "cur_chan=%d, target_chan=%d\n",
-                       cur_chan, target_chan);
-               if (wl_ext_diff_band(cur_chan, target_chan)) {
+               target_band = chan_info.band;
+               IAPSTA_INFO(cur_if->ifname, "cur_chan=%s-%d, target_chan=%s-%d\n",
+                       WLCBAND2STR(cur_band), cur_chan,
+                       WLCBAND2STR(target_band), target_chan);
+               if (wl_ext_rsdb_band(cur_band, target_band)) {
                        if (!apsta_params->rsdb)
                                return target_chan;
                } else {
@@ -1622,23 +1839,25 @@ wl_ext_rsdb_core_conflict(struct wl_apsta_params *apsta_params,
        struct wl_if_info *cur_if)
 {
        struct wl_if_info *tmp_if;
-       uint16 cur_chan, tmp_chan;
+       struct wl_chan_info cur_chan_info, tmp_chan_info;
        int i;
 
        if (apsta_params->rsdb) {
-               cur_chan = wl_ext_get_chan(apsta_params, cur_if->dev);
+               memset(&cur_chan_info, 0, sizeof(struct wl_chan_info));
+               wl_ext_get_chan(cur_if->dev, &cur_chan_info);
                for (i=0; i<MAX_IF_NUM; i++) {
                        tmp_if = &apsta_params->if_info[i];
                        if (tmp_if != cur_if && wl_get_isam_status(tmp_if, IF_READY) &&
                                        tmp_if->prio > cur_if->prio) {
-                               tmp_chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
-                               if (!tmp_chan)
+                               memset(&tmp_chan_info, 0, sizeof(struct wl_chan_info));
+                               wl_ext_get_chan(tmp_if->dev, &tmp_chan_info);
+                               if (!tmp_chan_info.chan)
                                        continue;
-                               if (wl_ext_diff_band(cur_chan, tmp_chan) &&
-                                               wl_ext_diff_band(cur_chan, cur_if->channel))
+                               if (wl_ext_rsdb_band(cur_chan_info.band, tmp_chan_info.band) &&
+                                               wl_ext_rsdb_band(cur_chan_info.band, cur_if->chan_info.chan))
                                        return TRUE;
-                               else if (!wl_ext_diff_band(cur_chan, tmp_chan) &&
-                                               wl_ext_diff_band(cur_chan, cur_if->channel))
+                               else if (!wl_ext_rsdb_band(cur_chan_info.band, tmp_chan_info.band) &&
+                                               wl_ext_rsdb_band(cur_chan_info.band, cur_if->chan_info.chan))
                                        return TRUE;
                        }
                }
@@ -1653,26 +1872,25 @@ wl_ext_trigger_csa(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_
        bool core_conflict = FALSE;
 
        if (wl_ext_master_if(cur_if) && (apsta_params->csa & CSA_DRV_BIT)) {
-               if (!cur_if->channel) {
+               if (!cur_if->chan_info.chan) {
                        WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
-               } else if (wl_ext_dfs_chan(cur_if->channel) && !apsta_params->radar) {
+               } else if (wl_ext_dfs_chan(&cur_if->chan_info) && !apsta_params->radar) {
                        WL_MSG(cur_if->ifname, "[%c] skip DFS channel %d\n",
-                               cur_if->prefix, cur_if->channel);
+                               cur_if->prefix, cur_if->chan_info.chan);
                        wl_ext_if_down(apsta_params, 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_chan_to_chanspec(apsta_params, cur_if->dev,
-                               cur_if->channel);
+                       csa_arg.chspec = wl_ext_chan_to_chanspec(cur_if->dev, &cur_if->chan_info);
                        core_conflict = wl_ext_rsdb_core_conflict(apsta_params, cur_if);
                        if (core_conflict) {
                                WL_MSG(cur_if->ifname, "[%c] Skip CSA due to rsdb core conflict\n",
                                        cur_if->prefix);
                        } else if (csa_arg.chspec) {
                                WL_MSG(cur_if->ifname, "[%c] Trigger CSA to channel %d(0x%x)\n",
-                                       cur_if->prefix, cur_if->channel, csa_arg.chspec);
+                                       cur_if->prefix, cur_if->chan_info.chan, csa_arg.chspec);
                                wl_set_isam_status(cur_if, AP_CREATING);
                                wl_ext_iovar_setbuf(cur_if->dev, "csa", &csa_arg, sizeof(csa_arg),
                                        iovar_buf, sizeof(iovar_buf), NULL);
@@ -1692,128 +1910,125 @@ static void
 wl_ext_move_cur_dfs_channel(struct wl_apsta_params *apsta_params,
        struct wl_if_info *cur_if)
 {
-       uint16 other_chan = 0, cur_chan = cur_if->channel;
+       struct wl_chan_info *cur_chan_info = &cur_if->chan_info;
+       uint cur_band = cur_chan_info->band;
+       uint16 cur_chan = cur_chan_info->chan, auto_chan = 0;
        uint16 chan_2g = 0, chan_5g = 0;
-       uint32 auto_band = WLC_BAND_2G;
-
-       if (wl_ext_master_if(cur_if) && wl_ext_dfs_chan(cur_if->channel) &&
-                       !apsta_params->radar) {
 
+       if (!apsta_params->radar && wl_ext_master_if(cur_if) &&
+                       wl_ext_dfs_chan(cur_chan_info)) {
                wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE);
                if (!chan_2g && !chan_5g) {
-                       cur_if->channel = 0;
+                       cur_chan_info->chan = 0;
                        WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
                        return;
                }
-
                if (apsta_params->vsdb) {
-                       if (chan_5g) {
-                               cur_if->channel = chan_5g;
-                               auto_band = WLC_BAND_5G;
-                               other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
-                       } else {
-                               cur_if->channel = chan_2g;
-                               auto_band = WLC_BAND_2G;
-                               other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
-                       }
-                       if (!other_chan) {
-                               other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
-                                       auto_band);
+                       if (chan_5g)
+                               wl_ext_set_chan_info(cur_if, WLC_BAND_5G, chan_5g);
+                       else
+                               wl_ext_set_chan_info(cur_if, WLC_BAND_2G, chan_2g);
+                       auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, TRUE);
+                       if (!auto_chan) {
+                               auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
+                                       cur_chan_info->band);
                        }
-                       if (other_chan)
-                               cur_if->channel = other_chan;
-               } else if (apsta_params->rsdb) {
+                       if (auto_chan)
+                               cur_chan_info->chan = auto_chan;
+               }
+               else if (apsta_params->rsdb) {
                        if (chan_5g) {
-                               cur_if->channel = chan_5g;
-                               auto_band = WLC_BAND_5G;
-                               other_chan = wl_ext_same_band(apsta_params, cur_if, FALSE);
-                               if (wl_ext_dfs_chan(other_chan) && chan_2g) {
-                                       cur_if->channel = chan_2g;
-                                       auto_band = WLC_BAND_2G;
-                                       other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
+                               wl_ext_set_chan_info(cur_if, WLC_BAND_5G, chan_5g);
+                               auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, FALSE);
+                               if (auto_chan) {
+                                       if (wl_ext_dfs_chan(cur_chan_info) && chan_2g) {
+                                               wl_ext_set_chan_info(cur_if, WLC_BAND_2G, chan_2g);
+                                               auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, TRUE);
+                                       }
                                }
                        } else {
-                               cur_if->channel = chan_2g;
-                               auto_band = WLC_BAND_2G;
-                               other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
+                               wl_ext_set_chan_info(cur_if, WLC_BAND_2G, chan_2g);
+                               auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, TRUE);
                        }
-                       if (!other_chan) {
-                               other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
-                                       auto_band);
+                       if (!auto_chan) {
+                               auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
+                                       cur_chan_info->band);
                        }
-                       if (other_chan)
-                               cur_if->channel = other_chan;
-               } else {
-                       cur_if->channel = chan_5g;
-                       other_chan = wl_ext_same_band(apsta_params, cur_if, FALSE);
-                       if (other_chan) {
-                               cur_if->channel = other_chan;
+                       if (auto_chan) {
+                               cur_chan_info->chan = auto_chan;
+                       }
+               }
+               else {
+                       wl_ext_set_chan_info(cur_if, WLC_BAND_5G, chan_5g);
+                       auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, FALSE);
+                       if (auto_chan) {
+                               cur_chan_info->chan = auto_chan;
                        } else {
-                               auto_band = WLC_BAND_5G;
-                               other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
-                                       auto_band);
-                               if (other_chan)
-                                       cur_if->channel = other_chan;
+                               auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
+                                       cur_chan_info->band);
+                               if (auto_chan) {
+                                       cur_chan_info->chan = auto_chan;
+                               }
                        }
                }
-               WL_MSG(cur_if->ifname, "[%c] move channel %d => %d\n",
-                       cur_if->prefix, cur_chan, cur_if->channel);
+               WL_MSG(cur_if->ifname, "[%c] move channel %s-%d => %s-%d\n",
+                       cur_if->prefix, WLCBAND2STR(cur_band), cur_chan,
+                       WLCBAND2STR(cur_chan_info->band), cur_chan_info->chan);
        }
 }
 
 static void
 wl_ext_move_other_dfs_channel(struct wl_apsta_params *apsta_params,
-       struct wl_if_info *cur_if)
+       struct wl_if_info *tgt_if)
 {
-       uint16 other_chan = 0, cur_chan = cur_if->channel;
+       struct wl_chan_info *tgt_chan_info = &tgt_if->chan_info;
+       uint cur_band = tgt_chan_info->band;
+       uint16 cur_chan = tgt_chan_info->chan, auto_chan = 0;
        uint16 chan_2g = 0, chan_5g = 0;
-       uint32 auto_band = WLC_BAND_2G;
 
-       if (wl_ext_master_if(cur_if) && wl_ext_dfs_chan(cur_if->channel) &&
-                       !apsta_params->radar) {
-
-               wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE);
+       if (!apsta_params->radar && wl_ext_master_if(tgt_if) &&
+                       wl_ext_dfs_chan(tgt_chan_info)) {
+               wl_ext_get_default_chan(tgt_if->dev, &chan_2g, &chan_5g, TRUE);
                if (!chan_2g && !chan_5g) {
-                       cur_if->channel = 0;
-                       WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
+                       tgt_chan_info->chan = 0;
+                       WL_MSG(tgt_if->ifname, "[%c] no valid channel\n", tgt_if->prefix);
                        return;
                }
 
                if (apsta_params->vsdb) {
-                       if (chan_5g) {
-                               cur_if->channel = chan_5g;
-                               auto_band = WLC_BAND_5G;
-                               other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
-                       } else {
-                               cur_if->channel = chan_2g;
-                               auto_band = WLC_BAND_2G;
-                               other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
+                       if (chan_5g)
+                               wl_ext_set_chan_info(tgt_if, WLC_BAND_5G, chan_5g);
+                       else
+                               wl_ext_set_chan_info(tgt_if, WLC_BAND_2G, chan_2g);
+                       auto_chan = wl_ext_get_same_band_chan(apsta_params, tgt_if, TRUE);
+                       if (!auto_chan) {
+                               auto_chan = wl_ext_autochannel(tgt_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
+                                       tgt_chan_info->band);
                        }
-                       if (!other_chan) {
-                               other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
-                                       auto_band);
+                       if (auto_chan) {
+                               tgt_chan_info->chan = auto_chan;
                        }
-                       if (other_chan)
-                               cur_if->channel = other_chan;
-               } else if (apsta_params->rsdb) {
+               }
+               else if (apsta_params->rsdb) {
                        if (chan_2g) {
-                               cur_if->channel = chan_2g;
-                               auto_band = WLC_BAND_2G;
-                               other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
-                               if (!other_chan) {
-                                       other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
-                                               auto_band);
+                               wl_ext_set_chan_info(tgt_if, WLC_BAND_2G, chan_2g);
+                               auto_chan = wl_ext_get_same_band_chan(apsta_params, tgt_if, TRUE);
+                               if (!auto_chan) {
+                                       auto_chan = wl_ext_autochannel(tgt_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
+                                               tgt_chan_info->band);
                                }
                        } else {
-                               cur_if->channel = 0;
+                               tgt_chan_info->chan = 0;
+                       }
+                       if (auto_chan) {
+                               tgt_chan_info->chan = auto_chan;
                        }
-                       if (other_chan)
-                               cur_if->channel = other_chan;
                } else {
-                       cur_if->channel = 0;
+                       tgt_chan_info->chan = 0;
                }
-               WL_MSG(cur_if->ifname, "[%c] move channel %d => %d\n",
-                       cur_if->prefix, cur_chan, cur_if->channel);
+               WL_MSG(tgt_if->ifname, "[%c] move channel %s-%d => %s-%d\n",
+                       tgt_if->prefix, WLCBAND2STR(cur_band), cur_chan,
+                       WLCBAND2STR(tgt_chan_info->band), tgt_chan_info->chan);
        }
 }
 
@@ -1822,12 +2037,12 @@ wl_ext_move_cur_channel(struct wl_apsta_params *apsta_params,
        struct wl_if_info *cur_if)
 {
        struct wl_if_info *tmp_if, *target_if = NULL;
-       uint16 tmp_chan, target_chan = 0;
+       struct wl_chan_info cur_chan_info, tgt_chan_info;
+       uint16 tmp_chan;
        wl_prio_t max_prio;
        int i;
 
        if (apsta_params->vsdb) {
-               target_chan = cur_if->channel;
                goto exit;
        }
 
@@ -1840,31 +2055,35 @@ wl_ext_move_cur_channel(struct wl_apsta_params *apsta_params,
                        tmp_chan = wl_ext_get_vsdb_chan(apsta_params, cur_if, tmp_if);
                        if (tmp_chan) {
                                target_if = tmp_if;
-                               target_chan = tmp_chan;
                                max_prio = tmp_if->prio;
                        }
                }
        }
 
-       if (target_chan) {
-               tmp_chan = wl_ext_get_chan(apsta_params, cur_if->dev);
-               if (apsta_params->rsdb && tmp_chan &&
-                               wl_ext_diff_band(tmp_chan, target_chan)) {
-                       WL_MSG(cur_if->ifname, "[%c] keep on current channel %d\n",
-                               cur_if->prefix, tmp_chan);
-                       cur_if->channel = 0;
+       if (target_if) {
+               memset(&cur_chan_info, 0, sizeof(struct wl_chan_info));
+               memset(&tgt_chan_info, 0, sizeof(struct wl_chan_info));
+               wl_ext_get_chan(cur_if->dev, &cur_chan_info);
+               wl_ext_get_chan(target_if->dev, &tgt_chan_info);
+               if (apsta_params->rsdb && cur_chan_info.chan &&
+                               wl_ext_rsdb_band(cur_chan_info.band, tgt_chan_info.band)) {
+                       WL_MSG(cur_if->ifname, "[%c] keep on current channel %s-%d\n",
+                               cur_if->prefix, WLCBAND2STR(cur_chan_info.band), cur_chan_info.chan);
+                       cur_if->chan_info.chan = 0;
                } else {
-                       WL_MSG(cur_if->ifname, "[%c] channel=%d => %s[%c] channel=%d\n",
-                               cur_if->prefix, cur_if->channel,
-                               target_if->ifname, target_if->prefix, target_chan);
-                       cur_if->channel = target_chan;
+                       WL_MSG(cur_if->ifname, "[%c] channel=%s-%d => %s[%c] channel=%s-%d\n",
+                               cur_if->prefix,
+                               WLCBAND2STR(cur_if->chan_info.band), cur_if->chan_info.chan,
+                               target_if->ifname, target_if->prefix,
+                               WLCBAND2STR(tgt_chan_info.band), tgt_chan_info.chan);
+                       wl_ext_set_chan_info(cur_if, tgt_chan_info.band, tgt_chan_info.chan);
                }
        }
 
 exit:
        wl_ext_move_cur_dfs_channel(apsta_params, cur_if);
 
-       return cur_if->channel;
+       return cur_if->chan_info.chan;
 }
 
 static struct wl_if_info *
@@ -1876,7 +2095,7 @@ wl_ext_move_other_channel(struct wl_apsta_params *apsta_params,
        wl_prio_t max_prio = 0, cur_prio;
        int i;
 
-       if (apsta_params->vsdb || !cur_if->channel) {
+       if (apsta_params->vsdb || !cur_if->chan_info.chan) {
                return NULL;
        }
 
@@ -1896,9 +2115,10 @@ wl_ext_move_other_channel(struct wl_apsta_params *apsta_params,
        }
 
        if (target_if) {
-               WL_MSG(target_if->ifname, "channel=%d => %s channel=%d\n",
-                       target_chan, cur_if->ifname, cur_if->channel);
-               target_if->channel = cur_if->channel;
+               WL_MSG(target_if->ifname, "channel=%s-%d => %s channel=%s-%d\n",
+                       WLCBAND2STR(target_if->chan_info.band), target_chan,
+                       cur_if->ifname, WLCBAND2STR(cur_if->chan_info.band), cur_if->chan_info.chan);
+               wl_ext_set_chan_info(target_if, cur_if->chan_info.band, cur_if->chan_info.chan);
                wl_ext_move_other_dfs_channel(apsta_params, target_if);
                if (apsta_params->csa == 0) {
                        wl_ext_if_down(apsta_params, target_if);
@@ -1973,7 +2193,7 @@ wl_ext_iapsta_other_if_enabled(struct net_device *net)
        for (i=0; i<MAX_IF_NUM; i++) {
                tmp_if = &apsta_params->if_info[i];
                if (tmp_if && wl_get_isam_status(tmp_if, IF_READY)) {
-                       if (wl_ext_get_chan(apsta_params, tmp_if->dev)) {
+                       if (wl_ext_associated(tmp_if->dev)) {
                                enabled = TRUE;
                                break;
                        }
@@ -2006,14 +2226,58 @@ wl_ext_sta_connecting(struct net_device *dev)
        return connecting;
 }
 
-#ifdef PROPTX_MAXCOUNT
-int
-wl_ext_get_wlfc_maxcount(struct dhd_pub *dhd, int ifidx)
+bool
+wl_ext_sta_handshaking(struct net_device *dev)
 {
-       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
-       struct wl_if_info *tmp_if, *cur_if = NULL;
-       int i, maxcount = WL_TXSTATUS_FREERUNCTR_MASK;
-
+       struct wl_if_info *cur_if = NULL;
+       bool connecting = FALSE;
+       int state;
+
+       cur_if = wl_get_cur_if(dev);
+       if (!cur_if)
+               return FALSE;
+
+       if (cur_if->ifmode != ISTA_MODE && cur_if->ifmode != IGC_MODE)
+               return FALSE;
+
+       state = cur_if->conn_state;
+       if (state >= CONN_STATE_4WAY_M1 && state < CONN_STATE_CONNECTED) {
+               connecting = TRUE;
+               IAPSTA_TRACE(dev->name, "conn_state %d\n", state);
+       }
+
+       return connecting;
+}
+
+#ifdef DHD_LOSSLESS_ROAMING
+int
+wl_ext_any_sta_handshaking(struct dhd_pub *dhd)
+{
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       struct wl_if_info *cur_if;
+       int state = 0, i;
+
+       for (i=0; i<MAX_IF_NUM; i++) {
+               cur_if = &apsta_params->if_info[i];
+               if (cur_if->dev && cur_if->ifmode == ISTA_MODE) {
+                       state = cur_if->conn_state;
+                       if (state >= CONN_STATE_4WAY_M1 && state < CONN_STATE_CONNECTED) {
+                               return state;
+                       }
+               }
+       }
+       return 0;
+}
+#endif /* DHD_LOSSLESS_ROAMING */
+
+#ifdef PROPTX_MAXCOUNT
+int
+wl_ext_get_wlfc_maxcount(struct dhd_pub *dhd, int ifidx)
+{
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       struct wl_if_info *tmp_if, *cur_if = NULL;
+       int i, maxcount = WL_TXSTATUS_FREERUNCTR_MASK;
+
        if (!apsta_params->rsdb)
                return maxcount;
 
@@ -2037,8 +2301,8 @@ wl_ext_update_wlfc_maxcount(struct dhd_pub *dhd)
 {
        struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        struct wl_if_info *tmp_if;
+       struct wl_chan_info chan_info;
        bool band_5g = FALSE;
-       uint16 chan = 0;
        int i, ret;
 
        if (!apsta_params->rsdb)
@@ -2047,8 +2311,9 @@ wl_ext_update_wlfc_maxcount(struct dhd_pub *dhd)
        for (i=0; i<MAX_IF_NUM; i++) {
                tmp_if = &apsta_params->if_info[i];
                if (tmp_if->dev) {
-                       chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
-                       if (chan > CH_MAX_2G_CHANNEL) {
+                       memset(&chan_info, 0, sizeof(struct wl_chan_info));
+                       wl_ext_get_chan(tmp_if->dev, &chan_info);
+                       if (chan_info.band == WLC_BAND_5G || chan_info.band == WLC_BAND_6G) {
                                tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_5g;
                                ret = dhd_wlfc_update_maxcount(dhd, tmp_if->ifidx,
                                        tmp_if->transit_maxcount);
@@ -2063,9 +2328,9 @@ wl_ext_update_wlfc_maxcount(struct dhd_pub *dhd)
        for (i=0; i<MAX_IF_NUM; i++) {
                tmp_if = &apsta_params->if_info[i];
                if (tmp_if->dev) {
-                       chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
-                       if ((chan == 0) || (chan <= CH_MAX_2G_CHANNEL && chan >= CH_MIN_2G_CHANNEL)) {
-                               if (chan == 0) {
+                       wl_ext_get_chan(tmp_if->dev, &chan_info);
+                       if ((chan_info.chan == 0) || (chan_info.band == WLC_BAND_2G)) {
+                               if (chan_info.chan == 0) {
                                        tmp_if->transit_maxcount = WL_TXSTATUS_FREERUNCTR_MASK;
                                } else if (band_5g) {
                                        tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_2g;
@@ -2088,15 +2353,16 @@ static struct wl_if_info *
 wl_ext_get_dfs_master_if(struct wl_apsta_params *apsta_params)
 {
        struct wl_if_info *cur_if = NULL;
-       uint16 chan = 0;
+       struct wl_chan_info chan_info;
        int i;
 
        for (i=0; i<MAX_IF_NUM; i++) {
                cur_if = &apsta_params->if_info[i];
                if (!cur_if->dev || !wl_ext_master_if(cur_if))
                        continue;
-               chan = wl_ext_get_chan(apsta_params, cur_if->dev);
-               if (wl_ext_dfs_chan(chan)) {
+               memset(&chan_info, 0, sizeof(struct wl_chan_info));
+               wl_ext_get_chan(cur_if->dev, &chan_info);
+               if (chan_info.chan && wl_ext_dfs_chan(&chan_info)) {
                        return cur_if;
                }
        }
@@ -2108,7 +2374,7 @@ wl_ext_save_master_channel(struct wl_apsta_params *apsta_params,
        uint16 post_channel)
 {
        struct wl_if_info *cur_if = NULL;
-       uint16 chan = 0;
+       struct wl_chan_info chan_info;
        int i;
 
        if (apsta_params->vsdb)
@@ -2118,14 +2384,68 @@ wl_ext_save_master_channel(struct wl_apsta_params *apsta_params,
                cur_if = &apsta_params->if_info[i];
                if (!cur_if->dev || !wl_ext_master_if(cur_if))
                        continue;
-               chan = wl_ext_get_chan(apsta_params, cur_if->dev);
-               if (chan) {
-                       cur_if->prev_channel = chan;
+               memset(&chan_info, 0, sizeof(struct wl_chan_info));
+               wl_ext_get_chan(cur_if->dev, &chan_info);
+               if (chan_info.chan) {
+                       cur_if->prev_channel = chan_info.chan;
                        cur_if->post_channel = post_channel;
                }
        }
 }
 
+void
+wl_ext_iapsta_enable_master_if(struct net_device *dev, bool post)
+{
+       dhd_pub_t *dhd = dhd_get_pub(dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       struct wl_if_info *cur_if = NULL;
+       int i;
+
+       for (i=0; i<MAX_IF_NUM; i++) {
+               cur_if = &apsta_params->if_info[i];
+               if (cur_if && cur_if->post_channel) {
+                       if (post)
+                               cur_if->chan_info.chan = cur_if->post_channel;
+                       else
+                               cur_if->chan_info.chan = cur_if->prev_channel;
+                       if (wl_ext_associated(cur_if->dev))
+                               wl_ext_if_down(apsta_params, cur_if);
+                       wl_ext_if_up(apsta_params, cur_if, TRUE, 0);
+                       cur_if->prev_channel = 0;
+                       cur_if->post_channel = 0;
+               }
+       }
+}
+
+void
+wl_ext_iapsta_restart_master(struct net_device *dev)
+{
+       dhd_pub_t *dhd = dhd_get_pub(dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       struct wl_if_info *ap_if = NULL;
+
+       if (apsta_params->radar)
+               return;
+
+       ap_if = wl_ext_get_dfs_master_if(apsta_params);
+       if (ap_if) {
+               uint16 chan_2g, chan_5g;
+               wl_ext_if_down(apsta_params, ap_if);
+               wl_ext_iapsta_restart_master(dev);
+               wl_ext_get_default_chan(ap_if->dev, &chan_2g, &chan_5g, TRUE);
+               if (chan_5g)
+                       wl_ext_set_chan_info(ap_if, WLC_BAND_5G, chan_5g);
+               else if (chan_2g)
+                       wl_ext_set_chan_info(ap_if, WLC_BAND_2G, chan_2g);
+               else
+                       ap_if->chan_info.chan = 0;
+               if (ap_if->chan_info.chan) {
+                       wl_ext_move_cur_channel(apsta_params, ap_if);
+                       wl_ext_if_up(apsta_params, ap_if, FALSE, 0);
+               }
+       }
+}
+
 static void
 wl_ext_if_reenabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode, u32 channel)
 {
@@ -2136,7 +2456,7 @@ wl_ext_if_reenabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode, u32 c
                tmp_if = &apsta_params->if_info[i];
                if (tmp_if && tmp_if->ifmode == ifmode &&
                                wl_get_isam_status(tmp_if, IF_READY)) {
-                       if (wl_ext_get_chan(apsta_params, tmp_if->dev) == channel) {
+                       if (wl_ext_get_chan(tmp_if->dev, &tmp_if->chan_info) == channel) {
                            WL_MSG(tmp_if->ifname, "re-enable channel %d\n", channel);
                                if (ifmode == IAP_MODE) {
                                        wl_ext_if_down(apsta_params, tmp_if);
@@ -2150,7 +2470,7 @@ wl_ext_if_reenabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode, u32 c
 }
 
 u32
-wl_ext_iapsta_update_channel(struct net_device *dev, u32 channel)
+wl_ext_iapsta_update_channel(struct net_device *dev, u32 chanspec)
 {
        struct dhd_pub *dhd = dhd_get_pub(dev);
        struct wl_apsta_params *apsta_params = dhd->iapsta_params;
@@ -2159,18 +2479,19 @@ wl_ext_iapsta_update_channel(struct net_device *dev, u32 channel)
 
        cur_if = wl_get_cur_if(dev);
        if (cur_if) {
+               struct wl_chan_info *chan_info = &cur_if->chan_info;
                mutex_lock(&apsta_params->usr_sync);
                wl_ext_isam_status(cur_if->dev, NULL, 0);
-               cur_if->channel = channel;
+               wl_ext_set_chan_info(cur_if, CHSPEC2WLC_BAND(chanspec),
+                       wf_chspec_ctlchan(chanspec));
                if (wl_ext_master_if(cur_if) && apsta_params->acs) {
-                       uint auto_band = WL_GET_BAND(channel);
-                       cur_if->channel = wl_ext_autochannel(cur_if->dev, apsta_params->acs,
-                               auto_band);
-               }
-               channel = wl_ext_move_cur_channel(apsta_params, cur_if);
-               if (channel) {
-                       if (cur_if->ifmode == ISTA_MODE && wl_ext_dfs_chan(channel))
-                               wl_ext_save_master_channel(apsta_params, channel);
+                       chan_info->chan = wl_ext_autochannel(cur_if->dev, apsta_params->acs,
+                               chan_info->band);
+               }
+               chan_info->chan = wl_ext_move_cur_channel(apsta_params, cur_if);
+               if (chan_info->chan) {
+                       if (cur_if->ifmode == ISTA_MODE && wl_ext_dfs_chan(chan_info))
+                               wl_ext_save_master_channel(apsta_params, chan_info->chan);
                        target_if = wl_ext_move_other_channel(apsta_params, cur_if);
                        if (dhd->conf->chip == BCM4359_CHIP_ID &&
                                        cur_if->ifmode == ISTA_MODE && !target_if) {
@@ -2179,22 +2500,23 @@ wl_ext_iapsta_update_channel(struct net_device *dev, u32 channel)
                                 * step2: enable wlan2 on channel 36
                                 * step3: enable wlan0 to connect channel 1 AP, then it will fw trap
                                */
-                               wl_ext_if_reenabled(apsta_params, IAP_MODE, channel);
+                               wl_ext_if_reenabled(apsta_params, IAP_MODE, chan_info->chan);
                        }
                }
                if (cur_if->ifmode == ISTA_MODE) {
-                       if (conf->war & SET_CHAN_INCONN) {
+                       if (conf->war & SET_CHAN_INCONN && chan_info->chan) {
                                chanspec_t fw_chspec;
-                           IAPSTA_INFO(dev->name, "set channel %d\n", channel);
-                           wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver, channel,
-                                   &fw_chspec);
+                           IAPSTA_INFO(dev->name, "set channel %d\n", chan_info->chan);
+                           wl_ext_set_chanspec(cur_if->dev, chan_info, &fw_chspec);
                        }
                        wl_set_isam_status(cur_if, STA_CONNECTING);
                }
+               chanspec = wf_create_chspec_from_primary(chan_info->chan,
+                       CHSPEC_BW(chanspec), wl_ext_wlcband_to_chanspec_band(chan_info->band));
                mutex_unlock(&apsta_params->usr_sync);
        }
 
-       return channel;
+       return chanspec;
 }
 
 static int
@@ -2240,6 +2562,9 @@ wl_ext_iapsta_update_iftype(struct net_device *net, int wl_iftype)
                        cur_if->prio = PRIO_STA;
                        cur_if->vsdb = TRUE;
                        cur_if->prefix = 'S';
+#ifdef WL_STATIC_IF
+                       dhd_conf_preinit_ioctls_sta(dhd, ifidx);
+#endif /* WL_STATIC_IF */
                } else if (wl_iftype == WL_IF_TYPE_AP && cur_if->ifmode != IMESH_MODE) {
                        cur_if->ifmode = IAP_MODE;
                        cur_if->prio = PRIO_AP;
@@ -2295,57 +2620,6 @@ wl_ext_iapsta_iftype_enabled(struct net_device *net, int wl_iftype)
        return FALSE;
 }
 
-void
-wl_ext_iapsta_enable_master_if(struct net_device *dev, bool post)
-{
-       dhd_pub_t *dhd = dhd_get_pub(dev);
-       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
-       struct wl_if_info *cur_if = NULL;
-       int i;
-
-       for (i=0; i<MAX_IF_NUM; i++) {
-               cur_if = &apsta_params->if_info[i];
-               if (cur_if && cur_if->post_channel) {
-                       if (post)
-                               cur_if->channel = cur_if->post_channel;
-                       else
-                               cur_if->channel = cur_if->prev_channel;
-                       wl_ext_if_up(apsta_params, cur_if, TRUE, 0);
-                       cur_if->prev_channel = 0;
-                       cur_if->post_channel = 0;
-               }
-       }
-}
-
-void
-wl_ext_iapsta_restart_master(struct net_device *dev)
-{
-       dhd_pub_t *dhd = dhd_get_pub(dev);
-       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
-       struct wl_if_info *ap_if = NULL;
-
-       if (apsta_params->radar)
-               return;
-
-       ap_if = wl_ext_get_dfs_master_if(apsta_params);
-       if (ap_if) {
-               uint16 chan_2g, chan_5g;
-               wl_ext_if_down(apsta_params, ap_if);
-               wl_ext_iapsta_restart_master(dev);
-               wl_ext_get_default_chan(ap_if->dev, &chan_2g, &chan_5g, TRUE);
-               if (chan_5g)
-                       ap_if->channel = chan_5g;
-               else if (chan_2g)
-                       ap_if->channel = chan_2g;
-               else
-                       ap_if->channel = 0;
-               if (ap_if->channel) {
-                       wl_ext_move_cur_channel(apsta_params, ap_if);
-                       wl_ext_if_up(apsta_params, ap_if, FALSE, 0);
-               }
-       }
-}
-
 bool
 wl_ext_iapsta_mesh_creating(struct net_device *net)
 {
@@ -2395,7 +2669,84 @@ wl_ext_reconnect_timeout(unsigned long data)
                return;
        }
        IAPSTA_ERROR(dev->name, "timer expired\n");
-       wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS);
+       wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WLC_E_STATUS_SUCCESS);
+}
+
+#ifdef WL_EXT_DISCONNECT_RECONNECT
+static bool
+wl_ext_disc_recon_retry(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
+{
+       int sta_disc_recon_cnt = cur_if->sta_disc_recon_cnt;
+       struct osl_timespec *sta_disc_conn_ts = &cur_if->sta_disc_conn_ts;
+       struct osl_timespec cur_ts;
+       uint32 diff_ms = 0;
+       bool retry = FALSE;
+
+       if (sta_disc_recon_cnt == 0)
+               osl_do_gettimeofday(sta_disc_conn_ts);
+
+       osl_do_gettimeofday(&cur_ts);
+       diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_conn_ts)/1000;
+
+       IAPSTA_INFO(cur_if->ifname, "sta_disc_recon_cnt=%d, diff_ms = %dms\n",
+               sta_disc_recon_cnt, diff_ms);
+       if (sta_disc_recon_cnt >= STA_DISCONNECT_RECONNECT_MAX) {
+               if (diff_ms >= STA_DISCONNECT_RECONNECT_TIMEOUT) {
+                       osl_do_gettimeofday(sta_disc_conn_ts);
+                       cur_if->sta_disc_recon_cnt = 0;
+                       retry = TRUE;
+               } else {
+                       retry = FALSE;
+               }
+       } else {
+               retry = TRUE;
+       }
+
+       if (retry)
+               cur_if->sta_disc_recon_cnt++;
+
+       return retry;
+}
+#endif /* WL_EXT_DISCONNECT_RECONNECT */
+
+static void
+wl_ext_update_assoc_info(struct net_device *dev, bool reassoc)
+{
+#ifndef WL_REASSOC_BCAST
+       dhd_pub_t *dhd = dhd_get_pub(dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       struct wl_chan_info chan_info;
+#endif
+       struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
+       wlcfg_assoc_info_t *assoc_info;
+       struct wl_if_info *cur_if;
+
+       cur_if = wl_get_cur_if(dev);
+       if (cur_if) {
+               assoc_info = &cur_if->assoc_info;
+               assoc_info->reassoc = reassoc;
+               assoc_info->bssid_hint = false;
+#ifdef WL_REASSOC_BCAST
+               assoc_info->chan_cnt = 0;
+               assoc_info->chanspecs[0] = 0;
+               memcpy(&assoc_info->bssid, &ether_bcast, ETHER_ADDR_LEN);
+#else
+               assoc_info->chanspecs[0] = wl_ext_get_chanspec(dev, &chan_info);
+               if (assoc_info->chanspecs[0] && reassoc) {
+                       assoc_info->chan_cnt = 1;
+                       wldev_ioctl(dev, WLC_GET_BSSID, &cur_if->bssid, ETHER_ADDR_LEN, 0);
+                       memcpy(&assoc_info->bssid, &cur_if->bssid, ETHER_ADDR_LEN);
+               } else {
+                       assoc_info->chan_cnt = 0;
+                       memcpy(&assoc_info->bssid, &ether_bcast, ETHER_ADDR_LEN);
+               }
+#endif /* WL_REASSOC_BCAST */
+               if (!ETHER_ISBCAST(assoc_info->bssid))
+                       assoc_info->targeted_join = true;
+               else
+                       assoc_info->targeted_join = false;
+               wl_get_assoc_channels(cfg, dev, assoc_info);
+       }
 }
 
 static int
@@ -2405,45 +2756,122 @@ wl_ext_connect_retry(struct net_device *dev, wl_event_msg_t *e)
        struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        struct wl_if_info *cur_if;
        struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
-       struct osl_timespec cur_ts, *sta_conn_ts = &apsta_params->sta_conn_ts;
+       struct osl_timespec cur_ts, *sta_conn_ts;
+       wlcfg_assoc_info_t *assoc_info;
        uint32 diff_ms = 0;
        int max_wait_time = 0, ret = 0;
-       bool connecting = FALSE;
+       bool connecting, handshaking, associated;
+       uint32 etype = ntoh32(e->event_type);
+       uint32 status = ntoh32(e->status);
+
+       if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
+               WL_MSG(dev->name, "skip connect retry due to disconnecting\n");
+               return BCME_BADADDR;
+       }
 
        cur_if = wl_get_cur_if(dev);
        if (!cur_if)
                return ret;
+       sta_conn_ts = &cur_if->sta_conn_ts;
+       connecting = wl_ext_sta_connecting(dev);
+       handshaking = wl_ext_sta_handshaking(dev);
 
        mutex_unlock(&apsta_params->in4way_sync);
        mutex_lock(&cfg->connect_sync);
-       connecting = wl_ext_sta_connecting(dev);
 
        osl_do_gettimeofday(&cur_ts);
        diff_ms = osl_do_gettimediff(&cur_ts, sta_conn_ts)/1000;
+       associated = wl_ext_associated(dev);
+       assoc_info = &cur_if->assoc_info;
 
        if (connecting && diff_ms < STA_CONNECT_TIMEOUT &&
                        !wl_get_drv_status(cfg, DISCONNECTING, dev)) {
-               uint32 etype = ntoh32(e->event_type);
-               uint32 status = ntoh32(e->status);
                if (etype == WLC_E_SET_SSID && (status == WLC_E_STATUS_NO_NETWORKS ||
                                status == WLC_E_STATUS_NO_ACK)) {
-                       wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0);
-                       if (cur_if->assoc_info.reassoc) {
+                       wl_timer_mod(dhd, &cur_if->reconnect_timer, 0);
+                       if (assoc_info->reassoc && associated && !handshaking) {
+                               /* There are two cases will come in to retry reassoc:
+                                * 1) reconnect from wpa_supplicant
+                                * 2) fw roam
+                                */
+                               if (associated)
+                                       bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
                                WL_MSG(dev->name, "retry reassoc\n");
-                               wl_handle_reassoc(cfg, dev, &cur_if->assoc_info);
-                               max_wait_time = STA_RECONNECT_RETRY_TIMEOUT;
-                       } else {
-                               if (!wl_ext_get_chan(apsta_params, dev)) {
-                                       WL_MSG(dev->name, "retry join\n");
-                                       wl_cfg80211_disassoc(dev, WLAN_REASON_DEAUTH_LEAVING);
-                                       wl_handle_join(cfg, dev, &cur_if->assoc_info);
-                                       max_wait_time = STA_CONNECT_RETRY_TIMEOUT;
+                               if (wl_handle_reassoc(cfg, dev, assoc_info))
+                                       goto exit;
+                               if (assoc_info->chan_cnt == 0)
+                                       max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT;
+                               else
+                                       max_wait_time = STA_RECONNECT_RETRY_TIMEOUT +
+                                               (WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt);
+                               max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT);
+                       }
+                       else {
+                               /* There is one case will come in to retry join:
+                                * 1) connect from wpa_supplicant
+                                */
+                               WL_MSG(dev->name, "retry join\n");
+                               if (associated) {
+                                       bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
+                                       wl_cfg80211_disassoc(dev, WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT);
+                               }
+                               if (wl_handle_join(cfg, dev, assoc_info))
+                                       goto exit;
+                               if (assoc_info->chan_cnt == 0)
+                                       max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT;
+                               else
+                                       max_wait_time = STA_CONNECT_RETRY_TIMEOUT +
+                                               (WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt);
+                               max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT);
+                       }
+                       IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time);
+                       wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time);
+               }
+               ret = BCME_ERROR;
+       }
+#ifdef WL_EXT_DISCONNECT_RECONNECT
+       else if (cur_if->conn_state >= CONN_STATE_CONNECTED &&
+                       !wl_get_drv_status(cfg, DISCONNECTING, dev) &&
+                       wl_get_drv_status(cfg, CONNECTED, dev)) {
+               if (etype == WLC_E_DISASSOC_IND || etype == WLC_E_DEAUTH_IND) {
+                       /* There is one case will come in to retry join:
+                        * 1) receive disconnect from AP after connected
+                        */
+                       if (wl_ext_disc_recon_retry(apsta_params, cur_if)) {
+                               int wpa_auth = 0;
+                               WL_MSG(dev->name, "retry join cnt %d\n", cur_if->sta_disc_recon_cnt);
+                               bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
+                               wl_ext_update_assoc_info(dev, FALSE);
+#ifdef DHD_LOSSLESS_ROAMING
+                               wl_ext_send_event_msg(dev, WLC_E_ROAM_PREP, WLC_E_STATUS_SUCCESS, WLC_E_REASON_DEAUTH);
+#endif
+                               if (wl_handle_join(cfg, dev, assoc_info))
+                                       goto exit;
+                               wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT);
+                               osl_do_gettimeofday(sta_conn_ts);
+                               wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING);
+                               wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
+                               if (!(wpa_auth & (WPA3_AUTH_SAE_PSK|0x20))) {
+                                       if (assoc_info->chan_cnt == 0)
+                                               max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT;
+                                       else
+                                               max_wait_time = STA_CONNECT_RETRY_TIMEOUT +
+                                                       (WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt);
+                                       max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT);
+                                       IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time);
+                                       wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time);
                                }
+                               ret = BCME_ERROR;
+                       }
+                       else {
+                               WL_MSG(dev->name, "out of retry cnt %d within %dms\n",
+                                       cur_if->sta_disc_recon_cnt, STA_DISCONNECT_RECONNECT_TIMEOUT);
                        }
-                       wl_ext_mod_timer(&cur_if->reconnect_timer, 0, max_wait_time);
                }
-               ret = -EAGAIN;
        }
+#endif /* WL_EXT_DISCONNECT_RECONNECT */
+
+exit:
        mutex_unlock(&cfg->connect_sync);
        mutex_lock(&apsta_params->in4way_sync);
 
@@ -2453,6 +2881,7 @@ wl_ext_connect_retry(struct net_device *dev, wl_event_msg_t *e)
 static void
 wl_ext_set_connect_retry(struct net_device *dev, void *context)
 {
+       struct dhd_pub *dhd = dhd_get_pub(dev);
        wlcfg_assoc_info_t *assoc_info = (wlcfg_assoc_info_t *)context;
        struct wl_if_info *cur_if;
        int max_wait_time;
@@ -2462,21 +2891,90 @@ wl_ext_set_connect_retry(struct net_device *dev, void *context)
        if (!cur_if)
                return;
 
-       wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0);
+       wl_timer_mod(dhd, &cur_if->reconnect_timer, 0);
        memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t));
        wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
        if (!(wpa_auth & (WPA3_AUTH_SAE_PSK|0x20) && assoc_info)) {
                memcpy(&cur_if->bssid, assoc_info->bssid, ETHER_ADDR_LEN);
                memcpy(&cur_if->assoc_info, assoc_info, sizeof(wlcfg_assoc_info_t));
-               if (assoc_info->reassoc)
+               if (assoc_info->chan_cnt == 0)
+                       max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT;
+               else if (assoc_info->reassoc)
                        max_wait_time = STA_RECONNECT_RETRY_TIMEOUT;
                else
                        max_wait_time = STA_CONNECT_RETRY_TIMEOUT;
                IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time);
-               wl_ext_mod_timer(&cur_if->reconnect_timer, 0, max_wait_time);
+               wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time);
        }
 }
 #endif /* WL_EXT_RECONNECT */
+
+#ifdef STA_MGMT
+static void
+wl_ext_flush_sta_list(struct net_device *net, int ifidx)
+{
+       struct dhd_pub *dhd = dhd_get_pub(net);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       wl_sta_info_t *node, *next;
+
+       list_for_each_entry_safe(node, next, &apsta_params->sta_list, list) {
+               if (node->ifidx == ifidx || ifidx == 0xFF) {
+                       IAPSTA_INFO(net->name, "Del BSSID %pM\n", &node->bssid);
+                       list_del(&node->list);
+                       kfree(node);
+               }
+       }
+}
+
+bool
+wl_ext_del_sta_info(struct net_device *net, u8 *bssid)
+{
+       struct dhd_pub *dhd = dhd_get_pub(net);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       int ifidx = dhd_net2idx(dhd->info, net);
+       wl_sta_info_t *node, *next;
+       bool in_list = FALSE;
+
+       list_for_each_entry_safe(node, next, &apsta_params->sta_list, list) {
+               if (node->ifidx == ifidx && !memcmp(&node->bssid, bssid, ETHER_ADDR_LEN)) {
+                       IAPSTA_INFO(net->name, "Del BSSID %pM\n", &node->bssid);
+                       in_list = TRUE;
+                       list_del(&node->list);
+                       kfree(node);
+               }
+       }
+       return in_list;
+}
+
+bool
+wl_ext_add_sta_info(struct net_device *net, u8 *bssid)
+{
+       struct dhd_pub *dhd = dhd_get_pub(net);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       int ifidx = dhd_net2idx(dhd->info, net);
+       wl_sta_info_t *node, *next, *leaf;
+
+       list_for_each_entry_safe(node, next, &apsta_params->sta_list, list) {
+               if (node->ifidx == ifidx && !memcmp(&node->bssid, bssid, ETHER_ADDR_LEN)) {
+                       IAPSTA_INFO(net->name, "BSSID %pM already in list\n", bssid);
+                       return FALSE;
+               }
+       }
+
+       leaf = kmalloc(sizeof(wl_sta_info_t), GFP_KERNEL);
+       if (!leaf) {
+               IAPSTA_ERROR(net->name, "Memory alloc failure %d\n",
+                       (int)sizeof(wl_sta_info_t));
+               return FALSE;
+       }
+       IAPSTA_INFO(net->name, "Add BSSID %pM in the leaf\n", bssid);
+       leaf->ifidx = ifidx;
+       memcpy(&leaf->bssid, bssid, ETHER_ADDR_LEN);
+       list_add_tail(&leaf->list, &apsta_params->sta_list);
+
+       return TRUE;
+}
+#endif /* STA_MGMT */
 #endif /* WL_CFG80211 */
 
 #ifndef WL_STATIC_IF
@@ -2729,7 +3227,7 @@ wl_ext_update_conn_state(dhd_pub_t *dhd, int ifidx, uint conn_state)
                                        conn_state >= CONN_STATE_CONNECTED ||
                                        conn_state <= CONN_STATE_CONNECTING)
                                apsta_params->if_info[ifidx].conn_state = conn_state;
-                        else
+                       else
                                IAPSTA_INFO(cur_if->dev->name, "skip update %d\n", conn_state);
                } else {
                        apsta_params->if_info[ifidx].conn_state = conn_state;
@@ -2784,7 +3282,7 @@ wl_ext_free_eapol_txpkt(struct wl_if_info *cur_if, bool rx)
 #ifdef BCMDBUS
        if (!rx)
 #endif /* BCMDBUS */
-       wl_ext_mod_timer(&cur_if->eapol_timer, 0, 0);
+       wl_timer_mod(dhd, &cur_if->eapol_timer, 0);
 
        if (cur_if->pend_eapol_pkt) {
                PKTCFREE(dhd->osh, cur_if->pend_eapol_pkt, TRUE);
@@ -2843,7 +3341,7 @@ wl_ext_backup_eapol_txpkt(dhd_pub_t *dhd, int ifidx, void *pkt)
 #else
                                interval = STA_EAPOL_TIMEOUT;
 #endif /* EAPOL_DYNAMATIC_RESEND */
-                               wl_ext_mod_timer(&cur_if->eapol_timer, 0, interval);
+                               wl_timer_mod(dhd, &cur_if->eapol_timer, interval);
                                IAPSTA_TRACE(cur_if->dev->name, "backup eapol pkt\n");
                        }
                        spin_unlock_irqrestore(&apsta_params->eapol_lock, flags);
@@ -2877,7 +3375,7 @@ wl_resend_eapol_handler(struct wl_if_info *cur_if,
                                        cur_if->eapol_max_intvl, STA_EAPOL_TIMEOUT,
                                        cur_if->eapol_cnt);
 #else
-                               IAPSTA_INFO(dev->name, "resend eapol pkt %d\n", STA_EAPOL_TIMEOUT);
+                               IAPSTA_INFO(dev->name, "resend eapol pkt %dms\n", STA_EAPOL_TIMEOUT);
 #endif /* EAPOL_DYNAMATIC_RESEND */
                                pending = TRUE;
                        }
@@ -2906,89 +3404,186 @@ wl_eapol_timer(unsigned long data)
        bzero(&msg, sizeof(wl_event_msg_t));
        IAPSTA_TRACE(dev->name, "timer expired\n");
 
-       msg.ifidx = hton32(dhd_net2idx(dhd->info, dev));
+       msg.ifidx = dhd_net2idx(dhd->info, dev);
        msg.event_type = hton32(WLC_E_RESERVED);
        msg.reason = hton32(ISAM_RC_EAPOL_RESEND);
        wl_ext_event_send(dhd->event_params, &msg, NULL);
 }
 #endif /* EAPOL_RESEND */
 
-#if defined(WL_CFG80211) && defined(SCAN_SUPPRESS)
+#ifdef KEY_INSTALL_CHECK
 static void
-wl_ext_light_scan_prep(struct net_device *dev, void *scan_params, bool scan_v2)
+wl_ext_key_install_timeout(unsigned long data)
 {
-       wl_scan_params_t *params = NULL;
-       wl_scan_params_v2_t *params_v2 = NULL;
+       struct net_device *dev = (struct net_device *)data;
+       struct dhd_pub *dhd;
+       wl_event_msg_t msg;
 
-       if (!scan_params) {
-               IAPSTA_ERROR(dev->name, "NULL scan_params\n");
+       if (!dev) {
+               IAPSTA_ERROR("wlan", "dev is not ready\n");
                return;
        }
-       IAPSTA_INFO(dev->name, "Enter\n");
 
-       if (scan_v2) {
-               params_v2 = (wl_scan_params_v2_t *)scan_params;
-       } else {
-               params = (wl_scan_params_t *)scan_params;
-       }
+       dhd = dhd_get_pub(dev);
 
-       if (params_v2) {
-               /* scan params ver2 */
-               params_v2->nprobes = 1;
-               params_v2->active_time = 20;
-               params_v2->home_time = 150;
-       } else {
-               /* scan params ver 1 */
-               if (!params) {
-                       ASSERT(0);
-                       return;
-               }
-               params->nprobes = 1;
-               params->active_time = 20;
-               params->home_time = 150;
+       bzero(&msg, sizeof(wl_event_msg_t));
+       IAPSTA_TRACE(dev->name, "timer expired\n");
+
+       msg.ifidx = dhd_net2idx(dhd->info, dev);
+       msg.event_type = hton32(WLC_E_RESERVED);
+       msg.reason = hton32(ISAM_RC_KEY_INSTALL);
+       wl_ext_event_send(dhd->event_params, &msg, NULL);
+}
+
+static void
+wl_ext_key_install_handler(struct wl_if_info *cur_if,
+       const wl_event_msg_t *e, void *data)
+{
+       struct net_device *dev = cur_if->dev;
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
+       uint32 etype = ntoh32(e->event_type);
+       uint32 reason = ntoh32(e->reason);
+       int err, key_installed = 0;
+
+       if (etype == WLC_E_RESERVED && reason == ISAM_RC_KEY_INSTALL) {
+               if (cur_if->conn_state >= CONN_STATE_4WAY_M4 &&
+                               !wl_get_drv_status(cfg, DISCONNECTING, dev) &&
+                               wl_get_drv_status(cfg, CONNECTED, dev)) {
+                       err = wldev_iovar_getint(dev, "buf_key_b4_m4_installed", &key_installed);
+                       if (!err && !key_installed) {
+                               cur_if->key_install_cnt++;
+                               if (cur_if->key_install_cnt > STA_KEY_INSTALL_MAX) {
+                                       IAPSTA_ERROR(dev->name, "key not installed, send disconnect\n");
+#ifdef EAPOL_RESEND
+                                       wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
+#endif /* EAPOL_RESEND */
+                                       wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED);
+                                       wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
+                                       wl_timer_mod(dhd, &cur_if->key_install_timer, 0);
+                                       cur_if->key_install_cnt = 0;
+                               } else {
+                                       IAPSTA_INFO(dev->name, "check key installed %dms later, cnt=%d\n",
+                                               STA_KEY_INSTALL_INTERVAL, cur_if->key_install_cnt);
+                                       wl_timer_mod(dhd, &cur_if->key_install_timer, STA_KEY_INSTALL_INTERVAL);
+                               }
+                       } else {
+#ifdef EAPOL_RESEND
+                               wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
+#endif /* EAPOL_RESEND */
+                               IAPSTA_INFO(dev->name, "key installed\n");
+                               wl_timer_mod(dhd, &cur_if->connect_timer, 0);
+                               wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED);
+                               cur_if->key_install_cnt = 0;
+                       }
+               }
+       }
+       return;
+}
+
+static int
+wl_key_installed(struct wl_if_info *cur_if)
+{
+       struct net_device *dev = cur_if->dev;
+       dhd_pub_t *dhd = dhd_get_pub(dev);
+       int err, key_installed = 0;
+
+       err = wldev_iovar_getint(dev, "buf_key_b4_m4_installed", &key_installed);
+       if (err) {
+               IAPSTA_INFO(dev->name, "not supported %d\n", err);
+               key_installed = 1;
+       } else if (key_installed)
+               IAPSTA_INFO(dev->name, "key installed\n");
+
+       if (key_installed)
+               wl_timer_mod(dhd, &cur_if->key_install_timer, 0);
+       else {
+               IAPSTA_INFO(dev->name, "check key installed %dms later\n", STA_KEY_INSTALL_INTERVAL);
+               wl_timer_mod(dhd, &cur_if->key_install_timer, STA_KEY_INSTALL_INTERVAL);
+       }
+
+       return key_installed;
+}
+#endif /* KEY_INSTALL_CHECK */
+
+#if defined(WL_CFG80211) && defined(SCAN_SUPPRESS)
+static void
+wl_ext_light_scan_prep(struct net_device *dev, void *scan_params, bool scan_v2)
+{
+       wl_scan_params_v1_t *params = NULL;
+       wl_scan_params_v2_t *params_v2 = NULL;
+
+       if (!scan_params) {
+               IAPSTA_ERROR(dev->name, "NULL scan_params\n");
+               return;
+       }
+       IAPSTA_INFO(dev->name, "Enter\n");
+
+       if (scan_v2) {
+               params_v2 = (wl_scan_params_v2_t *)scan_params;
+       } else {
+               params = (wl_scan_params_v1_t *)scan_params;
+       }
+
+       if (params_v2) {
+               /* scan params ver2 */
+               params_v2->nprobes = 1;
+               params_v2->active_time = 20;
+               params_v2->home_time = 150;
+       } else {
+               /* scan params ver 1 */
+               if (!params) {
+                       ASSERT(0);
+                       return;
+               }
+               params->nprobes = 1;
+               params->active_time = 20;
+               params->home_time = 150;
        }
 
        return;
 }
 
 static uint16
-wl_ext_max_tput_chan(struct wl_apsta_params *apsta_params)
+wl_ext_max_tput_chan(struct wl_apsta_params *apsta_params,
+       struct wl_chan_info *chan_info)
 {
        struct wl_if_info *tmp_if, *max_tput_if = NULL;
-       uint16 chan = 0, max_tput_chan = 0;
        int32 tput_sum = 0;
        int i;
 
        for (i=0; i<MAX_IF_NUM; i++) {
                tmp_if = &apsta_params->if_info[i];
-               if (tmp_if->dev && (tmp_if->tput_tx + tmp_if->tput_rx) > tput_sum) {
-                       chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
-                       if (chan) {
+               if (tmp_if->dev && (tmp_if->tput_info.tput_tx + tmp_if->tput_info.tput_rx) > tput_sum) {
+                       memset(chan_info, 0, sizeof(struct wl_chan_info));
+                       wl_ext_get_chan(tmp_if->dev, chan_info);
+                       if (chan_info->chan) {
                                max_tput_if = tmp_if;
-                               tput_sum = tmp_if->tput_tx + tmp_if->tput_rx;
-                               max_tput_chan = chan;
+                               tput_sum = tmp_if->tput_info.tput_tx + tmp_if->tput_info.tput_rx;
                                break;
                        }
                }
        }
 
-       if (max_tput_chan)
-               IAPSTA_INFO(max_tput_if->dev->name, "chan=%d\n", max_tput_chan);
+       if (max_tput_if)
+               IAPSTA_INFO(max_tput_if->dev->name, "chan=%s-%d\n",
+                       WLCBAND2STR(chan_info->band), chan_info->chan);
 
-       return max_tput_chan;
+       return chan_info->chan;
 }
 
 uint16
-wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2)
+wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2,
+       struct wl_chan_info *chan_info)
 {
        struct dhd_pub *dhd = dhd_get_pub(dev);
        struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        struct dhd_conf *conf = dhd->conf;
-       uint16 chan = 0;
 
        if (!(conf->scan_intput & (SCAN_CURCHAN_INTPUT|SCAN_LIGHT_INTPUT)))
                return 0;
 
+       memset(chan_info, 0, sizeof(struct wl_chan_info));
        if (apsta_params->tput_sum >= conf->scan_tput_thresh) {
                IAPSTA_INFO(dev->name, "tput %dMbps >= %dMbps (busy cnt/thresh %d/%d)\n",
                        apsta_params->tput_sum, conf->scan_tput_thresh,
@@ -2996,9 +3591,9 @@ wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2)
                if (apsta_params->scan_busy_cnt >= conf->scan_busy_thresh) {
                        apsta_params->scan_busy_cnt = 0;
                } else if (conf->scan_intput & SCAN_CURCHAN_INTPUT) {
-                       chan = wl_ext_max_tput_chan(apsta_params);
+                       wl_ext_max_tput_chan(apsta_params, chan_info);
                }
-               if ((conf->scan_intput & SCAN_LIGHT_INTPUT) && !chan)
+               if ((conf->scan_intput & SCAN_LIGHT_INTPUT) && !chan_info->chan)
                        wl_ext_light_scan_prep(dev, scan_params, scan_v2);
                apsta_params->scan_busy_cnt++;
        }
@@ -3006,7 +3601,7 @@ wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2)
                apsta_params->scan_busy_cnt = 0;
        }
 
-       return chan;
+       return chan_info->chan;
 }
 
 static int
@@ -3100,7 +3695,6 @@ wl_set_btc_in4way(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_i
                        }
                }
        }
-
 }
 
 static void
@@ -3108,7 +3702,7 @@ wl_wait_disconnect(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_
        enum wl_ext_status status)
 {
        struct net_device *dev = cur_if->dev;
-       struct osl_timespec cur_ts, *sta_disc_ts = &apsta_params->sta_disc_ts;
+       struct osl_timespec cur_ts, *sta_disc_ts = &cur_if->sta_disc_ts;
        int max_wait_time = 200, max_wait_cnt = 20;
        int cur_conn_state = cur_if->conn_state;
        uint32 diff_ms = 0;
@@ -3158,13 +3752,13 @@ wl_iapsta_suspend_resume_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if,
 
        if (suspend) {
                if (insuspend & AP_DOWN_IN_SUSPEND) {
-                       cur_if->channel = wl_ext_get_chan(apsta_params, cur_if->dev);
-                       if (cur_if->channel)
+                       cur_if->chan_info.chan = wl_ext_get_chan(cur_if->dev, &cur_if->chan_info);
+                       if (cur_if->chan_info.chan)
                                wl_ext_if_down(apsta_params, cur_if);
                }
        } else {
                if (insuspend & AP_DOWN_IN_SUSPEND) {
-                       if (cur_if->channel)
+                       if (cur_if->chan_info.chan)
                                wl_ext_if_up(apsta_params, cur_if, FALSE, 0);
                }
        }
@@ -3181,7 +3775,7 @@ wl_iapsta_suspend_resume(dhd_pub_t *dhd, int suspend)
 
 #ifdef TPUT_MONITOR
        if (suspend)
-               wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0);
+               wl_timer_mod(dhd, &apsta_params->monitor_timer, 0);
 #endif /* TPUT_MONITOR */
 
        for (i=0; i<MAX_IF_NUM; i++) {
@@ -3200,7 +3794,7 @@ wl_iapsta_suspend_resume(dhd_pub_t *dhd, int suspend)
 
 #ifdef TPUT_MONITOR
        if (!suspend)
-               wl_ext_mod_timer(&apsta_params->monitor_timer, 0, dhd->conf->tput_monitor_ms);
+               wl_timer_mod(dhd, &apsta_params->monitor_timer, dhd->conf->tput_monitor_ms);
 #endif /* TPUT_MONITOR */
 
        return 0;
@@ -3213,11 +3807,11 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
        struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        struct dhd_conf *conf = dhd->conf;
        struct net_device *dev = cur_if->dev;
-       struct osl_timespec cur_ts, *sta_disc_ts = &apsta_params->sta_disc_ts;
-       struct osl_timespec *sta_conn_ts = &apsta_params->sta_conn_ts;
+       struct osl_timespec cur_ts, *sta_disc_ts = &cur_if->sta_disc_ts;
+       struct osl_timespec *sta_conn_ts = &cur_if->sta_conn_ts;
        uint32 diff_ms = 0;
-       int ret = 0, cur_conn_state;
-       int suppressed = 0, wpa_auth = 0;
+       int ret = 0, suppressed = 0, wpa_auth = 0, max_wait_time = 0, key_installed = 1;
+       uint cur_conn_state, conn_state;
        bool connecting = FALSE;
        wl_event_msg_t *e = (wl_event_msg_t *)context;
 #ifdef WL_CFG80211
@@ -3268,7 +3862,8 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                                osl_do_gettimeofday(&cur_ts);
                                diff_ms = osl_do_gettimediff(&cur_ts, sta_conn_ts)/1000;
                                if (connecting && diff_ms <= STA_CONNECT_TIMEOUT) {
-                                       IAPSTA_ERROR(dev->name, "connecting... %d\n", cur_conn_state);
+                                       IAPSTA_ERROR(dev->name, "scan during connecting... %d\n",
+                                               cur_conn_state);
                                        ret = -EBUSY;
                                        break;
                                }
@@ -3282,34 +3877,25 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                                if (wl_get_drv_status(cfg, CONNECTING, dev) ||
                                                (connecting && diff_ms <= STA_CONNECT_TIMEOUT) ||
                                                (cur_if->empty_scan >= STA_EMPTY_SCAN_MAX)) {
-                                       unsigned long flags = 0;
                                        cur_if->empty_scan = 0;
-                                       spin_lock_irqsave(&dhd->up_lock, flags);
-                                       if (dhd->up) {
-                                               wl_event_msg_t msg;
-                                               bzero(&msg, sizeof(wl_event_msg_t));
-                                               msg.event_type = hton32(WLC_E_ESCAN_RESULT);
-                                               msg.status = hton32(WLC_E_STATUS_SUCCESS);
-                                               WL_MSG(dev->name, "FAKE SCAN\n");
-                                               wl_cfg80211_event(dev, &msg, NULL);
-                                               ret = -EBUSY;
-                                       }
-                                       spin_unlock_irqrestore(&dhd->up_lock, flags);
+                                       WL_MSG(dev->name, "FAKE SCAN\n");
+                                       ret = -EBUSY;
                                }
                        }
                        break;
                case WL_EXT_STATUS_SCAN_COMPLETE:
-                       if ((conf->war & FW_REINIT_EMPTY_SCAN) && cfg->bss_list->count == 0) {
-                               uint16 channel;
+                       if ((conf->war & FW_REINIT_EMPTY_SCAN) &&
+                                       cfg->bss_list->count == 0 && !p2p_scan(cfg)) {
+                               bool assoc;
                                osl_do_gettimeofday(&cur_ts);
                                diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_ts)/1000;
-                               channel = wl_ext_get_chan(apsta_params, dev);
+                               assoc = wl_ext_associated(dev);
                                cur_if->empty_scan++;
-                               if ((channel && cur_if->empty_scan >= STA_EMPTY_SCAN_MAX) ||
+                               if ((assoc && cur_if->empty_scan >= STA_EMPTY_SCAN_MAX) ||
                                                (diff_ms < STA_LINKDOWN_TIMEOUT &&
                                                apsta_params->linkdown_reason == WLC_E_LINK_BCN_LOSS)) {
                                        if (conf->chip == BCM43569_CHIP_ID) {
-                                               if (channel) {
+                                               if (assoc) {
                                                        IAPSTA_INFO(dev->name, "wl disassoc for empty scan\n");
                                                        wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
                                                }
@@ -3324,18 +3910,26 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                        }
                        break;
 #endif /* WL_CFG80211 */
-               case WL_EXT_STATUS_DISCONNECTING:
+               case WL_EXT_STATUS_PRE_DISCONNECTING:
 #ifdef EAPOL_RESEND
                        wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
 #endif /* EAPOL_RESEND */
-                       wl_ext_mod_timer(&cur_if->connect_timer, 0, 0);
+#ifdef KEY_INSTALL_CHECK
+                       wl_timer_mod(dhd, &cur_if->key_install_timer, 0);
+#endif /* KEY_INSTALL_CHECK */
+                       wl_timer_mod(dhd, &cur_if->connect_timer, 0);
 #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
-                       wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0);
+                       wl_timer_mod(dhd, &cur_if->reconnect_timer, 0);
                        memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t));
+#ifdef WL_EXT_DISCONNECT_RECONNECT
+                       cur_if->sta_disc_recon_cnt = 0;
+#endif /* WL_EXT_DISCONNECT_RECONNECT */
 #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
 #ifdef SCAN_SUPPRESS
                        apsta_params->scan_busy_cnt = 0;
 #endif /* SCAN_SUPPRESS */
+                       break;
+               case WL_EXT_STATUS_DISCONNECTING:
                        if (connecting) {
                                IAPSTA_ERROR(dev->name, "connect failed at %d\n", cur_conn_state);
                                wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_IDLE);
@@ -3343,6 +3937,9 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                        if (action & STA_NO_BTC_IN4WAY) {
                                wl_set_btc_in4way(apsta_params, cur_if, status, FALSE);
                        }
+#ifdef BTC_WAR
+                       wl_ext_btc_config(cur_if->dev, FALSE);
+#endif /* BTC_WAR */
                        if (action & STA_WAIT_DISCONNECTED) {
                                wl_wait_disconnect(apsta_params, cur_if, status);
                                wake_up_interruptible(&conf->event_complete);
@@ -3353,8 +3950,11 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                        if (action & STA_REASSOC_RETRY) {
                                wl_ext_set_connect_retry(dev, context);
                        }
+#ifdef WL_EXT_DISCONNECT_RECONNECT
+                       cur_if->sta_disc_recon_cnt = 0;
+#endif /* WL_EXT_DISCONNECT_RECONNECT */
 #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
-                       wl_ext_mod_timer(&cur_if->connect_timer, 0, STA_CONNECT_TIMEOUT);
+                       wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT);
                        osl_do_gettimeofday(sta_conn_ts);
                        wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING);
                        if (action & STA_NO_BTC_IN4WAY) {
@@ -3364,12 +3964,18 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                case WL_EXT_STATUS_CONNECTED:
                        wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
                        if ((wpa_auth < WPA_AUTH_UNSPECIFIED) || (wpa_auth & WPA2_AUTH_FT)) {
-                               wl_ext_mod_timer(&cur_if->connect_timer, 0, 0);
+                               wl_timer_mod(dhd, &cur_if->connect_timer, 0);
                                wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED);
+#ifdef BTC_WAR
+                               wl_ext_btc_config(cur_if->dev, TRUE);
+#endif /* BTC_WAR */
+                               max_wait_time = 0;
+                       } else {
+                               max_wait_time = STA_4WAY_TIMEOUT;
                        }
 #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
-                       wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0);
-                       memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t));
+                       wl_ext_update_assoc_info(dev, TRUE);
+                       wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time);
 #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
                        if (cur_if->ifmode == ISTA_MODE) {
                                dhd_conf_set_wme(dhd, cur_if->ifidx, 0);
@@ -3379,6 +3985,31 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                                dhd_conf_set_mchan_bw(dhd, WL_P2P_IF_CLIENT, -1);
                        }
                        break;
+               case WL_EXT_STATUS_ROAMED:
+                       wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
+                       if ((wpa_auth >= WPA_AUTH_UNSPECIFIED) && !(wpa_auth & WPA2_AUTH_FT)) {
+                               wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT);
+                               osl_do_gettimeofday(sta_conn_ts);
+                               wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING);
+#ifdef BTC_WAR
+                               wl_ext_btc_config(cur_if->dev, TRUE);
+#endif /* BTC_WAR */
+                               max_wait_time = STA_4WAY_TIMEOUT;
+                       } else {
+                               max_wait_time = 0;
+                       }
+#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
+                       wl_ext_update_assoc_info(dev, TRUE);
+                       wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time);
+#endif /* WL_EXT_RECONNECT && WL_CFG80211 */
+#ifdef KEY_INSTALL_CHECK
+                       wl_timer_mod(dhd, &cur_if->key_install_timer, 0);
+#endif /* KEY_INSTALL_CHECK */
+                       if (cur_if->ifmode == ISTA_MODE) {
+                               dhd_conf_set_wme(dhd, cur_if->ifidx, 0);
+                               wake_up_interruptible(&conf->event_complete);
+                       }
+                       break;
                case WL_EXT_STATUS_RECONNECT:
 #ifdef EAPOL_RESEND
                        wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
@@ -3393,9 +4024,15 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
 #ifdef EAPOL_RESEND
                        wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
 #endif /* EAPOL_RESEND */
+#ifdef KEY_INSTALL_CHECK
+                       wl_timer_mod(dhd, &cur_if->key_install_timer, 0);
+#endif /* KEY_INSTALL_CHECK */
 #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
-                       wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0);
+                       wl_timer_mod(dhd, &cur_if->reconnect_timer, 0);
                        memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t));
+#ifdef WL_EXT_DISCONNECT_RECONNECT
+                       cur_if->sta_disc_recon_cnt = 0;
+#endif /* WL_EXT_DISCONNECT_RECONNECT */
 #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
 #ifdef SCAN_SUPPRESS
                        apsta_params->scan_busy_cnt = 0;
@@ -3404,7 +4041,7 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                                        !(ntoh16(e->flags) & WLC_EVENT_MSG_LINK)) {
                                apsta_params->linkdown_reason = ntoh32(e->reason);
                        }
-                       wl_ext_mod_timer(&cur_if->connect_timer, 0, 0);
+                       wl_timer_mod(dhd, &cur_if->connect_timer, 0);
                        if (connecting) {
                                IAPSTA_ERROR(dev->name, "connect failed at %d\n", cur_conn_state);
                        }
@@ -3412,23 +4049,37 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                        if (action & STA_NO_BTC_IN4WAY) {
                                wl_set_btc_in4way(apsta_params, cur_if, status, FALSE);
                        }
+#ifdef BTC_WAR
+                       wl_ext_btc_config(cur_if->dev, FALSE);
+#endif /* BTC_WAR */
                        osl_do_gettimeofday(sta_disc_ts);
                        wake_up_interruptible(&conf->event_complete);
                        break;
                case WL_EXT_STATUS_ADD_KEY:
-                       wl_ext_mod_timer(&cur_if->connect_timer, 0, 0);
-                       wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED);
-#ifdef EAPOL_RESEND
-                       wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
-#endif /* EAPOL_RESEND */
+                       conn_state = CONN_STATE_ADD_KEY;
+                       wl_timer_mod(dhd, &cur_if->connect_timer, 0);
 #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
-                       wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0);
+                       wl_timer_mod(dhd, &cur_if->reconnect_timer, 0);
 #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
+#ifdef KEY_INSTALL_CHECK
+                       key_installed = wl_key_installed(cur_if);
+#endif /* KEY_INSTALL_CHECK */
+                       if (key_installed)
+                               conn_state = CONN_STATE_CONNECTED;
+                       wl_ext_update_conn_state(dhd, cur_if->ifidx, conn_state);
+                       IAPSTA_INFO(dev->name, "WPA 4-WAY complete %d => %d\n",
+                               cur_conn_state, conn_state);
+#ifdef EAPOL_RESEND
+                       if (key_installed)
+                               wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE);
+#endif /* EAPOL_RESEND */
                        if (action & STA_NO_BTC_IN4WAY) {
                                wl_set_btc_in4way(apsta_params, cur_if, status, FALSE);
                        }
+#ifdef BTC_WAR
+                       wl_ext_btc_config(cur_if->dev, TRUE);
+#endif /* BTC_WAR */
                        wake_up_interruptible(&conf->event_complete);
-                       IAPSTA_INFO(dev->name, "WPA 4-WAY complete %d\n", cur_conn_state);
                        break;
                default:
                        IAPSTA_INFO(dev->name, "Unknown action=0x%x, status=%d\n", action, status);
@@ -3444,8 +4095,8 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if,
 {
        struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        struct net_device *dev = cur_if->dev;
-       struct osl_timespec cur_ts, *ap_disc_sta_ts = &apsta_params->ap_disc_sta_ts;
-       u8 *ap_disc_sta_bssid = (u8*)&apsta_params->ap_disc_sta_bssid;
+       struct osl_timespec cur_ts, *ap_disc_sta_ts = &cur_if->ap_disc_sta_ts;
+       u8 *ap_disc_sta_bssid = (u8*)&cur_if->ap_disc_sta_bssid;
        uint32 diff_ms = 0, timeout, max_wait_time = 300;
        int ret = 0, suppressed = 0;
        u8* mac_addr = context;
@@ -3464,12 +4115,25 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                                break;
                        }
                        break;
+               case WL_EXT_STATUS_AP_ENABLING:
+#ifdef RESTART_AP_WAR
+                       wl_timer_mod(dhd, &cur_if->restart_ap_timer, AP_RESTART_TIMEOUT);
+#endif /* RESTART_AP_WAR */
+                       break;
                case WL_EXT_STATUS_AP_ENABLED:
+#ifdef RESTART_AP_WAR
+                       wl_timer_mod(dhd, &cur_if->restart_ap_timer, 0);
+#endif /* RESTART_AP_WAR */
                        if (cur_if->ifmode == IAP_MODE)
                                dhd_conf_set_wme(dhd, cur_if->ifidx, 1);
                        else if (cur_if->ifmode == IGO_MODE)
                                dhd_conf_set_mchan_bw(dhd, WL_P2P_IF_GO, -1);
                        break;
+               case WL_EXT_STATUS_AP_DISABLING:
+#ifdef RESTART_AP_WAR
+                       wl_timer_mod(dhd, &cur_if->restart_ap_timer, 0);
+#endif /* RESTART_AP_WAR */
+                       break;
                case WL_EXT_STATUS_DELETE_STA:
                        if (action & AP_WAIT_STA_RECONNECT) {
                                osl_do_gettimeofday(&cur_ts);
@@ -3485,13 +4149,13 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                                }
                                if (wait) {
                                        IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d, waiting %dms ...\n",
-                                               status, apsta_params->ap_recon_sta, max_wait_time);
+                                               status, cur_if->ap_recon_sta, max_wait_time);
                                        mutex_unlock(&apsta_params->in4way_sync);
-                                       timeout = wait_event_interruptible_timeout(apsta_params->ap_recon_sta_event,
-                                               apsta_params->ap_recon_sta, msecs_to_jiffies(max_wait_time));
+                                       timeout = wait_event_interruptible_timeout(cur_if->ap_recon_sta_event,
+                                               cur_if->ap_recon_sta, msecs_to_jiffies(max_wait_time));
                                        mutex_lock(&apsta_params->in4way_sync);
                                        IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d, timeout=%d\n",
-                                               status, apsta_params->ap_recon_sta, timeout);
+                                               status, cur_if->ap_recon_sta, timeout);
                                        if (timeout > 0) {
                                                IAPSTA_INFO(dev->name, "skip delete STA %pM\n", mac_addr);
                                                ret = -1;
@@ -3499,8 +4163,8 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                                        }
                                } else {
                                        IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d => 0\n",
-                                               status, apsta_params->ap_recon_sta);
-                                       apsta_params->ap_recon_sta = FALSE;
+                                               status, cur_if->ap_recon_sta);
+                                       cur_if->ap_recon_sta = FALSE;
                                        if (cur_if->ifmode == IGO_MODE)
                                                wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_IDLE);
                                }
@@ -3509,10 +4173,10 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                case WL_EXT_STATUS_STA_DISCONNECTED:
                        if (action & AP_WAIT_STA_RECONNECT) {
                                IAPSTA_INFO(dev->name, "latest disc STA %pM ap_recon_sta=%d\n",
-                                       ap_disc_sta_bssid, apsta_params->ap_recon_sta);
+                                       ap_disc_sta_bssid, cur_if->ap_recon_sta);
                                osl_do_gettimeofday(ap_disc_sta_ts);
                                memcpy(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN);
-                               apsta_params->ap_recon_sta = FALSE;
+                               cur_if->ap_recon_sta = FALSE;
                        }
                        break;
                case WL_EXT_STATUS_STA_CONNECTED:
@@ -3522,11 +4186,11 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if,
                                if (diff_ms < max_wait_time &&
                                                !memcmp(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN)) {
                                        IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d => 1\n",
-                                               status, apsta_params->ap_recon_sta);
-                                       apsta_params->ap_recon_sta = TRUE;
-                                       wake_up_interruptible(&apsta_params->ap_recon_sta_event);
+                                               status, cur_if->ap_recon_sta);
+                                       cur_if->ap_recon_sta = TRUE;
+                                       wake_up_interruptible(&cur_if->ap_recon_sta_event);
                                } else {
-                                       apsta_params->ap_recon_sta = FALSE;
+                                       cur_if->ap_recon_sta = FALSE;
                                }
                        }
                        break;
@@ -3664,6 +4328,29 @@ wl_ext_in4way_sync_wext(struct net_device *dev, uint action,
 #endif /* WL_WIRELESS_EXT */
 
 #ifdef TPUT_MONITOR
+static void
+wl_tput_monitor_timer(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct dhd_pub *dhd;
+       wl_event_msg_t msg;
+
+       if (!dev) {
+               IAPSTA_ERROR("wlan", "dev is not ready\n");
+               return;
+       }
+
+       dhd = dhd_get_pub(dev);
+
+       bzero(&msg, sizeof(wl_event_msg_t));
+       IAPSTA_TRACE(dev->name, "timer expired\n");
+
+       msg.ifidx = 0;
+       msg.event_type = hton32(WLC_E_RESERVED);
+       msg.reason = hton32(ISAM_RC_TPUT_MONITOR);
+       wl_ext_event_send(dhd->event_params, &msg, NULL);
+}
+
 static int
 wl_ext_assoclist_num(struct net_device *dev)
 {
@@ -3681,194 +4368,402 @@ wl_ext_assoclist_num(struct net_device *dev)
        return maxassoc;
 }
 
+static int
+dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len)
+{
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       dhd_ioctl_t ioc;
+       int8 index;
+       int ret;
+
+       memset(&ioc, 0, sizeof(ioc));
+       ioc.cmd = cmd;
+       ioc.buf = arg;
+       ioc.len = len;
+
+       index = dhd_net2idx(dhd->info, dev);
+       if (index == DHD_BAD_IF) {
+               IAPSTA_ERROR(dev->name, "Bad ifidx from dev\n");
+               return -ENODEV;
+       }
+       ret = dhd_ioctl_process(dhd, index, &ioc, arg);
+
+       return ret;
+}
+
 static void
-wl_tput_monitor_timer(unsigned long data)
+wl_ampdu_dump(struct net_device *dev)
 {
-       struct net_device *dev = (struct net_device *)data;
-       struct dhd_pub *dhd;
-       wl_event_msg_t msg;
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       char *ioctl_buf = apsta_params->ioctl_buf, *buf = NULL;
+       char *tx_pch_start, *tx_pch_end, *rx_pch_start, *rx_pch_end;
+       int ret = 0, max_len, tx_len, rx_len;
 
-       if (!dev) {
-               IAPSTA_ERROR("wlan", "dev is not ready\n");
+       if (!(android_msg_level & ANDROID_AMPDU_LEVEL))
+               return;
+
+       if (!ioctl_buf)
                return;
+
+       memset(ioctl_buf, 0, WL_DUMP_BUF_LEN);
+       ret = bcm_mkiovar("dump", "ampdu", strlen("ampdu"), ioctl_buf, WL_DUMP_BUF_LEN);
+       if (ret == 0) {
+               goto exit;
+       }
+       ret = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctl_buf, WL_DUMP_BUF_LEN);
+       if (ret) {
+               goto exit;
        }
 
-       dhd = dhd_get_pub(dev);
+       buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
+       if (buf == NULL) {
+               IAPSTA_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_MEDLEN);
+               goto exit;
+       }
+       memset(buf, 0, WLC_IOCTL_MEDLEN);
+       ret = bcm_mkiovar("dump_clear", "ampdu", strlen("ampdu"), buf, WLC_IOCTL_MEDLEN);
+       if (ret == 0) {
+               goto exit;
+       }
+       ret = dev_wlc_ioctl(dev, WLC_SET_VAR, (void *)buf, WLC_IOCTL_MEDLEN);
+       if (ret) {
+               goto exit;
+       }
 
-       bzero(&msg, sizeof(wl_event_msg_t));
-       IAPSTA_TRACE(dev->name, "timer expired\n");
+       tx_pch_start = strstr(ioctl_buf, "TX MCS");
+       tx_pch_end = strstr(ioctl_buf, "HEMU");
+       rx_pch_start = strstr(ioctl_buf, "RX MCS");
+       rx_pch_end = strstr(ioctl_buf, "RX MCS SGI");
+       max_len = (tx_pch_end-tx_pch_start) + (rx_pch_end-rx_pch_start);
+       if (max_len > (WLC_IOCTL_MEDLEN-1))
+               goto exit;
 
-       msg.ifidx = 0;
-       msg.event_type = hton32(WLC_E_RESERVED);
-       msg.reason = hton32(ISAM_RC_TPUT_MONITOR);
-       wl_ext_event_send(dhd->event_params, &msg, NULL);
+       tx_len = tx_pch_end - tx_pch_start;
+       rx_len = rx_pch_end - rx_pch_start;
+
+       memset(buf, 0, WLC_IOCTL_MEDLEN);
+       memcpy(buf, tx_pch_start, tx_len);
+       memcpy(buf+tx_len, rx_pch_start, rx_len);
+       WL_MSG(dev->name,"\n%s\n", buf);
+
+exit:
+       if (buf)
+               kfree(buf);
 }
 
 static void
-wl_tput_dump(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
+wl_btc_dump(struct net_device *dev)
 {
-       struct dhd_pub *dhd = apsta_params->dhd;
-       void *buf = NULL;
-       sta_info_v4_t *sta = NULL;
-       struct ether_addr bssid;
-       wl_rssi_ant_t *rssi_ant_p;
-       char rssi_buf[16];
-       scb_val_t scb_val;
-       int ret, bytes_written = 0, i;
-       s32 rate = 0;
-       dhd_if_t *ifp = NULL;
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       int ret, val;
 
-       if (!(android_msg_level & ANDROID_TPUT_LEVEL))
+       if (!(android_msg_level & ANDROID_BTC_LEVEL))
                return;
 
-       ifp = dhd_get_ifp(dhd, cur_if->ifidx);
+       ret = dhd_conf_reg2args(dhd, "btc_params", FALSE, 15, &val);
+       if (!ret)
+               WL_MSG(dev->name,"btc_params15=%d\n", val);
+}
 
-       buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
-       if (buf == NULL) {
-               IAPSTA_ERROR(cur_if->dev->name, "MALLOC failed\n");
+static void
+wl_tvpm_dump(struct net_device *dev)
+{
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       wl_tvpm_req_t* tvpm_req = NULL;
+       size_t reqlen = sizeof(wl_tvpm_req_t) + sizeof(wl_tvpm_status_t);
+       uint8 *outbuf = apsta_params->ioctl_buf;
+       size_t outlen = WLC_IOCTL_MEDLEN;
+       wl_tvpm_status_t* status;
+       int ret, phy_temp = 0;
+       bool tvpm = FALSE, sense = FALSE;
+
+       if (!(android_msg_level & ANDROID_TVPM_LEVEL))
+               return;
+
+       tvpm_req = kmalloc(reqlen, GFP_KERNEL);
+       if (tvpm_req == NULL) {
+               IAPSTA_ERROR(dev->name, "MALLOC failed\n");
                goto exit;
        }
+       memset(tvpm_req, 0, reqlen);
 
-       wldev_ioctl_get(cur_if->dev, WLC_GET_RATE, &rate, sizeof(rate));
-       rate = dtoh32(rate);
-       memset(rssi_buf, 0, sizeof(rssi_buf));
-       if (cur_if->ifmode == ISTA_MODE) {
-               ret = wldev_iovar_getbuf(cur_if->dev, "phy_rssi_ant", NULL, 0,
-                       buf, WLC_IOCTL_MEDLEN, NULL);
-               rssi_ant_p = (wl_rssi_ant_t *)buf;
-               rssi_ant_p->version = dtoh32(rssi_ant_p->version);
-               rssi_ant_p->count = dtoh32(rssi_ant_p->count);
-               if (ret < 0 || rssi_ant_p->count == 0) {
-                       wldev_ioctl(cur_if->dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0);
+       tvpm_req->version = TVPM_REQ_VERSION_1;
+       tvpm_req->length = reqlen;
+       tvpm_req->req_type = WL_TVPM_REQ_STATUS;
+       ret = wldev_iovar_getbuf(dev, "tvpm", tvpm_req, reqlen, outbuf, outlen, NULL);
+       status = (wl_tvpm_status_t*)outbuf;
+       if (!ret && status->enable) {
+               tvpm = TRUE;
+       } else {
+               ret = wldev_iovar_getbuf(dev, "phy_tempsense", &phy_temp, sizeof(phy_temp),
+                       outbuf, outlen, NULL);
+               if (!ret) {
+                       phy_temp = dtoh32(*(int*)outbuf);
+                       sense = TRUE;
+               }
+       }
+
+       if (tvpm) {
+               WL_MSG(dev->name,"temp=%3d, duty=%3d, pwrbko=%d, chains=%d\n",
+                       status->temp, status->tx_dutycycle, status->tx_power_backoff,
+                       status->num_active_chains);
+       }
+       else if (sense) {
+               WL_MSG(dev->name,"phy_temp=%3d\n", phy_temp);
+       }
+
+exit:
+       if (tvpm_req)
+               kfree(tvpm_req);
+}
+
+static void
+wl_phy_rssi_ant(struct net_device *dev, struct ether_addr *mac,
+       char *rssi_buf, int len)
+{
+       struct wl_if_info *cur_if = NULL;
+       char buf[WLC_IOCTL_SMLEN];
+       wl_rssi_ant_t *rssi_ant_p;
+       int ret, bytes_written = 0, i;
+       scb_val_t scb_val;
+
+       cur_if = wl_get_cur_if(dev);
+       if (!cur_if)
+               return;
+
+       memset(buf, 0, sizeof(buf));
+       ret = wldev_iovar_getbuf(dev, "phy_rssi_ant",
+               mac, mac ? ETHER_ADDR_LEN : 0, buf, sizeof(buf), NULL);
+       rssi_ant_p = (wl_rssi_ant_t *)buf;
+       rssi_ant_p->version = dtoh32(rssi_ant_p->version);
+       rssi_ant_p->count = dtoh32(rssi_ant_p->count);
+       if (ret < 0 || rssi_ant_p->count == 0) {
+               if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
+                       wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0);
                        rssi_ant_p->count = 1;
                        rssi_ant_p->rssi_ant[0] = dtoh32(scb_val.val);
                }
-               for (i=0; i<rssi_ant_p->count && rssi_ant_p->rssi_ant[i]; i++) {
-                       bytes_written += snprintf(rssi_buf+bytes_written, sizeof(rssi_buf),
-                               "[%2d]", rssi_ant_p->rssi_ant[i]);
+       }
+       for (i=0; i<rssi_ant_p->count && rssi_ant_p->rssi_ant[i]; i++) {
+               bytes_written += snprintf(rssi_buf+bytes_written, len,
+                       "[%2d]", rssi_ant_p->rssi_ant[i]);
+       }
+}
+
+static void
+wl_tput_dump(struct wl_apsta_params *apsta_params,
+       struct net_device *dev, wl_tput_info_t *tput_info)
+{
+       WL_MSG(dev->name,
+               "tx=%3d.%d%d%d Mbps, rx=%3d.%d%d%d Mbps, tput_sum=%3d.%d%d%d Mbps\n",
+               tput_info->tput_tx, (tput_info->tput_tx_kb/100)%10,
+               (tput_info->tput_tx_kb/10)%10, (tput_info->tput_tx_kb)%10,
+               tput_info->tput_rx, (tput_info->tput_rx_kb/100)%10,
+               (tput_info->tput_rx_kb/10)%10, (tput_info->tput_rx_kb)%10,
+               apsta_params->tput_sum, (apsta_params->tput_sum_kb/100)%10,
+               (apsta_params->tput_sum_kb/10)%10, (apsta_params->tput_sum_kb)%10);
+}
+
+static void
+wl_sta_info_dump(struct net_device *dev, struct ether_addr *mac)
+{
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       void *buf = apsta_params->ioctl_buf;
+       sta_info_v4_t *sta = NULL;
+       char rssi_buf[16];
+       int ret;
+       s32 rate = 0;
+
+       memset(rssi_buf, 0, sizeof(rssi_buf));
+       wl_phy_rssi_ant(dev, mac, rssi_buf, sizeof(rssi_buf));
+       ret = wldev_iovar_getbuf(dev, "sta_info", (const void*)mac,
+               ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL);
+       if (ret == 0) {
+               sta = (sta_info_v4_t *)buf;
+       }
+       if (sta == NULL || (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5 &&
+                       sta->ver != WL_STA_VER_6)) {
+               wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
+               rate = dtoh32(rate);
+               WL_MSG(dev->name,
+                       "mac=%pM, rssi=%s, tx_rate:%4d%2s\n",
+                       mac, rssi_buf, rate/2, (rate & 1) ? ".5" : "");
+       } else {
+               if (dtoh32(sta->rx_rate) != -1) {
+                       WL_MSG(dev->name,
+                               "mac=%pM, rssi=%s, tx_rate:%4d.%d, rx_rate:%4d.%d\n",
+                               mac, rssi_buf,
+                               dtoh32(sta->tx_rate)/1000, ((dtoh32(sta->tx_rate)/100)%10),
+                               dtoh32(sta->rx_rate)/1000, ((dtoh32(sta->rx_rate)/100)%10));
+               } else {
+                       WL_MSG(dev->name,
+                               "mac=%pM, rssi=%s, tx_rate:%4d.%d, rx_rate:%4d\n",
+                               mac, rssi_buf,
+                               dtoh32(sta->tx_rate)/1000, ((dtoh32(sta->tx_rate)/100)%10),
+                               dtoh32(sta->rx_rate));
                }
+       }
+}
+
+static void
+wl_cur_if_tput_dump(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
+{
+#ifdef WLDWDS
+       struct wl_dwds_info *dwds_if;
+       int i;
+#endif /* WLDWDS */
+       struct ether_addr bssid;
+       int ret = 0;
+
+       if (!(android_msg_level & ANDROID_TPUT_LEVEL))
+               return;
+
+       wl_tput_dump(apsta_params, cur_if->dev, &cur_if->tput_info);
+
+       if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
                wldev_ioctl(cur_if->dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
-               ret = wldev_iovar_getbuf(cur_if->dev, "sta_info", (const void*)&bssid,
-                               ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL);
-               if (ret == 0) {
-                       sta = (sta_info_v4_t *)buf;
+               if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
+                       wl_sta_info_dump(cur_if->dev, &bssid);
                }
        }
-       else {
-               bytes_written += snprintf(rssi_buf+bytes_written, sizeof(rssi_buf),
-                       "[   ][   ]");
-       }
-
-       if (sta == NULL || (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5)) {
-               WL_MSG(cur_if->dev->name,
-                       "rssi=%s, tx=%3d.%d%d%d Mbps(rate:%4d%2s), rx=%3d.%d%d%d Mbps(rate:      ), "\
-                       "tput_sum=%3d.%d%d%d Mbps\n",
-                       rssi_buf, cur_if->tput_tx, (cur_if->tput_tx_kb/100)%10,
-                       (cur_if->tput_tx_kb/10)%10, (cur_if->tput_tx_kb)%10,
-                       rate/2, (rate & 1) ? ".5" : "",
-                       cur_if->tput_rx, (cur_if->tput_rx_kb/100)%10,
-                       (cur_if->tput_rx_kb/10)%10, (cur_if->tput_rx_kb)%10,
-                       apsta_params->tput_sum, (apsta_params->tput_sum_kb/100)%10,
-                       (apsta_params->tput_sum_kb/10)%10, (apsta_params->tput_sum_kb)%10);
-       } else {
-               WL_MSG(cur_if->dev->name,
-                       "rssi=%s, tx=%3d.%d%d%d Mbps(rate:%4d%2s), rx=%3d.%d%d%d Mbps(rate:%4d.%d), "\
-                       "tput_sum=%3d.%d%d%d Mbps\n",
-                       rssi_buf, cur_if->tput_tx, (cur_if->tput_tx_kb/100)%10,
-                       (cur_if->tput_tx_kb/10)%10, (cur_if->tput_tx_kb)%10,
-                       rate/2, (rate & 1) ? ".5" : "",
-                       cur_if->tput_rx, (cur_if->tput_rx_kb/100)%10,
-                       (cur_if->tput_rx_kb/10)%10, (cur_if->tput_rx_kb)%10,
-                       dtoh32(sta->rx_rate)/1000, ((dtoh32(sta->rx_rate)/100)%10),
-                       apsta_params->tput_sum, (apsta_params->tput_sum_kb/100)%10,
-                       (apsta_params->tput_sum_kb/10)%10, (apsta_params->tput_sum_kb)%10);
+       else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE) {
+               int i, maxassoc = 0;
+               char mac_buf[MAX_NUM_OF_ASSOCLIST *
+                       sizeof(struct ether_addr) + sizeof(uint)] = {0};
+               struct maclist *assoc_maclist = (struct maclist *)mac_buf;
+
+               assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
+               ret = wl_ext_ioctl(cur_if->dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), 0);
+               if (ret)
+                       goto exit;
+               maxassoc = dtoh32(assoc_maclist->count);
+               for (i=0; i<maxassoc; i++) {
+                       wl_sta_info_dump(cur_if->dev, &assoc_maclist->ea[i]);
+               }
+#ifdef WLDWDS
+               for (i=0; i<MAX_DWDS_IF_NUM; i++) {
+                       dwds_if = &apsta_params->dwds_info[i];
+                       if (dwds_if->dev && cur_if->bssidx == dwds_if->bssidx) {
+                               wl_tput_dump(apsta_params, dwds_if->dev, &dwds_if->tput_info);
+                       }
+               }
+#endif /* WLDWDS */
        }
 
 exit:
-       if (buf) {
-               kfree(buf);
-       }
+       return;
 }
 
 static void
-wl_tput_monitor(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
+wl_tput_monitor(struct dhd_pub *dhd, int ifidx, struct wl_tput_info *tput_info)
 {
-       struct dhd_pub *dhd = apsta_params->dhd;
        dhd_if_t *ifp = NULL;
 
-       ifp = dhd_get_ifp(dhd, cur_if->ifidx);
+       ifp = dhd_get_ifp(dhd, ifidx);
+       if (!ifp)
+               return;
 
-       if (cur_if->tput_ts.tv_sec == 0 && cur_if->tput_ts.tv_nsec == 0) {
-               osl_do_gettimeofday(&cur_if->tput_ts);
-               cur_if->last_tx = ifp->stats.tx_bytes;
-               cur_if->last_rx = ifp->stats.rx_bytes;
+       if (tput_info->tput_ts.tv_sec == 0 && tput_info->tput_ts.tv_nsec == 0) {
+               osl_do_gettimeofday(&tput_info->tput_ts);
+               tput_info->last_tx = ifp->stats.tx_bytes;
+               tput_info->last_rx = ifp->stats.rx_bytes;
        } else {
                struct osl_timespec cur_ts;
                uint32 diff_ms;
 
                osl_do_gettimeofday(&cur_ts);
-               diff_ms = osl_do_gettimediff(&cur_ts, &cur_if->tput_ts)/1000;
-               memcpy(&cur_if->tput_ts, &cur_ts, sizeof(struct osl_timespec));
-               cur_if->tput_tx = (int32)(((ifp->stats.tx_bytes-cur_if->last_tx)/1024/1024)*8)*1000/diff_ms;
-               if (cur_if->tput_tx == 0) {
-                       cur_if->tput_tx = (int32)((ifp->stats.tx_bytes-cur_if->last_tx)*8*1000/1024/1024)/diff_ms;
-                       cur_if->tput_tx_kb = (int32)((ifp->stats.tx_bytes-cur_if->last_tx)*8*1000/1024)/diff_ms;
-                       cur_if->tput_tx_kb = cur_if->tput_tx_kb % 1000;
+               diff_ms = osl_do_gettimediff(&cur_ts, &tput_info->tput_ts)/1000;
+               memcpy(&tput_info->tput_ts, &cur_ts, sizeof(struct osl_timespec));
+               tput_info->tput_tx = (int32)(((ifp->stats.tx_bytes-tput_info->last_tx)/1024/1024)*8)*1000/diff_ms;
+               if (tput_info->tput_tx == 0) {
+                       tput_info->tput_tx = (int32)((ifp->stats.tx_bytes-tput_info->last_tx)*8*1000/1024/1024)/diff_ms;
+                       tput_info->tput_tx_kb = (int32)((ifp->stats.tx_bytes-tput_info->last_tx)*8*1000/1024)/diff_ms;
+                       tput_info->tput_tx_kb = tput_info->tput_tx_kb % 1000;
                } else
-                       cur_if->tput_tx_kb = 0;
-               cur_if->tput_rx = (int32)(((ifp->stats.rx_bytes-cur_if->last_rx)/1024/1024)*8)*1000/diff_ms;
-               if (cur_if->tput_rx == 0) {
-                       cur_if->tput_rx = (int32)((ifp->stats.rx_bytes-cur_if->last_rx)*8*1000/1024/1024)/diff_ms;
-                       cur_if->tput_rx_kb = (int32)((ifp->stats.rx_bytes-cur_if->last_rx)*8*1000/1024)/diff_ms;
-                       cur_if->tput_rx_kb = cur_if->tput_rx_kb % 1000;
+                       tput_info->tput_tx_kb = 0;
+               tput_info->tput_rx = (int32)(((ifp->stats.rx_bytes-tput_info->last_rx)/1024/1024)*8)*1000/diff_ms;
+               if (tput_info->tput_rx == 0) {
+                       tput_info->tput_rx = (int32)((ifp->stats.rx_bytes-tput_info->last_rx)*8*1000/1024/1024)/diff_ms;
+                       tput_info->tput_rx_kb = (int32)((ifp->stats.rx_bytes-tput_info->last_rx)*8*1000/1024)/diff_ms;
+                       tput_info->tput_rx_kb = tput_info->tput_rx_kb % 1000;
                } else
-                       cur_if->tput_rx_kb = 0;
-               cur_if->last_tx = ifp->stats.tx_bytes;
-               cur_if->last_rx = ifp->stats.rx_bytes;
+                       tput_info->tput_rx_kb = 0;
+               tput_info->last_tx = ifp->stats.tx_bytes;
+               tput_info->last_rx = ifp->stats.rx_bytes;
        }
 }
 
 static void
-wl_tput_monitor_handler(struct wl_apsta_params *apsta_params,
-       struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data)
+wl_tput_monitor_handler(struct wl_if_info *cur_if,
+       const wl_event_msg_t *e, void *data)
 {
-       struct dhd_pub *dhd = apsta_params->dhd;
+       struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       wl_tput_info_t *tput_info;
        struct wl_if_info *tmp_if;
+#ifdef WLDWDS
+       struct wl_dwds_info *dwds_if;
+#endif /* WLDWDS */
        uint32 etype = ntoh32(e->event_type);
        uint32 status =  ntoh32(e->status);
        uint32 reason = ntoh32(e->reason);
        uint16 flags =  ntoh16(e->flags);
        uint timeout = dhd->conf->tput_monitor_ms;
        int32 tput_sum = 0, tput_sum_kb = 0;
-       bool monitor_if[MAX_IF_NUM] = {FALSE};
+       bool monitor_if[MAX_IF_NUM] = {FALSE}, monitor = FALSE;
        int i;
 
        if (etype == WLC_E_RESERVED && reason == ISAM_RC_TPUT_MONITOR) {
                tput_sum = 0;
                for (i=0; i<MAX_IF_NUM; i++) {
                        tmp_if = &apsta_params->if_info[i];
-                       if (tmp_if->dev && tmp_if->ifmode == ISTA_MODE &&
-                                       wl_ext_get_chan(apsta_params, tmp_if->dev)) {
-                               wl_tput_monitor(apsta_params, tmp_if);
+                       if (tmp_if->dev &&
+                                       (tmp_if->ifmode == ISTA_MODE || tmp_if->ifmode == IGC_MODE) &&
+                                       wl_ext_associated(tmp_if->dev)) {
+                               wl_tput_monitor(dhd, tmp_if->ifidx, &tmp_if->tput_info);
                                monitor_if[i] = TRUE;
                        }
-                       else if (tmp_if->dev && tmp_if->ifmode == IAP_MODE &&
+                       else if (tmp_if->dev &&
+                                       (tmp_if->ifmode == IAP_MODE || tmp_if->ifmode == IGO_MODE) &&
                                        wl_ext_assoclist_num(tmp_if->dev)) {
-                               wl_tput_monitor(apsta_params, tmp_if);
+                               wl_tput_monitor(dhd, tmp_if->ifidx, &tmp_if->tput_info);
                                monitor_if[i] = TRUE;
                        }
-                       tput_sum += (tmp_if->tput_tx + tmp_if->tput_rx);
-                       tput_sum_kb += (tmp_if->tput_tx_kb + tmp_if->tput_rx_kb);
+                       if (monitor_if[i] == TRUE) {
+                               tput_info = &tmp_if->tput_info;
+                               tput_sum += (tput_info->tput_tx + tput_info->tput_rx);
+                               tput_sum_kb += (tput_info->tput_tx_kb + tput_info->tput_rx_kb);
+                       }
+               }
+#ifdef WLDWDS
+               for (i=0; i<MAX_DWDS_IF_NUM; i++) {
+                       dwds_if = &apsta_params->dwds_info[i];
+                       if (dwds_if->dev) {
+                               wl_tput_monitor(dhd, dwds_if->ifidx, &dwds_if->tput_info);
+                               tput_info = &dwds_if->tput_info;
+                               tput_sum += (tput_info->tput_tx + tput_info->tput_rx);
+                               tput_sum_kb += (tput_info->tput_tx_kb + tput_info->tput_rx_kb);
+                       }
                }
+#endif /* WLDWDS */
                apsta_params->tput_sum = tput_sum + (tput_sum_kb/1000);
                apsta_params->tput_sum_kb = tput_sum_kb % 1000;
                for (i=0; i<MAX_IF_NUM; i++) {
                        if (monitor_if[i]) {
                                tmp_if = &apsta_params->if_info[i];
-                               wl_tput_dump(apsta_params, tmp_if);
-                               wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout);
+                               wl_cur_if_tput_dump(apsta_params, tmp_if);
+                               monitor = TRUE;
                        }
                }
+               if (monitor) {
+                       wl_btc_dump(cur_if->dev);
+                       wl_tvpm_dump(cur_if->dev);
+                       wl_ampdu_dump(cur_if->dev);
+                       wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout);
+               }
 #ifdef BCMSDIO
                if (apsta_params->tput_sum >= dhd->conf->doflow_tput_thresh && dhd_doflow) {
                        dhd_doflow = FALSE;
@@ -3881,57 +4776,44 @@ wl_tput_monitor_handler(struct wl_apsta_params *apsta_params,
                }
 #endif
        }
-       else if (cur_if->ifmode == ISTA_MODE) {
+       else if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
                if (etype == WLC_E_LINK) {
                        if (flags & WLC_EVENT_MSG_LINK) {
-                               wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout);
+                               wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout);
                        } else if (!wl_ext_iapsta_other_if_enabled(cur_if->dev)) {
-                               wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0);
+                               wl_timer_mod(dhd, &apsta_params->monitor_timer, 0);
                        }
                }
        }
-       else if (cur_if->ifmode == IAP_MODE) {
+       else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE) {
                if ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
                                (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
                                reason == WLC_E_REASON_INITIAL_ASSOC)) {
-                       wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout);
+                       wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout);
                } else if ((etype == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
                                (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
                                reason == WLC_E_REASON_DEAUTH)) {
                        if (!wl_ext_iapsta_other_if_enabled(cur_if->dev)) {
-                               wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0);
+                               wl_timer_mod(dhd, &apsta_params->monitor_timer, 0);
                        }
                } else if ((etype == WLC_E_ASSOC_IND || etype == WLC_E_REASSOC_IND) &&
                                reason == DOT11_SC_SUCCESS) {
-                       wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout);
+                       wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout);
                }
        }
 }
 #endif /* TPUT_MONITOR */
 
 #ifdef ACS_MONITOR
-static void
-wl_ext_mod_timer_pending(timer_list_compat_t *timer, uint sec, uint msec)
-{
-       uint timeout = sec * 1000 + msec;
-
-       if (timeout && !timer_pending(timer)) {
-               IAPSTA_TRACE("wlan", "timeout=%d\n", timeout);
-               mod_timer(timer, jiffies + msecs_to_jiffies(timeout));
-       }
-}
-
 static bool
 wl_ext_max_prio_if(struct wl_apsta_params *apsta_params,
        struct wl_if_info *cur_if)
 {
        struct wl_if_info *tmp_if;
        wl_prio_t max_prio;
-       uint16 target_chan;
        int i;
 
        if (apsta_params->vsdb) {
-               target_chan = cur_if->channel;
                goto exit;
        }
 
@@ -3941,8 +4823,7 @@ wl_ext_max_prio_if(struct wl_apsta_params *apsta_params,
                tmp_if = &apsta_params->if_info[i];
                if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) &&
                                tmp_if->prio > max_prio) {
-                       target_chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
-                       if (target_chan) {
+                       if (wl_ext_associated(tmp_if->dev)) {
                                return TRUE;
                        }
                }
@@ -3955,7 +4836,7 @@ static void
 wl_ext_acs_scan(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
 {
        if (apsta_params->acs & ACS_DRV_BIT) {
-               if (wl_ext_get_chan(apsta_params, cur_if->dev)) {
+               if (wl_ext_associated(cur_if->dev)) {
                        int ret, cur_scan_time;
                        cur_if->escan->autochannel = 1;
                        cur_scan_time = wl_ext_set_scan_time(cur_if->dev, 80,
@@ -3973,22 +4854,22 @@ wl_ext_acs_scan(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
 static void
 wl_ext_acs(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
 {
-       uint cur_band;
-       uint16 cur_chan, acs_chan;
+       struct wl_chan_info chan_info;
 
        if (apsta_params->acs & ACS_DRV_BIT) {
                mutex_lock(&apsta_params->usr_sync);
-               cur_chan = wl_ext_get_chan(apsta_params, cur_if->dev);
-               if (cur_chan) {
-                       cur_band = WL_GET_BAND(cur_chan);
-                       if (cur_band == WLC_BAND_5G)
-                               cur_if->channel = cur_if->escan->best_5g_ch;
+               memset(&chan_info, 0, sizeof(struct wl_chan_info));
+               wl_ext_get_chan(cur_if->dev, &chan_info);
+               if (chan_info.chan) {
+                       if (chan_info.band == WLC_BAND_5G)
+                               cur_if->chan_info.chan = cur_if->escan->best_5g_ch;
                        else
-                               cur_if->channel = cur_if->escan->best_2g_ch;
-                       acs_chan = wl_ext_move_cur_channel(apsta_params, cur_if);
-                       if (acs_chan != cur_chan) {
-                               WL_MSG(cur_if->dev->name, "move channel %d => %d\n",
-                                       cur_chan, acs_chan);
+                               cur_if->chan_info.chan = cur_if->escan->best_2g_ch;
+                       wl_ext_move_cur_channel(apsta_params, cur_if);
+                       if (!wl_ext_same_chan(&cur_if->chan_info, &chan_info)) {
+                               WL_MSG(cur_if->dev->name, "move channel %s-%d => %s-%d\n",
+                                       WLCBAND2STR(chan_info.band), chan_info.chan,
+                                       WLCBAND2STR(cur_if->chan_info.band), cur_if->chan_info.chan);
                                wl_ext_if_down(apsta_params, cur_if);
                                wl_ext_move_other_channel(apsta_params, cur_if);
                                wl_ext_if_up(apsta_params, cur_if, FALSE, 500);
@@ -4015,7 +4896,7 @@ wl_acs_timer(unsigned long data)
        bzero(&msg, sizeof(wl_event_msg_t));
        IAPSTA_TRACE(dev->name, "timer expired\n");
 
-       msg.ifidx = hton32(dhd_net2idx(dhd->info, dev));
+       msg.ifidx = dhd_net2idx(dhd->info, dev);
        msg.event_type = hton32(WLC_E_RESERVED);
        msg.reason = hton32(ISAM_RC_AP_ACS);
        wl_ext_event_send(dhd->event_params, &msg, NULL);
@@ -4036,34 +4917,34 @@ wl_acs_handler(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data)
                                (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
                                reason == WLC_E_REASON_INITIAL_ASSOC)) {
                        // Link up
-                       wl_ext_mod_timer_pending(&cur_if->acs_timer, acs_tmo, 0);
+                       wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000);
                }
                else if ((etype == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
                                (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
                                reason == WLC_E_REASON_DEAUTH)) {
                        // Link down
-                       wl_ext_mod_timer(&cur_if->acs_timer, 0, 0);
+                       wl_timer_mod(dhd, &cur_if->acs_timer, 0);
                        cur_if->escan->autochannel = 0;
                }
                else if ((etype == WLC_E_ASSOC_IND || etype == WLC_E_REASSOC_IND) &&
                                reason == DOT11_SC_SUCCESS) {
                        // external STA connected
-                       wl_ext_mod_timer(&cur_if->acs_timer, 0, 0);
+                       wl_timer_mod(dhd, &cur_if->acs_timer, 0);
                }
                else if (etype == WLC_E_DISASSOC_IND ||
                                etype == WLC_E_DEAUTH_IND ||
                                (etype == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
                        // external STA disconnected
-                       wl_ext_mod_timer_pending(&cur_if->acs_timer, acs_tmo, 0);
+                       wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000);
                }
                else if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_ACS) {
                        // acs_tmo expired
                        if (!wl_ext_assoclist_num(cur_if->dev) &&
                                        !wl_ext_max_prio_if(apsta_params, cur_if)) {
                                wl_ext_acs_scan(apsta_params, cur_if);
-                               wl_ext_mod_timer(&cur_if->acs_timer, acs_tmo, 0);
+                               wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000);
                        } else {
-                               wl_ext_mod_timer(&cur_if->acs_timer, 0, 0);
+                               wl_timer_mod(dhd, &cur_if->acs_timer, 0);
                        }
                }
                else if (((etype == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) ||
@@ -4077,63 +4958,370 @@ wl_acs_handler(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data)
                                        !wl_ext_max_prio_if(apsta_params, cur_if)) {
                                wl_ext_acs(apsta_params, cur_if);
                        } else {
-                               wl_ext_mod_timer(&cur_if->acs_timer, 0, 0);
+                               wl_timer_mod(dhd, &cur_if->acs_timer, 0);
+                       }
+               }
+       }
+}
+
+static void
+wl_acs_detach(struct wl_if_info *cur_if)
+{
+       IAPSTA_TRACE(cur_if->dev->name, "Enter\n");
+       wl_timer_deregister(cur_if->dev, &cur_if->acs_timer);
+       if (cur_if->escan) {
+               cur_if->escan = NULL;
+       }
+}
+
+static void
+wl_acs_attach(dhd_pub_t *dhd, struct wl_if_info *cur_if)
+{
+       IAPSTA_TRACE(cur_if->dev->name, "Enter\n");
+       cur_if->escan = dhd->escan;
+       wl_timer_register(cur_if->dev, &cur_if->acs_timer, wl_acs_timer);
+}
+#endif /* ACS_MONITOR */
+
+#ifdef RESTART_AP_WAR
+static void
+wl_ext_restart_ap_timeout(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct dhd_pub *dhd;
+       wl_event_msg_t msg;
+
+       if (!dev) {
+               IAPSTA_ERROR("wlan", "dev is not ready\n");
+               return;
+       }
+
+       dhd = dhd_get_pub(dev);
+
+       bzero(&msg, sizeof(wl_event_msg_t));
+       IAPSTA_TRACE(dev->name, "timer expired\n");
+
+       msg.ifidx = dhd_net2idx(dhd->info, dev);
+       msg.event_type = hton32(WLC_E_RESERVED);
+       msg.reason = hton32(ISAM_RC_AP_RESTART);
+       wl_ext_event_send(dhd->event_params, &msg, NULL);
+}
+
+static void
+wl_ext_restart_ap_handler(struct wl_if_info *cur_if,
+       const wl_event_msg_t *e, void *data)
+{
+       struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       uint32 etype = ntoh32(e->event_type);
+       uint32 reason = ntoh32(e->reason);
+
+       if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_RESTART) {
+               if (!wl_get_isam_status(cur_if, AP_CREATED)) {
+                       if (!wl_ext_associated(cur_if->dev)) {
+                               WL_MSG(cur_if->ifname, "restart AP\n");
+                               wl_ext_if_down(apsta_params, cur_if);
+                               wl_ext_if_up(apsta_params, cur_if, FALSE, 1);
+                               wl_timer_mod(dhd, &cur_if->restart_ap_timer, AP_RESTART_TIMEOUT);
+                       } else {
+                               WL_MSG(cur_if->ifname, "skip restart AP\n");
                        }
                }
        }
+       return;
+}
+#endif /* RESTART_AP_WAR */
+
+#if defined(RESET_AP_WAR) || defined(RXF0OVFL_REINIT_WAR)
+static int
+wl_ext_counters_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
+{
+       struct wl_if_info *cur_if = ctx;
+       struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       int res = BCME_OK;
+
+       switch (type) {
+               case WL_CNT_XTLV_CNTV_LE10_UCODE: {
+                       wl_cnt_v_le10_mcst_t *cnt = (wl_cnt_v_le10_mcst_t *)data;
+                       if (len != sizeof(wl_cnt_v_le10_mcst_t)) {
+                               printf("type %d: cnt struct length mismatch! %d != %d\n",
+                                       type, len, (int)sizeof(wl_cnt_v_le10_mcst_t));
+                       }
+#ifdef RESET_AP_WAR
+                       if (apsta_params->war_reason == ISAM_RC_AP_RESET)
+                               cur_if->txbcnfrm = dtoh32(cnt->txbcnfrm);
+#endif /* RESET_AP_WAR */
+#ifdef RXF0OVFL_REINIT_WAR
+                       if (apsta_params->war_reason == ISAM_RC_RXF0OVFL_REINIT) {
+                               apsta_params->rxbeaconmbss = dtoh32(cnt->rxbeaconmbss);
+                               apsta_params->rxf0ovfl = dtoh32(cnt->rxf0ovfl);
+                       }
+#endif /* RXF0OVFL_REINIT_WAR */
+                       break;
+               }
+               case WL_CNT_XTLV_GE40_UCODE_V1:
+               {
+                       wl_cnt_ge40mcst_v1_t *cnt = (wl_cnt_ge40mcst_v1_t *)data;
+                       if (len != sizeof(wl_cnt_ge40mcst_v1_t)) {
+                               IAPSTA_ERROR(cur_if->ifname,
+                                       "type 0x%x, cnt struct length mismatch! %d != %d\n",
+                                       type, len, (int)sizeof(wl_cnt_ge40mcst_v1_t));
+                       }
+#ifdef RESET_AP_WAR
+                       if (apsta_params->war_reason == ISAM_RC_AP_RESET)
+                               cur_if->txbcnfrm = dtoh32(cnt->txbcnfrm);
+#endif /* RESET_AP_WAR */
+#ifdef RXF0OVFL_REINIT_WAR
+                       if (apsta_params->war_reason == ISAM_RC_RXF0OVFL_REINIT) {
+                               apsta_params->rxbeaconmbss = dtoh32(cnt->rxbeaconmbss);
+                               apsta_params->rxf0ovfl = dtoh32(cnt->rxf0ovfl);
+                       }
+#endif /* RXF0OVFL_REINIT_WAR */
+                       break;
+               }
+               case WL_CNT_XTLV_GE80_UCODE_V1:
+               {
+                       wl_cnt_ge80mcst_v1_t *cnt = (wl_cnt_ge80mcst_v1_t *)data;
+                       if (len != sizeof(wl_cnt_ge80mcst_v1_t)) {
+                               IAPSTA_ERROR(cur_if->ifname,
+                                       "type 0x%x, cnt struct length mismatch! %d != %d\n",
+                                       type, len, (int)sizeof(wl_cnt_ge80mcst_v1_t));
+                       }
+#ifdef RESET_AP_WAR
+                       if (apsta_params->war_reason == ISAM_RC_AP_RESET)
+                               cur_if->txbcnfrm = dtoh32(cnt->txbcnfrm);
+#endif /* RESET_AP_WAR */
+#ifdef RXF0OVFL_REINIT_WAR
+                       if (apsta_params->war_reason == ISAM_RC_RXF0OVFL_REINIT) {
+                               apsta_params->rxbeaconmbss = dtoh32(cnt->rxbeaconmbss);
+                               apsta_params->rxf0ovfl = dtoh32(cnt->rxf0ovfl);
+                       }
+#endif /* RXF0OVFL_REINIT_WAR */
+                       break;
+               }
+               default:
+                       break;
+       }
+       return res;
+}
+
+static int
+wl_ext_counters_update(struct wl_if_info *cur_if, int war_reason)
+{
+       struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       char *iovar_buf = apsta_params->ioctl_buf;
+       uint32 corerev = 0;
+       wl_cnt_info_t *cntinfo;
+       uint16 ver;
+       int ret = 0;
+
+       ret = wldev_iovar_getbuf(cur_if->dev, "counters", NULL, 0,
+               iovar_buf, WLC_IOCTL_MEDLEN, NULL);
+       if (unlikely(ret)) {
+               IAPSTA_ERROR(cur_if->ifname,
+                       "counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t));
+               goto exit;
+       }
+       cntinfo = (wl_cnt_info_t *)iovar_buf;
+       cntinfo->version = dtoh16(cntinfo->version);
+       cntinfo->datalen = dtoh16(cntinfo->datalen);
+       ver = cntinfo->version;
+       CHK_CNTBUF_DATALEN(iovar_buf, WLC_IOCTL_MEDLEN);
+       if (ver > WL_CNT_VERSION_XTLV) {
+               IAPSTA_ERROR(cur_if->ifname,
+                       "Incorrect version of counters struct: expected %d; got %d\n",
+                       WL_CNT_VERSION_XTLV, ver);
+               goto exit;
+       }
+
+       if (ver == WL_CNT_VERSION_11) {
+               wlc_rev_info_t revinfo;
+               memset(&revinfo, 0, sizeof(revinfo));
+               ret = wl_ext_ioctl(cur_if->dev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), 0);
+               if (ret) {
+                       IAPSTA_ERROR(cur_if->ifname, "WLC_GET_REVINFO failed %d\n", ret);
+                       goto exit;
+               }
+               corerev = dtoh32(revinfo.corerev);
+       }
+       ret = wl_cntbuf_to_xtlv_format(NULL, cntinfo, WLC_IOCTL_MEDLEN, corerev);
+       if (ret) {
+               IAPSTA_ERROR(cur_if->ifname, "wl_cntbuf_to_xtlv_format failed %d\n", ret);
+               goto exit;
+       }
+
+       apsta_params->war_reason = war_reason;
+       if ((ret = bcm_unpack_xtlv_buf(cur_if, cntinfo->data, cntinfo->datalen,
+                       BCM_XTLV_OPTION_ALIGN32, wl_ext_counters_cbfn))) {
+               IAPSTA_ERROR(cur_if->ifname, "bcm_unpack_xtlv_buf failed %d\n", ret);
+               goto exit;
+       }
+
+exit:
+       return ret;
+}
+#endif /* RESET_AP_WAR | RXF0OVFL_REINIT_WAR */
+
+#ifdef RESET_AP_WAR
+static void
+wl_ext_reset_ap_timeout(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct dhd_pub *dhd;
+       wl_event_msg_t msg;
+
+       if (!dev) {
+               IAPSTA_ERROR("wlan", "dev is not ready\n");
+               return;
+       }
+
+       dhd = dhd_get_pub(dev);
+
+       bzero(&msg, sizeof(wl_event_msg_t));
+       IAPSTA_TRACE(dev->name, "timer expired\n");
+
+       msg.ifidx = dhd_net2idx(dhd->info, dev);
+       msg.event_type = hton32(WLC_E_RESERVED);
+       msg.reason = hton32(ISAM_RC_AP_RESET);
+       wl_ext_event_send(dhd->event_params, &msg, NULL);
+}
+
+static void
+wl_ext_reset_ap_handler(struct wl_if_info *cur_if,
+       const wl_event_msg_t *e, void *data)
+{
+       struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       uint32 etype = ntoh32(e->event_type);
+       uint32 status = ntoh32(e->status);
+       uint32 reason = ntoh32(e->reason);
+       uint32 txbcnfrm;
+       int ret = 0;
+
+       if (wl_get_isam_status(cur_if, AP_CREATED)) {
+               if ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
+                               (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
+                               reason == WLC_E_REASON_INITIAL_ASSOC)) {
+                       // Link up
+                       wl_ext_counters_update(cur_if, ISAM_RC_AP_RESET);
+                       wl_timer_mod(dhd, &cur_if->reset_ap_timer, AP_TXBCNFRM_TIMEOUT);
+               }
+               else if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_RESET) {
+                       txbcnfrm = cur_if->txbcnfrm;
+                       ret = wl_ext_counters_update(cur_if, ISAM_RC_AP_RESET);
+                       if (ret)
+                               goto done;
+                       if ((cur_if->txbcnfrm != 0) && (txbcnfrm == cur_if->txbcnfrm)) {
+                               WL_MSG(cur_if->ifname, "reset AP mode\n");
+                               wl_ext_if_down(apsta_params, cur_if);
+                               wl_ext_if_up(apsta_params, cur_if, FALSE, 500);
+                       }
+done:
+                       wl_timer_mod(dhd, &cur_if->reset_ap_timer, AP_TXBCNFRM_TIMEOUT);
+               }
+       }
+       return;
+}
+#endif /* RESET_AP_WAR */
+
+#ifdef RXF0OVFL_REINIT_WAR
+static void
+wl_ext_rxf0ovfl_reinit_timeout(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct dhd_pub *dhd;
+       wl_event_msg_t msg;
+
+       if (!dev) {
+               IAPSTA_ERROR("wlan", "dev is not ready\n");
+               return;
+       }
+
+       dhd = dhd_get_pub(dev);
+
+       bzero(&msg, sizeof(wl_event_msg_t));
+       IAPSTA_TRACE(dev->name, "timer expired\n");
+
+       msg.ifidx = dhd_net2idx(dhd->info, dev);
+       msg.event_type = hton32(WLC_E_RESERVED);
+       msg.reason = hton32(ISAM_RC_RXF0OVFL_REINIT);
+       wl_ext_event_send(dhd->event_params, &msg, NULL);
 }
 
 static void
-wl_acs_detach(struct wl_if_info *cur_if)
+wl_ext_rxf0ovfl_reinit_handler(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data)
 {
-       IAPSTA_TRACE(cur_if->dev->name, "Enter\n");
-       del_timer_sync(&cur_if->acs_timer);
-       if (cur_if->escan) {
-               cur_if->escan = NULL;
+       struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       uint32 etype = ntoh32(e->event_type);
+       uint32 reason = ntoh32(e->reason);
+       uint32 status = ntoh32(e->status);
+       uint16 flags =  ntoh16(e->flags);
+       uint32 rxbeaconmbss, rxbeaconmbss_diff = 0, rxf0ovfl, rxf0ovfl_diff = 0;
+       int ret = 0;
+       bool reinit = FALSE;
+
+       if ((cur_if->ifmode == ISTA_MODE) &&
+                       (etype == WLC_E_LINK) && (flags & WLC_EVENT_MSG_LINK)) {
+               // Link up
+               wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT);
+               wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT);
+       }
+       else if ((cur_if->ifmode == IAP_MODE) &&
+                       ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
+                       (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
+                       reason == WLC_E_REASON_INITIAL_ASSOC))) {
+               // Link up
+               wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT);
+               wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT);
+       }
+       else if ((etype == WLC_E_RESERVED) && (reason == ISAM_RC_RXF0OVFL_REINIT) &&
+                       (wl_ext_iapsta_other_if_enabled(cur_if->dev))) {
+               rxbeaconmbss = apsta_params->rxbeaconmbss;
+               rxf0ovfl = apsta_params->rxf0ovfl;
+               wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT);
+               if (ret)
+                       goto done;
+               rxf0ovfl_diff = apsta_params->rxf0ovfl - rxf0ovfl;
+               rxbeaconmbss_diff = apsta_params->rxbeaconmbss - rxbeaconmbss;
+               if (rxf0ovfl_diff > 0) {
+                       IAPSTA_INFO(cur_if->ifname,
+                               "rxf0ovfl diff = %d, rxbeaconmbss diff = %d\n",
+                               rxf0ovfl_diff, rxbeaconmbss_diff);
+               }
+               if (wl_ext_if_enabled(apsta_params, ISTA_MODE)) {
+                       if (rxbeaconmbss_diff < 5 && rxf0ovfl_diff > RXF0OVFL_THRESHOLD)
+                               reinit = TRUE;
+               }
+               else if (wl_ext_if_enabled(apsta_params, IAP_MODE)) {
+                       if (rxf0ovfl_diff > RXF0OVFL_THRESHOLD)
+                               reinit = TRUE;
+               }
+               if (reinit) {
+                       WL_MSG(cur_if->ifname, "wl reinit\n");
+                       wl_ext_ioctl(cur_if->dev, WLC_INIT, NULL, 0, 1);
+               }
+done:
+               wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT);
        }
-}
 
-static void
-wl_acs_attach(dhd_pub_t *dhd, struct wl_if_info *cur_if)
-{
-       IAPSTA_TRACE(cur_if->dev->name, "Enter\n");
-       cur_if->escan = dhd->escan;
-       init_timer_compat(&cur_if->acs_timer, wl_acs_timer, cur_if->dev);
+       return;
 }
-#endif /* ACS_MONITOR */
+#endif /* RXF0OVFL_REINIT_WAR */
 
 void
-wl_ext_iapsta_event(struct net_device *dev, void *argu,
+wl_ext_iapsta_link(struct wl_if_info *cur_if,
        const wl_event_msg_t *e, void *data)
 {
-       struct wl_apsta_params *apsta_params = (struct wl_apsta_params *)argu;
-       struct wl_if_info *cur_if = NULL;
-#if defined(WLMESH) && defined(WL_ESCAN)
-       struct wl_if_info *tmp_if = NULL;
-       struct wl_if_info *mesh_if = NULL;
-       int i;
-#endif /* WLMESH && WL_ESCAN */
+       struct dhd_pub *dhd = dhd_get_pub(cur_if->dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        uint32 event_type = ntoh32(e->event_type);
        uint32 status =  ntoh32(e->status);
        uint32 reason =  ntoh32(e->reason);
        uint16 flags =  ntoh16(e->flags);
 
-       cur_if = wl_get_cur_if(dev);
-
-#if defined(WLMESH) && defined(WL_ESCAN)
-       for (i=0; i<MAX_IF_NUM; i++) {
-               tmp_if = &apsta_params->if_info[i];
-               if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE) {
-                       mesh_if = tmp_if;
-                       break;
-               }
-       }
-#endif /* WLMESH && WL_ESCAN */
-       if (!cur_if || !cur_if->dev) {
-               IAPSTA_DBG(dev->name, "ifidx %d is not ready\n", e->ifidx);
-               return;
-       }
-
        if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
                if (event_type == WLC_E_LINK) {
                        if (!(flags & WLC_EVENT_MSG_LINK)) {
@@ -4145,10 +5333,6 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu,
                                wl_ext_net_setcarrier(cur_if, FALSE, FALSE);
 #endif /* SET_CARRIER */
                                wl_clr_isam_status(cur_if, STA_CONNECTED);
-#if defined(WLMESH) && defined(WL_ESCAN)
-                               if (mesh_if && apsta_params->macs)
-                                       wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE);
-#endif /* WLMESH && WL_ESCAN */
                        } else {
                                WL_MSG(cur_if->ifname, "[%c] Link UP with %pM\n",
                                        cur_if->prefix, &e->addr);
@@ -4156,15 +5340,11 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu,
                                wl_ext_net_setcarrier(cur_if, TRUE, FALSE);
 #endif /* SET_CARRIER */
                                wl_set_isam_status(cur_if, STA_CONNECTED);
-#if defined(WLMESH) && defined(WL_ESCAN)
-                               if (mesh_if && apsta_params->macs)
-                                       wl_mesh_update_master_info(apsta_params, mesh_if);
-#endif /* WLMESH && WL_ESCAN */
                        }
                        wl_clr_isam_status(cur_if, STA_CONNECTING);
                        wake_up_interruptible(&apsta_params->netif_change_event);
 #ifdef PROPTX_MAXCOUNT
-                       wl_ext_update_wlfc_maxcount(apsta_params->dhd);
+                       wl_ext_update_wlfc_maxcount(dhd);
 #endif /* PROPTX_MAXCOUNT */
                }
                else if (event_type == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) {
@@ -4173,12 +5353,8 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu,
                                event_type, reason, status);
                        wl_clr_isam_status(cur_if, STA_CONNECTING);
                        wake_up_interruptible(&apsta_params->netif_change_event);
-#if defined(WLMESH) && defined(WL_ESCAN)
-                       if (mesh_if && apsta_params->macs)
-                               wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE);
-#endif /* WLMESH && WL_ESCAN */
 #ifdef PROPTX_MAXCOUNT
-                       wl_ext_update_wlfc_maxcount(apsta_params->dhd);
+                       wl_ext_update_wlfc_maxcount(dhd);
 #endif /* PROPTX_MAXCOUNT */
                }
                else if (event_type == WLC_E_DEAUTH || event_type == WLC_E_DEAUTH_IND ||
@@ -4189,10 +5365,6 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu,
 #ifdef SET_CARRIER
                        wl_ext_net_setcarrier(cur_if, FALSE, FALSE);
 #endif /* SET_CARRIER */
-#if defined(WLMESH) && defined(WL_ESCAN)
-                       if (mesh_if && apsta_params->macs)
-                               wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE);
-#endif /* WLMESH && WL_ESCAN */
                }
        }
        else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE ||
@@ -4214,7 +5386,7 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu,
                        wl_ext_net_setcarrier(cur_if, TRUE, FALSE);
 #endif /* SET_CARRIER */
 #ifdef PROPTX_MAXCOUNT
-                       wl_ext_update_wlfc_maxcount(apsta_params->dhd);
+                       wl_ext_update_wlfc_maxcount(dhd);
 #endif /* PROPTX_MAXCOUNT */
                }
                else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
@@ -4227,7 +5399,7 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu,
                        wl_ext_net_setcarrier(cur_if, FALSE, FALSE);
 #endif /* SET_CARRIER */
 #ifdef PROPTX_MAXCOUNT
-                       wl_ext_update_wlfc_maxcount(apsta_params->dhd);
+                       wl_ext_update_wlfc_maxcount(dhd);
 #endif /* PROPTX_MAXCOUNT */
                }
                else if ((event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) &&
@@ -4245,17 +5417,34 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu,
                                event_type, reason);
                        wl_ext_isam_status(cur_if->dev, NULL, 0);
                }
-#if defined(WLMESH) && defined(WL_ESCAN)
-               if (cur_if->ifmode == IMESH_MODE && apsta_params->macs)
-                       wl_mesh_event_handler(apsta_params, cur_if, e, data);
-#endif /* WLMESH && WL_ESCAN */
+       }
+}
+
+void
+wl_ext_iapsta_event(struct net_device *dev, void *argu,
+       const wl_event_msg_t *e, void *data)
+{
+#ifdef ACS_MONITOR
+       struct wl_apsta_params *apsta_params = (struct wl_apsta_params *)argu;
+#endif /* ACS_MONITOR */
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       struct wl_if_info *cur_if = NULL;
+
+       cur_if = wl_get_cur_if(dev);
+       if (!cur_if || !cur_if->dev) {
+               IAPSTA_DBG(dev->name, "ifidx %d is not ready\n", e->ifidx);
+               return;
        }
 
+       wl_ext_iapsta_link(cur_if, e, data);
 #ifdef TPUT_MONITOR
-       if (apsta_params->dhd->conf->tput_monitor_ms)
-               wl_tput_monitor_handler(apsta_params, cur_if, e, data);
+       if (dhd->conf->tput_monitor_ms)
+               wl_tput_monitor_handler(cur_if, e, data);
 #endif /* TPUT_MONITOR */
 
+#if defined(WLMESH) && defined(WL_ESCAN)
+       wl_mesh_event_handler(cur_if, e, data);
+#endif /* WLMESH && WL_ESCAN */
 #ifdef ACS_MONITOR
        if ((apsta_params->acs & ACS_DRV_BIT) && apsta_params->acs_tmo)
                wl_acs_handler(cur_if, e, data);
@@ -4263,6 +5452,18 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu,
 #ifdef EAPOL_RESEND
        wl_resend_eapol_handler(cur_if, e, data);
 #endif /* EAPOL_RESEND */
+#ifdef KEY_INSTALL_CHECK
+       wl_ext_key_install_handler(cur_if, e, data);
+#endif /* KEY_INSTALL_CHECK */
+#ifdef RESTART_AP_WAR
+       wl_ext_restart_ap_handler(cur_if, e, data);
+#endif /* RESTART_AP_WAR */
+#ifdef RESET_AP_WAR
+       wl_ext_reset_ap_handler(cur_if, e, data);
+#endif /* RESET_AP_WAR */
+#ifdef RXF0OVFL_REINIT_WAR
+       wl_ext_rxf0ovfl_reinit_handler(cur_if, e, data);
+#endif /* RXF0OVFL_REINIT_WAR */
 
        return;
 }
@@ -4288,6 +5489,7 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
                {" bgnmode ",   NULL, NULL},
                {" hidden ",    NULL, NULL},
                {" maxassoc ",  NULL, NULL},
+               {" band ",              NULL, NULL},
                {" chan ",              NULL, NULL},
                {" amode ",     NULL, NULL},
                {" emode ",     NULL, NULL},
@@ -4402,8 +5604,23 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
                                }
                        } else if (!strcmp(row->name, " maxassoc ")) {
                                cur_if->maxassoc = (int)simple_strtol(pick_tmp, NULL, 10);
+                       } else if (!strcmp(row->name, " band ")) {
+                               if (!strcmp(pick_tmp, "2g"))
+                                       cur_if->amode = WLC_BAND_2G;
+                               else if (!strcmp(pick_tmp, "5g"))
+                                       cur_if->amode = WLC_BAND_5G;
+#ifdef WL_6G_BAND
+                               else if (!strcmp(pick_tmp, "6g"))
+                                       cur_if->amode = WLC_BAND_6G;
+#endif /* WL_6G_BAND */
+                               else {
+                                       IAPSTA_ERROR(cur_if->dev->name, "band [2g|5g|6g]\n");
+                                       return -1;
+                               }
                        } else if (!strcmp(row->name, " chan ")) {
-                               cur_if->channel = (int)simple_strtol(pick_tmp, NULL, 10);
+                               cur_if->chan_info.chan = (int)simple_strtol(pick_tmp, NULL, 10);
+                               if (!cur_if->chan_info.band)
+                                       cur_if->chan_info.band = WL_GET_BAND(cur_if->chan_info.chan);
                        } else if (!strcmp(row->name, " amode ")) {
                                if (!strcmp(pick_tmp, "open"))
                                        cur_if->amode = AUTH_OPEN;
@@ -4468,14 +5685,14 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para
                if (i >= 1 && !strlen(cur_if->ifname))
                        snprintf(cur_if->ifname, IFNAMSIZ, "wlan%d", i);
                if (cur_if->ifmode == ISTA_MODE) {
-                       cur_if->channel = 0;
+                       wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 0);
                        cur_if->maxassoc = -1;
                        cur_if->prio = PRIO_STA;
                        cur_if->vsdb = TRUE;
                        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;
+                       wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1);
                        cur_if->maxassoc = -1;
                        cur_if->prio = PRIO_AP;
                        cur_if->vsdb = FALSE;
@@ -4483,16 +5700,12 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para
                        snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
 #ifdef WLMESH
                } else if (cur_if->ifmode == IMESH_MODE) {
-                       cur_if->channel = 1;
+                       wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1);
                        cur_if->maxassoc = -1;
                        cur_if->prio = PRIO_MESH;
                        cur_if->vsdb = FALSE;
                        cur_if->prefix = 'M';
                        snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
-#ifdef WL_ESCAN
-                       if (i == 0 && apsta_params->macs)
-                               wl_mesh_escan_attach(dhd, cur_if);
-#endif /* WL_ESCAN */
 #endif /* WLMESH */
                }
        }
@@ -4600,7 +5813,6 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para
        }
 #endif /* WLMESH */
 
-       wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver);
        apsta_params->init = TRUE;
 
        WL_MSG(dev->name, "apstamode=%d\n", apstamode);
@@ -4721,7 +5933,7 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock
        struct wl_apsta_params *apsta_params = dhd->iapsta_params;
        apstamode_t apstamode = apsta_params->apstamode;
        struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
-       uint16 cur_chan;
+       struct wl_chan_info chan_info;
        struct wl_conn_info conn_info;
        u32 timeout;
 
@@ -4753,13 +5965,11 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock
 
        if (wl_ext_master_if(cur_if) && apsta_params->acs) {
                uint16 chan_2g, chan_5g;
-               uint auto_band;
-               auto_band = WL_GET_BAND(cur_if->channel);
                wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE);
-               if ((chan_2g && auto_band == WLC_BAND_2G) ||
-                               (chan_5g && auto_band == WLC_BAND_5G)) {
-                       cur_if->channel = wl_ext_autochannel(cur_if->dev, apsta_params->acs,
-                               auto_band);
+               if ((chan_2g && cur_if->chan_info.band == WLC_BAND_2G) ||
+                               (chan_5g && cur_if->chan_info.band == WLC_BAND_5G)) {
+                       cur_if->chan_info.chan = wl_ext_autochannel(cur_if->dev, apsta_params->acs,
+                               cur_if->chan_info.band);
                } else {
                        IAPSTA_ERROR(ifname, "invalid channel\n");
                        ret = -1;
@@ -4769,16 +5979,17 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock
 
        wl_ext_move_cur_channel(apsta_params, cur_if);
 
-       if (wl_ext_master_if(cur_if) && !cur_if->channel) {
+       if (wl_ext_master_if(cur_if) && !cur_if->chan_info.chan) {
                IAPSTA_ERROR(ifname, "skip channel 0\n");
                ret = -1;
                goto exit;
        }
 
-       cur_chan = wl_ext_get_chan(apsta_params, cur_if->dev);
-       if (cur_chan) {
+       memset(&chan_info, 0, sizeof(struct wl_chan_info));
+       wl_ext_get_chan(cur_if->dev, &chan_info);
+       if (chan_info.chan) {
                IAPSTA_INFO(cur_if->ifname, "Associated\n");
-               if (cur_chan != cur_if->channel) {
+               if (!wl_ext_same_chan(&cur_if->chan_info, &chan_info)) {
                        wl_ext_trigger_csa(apsta_params, cur_if);
                }
                goto exit;
@@ -4811,21 +6022,20 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock
 
        if (wl_ext_master_if(cur_if)) {
                wl_ext_set_bgnmode(cur_if);
-               if (!cur_if->channel) {
-                       cur_if->channel = 1;
+               if (!cur_if->chan_info.chan) {
+                       wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1);
                }
-               ret = wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver,
-                       cur_if->channel, &fw_chspec);
+               ret = wl_ext_set_chanspec(cur_if->dev, &cur_if->chan_info, &fw_chspec);
                if (ret)
                        goto exit;
        }
 
        wl_ext_set_amode(cur_if);
-       wl_ext_set_emode(apsta_params, cur_if);
+       wl_ext_set_emode(cur_if);
 
        if (cur_if->ifmode == ISTA_MODE) {
                conn_info.bssidx = cur_if->bssidx;
-               conn_info.channel = cur_if->channel;
+               conn_info.channel = cur_if->chan_info.chan;
                memcpy(conn_info.ssid.SSID, cur_if->ssid, strlen(cur_if->ssid));
                conn_info.ssid.SSID_len = strlen(cur_if->ssid);
                memcpy(&conn_info.bssid, &cur_if->bssid, ETHER_ADDR_LEN);
@@ -4949,22 +6159,67 @@ exit:
 }
 
 int
-wl_ext_isam_status(struct net_device *dev, char *command, int total_len)
+wl_ext_isam_dev_status(struct net_device *dev, ifmode_t ifmode, char prefix,
+       char *dump_buf, int dump_len)
 {
-       struct dhd_pub *dhd = dhd_get_pub(dev);
-       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
-       int i;
-       struct wl_if_info *tmp_if;
-       uint16 chan = 0;
+       struct wl_chan_info chan_info;
        wlc_ssid_t ssid = { 0, {0} };
        struct ether_addr bssid;
        scb_val_t scb_val;
        char sec[64];
        u32 chanspec = 0;
-       char *dump_buf = NULL;
-       int dump_len = WLC_IOCTL_MEDLEN;
        int dump_written = 0;
 
+       if (dev) {
+               memset(&ssid, 0, sizeof(ssid));
+               memset(&bssid, 0, sizeof(bssid));
+               memset(&scb_val, 0, sizeof(scb_val));
+               memset(&chan_info, 0, sizeof(struct wl_chan_info));
+               if (wl_ext_associated(dev)) {
+                       wl_ext_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
+                       wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
+                       wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0);
+                       chanspec = wl_ext_get_chanspec(dev, &chan_info);
+                       wl_ext_get_sec(dev, ifmode, sec, sizeof(sec), FALSE);
+                       dump_written += snprintf(dump_buf+dump_written, dump_len,
+                               "\n" DHD_LOG_PREFIXS "[%s-%c]: bssid=%pM, chan=%s-%-3d(0x%x %sMHz), "
+                               "rssi=%3d, sec=%-20s, SSID=\"%s\"",
+                               dev->name, prefix, &bssid,
+                               WLCBAND2STR(chan_info.band), chan_info.chan, chanspec,
+                               CHSPEC_IS20(chanspec)?"20":
+                               CHSPEC_IS40(chanspec)?"40":
+                               CHSPEC_IS80(chanspec)?"80":"160",
+                               dtoh32(scb_val.val), sec, ssid.SSID);
+                       if (ifmode == IAP_MODE) {
+                               dump_written += wl_ext_assoclist(dev, NULL,
+                                       dump_buf+dump_written, dump_len-dump_written);
+                       }
+#ifdef WLMESH
+                       else if (ifmode == IMESH_MODE) {
+                               dump_written += snprintf(dump_buf+dump_written, dump_len, "\n");
+                               dump_written += wl_ext_mesh_peer_status(dev, NULL,
+                                       dump_buf+dump_written, dump_len-dump_written);
+                       }
+#endif /* WLMESH */
+               } else {
+                       dump_written += snprintf(dump_buf+dump_written, dump_len,
+                               "\n" DHD_LOG_PREFIXS "[%s-%c]:", dev->name, prefix);
+               }
+       }
+
+       return dump_written;
+}
+
+int
+wl_ext_isam_status(struct net_device *dev, char *command, int total_len)
+{
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       struct wl_if_info *cur_if = NULL;
+       char *dump_buf = NULL;
+       int dump_len = WLC_IOCTL_MEDLEN, dump_written = 0;
+       int i;
+
        if (command || android_msg_level & ANDROID_INFO_LEVEL) {
                if (command) {
                        dump_buf = command;
@@ -4976,48 +6231,28 @@ wl_ext_isam_status(struct net_device *dev, char *command, int total_len)
                                        dump_len);
                                return -1;
                        }
+                       memset(dump_buf, 0, dump_len);
                }
                dump_written += snprintf(dump_buf+dump_written, dump_len,
                        "apstamode=%d", apsta_params->apstamode);
                for (i=0; i<MAX_IF_NUM; i++) {
-                       memset(&ssid, 0, sizeof(ssid));
-                       memset(&bssid, 0, sizeof(bssid));
-                       memset(&scb_val, 0, sizeof(scb_val));
-                       tmp_if = &apsta_params->if_info[i];
-                       if (tmp_if->dev) {
-                               chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
-                               if (chan) {
-                                       wl_ext_ioctl(tmp_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
-                                       wldev_ioctl(tmp_if->dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
-                                       wldev_ioctl(tmp_if->dev, WLC_GET_RSSI, &scb_val,
-                                               sizeof(scb_val_t), 0);
-                                       chanspec = wl_ext_get_chanspec(apsta_params, tmp_if->dev);
-                                       wl_ext_get_sec(tmp_if->dev, tmp_if->ifmode, sec, sizeof(sec), FALSE);
-                                       dump_written += snprintf(dump_buf+dump_written, dump_len,
-                                               "\n" DHD_LOG_PREFIXS "[%s-%c]: bssid=%pM, chan=%3d(0x%x %sMHz), "
-                                               "rssi=%3d, sec=%-15s, SSID=\"%s\"",
-                                               tmp_if->ifname, tmp_if->prefix, &bssid, chan, chanspec,
-                                               CHSPEC_IS20(chanspec)?"20":
-                                               CHSPEC_IS40(chanspec)?"40":
-                                               CHSPEC_IS80(chanspec)?"80":"160",
-                                               dtoh32(scb_val.val), sec, ssid.SSID);
-                                       if (tmp_if->ifmode == IAP_MODE) {
-                                               dump_written += snprintf(dump_buf+dump_written, dump_len, "\n");
-                                               dump_written += wl_ext_assoclist(tmp_if->dev, NULL,
-                                                       dump_buf+dump_written, dump_len-dump_written);
-                                       }
-#ifdef WLMESH
-                                       else if (tmp_if->ifmode == IMESH_MODE) {
-                                               dump_written += snprintf(dump_buf+dump_written, dump_len, "\n");
-                                               dump_written += wl_ext_mesh_peer_status(tmp_if->dev, NULL,
+                       cur_if = &apsta_params->if_info[i];
+                       if (cur_if->dev) {
+                               dump_written += wl_ext_isam_dev_status(cur_if->dev,
+                                       cur_if->ifmode, cur_if->prefix,
+                                       dump_buf+dump_written, dump_len-dump_written);
+                       }
+#ifdef WLDWDS
+                       if (cur_if->ifmode == IAP_MODE) {
+                               for (i=0; i<MAX_DWDS_IF_NUM; i++) {
+                                       if (apsta_params->dwds_info[i].dev) {
+                                               dump_written += wl_ext_isam_dev_status(apsta_params->dwds_info[i].dev,
+                                                       IAP_MODE, 'W',
                                                        dump_buf+dump_written, dump_len-dump_written);
                                        }
-#endif /* WLMESH */
-                               } else {
-                                       dump_written += snprintf(dump_buf+dump_written, dump_len,
-                                               "\n" DHD_LOG_PREFIXS "[%s-%c]:", tmp_if->ifname, tmp_if->prefix);
                                }
                        }
+#endif /* WLDWDS */
                }
                IAPSTA_INFO(dev->name, "%s\n", dump_buf);
        }
@@ -5065,7 +6300,7 @@ wl_ext_isam_param(struct net_device *dev, char *command, int total_len)
                                if (apsta_params->acs_tmo != acs_tmo) {
                                        apsta_params->acs_tmo = acs_tmo;
                                        WL_MSG(dev->name, "acs_timer reset to %d\n", acs_tmo);
-                                       wl_ext_mod_timer(&cur_if->acs_timer, acs_tmo, 0);
+                                       wl_timer_mod(dhd, &cur_if->acs_timer, 0);
                                }
                                ret = 0;
                        } else {
@@ -5382,7 +6617,6 @@ wl_ext_iapsta_alive_postinit(struct net_device *dev)
        }
        // fix me: how to check it's ISTAAP_MODE or IDUALAP_MODE?
 
-       wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver);
        WL_MSG(dev->name, "apstamode=%d\n", apsta_params->apstamode);
 
        for (i=0; i<MAX_IF_NUM; i++) {
@@ -5392,7 +6626,7 @@ wl_ext_iapsta_alive_postinit(struct net_device *dev)
                if (i == 2 && !strlen(cur_if->ifname))
                        strcpy(cur_if->ifname, "wlan2");
                if (cur_if->ifmode == ISTA_MODE) {
-                       cur_if->channel = 0;
+                       wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 0);
                        cur_if->maxassoc = -1;
                        wl_set_isam_status(cur_if, IF_READY);
                        cur_if->prio = PRIO_STA;
@@ -5401,7 +6635,7 @@ wl_ext_iapsta_alive_postinit(struct net_device *dev)
                        snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
                }
                else if (cur_if->ifmode == IAP_MODE) {
-                       cur_if->channel = 1;
+                       wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1);
                        cur_if->maxassoc = -1;
                        wl_set_isam_status(cur_if, IF_READY);
                        cur_if->prio = PRIO_AP;
@@ -5411,7 +6645,7 @@ wl_ext_iapsta_alive_postinit(struct net_device *dev)
                }
 #ifdef WLMESH
                else if (cur_if->ifmode == IMESH_MODE) {
-                       cur_if->channel = 1;
+                       wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1);
                        cur_if->maxassoc = -1;
                        wl_set_isam_status(cur_if, IF_READY);
                        cur_if->prio = PRIO_MESH;
@@ -5469,6 +6703,10 @@ wl_ext_iapsta_postinit(struct net_device *net, struct wl_if_info *cur_if)
                if (dhd->conf->fw_type == FW_TYPE_MESH) {
                        apsta_params->csa |= (CSA_FW_BIT | CSA_DRV_BIT);
                }
+               cur_if->ifmode = ISTA_MODE;
+               cur_if->prio = PRIO_STA;
+               cur_if->vsdb = TRUE;
+               cur_if->prefix = 'S';
                if (dhd->conf->vndr_ie_assocreq && strlen(dhd->conf->vndr_ie_assocreq))
                        wl_ext_add_del_ie(net, VNDR_IE_ASSOCREQ_FLAG, dhd->conf->vndr_ie_assocreq, "add");
        } else {
@@ -5557,9 +6795,11 @@ wl_ext_iapsta_update_net_device(struct net_device *net, int ifidx)
                if (apsta_params->apstamode != IUNKNOWN_MODE &&
                                apsta_params->apstamode != ISTAAPAP_MODE &&
                                apsta_params->apstamode != ISTASTA_MODE) {
-                       memcpy(net->dev_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN);
-                       net->dev_addr[0] |= 0x02;
-                       wl_ext_iapsta_get_vif_macaddr(dhd, ifidx, net->dev_addr);
+                       u8 mac_addr[ETH_ALEN];
+                       memcpy(mac_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN);
+                       mac_addr[0] |= 0x02;
+                       wl_ext_iapsta_get_vif_macaddr(dhd, ifidx, mac_addr);
+                       dev_addr_set(net, mac_addr);
                }
 #endif /* WL_STATIC_IF */
        }
@@ -5567,80 +6807,158 @@ wl_ext_iapsta_update_net_device(struct net_device *net, int ifidx)
        return 0;
 }
 
+#ifdef WLDWDS
+int
+wl_ext_iapsta_attach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssidx)
+{
+       struct dhd_pub *dhd = dhd_get_pub(net);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       struct wl_if_info *cur_if = NULL;
+       int i;
+
+       for (i=0; i<MAX_IF_NUM; i++) {
+               cur_if = &apsta_params->if_info[ifidx];
+               if (cur_if->bssidx == bssidx) {
+                       break;
+               }
+       }
+
+       if (cur_if) {
+               IAPSTA_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx);
+               for (i=0; i<MAX_DWDS_IF_NUM; i++) {
+                       if (apsta_params->dwds_info[i].dev == NULL) {
+                               apsta_params->dwds_info[i].dev = net;
+                               apsta_params->dwds_info[i].ifidx = ifidx;
+                               apsta_params->dwds_info[i].bssidx = bssidx;
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int
+wl_ext_iapsta_dettach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssidx)
+{
+       struct dhd_pub *dhd = dhd_get_pub(net);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+       struct wl_if_info *cur_if = NULL;
+       int i;
+
+       for (i=0; i<MAX_IF_NUM; i++) {
+               cur_if = &apsta_params->if_info[ifidx];
+               if (cur_if->bssidx == bssidx) {
+                       break;
+               }
+       }
+
+       if (cur_if) {
+               IAPSTA_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx);
+               for (i=0; i<MAX_DWDS_IF_NUM; i++) {
+                       if (apsta_params->dwds_info[i].dev == net) {
+                               memset(&apsta_params->dwds_info[i], 0, sizeof(struct wl_dwds_info));
+                       }
+               }
+       }
+
+       return 0;
+}
+#endif /* WLDWDS */
+
+static void
+wl_ext_iapsta_init_priv(struct net_device *net)
+{
+       struct dhd_pub *dhd = dhd_get_pub(net);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+
+       if (!apsta_params->ioctl_buf) {
+               apsta_params->ioctl_buf = kmalloc(WL_DUMP_BUF_LEN, GFP_KERNEL);
+               if (unlikely(!apsta_params->ioctl_buf)) {
+                       IAPSTA_ERROR(net->name, "Can not allocate ioctl_buf\n");
+               }
+       }
+       init_waitqueue_head(&apsta_params->netif_change_event);
+       mutex_init(&apsta_params->usr_sync);
+       mutex_init(&apsta_params->in4way_sync);
+#ifdef STA_MGMT
+       INIT_LIST_HEAD(&apsta_params->sta_list);
+#endif /* STA_MGMT */
+#ifdef EAPOL_RESEND
+       spin_lock_init(&apsta_params->eapol_lock);
+#endif /* EAPOL_RESEND */
+}
+
+static void
+wl_ext_iapsta_deinit_priv(struct net_device *net)
+{
+       struct dhd_pub *dhd = dhd_get_pub(net);
+       struct wl_apsta_params *apsta_params = dhd->iapsta_params;
+
+       if (apsta_params->ioctl_buf) {
+               kfree(apsta_params->ioctl_buf);
+               apsta_params->ioctl_buf = NULL;
+       }
+       memset(apsta_params, 0, sizeof(struct wl_apsta_params));
+}
+
 int
 wl_ext_iapsta_attach_netdev(struct net_device *net, int ifidx, uint8 bssidx)
 {
        struct dhd_pub *dhd = dhd_get_pub(net);
        struct wl_apsta_params *apsta_params = dhd->iapsta_params;
-       struct wl_if_info *cur_if = NULL, *primary_if;
+       struct wl_if_info *cur_if = NULL;
 
        if (ifidx < MAX_IF_NUM) {
                IAPSTA_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx);
                cur_if = &apsta_params->if_info[ifidx];
        }
+
        if (ifidx == 0) {
-               memset(apsta_params, 0, sizeof(struct wl_apsta_params));
-               apsta_params->dhd = dhd;
-               cur_if->dev = net;
-               cur_if->ifidx = ifidx;
-               cur_if->bssidx = bssidx;
-               cur_if->ifmode = ISTA_MODE;
-               cur_if->prio = PRIO_STA;
-               cur_if->vsdb = TRUE;
-               cur_if->prefix = 'S';
-               wl_ext_event_register(net, dhd, WLC_E_LAST, wl_ext_iapsta_event,
-                       apsta_params, PRIO_EVENT_IAPSTA);
+               wl_ext_iapsta_init_priv(net);
                strcpy(cur_if->ifname, net->name);
-               init_waitqueue_head(&apsta_params->netif_change_event);
-               init_waitqueue_head(&apsta_params->ap_recon_sta_event);
-               mutex_init(&apsta_params->usr_sync);
-               mutex_init(&apsta_params->in4way_sync);
-               mutex_init(&cur_if->pm_sync);
 #ifdef TPUT_MONITOR
-               init_timer_compat(&apsta_params->monitor_timer, wl_tput_monitor_timer, net);
+               wl_timer_register(net, &apsta_params->monitor_timer, wl_tput_monitor_timer);
 #endif /* TPUT_MONITOR */
-#ifdef ACS_MONITOR
-               wl_acs_attach(dhd, cur_if);
-#endif /* ACS_MONITOR */
-               INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler);
-#ifdef SET_CARRIER
-               wl_ext_net_setcarrier(cur_if, FALSE, TRUE);
-#endif /* SET_CARRIER */
-               init_timer_compat(&cur_if->connect_timer, wl_ext_connect_timeout, net);
-#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
-               init_timer_compat(&cur_if->reconnect_timer, wl_ext_reconnect_timeout, net);
-#endif /* WL_EXT_RECONNECT && WL_CFG80211 */
-#ifdef EAPOL_RESEND
-               spin_lock_init(&apsta_params->eapol_lock);
-               init_timer_compat(&cur_if->eapol_timer, wl_eapol_timer, net);
-#endif /* EAPOL_RESEND */
-       } else if (cur_if && wl_get_isam_status(cur_if, IF_ADDING)) {
-               primary_if = &apsta_params->if_info[IF_PIF];
+#ifdef RXF0OVFL_REINIT_WAR
+               wl_timer_register(net, &apsta_params->rxf0ovfl_timer, wl_ext_rxf0ovfl_reinit_timeout);
+#endif /* RXF0OVFL_REINIT_WAR */
+       }
+
+       if (ifidx == 0 || (cur_if && wl_get_isam_status(cur_if, IF_ADDING))) {
                cur_if->dev = net;
                cur_if->ifidx = ifidx;
                cur_if->bssidx = bssidx;
+               mutex_init(&cur_if->pm_sync);
+               INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler);
+               init_waitqueue_head(&cur_if->ap_recon_sta_event);
                wl_ext_event_register(net, dhd, WLC_E_LAST, wl_ext_iapsta_event,
                        apsta_params, PRIO_EVENT_IAPSTA);
 #if defined(WLMESH) && defined(WL_ESCAN)
-               if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) {
-                       wl_mesh_escan_attach(dhd, cur_if);
-               }
+               wl_mesh_escan_attach(dhd, cur_if);
 #endif /* WLMESH && WL_ESCAN */
 #ifdef ACS_MONITOR
                wl_acs_attach(dhd, cur_if);
 #endif /* ACS_MONITOR */
-               mutex_init(&cur_if->pm_sync);
-               INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler);
 #ifdef SET_CARRIER
                wl_ext_net_setcarrier(cur_if, FALSE, TRUE);
 #endif /* SET_CARRIER */
-               init_timer_compat(&cur_if->connect_timer, wl_ext_connect_timeout, net);
+               wl_timer_register(net, &cur_if->connect_timer, wl_ext_connect_timeout);
 #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
-               init_timer_compat(&cur_if->reconnect_timer, wl_ext_reconnect_timeout, net);
+               wl_timer_register(net, &cur_if->reconnect_timer, wl_ext_reconnect_timeout);
 #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
+#ifdef RESTART_AP_WAR
+               wl_timer_register(net, &cur_if->restart_ap_timer, wl_ext_restart_ap_timeout);
+#endif /* RESTART_AP_WAR */
+#ifdef RESET_AP_WAR
+               wl_timer_register(net, &cur_if->reset_ap_timer, wl_ext_reset_ap_timeout);
+#endif /* RESET_AP_WAR */
 #ifdef EAPOL_RESEND
-               init_timer_compat(&cur_if->eapol_timer, wl_eapol_timer, net);
+               wl_timer_register(net, &cur_if->eapol_timer, wl_eapol_timer);
 #endif /* EAPOL_RESEND */
+#ifdef KEY_INSTALL_CHECK
+               wl_timer_register(net, &cur_if->key_install_timer, wl_ext_key_install_timeout);
+#endif /* KEY_INSTALL_CHECK */
        }
 
        return 0;
@@ -5661,41 +6979,24 @@ wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx)
                cur_if = &apsta_params->if_info[ifidx];
        }
 
-       if (ifidx == 0) {
-#ifdef EAPOL_RESEND
-               wl_ext_release_eapol_txpkt(dhd, ifidx, FALSE);
-#endif /* EAPOL_RESEND */
-               wl_ext_mod_timer(&cur_if->connect_timer, 0, 0);
-#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
-               wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0);
-#endif /* WL_EXT_RECONNECT && WL_CFG80211 */
-#ifdef SET_CARRIER
-               wl_ext_net_setcarrier(cur_if, FALSE, FALSE);
-#endif /* SET_CARRIER */
-               wl_ext_add_remove_pm_enable_work(net, FALSE);
-#ifdef ACS_MONITOR
-               wl_acs_detach(cur_if);
-#endif /* ACS_MONITOR */
-#ifdef TPUT_MONITOR
-               wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0);
-#endif /* TPUT_MONITOR */
-#if defined(WLMESH) && defined(WL_ESCAN)
-               if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) {
-                       wl_mesh_escan_detach(dhd, cur_if);
-               }
-#endif /* WLMESH && WL_ESCAN */
-               wl_ext_event_deregister(net, dhd, WLC_E_LAST, wl_ext_iapsta_event);
-               memset(apsta_params, 0, sizeof(struct wl_apsta_params));
-       }
-       else if (cur_if && (wl_get_isam_status(cur_if, IF_READY) ||
-                       wl_get_isam_status(cur_if, IF_ADDING))) {
+       if (ifidx == 0 || (cur_if && (wl_get_isam_status(cur_if, IF_READY) ||
+                       wl_get_isam_status(cur_if, IF_ADDING)))) {
 #ifdef EAPOL_RESEND
                wl_ext_release_eapol_txpkt(dhd, ifidx, FALSE);
 #endif /* EAPOL_RESEND */
-               wl_ext_mod_timer(&cur_if->connect_timer, 0, 0);
+#ifdef KEY_INSTALL_CHECK
+               wl_timer_deregister(net, &cur_if->key_install_timer);
+#endif /* KEY_INSTALL_CHECK */
+               wl_timer_deregister(net, &cur_if->connect_timer);
 #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211)
-               wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0);
+               wl_timer_deregister(net, &cur_if->reconnect_timer);
 #endif /* WL_EXT_RECONNECT && WL_CFG80211 */
+#ifdef RESTART_AP_WAR
+               wl_timer_deregister(net, &cur_if->restart_ap_timer);
+#endif /* RESTART_AP_WAR */
+#ifdef RESET_AP_WAR
+               wl_timer_deregister(net, &cur_if->reset_ap_timer);
+#endif /* RESET_AP_WAR */
 #ifdef SET_CARRIER
                wl_ext_net_setcarrier(cur_if, FALSE, FALSE);
 #endif /* SET_CARRIER */
@@ -5704,14 +7005,25 @@ wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx)
                wl_acs_detach(cur_if);
 #endif /* ACS_MONITOR */
 #if defined(WLMESH) && defined(WL_ESCAN)
-               if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) {
-                       wl_mesh_escan_detach(dhd, cur_if);
-               }
+               wl_mesh_escan_detach(dhd, cur_if);
 #endif /* WLMESH && WL_ESCAN */
                wl_ext_event_deregister(net, dhd, WLC_E_LAST, wl_ext_iapsta_event);
+#ifdef STA_MGMT
+               wl_ext_flush_sta_list(net, ifidx);
+#endif /* STA_MGMT */
                memset(cur_if, 0, sizeof(struct wl_if_info));
        }
 
+       if (ifidx == 0) {
+#ifdef RXF0OVFL_REINIT_WAR
+               wl_timer_deregister(net, &apsta_params->rxf0ovfl_timer);
+#endif /* RXF0OVFL_REINIT_WAR */
+#ifdef TPUT_MONITOR
+               wl_timer_deregister(net, &apsta_params->monitor_timer);
+#endif /* TPUT_MONITOR */
+               wl_ext_iapsta_deinit_priv(net);
+       }
+
        return 0;
 }
 
@@ -5725,7 +7037,7 @@ wl_ext_iapsta_attach(struct net_device *net)
 
        iapsta_params = kzalloc(sizeof(struct wl_apsta_params), GFP_KERNEL);
        if (unlikely(!iapsta_params)) {
-               IAPSTA_ERROR("wlan", "Could not allocate apsta_params\n");
+               IAPSTA_ERROR(net->name, "Can not allocate apsta_params\n");
                return -ENOMEM;
        }
        dhd->iapsta_params = (void *)iapsta_params;
@@ -5741,6 +7053,7 @@ wl_ext_iapsta_dettach(struct net_device *net)
        IAPSTA_TRACE(net->name, "Enter\n");
 
        if (dhd->iapsta_params) {
+               wl_ext_iapsta_deinit_priv(net);
                kfree(dhd->iapsta_params);
                dhd->iapsta_params = NULL;
        }
index 6e42b169d6c938cefc4fd670517758234d79d169..f88c6e7581f79d6e204795cb2022836350d689b4 100755 (executable)
@@ -10,7 +10,8 @@ typedef enum IFMODE {
 } ifmode_t;
 
 enum wl_ext_status {
-       WL_EXT_STATUS_DISCONNECTING = 0,
+       WL_EXT_STATUS_PRE_DISCONNECTING = 0,
+       WL_EXT_STATUS_DISCONNECTING,
        WL_EXT_STATUS_DISCONNECTED,
        WL_EXT_STATUS_SCAN,
        WL_EXT_STATUS_SCANNING,
@@ -18,11 +19,14 @@ enum wl_ext_status {
        WL_EXT_STATUS_CONNECTING,
        WL_EXT_STATUS_RECONNECT,
        WL_EXT_STATUS_CONNECTED,
+       WL_EXT_STATUS_ROAMED,
        WL_EXT_STATUS_ADD_KEY,
+       WL_EXT_STATUS_AP_ENABLING,
        WL_EXT_STATUS_AP_ENABLED,
        WL_EXT_STATUS_DELETE_STA,
        WL_EXT_STATUS_STA_DISCONNECTED,
        WL_EXT_STATUS_STA_CONNECTED,
+       WL_EXT_STATUS_AP_DISABLING,
        WL_EXT_STATUS_AP_DISABLED
 };
 
@@ -33,6 +37,10 @@ void wl_ext_backup_eapol_txpkt(dhd_pub_t *dhd, int ifidx, void *pkt);
 void wl_ext_release_eapol_txpkt(dhd_pub_t *dhd, int ifidx, bool rx);
 #endif /* EAPOL_RESEND */
 void wl_ext_iapsta_get_vif_macaddr(struct dhd_pub *dhd, int ifidx, u8 *mac_addr);
+#ifdef WLDWDS
+int wl_ext_iapsta_attach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssidx);
+int wl_ext_iapsta_dettach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssidx);
+#endif /* WLDWDS */
 int wl_ext_iapsta_attach_netdev(struct net_device *net, int ifidx, uint8 bssidx);
 int wl_ext_iapsta_attach_name(struct net_device *net, int ifidx);
 int wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx);
@@ -50,6 +58,10 @@ int wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len);
 void wl_ext_add_remove_pm_enable_work(struct net_device *dev, bool add);
 bool wl_ext_iapsta_other_if_enabled(struct net_device *net);
 bool wl_ext_sta_connecting(struct net_device *dev);
+void wl_ext_get_chan_str(struct net_device *dev, char *chan_str, int total_len);
+#ifdef DHD_LOSSLESS_ROAMING
+int wl_ext_any_sta_handshaking(struct dhd_pub *dhd);
+#endif /* DHD_LOSSLESS_ROAMING */
 void wl_iapsta_wait_event_complete(struct dhd_pub *dhd);
 int wl_iapsta_suspend_resume(dhd_pub_t *dhd, int suspend);
 #ifdef USE_IW
@@ -74,8 +86,18 @@ void wl_ext_iapsta_restart_master(struct net_device *dev);
 void wl_ext_iapsta_ifadding(struct net_device *net, int ifidx);
 bool wl_ext_iapsta_mesh_creating(struct net_device *net);
 void wl_ext_fw_reinit_incsa(struct net_device *dev);
+void wl_ext_send_event_msg(struct net_device *dev, int event, int status,
+       int reason);
+#ifdef BTC_WAR
+void wl_ext_btc_config(struct net_device *dev, bool enable);
+#endif /* BTC_WAR */
+#ifdef STA_MGMT
+bool wl_ext_del_sta_info(struct net_device *net, u8 *bssid);
+bool wl_ext_add_sta_info(struct net_device *net, u8 *bssid);
+#endif /* STA_MGMT */
 #ifdef SCAN_SUPPRESS
-uint16 wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2);
+uint16 wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2,
+       struct wl_chan_info *chan_info);
 void wl_ext_reset_scan_busy(dhd_pub_t *dhd);
 #endif /* SCAN_SUPPRESS */
 #endif
index 160148e0fe81034dd2315554b927bd4f16a2b402..10e4f34e9f1455d92e947f40deb7e9b3b05fa644 100755 (executable)
@@ -216,8 +216,8 @@ static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action);
 #endif /* !WL_ESCAN */
 
 struct pmk_list {
-       pmkid_list_t pmkids;
-       pmkid_t foo[MAXPMKID - 1];
+       pmkid_list_v1_t pmkids;
+       pmkid_v1_t foo[MAXPMKID - 1];
 };
 
 typedef struct wl_wext_info {
@@ -293,7 +293,7 @@ dev_wlc_ioctl(
 
        index = dhd_net2idx(dhd->info, dev);
        if (index == DHD_BAD_IF) {
-               WL_ERROR(("Bad ifidx from dev:%p\n", dev));
+               WL_ERROR(("Bad ifidx from %s\n", dev->name));
                return -ENODEV;
        }
        ret = dhd_ioctl_process(dhd, index, &ioc, arg);
@@ -456,6 +456,7 @@ typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
 #endif /* WIRELESS_EXT < 13 */
 
 #if WIRELESS_EXT > 12
+#ifdef CONFIG_WEXT_PRIV
 static int
 wl_iw_set_leddc(
        struct net_device *dev,
@@ -502,6 +503,7 @@ wl_iw_set_pm(
        error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
        return error;
 }
+#endif /* CONFIG_WEXT_PRIV */
 #endif /* WIRELESS_EXT > 12 */
 
 int
@@ -532,7 +534,7 @@ static int
 wl_iw_config_commit(
        struct net_device *dev,
        struct iw_request_info *info,
-       void *zwrq,
+       union iwreq_data *zwrq,
        char *extra
 )
 {
@@ -616,10 +618,11 @@ static int
 wl_iw_set_freq(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_freq *fwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_freq *fwrq = &wrqu->freq;
        int error, chan;
        uint sf = 0;
        struct dhd_pub *dhd = dhd_get_pub(dev);
@@ -668,18 +671,22 @@ static int
 wl_iw_get_freq(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_freq *fwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct dhd_pub *dhd = dhd_get_pub(dev);
+       struct iw_freq *fwrq = &wrqu->freq;
        int error;
-       u32 chanspec = 0;
+       chanspec_t chanspec = 0;
        int ctl_chan;
 
        WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
 
-       if ((error = dev_wlc_intvar_get(dev, "chanspec", &chanspec)))
+       DHD_CHECK(dhd, dev);
+       if ((error = dev_wlc_intvar_get(dev, "chanspec", (s32 *)&chanspec)))
                return error;
+       chanspec = wl_ext_chspec_driver_to_host(dhd, chanspec);
        ctl_chan = wf_chspec_ctlchan(chanspec);
 
        /* Return radio channel in channel form */
@@ -692,7 +699,7 @@ static int
 wl_iw_set_mode(
        struct net_device *dev,
        struct iw_request_info *info,
-       __u32 *uwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
@@ -709,7 +716,7 @@ wl_iw_set_mode(
                wext_info->conn_info.channel = 0;
        }
 
-       switch (*uwrq) {
+       switch (wrqu->mode) {
        case IW_MODE_MASTER:
                infra = ap = 1;
                break;
@@ -737,7 +744,7 @@ static int
 wl_iw_get_mode(
        struct net_device *dev,
        struct iw_request_info *info,
-       __u32 *uwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
@@ -751,7 +758,7 @@ wl_iw_get_mode(
 
        infra = dtoh32(infra);
        ap = dtoh32(ap);
-       *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
+       wrqu->mode = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
 
        return 0;
 }
@@ -760,10 +767,11 @@ static int
 wl_iw_get_range(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        struct iw_range *range = (struct iw_range *) extra;
        static int channels[MAXCHANNEL+1];
        wl_uint32_list_t *list = (wl_uint32_list_t *) channels;
@@ -992,10 +1000,11 @@ static int
 wl_iw_set_spy(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        wl_iw_t *iw = IW_DEV_IF(dev);
        struct sockaddr *addr = (struct sockaddr *) extra;
        int i;
@@ -1017,10 +1026,11 @@ static int
 wl_iw_get_spy(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        wl_iw_t *iw = IW_DEV_IF(dev);
        struct sockaddr *addr = (struct sockaddr *) extra;
        struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num];
@@ -1046,7 +1056,7 @@ static int
 wl_iw_set_wap(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct sockaddr *awrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
@@ -1057,13 +1067,13 @@ wl_iw_set_wap(
        WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
        DHD_CHECK(dhd, dev);
        wext_info = dhd->wext_info;
-       if (awrq->sa_family != ARPHRD_ETHER) {
+       if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) {
                WL_ERROR(("Invalid Header...sa_family\n"));
                return -EINVAL;
        }
 
        /* Ignore "auto" or "off" */
-       if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
+       if (ETHER_ISBCAST(wrqu->ap_addr.sa_data) || ETHER_ISNULLADDR(wrqu->ap_addr.sa_data)) {
                scb_val_t scbval;
                bzero(&scbval, sizeof(scb_val_t));
                WL_MSG(dev->name, "WLC_DISASSOC\n");
@@ -1076,21 +1086,21 @@ wl_iw_set_wap(
 #endif
                return 0;
        }
-       /* WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(awrq->sa_data),
+       /* WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(wrqu->ap_addr.sa_data),
         * eabuf)));
         */
        /* Reassociate to the specified AP */
        if (wext_info)
-               memcpy(&wext_info->conn_info.bssid, awrq->sa_data, ETHER_ADDR_LEN);
+               memcpy(&wext_info->conn_info.bssid, wrqu->ap_addr.sa_data, ETHER_ADDR_LEN);
        if (wext_info && wext_info->conn_info.ssid.SSID_len) {
                if ((error = wl_ext_connect(dev, &wext_info->conn_info)))
                        return error;
        } else {
-               if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) {
+               if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, wrqu->ap_addr.sa_data, ETHER_ADDR_LEN))) {
                        WL_ERROR(("WLC_REASSOC failed (%d).\n", error));
                        return error;
                }
-               WL_MSG(dev->name, "join BSSID="MACSTR"\n", MAC2STR((u8 *)awrq->sa_data));
+               WL_MSG(dev->name, "join BSSID="MACSTR"\n", MAC2STR((u8 *)wrqu->ap_addr.sa_data));
        }
 #ifdef WL_EXT_IAPSTA
        wl_ext_in4way_sync_wext(dev, STA_NO_BTC_IN4WAY, WL_EXT_STATUS_CONNECTING, NULL);
@@ -1103,17 +1113,17 @@ static int
 wl_iw_get_wap(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct sockaddr *awrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
        WL_TRACE(("%s: SIOCGIWAP\n", dev->name));
 
-       awrq->sa_family = ARPHRD_ETHER;
-       memset(awrq->sa_data, 0, ETHER_ADDR_LEN);
+       wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+       memset(wrqu->ap_addr.sa_data, 0, ETHER_ADDR_LEN);
 
        /* Ignore error (may be down or disassociated) */
-       (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN);
+       (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, wrqu->ap_addr.sa_data, ETHER_ADDR_LEN);
 
        return 0;
 }
@@ -1123,7 +1133,7 @@ static int
 wl_iw_mlme(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct sockaddr *awrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
@@ -1171,14 +1181,15 @@ static int
 wl_iw_get_aplist(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
-       wl_scan_results_t *list;
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
+       wl_scan_results_v109_t *list;
        struct sockaddr *addr = (struct sockaddr *) extra;
        struct iw_quality qual[IW_MAX_AP];
-       wl_bss_info_t *bi = NULL;
+       wl_bss_info_v109_t *bi = NULL;
        int error, i;
        uint buflen = dwrq->length;
        int16 rssi;
@@ -1205,7 +1216,7 @@ wl_iw_get_aplist(
        ASSERT(list->version == WL_BSS_INFO_VERSION);
 
        for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
-               bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
+               bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
                ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
                        buflen));
 
@@ -1247,17 +1258,18 @@ static int
 wl_iw_iscan_get_aplist(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
-       wl_scan_results_t *list;
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
+       wl_scan_results_v109_t *list;
        iscan_buf_t * buf;
        iscan_info_t *iscan;
 
        struct sockaddr *addr = (struct sockaddr *) extra;
        struct iw_quality qual[IW_MAX_AP];
-       wl_bss_info_t *bi = NULL;
+       wl_bss_info_v109_t *bi = NULL;
        int i;
        int16 rssi;
        struct dhd_pub *dhd = dhd_get_pub(dev);
@@ -1283,7 +1295,7 @@ wl_iw_iscan_get_aplist(
 
            bi = NULL;
        for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
-               bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
+               bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
                ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
                        WLC_IW_ISCAN_MAXLEN));
 
@@ -1365,11 +1377,11 @@ wl_iw_iscan_set_scan(
 )
 {
        struct dhd_pub *dhd = dhd_get_pub(dev);
-       wl_wext_info_t *wext_info = NULL;
        wlc_ssid_t ssid;
 #ifdef WL_ESCAN
        wl_scan_info_t scan_info;
 #else
+       wl_wext_info_t *wext_info = NULL;
        iscan_info_t *iscan;
 #ifdef WL_EXT_IAPSTA
        int err;
@@ -1377,7 +1389,6 @@ wl_iw_iscan_set_scan(
 #endif
 
        DHD_CHECK(dhd, dev);
-       wext_info = dhd->wext_info;
 #ifdef WL_ESCAN
        /* default Broadcast scan */
        memset(&ssid, 0, sizeof(ssid));
@@ -1398,6 +1409,7 @@ wl_iw_iscan_set_scan(
        scan_info.ssid.SSID_len = ssid.SSID_len;
        return wl_escan_set_scan(dev, &scan_info);
 #else
+       wext_info = dhd->wext_info;
        iscan = &wext_info->iscan;
        WL_TRACE(("%s: SIOCSIWSCAN iscan=%p\n", dev->name, iscan));
 #ifdef WL_EXT_IAPSTA
@@ -1532,7 +1544,7 @@ static
 #endif
 int
 wl_iw_handle_scanresults_ies(char **event_p, char *end,
-       struct iw_request_info *info, wl_bss_info_t *bi)
+       struct iw_request_info *info, wl_bss_info_v109_t *bi)
 {
 #if WIRELESS_EXT > 17
        struct iw_event iwe;
@@ -1596,7 +1608,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end,
                }
 
 #ifdef BCMWAPI_WPI
-               ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
+               ptr = ((uint8 *)bi) + sizeof(wl_bss_info_v109_t);
                ptr_len = bi->ie_length;
 
                while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WAPI_ID))) {
@@ -1639,14 +1651,15 @@ static int
 wl_iw_get_scan(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        channel_info_t ci;
-       wl_scan_results_t *list;
+       wl_scan_results_v109_t *list;
        struct iw_event iwe;
-       wl_bss_info_t *bi = NULL;
+       wl_bss_info_v109_t *bi = NULL;
        int error, i, j;
        char *event = extra, *end = extra + dwrq->length, *value;
        uint buflen = dwrq->length;
@@ -1682,7 +1695,7 @@ wl_iw_get_scan(
        ASSERT(list->version == WL_BSS_INFO_VERSION);
 
        for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
-               bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
+               bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
                ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
                        buflen));
 
@@ -1769,16 +1782,17 @@ static int
 wl_iw_iscan_get_scan(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        struct dhd_pub *dhd = dhd_get_pub(dev);
-       wl_wext_info_t *wext_info = NULL;
 #ifndef WL_ESCAN
-       wl_scan_results_t *list;
+       wl_wext_info_t *wext_info = NULL;
+       wl_scan_results_v109_t *list;
        struct iw_event iwe;
-       wl_bss_info_t *bi = NULL;
+       wl_bss_info_v109_t *bi = NULL;
        int ii, j;
        int apcnt;
        char *event = extra, *end = extra + dwrq->length, *value;
@@ -1789,7 +1803,6 @@ wl_iw_iscan_get_scan(
 #endif
 
        DHD_CHECK(dhd, dev);
-       wext_info = dhd->wext_info;
 #ifdef WL_ESCAN
        return wl_escan_get_scan(dev, info, dwrq, extra);
 #else
@@ -1798,6 +1811,7 @@ wl_iw_iscan_get_scan(
        if (!extra)
                return -EINVAL;
 
+       wext_info = dhd->wext_info;
        /* use backup if our thread is not successful */
        iscan = &wext_info->iscan;
        if ((!iscan) || (iscan->sysioc_pid < 0)) {
@@ -1822,7 +1836,7 @@ wl_iw_iscan_get_scan(
 
                bi = NULL;
                for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) {
-                       bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
+                       bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
                        ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
                                WLC_IW_ISCAN_MAXLEN));
 
@@ -1919,10 +1933,11 @@ static int
 wl_iw_set_essid(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        wlc_ssid_t ssid;
        int error;
        struct dhd_pub *dhd = dhd_get_pub(dev);
@@ -1982,10 +1997,11 @@ static int
 wl_iw_get_essid(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        wlc_ssid_t ssid;
        int error;
 
@@ -2004,14 +2020,15 @@ wl_iw_get_essid(
        /* Max SSID length check */
        if (ssid.SSID_len > IW_ESSID_MAX_SIZE) {
                ssid.SSID_len = IW_ESSID_MAX_SIZE;
+               /* Get the current SSID */
+               memcpy(extra, ssid.SSID, ssid.SSID_len);
+               /* NULL terminating as length of extra buffer is IW_ESSID_MAX_SIZE ie 32 */
+               extra[IW_ESSID_MAX_SIZE-1] = '\0';
+       } else {
+               /* Get the current SSID */
+               memcpy(extra, ssid.SSID, ssid.SSID_len);
        }
 
-       /* Get the current SSID */
-       memcpy(extra, ssid.SSID, ssid.SSID_len);
-
-       /* NULL terminating as length of extra buffer is IW_ESSID_MAX_SIZE ie 32 */
-       extra[IW_ESSID_MAX_SIZE] = '\0';
-
        dwrq->length = ssid.SSID_len;
 
        dwrq->flags = 1; /* active */
@@ -2023,10 +2040,11 @@ static int
 wl_iw_set_nick(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        wl_iw_t *iw = IW_DEV_IF(dev);
        WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name));
 
@@ -2047,10 +2065,11 @@ static int
 wl_iw_get_nick(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        wl_iw_t *iw = IW_DEV_IF(dev);
        WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name));
 
@@ -2066,10 +2085,11 @@ wl_iw_get_nick(
 static int wl_iw_set_rate(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->bitrate;
        wl_rateset_t rateset;
        int error, rate, i, error_bg, error_a;
 
@@ -2132,10 +2152,11 @@ static int wl_iw_set_rate(
 static int wl_iw_get_rate(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->bitrate;
        int error, rate;
 
        WL_TRACE(("%s: SIOCGIWRATE\n", dev->name));
@@ -2153,10 +2174,11 @@ static int
 wl_iw_set_rts(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->rts;
        int error, rts;
 
        WL_TRACE(("%s: SIOCSIWRTS\n", dev->name));
@@ -2178,10 +2200,11 @@ static int
 wl_iw_get_rts(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->rts;
        int error, rts;
 
        WL_TRACE(("%s: SIOCGIWRTS\n", dev->name));
@@ -2200,10 +2223,11 @@ static int
 wl_iw_set_frag(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->frag;
        int error, frag;
 
        WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name));
@@ -2225,10 +2249,11 @@ static int
 wl_iw_get_frag(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->frag;
        int error, fragthreshold;
 
        WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name));
@@ -2247,10 +2272,11 @@ static int
 wl_iw_set_txpow(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->txpower;
        int error, disable;
        uint16 txpwrmw;
        WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name));
@@ -2287,10 +2313,11 @@ static int
 wl_iw_get_txpow(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->txpower;
        int error, disable, txpwrdbm;
        uint8 result;
 
@@ -2315,10 +2342,11 @@ static int
 wl_iw_set_retry(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->retry;
        int error, lrl, srl;
 
        WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name));
@@ -2362,10 +2390,11 @@ static int
 wl_iw_get_retry(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->retry;
        int error, lrl, srl;
 
        WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name));
@@ -2403,10 +2432,11 @@ static int
 wl_iw_set_encode(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        wl_wsec_key_t key;
        int error, val, wsec;
 
@@ -2492,10 +2522,11 @@ static int
 wl_iw_get_encode(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        wl_wsec_key_t key;
        int error, val, wsec, auth;
 
@@ -2555,10 +2586,11 @@ static int
 wl_iw_set_power(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->power;
        int error, pm;
 
        WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name));
@@ -2576,10 +2608,11 @@ static int
 wl_iw_get_power(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->power;
        int error, pm;
 
        WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name));
@@ -2599,10 +2632,11 @@ static int
 wl_iw_set_wpaie(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *iwp,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *iwp = (struct iw_point *)wrqu;
 #if defined(BCMWAPI_WPI)
        uchar buf[WLC_IOCTL_SMLEN] = {0};
        uchar *p = buf;
@@ -2627,10 +2661,11 @@ static int
 wl_iw_get_wpaie(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *iwp,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *iwp = (struct iw_point *)wrqu;
        WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name));
        iwp->length = 64;
        dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
@@ -2641,10 +2676,11 @@ static int
 wl_iw_set_encodeext(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_point *dwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_point *dwrq = (struct iw_point *)wrqu;
        wl_wsec_key_t key;
        int error;
        struct iw_encode_ext *iwe;
@@ -2793,7 +2829,7 @@ static int
 wl_iw_set_pmksa(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
@@ -2801,7 +2837,7 @@ wl_iw_set_pmksa(
        struct iw_pmksa *iwpmksa;
        uint i;
        char eabuf[ETHER_ADDR_STR_LEN];
-       pmkid_t *pmkid_array = NULL;
+       pmkid_v1_t *pmkid_array = NULL;
        struct dhd_pub *dhd = dhd_get_pub(dev);
        wl_wext_info_t *wext_info = NULL;
 
@@ -2818,7 +2854,7 @@ wl_iw_set_pmksa(
                bzero((char *)pmk_list, sizeof(struct pmk_list));
        }
        if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
-               pmkid_list_t pmkid, *pmkidptr;
+               pmkid_list_v1_t pmkid, *pmkidptr;
                pmkidptr = &pmkid;
                bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN);
                bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN);
@@ -2883,7 +2919,7 @@ static int
 wl_iw_get_encodeext(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
@@ -2895,10 +2931,11 @@ static int
 wl_iw_set_wpaauth(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->param;
        int error = 0;
        int paramid;
        int paramval;
@@ -2935,7 +2972,7 @@ wl_iw_set_wpaauth(
 
        case IW_AUTH_CIPHER_PAIRWISE:
        case IW_AUTH_CIPHER_GROUP: {
-               int fbt_cap = 0;
+//             int fbt_cap = 0;
 
                if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
                        iw->pwsec = paramval;
@@ -2984,6 +3021,7 @@ wl_iw_set_wpaauth(
                        return error;
                }
 
+#if 0
                /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
                 * handshake.
                 */
@@ -3004,6 +3042,7 @@ wl_iw_set_wpaauth(
                                }
                        }
                }
+#endif
                break;
        }
 
@@ -3151,10 +3190,11 @@ static int
 wl_iw_get_wpaauth(
        struct net_device *dev,
        struct iw_request_info *info,
-       struct iw_param *vwrq,
+       union iwreq_data *wrqu,
        char *extra
 )
 {
+       struct iw_param *vwrq = &wrqu->param;
        int error;
        int paramid;
        int paramval = 0;
@@ -3321,6 +3361,7 @@ static const iw_handler wl_iw_handler[] =
 };
 
 #if WIRELESS_EXT > 12
+#ifdef CONFIG_WEXT_PRIV
 enum {
        WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV,
        WL_IW_SET_VLANMODE,
@@ -3356,15 +3397,18 @@ static struct iw_priv_args wl_iw_priv_args[] = {
        },
        { 0, 0, 0, { 0 } }
 };
+#endif /* CONFIG_WEXT_PRIV */
 
 const struct iw_handler_def wl_iw_handler_def =
 {
        .num_standard = ARRAYSIZE(wl_iw_handler),
+       .standard = (const iw_handler *) wl_iw_handler,
+#ifdef CONFIG_WEXT_PRIV
        .num_private = ARRAY_SIZE(wl_iw_priv_handler),
        .num_private_args = ARRAY_SIZE(wl_iw_priv_args),
-       .standard = (const iw_handler *) wl_iw_handler,
        .private = wl_iw_priv_handler,
        .private_args = wl_iw_priv_args,
+#endif /* CONFIG_WEXT_PRIV */
 #if WIRELESS_EXT >= 19
        get_wireless_stats: dhd_get_wireless_stats,
 #endif /* WIRELESS_EXT >= 19 */
@@ -3849,10 +3893,12 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat
        int rssi;
        scb_val_t scb_val;
 #if WIRELESS_EXT > 11
+#ifdef WL_NAN
        char *cntbuf = NULL;
        wl_cnt_info_t *cntinfo;
        uint16 ver;
        uint32 corerev = 0;
+#endif
 #endif /* WIRELESS_EXT > 11 */
 
        phy_noise = 0;
@@ -3896,6 +3942,7 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat
 #endif /* WIRELESS_EXT > 18 */
 
 #if WIRELESS_EXT > 11
+#ifdef WL_NAN
        WL_TRACE(("wl_iw_get_wireless_stats counters\n *****"));
 
        cntbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL);
@@ -3916,12 +3963,10 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat
        cntinfo->version = dtoh16(cntinfo->version);
        cntinfo->datalen = dtoh16(cntinfo->datalen);
        ver = cntinfo->version;
-#ifdef WL_NAN
        CHK_CNTBUF_DATALEN(cntbuf, MAX_WLIW_IOCTL_LEN);
-#endif
-       if (ver > WL_CNT_T_VERSION) {
+       if (ver > WL_CNT_VERSION_XTLV) {
                WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n",
-                       WL_CNT_T_VERSION, ver));
+                       WL_CNT_VERSION_XTLV, ver));
                res = BCME_VERSION;
                goto done;
        }
@@ -3937,7 +3982,6 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat
                corerev = dtoh32(revinfo.corerev);
        }
 
-#ifdef WL_NAN
        res = wl_cntbuf_to_xtlv_format(NULL, cntinfo, MAX_WLIW_IOCTL_LEN, corerev);
        if (res) {
                WL_ERROR(("wl_cntbuf_to_xtlv_format failed %d\n", res));
@@ -3953,9 +3997,11 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat
 
 done:
 #if WIRELESS_EXT > 11
+#ifdef WL_NAN
        if (cntbuf) {
                kfree(cntbuf);
        }
+#endif
 #endif /* WIRELESS_EXT > 11 */
        return res;
 }
@@ -3987,7 +4033,7 @@ wl_iw_set_event_mask(struct net_device *dev)
 }
 
 static int
-wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
+wl_iw_iscan_prep(wl_scan_params_v1_t *params, wlc_ssid_t *ssid)
 {
        int err = 0;
 
@@ -4013,14 +4059,14 @@ wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
 static int
 wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action)
 {
-       int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params));
-       wl_iscan_params_t *params;
+       int params_size = (WL_SCAN_PARAMS_V1_FIXED_SIZE + OFFSETOF(wl_iscan_params_v1_t, params));
+       wl_iscan_params_v1_t *params;
        int err = 0;
 
        if (ssid && ssid->SSID_len) {
                params_size += sizeof(wlc_ssid_t);
        }
-       params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
+       params = (wl_iscan_params_v1_t*)kmalloc(params_size, GFP_KERNEL);
        if (params == NULL) {
                return -ENOMEM;
        }
@@ -4034,7 +4080,7 @@ wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action)
                params->action = htod16(action);
                params->scan_duration = htod16(0);
 
-               /* params_size += OFFSETOF(wl_iscan_params_t, params); */
+               /* params_size += OFFSETOF(wl_iscan_params_v1_t, params); */
                (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size,
                        iscan->ioctlbuf, WLC_IOCTL_SMLEN);
        }
@@ -4050,7 +4096,7 @@ wl_iw_iscan_get(iscan_info_t *iscan)
        iscan_buf_t * ptr;
        wl_iscan_results_t * list_buf;
        wl_iscan_results_t list;
-       wl_scan_results_t *results;
+       wl_scan_results_v109_t *results;
        uint32 status;
 
        /* buffers are allocated on demand */
@@ -4275,14 +4321,12 @@ s32
 wl_iw_autochannel(struct net_device *dev, char* command, int total_len)
 {
        struct dhd_pub *dhd = dhd_get_pub(dev);
-       wl_wext_info_t *wext_info = NULL;
        int ret = 0;
 #ifdef WL_ESCAN
        int bytes_written = -1;
 #endif
 
        DHD_CHECK(dhd, dev);
-       wext_info = dhd->wext_info;
 #ifdef WL_ESCAN
        sscanf(command, "%*s %d", &dhd->escan->autochannel);
        if (dhd->escan->autochannel == 0) {
index c6254da1655bef5eb4469b49a27309d0aac972fc..52ee4d3c0a98e95329987ccea125661476b7057d 100755 (executable)
@@ -226,7 +226,7 @@ int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan,
                n++;
        }
 
-       WL_DBG((" %s: 0x%04X\n", __FUNCTION__, channels[0]));
+       WL_SCAN(("0x%04X\n", channels[0]));
 
 #ifdef WES_SUPPORT
        if (cfg->roamscan_mode == ROAMSCAN_MODE_WES) {
@@ -242,7 +242,7 @@ int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan,
                        ch = wf_chspec_ctlchan(ch) | CHSPEC_BAND(ch) | band_bw;
 
                        if (band_match && !is_duplicated_channel(channels, n, ch)) {
-                               WL_DBG(("%s: Chanspec = %s\n", __FUNCTION__,
+                               WL_SCAN(("Chanspec = %s\n",
                                        wf_chspec_ntoa_ex(ch, chanbuf)));
                                channels[n++] = ch;
                                if (n >= n_channels) {
@@ -270,7 +270,7 @@ int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan,
                        band_match && !is_duplicated_channel(channels, n, ch) &&
                        (memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) {
                        /* match found, add it */
-                       WL_DBG(("%s: Chanspec = %s\n", __FUNCTION__,
+                       WL_SCAN(("Chanspec = %s\n",
                                wf_chspec_ntoa_ex(ch, chanbuf)));
                        channels[n++] = ch;
                        if (n >= n_channels) {
diff --git a/bcmdhd.101.10.361.x/wl_timer.c b/bcmdhd.101.10.361.x/wl_timer.c
new file mode 100755 (executable)
index 0000000..e9ea4d8
--- /dev/null
@@ -0,0 +1,611 @@
+#include <wl_android.h>\r
+#ifdef WL_TIMER\r
+\r
+#define TIMER_ERROR(name, arg1, args...) \\r
+       do { \\r
+               if (android_msg_level & ANDROID_ERROR_LEVEL) { \\r
+                       printf("[%s] TIMER-ERROR) %s : " arg1, name, __func__, ## args); \\r
+               } \\r
+       } while (0)\r
+#define TIMER_TRACE(name, arg1, args...) \\r
+       do { \\r
+               if (android_msg_level & ANDROID_TRACE_LEVEL) { \\r
+                       printf("[%s] TIMER-TRACE) %s : " arg1, name, __func__, ## args); \\r
+               } \\r
+       } while (0)\r
+\r
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \\r
+       4 && __GNUC_MINOR__ >= 6))\r
+#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \\r
+_Pragma("GCC diagnostic push") \\r
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \\r
+(entry) = list_first_entry((ptr), type, member); \\r
+_Pragma("GCC diagnostic pop") \\r
+\r
+#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \\r
+_Pragma("GCC diagnostic push") \\r
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \\r
+entry = container_of((ptr), type, member); \\r
+_Pragma("GCC diagnostic pop") \\r
+\r
+#else\r
+#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \\r
+(entry) = list_first_entry((ptr), type, member); \\r
+\r
+#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \\r
+entry = container_of((ptr), type, member); \\r
+\r
+#endif /* STRICT_GCC_WARNINGS */\r
+\r
+typedef void(*FUNC_HANDLER) (void *cb_argu);\r
+\r
+struct wl_func_q {\r
+       struct list_head eq_list;\r
+       FUNC_HANDLER cb_func;\r
+       void *cb_argu;\r
+};\r
+\r
+typedef void(*TIMER_HANDLER) (void *cb_argu);\r
+\r
+typedef struct timer_handler_list {\r
+       struct list_head list;\r
+       struct net_device *net;\r
+       timer_list_compat_t *timer;\r
+       TIMER_HANDLER cb_func;\r
+       void *cb_argu;\r
+       uint tmo_ms;\r
+       ulong tmo_jiffies;\r
+} timer_handler_list_t;\r
+\r
+typedef struct wl_timer_params {\r
+       dhd_pub_t *pub;\r
+       struct list_head timer_list;\r
+       struct list_head eq_list;\r
+       timer_list_compat_t timer;\r
+       spinlock_t eq_lock;\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+       struct workqueue_struct *timer_workq;\r
+       struct work_struct timer_work;\r
+       struct workqueue_struct *func_workq;\r
+       struct work_struct func_work;\r
+#else\r
+       tsk_ctl_t thr_timer_ctl;\r
+       tsk_ctl_t thr_func_ctl;\r
+#endif\r
+} wl_timer_params_t;\r
+\r
+static unsigned long\r
+wl_func_lock_eq(struct wl_timer_params *timer_params)\r
+{\r
+       unsigned long flags;\r
+\r
+       spin_lock_irqsave(&timer_params->eq_lock, flags);\r
+       return flags;\r
+}\r
+\r
+static void\r
+wl_func_unlock_eq(struct wl_timer_params *timer_params, unsigned long flags)\r
+{\r
+       spin_unlock_irqrestore(&timer_params->eq_lock, flags);\r
+}\r
+\r
+static void\r
+wl_func_init_eq_lock(struct wl_timer_params *timer_params)\r
+{\r
+       spin_lock_init(&timer_params->eq_lock);\r
+}\r
+\r
+static void\r
+wl_func_init_eq(struct wl_timer_params *timer_params)\r
+{\r
+       wl_func_init_eq_lock(timer_params);\r
+       INIT_LIST_HEAD(&timer_params->eq_list);\r
+}\r
+\r
+static void\r
+wl_func_flush_eq(struct wl_timer_params *timer_params)\r
+{\r
+       struct wl_func_q *e;\r
+       unsigned long flags;\r
+\r
+       flags = wl_func_lock_eq(timer_params);\r
+       while (!list_empty_careful(&timer_params->eq_list)) {\r
+               BCM_SET_LIST_FIRST_ENTRY(e, &timer_params->eq_list, struct wl_func_q, eq_list);\r
+               list_del(&e->eq_list);\r
+               kfree(e);\r
+       }\r
+       wl_func_unlock_eq(timer_params, flags);\r
+}\r
+\r
+static struct wl_func_q *\r
+wl_func_deq(struct wl_timer_params *timer_params)\r
+{\r
+       struct wl_func_q *e = NULL;\r
+       unsigned long flags;\r
+\r
+       flags = wl_func_lock_eq(timer_params);\r
+       if (likely(!list_empty(&timer_params->eq_list))) {\r
+               BCM_SET_LIST_FIRST_ENTRY(e, &timer_params->eq_list, struct wl_func_q, eq_list);\r
+               list_del(&e->eq_list);\r
+       }\r
+       wl_func_unlock_eq(timer_params, flags);\r
+\r
+       return e;\r
+}\r
+\r
+static s32\r
+wl_func_enq(struct wl_timer_params *timer_params,\r
+       void *cb_func, void *cb_argu)\r
+{\r
+       struct wl_func_q *e;\r
+       s32 err = 0;\r
+       uint32 funcq_size;\r
+       unsigned long flags;\r
+       gfp_t aflags;\r
+\r
+       funcq_size = sizeof(struct wl_func_q);\r
+       aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;\r
+       e = kzalloc(funcq_size, aflags);\r
+       if (unlikely(!e)) {\r
+               TIMER_ERROR("wlan", "funcq_size alloc failed %d\n", funcq_size);\r
+               return -ENOMEM;\r
+       }\r
+       e->cb_func = cb_func;\r
+       e->cb_argu = cb_argu;\r
+       flags = wl_func_lock_eq(timer_params);\r
+       list_add_tail(&e->eq_list, &timer_params->eq_list);\r
+       wl_func_unlock_eq(timer_params, flags);\r
+\r
+       return err;\r
+}\r
+\r
+static void\r
+wl_func_put(struct wl_func_q *e)\r
+{\r
+       kfree(e);\r
+}\r
+\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+static void wl_func_handler(struct work_struct *data);\r
+#define WL_FUNC_HANDLER() static void wl_func_handler(struct work_struct *data)\r
+#else\r
+static int wl_func_handler(void *data);\r
+#define WL_FUNC_HANDLER() static int wl_func_handler(void *data)\r
+#endif\r
+\r
+WL_FUNC_HANDLER()\r
+{\r
+       struct wl_timer_params *timer_params = NULL;\r
+       struct wl_func_q *e;\r
+       struct net_device *net = NULL;\r
+       dhd_pub_t *dhd;\r
+       unsigned long flags = 0;\r
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))\r
+       tsk_ctl_t *tsk = (tsk_ctl_t *)data;\r
+       timer_params = (struct wl_timer_params *)tsk->parent;\r
+#else\r
+       BCM_SET_CONTAINER_OF(timer_params, data, struct wl_timer_params, func_work);\r
+#endif\r
+\r
+       dhd = timer_params->pub;\r
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))\r
+       while (1) {\r
+       if (down_interruptible(&tsk->sema) == 0) {\r
+               SMP_RD_BARRIER_DEPENDS();\r
+               if (tsk->terminated) {\r
+                       break;\r
+               }\r
+#endif\r
+       DHD_EVENT_WAKE_LOCK(dhd);\r
+       while ((e = wl_func_deq(timer_params))) {\r
+               DHD_GENERAL_LOCK(dhd, flags);\r
+               if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd)) {\r
+                       TIMER_ERROR(net->name, "BUS is DOWN.\n");\r
+                       DHD_GENERAL_UNLOCK(dhd, flags);\r
+                       goto fail;\r
+               }\r
+               DHD_GENERAL_UNLOCK(dhd, flags);\r
+               e->cb_func(e->cb_argu);\r
+fail:\r
+               wl_func_put(e);\r
+       }\r
+       DHD_EVENT_WAKE_UNLOCK(dhd);\r
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))\r
+       } else {\r
+               break;\r
+       }\r
+       }\r
+       complete_and_exit(&tsk->completed, 0);\r
+#endif\r
+}\r
+\r
+void\r
+wl_func_send(void *params, void *cb_func, void *cb_argu)\r
+{\r
+       struct wl_timer_params *timer_params = params;\r
+\r
+       if (timer_params == NULL) {\r
+               TIMER_ERROR("wlan", "Stale ignored\n");\r
+               return;\r
+       }\r
+\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+       if (timer_params->func_workq == NULL) {\r
+               TIMER_ERROR("wlan", "Event handler is not created\n");\r
+               return;\r
+       }\r
+#endif\r
+\r
+       if (likely(!wl_func_enq(timer_params, cb_func, cb_argu))) {\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+               queue_work(timer_params->func_workq, &timer_params->func_work);\r
+#else\r
+               if (timer_params->thr_func_ctl.thr_pid >= 0) {\r
+                       up(&timer_params->thr_func_ctl.sema);\r
+               }\r
+#endif\r
+       }\r
+}\r
+\r
+static s32\r
+wl_func_create_handler(struct wl_timer_params *timer_params)\r
+{\r
+       int ret = 0;\r
+       TIMER_TRACE("wlan", "Enter\n");\r
+\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+       if (!timer_params->func_workq) {\r
+               timer_params->func_workq = alloc_workqueue("timer_funcd",\r
+                       WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0);\r
+       }\r
+       if (!timer_params->func_workq) {\r
+               TIMER_ERROR("wlan", "func_workq alloc_workqueue failed\n");\r
+               ret = -ENOMEM;\r
+       } else {\r
+               INIT_WORK(&timer_params->func_work, wl_func_handler);\r
+       }\r
+#else\r
+       PROC_START(wl_func_handler, timer_params, &timer_params->thr_func_ctl, 0, "timer_funcd");\r
+       if (timer_params->thr_func_ctl.thr_pid < 0) {\r
+               ret = -ENOMEM;\r
+       }\r
+#endif\r
+\r
+       return ret;\r
+}\r
+\r
+static void\r
+wl_func_destroy_handler(struct wl_timer_params *timer_params)\r
+{\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+       if (timer_params && timer_params->func_workq) {\r
+               cancel_work_sync(&timer_params->func_work);\r
+               destroy_workqueue(timer_params->func_workq);\r
+               timer_params->func_workq = NULL;\r
+       }\r
+#else\r
+       if (timer_params->thr_func_ctl.thr_pid >= 0) {\r
+               PROC_STOP(&timer_params->thr_func_ctl);\r
+       }\r
+#endif\r
+}\r
+\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+static void wl_timer_handler(struct work_struct *data);\r
+#define WL_TIMER_HANDLER() static void wl_timer_handler(struct work_struct *data)\r
+#else\r
+static int wl_timer_handler(void *data);\r
+#define WL_TIMER_HANDLER() static int wl_timer_handler(void *data)\r
+#endif\r
+\r
+WL_TIMER_HANDLER()\r
+{\r
+       struct wl_timer_params *timer_params = NULL;\r
+       struct timer_handler_list *node, *next;\r
+       dhd_pub_t *dhd;\r
+       unsigned long flags = 0;\r
+       unsigned long cur_jiffies, diff_jiffies, min_jiffies = 0;\r
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))\r
+       tsk_ctl_t *tsk = (tsk_ctl_t *)data;\r
+       timer_params = (struct wl_timer_params *)tsk->parent;\r
+#else\r
+       BCM_SET_CONTAINER_OF(timer_params, data, struct wl_timer_params, timer_work);\r
+#endif\r
+\r
+       dhd = timer_params->pub;\r
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))\r
+       while (1) {\r
+       if (down_interruptible(&tsk->sema) == 0) {\r
+               SMP_RD_BARRIER_DEPENDS();\r
+               if (tsk->terminated) {\r
+                       break;\r
+               }\r
+#endif\r
+       DHD_EVENT_WAKE_LOCK(dhd);\r
+       DHD_GENERAL_LOCK(dhd, flags);\r
+       if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd)) {\r
+               TIMER_ERROR("wlan", "BUS is DOWN.\n");\r
+               DHD_GENERAL_UNLOCK(dhd, flags);\r
+               goto exit;\r
+       }\r
+       DHD_GENERAL_UNLOCK(dhd, flags);\r
+       cur_jiffies = jiffies;\r
+       list_for_each_entry_safe(node, next, &timer_params->timer_list, list) {\r
+               if (node->tmo_ms) {\r
+                       if (time_after(cur_jiffies, node->tmo_jiffies)) {\r
+                               wl_func_send(timer_params, node->cb_func, node->cb_argu);\r
+                               node->tmo_ms = 0;\r
+                       } else {\r
+                               diff_jiffies = node->tmo_jiffies - cur_jiffies;\r
+                               if (min_jiffies == 0)\r
+                                       min_jiffies = diff_jiffies;\r
+                               else if (diff_jiffies < min_jiffies)\r
+                                       min_jiffies = diff_jiffies;\r
+                       }\r
+               }\r
+       }\r
+       if (min_jiffies)\r
+               mod_timer(&timer_params->timer, jiffies + min_jiffies);\r
+exit:\r
+       DHD_EVENT_WAKE_UNLOCK(dhd);\r
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))\r
+       } else {\r
+               break;\r
+       }\r
+       }\r
+       complete_and_exit(&tsk->completed, 0);\r
+#endif\r
+}\r
+\r
+void\r
+wl_timer_kick_handler(wl_timer_params_t *timer_params)\r
+{\r
+       if (timer_params == NULL) {\r
+               TIMER_ERROR("wlan", "timer_params not ready\n");\r
+               return;\r
+       }\r
+\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+       if (timer_params->timer_workq == NULL) {\r
+               TIMER_ERROR("wlan", "timer handler is not created\n");\r
+               return;\r
+       }\r
+       queue_work(timer_params->timer_workq, &timer_params->timer_work);\r
+#else\r
+       if (timer_params->thr_timer_ctl.thr_pid >= 0) {\r
+               up(&timer_params->thr_timer_ctl.sema);\r
+       }\r
+#endif\r
+}\r
+\r
+static void\r
+wl_timer_timeout(unsigned long data)\r
+{\r
+       struct wl_timer_params *timer_params = (struct wl_timer_params *)data;\r
+\r
+       if (!timer_params) {\r
+               TIMER_ERROR("wlan", "timer_params is not ready\n");\r
+               return;\r
+       }\r
+\r
+       TIMER_TRACE("wlan", "timer expired\n");\r
+       wl_timer_kick_handler(timer_params);\r
+}\r
+\r
+static s32\r
+wl_timer_create_handler(struct wl_timer_params *timer_params)\r
+{\r
+       int ret = 0;\r
+\r
+       TIMER_TRACE("wlan", "Enter\n");\r
+       \r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+       if (!timer_params->timer_workq) {\r
+               timer_params->timer_workq = alloc_workqueue("timerd",\r
+                       WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0);\r
+       }\r
+       if (!timer_params->timer_workq) {\r
+               TIMER_ERROR("wlan", "timer_workq alloc_workqueue failed\n");\r
+               ret = -ENOMEM;\r
+       } else {\r
+               INIT_WORK(&timer_params->timer_work, wl_timer_handler);\r
+       }\r
+#else\r
+       PROC_START(wl_timer_handler, timer_params, &timer_params->thr_timer_ctl, 0, "timerd");\r
+       if (timer_params->thr_timer_ctl.thr_pid < 0) {\r
+               ret = -ENOMEM;\r
+       }\r
+#endif\r
+\r
+       return ret;\r
+}\r
+\r
+static void\r
+wl_timer_destroy_handler(struct wl_timer_params *timer_params)\r
+{\r
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))\r
+       if (timer_params && timer_params->timer_workq) {\r
+               cancel_work_sync(&timer_params->timer_work);\r
+               destroy_workqueue(timer_params->timer_workq);\r
+               timer_params->timer_workq = NULL;\r
+       }\r
+#else\r
+       if (timer_params->thr_timer_ctl.thr_pid >= 0) {\r
+               PROC_STOP(&timer_params->thr_timer_ctl);\r
+       }\r
+#endif\r
+}\r
+\r
+static void\r
+wl_timer_free(struct wl_timer_params *timer_params)\r
+{\r
+       timer_handler_list_t *node, *next;\r
+\r
+       list_for_each_entry_safe(node, next, &timer_params->timer_list, list) {\r
+               TIMER_TRACE(node->net->name, "Free timer\n");\r
+               list_del(&node->list);\r
+               kfree(node);\r
+       }\r
+}\r
+\r
+void\r
+wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms)\r
+{\r
+       wl_timer_params_t *timer_params = dhd->timer_params;\r
+       timer_handler_list_t *node, *next;\r
+       bool found = FALSE;\r
+\r
+       list_for_each_entry_safe(node, next, &timer_params->timer_list, list) {\r
+               if (node->timer == timer) {\r
+                       node->tmo_ms = tmo_ms;\r
+                       if (tmo_ms) {\r
+                               TIMER_TRACE(node->net->name, "update timer %dms\n", tmo_ms);\r
+                               node->tmo_jiffies = jiffies + msecs_to_jiffies(tmo_ms);\r
+                               wl_timer_kick_handler(timer_params);\r
+                       }\r
+                       found = TRUE;\r
+                       break;\r
+               }\r
+       }\r
+       if (!found)\r
+               TIMER_ERROR("wlan", "timer not found\n");\r
+}\r
+\r
+void\r
+wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func)\r
+{\r
+       dhd_pub_t *dhd = dhd_get_pub(net);\r
+       wl_timer_params_t *timer_params = dhd->timer_params;\r
+       timer_handler_list_t *node, *next, *leaf;\r
+\r
+       list_for_each_entry_safe(node, next, &timer_params->timer_list, list) {\r
+               if (node->timer == timer) {\r
+                       TIMER_TRACE(net->name, "timer already registered\n");\r
+                       return;\r
+               }\r
+       }\r
+\r
+       leaf = kmalloc(sizeof(timer_handler_list_t), GFP_KERNEL);\r
+       if (!leaf) {\r
+               TIMER_ERROR(net->name, "Memory alloc failure %d\n",\r
+                       (int)sizeof(timer_handler_list_t));\r
+               return;\r
+       }\r
+       memset(leaf, 0, sizeof(timer_handler_list_t));\r
+       leaf->net = net;\r
+       leaf->timer = timer;\r
+       leaf->cb_func = cb_func;\r
+       leaf->cb_argu = net;\r
+       TIMER_ERROR(net->name, "timer registered tmo=%d\n", leaf->tmo_ms);\r
+       list_add_tail(&leaf->list, &timer_params->timer_list);\r
+\r
+       return;\r
+}\r
+\r
+void\r
+wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer)\r
+{\r
+       dhd_pub_t *dhd = dhd_get_pub(net);\r
+       wl_timer_params_t *timer_params = dhd->timer_params;\r
+       timer_handler_list_t *node, *next;\r
+\r
+       list_for_each_entry_safe(node, next, &timer_params->timer_list, list) {\r
+               if (node->timer == timer) {\r
+                       TIMER_TRACE(net->name, "timer deregistered\n");\r
+                       list_del(&node->list);\r
+                       kfree(node);\r
+               }\r
+       }\r
+       return;\r
+}\r
+\r
+static s32\r
+wl_timer_init_priv(struct wl_timer_params *timer_params)\r
+{\r
+       s32 err = 0;\r
+\r
+       INIT_LIST_HEAD(&timer_params->timer_list);\r
+       if (wl_timer_create_handler(timer_params))\r
+               return -ENOMEM;\r
+       wl_func_init_eq(timer_params);\r
+       if (wl_func_create_handler(timer_params))\r
+               return -ENOMEM;\r
+\r
+       return err;\r
+}\r
+\r
+static void\r
+wl_timer_deinit_priv(struct wl_timer_params *timer_params)\r
+{\r
+       wl_timer_free(timer_params);\r
+       wl_func_destroy_handler(timer_params);\r
+       wl_func_flush_eq(timer_params);\r
+       wl_timer_destroy_handler(timer_params);\r
+}\r
+\r
+void\r
+wl_timer_dettach(dhd_pub_t *dhdp)\r
+{\r
+       struct wl_timer_params *timer_params = dhdp->timer_params;\r
+\r
+       if (timer_params) {\r
+               if (timer_pending(&timer_params->timer))\r
+                       del_timer_sync(&timer_params->timer);\r
+               wl_timer_deinit_priv(timer_params);\r
+               kfree(timer_params);\r
+               dhdp->timer_params = NULL;\r
+       }\r
+}\r
+\r
+s32\r
+wl_timer_attach(struct net_device *net)\r
+{\r
+       struct dhd_pub *dhdp = dhd_get_pub(net);\r
+       struct wl_timer_params *timer_params = NULL;\r
+       s32 err = 0;\r
+\r
+       timer_params = kmalloc(sizeof(wl_timer_params_t), GFP_KERNEL);\r
+       if (!timer_params) {\r
+               TIMER_ERROR(net->name, "Failed to allocate memory (%zu)\n",\r
+                       sizeof(wl_timer_params_t));\r
+               return -ENOMEM;\r
+       }\r
+       dhdp->timer_params = timer_params;\r
+       memset(timer_params, 0, sizeof(wl_timer_params_t));\r
+       timer_params->pub = dhdp;\r
+\r
+       err = wl_timer_init_priv(timer_params);\r
+       if (err) {\r
+               TIMER_ERROR(net->name, "Failed to wl_timer_init_priv (%d)\n", err);\r
+               goto exit;\r
+       }\r
+       init_timer_compat(&timer_params->timer, wl_timer_timeout, timer_params);\r
+\r
+exit:\r
+       if (err)\r
+               wl_timer_dettach(dhdp);\r
+       return err;\r
+}\r
+#else\r
+void\r
+wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms)\r
+{\r
+       if (timer_pending(timer))\r
+               del_timer_sync(timer);\r
+       if (tmo_ms)\r
+               mod_timer(timer, jiffies + msecs_to_jiffies(tmo_ms));\r
+}\r
+\r
+void\r
+wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func)\r
+{\r
+       init_timer_compat(timer, cb_func, net);\r
+}\r
+\r
+void\r
+wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer)\r
+{\r
+       if (timer_pending(timer))\r
+               del_timer_sync(timer);\r
+}\r
+#endif\r
diff --git a/bcmdhd.101.10.361.x/wl_timer.h b/bcmdhd.101.10.361.x/wl_timer.h
new file mode 100755 (executable)
index 0000000..97997f4
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _wl_timer_\r
+#define _wl_timer_\r
+s32 wl_timer_attach(struct net_device *net);\r
+void wl_timer_dettach(dhd_pub_t *dhdp);\r
+void wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func);\r
+void wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer);\r
+void wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms);\r
+#endif\r
index 9cf13d2f0f62c20653f079df5fbf94395ef9e47e..801d332d6ab8b77b6340c3d090ef6f2ba0736d3a 100755 (executable)
@@ -508,30 +508,16 @@ int wldev_get_mode(
 int wldev_set_country(
        struct net_device *dev, char *country_code, bool notify, int revinfo)
 {
+       int error = 0;
 #if defined(BCMDONGLEHOST)
-       int error = -1;
-       wl_country_t cspec = {{0}, 0, {0}};
+       struct dhd_pub *dhd = dhd_get_pub(dev);
 
        if (!country_code)
-               return error;
-
-       cspec.rev = revinfo;
-       strlcpy(cspec.country_abbrev, country_code, WL_CCODE_LEN + 1);
-       strlcpy(cspec.ccode, country_code, WL_CCODE_LEN + 1);
-       error = dhd_conf_map_country_list(dhd_get_pub(dev), &cspec);
-       if (error)
-               dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec);
-       error = dhd_conf_set_country(dhd_get_pub(dev), &cspec);
-       if (error < 0) {
-               WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n",
-                       __FUNCTION__, country_code, cspec.ccode, cspec.rev));
-               return error;
-       }
-       dhd_conf_fix_country(dhd_get_pub(dev));
-       dhd_conf_get_country(dhd_get_pub(dev), &cspec);
-       dhd_bus_country_set(dev, &cspec, notify);
+               return -1;
+       error = dhd_conf_country(dhd, "country", country_code);
+       dhd_bus_country_set(dev, &dhd->dhd_cspec, notify);
        printf("%s: set country for %s as %s rev %d\n",
-               __FUNCTION__, country_code, cspec.ccode, cspec.rev);
+               __FUNCTION__, country_code, dhd->dhd_cspec.ccode, dhd->dhd_cspec.rev);
 #endif /* defined(BCMDONGLEHOST) */
-       return 0;
+       return error;
 }