Source for wifi_rtl8822BS
diff --git a/Kconfig b/Kconfig
new file mode 100644
index 0000000..f6794f1
--- /dev/null
+++ b/Kconfig
@@ -0,0 +1,4 @@
+config RTL8822BS
+	tristate "Realtek 8822B SDIO WiFi"
+	---help---
+	  Help message of RTL8822BS
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..f3b6c3a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2061 @@
+EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS)
+EXTRA_CFLAGS += -O1
+#EXTRA_CFLAGS += -O3
+#EXTRA_CFLAGS += -Wall
+#EXTRA_CFLAGS += -Wextra
+#EXTRA_CFLAGS += -Werror
+#EXTRA_CFLAGS += -pedantic
+#EXTRA_CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes
+
+EXTRA_CFLAGS += -Wno-unused-variable
+EXTRA_CFLAGS += -Wno-unused-value
+EXTRA_CFLAGS += -Wno-unused-label
+EXTRA_CFLAGS += -Wno-unused-parameter
+EXTRA_CFLAGS += -Wno-unused-function
+EXTRA_CFLAGS += -Wno-unused
+#EXTRA_CFLAGS += -Wno-uninitialized
+
+GCC_VER_49 := $(shell echo `$(CC) -dumpversion | cut -f1-2 -d.` \>= 4.9 | bc )
+ifeq ($(GCC_VER_49),1)
+EXTRA_CFLAGS += -Wno-date-time	# Fix compile error && warning on gcc 4.9 and later
+endif
+
+EXTRA_CFLAGS += -I$(src)/include
+
+EXTRA_LDFLAGS += --strip-debug
+
+CONFIG_AUTOCFG_CP = n
+
+########################## WIFI IC ############################
+CONFIG_MULTIDRV = n
+CONFIG_RTL8188E = n
+CONFIG_RTL8812A = n
+CONFIG_RTL8821A = n
+CONFIG_RTL8192E = n
+CONFIG_RTL8723B = n
+CONFIG_RTL8814A = n
+CONFIG_RTL8723C = n
+CONFIG_RTL8188F = n
+CONFIG_RTL8822B = y
+CONFIG_RTL8723D = n
+CONFIG_RTL8821C = n
+######################### Interface ###########################
+CONFIG_USB_HCI = n
+CONFIG_PCI_HCI = n
+CONFIG_SDIO_HCI = y
+CONFIG_GSPI_HCI = n
+########################## Features ###########################
+CONFIG_MP_INCLUDED = y
+CONFIG_POWER_SAVING = y
+CONFIG_USB_AUTOSUSPEND = n
+CONFIG_HW_PWRP_DETECTION = n
+CONFIG_WIFI_TEST = n
+CONFIG_BT_COEXIST = y
+CONFIG_INTEL_WIDI = n
+CONFIG_WAPI_SUPPORT = n
+CONFIG_EFUSE_CONFIG_FILE = y
+CONFIG_EXT_CLK = n
+CONFIG_TRAFFIC_PROTECT = n
+CONFIG_LOAD_PHY_PARA_FROM_FILE = y
+CONFIG_TXPWR_BY_RATE_EN = y
+CONFIG_TXPWR_LIMIT_EN = n
+CONFIG_RTW_CHPLAN = 0xFF
+CONFIG_RTW_ADAPTIVITY_EN = disable
+CONFIG_RTW_ADAPTIVITY_MODE = normal
+CONFIG_SIGNAL_SCALE_MAPPING = n
+CONFIG_80211W = n
+CONFIG_REDUCE_TX_CPU_LOADING = n
+CONFIG_BR_EXT = y
+CONFIG_TDLS = n
+CONFIG_WIFI_MONITOR = n
+CONFIG_MCC_MODE = n
+CONFIG_APPEND_VENDOR_IE_ENABLE = n
+CONFIG_RTW_NAPI = y
+CONFIG_RTW_GRO = y
+CONFIG_RTW_NETIF_SG = y
+# Enable VHT rate on 2.4G channel or not
+CONFIG_RTW_VHT_2G4 = y
+CONFIG_RTW_IPCAM_APPLICATION = n
+CONFIG_RTW_REPEATER_SON = n
+CONFIG_RTW_WIFI_HAL = y
+CONFIG_IP_R_Monitor = y #arp VOQ and high rate
+########################## Debug ###########################
+CONFIG_RTW_DEBUG = y
+# default log level is _DRV_INFO_ = 4,
+# please refer to "How_to_set_driver_debug_log_level.doc" to set the available level.
+CONFIG_RTW_LOG_LEVEL = 2
+######################## Wake On Lan ##########################
+CONFIG_WOWLAN = n
+CONFIG_WAKEUP_TYPE = 0x7 #bit2: deauth, bit1: unicast, bit0: magic pkt.
+CONFIG_GPIO_WAKEUP = n
+CONFIG_WAKEUP_GPIO_IDX = default
+CONFIG_HIGH_ACTIVE = n
+CONFIG_PNO_SUPPORT = n
+CONFIG_PNO_SET_DEBUG = n
+CONFIG_AP_WOWLAN = n
+######### Notify SDIO Host Keep Power During Syspend ##########
+CONFIG_RTW_SDIO_PM_KEEP_POWER = y
+###################### MP HW TX MODE FOR VHT #######################
+CONFIG_MP_VHT_HW_TX_MODE = n
+###################### Platform Related #######################
+CONFIG_PLATFORM_I386_PC = n
+CONFIG_PLATFORM_ANDROID_X86 = n
+CONFIG_PLATFORM_ANDROID_INTEL_X86 = n
+CONFIG_PLATFORM_JB_X86 = n
+CONFIG_PLATFORM_ARM_S3C2K4 = n
+CONFIG_PLATFORM_ARM_PXA2XX = n
+CONFIG_PLATFORM_ARM_S3C6K4 = n
+CONFIG_PLATFORM_MIPS_RMI = n
+CONFIG_PLATFORM_RTD2880B = n
+CONFIG_PLATFORM_MIPS_AR9132 = n
+CONFIG_PLATFORM_RTK_DMP = n
+CONFIG_PLATFORM_MIPS_PLM = n
+CONFIG_PLATFORM_MSTAR389 = n
+CONFIG_PLATFORM_MT53XX = n
+CONFIG_PLATFORM_ARM_MX51_241H = n
+CONFIG_PLATFORM_FS_MX61 = n
+CONFIG_PLATFORM_ACTIONS_ATJ227X = n
+CONFIG_PLATFORM_TEGRA3_CARDHU = n
+CONFIG_PLATFORM_TEGRA4_DALMORE = n
+CONFIG_PLATFORM_ARM_TCC8900 = n
+CONFIG_PLATFORM_ARM_TCC8920 = n
+CONFIG_PLATFORM_ARM_TCC8920_JB42 = n
+CONFIG_PLATFORM_ARM_TCC8930_JB42 = n
+CONFIG_PLATFORM_ARM_RK2818 = n
+CONFIG_PLATFORM_ARM_RK3066 = n
+CONFIG_PLATFORM_ARM_RK3188 = n
+CONFIG_PLATFORM_ARM_URBETTER = n
+CONFIG_PLATFORM_ARM_TI_PANDA = n
+CONFIG_PLATFORM_MIPS_JZ4760 = n
+CONFIG_PLATFORM_DMP_PHILIPS = n
+CONFIG_PLATFORM_MSTAR_TITANIA12 = n
+CONFIG_PLATFORM_MSTAR = n
+CONFIG_PLATFORM_SZEBOOK = n
+CONFIG_PLATFORM_ARM_SUNxI = n
+CONFIG_PLATFORM_ARM_SUN6I = n
+CONFIG_PLATFORM_ARM_SUN7I = n
+CONFIG_PLATFORM_ARM_SUN8I_W3P1 = n
+CONFIG_PLATFORM_ARM_SUN8I_W5P1 = n
+CONFIG_PLATFORM_ACTIONS_ATM702X = n
+CONFIG_PLATFORM_ACTIONS_ATV5201 = n
+CONFIG_PLATFORM_ACTIONS_ATM705X = n
+CONFIG_PLATFORM_ARM_SUN50IW1P1 = n
+CONFIG_PLATFORM_ARM_RTD299X = n
+CONFIG_PLATFORM_ARM_SPREADTRUM_6820 = n
+CONFIG_PLATFORM_ARM_SPREADTRUM_8810 = n
+CONFIG_PLATFORM_AML_S905 = y
+CONFIG_PLATFORM_ARM_WMT = n
+CONFIG_PLATFORM_TI_DM365 = n
+CONFIG_PLATFORM_MOZART = n
+CONFIG_PLATFORM_RTK119X = n
+CONFIG_PLATFORM_RTK129X = n
+CONFIG_PLATFORM_NOVATEK_NT72668 = n
+CONFIG_PLATFORM_HISILICON = n
+CONFIG_PLATFORM_HISILICON_HI3798 = n
+CONFIG_PLATFORM_NV_TK1 = n
+CONFIG_PLATFORM_RTL8197D = n
+CONFIG_PLATFORM_ZTE_ZX296716 = n
+###############################################################
+
+CONFIG_DRVEXT_MODULE = n
+
+export TopDIR ?= $(shell pwd)
+
+########### COMMON  #################################
+ifeq ($(CONFIG_GSPI_HCI), y)
+HCI_NAME = gspi
+endif
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+HCI_NAME = sdio
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+HCI_NAME = usb
+endif
+
+ifeq ($(CONFIG_PCI_HCI), y)
+HCI_NAME = pci
+endif
+
+
+_OS_INTFS_FILES :=	os_dep/osdep_service.o \
+			os_dep/linux/os_intfs.o \
+			os_dep/linux/$(HCI_NAME)_intf.o \
+			os_dep/linux/$(HCI_NAME)_ops_linux.o \
+			os_dep/linux/ioctl_linux.o \
+			os_dep/linux/xmit_linux.o \
+			os_dep/linux/mlme_linux.o \
+			os_dep/linux/recv_linux.o \
+			os_dep/linux/ioctl_cfg80211.o \
+			os_dep/linux/rtw_cfgvendor.o \
+			os_dep/linux/wifi_regd.o \
+			os_dep/linux/rtw_android.o \
+			os_dep/linux/rtw_proc.o
+
+ifeq ($(CONFIG_MP_INCLUDED), y)
+_OS_INTFS_FILES += os_dep/linux/ioctl_mp.o
+endif
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o
+_OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o
+endif
+
+ifeq ($(CONFIG_GSPI_HCI), y)
+_OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o
+_OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o
+endif
+
+
+_HAL_INTFS_FILES :=	hal/hal_intf.o \
+			hal/hal_com.o \
+			hal/hal_com_phycfg.o \
+			hal/hal_phy.o \
+			hal/hal_dm.o \
+			hal/hal_dm_acs.o \
+			hal/hal_btcoex_wifionly.o \
+			hal/hal_btcoex.o \
+			hal/hal_mp.o \
+			hal/hal_mcc.o \
+			hal/hal_hci/hal_$(HCI_NAME).o \
+			hal/led/hal_$(HCI_NAME)_led.o
+
+
+EXTRA_CFLAGS += -I$(src)/platform
+_PLATFORM_FILES := platform/platform_ops.o
+
+EXTRA_CFLAGS += -I$(src)/hal/btc
+
+########### HAL_RTL8188E #################################
+ifeq ($(CONFIG_RTL8188E), y)
+
+RTL871X = rtl8188e
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8189es
+endif
+
+ifeq ($(CONFIG_GSPI_HCI), y)
+MODULE_NAME = 8189es
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8188eu
+endif
+
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8188ee
+endif
+EXTRA_CFLAGS += -DCONFIG_RTL8188E
+
+_HAL_INTFS_FILES +=	hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8188EPwrSeq.o\
+ 					hal/$(RTL871X)/$(RTL871X)_xmit.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/hal8188e_s_fw.o \
+			hal/$(RTL871X)/hal8188e_t_fw.o \
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+ifeq ($(CONFIG_GSPI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+endif
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_PCIE.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_SDIO.o
+endif
+
+endif
+
+########### HAL_RTL8192E #################################
+ifeq ($(CONFIG_RTL8192E), y)
+
+RTL871X = rtl8192e
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8192es
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8192eu
+endif
+
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8192ee
+endif
+EXTRA_CFLAGS += -DCONFIG_RTL8192E
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8192EPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_xmit.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/hal8192e_fw.o \
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+ifeq ($(CONFIG_GSPI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+endif
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8192E_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8192E_PCIE.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8192E_SDIO.o
+endif
+
+ifeq ($(CONFIG_BT_COEXIST), y)
+_BTC_FILES += hal/btc/halbtc8192e1ant.o \
+				hal/btc/halbtc8192e2ant.o
+endif
+
+endif
+
+########### HAL_RTL8812A_RTL8821A #################################
+
+ifneq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A), n_n)
+
+RTL871X = rtl8812a
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8812au
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8812ae
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8812as
+endif
+
+_HAL_INTFS_FILES +=  hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8812PwrSeq.o \
+					hal/$(RTL871X)/Hal8821APwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_xmit.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+ifeq ($(CONFIG_GSPI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+endif
+endif
+
+ifeq ($(CONFIG_RTL8812A), y)
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_PCIE.o
+endif
+endif
+ifeq ($(CONFIG_RTL8821A), y)
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_PCIE.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_SDIO.o
+endif
+endif
+
+ifeq ($(CONFIG_RTL8812A), y)
+EXTRA_CFLAGS += -DCONFIG_RTL8812A
+_HAL_INTFS_FILES +=	hal/rtl8812a/hal8812a_fw.o
+endif
+
+ifeq ($(CONFIG_RTL8821A), y)
+
+ifeq ($(CONFIG_RTL8812A), n)
+
+RTL871X = rtl8821a
+ifeq ($(CONFIG_USB_HCI), y)
+ifeq ($(CONFIG_BT_COEXIST), y)
+MODULE_NAME := 8821au
+else
+MODULE_NAME := 8811au
+endif
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME := 8821ae
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME := 8821as
+endif
+
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8821A
+
+_HAL_INTFS_FILES +=	hal/rtl8812a/hal8821a_fw.o
+		
+endif
+
+ifeq ($(CONFIG_BT_COEXIST), y)
+ifeq ($(CONFIG_RTL8812A), y)
+_BTC_FILES += hal/btc/halbtc8812a1ant.o \
+				hal/btc/halbtc8812a2ant.o
+endif
+ifeq ($(CONFIG_RTL8821A), y)
+_BTC_FILES += hal/btc/halbtc8821a1ant.o \
+				hal/btc/halbtc8821a2ant.o
+endif
+endif
+
+endif
+
+########### HAL_RTL8723B #################################
+ifeq ($(CONFIG_RTL8723B), y)
+
+RTL871X = rtl8723b
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8723bu
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8723be
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8723bs
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8723B
+
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8723BPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/hal8723b_fw.o
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_PCIE.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_SDIO.o
+endif
+
+_BTC_FILES += hal/btc/halbtc8723bwifionly.o
+ifeq ($(CONFIG_BT_COEXIST), y)
+_BTC_FILES += hal/btc/halbtc8723b1ant.o \
+				hal/btc/halbtc8723b2ant.o
+endif
+
+endif
+
+########### HAL_RTL8814A #################################
+ifeq ($(CONFIG_RTL8814A), y)
+## ADD NEW VHT MP HW TX MODE ##
+#EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE
+#CONFIG_MP_VHT_HW_TX_MODE = y
+##########################################
+RTL871X = rtl8814a
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8814au
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8814ae
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8814as
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8814A
+
+_HAL_INTFS_FILES +=  hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8814PwrSeq.o \
+					hal/$(RTL871X)/$(RTL871X)_xmit.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/hal8814a_fw.o
+
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+ifeq ($(CONFIG_GSPI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+endif
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_PCIE.o
+endif
+
+endif
+
+########### HAL_RTL8723C #################################
+ifeq ($(CONFIG_RTL8723C), y)
+
+RTL871X = rtl8703b
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8723cu
+MODULE_SUB_NAME = 8703bu
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8723ce
+MODULE_SUB_NAME = 8703be
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8723cs
+MODULE_SUB_NAME = 8703bs
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8703B
+
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8703BPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/hal8703b_fw.o
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o
+
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_PCIE.o
+endif
+
+ifeq ($(CONFIG_BT_COEXIST), y)
+_BTC_FILES += hal/btc/halbtc8703b1ant.o
+endif
+
+endif
+
+########### HAL_RTL8723D #################################
+ifeq ($(CONFIG_RTL8723D), y)
+
+RTL871X = rtl8723d
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8723du
+MODULE_SUB_NAME = 8723du
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8723de
+MODULE_SUB_NAME = 8723de
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8723ds
+MODULE_SUB_NAME = 8723ds
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8723D
+
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8723DPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/hal8723d_fw.o \
+			hal/$(RTL871X)/$(RTL871X)_lps_poff.o
+
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o
+
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_PCIE.o
+endif
+
+ifeq ($(CONFIG_BT_COEXIST), y)
+_BTC_FILES += hal/btc/halbtc8723d1ant.o \
+				hal/btc/halbtc8723d2ant.o
+endif
+
+endif
+
+########### HAL_RTL8188F #################################
+ifeq ($(CONFIG_RTL8188F), y)
+
+RTL871X = rtl8188f
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8188fu
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8188fe
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8189fs
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8188F
+
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8188FPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/hal8188f_fw.o
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_USB.o
+endif
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_SDIO.o
+endif
+
+endif
+
+########### HAL_RTL8822B #################################
+ifeq ($(CONFIG_RTL8822B), y)
+RTL871X := rtl8822b
+ifeq ($(CONFIG_USB_HCI), y)
+ifeq ($(CONFIG_BT_COEXIST), n)
+MODULE_NAME = 8812bu
+else
+MODULE_NAME = 88x2bu
+endif
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 88x2be
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8822bs
+endif
+
+endif
+########### HAL_RTL8821C #################################
+ifeq ($(CONFIG_RTL8821C), y)
+RTL871X := rtl8821c
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8821cu
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8821ce
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8821cs
+endif
+
+endif
+########### AUTO_CFG  #################################
+
+ifeq ($(CONFIG_AUTOCFG_CP), y)
+
+ifeq ($(CONFIG_MULTIDRV), y)
+$(shell cp $(TopDIR)/autoconf_multidrv_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h)
+else
+ifeq ($(CONFIG_RTL8188E)$(CONFIG_SDIO_HCI),yy)
+$(shell cp $(TopDIR)/autoconf_rtl8189e_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h)
+else ifeq ($(CONFIG_RTL8188F)$(CONFIG_SDIO_HCI),yy)
+$(shell cp $(TopDIR)/autoconf_rtl8189f_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h)
+else ifeq ($(CONFIG_RTL8723C),y)
+$(shell cp $(TopDIR)/autoconf_rtl8723c_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h)
+else
+$(shell cp $(TopDIR)/autoconf_$(RTL871X)_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h)
+endif
+endif
+
+endif
+
+########### END OF PATH  #################################
+
+ifeq ($(CONFIG_USB_HCI), y)
+ifeq ($(CONFIG_USB_AUTOSUSPEND), y)
+EXTRA_CFLAGS += -DCONFIG_USB_AUTOSUSPEND
+endif
+endif
+
+ifeq ($(CONFIG_MP_INCLUDED), y)
+#MODULE_NAME := $(MODULE_NAME)_mp
+EXTRA_CFLAGS += -DCONFIG_MP_INCLUDED
+endif
+
+ifeq ($(CONFIG_POWER_SAVING), y)
+EXTRA_CFLAGS += -DCONFIG_POWER_SAVING
+endif
+
+ifeq ($(CONFIG_HW_PWRP_DETECTION), y)
+EXTRA_CFLAGS += -DCONFIG_HW_PWRP_DETECTION
+endif
+
+ifeq ($(CONFIG_WIFI_TEST), y)
+EXTRA_CFLAGS += -DCONFIG_WIFI_TEST
+endif
+
+ifeq ($(CONFIG_BT_COEXIST), y)
+EXTRA_CFLAGS += -DCONFIG_BT_COEXIST
+endif
+
+ifeq ($(CONFIG_INTEL_WIDI), y)
+EXTRA_CFLAGS += -DCONFIG_INTEL_WIDI
+endif
+
+ifeq ($(CONFIG_WAPI_SUPPORT), y)
+EXTRA_CFLAGS += -DCONFIG_WAPI_SUPPORT
+endif
+
+
+ifeq ($(CONFIG_EFUSE_CONFIG_FILE), y)
+EXTRA_CFLAGS += -DCONFIG_EFUSE_CONFIG_FILE
+
+#EFUSE_MAP_PATH
+USER_EFUSE_MAP_PATH ?=
+ifneq ($(USER_EFUSE_MAP_PATH),)
+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"$(USER_EFUSE_MAP_PATH)\"
+else ifeq ($(MODULE_NAME), 8189es)
+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8189e.map\"
+else ifeq ($(MODULE_NAME), 8723bs)
+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8723bs.map\"
+else
+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_$(MODULE_NAME).map\"
+endif
+
+#WIFIMAC_PATH
+USER_WIFIMAC_PATH ?=
+ifneq ($(USER_WIFIMAC_PATH),)
+EXTRA_CFLAGS += -DWIFIMAC_PATH=\"$(USER_WIFIMAC_PATH)\"
+else
+EXTRA_CFLAGS += -DWIFIMAC_PATH=\"/data/wifimac.txt\"
+endif
+
+endif
+
+ifeq ($(CONFIG_EXT_CLK), y)
+EXTRA_CFLAGS += -DCONFIG_EXT_CLK
+endif
+
+ifeq ($(CONFIG_TRAFFIC_PROTECT), y)
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+endif
+
+ifeq ($(CONFIG_LOAD_PHY_PARA_FROM_FILE), y)
+EXTRA_CFLAGS += -DCONFIG_LOAD_PHY_PARA_FROM_FILE
+#EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH_WITH_IC_NAME_FOLDER
+EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"/lib/firmware/\"
+endif
+
+ifeq ($(CONFIG_TXPWR_BY_RATE_EN), n)
+EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=0
+else ifeq ($(CONFIG_TXPWR_BY_RATE_EN), y)
+EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=1
+else ifeq ($(CONFIG_TXPWR_BY_RATE_EN), auto)
+EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=2
+endif
+
+ifeq ($(CONFIG_TXPWR_LIMIT_EN), n)
+EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=0
+else ifeq ($(CONFIG_TXPWR_LIMIT_EN), y)
+EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=1
+else ifeq ($(CONFIG_TXPWR_LIMIT_EN), auto)
+EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=2
+endif
+
+ifneq ($(CONFIG_RTW_CHPLAN), 0xFF)
+EXTRA_CFLAGS += -DCONFIG_RTW_CHPLAN=$(CONFIG_RTW_CHPLAN)
+endif
+
+ifeq ($(CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY), y)
+EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_BY_REGULATORY
+endif
+
+ifeq ($(CONFIG_CALIBRATE_TX_POWER_TO_MAX), y)
+EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_TO_MAX
+endif
+
+ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), disable)
+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=0
+else ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), enable)
+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=1
+endif
+
+ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), normal)
+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=0
+else ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), carrier_sense)
+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=1
+endif
+
+ifeq ($(CONFIG_SIGNAL_SCALE_MAPPING), y)
+EXTRA_CFLAGS += -DCONFIG_SIGNAL_SCALE_MAPPING
+endif
+
+ifeq ($(CONFIG_80211W), y)
+EXTRA_CFLAGS += -DCONFIG_IEEE80211W
+endif
+
+ifeq ($(CONFIG_WOWLAN), y)
+EXTRA_CFLAGS += -DCONFIG_WOWLAN -DRTW_WAKEUP_EVENT=$(CONFIG_WAKEUP_TYPE)
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER
+endif
+endif
+
+ifeq ($(CONFIG_AP_WOWLAN), y)
+EXTRA_CFLAGS += -DCONFIG_AP_WOWLAN
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER
+endif
+endif
+
+ifeq ($(CONFIG_PNO_SUPPORT), y)
+EXTRA_CFLAGS += -DCONFIG_PNO_SUPPORT
+ifeq ($(CONFIG_PNO_SET_DEBUG), y)
+EXTRA_CFLAGS += -DCONFIG_PNO_SET_DEBUG
+endif
+endif
+
+ifeq ($(CONFIG_GPIO_WAKEUP), y)
+EXTRA_CFLAGS += -DCONFIG_GPIO_WAKEUP
+ifeq ($(CONFIG_HIGH_ACTIVE), y)
+EXTRA_CFLAGS += -DHIGH_ACTIVE=1
+else
+EXTRA_CFLAGS += -DHIGH_ACTIVE=0
+endif
+endif
+
+ifneq ($(CONFIG_WAKEUP_GPIO_IDX), default)
+EXTRA_CFLAGS += -DWAKEUP_GPIO_IDX=$(CONFIG_WAKEUP_GPIO_IDX)
+endif
+
+ifeq ($(CONFIG_RTW_SDIO_PM_KEEP_POWER), y)
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER
+endif
+endif
+
+ifeq ($(CONFIG_REDUCE_TX_CPU_LOADING), y)
+EXTRA_CFLAGS += -DCONFIG_REDUCE_TX_CPU_LOADING
+endif
+
+ifeq ($(CONFIG_BR_EXT), y)
+BR_NAME = br0
+EXTRA_CFLAGS += -DCONFIG_BR_EXT
+EXTRA_CFLAGS += '-DCONFIG_BR_EXT_BRNAME="'$(BR_NAME)'"'
+endif
+
+
+ifeq ($(CONFIG_TDLS), y)
+EXTRA_CFLAGS += -DCONFIG_TDLS
+endif
+
+ifeq ($(CONFIG_WIFI_MONITOR), y)
+EXTRA_CFLAGS += -DCONFIG_WIFI_MONITOR
+endif
+
+ifeq ($(CONFIG_MCC_MODE), y)
+EXTRA_CFLAGS += -DCONFIG_MCC_MODE
+endif
+
+ifeq ($(CONFIG_RTW_NAPI), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_NAPI
+endif
+
+ifeq ($(CONFIG_RTW_GRO), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_GRO
+endif
+
+ifeq ($(CONFIG_RTW_REPEATER_SON), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_REPEATER_SON
+endif
+
+ifeq ($(CONFIG_RTW_IPCAM_APPLICATION), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_IPCAM_APPLICATION
+ifeq ($(CONFIG_WIFI_MONITOR), n)
+EXTRA_CFLAGS += -DCONFIG_WIFI_MONITOR
+endif
+endif
+
+ifeq ($(CONFIG_RTW_NETIF_SG), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_NETIF_SG
+endif
+
+ifeq ($(CONFIG_RTW_VHT_2G4), y)
+EXTRA_CFLAGS += -DRTW_VHT_2G4=1
+else
+EXTRA_CFLAGS += -DRTW_VHT_2G4=0
+endif
+
+ifeq ($(CONFIG_RTW_WIFI_HAL), y)
+#EXTRA_CFLAGS += -DCONFIG_RTW_WIFI_HAL_DEBUG
+EXTRA_CFLAGS += -DCONFIG_RTW_WIFI_HAL
+EXTRA_CFLAGS += -DCONFIG_RTW_CFGVEDNOR_LLSTATS
+endif
+
+ifeq ($(CONFIG_IP_R_Monitor), y)
+EXTRA_CFLAGS += -DCONFIG_IP_R_Monitor
+endif
+
+ifeq ($(CONFIG_MP_VHT_HW_TX_MODE), y)
+EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE
+ifeq ($(CONFIG_PLATFORM_I386_PC), y)
+## For I386 X86 ToolChain use Hardware FLOATING
+EXTRA_CFLAGS += -mhard-float
+else
+## For ARM ToolChain use Hardware FLOATING
+EXTRA_CFLAGS += -mfloat-abi=hard
+endif
+endif
+
+ifeq ($(CONFIG_APPEND_VENDOR_IE_ENABLE), y)
+EXTRA_CFLAGS += -DCONFIG_APPEND_VENDOR_IE_ENABLE
+endif
+
+ifeq ($(CONFIG_RTW_DEBUG), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_DEBUG
+EXTRA_CFLAGS += -DRTW_LOG_LEVEL=$(CONFIG_RTW_LOG_LEVEL)
+endif
+
+EXTRA_CFLAGS += -DDM_ODM_SUPPORT_TYPE=0x04
+
+ifeq ($(CONFIG_PLATFORM_I386_PC), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/)
+ARCH ?= $(SUBARCH)
+CROSS_COMPILE ?=
+KVER  := $(shell uname -r)
+KSRC := /lib/modules/$(KVER)/build
+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/
+INSTALL_PREFIX :=
+STAGINGMODDIR := /lib/modules/$(KVER)/kernel/drivers/staging
+endif
+
+ifeq ($(CONFIG_PLATFORM_NV_TK1), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_NV_TK1
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+#EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+
+# Default setting for Android
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ANDROID
+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+# Enable these for Android 4.1, 4.2 and later
+# Enable these for Android 5.0 and later
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+EXTRA_CFLAGS += -DRTW_VENDOR_EXT_SUPPORT
+
+ARCH ?= arm
+
+# for ubuntu environment
+#CROSS_COMPILE ?=
+#KVER := $(shell uname -r)
+#KSRC := /lib/modules/$(KVER)/build
+#MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/
+#INSTALL_PREFIX :=
+
+# for Android
+CROSS_COMPILE ?= /mnt/newdisk/android_sdk/nvidia_tk1/android_L/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
+KSRC ?=/mnt/newdisk/android_sdk/nvidia_tk1/android_L/out/target/product/shieldtablet/obj/KERNEL/
+USER_MODULE_NAME := wlan
+
+endif
+
+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM702X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ACTIONS_ATM702X
+#ARCH := arm
+ARCH := $(R_ARCH)
+#CROSS_COMPILE := arm-none-linux-gnueabi-
+CROSS_COMPILE := $(R_CROSS_COMPILE)
+KVER:= 3.4.0
+#KSRC := ../../../../build/out/kernel
+KSRC := $(KERNEL_BUILD_PATH)
+MODULE_NAME :=wlan
+endif
+
+
+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM705X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+#EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+# default setting for Android 4.1, 4.2, 4.3, 4.4
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ACTIONS_ATM705X
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+
+# Enable this for Android 5.0
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+_PLATFORM_FILES += platform/platform_arm_act_sdio.o
+endif
+
+ARCH := arm
+CROSS_COMPILE := /opt/arm-2011.09/bin/arm-none-linux-gnueabi-
+KSRC := /home/android_sdk/Action-semi/705a_android_L/android/kernel
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUN50IW1P1), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN50IW1P1
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+
+# Enable this for Android 5.0
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_SUN50IW1P1_sdio.o
+endif
+
+ARCH := arm64
+# ===Cross compile setting for Android 5.1(64) SDK ===
+CROSS_COMPILE := /home/android_sdk/Allwinner/a64/android-51/lichee/out/sun50iw1p1/android/common/buildroot/external-toolchain/bin/aarch64-linux-gnu-
+KSRC :=/home/android_sdk/Allwinner/a64/android-51/lichee/linux-3.10/
+endif
+
+ifeq ($(CONFIG_PLATFORM_TI_AM3517), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_SHUTTLE
+CROSS_COMPILE := arm-eabi-
+KSRC := $(shell pwd)/../../../Android/kernel
+ARCH := arm
+endif
+
+ifeq ($(CONFIG_PLATFORM_MSTAR_TITANIA12), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_PLATFORM_MSTAR_TITANIA12
+ARCH:=mips
+CROSS_COMPILE:= /usr/src/Mstar_kernel/mips-4.3/bin/mips-linux-gnu-
+KVER:= 2.6.28.9
+KSRC:= /usr/src/Mstar_kernel/2.6.28.9/
+endif
+
+ifeq ($(CONFIG_PLATFORM_MSTAR), y)
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR_HIGH
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX -DCONFIG_FIX_NR_BULKIN_BUFFER
+endif
+ARCH:=arm
+CROSS_COMPILE:= /usr/src/bin/arm-none-linux-gnueabi-
+KVER:= 3.1.10
+KSRC:= /usr/src/Mstar_kernel/3.1.10/
+endif
+
+ifeq ($(CONFIG_PLATFORM_ANDROID_X86), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/)
+ARCH := $(SUBARCH)
+CROSS_COMPILE := /media/DATA-2/android-x86/ics-x86_20120130/prebuilt/linux-x86/toolchain/i686-unknown-linux-gnu-4.2.1/bin/i686-unknown-linux-gnu-
+KSRC := /media/DATA-2/android-x86/ics-x86_20120130/out/target/product/generic_x86/obj/kernel
+MODULE_NAME :=wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ANDROID_INTEL_X86), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ANDROID_INTEL_X86
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_INTEL_BYT
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_SKIP_SIGNAL_SCALE_MAPPING
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE
+endif
+endif
+
+ifeq ($(CONFIG_PLATFORM_JB_X86), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/)
+ARCH := $(SUBARCH)
+CROSS_COMPILE := /home/android_sdk/android-x86_JB/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7/bin/i686-linux-android-
+KSRC := /home/android_sdk/android-x86_JB/out/target/product/x86/obj/kernel/
+MODULE_NAME :=wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_PXA2XX), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := arm-none-linux-gnueabi-
+KVER  := 2.6.34.1
+KSRC ?= /usr/src/linux-2.6.34.1
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_S3C2K4), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := arm-linux-
+KVER  := 2.6.24.7_$(ARCH)
+KSRC := /usr/src/kernels/linux-$(KVER)
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_S3C6K4), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := arm-none-linux-gnueabi-
+KVER  := 2.6.34.1
+KSRC ?= /usr/src/linux-2.6.34.1
+endif
+
+ifeq ($(CONFIG_PLATFORM_RTD2880B), y)
+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -DCONFIG_PLATFORM_RTD2880B
+ARCH:=
+CROSS_COMPILE:=
+KVER:=
+KSRC:=
+endif
+
+ifeq ($(CONFIG_PLATFORM_MIPS_RMI), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH:=mips
+CROSS_COMPILE:=mipsisa32r2-uclibc-
+KVER:=
+KSRC:= /root/work/kernel_realtek
+endif
+
+ifeq ($(CONFIG_PLATFORM_MIPS_PLM), y)
+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN
+ARCH:=mips
+CROSS_COMPILE:=mipsisa32r2-uclibc-
+KVER:=
+KSRC:= /root/work/kernel_realtek
+endif
+
+ifeq ($(CONFIG_PLATFORM_MSTAR389), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR389
+ARCH:=mips
+CROSS_COMPILE:= mips-linux-gnu-
+KVER:= 2.6.28.10
+KSRC:= /home/mstar/mstar_linux/2.6.28.9/
+endif
+
+ifeq ($(CONFIG_PLATFORM_MIPS_AR9132), y)
+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN
+ARCH := mips
+CROSS_COMPILE := mips-openwrt-linux-
+KSRC := /home/alex/test_openwrt/tmp/linux-2.6.30.9
+endif
+
+ifeq ($(CONFIG_PLATFORM_DMP_PHILIPS), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM
+ARCH := mips
+#CROSS_COMPILE:=/usr/local/msdk-4.3.6-mips-EL-2.6.12.6-0.9.30.3/bin/mipsel-linux-
+CROSS_COMPILE:=/usr/local/toolchain_mipsel/bin/mipsel-linux-
+KSRC ?=/usr/local/Jupiter/linux-2.6.12
+endif
+
+ifeq ($(CONFIG_PLATFORM_RTK_DMP), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM  -DCONFIG_WIRELESS_EXT
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+_PLATFORM_FILES += platform/platform_RTK_DMP_usb.o
+endif
+ARCH:=mips
+CROSS_COMPILE:=mipsel-linux-
+KVER:=
+KSRC ?= /usr/src/DMP_Kernel/jupiter/linux-2.6.12
+endif
+
+ifeq ($(CONFIG_PLATFORM_MT53XX), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MT53XX
+ARCH:= arm
+CROSS_COMPILE:= arm11_mtk_le-
+KVER:= 2.6.27
+KSRC?= /proj/mtk00802/BD_Compare/BDP/Dev/BDP_V301/BDP_Linux/linux-2.6.27
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_MX51_241H), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_WISTRON_PLATFORM
+ARCH := arm
+CROSS_COMPILE := /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-
+KVER  := 2.6.31
+KSRC ?= /lib/modules/2.6.31-770-g0e46b52/source
+endif
+
+ifeq ($(CONFIG_PLATFORM_FS_MX61), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := /home/share/CusEnv/FreeScale/arm-eabi-4.4.3/bin/arm-eabi-
+KSRC ?= /home/share/CusEnv/FreeScale/FS_kernel_env
+endif
+
+
+
+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATJ227X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATJ227X
+ARCH := mips
+CROSS_COMPILE := /home/cnsd4/project/actions/tools-2.6.27/bin/mipsel-linux-gnu-
+KVER  := 2.6.27
+KSRC := /home/cnsd4/project/actions/linux-2.6.27.28
+endif
+
+ifeq ($(CONFIG_PLATFORM_TI_DM365), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_TI_DM365
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX
+EXTRA_CFLAGS += -DCONFIG_SINGLE_XMIT_BUF -DCONFIG_SINGLE_RECV_BUF
+ARCH := arm
+#CROSS_COMPILE := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-
+#KSRC := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/lsp/ti-davinci/linux-dm365
+CROSS_COMPILE := /opt/montavista/pro5.0/devkit/arm/v5t_le/bin/arm-linux-
+KSRC:= /home/vivotek/lsp/DM365/kernel_platform/kernel/linux-2.6.18
+KERNELOUTPUT := ${PRODUCTDIR}/tmp
+KVER  := 2.6.18
+endif
+
+ifeq ($(CONFIG_PLATFORM_MOZART), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MOZART
+ARCH := arm
+CROSS_COMPILE := /home/vivotek/lsp/mozart3v2/Mozart3e_Toolchain/build_arm_nofpu/usr/bin/arm-linux-
+KVER  := $(shell uname -r)
+KSRC:= /opt/Vivotek/lsp/mozart3v2/kernel_platform/kernel/mozart_kernel-1.17
+KERNELOUTPUT := /home/pink/sample/ODM/IP8136W-VINT/tmp/kernel
+endif
+
+ifeq ($(CONFIG_PLATFORM_TEGRA3_CARDHU), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+KSRC := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/out/target/product/cardhu/obj/KERNEL
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_TEGRA4_DALMORE), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
+KSRC := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/out/target/product/dalmore/obj/KERNEL
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_TCC8900), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Telechips/SDK_2304_20110613/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+KSRC := /home/android_sdk/Telechips/SDK_2304_20110613/kernel
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_TCC8920), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+KSRC := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/kernel
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_TCC8920_JB42), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
+KSRC := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/kernel
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_RK2818), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS
+ARCH := arm
+CROSS_COMPILE := /usr/src/release_fae_version/toolchain/arm-eabi-4.4.0/bin/arm-eabi-
+KSRC := /usr/src/release_fae_version/kernel25_A7_281x
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_RK3188), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS
+# default setting for Android 4.1, 4.2, 4.3, 4.4
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+# default setting for Power control
+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN
+# default setting for Special function
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3188/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
+KSRC := /home/android_sdk/Rockchip/Rk3188/kernel
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_RK3066), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_RK3066
+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN
+endif
+EXTRA_CFLAGS += -fno-pic
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Rockchip/rk3066_20130607/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi-
+#CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3066sdk/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi-
+KSRC := /home/android_sdk/Rockchip/Rk3066sdk/kernel
+MODULE_NAME :=wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_URBETTER), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE
+ARCH := arm
+CROSS_COMPILE := /media/DATA-1/urbetter/arm-2009q3/bin/arm-none-linux-gnueabi-
+KSRC := /media/DATA-1/urbetter/ics-urbetter/kernel
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_TI_PANDA), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE
+ARCH := arm
+#CROSS_COMPILE := /media/DATA-1/aosp/ics-aosp_20111227/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+#KSRC := /media/DATA-1/aosp/android-omap-panda-3.0_20120104
+CROSS_COMPILE := /media/DATA-1/android-4.0/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+KSRC := /media/DATA-1/android-4.0/panda_kernel/omap
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_MIPS_JZ4760), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_MINIMAL_MEMORY_USAGE
+ARCH ?= mips
+CROSS_COMPILE ?= /mnt/sdb5/Ingenic/Umido/mips-4.3/bin/mips-linux-gnu-
+KSRC ?= /mnt/sdb5/Ingenic/Umido/kernel
+endif
+
+ifeq ($(CONFIG_PLATFORM_SZEBOOK), y)
+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN
+ARCH:=arm
+CROSS_COMPILE:=/opt/crosstool2/bin/armeb-unknown-linux-gnueabi-
+KVER:= 2.6.31.6
+KSRC:= ../code/linux-2.6.31.6-2020/
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUNxI), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUNxI
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+# default setting for A10-EVB mmc0
+#EXTRA_CFLAGS += -DCONFIG_WITS_EVB_V13
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_sdio.o
+endif
+
+ARCH := arm
+#CROSS_COMPILE := arm-none-linux-gnueabi-
+CROSS_COMPILE=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/buildroot/output/external-toolchain/bin/arm-none-linux-gnueabi-
+KVER  := 3.0.8
+#KSRC:= ../lichee/linux-3.0/
+KSRC=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/linux-3.0
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUN6I), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN6I
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2, 4.3, 4.4
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS +=  -DCONFIG_QOS_OPTIMIZATION
+
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+# default setting for A31-EVB mmc0
+EXTRA_CFLAGS += -DCONFIG_A31_EVB
+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o
+endif
+
+ARCH := arm
+#Android-JB42
+#CROSS_COMPILE := /home/android_sdk/Allwinner/a31/android-jb42/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi-
+#KSRC :=/home/android_sdk/Allwinner/a31/android-jb42/lichee/linux-3.3
+#ifeq ($(CONFIG_USB_HCI), y)
+#MODULE_NAME := 8188eu_sw
+#endif
+# ==== Cross compile setting for kitkat-a3x_v4.5 =====
+CROSS_COMPILE := /home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi-
+KSRC :=/home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/linux-3.3
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUN7I), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2, 4.3, 4.4
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS +=  -DCONFIG_QOS_OPTIMIZATION
+
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o
+endif
+
+ARCH := arm
+# ===Cross compile setting for Android 4.2 SDK ===
+#CROSS_COMPILE := /home/android_sdk/Allwinner/a20_evb/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+#KSRC := /home/android_sdk/Allwinner/a20_evb/lichee/linux-3.3
+# ==== Cross compile setting for Android 4.3 SDK =====
+#CROSS_COMPILE := /home/android_sdk/Allwinner/a20/android-jb43/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+#KSRC := /home/android_sdk/Allwinner/a20/android-jb43/lichee/linux-3.4
+# ==== Cross compile setting for kitkat-a20_v4.4 =====
+CROSS_COMPILE := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+KSRC := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/linux-3.4
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W3P1), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W3P1
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o
+endif
+
+ARCH := arm
+# ===Cross compile setting for Android 4.2 SDK ===
+#CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-jb42/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+#KSRC :=/home/android_sdk/Allwinner/a23/android-jb42/lichee/linux-3.4
+# ===Cross compile setting for Android 4.4 SDK ===
+CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-kk44/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+KSRC :=/home/android_sdk/Allwinner/a23/android-kk44/lichee/linux-3.4
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W5P1), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W5P1
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+
+# Enable this for Android 5.0
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o
+endif
+
+ARCH := arm
+# ===Cross compile setting for Android L SDK ===
+CROSS_COMPILE := /home/android_sdk/Allwinner/a33/android-L/lichee/out/sun8iw5p1/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+KSRC :=/home/android_sdk/Allwinner/a33/android-L/lichee/linux-3.4
+endif
+
+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATV5201), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATV5201
+EXTRA_CFLAGS += -DCONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP
+ARCH := mips
+CROSS_COMPILE := mipsel-linux-gnu-
+KVER  := $(KERNEL_VER)
+KSRC:= $(CFGDIR)/../../kernel/linux-$(KERNEL_VER)
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_RTD299X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DUSB_XMITBUF_ALIGN_SZ=1024 -DUSB_PACKET_OFFSET_SZ=0
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+ifeq ($(CONFIG_ANDROID), y)
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+# Enable this for Android 5.0
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+endif
+#ARCH, CROSS_COMPILE, KSRC,and  MODDESTDIR are provided by external makefile
+INSTALL_PREFIX :=
+endif
+
+ifeq ($(CONFIG_PLATFORM_HISILICON), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_HISILICON
+ifeq ($(SUPPORT_CONCURRENT),y)
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+endif
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+ARCH := arm
+ifeq ($(CROSS_COMPILE),)
+       CROSS_COMPILE = arm-hisiv200-linux-
+endif
+MODULE_NAME := rtl8192eu
+ifeq ($(KSRC),)
+       KSRC := ../../../../../../kernel/linux-3.4.y
+endif
+endif
+
+ifeq ($(CONFIG_PLATFORM_HISILICON_HI3798), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_HISILICON
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_HISILICON_HI3798
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+
+# default setting for Android 5.x and later
+#EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+_PLATFORM_FILES += platform/platform_hisilicon_hi3798_sdio.o
+EXTRA_CFLAGS += -DCONFIG_HISI_SDIO_ID=1
+endif
+
+ARCH ?= arm
+CROSS_COMPILE ?= /HiSTBAndroidV600R003C00SPC021_git_0512/device/hisilicon/bigfish/sdk/tools/linux/toolchains/arm-histbv310-linux/bin/arm-histbv310-linux-
+ifndef KSRC
+KSRC := /HiSTBAndroidV600R003C00SPC021_git_0512/device/hisilicon/bigfish/sdk/source/kernel/linux-3.18.y
+KSRC += O=/HiSTBAndroidV600R003C00SPC021_git_0512/out/target/product/Hi3798MV200/obj/KERNEL_OBJ
+endif
+
+ifeq ($(CONFIG_RTL8822B), y)
+ifeq ($(CONFIG_SDIO_HCI), y)
+# default 8822bs module name would be 88x2bs, but Hisilicon use rtl8822bs
+USER_MODULE_NAME := rtl8822bs
+endif
+endif
+
+endif
+
+# Platform setting
+ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_6820), y)
+ifeq ($(CONFIG_ANDROID_2X), y)
+EXTRA_CFLAGS += -DANDROID_2X
+endif
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD
+EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_6820
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ifeq ($(RTL871X), rtl8188e)
+EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+_PLATFORM_FILES += platform/platform_sprd_sdio.o
+endif
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_8810), y)
+ifeq ($(CONFIG_ANDROID_2X), y)
+EXTRA_CFLAGS += -DANDROID_2X
+endif
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD
+EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_8810
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ifeq ($(RTL871X), rtl8188e)
+EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+_PLATFORM_FILES += platform/platform_sprd_sdio.o
+endif
+endif
+
+ifeq ($(CONFIG_PLATFORM_AML_S905), y)
+EXTRA_CFLAGS += -Wno-error=date-time
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_AML_S905
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -fno-pic
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DRTW_USE_CFG80211_STA_EVENT -DCONFIG_RTW_IOCTL_SET_COUNTRY
+
+# Enable this for Android 5.0 and later
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+_PLATFORM_FILES += platform/platform_aml_s905_sdio.o
+endif
+
+ARCH ?= arm64
+CROSS_COMPILE ?= /4.4_S905L_8822bs_compile/gcc-linaro-aarch64-linux-gnu-4.9-2014.09_linux/bin/aarch64-linux-gnu-
+ifndef KSRC
+KSRC := /4.4_S905L_8822bs_compile/common
+# To locate output files in a separate directory.
+KSRC += O=/4.4_S905L_8822bs_compile/KERNEL_OBJ
+endif
+
+ifeq ($(CONFIG_RTL8822B), y)
+ifeq ($(CONFIG_SDIO_HCI), y)
+CONFIG_RTL8822BS ?= m
+# default 8822bs module name would be 88x2bs, but Amlogic use 8822bs
+USER_MODULE_NAME := 8822bs
+endif
+endif
+
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_WMT), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_WMT_sdio.o
+endif
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/WonderMedia/wm8880-android4.4/toolchain/arm_201103_gcc4.5.2/mybin/arm_1103_le-
+KSRC := /home/android_sdk/WonderMedia/wm8880-android4.4/kernel4.4/
+MODULE_NAME :=8189es_kk
+endif
+
+ifeq ($(CONFIG_PLATFORM_RTK119X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+#EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IFACE_NUMBER=3
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+#EXTRA_CFLAGS +=  -DCONFIG_QOS_OPTIMIZATION
+EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION
+
+#EXTRA_CFLAGS += -DCONFIG_#PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+#_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o
+endif
+
+ARCH := arm
+
+# ==== Cross compile setting for Android 4.4 SDK =====
+#CROSS_COMPILE := arm-linux-gnueabihf-
+KVER  := 3.10.24
+#KSRC :=/home/android_sdk/Allwinner/a20/android-kitkat44/lichee/linux-3.4
+CROSS_COMPILE := /home/realtek/software_phoenix/phoenix/toolchain/usr/local/arm-2013.11/bin/arm-linux-gnueabihf-
+KSRC := /home/realtek/software_phoenix/linux-kernel
+MODULE_NAME := 8192eu
+
+endif
+
+ifeq ($(CONFIG_PLATFORM_RTK129X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DRTK_129X_PLATFORM
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+#EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_QOS_OPTIMIZATION
+EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION
+# Enable this for Android 5.0
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+ifeq ($(CONFIG_RTL8821C)$(CONFIG_SDIO_HCI),yy)
+EXTRA_CFLAGS += -DCONFIG_WAKEUP_GPIO_INPUT_MODE
+EXTRA_CFLAGS += -DCONFIG_BT_WAKE_HST_OPEN_DRAIN
+endif
+EXTRA_CFLAGS += -Wno-error=date-time
+# default setting for Android 7.0
+ifeq ($(RTK_ANDROID_VERSION), nougat)
+EXTRA_CFLAGS += -DRTW_P2P_GROUP_INTERFACE=1
+endif
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+endif
+
+ARCH := arm64
+
+# ==== Cross compile setting for Android 4.4 SDK =====
+#CROSS_COMPILE := arm-linux-gnueabihf-
+#KVER := 4.1.10
+#CROSS_COMPILE := $(CROSS)
+#KSRC := $(LINUX_KERNEL_PATH)
+CROSS_COMPILE := /home/android_sdk/DHC/trunk-6.0.0_r1-QA160627/phoenix/toolchain/asdk64-4.9.4-a53-EL-3.10-g2.19-a64nt-160307/bin/asdk64-linux-
+KSRC := /home/android_sdk/DHC/trunk-6.0.0_r1-QA160627/linux-kernel
+endif
+
+ifeq ($(CONFIG_PLATFORM_NOVATEK_NT72668), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_NOVATEK_NT72668
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+ARCH ?= arm
+CROSS_COMPILE := arm-linux-gnueabihf-
+KVER := 3.8.0
+KSRC := /Custom/Novatek/TCL/linux-3.8_header
+#KSRC := $(KERNELDIR)
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_TCC8930_JB42), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Telechips/v13.05_r1-tcc-android-4.2.2_tcc893x-evm_build/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
+KSRC := /home/android_sdk/Telechips/v13.05_r1-tcc-android-4.2.2_tcc893x-evm_build/kernel
+MODULE_NAME := wlan
+endif 
+
+ifeq ($(CONFIG_PLATFORM_RTL8197D), y)
+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -DCONFIG_PLATFORM_RTL8197D
+export DIR_LINUX=$(shell pwd)/../SDK/rlxlinux-sdk321-v50/linux-2.6.30
+ARCH ?= rlx
+CROSS_COMPILE:= $(DIR_LINUX)/../toolchain/rsdk-1.5.5-5281-EB-2.6.30-0.9.30.3-110714/bin/rsdk-linux-
+KSRC := $(DIR_LINUX)
+endif
+
+ifeq ($(CONFIG_PLATFORM_ZTE_ZX296716), y)
+EXTRA_CFLAGS += -Wno-error=date-time
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ZTE_ZX296716
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+# default setting for Android 5.x and later
+#EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+# others
+#EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+# mark this temporarily
+#EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+#_PLATFORM_FILES += platform/platform_zte_zx296716_sdio.o
+endif
+
+ARCH ?= arm64
+CROSS_COMPILE ?=
+KSRC ?=
+
+ifeq ($(CONFIG_RTL8822B), y)
+ifeq ($(CONFIG_SDIO_HCI), y)
+# default 8822bs module name would be 88x2bs, but ZTE use 8822bs
+USER_MODULE_NAME := 8822bs
+endif
+endif
+
+endif
+
+
+ifeq ($(CONFIG_MULTIDRV), y)
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME := rtw_sdio
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME := rtw_usb
+endif
+
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME := rtw_pci
+endif
+
+
+endif
+
+USER_MODULE_NAME ?=
+ifneq ($(USER_MODULE_NAME),)
+MODULE_NAME := $(USER_MODULE_NAME)
+endif
+
+ifneq ($(KERNELRELEASE),)
+
+########### this part for *.mk ############################
+include $(src)/hal/phydm/phydm.mk
+
+########### HAL_RTL8822B #################################
+ifeq ($(CONFIG_RTL8822B), y)
+include $(src)/rtl8822b.mk
+endif
+
+########### HAL_RTL8821C #################################
+ifeq ($(CONFIG_RTL8821C), y)
+include $(src)/rtl8821c.mk
+endif
+
+rtk_core :=	core/rtw_cmd.o \
+		core/rtw_security.o \
+		core/rtw_debug.o \
+		core/rtw_io.o \
+		core/rtw_ioctl_query.o \
+		core/rtw_ioctl_set.o \
+		core/rtw_ieee80211.o \
+		core/rtw_mlme.o \
+		core/rtw_mlme_ext.o \
+		core/rtw_mi.o \
+		core/rtw_wlan_util.o \
+		core/rtw_vht.o \
+		core/rtw_pwrctrl.o \
+		core/rtw_rf.o \
+		core/rtw_recv.o \
+		core/rtw_sta_mgt.o \
+		core/rtw_ap.o \
+		core/rtw_xmit.o	\
+		core/rtw_p2p.o \
+		core/rtw_rson.o \
+		core/rtw_tdls.o \
+		core/rtw_br_ext.o \
+		core/rtw_iol.o \
+		core/rtw_sreset.o \
+		core/rtw_btcoex_wifionly.o \
+		core/rtw_btcoex.o \
+		core/rtw_beamforming.o \
+		core/rtw_odm.o \
+		core/efuse/rtw_efuse.o 
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+rtk_core += core/rtw_sdio.o
+endif
+
+$(MODULE_NAME)-y += $(rtk_core)
+
+$(MODULE_NAME)-$(CONFIG_INTEL_WIDI) += core/rtw_intel_widi.o
+
+$(MODULE_NAME)-$(CONFIG_WAPI_SUPPORT) += core/rtw_wapi.o	\
+					core/rtw_wapi_sms4.o
+
+$(MODULE_NAME)-y += $(_OS_INTFS_FILES)
+$(MODULE_NAME)-y += $(_HAL_INTFS_FILES)
+$(MODULE_NAME)-y += $(_PHYDM_FILES)
+$(MODULE_NAME)-y += $(_BTC_FILES)
+$(MODULE_NAME)-y += $(_PLATFORM_FILES)
+
+$(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o
+
+ifeq ($(CONFIG_RTL8723B), y)
+$(MODULE_NAME)-$(CONFIG_MP_INCLUDED)+= core/rtw_bt_mp.o
+endif
+
+obj-m:= $(MODULE_NAME).o
+
+else
+
+export CONFIG_RTL8822BS = m
+
+all: modules
+
+modules:
+	$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd)  modules
+
+strip:
+	$(CROSS_COMPILE)strip $(MODULE_NAME).ko --strip-unneeded
+
+install:
+	install -p -m 644 $(MODULE_NAME).ko  $(MODDESTDIR)
+	/sbin/depmod -a ${KVER}
+
+uninstall:
+	rm -f $(MODDESTDIR)/$(MODULE_NAME).ko
+	/sbin/depmod -a ${KVER}
+
+backup_rtlwifi:
+	@echo "Making backup rtlwifi drivers"
+ifneq (,$(wildcard $(STAGINGMODDIR)/rtl*))
+	@tar cPf $(wildcard $(STAGINGMODDIR))/backup_rtlwifi_driver.tar $(wildcard $(STAGINGMODDIR)/rtl*)
+	@rm -rf $(wildcard $(STAGINGMODDIR)/rtl*)
+endif
+ifneq (,$(wildcard $(MODDESTDIR)realtek))
+	@tar cPf $(MODDESTDIR)backup_rtlwifi_driver.tar $(MODDESTDIR)realtek
+	@rm -fr $(MODDESTDIR)realtek
+endif
+ifneq (,$(wildcard $(MODDESTDIR)rtl*))
+	@tar cPf $(MODDESTDIR)../backup_rtlwifi_driver.tar $(wildcard $(MODDESTDIR)rtl*)
+	@rm -fr $(wildcard $(MODDESTDIR)rtl*)
+endif
+	@/sbin/depmod -a ${KVER}
+	@echo "Please reboot your system"
+
+restore_rtlwifi:
+	@echo "Restoring backups"
+ifneq (,$(wildcard $(STAGINGMODDIR)/backup_rtlwifi_driver.tar))
+	@tar xPf $(STAGINGMODDIR)/backup_rtlwifi_driver.tar
+	@rm $(STAGINGMODDIR)/backup_rtlwifi_driver.tar
+endif
+ifneq (,$(wildcard $(MODDESTDIR)backup_rtlwifi_driver.tar))
+	@tar xPf $(MODDESTDIR)backup_rtlwifi_driver.tar
+	@rm $(MODDESTDIR)backup_rtlwifi_driver.tar
+endif
+ifneq (,$(wildcard $(MODDESTDIR)../backup_rtlwifi_driver.tar))
+	@tar xPf $(MODDESTDIR)../backup_rtlwifi_driver.tar
+	@rm $(MODDESTDIR)../backup_rtlwifi_driver.tar
+endif
+	@/sbin/depmod -a ${KVER}
+	@echo "Please reboot your system"
+
+config_r:
+	@echo "make config"
+	/bin/bash script/Configure script/config.in
+
+
+.PHONY: modules clean
+
+clean:
+	#$(MAKE) -C $(KSRC) M=$(shell pwd) clean
+	cd hal ; rm -fr */*/*/*.mod.c */*/*/*.mod */*/*/*.o */*/*/.*.cmd */*/*/*.ko
+	cd hal ; rm -fr */*/*.mod.c */*/*.mod */*/*.o */*/.*.cmd */*/*.ko
+	cd hal ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko
+	cd hal ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd core/efuse ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd core ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd os_dep/linux ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd os_dep ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd platform ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	rm -fr Module.symvers ; rm -fr Module.markers ; rm -fr modules.order
+	rm -fr *.mod.c *.mod *.o .*.cmd *.ko *~
+	rm -fr .tmp_versions
+endif
+
diff --git a/clean b/clean
new file mode 100644
index 0000000..bf6f4c3
--- /dev/null
+++ b/clean
@@ -0,0 +1,3 @@
+#!/bin/bash
+rmmod 8822bs
+rmmod 88x2bs
diff --git a/core/efuse/rtw_efuse.c b/core/efuse/rtw_efuse.c
new file mode 100644
index 0000000..2f3d6cf
--- /dev/null
+++ b/core/efuse/rtw_efuse.c
@@ -0,0 +1,3215 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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 _RTW_EFUSE_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+#include "../hal/efuse/efuse_mask.h"
+
+/*------------------------Define local variable------------------------------*/
+u8	fakeEfuseBank = {0};
+u32	fakeEfuseUsedBytes = {0};
+u8	fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0};
+u8	fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0};
+u8	fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0};
+
+u32	BTEfuseUsedBytes = {0};
+u8	BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+u8	BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+u8	BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+
+u32	fakeBTEfuseUsedBytes = {0};
+u8	fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+u8	fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+u8	fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+
+u8	maskfileBuffer[64];
+/*------------------------Define local variable------------------------------*/
+BOOLEAN rtw_file_efuse_IsMasked(PADAPTER pAdapter, u16 Offset)
+{
+	int r = Offset / 16;
+	int c = (Offset % 16) / 2;
+	int result = 0;
+
+	if (pAdapter->registrypriv.boffefusemask)
+		return FALSE;
+
+	if (c < 4) /* Upper double word */
+		result = (maskfileBuffer[r] & (0x10 << c));
+	else
+		result = (maskfileBuffer[r] & (0x01 << (c - 4)));
+
+	return (result > 0) ? 0 : 1;
+}
+
+BOOLEAN efuse_IsMasked(PADAPTER pAdapter, u16 Offset)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	if (pAdapter->registrypriv.boffefusemask)
+		return FALSE;
+
+#if DEV_BUS_TYPE == RT_USB_INTERFACE
+#if defined(CONFIG_RTL8188E)
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))
+		return (IS_MASKED(8188E, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8812A)
+	if (IS_HARDWARE_TYPE_8812(pAdapter))
+		return (IS_MASKED(8812A, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8821A)
+#if 0
+	if (IS_HARDWARE_TYPE_8811AU(pAdapter))
+		return (IS_MASKED(8811A, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+	if (IS_HARDWARE_TYPE_8821(pAdapter))
+		return (IS_MASKED(8821A, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8192E)
+	if (IS_HARDWARE_TYPE_8192E(pAdapter))
+		return (IS_MASKED(8192E, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8723B)
+	if (IS_HARDWARE_TYPE_8723B(pAdapter))
+		return (IS_MASKED(8723B, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8703B)
+	if (IS_HARDWARE_TYPE_8703B(pAdapter))
+		return (IS_MASKED(8703B, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8814A)
+	if (IS_HARDWARE_TYPE_8814A(pAdapter))
+		return (IS_MASKED(8814A, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8188F)
+	if (IS_HARDWARE_TYPE_8188F(pAdapter))
+		return (IS_MASKED(8188F, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8822B)
+	if (IS_HARDWARE_TYPE_8822B(pAdapter))
+		return (IS_MASKED(8822B, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8723D)
+	if (IS_HARDWARE_TYPE_8723D(pAdapter))
+		return (IS_MASKED(8723D, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+
+#if defined(CONFIG_RTL8821C)
+	if (IS_HARDWARE_TYPE_8821CU(pAdapter))
+		return (IS_MASKED(8821C, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+
+#elif DEV_BUS_TYPE == RT_PCI_INTERFACE
+#if defined(CONFIG_RTL8188E)
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))
+		return (IS_MASKED(8188E, _MPCIE, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8192E)
+	if (IS_HARDWARE_TYPE_8192E(pAdapter))
+		return (IS_MASKED(8192E, _MPCIE, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8812A)
+	if (IS_HARDWARE_TYPE_8812(pAdapter))
+		return (IS_MASKED(8812A, _MPCIE, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8821A)
+	if (IS_HARDWARE_TYPE_8821(pAdapter))
+		return (IS_MASKED(8821A, _MPCIE, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8723B)
+	if (IS_HARDWARE_TYPE_8723B(pAdapter))
+		return (IS_MASKED(8723B, _MPCIE, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8814A)
+	if (IS_HARDWARE_TYPE_8814A(pAdapter))
+		return (IS_MASKED(8814A, _MPCIE, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8822B)
+	if (IS_HARDWARE_TYPE_8822B(pAdapter))
+		return (IS_MASKED(8822B, _MPCIE, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8821C)
+	if (IS_HARDWARE_TYPE_8821CE(pAdapter))
+		return (IS_MASKED(8821C, _MPCIE, Offset)) ? TRUE : FALSE;
+#endif
+
+#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE
+#ifdef CONFIG_RTL8188E_SDIO
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))
+		return (IS_MASKED(8188E, _MSDIO, Offset)) ? TRUE : FALSE;
+#endif
+#ifdef CONFIG_RTL8723B
+	if (IS_HARDWARE_TYPE_8723BS(pAdapter))
+		return (IS_MASKED(8723B, _MSDIO, Offset)) ? TRUE : FALSE;
+#endif
+#ifdef CONFIG_RTL8188F_SDIO
+	if (IS_HARDWARE_TYPE_8188F(pAdapter))
+		return (IS_MASKED(8188F, _MSDIO, Offset)) ? TRUE : FALSE;
+#endif
+#ifdef CONFIG_RTL8192E
+	if (IS_HARDWARE_TYPE_8192ES(pAdapter))
+		return (IS_MASKED(8192E, _MSDIO, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8821A)
+	if (IS_HARDWARE_TYPE_8821S(pAdapter))
+		return (IS_MASKED(8821A, _MSDIO, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8821C)
+	if (IS_HARDWARE_TYPE_8821CS(pAdapter))
+		return (IS_MASKED(8821C, _MSDIO, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8822B)
+	if (IS_HARDWARE_TYPE_8822B(pAdapter))
+		return (IS_MASKED(8822B, _MSDIO, Offset)) ? TRUE : FALSE;
+#endif
+#endif
+
+	return FALSE;
+}
+
+void rtw_efuse_mask_array(PADAPTER pAdapter, u8 *pArray)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+#if DEV_BUS_TYPE == RT_USB_INTERFACE
+#if defined(CONFIG_RTL8188E)
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))
+		GET_MASK_ARRAY(8188E, _MUSB, pArray);
+#endif
+#if defined(CONFIG_RTL8812A)
+	if (IS_HARDWARE_TYPE_8812(pAdapter))
+		GET_MASK_ARRAY(8812A, _MUSB, pArray);
+#endif
+#if defined(CONFIG_RTL8821A)
+	if (IS_HARDWARE_TYPE_8821(pAdapter))
+		GET_MASK_ARRAY(8821A, _MUSB, pArray);
+#endif
+#if defined(CONFIG_RTL8192E)
+	if (IS_HARDWARE_TYPE_8192E(pAdapter))
+		GET_MASK_ARRAY(8192E, _MUSB, pArray);
+#endif
+#if defined(CONFIG_RTL8723B)
+	if (IS_HARDWARE_TYPE_8723B(pAdapter))
+		GET_MASK_ARRAY(8723B, _MUSB, pArray);
+#endif
+#if defined(CONFIG_RTL8703B)
+	if (IS_HARDWARE_TYPE_8703B(pAdapter))
+		GET_MASK_ARRAY(8703B, _MUSB, pArray);
+#endif
+#if defined(CONFIG_RTL8188F)
+	if (IS_HARDWARE_TYPE_8188F(pAdapter))
+		GET_MASK_ARRAY(8188F, _MUSB, pArray);
+#endif
+#if defined(CONFIG_RTL8814A)
+	if (IS_HARDWARE_TYPE_8814A(pAdapter))
+		GET_MASK_ARRAY(8814A, _MUSB, pArray);
+#endif
+#if defined(CONFIG_RTL8822B)
+	if (IS_HARDWARE_TYPE_8822B(pAdapter))
+		GET_MASK_ARRAY(8822B, _MUSB, pArray);
+#endif
+#if defined(CONFIG_RTL8821C)
+	if (IS_HARDWARE_TYPE_8821CU(pAdapter))
+		GET_MASK_ARRAY(8821C, _MUSB, pArray);
+#endif
+
+
+#elif DEV_BUS_TYPE == RT_PCI_INTERFACE
+#if defined(CONFIG_RTL8188E)
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))
+		GET_MASK_ARRAY(8188E, _MPCIE, pArray);
+#endif
+#if defined(CONFIG_RTL8192E)
+	if (IS_HARDWARE_TYPE_8192E(pAdapter))
+		GET_MASK_ARRAY(8192E, _MPCIE, pArray);
+#endif
+#if defined(CONFIG_RTL8812A)
+	if (IS_HARDWARE_TYPE_8812(pAdapter))
+		GET_MASK_ARRAY(8812A, _MPCIE, pArray);
+#endif
+#if defined(CONFIG_RTL8821A)
+	if (IS_HARDWARE_TYPE_8821(pAdapter))
+		GET_MASK_ARRAY(8821A, _MPCIE, pArray);
+#endif
+#if defined(CONFIG_RTL8723B)
+	if (IS_HARDWARE_TYPE_8723B(pAdapter))
+		GET_MASK_ARRAY(8723B, _MPCIE, pArray);
+#endif
+#if defined(CONFIG_RTL8814A)
+	if (IS_HARDWARE_TYPE_8814A(pAdapter))
+		GET_MASK_ARRAY(8814A, _MPCIE, pArray);
+#endif
+#if defined(CONFIG_RTL8822B)
+	if (IS_HARDWARE_TYPE_8822B(pAdapter))
+		GET_MASK_ARRAY(8822B, _MPCIE, pArray);
+#endif
+#if defined(CONFIG_RTL8821C)
+	if (IS_HARDWARE_TYPE_8821CE(pAdapter))
+		GET_MASK_ARRAY(8821C, _MPCIE, pArray);
+#endif
+
+
+#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE
+#if defined(CONFIG_RTL8188E)
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))
+		GET_MASK_ARRAY(8188E, _MSDIO, pArray);
+#endif
+#if defined(CONFIG_RTL8723B)
+	if (IS_HARDWARE_TYPE_8723BS(pAdapter))
+		GET_MASK_ARRAY(8723B, _MSDIO, pArray);
+#endif
+#if defined(CONFIG_RTL8188F)
+	if (IS_HARDWARE_TYPE_8188F(pAdapter))
+		GET_MASK_ARRAY(8188F, _MSDIO, pArray);
+#endif
+#if defined(CONFIG_RTL8192E)
+	if (IS_HARDWARE_TYPE_8192ES(pAdapter))
+		GET_MASK_ARRAY(8192E, _MSDIO, pArray);
+#endif
+#if defined(CONFIG_RTL8821A)
+	if (IS_HARDWARE_TYPE_8821S(pAdapter))
+		GET_MASK_ARRAY(8821A, _MSDIO, pArray);
+#endif
+#if defined(CONFIG_RTL8821C)
+	if (IS_HARDWARE_TYPE_8821CS(pAdapter))
+		GET_MASK_ARRAY(8821C , _MSDIO, pArray);
+#endif
+#if defined(CONFIG_RTL8822B)
+	if (IS_HARDWARE_TYPE_8822B(pAdapter))
+		GET_MASK_ARRAY(8822B , _MSDIO, pArray);
+#endif
+#endif /*#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE*/
+}
+
+u16 rtw_get_efuse_mask_arraylen(PADAPTER pAdapter)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(pAdapter);
+
+#if DEV_BUS_TYPE == RT_USB_INTERFACE
+#if defined(CONFIG_RTL8188E)
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))
+		return GET_MASK_ARRAY_LEN(8188E, _MUSB);
+#endif
+#if defined(CONFIG_RTL8812A)
+	if (IS_HARDWARE_TYPE_8812(pAdapter))
+		return GET_MASK_ARRAY_LEN(8812A, _MUSB);
+#endif
+#if defined(CONFIG_RTL8821A)
+	if (IS_HARDWARE_TYPE_8821(pAdapter))
+		return GET_MASK_ARRAY_LEN(8821A, _MUSB);
+#endif
+#if defined(CONFIG_RTL8192E)
+	if (IS_HARDWARE_TYPE_8192E(pAdapter))
+		return GET_MASK_ARRAY_LEN(8192E, _MUSB);
+#endif
+#if defined(CONFIG_RTL8723B)
+	if (IS_HARDWARE_TYPE_8723B(pAdapter))
+		return GET_MASK_ARRAY_LEN(8723B, _MUSB);
+#endif
+#if defined(CONFIG_RTL8703B)
+	if (IS_HARDWARE_TYPE_8703B(pAdapter))
+		return GET_MASK_ARRAY_LEN(8703B, _MUSB);
+#endif
+#if defined(CONFIG_RTL8188F)
+	if (IS_HARDWARE_TYPE_8188F(pAdapter))
+		return GET_MASK_ARRAY_LEN(8188F, _MUSB);
+#endif
+#if defined(CONFIG_RTL8814A)
+	if (IS_HARDWARE_TYPE_8814A(pAdapter))
+		return GET_MASK_ARRAY_LEN(8814A, _MUSB);
+#endif
+#if defined(CONFIG_RTL8822B)
+	if (IS_HARDWARE_TYPE_8822B(pAdapter))
+		return GET_MASK_ARRAY_LEN(8822B, _MUSB);
+#endif
+#if defined(CONFIG_RTL8821C)
+	if (IS_HARDWARE_TYPE_8821CU(pAdapter))
+		return GET_MASK_ARRAY_LEN(8821C, _MUSB);
+#endif
+
+
+#elif DEV_BUS_TYPE == RT_PCI_INTERFACE
+#if defined(CONFIG_RTL8188E)
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))
+		return GET_MASK_ARRAY_LEN(8188E, _MPCIE);
+#endif
+#if defined(CONFIG_RTL8192E)
+	if (IS_HARDWARE_TYPE_8192E(pAdapter))
+		return GET_MASK_ARRAY_LEN(8192E, _MPCIE);
+#endif
+#if defined(CONFIG_RTL8812A)
+	if (IS_HARDWARE_TYPE_8812(pAdapter))
+		return GET_MASK_ARRAY_LEN(8812A, _MPCIE);
+#endif
+#if defined(CONFIG_RTL8821A)
+	if (IS_HARDWARE_TYPE_8821(pAdapter))
+		return GET_MASK_ARRAY_LEN(8821A, _MPCIE);
+#endif
+#if defined(CONFIG_RTL8723B)
+	if (IS_HARDWARE_TYPE_8723B(pAdapter))
+		return GET_MASK_ARRAY_LEN(8723B, _MPCIE);
+#endif
+#if defined(CONFIG_RTL8814A)
+	if (IS_HARDWARE_TYPE_8814A(pAdapter))
+		return GET_MASK_ARRAY_LEN(8814A, _MPCIE);
+#endif
+#if defined(CONFIG_RTL8822B)
+	if (IS_HARDWARE_TYPE_8822B(pAdapter))
+		return GET_MASK_ARRAY_LEN(8822B, _MPCIE);
+#endif
+#if defined(CONFIG_RTL8821C)
+	if (IS_HARDWARE_TYPE_8821CE(pAdapter))
+		return GET_MASK_ARRAY_LEN(8821C, _MPCIE);
+#endif
+
+
+#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE
+#if defined(CONFIG_RTL8188E)
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))
+		return GET_MASK_ARRAY_LEN(8188E, _MSDIO);
+#endif
+#if defined(CONFIG_RTL8723B)
+	if (IS_HARDWARE_TYPE_8723BS(pAdapter))
+		return GET_MASK_ARRAY_LEN(8723B, _MSDIO);
+#endif
+#if defined(CONFIG_RTL8188F)
+	if (IS_HARDWARE_TYPE_8188F(pAdapter))
+		return GET_MASK_ARRAY_LEN(8188F, _MSDIO);
+#endif
+#if defined(CONFIG_RTL8192E)
+	if (IS_HARDWARE_TYPE_8192ES(pAdapter))
+		return GET_MASK_ARRAY_LEN(8192E, _MSDIO);
+#endif
+#if defined(CONFIG_RTL8821A)
+	if (IS_HARDWARE_TYPE_8821S(pAdapter))
+		return GET_MASK_ARRAY_LEN(8821A, _MSDIO);
+#endif
+#if defined(CONFIG_RTL8821C)
+	if (IS_HARDWARE_TYPE_8821CS(pAdapter))
+		return GET_MASK_ARRAY_LEN(8821C, _MSDIO);
+#endif
+#if defined(CONFIG_RTL8822B)
+	if (IS_HARDWARE_TYPE_8822B(pAdapter))
+		return GET_MASK_ARRAY_LEN(8822B, _MSDIO);
+#endif
+#endif
+	return 0;
+}
+
+static void rtw_mask_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u16 i = 0;
+
+	if (padapter->registrypriv.boffefusemask == 0) {
+
+			for (i = 0; i < cnts; i++) {
+				if (padapter->registrypriv.bFileMaskEfuse == _TRUE) {
+					if (rtw_file_efuse_IsMasked(padapter, addr + i)) /*use file efuse mask.*/
+						data[i] = 0xff;
+				} else {
+					/*RTW_INFO(" %s , data[%d] = %x\n", __func__, i, data[i]);*/
+					if (efuse_IsMasked(padapter, addr + i)) {
+						data[i] = 0xff;
+						/*RTW_INFO(" %s ,mask data[%d] = %x\n", __func__, i, data[i]);*/
+					}
+				}
+			}
+
+	}
+}
+
+u8 rtw_efuse_mask_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u8	ret = _SUCCESS;
+	u16	mapLen = 0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+
+	ret = rtw_efuse_map_read(padapter, addr, cnts , data);
+
+	rtw_mask_map_read(padapter, addr, cnts , data);
+
+	return ret;
+
+}
+
+/* ***********************************************************
+ *				Efuse related code
+ * *********************************************************** */
+static u8 hal_EfuseSwitchToBank(
+	PADAPTER	padapter,
+	u8			bank,
+	u8			bPseudoTest)
+{
+	u8 bRet = _FALSE;
+	u32 value32 = 0;
+#ifdef HAL_EFUSE_MEMORY
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter);
+	PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal;
+#endif
+
+
+	RTW_INFO("%s: Efuse switch bank to %d\n", __FUNCTION__, bank);
+	if (bPseudoTest) {
+#ifdef HAL_EFUSE_MEMORY
+		pEfuseHal->fakeEfuseBank = bank;
+#else
+		fakeEfuseBank = bank;
+#endif
+		bRet = _TRUE;
+	} else {
+		value32 = rtw_read32(padapter, 0x34);
+		bRet = _TRUE;
+		switch (bank) {
+		case 0:
+			value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0);
+			break;
+		case 1:
+			value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_0);
+			break;
+		case 2:
+			value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_1);
+			break;
+		case 3:
+			value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_2);
+			break;
+		default:
+			value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0);
+			bRet = _FALSE;
+			break;
+		}
+		rtw_write32(padapter, 0x34, value32);
+	}
+
+	return bRet;
+}
+
+void rtw_efuse_analyze(PADAPTER	padapter, u8 Type, u8 Fake)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+	PEFUSE_HAL		pEfuseHal = &(pHalData->EfuseHal);
+	u16	eFuse_Addr = 0;
+	u8 offset, wden;
+	u16	 i, j;
+	u8	u1temp = 0;
+	u8	efuseHeader = 0, efuseExtHdr = 0, efuseData[EFUSE_MAX_WORD_UNIT*2] = {0}, dataCnt = 0;
+	u16	efuseHeader2Byte = 0;
+	u8	*eFuseWord = NULL;// [EFUSE_MAX_SECTION_NUM][EFUSE_MAX_WORD_UNIT];
+	u8	offset_2_0 = 0;
+	u8	pgSectionCnt = 0;
+	u8	wd_cnt = 0;
+	u8	max_section = 64;
+	u16	mapLen = 0, maprawlen = 0;
+	boolean	bExtHeader = _FALSE;
+	u8	efuseType = EFUSE_WIFI;
+	boolean	bPseudoTest = _FALSE;
+	u8	bank = 0, startBank = 0, endBank = 1-1;
+	boolean	bCheckNextBank = FALSE;
+	u8	protectBytesBank = 0;
+	u16	efuse_max = 0;
+	u8	ParseEfuseExtHdr, ParseEfuseHeader, ParseOffset, ParseWDEN, ParseOffset2_0;
+
+	eFuseWord = rtw_zmalloc(EFUSE_MAX_SECTION_NUM * (EFUSE_MAX_WORD_UNIT * 2));
+
+	RTW_INFO("\n");
+	if (Type == 0) {
+		if (Fake == 0) {
+			RTW_INFO("\n\tEFUSE_Analyze Wifi Content\n");
+			efuseType = EFUSE_WIFI;
+			bPseudoTest = FALSE;
+			startBank = 0;
+			endBank = 0;
+		} else {
+			RTW_INFO("\n\tEFUSE_Analyze Wifi Pseudo Content\n");
+			efuseType = EFUSE_WIFI;
+			bPseudoTest = TRUE;
+			startBank = 0;
+			endBank = 0;
+		}
+	} else {
+		if (Fake == 0) {
+			RTW_INFO("\n\tEFUSE_Analyze BT Content\n");
+			efuseType = EFUSE_BT;
+			bPseudoTest = FALSE;
+			startBank = 1;
+			endBank = EFUSE_MAX_BANK - 1;
+		} else {
+			RTW_INFO("\n\tEFUSE_Analyze BT Pseudo Content\n");
+			efuseType = EFUSE_BT;
+			bPseudoTest = TRUE;
+			startBank = 1;
+			endBank = EFUSE_MAX_BANK - 1;
+			if (IS_HARDWARE_TYPE_8821(padapter))
+				endBank = 3 - 1;/*EFUSE_MAX_BANK_8821A - 1;*/
+		}
+	}
+
+	RTW_INFO("\n\r 1Byte header, [7:4]=offset, [3:0]=word enable\n");
+	RTW_INFO("\n\r 2Byte header, header[7:5]=offset[2:0], header[4:0]=0x0F\n");
+	RTW_INFO("\n\r 2Byte header, extHeader[7:4]=offset[6:3], extHeader[3:0]=word enable\n");
+
+	EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest);
+	EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_MAX_SECTION, (PVOID)&max_section, bPseudoTest);
+	EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_PROTECT_BYTES_BANK, (PVOID)&protectBytesBank, bPseudoTest);
+	EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_CONTENT_LEN_BANK, (PVOID)&efuse_max, bPseudoTest);
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&maprawlen, _FALSE);
+
+	_rtw_memset(eFuseWord, 0xff, EFUSE_MAX_SECTION_NUM * (EFUSE_MAX_WORD_UNIT * 2));
+	_rtw_memset(pEfuseHal->fakeEfuseInitMap, 0xff, EFUSE_MAX_MAP_LEN);
+
+	if (IS_HARDWARE_TYPE_8821(padapter))
+		endBank = 3 - 1;/*EFUSE_MAX_BANK_8821A - 1;*/
+
+	for (bank = startBank; bank <= endBank; bank++) {
+		if (!hal_EfuseSwitchToBank(padapter, bank, bPseudoTest)) {
+			RTW_INFO("EFUSE_SwitchToBank() Fail!!\n");
+			return;
+		}
+
+		eFuse_Addr = bank * EFUSE_MAX_BANK_SIZE;
+
+		efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest);
+
+		if (efuseHeader == 0xFF && bank == startBank && Fake != TRUE) {
+			RTW_INFO("Non-PGed Efuse\n");
+			return;
+		}
+		RTW_INFO("EFUSE_REAL_CONTENT_LEN = %d\n", maprawlen);
+
+		while ((efuseHeader != 0xFF) && ((efuseType == EFUSE_WIFI && (eFuse_Addr < maprawlen)) || (efuseType == EFUSE_BT && (eFuse_Addr < (endBank + 1) * EFUSE_MAX_BANK_SIZE)))) {
+
+			RTW_INFO("Analyzing: Offset: 0x%X\n", eFuse_Addr);
+
+			/* Check PG header for section num.*/
+			if (EXT_HEADER(efuseHeader)) {
+				bExtHeader = TRUE;
+				offset_2_0 = GET_HDR_OFFSET_2_0(efuseHeader);
+				efuse_OneByteRead(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest);
+
+				if (efuseExtHdr != 0xff) {
+					if (ALL_WORDS_DISABLED(efuseExtHdr)) {
+						/* Read next pg header*/
+						efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest);
+						continue;
+					} else {
+						offset = ((efuseExtHdr & 0xF0) >> 1) | offset_2_0;
+						wden = (efuseExtHdr & 0x0F);
+						efuseHeader2Byte = (efuseExtHdr<<8)|efuseHeader;
+						RTW_INFO("Find efuseHeader2Byte = 0x%04X, offset=%d, wden=0x%x\n",
+										efuseHeader2Byte, offset, wden);
+					}
+				} else {
+					RTW_INFO("Error, efuse[%d]=0xff, efuseExtHdr=0xff\n", eFuse_Addr-1);
+					break;
+				}
+			} else {
+				offset = ((efuseHeader >> 4) & 0x0f);
+				wden = (efuseHeader & 0x0f);
+			}
+
+			_rtw_memset(efuseData, '\0', EFUSE_MAX_WORD_UNIT * 2);
+			dataCnt = 0;
+
+			if (offset < max_section) {
+				for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+					/* Check word enable condition in the section	*/
+					if (!(wden & (0x01<<i))) {
+						if (!((efuseType == EFUSE_WIFI && (eFuse_Addr + 2 < maprawlen)) ||
+								(efuseType == EFUSE_BT && (eFuse_Addr + 2 < (endBank + 1) * EFUSE_MAX_BANK_SIZE)))) {
+							RTW_INFO("eFuse_Addr exceeds, break\n");
+							break;
+						}
+						efuse_OneByteRead(padapter, eFuse_Addr++, &efuseData[dataCnt++], bPseudoTest);
+						eFuseWord[(offset * 8) + (i * 2)] = (efuseData[dataCnt - 1]);
+						efuse_OneByteRead(padapter, eFuse_Addr++, &efuseData[dataCnt++], bPseudoTest);
+						eFuseWord[(offset * 8) + (i * 2 + 1)] = (efuseData[dataCnt - 1]);
+					}
+				}
+			}
+
+			if (bExtHeader) {
+				RTW_INFO("Efuse PG Section (%d) = ", pgSectionCnt);
+				RTW_INFO("[ %04X ], [", efuseHeader2Byte);
+
+			} else {
+				RTW_INFO("Efuse PG Section (%d) = ", pgSectionCnt);
+				RTW_INFO("[ %02X ], [", efuseHeader);
+			}
+
+			for (j = 0; j < dataCnt; j++)
+				RTW_INFO(" %02X ", efuseData[j]);
+
+			RTW_INFO("]\n");
+
+
+			if (bExtHeader) {
+				ParseEfuseExtHdr = (efuseHeader2Byte & 0xff00) >> 8;
+				ParseEfuseHeader = (efuseHeader2Byte & 0xff);
+				ParseOffset2_0 = GET_HDR_OFFSET_2_0(ParseEfuseHeader);
+				ParseOffset = ((ParseEfuseExtHdr & 0xF0) >> 1) | ParseOffset2_0;
+				ParseWDEN = (ParseEfuseExtHdr & 0x0F);
+				RTW_INFO("Header=0x%x, ExtHeader=0x%x, ", ParseEfuseHeader, ParseEfuseExtHdr);
+			} else {
+				ParseEfuseHeader = efuseHeader;
+				ParseOffset = ((ParseEfuseHeader >> 4) & 0x0f);
+				ParseWDEN = (ParseEfuseHeader & 0x0f);
+				RTW_INFO("Header=0x%x, ", ParseEfuseHeader);
+			}
+			RTW_INFO("offset=0x%x(%d), word enable=0x%x\n", ParseOffset, ParseOffset, ParseWDEN);
+
+			wd_cnt = 0;
+			for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+				if (!(wden & (0x01 << i))) {
+					RTW_INFO("Map[ %02X ] = %02X %02X\n", ((offset * EFUSE_MAX_WORD_UNIT * 2) + (i * 2)), efuseData[wd_cnt * 2 + 0], efuseData[wd_cnt * 2 + 1]);
+					wd_cnt++;
+				}
+			}
+
+			pgSectionCnt++;
+			bExtHeader = FALSE;
+			efuse_OneByteRead(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest);
+			if (efuseHeader == 0xFF) {
+				if ((eFuse_Addr + protectBytesBank) >= efuse_max)
+					bCheckNextBank = TRUE;
+				else
+					bCheckNextBank = FALSE;
+			}
+		}
+		if (!bCheckNextBank) {
+			RTW_INFO("Not need to check next bank, eFuse_Addr=%d, protectBytesBank=%d, efuse_max=%d\n",
+				eFuse_Addr, protectBytesBank, efuse_max);
+			break;
+		}
+	}
+	/* switch bank back to 0 for BT/wifi later use*/
+	hal_EfuseSwitchToBank(padapter, 0, bPseudoTest);
+
+	/* 3. Collect 16 sections and 4 word unit into Efuse map.*/
+	for (i = 0; i < max_section; i++) {
+		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
+			pEfuseHal->fakeEfuseInitMap[(i*8)+(j*2)] = (eFuseWord[(i*8)+(j*2)]);
+			pEfuseHal->fakeEfuseInitMap[(i*8)+((j*2)+1)] =  (eFuseWord[(i*8)+((j*2)+1)]);
+		}
+	}
+
+	RTW_INFO("\n\tEFUSE Analyze Map\n");
+	i = 0;
+	j = 0;
+
+	for (i = 0; i < mapLen; i++) {
+		if (i % 16 == 0)
+			RTW_PRINT_SEL(RTW_DBGDUMP, "0x%03x: ", i);
+			_RTW_PRINT_SEL(RTW_DBGDUMP, "%02X%s"
+				, pEfuseHal->fakeEfuseInitMap[i]
+				, ((i + 1) % 16 == 0) ? "\n" : (((i + 1) % 8 == 0) ? "	  " : " ")
+			);
+		}
+	_RTW_PRINT_SEL(RTW_DBGDUMP, "\n");
+	if (eFuseWord)
+		rtw_mfree((u8 *)eFuseWord, EFUSE_MAX_SECTION_NUM * (EFUSE_MAX_WORD_UNIT * 2));
+}
+
+VOID efuse_PreUpdateAction(
+	PADAPTER	pAdapter,
+	pu4Byte	BackupRegs)
+{
+	if (IS_HARDWARE_TYPE_8812AU(pAdapter) || IS_HARDWARE_TYPE_8822BU(pAdapter)) {
+		/* <20131115, Kordan> Turn off Rx to prevent from being busy when writing the EFUSE. (Asked by Chunchu.)*/
+		BackupRegs[0] = phy_query_mac_reg(pAdapter, REG_RCR, bMaskDWord);
+		BackupRegs[1] = phy_query_mac_reg(pAdapter, REG_RXFLTMAP0, bMaskDWord);
+		BackupRegs[2] = phy_query_mac_reg(pAdapter, REG_RXFLTMAP0+4, bMaskDWord);
+#ifdef CONFIG_RTL8812A
+		BackupRegs[3] = phy_query_mac_reg(pAdapter, REG_AFE_MISC, bMaskDWord);
+#endif
+		PlatformEFIOWrite4Byte(pAdapter, REG_RCR, 0x1);
+		PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0, 0);
+		PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+1, 0);
+		PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+2, 0);
+		PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+3, 0);
+		PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+4, 0);
+		PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+5, 0);
+#ifdef CONFIG_RTL8812A
+		/* <20140410, Kordan> 0x11 = 0x4E, lower down LX_SPS0 voltage. (Asked by Chunchu)*/
+		phy_set_mac_reg(pAdapter, REG_AFE_MISC, bMaskByte1, 0x4E);
+#endif
+		RTW_INFO(" %s , done\n", __func__);
+
+		}
+}
+
+
+VOID efuse_PostUpdateAction(
+	PADAPTER	pAdapter,
+	pu4Byte	BackupRegs)
+{
+	if (IS_HARDWARE_TYPE_8812AU(pAdapter) || IS_HARDWARE_TYPE_8822BU(pAdapter)) {
+		/* <20131115, Kordan> Turn on Rx and restore the registers. (Asked by Chunchu.)*/
+		phy_set_mac_reg(pAdapter, REG_RCR, bMaskDWord, BackupRegs[0]);
+		phy_set_mac_reg(pAdapter, REG_RXFLTMAP0, bMaskDWord, BackupRegs[1]);
+		phy_set_mac_reg(pAdapter, REG_RXFLTMAP0+4, bMaskDWord, BackupRegs[2]);
+#ifdef CONFIG_RTL8812A
+		phy_set_mac_reg(pAdapter, REG_AFE_MISC, bMaskDWord, BackupRegs[3]);
+#endif
+	RTW_INFO(" %s , done\n", __func__);
+	}
+}
+
+
+#ifdef RTW_HALMAC
+#include "../../hal/hal_halmac.h"
+
+void Efuse_PowerSwitch(PADAPTER adapter, u8 write, u8 pwrstate)
+{
+}
+
+void BTEfuse_PowerSwitch(PADAPTER adapter, u8 write, u8 pwrstate)
+{
+}
+
+u8 efuse_GetCurrentSize(PADAPTER adapter, u16 *size)
+{
+	*size = 0;
+
+	return _FAIL;
+}
+
+u16 efuse_GetMaxSize(PADAPTER adapter)
+{
+	struct dvobj_priv *d;
+	u32 size = 0;
+	int err;
+
+	d = adapter_to_dvobj(adapter);
+	err = rtw_halmac_get_physical_efuse_size(d, &size);
+	if (err)
+		return 0;
+
+	return size;
+}
+
+u16 efuse_GetavailableSize(PADAPTER adapter)
+{
+	struct dvobj_priv *d;
+	u32 size = 0;
+	int err;
+
+	d = adapter_to_dvobj(adapter);
+	err = rtw_halmac_get_available_efuse_size(d, &size);
+	if (err)
+		return 0;
+
+	return size;
+}
+
+
+u8 efuse_bt_GetCurrentSize(PADAPTER adapter, u16 *usesize)
+{
+	u8 *efuse_map;
+
+	*usesize = 0;
+	efuse_map = rtw_malloc(EFUSE_BT_MAP_LEN);
+	if (efuse_map == NULL) {
+		RTW_DBG("%s: malloc FAIL\n", __FUNCTION__);
+		return _FAIL;
+	}
+
+	/* for get bt phy efuse last use byte */
+	hal_ReadEFuse_BT_logic_map(adapter, 0x00, EFUSE_BT_MAP_LEN, efuse_map);
+	*usesize = fakeBTEfuseUsedBytes;
+
+	if (efuse_map)
+		rtw_mfree(efuse_map, EFUSE_BT_MAP_LEN);
+
+	return _SUCCESS;
+}
+
+u16 efuse_bt_GetMaxSize(PADAPTER adapter)
+{
+	return EFUSE_BT_REAL_CONTENT_LEN;
+}
+
+void EFUSE_GetEfuseDefinition(PADAPTER adapter, u8 efusetype, u8 type, void *out, BOOLEAN test)
+{
+	struct dvobj_priv *d;
+	u32 v32 = 0;
+
+
+	d = adapter_to_dvobj(adapter);
+
+	if (adapter->hal_func.EFUSEGetEfuseDefinition) {
+		adapter->hal_func.EFUSEGetEfuseDefinition(adapter, efusetype, type, out, test);
+		return;
+	}
+
+	if (EFUSE_WIFI == efusetype) {
+		switch (type) {
+		case TYPE_EFUSE_MAP_LEN:
+			rtw_halmac_get_logical_efuse_size(d, &v32);
+			*(u16 *)out = (u16)v32;
+			return;
+
+		case TYPE_EFUSE_REAL_CONTENT_LEN:	
+			rtw_halmac_get_physical_efuse_size(d, &v32);
+			*(u16 *)out = (u16)v32;
+			return;
+		}
+	} else if (EFUSE_BT == efusetype) {
+		switch (type) {
+		case TYPE_EFUSE_MAP_LEN:
+			*(u16 *)out = EFUSE_BT_MAP_LEN;
+			return;
+
+		case TYPE_EFUSE_REAL_CONTENT_LEN:
+			*(u16 *)out = EFUSE_BT_REAL_CONTENT_LEN;
+			return;
+		}
+	}
+}
+
+/*
+ * read/write raw efuse data
+ */
+u8 rtw_efuse_access(PADAPTER adapter, u8 write, u16 addr, u16 cnts, u8 *data)
+{
+	struct dvobj_priv *d;
+	u8 *efuse = NULL;
+	u32 size, i;
+	int err;
+
+
+	d = adapter_to_dvobj(adapter);
+	err = rtw_halmac_get_physical_efuse_size(d, &size);
+	if (err)
+		size = EFUSE_MAX_SIZE;
+
+	if ((addr + cnts) > size)
+		return _FAIL;
+
+	if (_TRUE == write) {
+		err = rtw_halmac_write_physical_efuse(d, addr, cnts, data);
+		if (err)
+			return _FAIL;
+	} else {
+		if (cnts > 16)
+			efuse = rtw_zmalloc(size);
+
+		if (efuse) {
+			err = rtw_halmac_read_physical_efuse_map(d, efuse, size);
+			if (err) {
+				rtw_mfree(efuse, size);
+				return _FAIL;
+			}
+
+			_rtw_memcpy(data, efuse + addr, cnts);
+			rtw_mfree(efuse, size);
+		} else {
+			err = rtw_halmac_read_physical_efuse(d, addr, cnts, data);
+			if (err)
+				return _FAIL;
+		}
+	}
+
+	return _SUCCESS;
+}
+
+static inline void dump_buf(u8 *buf, u32 len)
+{
+	u32 i;
+
+	RTW_INFO("-----------------Len %d----------------\n", len);
+	for (i = 0; i < len; i++)
+		printk("%2.2x-", *(buf + i));
+	printk("\n");
+}
+
+/*
+ * read/write raw efuse data
+ */
+u8 rtw_efuse_bt_access(PADAPTER adapter, u8 write, u16 addr, u16 cnts, u8 *data)
+{
+	struct dvobj_priv *d;
+	u8 *efuse = NULL;
+	u32 size, i;
+	int err = _FAIL;
+
+
+	d = adapter_to_dvobj(adapter);
+
+	size = EFUSE_BT_REAL_CONTENT_LEN;
+
+	if ((addr + cnts) > size)
+		return _FAIL;
+
+	if (_TRUE == write) {
+		err = rtw_halmac_write_bt_physical_efuse(d, addr, cnts, data);
+		if (err == -1) {
+			RTW_ERR("%s: rtw_halmac_write_bt_physical_efuse fail!\n", __FUNCTION__);
+			return _FAIL;
+		}
+		RTW_INFO("%s: rtw_halmac_write_bt_physical_efuse OK! data 0x%x\n", __FUNCTION__, *data);
+	} else {
+		efuse = rtw_zmalloc(size);
+
+		if (efuse) {
+			err = rtw_halmac_read_bt_physical_efuse_map(d, efuse, size);
+			
+			if (err == -1) {
+				RTW_ERR("%s: rtw_halmac_read_bt_physical_efuse_map fail!\n", __FUNCTION__);
+				rtw_mfree(efuse, size);
+				return _FAIL;
+			}
+			dump_buf(efuse + addr, cnts);
+
+			_rtw_memcpy(data, efuse + addr, cnts);
+
+			RTW_INFO("%s: rtw_halmac_read_bt_physical_efuse_map ok! data 0x%x\n", __FUNCTION__, *data);
+			rtw_mfree(efuse, size);
+		}
+	}
+
+	return _SUCCESS;
+}
+
+u8 rtw_efuse_map_read(PADAPTER adapter, u16 addr, u16 cnts, u8 *data)
+{
+	struct dvobj_priv *d;
+	u8 *efuse = NULL;
+	u32 size, i;
+	int err;
+	u32	backupRegs[4] = {0};
+	u8 status = _SUCCESS;
+
+	efuse_PreUpdateAction(adapter, backupRegs);
+
+	d = adapter_to_dvobj(adapter);
+	err = rtw_halmac_get_logical_efuse_size(d, &size);
+	if (err) {
+		status = _FAIL;
+		goto exit;
+	}
+	/* size error handle */
+	if ((addr + cnts) > size) {
+		if (addr < size)
+			cnts = size - addr;
+		else {
+			status = _FAIL;
+			goto exit;
+		}
+	}
+
+	if (cnts > 16)
+		efuse = rtw_zmalloc(size);
+
+	if (efuse) {
+		err = rtw_halmac_read_logical_efuse_map(d, efuse, size, NULL, 0);
+		if (err) {
+			rtw_mfree(efuse, size);
+			status = _FAIL;
+			goto exit;
+		}
+
+		_rtw_memcpy(data, efuse + addr, cnts);
+		rtw_mfree(efuse, size);
+	} else {
+		err = rtw_halmac_read_logical_efuse(d, addr, cnts, data);
+		if (err) {
+			status = _FAIL;
+			goto exit;
+		}
+	}
+	status = _SUCCESS;
+exit:
+	efuse_PostUpdateAction(adapter, backupRegs);
+
+	return status;
+}
+
+u8 rtw_efuse_map_write(PADAPTER adapter, u16 addr, u16 cnts, u8 *data)
+{
+	struct dvobj_priv *d;
+	u8 *efuse = NULL;
+	u32 size, i;
+	int err;
+	u8 mask_buf[64] = "";
+	u16 mask_len = sizeof(u8) * rtw_get_efuse_mask_arraylen(adapter);
+	u32 backupRegs[4] = {0};
+	u8 status = _SUCCESS;;
+
+	efuse_PreUpdateAction(adapter, backupRegs);
+
+	d = adapter_to_dvobj(adapter);
+	err = rtw_halmac_get_logical_efuse_size(d, &size);
+	if (err) {
+		status = _FAIL;
+		goto exit;
+	}
+
+	if ((addr + cnts) > size) {
+		status = _FAIL;
+		goto exit;
+	}
+
+	efuse = rtw_zmalloc(size);
+	if (!efuse) {
+		status = _FAIL;
+		goto exit;
+	}
+
+	err = rtw_halmac_read_logical_efuse_map(d, efuse, size, NULL, 0);
+	if (err) {
+		rtw_mfree(efuse, size);
+		status = _FAIL;
+		goto exit;
+	}
+
+	_rtw_memcpy(efuse + addr, data, cnts);
+
+	if (adapter->registrypriv.boffefusemask == 0) {
+		RTW_INFO("Use mask Array Len: %d\n", mask_len);
+
+		if (mask_len != 0) {
+			if (adapter->registrypriv.bFileMaskEfuse == _TRUE)
+				_rtw_memcpy(mask_buf, maskfileBuffer, mask_len);
+			else
+				rtw_efuse_mask_array(adapter, mask_buf);
+
+			err = rtw_halmac_write_logical_efuse_map(d, efuse, size, mask_buf, mask_len);
+		} else
+			err = rtw_halmac_write_logical_efuse_map(d, efuse, size, NULL, 0);
+	} else {
+		_rtw_memset(mask_buf, 0xFF, sizeof(mask_buf));
+		RTW_INFO("Efuse mask off\n");
+		err = rtw_halmac_write_logical_efuse_map(d, efuse, size, mask_buf, size/16);
+	}
+
+	if (err) {
+		rtw_mfree(efuse, size);
+		status = _FAIL;
+		goto exit;
+	}
+
+	rtw_mfree(efuse, size);
+	status = _SUCCESS;
+exit :
+	efuse_PostUpdateAction(adapter, backupRegs);
+
+	return status;
+}
+
+int Efuse_PgPacketRead(PADAPTER adapter, u8 offset, u8 *data, BOOLEAN test)
+{
+	return _FALSE;
+}
+
+int Efuse_PgPacketWrite(PADAPTER adapter, u8 offset, u8 word_en, u8 *data, BOOLEAN test)
+{
+	return _FALSE;
+}
+
+u8 rtw_BT_efuse_map_read(PADAPTER adapter, u16 addr, u16 cnts, u8 *data)
+{
+	hal_ReadEFuse_BT_logic_map(adapter,addr, cnts, data);
+
+	return _SUCCESS;
+}
+
+u8 rtw_BT_efuse_map_write(PADAPTER adapter, u16 addr, u16 cnts, u8 *data)
+{
+#define RT_ASSERT_RET(expr)									\
+	if (!(expr)) {										\
+		printk("Assertion failed! %s at ......\n", #expr);				\
+		printk("	  ......%s,%s, line=%d\n",__FILE__, __FUNCTION__, __LINE__);	\
+		return _FAIL;	\
+	}
+
+	u8	offset, word_en;
+	u8	*map;
+	u8	newdata[PGPKT_DATA_SIZE];
+	s32 i = 0, j = 0, idx;
+	u8	ret = _SUCCESS;
+	u16 mapLen = 1024;
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); /* have to be 8 byte alignment */
+	RT_ASSERT_RET((mapLen & 0x7) == 0); /* have to be PGPKT_DATA_SIZE alignment for memcpy */
+
+	map = rtw_zmalloc(mapLen);
+	if (map == NULL)
+		return _FAIL;
+
+	ret = rtw_BT_efuse_map_read(adapter, 0, mapLen, map);
+	if (ret == _FAIL)
+		goto exit;
+	RTW_INFO("OFFSET\tVALUE(hex)\n");
+	for (i = 0; i < mapLen; i += 16) { /* set 512 because the iwpriv's extra size have limit 0x7FF */
+		RTW_INFO("0x%03x\t", i);
+		for (j = 0; j < 8; j++)
+			RTW_INFO("%02X ", map[i + j]);
+		RTW_INFO("\t");
+		for (; j < 16; j++)
+			RTW_INFO("%02X ", map[i + j]);
+		RTW_INFO("\n");
+	}
+	RTW_INFO("\n");
+
+	idx = 0;
+	offset = (addr >> 3);
+	while (idx < cnts) {
+		word_en = 0xF;
+		j = (addr + idx) & 0x7;
+		_rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE);
+		for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) {
+			if (data[idx] != map[addr + idx]) {
+				word_en &= ~BIT(i >> 1);
+				newdata[i] = data[idx];
+			}
+		}
+
+		if (word_en != 0xF) {
+			ret = EfusePgPacketWrite_BT(adapter, offset, word_en, newdata, _FALSE);
+			RTW_INFO("offset=%x\n", offset);
+			RTW_INFO("word_en=%x\n", word_en);
+			RTW_INFO("%s: data=", __FUNCTION__);
+			for (i = 0; i < PGPKT_DATA_SIZE; i++)
+				RTW_INFO("0x%02X ", newdata[i]);
+			RTW_INFO("\n");
+			if (ret == _FAIL)
+				break;
+		}
+		offset++;
+	}
+exit:
+	rtw_mfree(map, mapLen);
+	return _SUCCESS;
+}
+
+VOID hal_ReadEFuse_BT_logic_map(
+	PADAPTER	padapter,
+	u16			_offset,
+	u16			_size_byte,
+	u8			*pbuf
+)
+{
+
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
+	PEFUSE_HAL		pEfuseHal = &pHalData->EfuseHal;
+
+	u8	*efuseTbl, *phyefuse;
+	u8	bank;
+	u16	eFuse_Addr = 0;
+	u8	efuseHeader, efuseExtHdr, efuseData;
+	u8	offset, wden;
+	u16	i, total, used;
+	u8	efuse_usage;
+
+
+	/* */
+	/* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */
+	/* */
+	if ((_offset + _size_byte) > EFUSE_BT_MAP_LEN) {
+		RTW_INFO("%s: Invalid offset(%#x) with read bytes(%#x)!!\n", __FUNCTION__, _offset, _size_byte);
+		return;
+	}
+
+	efuseTbl = rtw_malloc(EFUSE_BT_MAP_LEN);
+	phyefuse = rtw_malloc(EFUSE_BT_REAL_CONTENT_LEN);
+	if (efuseTbl == NULL || phyefuse == NULL) {
+		RTW_INFO("%s: efuseTbl or phyefuse malloc fail!\n", __FUNCTION__);
+		goto exit;
+	}
+
+	/* 0xff will be efuse default value instead of 0x00. */
+	_rtw_memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN);
+	_rtw_memset(phyefuse, 0xFF, EFUSE_BT_REAL_CONTENT_LEN);
+
+	if (rtw_efuse_bt_access(padapter, _FALSE, 0, EFUSE_BT_REAL_CONTENT_LEN, phyefuse))
+		dump_buf(phyefuse, EFUSE_BT_REAL_BANK_CONTENT_LEN);
+	
+	total = BANK_NUM;
+	for (bank = 1; bank <= total; bank++) { /* 8723d Max bake 0~2 */
+		eFuse_Addr = 0;
+
+		while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) {
+			/* ReadEFuseByte(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest); */
+			efuseHeader = phyefuse[eFuse_Addr++];
+
+			if (efuseHeader == 0xFF)
+				break;
+			RTW_INFO("%s: efuse[%#X]=0x%02x (header)\n", __FUNCTION__, (((bank - 1) * EFUSE_BT_REAL_CONTENT_LEN) + eFuse_Addr - 1), efuseHeader);
+
+			/* Check PG header for section num. */
+			if (EXT_HEADER(efuseHeader)) {	/* extended header */
+				offset = GET_HDR_OFFSET_2_0(efuseHeader);
+				RTW_INFO("%s: extended header offset_2_0=0x%X\n", __FUNCTION__, offset);
+
+				/* ReadEFuseByte(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest); */
+				efuseExtHdr = phyefuse[eFuse_Addr++];
+
+				RTW_INFO("%s: efuse[%#X]=0x%02x (ext header)\n", __FUNCTION__, (((bank - 1) * EFUSE_BT_REAL_CONTENT_LEN) + eFuse_Addr - 1), efuseExtHdr);
+				if (ALL_WORDS_DISABLED(efuseExtHdr))
+					continue;
+
+				offset |= ((efuseExtHdr & 0xF0) >> 1);
+				wden = (efuseExtHdr & 0x0F);
+			} else {
+				offset = ((efuseHeader >> 4) & 0x0f);
+				wden = (efuseHeader & 0x0f);
+			}
+
+			if (offset < EFUSE_BT_MAX_SECTION) {
+				u16 addr;
+
+				/* Get word enable value from PG header */
+				RTW_INFO("%s: Offset=%d Worden=%#X\n", __FUNCTION__, offset, wden);
+
+				addr = offset * PGPKT_DATA_SIZE;
+				for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+					/* Check word enable condition in the section */
+					if (!(wden & (0x01 << i))) {
+						efuseData = 0;
+						/* ReadEFuseByte(padapter, eFuse_Addr++, &efuseData, bPseudoTest); */
+						efuseData = phyefuse[eFuse_Addr++];
+
+						RTW_INFO("%s: efuse[%#X]=0x%02X\n", __FUNCTION__, eFuse_Addr - 1, efuseData);
+						efuseTbl[addr] = efuseData;
+
+						efuseData = 0;
+						/* ReadEFuseByte(padapter, eFuse_Addr++, &efuseData, bPseudoTest); */
+						efuseData = phyefuse[eFuse_Addr++];
+
+						RTW_INFO("%s: efuse[%#X]=0x%02X\n", __FUNCTION__, eFuse_Addr - 1, efuseData);
+						efuseTbl[addr + 1] = efuseData;
+					}
+					addr += 2;
+				}
+			} else {
+				RTW_INFO("%s: offset(%d) is illegal!!\n", __FUNCTION__, offset);
+				eFuse_Addr += Efuse_CalculateWordCnts(wden) * 2;
+			}
+		}
+
+		if ((eFuse_Addr - 1) < total) {
+			RTW_INFO("%s: bank(%d) data end at %#x\n", __FUNCTION__, bank, eFuse_Addr - 1);
+			break;
+		}
+	}
+
+	/* switch bank back to bank 0 for later BT and wifi use. */
+	//hal_EfuseSwitchToBank(padapter, 0, bPseudoTest);
+
+	/* Copy from Efuse map to output pointer memory!!! */
+	for (i = 0; i < _size_byte; i++)
+		pbuf[i] = efuseTbl[_offset + i];
+	/* Calculate Efuse utilization */
+	total = EFUSE_BT_REAL_BANK_CONTENT_LEN;
+
+	used = eFuse_Addr - 1;
+
+	if (total)
+		efuse_usage = (u8)((used * 100) / total);
+	else
+		efuse_usage = 100;
+
+	fakeBTEfuseUsedBytes = used;
+	RTW_INFO("%s: BTEfuseUsed last Bytes = %#x\n", __FUNCTION__, fakeBTEfuseUsedBytes);
+
+exit:
+	if (efuseTbl)
+		rtw_mfree(efuseTbl, EFUSE_BT_MAP_LEN);
+	if (phyefuse)
+		rtw_mfree(phyefuse, EFUSE_BT_REAL_BANK_CONTENT_LEN);
+}
+
+
+static u8 hal_EfusePartialWriteCheck(
+	PADAPTER		padapter,
+	u8				efuseType,
+	u16				*pAddr,
+	PPGPKT_STRUCT	pTargetPkt,
+	u8				bPseudoTest)
+{
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
+	PEFUSE_HAL		pEfuseHal = &pHalData->EfuseHal;
+	u8	bRet = _FALSE;
+	u16	startAddr = 0, efuse_max_available_len = EFUSE_BT_REAL_BANK_CONTENT_LEN, efuse_max = EFUSE_BT_REAL_BANK_CONTENT_LEN;
+	u8	efuse_data = 0;
+
+	startAddr = (u16)fakeBTEfuseUsedBytes;
+
+	startAddr %= efuse_max;
+	RTW_INFO("%s: startAddr=%#X\n", __FUNCTION__, startAddr);
+
+	while (1) {
+		if (startAddr >= efuse_max_available_len) {
+			bRet = _FALSE;
+			RTW_INFO("%s: startAddr(%d) >= efuse_max_available_len(%d)\n",
+				__FUNCTION__, startAddr, efuse_max_available_len);
+			break;
+		}
+		if (rtw_efuse_bt_access(padapter, _FALSE, startAddr, 1, &efuse_data)&& (efuse_data != 0xFF)) {
+			bRet = _FALSE;
+			RTW_INFO("%s: Something Wrong! last bytes(%#X=0x%02X) is not 0xFF\n",
+				 __FUNCTION__, startAddr, efuse_data);
+			break;
+		} else {
+			/* not used header, 0xff */
+			*pAddr = startAddr;
+			/*			RTW_INFO("%s: Started from unused header offset=%d\n", __FUNCTION__, startAddr)); */
+			bRet = _TRUE;
+			break;
+		}
+	}
+
+	return bRet;
+}
+
+
+static u8 hal_EfusePgPacketWrite2ByteHeader(
+	PADAPTER		padapter,
+	u8				efuseType,
+	u16				*pAddr,
+	PPGPKT_STRUCT	pTargetPkt,
+	u8				bPseudoTest)
+{
+	u16	efuse_addr, efuse_max_available_len = EFUSE_BT_REAL_BANK_CONTENT_LEN;
+	u8	pg_header = 0, tmp_header = 0;
+	u8	repeatcnt = 0;
+
+	/*	RTW_INFO("%s\n", __FUNCTION__); */
+
+	efuse_addr = *pAddr;
+	if (efuse_addr >= efuse_max_available_len) {
+		RTW_INFO("%s: addr(%d) over avaliable(%d)!!\n", __FUNCTION__, efuse_addr, efuse_max_available_len);
+		return _FALSE;
+	}
+
+	pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F;
+	/*	RTW_INFO("%s: pg_header=0x%x\n", __FUNCTION__, pg_header); */
+
+	do {
+		
+		rtw_efuse_bt_access(padapter, _TRUE, efuse_addr, 1, &pg_header);
+		rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &tmp_header);
+
+		if (tmp_header != 0xFF)
+			break;
+		if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+			RTW_INFO("%s: Repeat over limit for pg_header!!\n", __FUNCTION__);
+			return _FALSE;
+		}
+	} while (1);
+
+	if (tmp_header != pg_header) {
+		RTW_ERR("%s: PG Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header);
+		return _FALSE;
+	}
+
+	/* to write ext_header */
+	efuse_addr++;
+	pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en;
+
+	do {
+		rtw_efuse_bt_access(padapter, _TRUE, efuse_addr, 1, &pg_header);
+		rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &tmp_header);
+
+		if (tmp_header != 0xFF)
+			break;
+		if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+			RTW_INFO("%s: Repeat over limit for ext_header!!\n", __FUNCTION__);
+			return _FALSE;
+		}
+	} while (1);
+
+	if (tmp_header != pg_header) {	/* offset PG fail */
+		RTW_ERR("%s: PG EXT Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header);
+		return _FALSE;
+	}
+
+	*pAddr = efuse_addr;
+
+	return _TRUE;
+}
+
+
+static u8 hal_EfusePgPacketWrite1ByteHeader(
+	PADAPTER		pAdapter,
+	u8				efuseType,
+	u16				*pAddr,
+	PPGPKT_STRUCT	pTargetPkt,
+	u8				bPseudoTest)
+{
+	u8	bRet = _FALSE;
+	u8	pg_header = 0, tmp_header = 0;
+	u16	efuse_addr = *pAddr;
+	u8	repeatcnt = 0;
+
+
+	/*	RTW_INFO("%s\n", __FUNCTION__); */
+	pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en;
+
+	do {
+		rtw_efuse_bt_access(pAdapter, _TRUE, efuse_addr, 1, &pg_header);
+		rtw_efuse_bt_access(pAdapter, _FALSE, efuse_addr, 1, &tmp_header);
+
+		if (tmp_header != 0xFF)
+			break;
+		if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+			RTW_INFO("%s: Repeat over limit for pg_header!!\n", __FUNCTION__);
+			return _FALSE;
+		}
+	} while (1);
+
+	if (tmp_header != pg_header) {
+		RTW_ERR("%s: PG Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header);
+		return _FALSE;
+	}
+
+	*pAddr = efuse_addr;
+
+	return _TRUE;
+}
+
+static u8 hal_EfusePgPacketWriteHeader(
+	PADAPTER		padapter,
+	u8				efuseType,
+	u16				*pAddr,
+	PPGPKT_STRUCT	pTargetPkt,
+	u8				bPseudoTest)
+{
+	u8 bRet = _FALSE;
+
+	if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE)
+		bRet = hal_EfusePgPacketWrite2ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest);
+	else
+		bRet = hal_EfusePgPacketWrite1ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest);
+
+	return bRet;
+}
+
+
+static u8
+Hal_EfuseWordEnableDataWrite(
+	PADAPTER	padapter,
+	u16			efuse_addr,
+	u8			word_en,
+	u8			*data,
+	u8			bPseudoTest)
+{
+	u16	tmpaddr = 0;
+	u16	start_addr = efuse_addr;
+	u8	badworden = 0x0F;
+	u8	tmpdata[PGPKT_DATA_SIZE];
+
+
+	/*	RTW_INFO("%s: efuse_addr=%#x word_en=%#x\n", __FUNCTION__, efuse_addr, word_en); */
+	_rtw_memset(tmpdata, 0xFF, PGPKT_DATA_SIZE);
+
+	if (!(word_en & BIT(0))) {
+		tmpaddr = start_addr;
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[0]);
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[1]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[0]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[1]);
+		if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1]))
+			badworden &= (~BIT(0));
+	}
+	if (!(word_en & BIT(1))) {
+		tmpaddr = start_addr;
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[2]);
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[3]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[2]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[3]);
+		if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3]))
+			badworden &= (~BIT(1));
+	}
+	if (!(word_en & BIT(2))) {
+		tmpaddr = start_addr;
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[4]);
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[5]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[4]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[5]);
+		if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5]))
+			badworden &= (~BIT(2));
+	}
+	if (!(word_en & BIT(3))) {
+		tmpaddr = start_addr;
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[6]);
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[7]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[6]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[7]);
+
+		if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7]))
+			badworden &= (~BIT(3));
+	}
+
+	return badworden;
+}
+
+static void
+hal_EfuseConstructPGPkt(
+	u8				offset,
+	u8				word_en,
+	u8				*pData,
+	PPGPKT_STRUCT	pTargetPkt)
+{
+	_rtw_memset(pTargetPkt->data, 0xFF, PGPKT_DATA_SIZE);
+	pTargetPkt->offset = offset;
+	pTargetPkt->word_en = word_en;
+	efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data);
+	pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
+}
+
+static u8
+hal_EfusePgPacketWriteData(
+	PADAPTER		pAdapter,
+	u8				efuseType,
+	u16				*pAddr,
+	PPGPKT_STRUCT	pTargetPkt,
+	u8				bPseudoTest)
+{
+	u16	efuse_addr;
+	u8	badworden;
+
+	efuse_addr = *pAddr;
+	badworden = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr + 1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest);
+	if (badworden != 0x0F) {
+		RTW_INFO("%s: Fail!!\n", __FUNCTION__);
+		return _FALSE;
+	} else
+		RTW_INFO("%s: OK!!\n", __FUNCTION__);
+
+	return _TRUE;
+}
+
+u8 efuse_OneByteRead(struct _ADAPTER *a, u16 addr, u8 *data, u8 bPseudoTest)
+{
+		struct dvobj_priv *d;
+		int err;
+		u8 ret = _TRUE;
+
+		d = adapter_to_dvobj(a);
+		err = rtw_halmac_read_physical_efuse(d, addr, 1, data);
+		if (err) {
+			RTW_ERR("%s: addr=0x%x FAIL!!!\n", __FUNCTION__, addr);
+			ret = _FALSE;
+		}
+
+		return ret;
+	
+}
+
+static u16
+hal_EfuseGetCurrentSize_BT(
+	PADAPTER	padapter,
+	u8			bPseudoTest)
+{
+#ifdef HAL_EFUSE_MEMORY
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
+	PEFUSE_HAL		pEfuseHal = &pHalData->EfuseHal;
+#endif
+	u16 btusedbytes;
+	u16	efuse_addr;
+	u8	bank, startBank;
+	u8	hoffset = 0, hworden = 0;
+	u8	efuse_data, word_cnts = 0;
+	u16	retU2 = 0;
+	u8 bContinual = _TRUE;
+
+
+	btusedbytes = fakeBTEfuseUsedBytes;
+
+	efuse_addr = (u16)((btusedbytes % EFUSE_BT_REAL_BANK_CONTENT_LEN));
+	startBank = (u8)(1 + (btusedbytes / EFUSE_BT_REAL_BANK_CONTENT_LEN));
+
+	RTW_INFO("%s: start from bank=%d addr=0x%X\n", __FUNCTION__, startBank, efuse_addr);
+	retU2 = EFUSE_BT_REAL_CONTENT_LEN - EFUSE_PROTECT_BYTES_BANK;
+
+	for (bank = startBank; bank < 3; bank++) {
+		if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == _FALSE) {
+			RTW_ERR("%s: switch bank(%d) Fail!!\n", __FUNCTION__, bank);
+			/* bank = EFUSE_MAX_BANK; */
+			break;
+		}
+
+		/* only when bank is switched we have to reset the efuse_addr. */
+		if (bank != startBank)
+			efuse_addr = 0;
+
+
+		while (AVAILABLE_EFUSE_ADDR(efuse_addr)) {
+			if (rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &efuse_data) == _FALSE) {
+				RTW_ERR("%s: efuse_OneByteRead Fail! addr=0x%X !!\n", __FUNCTION__, efuse_addr);
+				/* bank = EFUSE_MAX_BANK; */
+				break;
+			}
+			RTW_INFO("%s: efuse_OneByteRead ! addr=0x%X !efuse_data=0x%X! bank =%d\n", __FUNCTION__, efuse_addr, efuse_data, bank);
+
+			if (efuse_data == 0xFF)
+				break;
+
+			if (EXT_HEADER(efuse_data)) {
+				hoffset = GET_HDR_OFFSET_2_0(efuse_data);
+				efuse_addr++;
+				rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &efuse_data);
+				RTW_INFO("%s: efuse_OneByteRead EXT_HEADER ! addr=0x%X !efuse_data=0x%X! bank =%d\n", __FUNCTION__, efuse_addr, efuse_data, bank);
+
+				if (ALL_WORDS_DISABLED(efuse_data)) {
+					efuse_addr++;
+					continue;
+				}
+
+				/*				hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); */
+				hoffset |= ((efuse_data & 0xF0) >> 1);
+				hworden = efuse_data & 0x0F;
+			} else {
+				hoffset = (efuse_data >> 4) & 0x0F;
+				hworden =  efuse_data & 0x0F;
+			}
+
+			RTW_INFO(FUNC_ADPT_FMT": Offset=%d Worden=%#X\n",
+				 FUNC_ADPT_ARG(padapter), hoffset, hworden);
+
+			word_cnts = Efuse_CalculateWordCnts(hworden);
+			/* read next header */
+			efuse_addr += (word_cnts * 2) + 1;
+		}
+		/* Check if we need to check next bank efuse */
+		if (efuse_addr < retU2)
+			break;/* don't need to check next bank. */
+	}
+	retU2 = ((bank - 1) * EFUSE_BT_REAL_BANK_CONTENT_LEN) + efuse_addr;
+
+	fakeBTEfuseUsedBytes = retU2;
+	RTW_INFO("%s: CurrentSize=%d\n", __FUNCTION__, retU2);
+	return retU2;
+}
+
+
+static u8
+hal_BT_EfusePgCheckAvailableAddr(
+	PADAPTER	pAdapter,
+	u8		bPseudoTest)
+{
+	u16	max_available = EFUSE_BT_REAL_CONTENT_LEN - EFUSE_PROTECT_BYTES_BANK;
+	u16	current_size = 0;
+
+	 RTW_INFO("%s: max_available=%d\n", __FUNCTION__, max_available);
+	current_size = hal_EfuseGetCurrentSize_BT(pAdapter, bPseudoTest);
+	if (current_size >= max_available) {
+		RTW_INFO("%s: Error!! current_size(%d)>max_available(%d)\n", __FUNCTION__, current_size, max_available);
+		return _FALSE;
+	}
+	return _TRUE;
+}
+
+u8 EfusePgPacketWrite_BT(
+	PADAPTER	pAdapter,
+	u8			offset,
+	u8			word_en,
+	u8			*pData,
+	u8			bPseudoTest)
+{
+	PGPKT_STRUCT targetPkt;
+	u16 startAddr = 0;
+	u8 efuseType = EFUSE_BT;
+
+	if (!hal_BT_EfusePgCheckAvailableAddr(pAdapter, bPseudoTest))
+		return _FALSE;
+
+	hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt);
+
+	if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
+		return _FALSE;
+
+	if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
+		return _FALSE;
+
+	if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
+		return _FALSE;
+
+	return _TRUE;
+}
+
+
+#else /* !RTW_HALMAC */
+/* ------------------------------------------------------------------------------ */
+#define REG_EFUSE_CTRL		0x0030
+#define EFUSE_CTRL			REG_EFUSE_CTRL		/* E-Fuse Control. */
+/* ------------------------------------------------------------------------------ */
+
+
+BOOLEAN
+Efuse_Read1ByteFromFakeContent(
+	IN		PADAPTER	pAdapter,
+	IN		u16		Offset,
+	IN OUT	u8		*Value);
+BOOLEAN
+Efuse_Read1ByteFromFakeContent(
+	IN		PADAPTER	pAdapter,
+	IN		u16		Offset,
+	IN OUT	u8		*Value)
+{
+	if (Offset >= EFUSE_MAX_HW_SIZE)
+		return _FALSE;
+	/* DbgPrint("Read fake content, offset = %d\n", Offset); */
+	if (fakeEfuseBank == 0)
+		*Value = fakeEfuseContent[Offset];
+	else
+		*Value = fakeBTEfuseContent[fakeEfuseBank - 1][Offset];
+	return _TRUE;
+}
+
+BOOLEAN
+Efuse_Write1ByteToFakeContent(
+	IN		PADAPTER	pAdapter,
+	IN		u16		Offset,
+	IN		u8		Value);
+BOOLEAN
+Efuse_Write1ByteToFakeContent(
+	IN		PADAPTER	pAdapter,
+	IN		u16		Offset,
+	IN		u8		Value)
+{
+	if (Offset >= EFUSE_MAX_HW_SIZE)
+		return _FALSE;
+	if (fakeEfuseBank == 0)
+		fakeEfuseContent[Offset] = Value;
+	else
+		fakeBTEfuseContent[fakeEfuseBank - 1][Offset] = Value;
+	return _TRUE;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	Efuse_PowerSwitch
+ *
+ * Overview:	When we want to enable write operation, we should change to
+ *				pwr on state. When we stop write, we should switch to 500k mode
+ *				and disable LDO 2.5V.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/17/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+VOID
+Efuse_PowerSwitch(
+	IN	PADAPTER	pAdapter,
+	IN	u8		bWrite,
+	IN	u8		PwrState)
+{
+	pAdapter->hal_func.EfusePowerSwitch(pAdapter, bWrite, PwrState);
+}
+
+VOID
+BTEfuse_PowerSwitch(
+	IN	PADAPTER	pAdapter,
+	IN	u8		bWrite,
+	IN	u8		PwrState)
+{
+	if (pAdapter->hal_func.BTEfusePowerSwitch)
+		pAdapter->hal_func.BTEfusePowerSwitch(pAdapter, bWrite, PwrState);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_GetCurrentSize
+ *
+ * Overview:	Get current efuse size!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/16/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+u16
+Efuse_GetCurrentSize(
+	IN PADAPTER		pAdapter,
+	IN u8			efuseType,
+	IN BOOLEAN		bPseudoTest)
+{
+	u16 ret = 0;
+
+	ret = pAdapter->hal_func.EfuseGetCurrentSize(pAdapter, efuseType, bPseudoTest);
+
+	return ret;
+}
+
+/*
+ *	Description:
+ *		Execute E-Fuse read byte operation.
+ *		Refered from SD1 Richard.
+ *
+ *	Assumption:
+ *		1. Boot from E-Fuse and successfully auto-load.
+ *		2. PASSIVE_LEVEL (USB interface)
+ *
+ *	Created by Roger, 2008.10.21.
+ *   */
+VOID
+ReadEFuseByte(
+	PADAPTER	Adapter,
+	u16			_offset,
+	u8			*pbuf,
+	IN BOOLEAN	bPseudoTest)
+{
+	u32	value32;
+	u8	readbyte;
+	u16	retry;
+	/* systime start=rtw_get_current_time(); */
+
+	if (bPseudoTest) {
+		Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf);
+		return;
+	}
+	if (IS_HARDWARE_TYPE_8723B(Adapter)) {
+		/* <20130121, Kordan> For SMIC S55 EFUSE specificatoin. */
+		/* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */
+		phy_set_mac_reg(Adapter, EFUSE_TEST, BIT11, 0);
+	}
+	/* Write Address */
+	rtw_write8(Adapter, EFUSE_CTRL + 1, (_offset & 0xff));
+	readbyte = rtw_read8(Adapter, EFUSE_CTRL + 2);
+	rtw_write8(Adapter, EFUSE_CTRL + 2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc));
+
+	/* Write bit 32 0 */
+	readbyte = rtw_read8(Adapter, EFUSE_CTRL + 3);
+	rtw_write8(Adapter, EFUSE_CTRL + 3, (readbyte & 0x7f));
+
+	/* Check bit 32 read-ready */
+	retry = 0;
+	value32 = rtw_read32(Adapter, EFUSE_CTRL);
+	/* while(!(((value32 >> 24) & 0xff) & 0x80)  && (retry<10)) */
+	while (!(((value32 >> 24) & 0xff) & 0x80)  && (retry < 10000)) {
+		value32 = rtw_read32(Adapter, EFUSE_CTRL);
+		retry++;
+	}
+
+	/* 20100205 Joseph: Add delay suggested by SD1 Victor. */
+	/* This fix the problem that Efuse read error in high temperature condition. */
+	/* Designer says that there shall be some delay after ready bit is set, or the */
+	/* result will always stay on last data we read. */
+	rtw_udelay_os(50);
+	value32 = rtw_read32(Adapter, EFUSE_CTRL);
+
+	*pbuf = (u8)(value32 & 0xff);
+	/* RTW_INFO("ReadEFuseByte _offset:%08u, in %d ms\n",_offset ,rtw_get_passing_time_ms(start)); */
+
+}
+
+/*
+ *	Description:
+ *		1. Execute E-Fuse read byte operation according as map offset and
+ *		    save to E-Fuse table.
+ *		2. Refered from SD1 Richard.
+ *
+ *	Assumption:
+ *		1. Boot from E-Fuse and successfully auto-load.
+ *		2. PASSIVE_LEVEL (USB interface)
+ *
+ *	Created by Roger, 2008.10.21.
+ *
+ *	2008/12/12 MH	1. Reorganize code flow and reserve bytes. and add description.
+ *					2. Add efuse utilization collect.
+ *	2008/12/22 MH	Read Efuse must check if we write section 1 data again!!! Sec1
+ *					write addr must be after sec5.
+ *   */
+
+VOID
+efuse_ReadEFuse(
+	PADAPTER	Adapter,
+	u8		efuseType,
+	u16		_offset,
+	u16		_size_byte,
+	u8	*pbuf,
+	IN	BOOLEAN	bPseudoTest
+);
+VOID
+efuse_ReadEFuse(
+	PADAPTER	Adapter,
+	u8		efuseType,
+	u16		_offset,
+	u16		_size_byte,
+	u8	*pbuf,
+	IN	BOOLEAN	bPseudoTest
+)
+{
+	Adapter->hal_func.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest);
+}
+
+VOID
+EFUSE_GetEfuseDefinition(
+	IN		PADAPTER	pAdapter,
+	IN		u8		efuseType,
+	IN		u8		type,
+	OUT		void		*pOut,
+	IN		BOOLEAN		bPseudoTest
+)
+{
+	pAdapter->hal_func.EFUSEGetEfuseDefinition(pAdapter, efuseType, type, pOut, bPseudoTest);
+}
+
+
+/*  11/16/2008 MH Read one byte from real Efuse. */
+u8
+efuse_OneByteRead(
+	IN	PADAPTER	pAdapter,
+	IN	u16			addr,
+	IN	u8			*data,
+	IN	BOOLEAN		bPseudoTest)
+{
+	u32	tmpidx = 0;
+	u8	bResult;
+	u8	readbyte;
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(pAdapter);
+
+	/* RTW_INFO("===> EFUSE_OneByteRead(), addr = %x\n", addr); */
+	/* RTW_INFO("===> EFUSE_OneByteRead() start, 0x34 = 0x%X\n", rtw_read32(pAdapter, EFUSE_TEST)); */
+
+	if (bPseudoTest) {
+		bResult = Efuse_Read1ByteFromFakeContent(pAdapter, addr, data);
+		return bResult;
+	}
+
+	if (IS_HARDWARE_TYPE_8723B(pAdapter) ||
+	    (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) ||
+	    (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id))
+	   ) {
+		/* <20130121, Kordan> For SMIC EFUSE specificatoin. */
+		/* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8])	 */
+		/* phy_set_mac_reg(pAdapter, 0x34, BIT11, 0); */
+		rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter, 0x34) & (~BIT11));
+	}
+
+	/* -----------------e-fuse reg ctrl --------------------------------- */
+	/* address			 */
+	rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff));
+	rtw_write8(pAdapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
+		   (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC));
+
+	/* rtw_write8(pAdapter, EFUSE_CTRL+3,  0x72); */ /* read cmd	 */
+	/* Write bit 32 0 */
+	readbyte = rtw_read8(pAdapter, EFUSE_CTRL + 3);
+	rtw_write8(pAdapter, EFUSE_CTRL + 3, (readbyte & 0x7f));
+
+	while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 1000)) {
+		rtw_mdelay_os(1);
+		tmpidx++;
+	}
+	if (tmpidx < 100) {
+		*data = rtw_read8(pAdapter, EFUSE_CTRL);
+		bResult = _TRUE;
+	} else {
+		*data = 0xff;
+		bResult = _FALSE;
+		RTW_INFO("%s: [ERROR] addr=0x%x bResult=%d time out 1s !!!\n", __FUNCTION__, addr, bResult);
+		RTW_INFO("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL));
+	}
+
+	return bResult;
+}
+
+/*  11/16/2008 MH Write one byte to reald Efuse. */
+u8
+efuse_OneByteWrite(
+	IN	PADAPTER	pAdapter,
+	IN	u16			addr,
+	IN	u8			data,
+	IN	BOOLEAN		bPseudoTest)
+{
+	u8	tmpidx = 0;
+	u8	bResult = _FALSE;
+	u32 efuseValue = 0;
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(pAdapter);
+
+	/* RTW_INFO("===> EFUSE_OneByteWrite(), addr = %x data=%x\n", addr, data); */
+	/* RTW_INFO("===> EFUSE_OneByteWrite() start, 0x34 = 0x%X\n", rtw_read32(pAdapter, EFUSE_TEST)); */
+
+	if (bPseudoTest) {
+		bResult = Efuse_Write1ByteToFakeContent(pAdapter, addr, data);
+		return bResult;
+	}
+
+	Efuse_PowerSwitch(pAdapter, _TRUE, _TRUE);
+
+	/* -----------------e-fuse reg ctrl ---------------------------------	 */
+	/* address			 */
+
+
+	efuseValue = rtw_read32(pAdapter, EFUSE_CTRL);
+	efuseValue |= (BIT21 | BIT31);
+	efuseValue &= ~(0x3FFFF);
+	efuseValue |= ((addr << 8 | data) & 0x3FFFF);
+
+	/* <20130227, Kordan> 8192E MP chip A-cut had better not set 0x34[11] until B-Cut. */
+	if (IS_HARDWARE_TYPE_8723B(pAdapter) ||
+	    (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) ||
+	    (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id))
+	   ) {
+		/* <20130121, Kordan> For SMIC EFUSE specificatoin. */
+		/* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */
+		/* phy_set_mac_reg(pAdapter, 0x34, BIT11, 1); */
+		rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter, 0x34) | (BIT11));
+		rtw_write32(pAdapter, EFUSE_CTRL, 0x90600000 | ((addr << 8 | data)));
+	} else
+		rtw_write32(pAdapter, EFUSE_CTRL, efuseValue);
+
+	rtw_mdelay_os(1);
+
+	while ((0x80 &  rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100)) {
+		rtw_mdelay_os(1);
+		tmpidx++;
+	}
+
+	if (tmpidx < 100)
+		bResult = _TRUE;
+	else {
+		bResult = _FALSE;
+		RTW_INFO("%s: [ERROR] addr=0x%x ,efuseValue=0x%x ,bResult=%d time out 1s !!!\n",
+			 __FUNCTION__, addr, efuseValue, bResult);
+		RTW_INFO("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL));
+	}
+
+	/* disable Efuse program enable */
+	if (IS_HARDWARE_TYPE_8723B(pAdapter) ||
+	    (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) ||
+	    (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id))
+	   )
+		phy_set_mac_reg(pAdapter, EFUSE_TEST, BIT(11), 0);
+
+	Efuse_PowerSwitch(pAdapter, _TRUE, _FALSE);
+
+	return bResult;
+}
+
+int
+Efuse_PgPacketRead(IN	PADAPTER	pAdapter,
+		   IN	u8			offset,
+		   IN	u8			*data,
+		   IN	BOOLEAN		bPseudoTest)
+{
+	int	ret = 0;
+
+	ret =  pAdapter->hal_func.Efuse_PgPacketRead(pAdapter, offset, data, bPseudoTest);
+
+	return ret;
+}
+
+int
+Efuse_PgPacketWrite(IN	PADAPTER	pAdapter,
+		    IN	u8			offset,
+		    IN	u8			word_en,
+		    IN	u8			*data,
+		    IN	BOOLEAN		bPseudoTest)
+{
+	int ret;
+
+	ret =  pAdapter->hal_func.Efuse_PgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest);
+
+	return ret;
+}
+
+
+int
+Efuse_PgPacketWrite_BT(IN	PADAPTER	pAdapter,
+		       IN	u8			offset,
+		       IN	u8			word_en,
+		       IN	u8			*data,
+		       IN	BOOLEAN		bPseudoTest)
+{
+	int ret;
+
+	ret =  pAdapter->hal_func.Efuse_PgPacketWrite_BT(pAdapter, offset, word_en, data, bPseudoTest);
+
+	return ret;
+}
+
+
+u8
+Efuse_WordEnableDataWrite(IN	PADAPTER	pAdapter,
+			  IN	u16		efuse_addr,
+			  IN	u8		word_en,
+			  IN	u8		*data,
+			  IN	BOOLEAN		bPseudoTest)
+{
+	u8	ret = 0;
+
+	ret =  pAdapter->hal_func.Efuse_WordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest);
+
+	return ret;
+}
+
+static u8 efuse_read8(PADAPTER padapter, u16 address, u8 *value)
+{
+	return efuse_OneByteRead(padapter, address, value, _FALSE);
+}
+
+static u8 efuse_write8(PADAPTER padapter, u16 address, u8 *value)
+{
+	return efuse_OneByteWrite(padapter, address, *value, _FALSE);
+}
+
+/*
+ * read/wirte raw efuse data
+ */
+u8 rtw_efuse_access(PADAPTER padapter, u8 bWrite, u16 start_addr, u16 cnts, u8 *data)
+{
+	int i = 0;
+	u16	real_content_len = 0, max_available_size = 0;
+	u8 res = _FAIL ;
+	u8(*rw8)(PADAPTER, u16, u8 *);
+	u32	backupRegs[4] = {0};
+
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&real_content_len, _FALSE);
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE);
+
+	if (start_addr > real_content_len)
+		return _FAIL;
+
+	if (_TRUE == bWrite) {
+		if ((start_addr + cnts) > max_available_size)
+			return _FAIL;
+		rw8 = &efuse_write8;
+	} else
+		rw8 = &efuse_read8;
+
+	efuse_PreUpdateAction(padapter, backupRegs);
+
+	Efuse_PowerSwitch(padapter, bWrite, _TRUE);
+
+	/* e-fuse one byte read / write */
+	for (i = 0; i < cnts; i++) {
+		if (start_addr >= real_content_len) {
+			res = _FAIL;
+			break;
+		}
+
+		res = rw8(padapter, start_addr++, data++);
+		if (_FAIL == res)
+			break;
+	}
+
+	Efuse_PowerSwitch(padapter, bWrite, _FALSE);
+
+	efuse_PostUpdateAction(padapter, backupRegs);
+
+	return res;
+}
+/* ------------------------------------------------------------------------------ */
+u16 efuse_GetMaxSize(PADAPTER padapter)
+{
+	u16	max_size;
+
+	max_size = 0;
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_size, _FALSE);
+	return max_size;
+}
+/* ------------------------------------------------------------------------------ */
+u8 efuse_GetCurrentSize(PADAPTER padapter, u16 *size)
+{
+	Efuse_PowerSwitch(padapter, _FALSE, _TRUE);
+	*size = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, _FALSE);
+	Efuse_PowerSwitch(padapter, _FALSE, _FALSE);
+
+	return _SUCCESS;
+}
+/* ------------------------------------------------------------------------------ */
+u16 efuse_bt_GetMaxSize(PADAPTER padapter)
+{
+	u16	max_size;
+
+	max_size = 0;
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_BT , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_size, _FALSE);
+	return max_size;
+}
+
+u8 efuse_bt_GetCurrentSize(PADAPTER padapter, u16 *size)
+{
+	Efuse_PowerSwitch(padapter, _FALSE, _TRUE);
+	*size = Efuse_GetCurrentSize(padapter, EFUSE_BT, _FALSE);
+	Efuse_PowerSwitch(padapter, _FALSE, _FALSE);
+
+	return _SUCCESS;
+}
+
+u8 rtw_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u16	mapLen = 0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	Efuse_PowerSwitch(padapter, _FALSE, _TRUE);
+
+	efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data, _FALSE);
+
+	Efuse_PowerSwitch(padapter, _FALSE, _FALSE);
+
+	return _SUCCESS;
+}
+
+u8 rtw_BT_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u16	mapLen = 0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	Efuse_PowerSwitch(padapter, _FALSE, _TRUE);
+
+	efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data, _FALSE);
+
+	Efuse_PowerSwitch(padapter, _FALSE, _FALSE);
+
+	return _SUCCESS;
+}
+
+/* ------------------------------------------------------------------------------ */
+u8 rtw_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+#define RT_ASSERT_RET(expr)												\
+	if (!(expr)) {															\
+		printk("Assertion failed! %s at ......\n", #expr);							\
+		printk("      ......%s,%s, line=%d\n",__FILE__, __FUNCTION__, __LINE__);	\
+		return _FAIL;	\
+	}
+
+	u8	offset, word_en;
+	u8	*map;
+	u8	newdata[PGPKT_DATA_SIZE];
+	s32	i, j, idx, chk_total_byte;
+	u8	ret = _SUCCESS;
+	u16	mapLen = 0, startAddr = 0, efuse_max_available_len = 0;
+	u32	backupRegs[4] = {0};
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+	PEFUSE_HAL	pEfuseHal = &pHalData->EfuseHal;
+
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_max_available_len, _FALSE);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); /* have to be 8 byte alignment */
+	RT_ASSERT_RET((mapLen & 0x7) == 0); /* have to be PGPKT_DATA_SIZE alignment for memcpy */
+
+	map = rtw_zmalloc(mapLen);
+	if (map == NULL)
+		return _FAIL;
+
+	_rtw_memset(map, 0xFF, mapLen);
+
+	ret = rtw_efuse_map_read(padapter, 0, mapLen, map);
+	if (ret == _FAIL)
+		goto exit;
+
+	if (padapter->registrypriv.boffefusemask == 0) {
+		for (i = 0; i < cnts; i++) {
+			if (padapter->registrypriv.bFileMaskEfuse == _TRUE) {
+				if (rtw_file_efuse_IsMasked(padapter, addr + i))	/*use file efuse mask. */
+					data[i] = map[addr + i];
+			} else {
+				if (efuse_IsMasked(padapter, addr + i))
+					data[i] = map[addr + i];
+			}
+			RTW_INFO("%s , data[%d] = %x, map[addr+i]= %x\n", __func__, i, data[i], map[addr + i]);
+		}
+	}
+	/*Efuse_PowerSwitch(padapter, _TRUE, _TRUE);*/
+
+	chk_total_byte = 0;
+	idx = 0;
+	offset = (addr >> 3);
+
+	while (idx < cnts) {
+		word_en = 0xF;
+		j = (addr + idx) & 0x7;
+		for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) {
+			if (data[idx] != map[addr + idx])
+				word_en &= ~BIT(i >> 1);
+		}
+
+		if (word_en != 0xF) {
+			chk_total_byte += Efuse_CalculateWordCnts(word_en) * 2;
+
+			if (offset >= EFUSE_MAX_SECTION_BASE) /* Over EFUSE_MAX_SECTION 16 for 2 ByteHeader */
+				chk_total_byte += 2;
+			else
+				chk_total_byte += 1;
+		}
+
+		offset++;
+	}
+
+	RTW_INFO("Total PG bytes Count = %d\n", chk_total_byte);
+	rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr);
+
+	if (startAddr == 0) {
+		startAddr = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, _FALSE);
+		RTW_INFO("%s: Efuse_GetCurrentSize startAddr=%#X\n", __func__, startAddr);
+	}
+	RTW_DBG("%s: startAddr=%#X\n", __func__, startAddr);
+
+	if ((startAddr + chk_total_byte) >= efuse_max_available_len) {
+		RTW_INFO("%s: startAddr(0x%X) + PG data len %d >= efuse_max_available_len(0x%X)\n",
+			 __func__, startAddr, chk_total_byte, efuse_max_available_len);
+		ret = _FAIL;
+		goto exit;
+	}
+
+	efuse_PreUpdateAction(padapter, backupRegs);
+
+	idx = 0;
+	offset = (addr >> 3);
+	while (idx < cnts) {
+		word_en = 0xF;
+		j = (addr + idx) & 0x7;
+		_rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE);
+		for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) {
+			if (data[idx] != map[addr + idx]) {
+				word_en &= ~BIT(i >> 1);
+				newdata[i] = data[idx];
+#ifdef CONFIG_RTL8723B
+				if (addr + idx == 0x8) {
+					if (IS_C_CUT(pHalData->version_id) || IS_B_CUT(pHalData->version_id)) {
+						if (pHalData->adjuseVoltageVal == 6) {
+							newdata[i] = map[addr + idx];
+							RTW_INFO(" %s ,\n adjuseVoltageVal = %d ,newdata[%d] = %x\n", __func__, pHalData->adjuseVoltageVal, i, newdata[i]);
+						}
+					}
+				}
+#endif
+			}
+		}
+
+		if (word_en != 0xF) {
+			ret = Efuse_PgPacketWrite(padapter, offset, word_en, newdata, _FALSE);
+			RTW_INFO("offset=%x\n", offset);
+			RTW_INFO("word_en=%x\n", word_en);
+
+			for (i = 0; i < PGPKT_DATA_SIZE; i++)
+				RTW_INFO("data=%x \t", newdata[i]);
+			if (ret == _FAIL)
+				break;
+		}
+
+		offset++;
+	}
+
+	/*Efuse_PowerSwitch(padapter, _TRUE, _FALSE);*/
+
+	efuse_PostUpdateAction(padapter, backupRegs);
+
+exit:
+
+	rtw_mfree(map, mapLen);
+
+	return ret;
+}
+
+
+u8 rtw_BT_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+#define RT_ASSERT_RET(expr)												\
+	if (!(expr)) {															\
+		printk("Assertion failed! %s at ......\n", #expr);							\
+		printk("      ......%s,%s, line=%d\n",__FILE__, __FUNCTION__, __LINE__);	\
+		return _FAIL;	\
+	}
+
+	u8	offset, word_en;
+	u8	*map;
+	u8	newdata[PGPKT_DATA_SIZE];
+	s32	i = 0, j = 0, idx;
+	u8	ret = _SUCCESS;
+	u16	mapLen = 0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); /* have to be 8 byte alignment */
+	RT_ASSERT_RET((mapLen & 0x7) == 0); /* have to be PGPKT_DATA_SIZE alignment for memcpy */
+
+	map = rtw_zmalloc(mapLen);
+	if (map == NULL)
+		return _FAIL;
+
+	ret = rtw_BT_efuse_map_read(padapter, 0, mapLen, map);
+	if (ret == _FAIL)
+		goto exit;
+	RTW_INFO("OFFSET\tVALUE(hex)\n");
+	for (i = 0; i < 1024; i += 16) { /* set 512 because the iwpriv's extra size have limit 0x7FF */
+		RTW_INFO("0x%03x\t", i);
+		for (j = 0; j < 8; j++)
+			RTW_INFO("%02X ", map[i + j]);
+		RTW_INFO("\t");
+		for (; j < 16; j++)
+			RTW_INFO("%02X ", map[i + j]);
+		RTW_INFO("\n");
+	}
+	RTW_INFO("\n");
+	Efuse_PowerSwitch(padapter, _TRUE, _TRUE);
+
+	idx = 0;
+	offset = (addr >> 3);
+	while (idx < cnts) {
+		word_en = 0xF;
+		j = (addr + idx) & 0x7;
+		_rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE);
+		for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) {
+			if (data[idx] != map[addr + idx]) {
+				word_en &= ~BIT(i >> 1);
+				newdata[i] = data[idx];
+			}
+		}
+
+		if (word_en != 0xF) {
+			RTW_INFO("offset=%x\n", offset);
+			RTW_INFO("word_en=%x\n", word_en);
+			RTW_INFO("%s: data=", __FUNCTION__);
+			for (i = 0; i < PGPKT_DATA_SIZE; i++)
+				RTW_INFO("0x%02X ", newdata[i]);
+			RTW_INFO("\n");
+			ret = Efuse_PgPacketWrite_BT(padapter, offset, word_en, newdata, _FALSE);
+			if (ret == _FAIL)
+				break;
+		}
+
+		offset++;
+	}
+
+	Efuse_PowerSwitch(padapter, _TRUE, _FALSE);
+
+exit:
+
+	rtw_mfree(map, mapLen);
+
+	return ret;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	Efuse_ReadAllMap
+ *
+ * Overview:	Read All Efuse content
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/11/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+VOID
+Efuse_ReadAllMap(
+	IN		PADAPTER	pAdapter,
+	IN		u8		efuseType,
+	IN OUT	u8		*Efuse,
+	IN		BOOLEAN		bPseudoTest);
+VOID
+Efuse_ReadAllMap(
+	IN		PADAPTER	pAdapter,
+	IN		u8		efuseType,
+	IN OUT	u8		*Efuse,
+	IN		BOOLEAN		bPseudoTest)
+{
+	u16	mapLen = 0;
+
+	Efuse_PowerSwitch(pAdapter, _FALSE, _TRUE);
+
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest);
+
+	efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse, bPseudoTest);
+
+	Efuse_PowerSwitch(pAdapter, _FALSE, _FALSE);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_ShadowWrite1Byte
+ *			efuse_ShadowWrite2Byte
+ *			efuse_ShadowWrite4Byte
+ *
+ * Overview:	Write efuse modify map by one/two/four byte.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/12/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+#ifdef PLATFORM
+static VOID
+efuse_ShadowWrite1Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN	u8		Value);
+#endif /* PLATFORM */
+static VOID
+efuse_ShadowWrite1Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN	u8		Value)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	pHalData->efuse_eeprom_data[Offset] = Value;
+
+}	/* efuse_ShadowWrite1Byte */
+
+/* ---------------Write Two Bytes */
+static VOID
+efuse_ShadowWrite2Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN	u16		Value)
+{
+
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+
+	pHalData->efuse_eeprom_data[Offset] = Value & 0x00FF;
+	pHalData->efuse_eeprom_data[Offset + 1] = Value >> 8;
+
+}	/* efuse_ShadowWrite1Byte */
+
+/* ---------------Write Four Bytes */
+static VOID
+efuse_ShadowWrite4Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN	u32		Value)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	pHalData->efuse_eeprom_data[Offset] = (u8)(Value & 0x000000FF);
+	pHalData->efuse_eeprom_data[Offset + 1] = (u8)((Value >> 8) & 0x0000FF);
+	pHalData->efuse_eeprom_data[Offset + 2] = (u8)((Value >> 16) & 0x00FF);
+	pHalData->efuse_eeprom_data[Offset + 3] = (u8)((Value >> 24) & 0xFF);
+
+}	/* efuse_ShadowWrite1Byte */
+
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_ShadowWrite
+ *
+ * Overview:	Write efuse modify map for later update operation to use!!!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/12/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+VOID
+EFUSE_ShadowWrite(
+	IN	PADAPTER	pAdapter,
+	IN	u8		Type,
+	IN	u16		Offset,
+	IN OUT	u32		Value);
+VOID
+EFUSE_ShadowWrite(
+	IN	PADAPTER	pAdapter,
+	IN	u8		Type,
+	IN	u16		Offset,
+	IN OUT	u32		Value)
+{
+#if (MP_DRIVER == 0)
+	return;
+#endif
+	if (pAdapter->registrypriv.mp_mode == 0)
+		return;
+
+
+	if (Type == 1)
+		efuse_ShadowWrite1Byte(pAdapter, Offset, (u8)Value);
+	else if (Type == 2)
+		efuse_ShadowWrite2Byte(pAdapter, Offset, (u16)Value);
+	else if (Type == 4)
+		efuse_ShadowWrite4Byte(pAdapter, Offset, (u32)Value);
+
+}	/* EFUSE_ShadowWrite */
+
+VOID
+Efuse_InitSomeVar(
+	IN		PADAPTER	pAdapter
+);
+VOID
+Efuse_InitSomeVar(
+	IN		PADAPTER	pAdapter
+)
+{
+	u8 i;
+
+	_rtw_memset((PVOID)&fakeEfuseContent[0], 0xff, EFUSE_MAX_HW_SIZE);
+	_rtw_memset((PVOID)&fakeEfuseInitMap[0], 0xff, EFUSE_MAX_MAP_LEN);
+	_rtw_memset((PVOID)&fakeEfuseModifiedMap[0], 0xff, EFUSE_MAX_MAP_LEN);
+
+	for (i = 0; i < EFUSE_MAX_BT_BANK; i++)
+		_rtw_memset((PVOID)&BTEfuseContent[i][0], EFUSE_MAX_HW_SIZE, 0xff);
+	_rtw_memset((PVOID)&BTEfuseInitMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN);
+	_rtw_memset((PVOID)&BTEfuseModifiedMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN);
+
+	for (i = 0; i < EFUSE_MAX_BT_BANK; i++)
+		_rtw_memset((PVOID)&fakeBTEfuseContent[i][0], 0xff, EFUSE_MAX_HW_SIZE);
+	_rtw_memset((PVOID)&fakeBTEfuseInitMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN);
+	_rtw_memset((PVOID)&fakeBTEfuseModifiedMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN);
+}
+#endif /* !RTW_HALMAC */
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_ShadowRead1Byte
+ *			efuse_ShadowRead2Byte
+ *			efuse_ShadowRead4Byte
+ *
+ * Overview:	Read from efuse init map by one/two/four bytes !!!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/12/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+static VOID
+efuse_ShadowRead1Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN OUT	u8		*Value)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	*Value = pHalData->efuse_eeprom_data[Offset];
+
+}	/* EFUSE_ShadowRead1Byte */
+
+/* ---------------Read Two Bytes */
+static VOID
+efuse_ShadowRead2Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN OUT	u16		*Value)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	*Value = pHalData->efuse_eeprom_data[Offset];
+	*Value |= pHalData->efuse_eeprom_data[Offset + 1] << 8;
+
+}	/* EFUSE_ShadowRead2Byte */
+
+/* ---------------Read Four Bytes */
+static VOID
+efuse_ShadowRead4Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN OUT	u32		*Value)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	*Value = pHalData->efuse_eeprom_data[Offset];
+	*Value |= pHalData->efuse_eeprom_data[Offset + 1] << 8;
+	*Value |= pHalData->efuse_eeprom_data[Offset + 2] << 16;
+	*Value |= pHalData->efuse_eeprom_data[Offset + 3] << 24;
+
+}	/* efuse_ShadowRead4Byte */
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_ShadowRead
+ *
+ * Overview:	Read from pHalData->efuse_eeprom_data
+ *---------------------------------------------------------------------------*/
+void
+EFUSE_ShadowRead(
+	IN		PADAPTER	pAdapter,
+	IN		u8		Type,
+	IN		u16		Offset,
+	IN OUT	u32		*Value)
+{
+	if (Type == 1)
+		efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value);
+	else if (Type == 2)
+		efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value);
+	else if (Type == 4)
+		efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value);
+
+}	/* EFUSE_ShadowRead */
+
+/*  11/16/2008 MH Add description. Get current efuse area enabled word!!. */
+u8
+Efuse_CalculateWordCnts(IN u8	word_en)
+{
+	u8 word_cnts = 0;
+	if (!(word_en & BIT(0)))
+		word_cnts++; /* 0 : write enable */
+	if (!(word_en & BIT(1)))
+		word_cnts++;
+	if (!(word_en & BIT(2)))
+		word_cnts++;
+	if (!(word_en & BIT(3)))
+		word_cnts++;
+	return word_cnts;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_WordEnableDataRead
+ *
+ * Overview:	Read allowed word in current efuse section data.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/16/2008	MHC		Create Version 0.
+ * 11/21/2008	MHC		Fix Write bug when we only enable late word.
+ *
+ *---------------------------------------------------------------------------*/
+void
+efuse_WordEnableDataRead(IN	u8	word_en,
+			 IN	u8	*sourdata,
+			 IN	u8	*targetdata)
+{
+	if (!(word_en & BIT(0))) {
+		targetdata[0] = sourdata[0];
+		targetdata[1] = sourdata[1];
+	}
+	if (!(word_en & BIT(1))) {
+		targetdata[2] = sourdata[2];
+		targetdata[3] = sourdata[3];
+	}
+	if (!(word_en & BIT(2))) {
+		targetdata[4] = sourdata[4];
+		targetdata[5] = sourdata[5];
+	}
+	if (!(word_en & BIT(3))) {
+		targetdata[6] = sourdata[6];
+		targetdata[7] = sourdata[7];
+	}
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_ShadowMapUpdate
+ *
+ * Overview:	Transfer current EFUSE content to shadow init and modify map.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/13/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void EFUSE_ShadowMapUpdate(
+	IN PADAPTER	pAdapter,
+	IN u8		efuseType,
+	IN BOOLEAN	bPseudoTest)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+	u16	mapLen = 0;
+#ifdef RTW_HALMAC
+	u8 *efuse_map = NULL;
+	int err;
+
+
+	mapLen = EEPROM_MAX_SIZE;
+	efuse_map = pHalData->efuse_eeprom_data;
+	/* efuse default content is 0xFF */
+	_rtw_memset(efuse_map, 0xFF, EEPROM_MAX_SIZE);
+
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest);
+	if (!mapLen) {
+		RTW_WARN("%s: <ERROR> fail to get efuse size!\n", __FUNCTION__);
+		mapLen = EEPROM_MAX_SIZE;
+	}
+	if (mapLen > EEPROM_MAX_SIZE) {
+		RTW_WARN("%s: <ERROR> size of efuse data(%d) is large than expected(%d)!\n",
+			 __FUNCTION__, mapLen, EEPROM_MAX_SIZE);
+		mapLen = EEPROM_MAX_SIZE;
+	}
+
+	if (pHalData->bautoload_fail_flag == _FALSE) {
+		err = rtw_halmac_read_logical_efuse_map(adapter_to_dvobj(pAdapter), efuse_map, mapLen, NULL, 0);
+		if (err)
+			RTW_ERR("%s: <ERROR> fail to get efuse map!\n", __FUNCTION__);
+	}
+#else /* !RTW_HALMAC */
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest);
+
+	if (pHalData->bautoload_fail_flag == _TRUE)
+		_rtw_memset(pHalData->efuse_eeprom_data, 0xFF, mapLen);
+	else {
+#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE
+		if (_SUCCESS != retriveAdaptorInfoFile(pAdapter->registrypriv.adaptor_info_caching_file_path, pHalData->efuse_eeprom_data)) {
+#endif
+
+			Efuse_ReadAllMap(pAdapter, efuseType, pHalData->efuse_eeprom_data, bPseudoTest);
+
+#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE
+			storeAdaptorInfoFile(pAdapter->registrypriv.adaptor_info_caching_file_path, pHalData->efuse_eeprom_data);
+		}
+#endif
+	}
+
+	/* PlatformMoveMemory((PVOID)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], */
+	/* (PVOID)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen); */
+#endif /* !RTW_HALMAC */
+
+	rtw_mask_map_read(pAdapter, 0x00, mapLen, pHalData->efuse_eeprom_data);
+
+	rtw_dump_cur_efuse(pAdapter);
+} /* EFUSE_ShadowMapUpdate */
+
+const u8 _mac_hidden_max_bw_to_hal_bw_cap[MAC_HIDDEN_MAX_BW_NUM] = {
+	0,
+	0,
+	(BW_CAP_160M | BW_CAP_80M | BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M),
+	(BW_CAP_5M),
+	(BW_CAP_10M | BW_CAP_5M),
+	(BW_CAP_20M | BW_CAP_10M | BW_CAP_5M),
+	(BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M),
+	(BW_CAP_80M | BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M),
+};
+
+const u8 _mac_hidden_proto_to_hal_proto_cap[MAC_HIDDEN_PROTOCOL_NUM] = {
+	0,
+	0,
+	(PROTO_CAP_11N | PROTO_CAP_11G | PROTO_CAP_11B),
+	(PROTO_CAP_11AC | PROTO_CAP_11N | PROTO_CAP_11G | PROTO_CAP_11B),
+};
+
+u8 mac_hidden_wl_func_to_hal_wl_func(u8 func)
+{
+	u8 wl_func = 0;
+
+	if (func & BIT0)
+		wl_func |= WL_FUNC_MIRACAST;
+	if (func & BIT1)
+		wl_func |= WL_FUNC_P2P;
+	if (func & BIT2)
+		wl_func |= WL_FUNC_TDLS;
+	if (func & BIT3)
+		wl_func |= WL_FUNC_FTM;
+
+	return wl_func;
+}
+
+#ifdef PLATFORM_LINUX
+#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE
+/* #include <rtw_eeprom.h> */
+
+int isAdaptorInfoFileValid(void)
+{
+	return _TRUE;
+}
+
+int storeAdaptorInfoFile(char *path, u8 *efuse_data)
+{
+	int ret = _SUCCESS;
+
+	if (path && efuse_data) {
+		ret = rtw_store_to_file(path, efuse_data, EEPROM_MAX_SIZE_512);
+		if (ret == EEPROM_MAX_SIZE)
+			ret = _SUCCESS;
+		else
+			ret = _FAIL;
+	} else {
+		RTW_INFO("%s NULL pointer\n", __FUNCTION__);
+		ret =  _FAIL;
+	}
+	return ret;
+}
+
+int retriveAdaptorInfoFile(char *path, u8 *efuse_data)
+{
+	int ret = _SUCCESS;
+	mm_segment_t oldfs;
+	struct file *fp;
+
+	if (path && efuse_data) {
+
+		ret = rtw_retrieve_from_file(path, efuse_data, EEPROM_MAX_SIZE);
+
+		if (ret == EEPROM_MAX_SIZE)
+			ret = _SUCCESS;
+		else
+			ret = _FAIL;
+
+#if 0
+		if (isAdaptorInfoFileValid())
+			return 0;
+		else
+			return _FAIL;
+#endif
+
+	} else {
+		RTW_INFO("%s NULL pointer\n", __FUNCTION__);
+		ret = _FAIL;
+	}
+	return ret;
+}
+#endif /* CONFIG_ADAPTOR_INFO_CACHING_FILE */
+
+u8 rtw_efuse_file_read(PADAPTER padapter, u8 *filepatch, u8 *buf, u32 len)
+{
+	char *ptmpbuf = NULL, *ptr;
+	u8 val8;
+	u32 count, i, j;
+	int err;
+	u32 bufsize = 4096;
+
+	ptmpbuf = rtw_zmalloc(bufsize);
+	if (ptmpbuf == NULL)
+		return _FALSE;
+
+	count = rtw_retrieve_from_file(filepatch, ptmpbuf, bufsize);
+	if (count <= 90) {
+		rtw_mfree(ptmpbuf, bufsize);
+		RTW_ERR("%s, filepatch %s, size=%d, FAIL!!\n", __FUNCTION__, filepatch, count);
+		return _FALSE;
+	}
+
+	i = 0;
+	j = 0;
+	ptr = ptmpbuf;
+	while ((j < len) && (i < count)) {
+		if (ptmpbuf[i] == '\0')
+			break;
+	
+		ptr = strpbrk(&ptmpbuf[i], " \t\n\r");
+		if (ptr) {
+			if (ptr == &ptmpbuf[i]) {
+				i++;
+				continue;
+			}
+
+			/* Add string terminating null */
+			*ptr = 0;
+		} else {
+			ptr = &ptmpbuf[count-1];
+		}
+
+		err = sscanf(&ptmpbuf[i], "%hhx", &val8);
+		if (err != 1) {
+			RTW_WARN("Something wrong to parse efuse file, string=%s\n", &ptmpbuf[i]);
+		} else {
+			buf[j] = val8;
+			RTW_DBG("i=%d, j=%d, 0x%02x\n", i, j, buf[j]);
+			j++;
+		}
+
+		i = ptr - ptmpbuf + 1;
+	}
+
+	rtw_mfree(ptmpbuf, bufsize);
+	RTW_INFO("%s, filepatch %s, size=%d, done\n", __FUNCTION__, filepatch, count);
+	return _TRUE;
+}
+
+#ifdef CONFIG_EFUSE_CONFIG_FILE
+u32 rtw_read_efuse_from_file(const char *path, u8 *buf, int map_size)
+{
+	u32 i;
+	u8 c;
+	u8 temp[3];
+	u8 temp_i;
+	u8 end = _FALSE;
+	u32 ret = _FAIL;
+
+	u8 *file_data = NULL;
+	u32 file_size, read_size, pos = 0;
+	u8 *map = NULL;
+
+	if (rtw_is_file_readable_with_size(path, &file_size) != _TRUE) {
+		RTW_PRINT("%s %s is not readable\n", __func__, path);
+		goto exit;
+	}
+
+	file_data = rtw_vmalloc(file_size);
+	if (!file_data) {
+		RTW_ERR("%s rtw_vmalloc(%d) fail\n", __func__, file_size);
+		goto exit;
+	}
+
+	read_size = rtw_retrieve_from_file(path, file_data, file_size);
+	if (read_size == 0) {
+		RTW_ERR("%s read from %s fail\n", __func__, path);
+		goto exit;
+	}
+
+	map = rtw_vmalloc(map_size);
+	if (!map) {
+		RTW_ERR("%s rtw_vmalloc(%d) fail\n", __func__, map_size);
+		goto exit;
+	}
+	_rtw_memset(map, 0xff, map_size);
+
+	temp[2] = 0; /* end of string '\0' */
+
+	for (i = 0 ; i < map_size ; i++) {
+		temp_i = 0;
+
+		while (1) {
+			if (pos >= read_size) {
+				end = _TRUE;
+				break;
+			}
+			c = file_data[pos++];
+
+			/* bypass spece or eol or null before first hex digit */
+			if (temp_i == 0 && (is_eol(c) == _TRUE || is_space(c) == _TRUE || is_null(c) == _TRUE))
+				continue;
+
+			if (IsHexDigit(c) == _FALSE) {
+				RTW_ERR("%s invalid 8-bit hex format for offset:0x%03x\n", __func__, i);
+				goto exit;
+			}
+
+			temp[temp_i++] = c;
+
+			if (temp_i == 2) {
+				/* parse value */
+				if (sscanf(temp, "%hhx", &map[i]) != 1) {
+					RTW_ERR("%s sscanf fail for offset:0x%03x\n", __func__, i);
+					goto exit;
+				}
+				break;
+			}
+		}
+
+		if (end == _TRUE) {
+			if (temp_i != 0) {
+				RTW_ERR("%s incomplete 8-bit hex format for offset:0x%03x\n", __func__, i);
+				goto exit;
+			}
+			break;
+		}
+	}
+
+	RTW_PRINT("efuse file:%s, 0x%03x byte content read\n", path, i);
+
+	_rtw_memcpy(buf, map, map_size);
+
+	ret = _SUCCESS;
+
+exit:
+	if (file_data)
+		rtw_vmfree(file_data, file_size);
+	if (map)
+		rtw_vmfree(map, map_size);
+
+	return ret;
+}
+
+u32 rtw_read_macaddr_from_file(const char *path, u8 *buf)
+{
+	u32 i;
+	u8 temp[3];
+	u32 ret = _FAIL;
+
+	u8 file_data[17];
+	u32 read_size, pos = 0;
+	u8 addr[ETH_ALEN];
+
+	if (rtw_is_file_readable(path) != _TRUE) {
+		RTW_PRINT("%s %s is not readable\n", __func__, path);
+		goto exit;
+	}
+
+	read_size = rtw_retrieve_from_file(path, file_data, 17);
+	if (read_size != 17) {
+		RTW_ERR("%s read from %s fail\n", __func__, path);
+		goto exit;
+	}
+
+	temp[2] = 0; /* end of string '\0' */
+
+	for (i = 0 ; i < ETH_ALEN ; i++) {
+		if (IsHexDigit(file_data[i * 3]) == _FALSE || IsHexDigit(file_data[i * 3 + 1]) == _FALSE) {
+			RTW_ERR("%s invalid 8-bit hex format for address offset:%u\n", __func__, i);
+			goto exit;
+		}
+
+		if (i < ETH_ALEN - 1 && file_data[i * 3 + 2] != ':') {
+			RTW_ERR("%s invalid separator after address offset:%u\n", __func__, i);
+			goto exit;
+		}
+
+		temp[0] = file_data[i * 3];
+		temp[1] = file_data[i * 3 + 1];
+		if (sscanf(temp, "%hhx", &addr[i]) != 1) {
+			RTW_ERR("%s sscanf fail for address offset:0x%03x\n", __func__, i);
+			goto exit;
+		}
+	}
+
+	_rtw_memcpy(buf, addr, ETH_ALEN);
+
+	RTW_PRINT("wifi_mac file: %s\n", path);
+#ifdef CONFIG_RTW_DEBUG
+	RTW_INFO(MAC_FMT"\n", MAC_ARG(buf));
+#endif
+
+	ret = _SUCCESS;
+
+exit:
+	return ret;
+}
+#endif /* CONFIG_EFUSE_CONFIG_FILE */
+
+#endif /* PLATFORM_LINUX */
diff --git a/core/rtw_ap.c b/core/rtw_ap.c
new file mode 100644
index 0000000..a4dd739
--- /dev/null
+++ b/core/rtw_ap.c
@@ -0,0 +1,4751 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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 _RTW_AP_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+#ifdef CONFIG_AP_MODE
+
+extern unsigned char	RTW_WPA_OUI[];
+extern unsigned char	WMM_OUI[];
+extern unsigned char	WPS_OUI[];
+extern unsigned char	P2P_OUI[];
+extern unsigned char	WFD_OUI[];
+
+void init_mlme_ap_info(_adapter *padapter)
+{
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	_rtw_spinlock_init(&pmlmepriv->bcn_update_lock);
+
+	/* pmlmeext->bstart_bss = _FALSE; */
+
+}
+
+void free_mlme_ap_info(_adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	stop_ap_mode(padapter);
+	_rtw_spinlock_free(&pmlmepriv->bcn_update_lock);
+
+}
+
+static void update_BCNTIM(_adapter *padapter)
+{
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network);
+	unsigned char *pie = pnetwork_mlmeext->IEs;
+
+#if 0
+
+
+	/* update TIM IE */
+	/* if(pstapriv->tim_bitmap) */
+#endif
+	if (_TRUE) {
+		u8 *p, *dst_ie, *premainder_ie = NULL, *pbackup_remainder_ie = NULL;
+		u16 tim_bitmap_le;
+		uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen;
+
+		tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap);
+
+		p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_);
+		if (p != NULL && tim_ielen > 0) {
+			tim_ielen += 2;
+
+			premainder_ie = p + tim_ielen;
+
+			tim_ie_offset = (sint)(p - pie);
+
+			remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen;
+
+			/*append TIM IE from dst_ie offset*/
+			dst_ie = p;
+		} else {
+			tim_ielen = 0;
+
+			/*calculate head_len*/
+			offset = _FIXED_IE_LENGTH_;
+
+			/* get ssid_ie len */
+			p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SSID_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));
+			if (p != NULL)
+				offset += tmp_len + 2;
+
+			/*get supported rates len*/
+			p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));
+			if (p !=  NULL)
+				offset += tmp_len + 2;
+
+			/*DS Parameter Set IE, len=3*/
+			offset += 3;
+
+			premainder_ie = pie + offset;
+
+			remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen;
+
+			/*append TIM IE from offset*/
+			dst_ie = pie + offset;
+
+		}
+
+		if (remainder_ielen > 0) {
+			pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+			if (pbackup_remainder_ie && premainder_ie)
+				_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+		}
+
+		*dst_ie++ = _TIM_IE_;
+
+		if ((pstapriv->tim_bitmap & 0xff00) && (pstapriv->tim_bitmap & 0x00fe))
+			tim_ielen = 5;
+		else
+			tim_ielen = 4;
+
+		*dst_ie++ = tim_ielen;
+
+		*dst_ie++ = 0;/*DTIM count*/
+		*dst_ie++ = 1;/*DTIM period*/
+
+		if (pstapriv->tim_bitmap & BIT(0))/*for bc/mc frames*/
+			*dst_ie++ = BIT(0);/*bitmap ctrl */
+		else
+			*dst_ie++ = 0;
+
+		if (tim_ielen == 4) {
+			u8 pvb = 0;
+
+			if (pstapriv->tim_bitmap & 0x00fe)
+				pvb = (u8)tim_bitmap_le;
+			else if (pstapriv->tim_bitmap & 0xff00)
+				pvb = (u8)(tim_bitmap_le >> 8);
+			else
+				pvb = (u8)tim_bitmap_le;
+
+			*dst_ie++ = pvb;
+
+		} else if (tim_ielen == 5) {
+			_rtw_memcpy(dst_ie, &tim_bitmap_le, 2);
+			dst_ie += 2;
+		}
+
+		/*copy remainder IE*/
+		if (pbackup_remainder_ie) {
+			_rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+			rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+		}
+
+		offset = (uint)(dst_ie - pie);
+		pnetwork_mlmeext->IELength = offset + remainder_ielen;
+
+	}
+}
+
+void rtw_add_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index, u8 *data, u8 len)
+{
+	PNDIS_802_11_VARIABLE_IEs	pIE;
+	u8	bmatch = _FALSE;
+	u8	*pie = pnetwork->IEs;
+	u8	*p = NULL, *dst_ie = NULL, *premainder_ie = NULL, *pbackup_remainder_ie = NULL;
+	u32	i, offset, ielen, ie_offset, remainder_ielen = 0;
+
+	for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pnetwork->IELength;) {
+		pIE = (PNDIS_802_11_VARIABLE_IEs)(pnetwork->IEs + i);
+
+		if (pIE->ElementID > index)
+			break;
+		else if (pIE->ElementID == index) { /* already exist the same IE */
+			p = (u8 *)pIE;
+			ielen = pIE->Length;
+			bmatch = _TRUE;
+			break;
+		}
+
+		p = (u8 *)pIE;
+		ielen = pIE->Length;
+		i += (pIE->Length + 2);
+	}
+
+	if (p != NULL && ielen > 0) {
+		ielen += 2;
+
+		premainder_ie = p + ielen;
+
+		ie_offset = (sint)(p - pie);
+
+		remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+		if (bmatch)
+			dst_ie = p;
+		else
+			dst_ie = (p + ielen);
+	}
+
+	if (dst_ie == NULL)
+		return;
+
+	if (remainder_ielen > 0) {
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if (pbackup_remainder_ie && premainder_ie)
+			_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	*dst_ie++ = index;
+	*dst_ie++ = len;
+
+	_rtw_memcpy(dst_ie, data, len);
+	dst_ie += len;
+
+	/* copy remainder IE */
+	if (pbackup_remainder_ie) {
+		_rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+		rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+	}
+
+	offset = (uint)(dst_ie - pie);
+	pnetwork->IELength = offset + remainder_ielen;
+}
+
+void rtw_remove_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index)
+{
+	u8 *p, *dst_ie = NULL, *premainder_ie = NULL, *pbackup_remainder_ie = NULL;
+	uint offset, ielen, ie_offset, remainder_ielen = 0;
+	u8	*pie = pnetwork->IEs;
+
+	p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, index, &ielen, pnetwork->IELength - _FIXED_IE_LENGTH_);
+	if (p != NULL && ielen > 0) {
+		ielen += 2;
+
+		premainder_ie = p + ielen;
+
+		ie_offset = (sint)(p - pie);
+
+		remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+		dst_ie = p;
+	} else
+		return;
+
+	if (remainder_ielen > 0) {
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if (pbackup_remainder_ie && premainder_ie)
+			_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	/* copy remainder IE */
+	if (pbackup_remainder_ie) {
+		_rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+		rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+	}
+
+	offset = (uint)(dst_ie - pie);
+	pnetwork->IELength = offset + remainder_ielen;
+}
+
+
+u8 chk_sta_is_alive(struct sta_info *psta);
+u8 chk_sta_is_alive(struct sta_info *psta)
+{
+	u8 ret = _FALSE;
+#ifdef DBG_EXPIRATION_CHK
+	RTW_INFO("sta:"MAC_FMT", rssi:%d, rx:"STA_PKTS_FMT", expire_to:%u, %s%ssq_len:%u\n"
+		 , MAC_ARG(psta->cmn.mac_addr)
+		 , psta->cmn.rssi_stat.rssi
+		 /* , STA_RX_PKTS_ARG(psta) */
+		 , STA_RX_PKTS_DIFF_ARG(psta)
+		 , psta->expire_to
+		 , psta->state & WIFI_SLEEP_STATE ? "PS, " : ""
+		 , psta->state & WIFI_STA_ALIVE_CHK_STATE ? "SAC, " : ""
+		 , psta->sleepq_len
+		);
+#endif
+
+	/* if(sta_last_rx_pkts(psta) == sta_rx_pkts(psta)) */
+	if ((psta->sta_stats.last_rx_data_pkts + psta->sta_stats.last_rx_ctrl_pkts) == (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts)) {
+#if 0
+		if (psta->state & WIFI_SLEEP_STATE)
+			ret = _TRUE;
+#endif
+	} else
+		ret = _TRUE;
+
+	sta_update_last_rx_pkts(psta);
+
+	return ret;
+}
+
+void	expire_timeout_chk(_adapter *padapter)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	u8 updated = _FALSE;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 chk_alive_num = 0;
+	char chk_alive_list[NUM_STA];
+	int i;
+
+
+#ifdef CONFIG_MCC_MODE
+	/*	then driver may check fail due to not recv client's frame under sitesurvey,
+	 *	don't expire timeout chk under MCC under sitesurvey */
+
+	if (rtw_hal_mcc_link_status_chk(padapter, __func__) == _FALSE)
+		return;
+#endif
+
+	_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+	phead = &pstapriv->auth_list;
+	plist = get_next(phead);
+
+	/* check auth_queue */
+#ifdef DBG_EXPIRATION_CHK
+	if (rtw_end_of_queue_search(phead, plist) == _FALSE) {
+		RTW_INFO(FUNC_NDEV_FMT" auth_list, cnt:%u\n"
+			, FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->auth_list_cnt);
+	}
+#endif
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, auth_list);
+
+		plist = get_next(plist);
+
+
+#ifdef CONFIG_ATMEL_RC_PATCH
+		if (_rtw_memcmp((void *)(pstapriv->atmel_rc_pattern), (void *)(psta->cmn.mac_addr), ETH_ALEN) == _TRUE)
+			continue;
+		if (psta->flag_atmel_rc)
+			continue;
+#endif
+		if (psta->expire_to > 0) {
+			psta->expire_to--;
+			if (psta->expire_to == 0) {
+				rtw_list_delete(&psta->auth_list);
+				pstapriv->auth_list_cnt--;
+
+				RTW_INFO("auth expire %02X%02X%02X%02X%02X%02X\n",
+					psta->cmn.mac_addr[0], psta->cmn.mac_addr[1], psta->cmn.mac_addr[2],
+					psta->cmn.mac_addr[3], psta->cmn.mac_addr[4], psta->cmn.mac_addr[5]);
+
+				_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+				/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);	 */
+				rtw_free_stainfo(padapter, psta);
+				/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);	 */
+
+				_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+			}
+		}
+
+	}
+
+	_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+	psta = NULL;
+
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	/* check asoc_queue */
+#ifdef DBG_EXPIRATION_CHK
+	if (rtw_end_of_queue_search(phead, plist) == _FALSE) {
+		RTW_INFO(FUNC_NDEV_FMT" asoc_list, cnt:%u\n"
+			, FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->asoc_list_cnt);
+	}
+#endif
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+#ifdef CONFIG_ATMEL_RC_PATCH
+		RTW_INFO("%s:%d  psta=%p, %02x,%02x||%02x,%02x  \n\n", __func__,  __LINE__,
+			psta, pstapriv->atmel_rc_pattern[0], pstapriv->atmel_rc_pattern[5], psta->cmn.mac_addr[0], psta->cmn.mac_addr[5]);
+		if (_rtw_memcmp((void *)pstapriv->atmel_rc_pattern, (void *)(psta->cmn.mac_addr), ETH_ALEN) == _TRUE)
+			continue;
+		if (psta->flag_atmel_rc)
+			continue;
+		RTW_INFO("%s: debug line:%d\n", __func__, __LINE__);
+#endif
+#ifdef CONFIG_AUTO_AP_MODE
+		if (psta->isrc)
+			continue;
+#endif
+		if (chk_sta_is_alive(psta) || !psta->expire_to) {
+			psta->expire_to = pstapriv->expire_to;
+			psta->keep_alive_trycnt = 0;
+#ifdef CONFIG_TX_MCAST2UNI
+			psta->under_exist_checking = 0;
+#endif	/* CONFIG_TX_MCAST2UNI */
+		} else
+			psta->expire_to--;
+
+#ifndef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+#ifdef CONFIG_80211N_HT
+#ifdef CONFIG_TX_MCAST2UNI
+		if ((psta->flags & WLAN_STA_HT) && (psta->htpriv.agg_enable_bitmap || psta->under_exist_checking)) {
+			/* check sta by delba(addba) for 11n STA */
+			/* ToDo: use CCX report to check for all STAs */
+			/* RTW_INFO("asoc check by DELBA/ADDBA! (pstapriv->expire_to=%d s)(psta->expire_to=%d s), [%02x, %d]\n", pstapriv->expire_to*2, psta->expire_to*2, psta->htpriv.agg_enable_bitmap, psta->under_exist_checking); */
+
+			if (psta->expire_to <= (pstapriv->expire_to - 50)) {
+				RTW_INFO("asoc expire by DELBA/ADDBA! (%d s)\n", (pstapriv->expire_to - psta->expire_to) * 2);
+				psta->under_exist_checking = 0;
+				psta->expire_to = 0;
+			} else if (psta->expire_to <= (pstapriv->expire_to - 3) && (psta->under_exist_checking == 0)) {
+				RTW_INFO("asoc check by DELBA/ADDBA! (%d s)\n", (pstapriv->expire_to - psta->expire_to) * 2);
+				psta->under_exist_checking = 1;
+				/* tear down TX AMPDU */
+				send_delba(padapter, 1, psta->cmn.mac_addr);/*  */ /* originator */
+				psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+				psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+			}
+		}
+#endif /* CONFIG_TX_MCAST2UNI */
+#endif /* CONFIG_80211N_HT */
+#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */
+
+		if (psta->expire_to <= 0) {
+			struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+			if (padapter->registrypriv.wifi_spec == 1) {
+				psta->expire_to = pstapriv->expire_to;
+				continue;
+			}
+
+#ifndef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+#ifdef CONFIG_80211N_HT
+
+#define KEEP_ALIVE_TRYCNT (3)
+
+			if (psta->keep_alive_trycnt > 0 && psta->keep_alive_trycnt <= KEEP_ALIVE_TRYCNT) {
+				if (psta->state & WIFI_STA_ALIVE_CHK_STATE)
+					psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+				else
+					psta->keep_alive_trycnt = 0;
+
+			} else if ((psta->keep_alive_trycnt > KEEP_ALIVE_TRYCNT) && !(psta->state & WIFI_STA_ALIVE_CHK_STATE))
+				psta->keep_alive_trycnt = 0;
+			if ((psta->htpriv.ht_option == _TRUE) && (psta->htpriv.ampdu_enable == _TRUE)) {
+				uint priority = 1; /* test using BK */
+				u8 issued = 0;
+
+				/* issued = (psta->htpriv.agg_enable_bitmap>>priority)&0x1; */
+				issued |= (psta->htpriv.candidate_tid_bitmap >> priority) & 0x1;
+
+				if (0 == issued) {
+					if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) {
+						psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority);
+
+						if (psta->state & WIFI_SLEEP_STATE)
+							psta->expire_to = 2; /* 2x2=4 sec */
+						else
+							psta->expire_to = 1; /* 2 sec */
+
+						psta->state |= WIFI_STA_ALIVE_CHK_STATE;
+
+						/* add_ba_hdl(padapter, (u8*)paddbareq_parm); */
+
+						RTW_INFO("issue addba_req to check if sta alive, keep_alive_trycnt=%d\n", psta->keep_alive_trycnt);
+
+						issue_addba_req(padapter, psta->cmn.mac_addr, (u8)priority);
+
+						_set_timer(&psta->addba_retry_timer, ADDBA_TO);
+
+						psta->keep_alive_trycnt++;
+
+						continue;
+					}
+				}
+			}
+			if (psta->keep_alive_trycnt > 0 && psta->state & WIFI_STA_ALIVE_CHK_STATE) {
+				psta->keep_alive_trycnt = 0;
+				psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+				RTW_INFO("change to another methods to check alive if staion is at ps mode\n");
+			}
+
+#endif /* CONFIG_80211N_HT */
+#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK	 */
+			if (psta->state & WIFI_SLEEP_STATE) {
+				if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) {
+					/* to check if alive by another methods if staion is at ps mode.					 */
+					psta->expire_to = pstapriv->expire_to;
+					psta->state |= WIFI_STA_ALIVE_CHK_STATE;
+
+					/* RTW_INFO("alive chk, sta:" MAC_FMT " is at ps mode!\n", MAC_ARG(psta->cmn.mac_addr)); */
+
+					/* to update bcn with tim_bitmap for this station */
+					pstapriv->tim_bitmap |= BIT(psta->cmn.aid);
+					update_beacon(padapter, _TIM_IE_, NULL, _TRUE);
+
+					if (!pmlmeext->active_keep_alive_check)
+						continue;
+				}
+			}
+#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+			if (pmlmeext->active_keep_alive_check) {
+				int stainfo_offset;
+
+				stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+				if (stainfo_offset_valid(stainfo_offset))
+					chk_alive_list[chk_alive_num++] = stainfo_offset;
+
+				continue;
+			}
+#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */
+			rtw_list_delete(&psta->asoc_list);
+			pstapriv->asoc_list_cnt--;
+			RTW_INFO("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->cmn.mac_addr), psta->state);
+			updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_DEAUTH_LEAVING, _TRUE);
+		} else {
+			/* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */
+			if (psta->sleepq_len > (NR_XMITFRAME / pstapriv->asoc_list_cnt)
+			    && padapter->xmitpriv.free_xmitframe_cnt < ((NR_XMITFRAME / pstapriv->asoc_list_cnt) / 2)
+			   ) {
+				RTW_INFO("%s sta:"MAC_FMT", sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__
+					 , MAC_ARG(psta->cmn.mac_addr)
+					, psta->sleepq_len, padapter->xmitpriv.free_xmitframe_cnt, pstapriv->asoc_list_cnt);
+				wakeup_sta_to_xmit(padapter, psta);
+			}
+		}
+	}
+
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+	if (chk_alive_num) {
+
+		u8 backup_ch = 0, backup_bw = 0, backup_offset = 0;
+		u8 union_ch = 0, union_bw, union_offset;
+		u8 switch_channel = _TRUE;
+		struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+		if (!rtw_mi_get_ch_setting_union(padapter, &union_ch, &union_bw, &union_offset)
+			|| pmlmeext->cur_channel != union_ch)
+			goto bypass_active_keep_alive;
+
+#ifdef CONFIG_MCC_MODE
+		if (MCC_EN(padapter)) {
+			/* driver doesn't switch channel under MCC */
+			if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC))
+				switch_channel = _FALSE;
+		}
+#endif
+		/* switch to correct channel of current network  before issue keep-alive frames */
+		if (switch_channel == _TRUE && rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) {
+			backup_ch = rtw_get_oper_ch(padapter);
+			backup_bw = rtw_get_oper_bw(padapter);
+			backup_offset = rtw_get_oper_choffset(padapter);
+			set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
+		}
+
+		/* issue null data to check sta alive*/
+		for (i = 0; i < chk_alive_num; i++) {
+			int ret = _FAIL;
+
+			psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
+#ifdef CONFIG_ATMEL_RC_PATCH
+			if (_rtw_memcmp(pstapriv->atmel_rc_pattern, psta->cmn.mac_addr, ETH_ALEN) == _TRUE)
+				continue;
+			if (psta->flag_atmel_rc)
+				continue;
+#endif
+			if (!(psta->state & _FW_LINKED))
+				continue;
+
+			if (psta->state & WIFI_SLEEP_STATE)
+				ret = issue_nulldata(padapter, psta->cmn.mac_addr, 0, 1, 50);
+			else
+				ret = issue_nulldata(padapter, psta->cmn.mac_addr, 0, 3, 50);
+
+			psta->keep_alive_trycnt++;
+			if (ret == _SUCCESS) {
+				RTW_INFO("asoc check, sta(" MAC_FMT ") is alive\n", MAC_ARG(psta->cmn.mac_addr));
+				psta->expire_to = pstapriv->expire_to;
+				psta->keep_alive_trycnt = 0;
+				continue;
+			} else if (psta->keep_alive_trycnt <= 3) {
+				RTW_INFO("ack check for asoc expire, keep_alive_trycnt=%d\n", psta->keep_alive_trycnt);
+				psta->expire_to = 1;
+				continue;
+			}
+
+			psta->keep_alive_trycnt = 0;
+			RTW_INFO("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->cmn.mac_addr), psta->state);
+			_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+			if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) {
+				rtw_list_delete(&psta->asoc_list);
+				pstapriv->asoc_list_cnt--;
+				updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_DEAUTH_LEAVING, _TRUE);
+			}
+			_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+		}
+
+		/* back to the original operation channel */
+		if (switch_channel && backup_ch > 0)
+			set_channel_bwmode(padapter, backup_ch, backup_offset, backup_bw);
+
+bypass_active_keep_alive:
+		;
+	}
+#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */
+
+	associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL);
+}
+
+void rtw_ap_update_sta_ra_info(_adapter *padapter, struct sta_info *psta)
+{
+	int i;
+	u8 rf_type;
+	unsigned char sta_band = 0;
+	u64 tx_ra_bitmap = 0;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
+
+	if (!psta)
+		return;
+
+	if (!(psta->state & _FW_LINKED))
+		return;
+
+	rtw_hal_update_sta_ra_info(padapter, psta);
+	tx_ra_bitmap = psta->cmn.ra_info.ramask;
+
+	if (pcur_network->Configuration.DSConfig > 14) {
+
+		if (tx_ra_bitmap & 0xffff000)
+			sta_band |= WIRELESS_11_5N;
+
+		if (tx_ra_bitmap & 0xff0)
+			sta_band |= WIRELESS_11A;
+
+		/* 5G band */
+#ifdef CONFIG_80211AC_VHT
+		if (psta->vhtpriv.vht_option)
+			sta_band = WIRELESS_11_5AC;
+#endif
+	} else {
+		if (tx_ra_bitmap & 0xffff000)
+			sta_band |= WIRELESS_11_24N;
+
+		if (tx_ra_bitmap & 0xff0)
+			sta_band |= WIRELESS_11G;
+
+		if (tx_ra_bitmap & 0x0f)
+			sta_band |= WIRELESS_11B;
+	}
+
+	psta->wireless_mode = sta_band;
+	rtw_hal_update_sta_wset(padapter, psta);
+	RTW_INFO("%s=> mac_id:%d , tx_ra_bitmap:0x%016llx, networkType:0x%02x\n",
+			__FUNCTION__, psta->cmn.mac_id, tx_ra_bitmap, psta->wireless_mode);
+}
+
+#ifdef CONFIG_BMC_TX_RATE_SELECT
+u8 rtw_ap_find_mini_tx_rate(_adapter *adapter)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	u8 miini_tx_rate = ODM_RATEVHTSS4MCS9, sta_tx_rate;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &adapter->stapriv;
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		sta_tx_rate = psta->cmn.ra_info.curr_tx_rate & 0x7F;
+		if (sta_tx_rate < miini_tx_rate)
+			miini_tx_rate = sta_tx_rate;
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	return miini_tx_rate;
+}
+
+u8 rtw_ap_find_bmc_rate(_adapter *adapter, u8 tx_rate)
+{
+	PHAL_DATA_TYPE	hal_data = GET_HAL_DATA(adapter);
+	u8 tx_ini_rate = ODM_RATE6M;
+
+	switch (tx_rate) {
+	case ODM_RATEVHTSS3MCS9:
+	case ODM_RATEVHTSS3MCS8:
+	case ODM_RATEVHTSS3MCS7:
+	case ODM_RATEVHTSS3MCS6:
+	case ODM_RATEVHTSS3MCS5:
+	case ODM_RATEVHTSS3MCS4:
+	case ODM_RATEVHTSS3MCS3:
+	case ODM_RATEVHTSS2MCS9:
+	case ODM_RATEVHTSS2MCS8:
+	case ODM_RATEVHTSS2MCS7:
+	case ODM_RATEVHTSS2MCS6:
+	case ODM_RATEVHTSS2MCS5:
+	case ODM_RATEVHTSS2MCS4:
+	case ODM_RATEVHTSS2MCS3:
+	case ODM_RATEVHTSS1MCS9:
+	case ODM_RATEVHTSS1MCS8:
+	case ODM_RATEVHTSS1MCS7:
+	case ODM_RATEVHTSS1MCS6:
+	case ODM_RATEVHTSS1MCS5:
+	case ODM_RATEVHTSS1MCS4:
+	case ODM_RATEVHTSS1MCS3:
+	case ODM_RATEMCS15:
+	case ODM_RATEMCS14:
+	case ODM_RATEMCS13:
+	case ODM_RATEMCS12:
+	case ODM_RATEMCS11:
+	case ODM_RATEMCS7:
+	case ODM_RATEMCS6:
+	case ODM_RATEMCS5:
+	case ODM_RATEMCS4:
+	case ODM_RATEMCS3:
+	case ODM_RATE54M:
+	case ODM_RATE48M:
+	case ODM_RATE36M:
+	case ODM_RATE24M:
+		tx_ini_rate = ODM_RATE24M;
+		break;
+	case ODM_RATEVHTSS3MCS2:
+	case ODM_RATEVHTSS3MCS1:
+	case ODM_RATEVHTSS2MCS2:
+	case ODM_RATEVHTSS2MCS1:
+	case ODM_RATEVHTSS1MCS2:
+	case ODM_RATEVHTSS1MCS1:
+	case ODM_RATEMCS10:
+	case ODM_RATEMCS9:
+	case ODM_RATEMCS2:
+	case ODM_RATEMCS1:
+	case ODM_RATE18M:
+	case ODM_RATE12M:
+		tx_ini_rate = ODM_RATE12M;
+		break;
+	case ODM_RATEVHTSS3MCS0:
+	case ODM_RATEVHTSS2MCS0:
+	case ODM_RATEVHTSS1MCS0:
+	case ODM_RATEMCS8:
+	case ODM_RATEMCS0:
+	case ODM_RATE9M:
+	case ODM_RATE6M:
+		tx_ini_rate = ODM_RATE6M;
+		break;
+	case ODM_RATE11M:
+	case ODM_RATE5_5M:
+	case ODM_RATE2M:
+	case ODM_RATE1M:
+		tx_ini_rate = ODM_RATE1M;
+		break;
+	default:
+		tx_ini_rate = ODM_RATE6M;
+		break;
+	}
+
+	if (hal_data->current_band_type == BAND_ON_5G)
+		if (tx_ini_rate < ODM_RATE6M)
+			tx_ini_rate = ODM_RATE6M;
+
+	return tx_ini_rate;
+}
+
+void rtw_update_bmc_sta_tx_rate(_adapter *adapter)
+{
+	struct sta_info *psta = NULL;
+	u8 tx_rate;
+
+	psta = rtw_get_bcmc_stainfo(adapter);
+	if (psta == NULL) {
+		RTW_ERR(ADPT_FMT "could not get bmc_sta !!\n", ADPT_ARG(adapter));
+		return;
+	}
+
+	if (adapter->bmc_tx_rate != MGN_UNKNOWN) {
+		psta->init_rate = adapter->bmc_tx_rate;
+		goto _exit;
+	}
+
+	if (adapter->stapriv.asoc_sta_count <= 2)
+		goto _exit;
+
+	tx_rate = rtw_ap_find_mini_tx_rate(adapter);
+	#ifdef CONFIG_BMC_TX_LOW_RATE
+	tx_rate = rtw_ap_find_bmc_rate(adapter, tx_rate);
+	#endif
+
+	psta->init_rate = hw_rate_to_m_rate(tx_rate);
+
+_exit:
+	RTW_INFO(ADPT_FMT" BMC Tx rate - %s\n", ADPT_ARG(adapter), MGN_RATE_STR(psta->init_rate));
+}
+#endif
+
+void rtw_init_bmc_sta_tx_rate(_adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+	u8 rate_idx = 0;
+	u8 brate_table[] = {MGN_1M, MGN_2M, MGN_5_5M, MGN_11M,
+		MGN_6M, MGN_9M, MGN_12M, MGN_18M, MGN_24M, MGN_36M, MGN_48M, MGN_54M};
+
+	if (!MLME_IS_AP(padapter) && !MLME_IS_MESH(padapter))
+		return;
+
+	if (padapter->bmc_tx_rate != MGN_UNKNOWN)
+		psta->init_rate = padapter->bmc_tx_rate;
+	else {
+		#ifdef CONFIG_BMC_TX_LOW_RATE
+		if (IsEnableHWOFDM(pmlmeext->cur_wireless_mode) && (psta->cmn.ra_info.ramask && 0xFF0))
+			rate_idx = get_lowest_rate_idx_ex(psta->cmn.ra_info.ramask, 4); /*from basic rate*/
+		else
+			rate_idx = get_lowest_rate_idx(psta->cmn.ra_info.ramask); /*from basic rate*/
+		#else
+		rate_idx = get_highest_rate_idx(psta->cmn.ra_info.ramask); /*from basic rate*/
+		#endif
+		if (rate_idx < 12)
+			psta->init_rate = brate_table[rate_idx];
+		else
+			psta->init_rate = MGN_1M;
+	}
+
+	RTW_INFO(ADPT_FMT" BMC Init Tx rate - %s\n", ADPT_ARG(padapter), MGN_RATE_STR(psta->init_rate));
+}
+
+void update_bmc_sta(_adapter *padapter)
+{
+	_irqL	irqL;
+	unsigned char	network_type;
+	int supportRateNum = 0;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
+	struct sta_info *psta = rtw_get_bcmc_stainfo(padapter);
+
+	if (psta) {
+		psta->cmn.aid = 0;/* default set to 0 */
+		psta->qos_option = 0;
+#ifdef CONFIG_80211N_HT
+		psta->htpriv.ht_option = _FALSE;
+#endif /* CONFIG_80211N_HT */
+
+		psta->ieee8021x_blocked = 0;
+
+		_rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+		/* psta->dot118021XPrivacy = _NO_PRIVACY_; */ /* !!! remove it, because it has been set before this. */
+
+		supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates);
+		network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, supportRateNum, pcur_network->Configuration.DSConfig);
+		if (IsSupportedTxCCK(network_type))
+			network_type = WIRELESS_11B;
+		else if (network_type == WIRELESS_INVALID) { /* error handling */
+			if (pcur_network->Configuration.DSConfig > 14)
+				network_type = WIRELESS_11A;
+			else
+				network_type = WIRELESS_11B;
+		}
+		update_sta_basic_rate(psta, network_type);
+		psta->wireless_mode = network_type;
+
+		rtw_hal_update_sta_ra_info(padapter, psta);
+
+		_enter_critical_bh(&psta->lock, &irqL);
+		psta->state = _FW_LINKED;
+		_exit_critical_bh(&psta->lock, &irqL);
+
+		rtw_sta_media_status_rpt(padapter, psta, 1);
+		rtw_init_bmc_sta_tx_rate(padapter, psta);
+
+	} else
+		RTW_INFO("add_RATid_bmc_sta error!\n");
+
+}
+
+#if defined(CONFIG_80211N_HT) && defined(CONFIG_BEAMFORMING)
+void update_sta_info_apmode_ht_bf_cap(_adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct ht_priv	*phtpriv_ap = &pmlmepriv->htpriv;
+	struct ht_priv	*phtpriv_sta = &psta->htpriv;
+
+	u8 cur_beamform_cap = 0;
+
+	/*Config Tx beamforming setting*/
+	if (TEST_FLAG(phtpriv_ap->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE) &&
+		GET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP((u8 *)(&phtpriv_sta->ht_cap))) {
+		SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE);
+		/*Shift to BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP*/
+		SET_FLAG(cur_beamform_cap, GET_HT_CAP_TXBF_CHNL_ESTIMATION_NUM_ANTENNAS((u8 *)(&phtpriv_sta->ht_cap)) << 6);
+	}
+
+	if (TEST_FLAG(phtpriv_ap->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE) &&
+		GET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP((u8 *)(&phtpriv_sta->ht_cap))) {
+		SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE);
+		/*Shift to BEAMFORMING_HT_BEAMFORMER_STEER_NUM*/
+		SET_FLAG(cur_beamform_cap, GET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS((u8 *)(&phtpriv_sta->ht_cap)) << 4);
+	}
+	if (cur_beamform_cap)
+		RTW_INFO("Client STA(%d) HT Beamforming Cap = 0x%02X\n", psta->cmn.aid, cur_beamform_cap);
+
+	phtpriv_sta->beamform_cap = cur_beamform_cap;
+	psta->cmn.bf_info.ht_beamform_cap = cur_beamform_cap;
+
+}
+#endif /*CONFIG_80211N_HT && CONFIG_BEAMFORMING*/
+
+/* notes:
+ * AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode  */
+void update_sta_info_apmode(_adapter *padapter, struct sta_info *psta)
+{
+	_irqL	irqL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+#ifdef CONFIG_80211N_HT
+	struct ht_priv	*phtpriv_ap = &pmlmepriv->htpriv;
+	struct ht_priv	*phtpriv_sta = &psta->htpriv;
+#endif /* CONFIG_80211N_HT */
+	u8	cur_ldpc_cap = 0, cur_stbc_cap = 0;
+	/* set intf_tag to if1 */
+	/* psta->intf_tag = 0; */
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	/*alloc macid when call rtw_alloc_stainfo(),release macid when call rtw_free_stainfo()*/
+
+	if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
+		psta->ieee8021x_blocked = _TRUE;
+	else
+		psta->ieee8021x_blocked = _FALSE;
+
+
+	/* update sta's cap */
+
+	/* ERP */
+	VCS_update(padapter, psta);
+#ifdef CONFIG_80211N_HT
+	/* HT related cap */
+	if (phtpriv_sta->ht_option) {
+		/* check if sta supports rx ampdu */
+		phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable;
+
+		phtpriv_sta->rx_ampdu_min_spacing = (phtpriv_sta->ht_cap.ampdu_params_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
+
+		/* bwmode */
+		if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH))
+			psta->cmn.bw_mode = CHANNEL_WIDTH_40;
+		else
+			psta->cmn.bw_mode = CHANNEL_WIDTH_20;
+
+		if (psta->ht_40mhz_intolerant)
+			psta->cmn.bw_mode = CHANNEL_WIDTH_20;
+
+		if (pmlmeext->cur_bwmode < psta->cmn.bw_mode)
+			psta->cmn.bw_mode = pmlmeext->cur_bwmode;
+
+		phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
+
+
+		/* check if sta support s Short GI 20M */
+		if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20))
+			phtpriv_sta->sgi_20m = _TRUE;
+
+		/* check if sta support s Short GI 40M */
+		if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_40)) {
+			if (psta->cmn.bw_mode == CHANNEL_WIDTH_40) /* according to psta->bw_mode */
+				phtpriv_sta->sgi_40m = _TRUE;
+			else
+				phtpriv_sta->sgi_40m = _FALSE;
+		}
+
+		psta->qos_option = _TRUE;
+
+		/* B0 Config LDPC Coding Capability */
+		if (TEST_FLAG(phtpriv_ap->ldpc_cap, LDPC_HT_ENABLE_TX) &&
+		    GET_HT_CAP_ELE_LDPC_CAP((u8 *)(&phtpriv_sta->ht_cap))) {
+			SET_FLAG(cur_ldpc_cap, (LDPC_HT_ENABLE_TX | LDPC_HT_CAP_TX));
+			RTW_INFO("Enable HT Tx LDPC for STA(%d)\n", psta->cmn.aid);
+		}
+
+		/* B7 B8 B9 Config STBC setting */
+		if (TEST_FLAG(phtpriv_ap->stbc_cap, STBC_HT_ENABLE_TX) &&
+		    GET_HT_CAP_ELE_RX_STBC((u8 *)(&phtpriv_sta->ht_cap))) {
+			SET_FLAG(cur_stbc_cap, (STBC_HT_ENABLE_TX | STBC_HT_CAP_TX));
+			RTW_INFO("Enable HT Tx STBC for STA(%d)\n", psta->cmn.aid);
+		}
+
+		#ifdef CONFIG_BEAMFORMING
+		update_sta_info_apmode_ht_bf_cap(padapter, psta);
+		#endif
+	} else {
+		phtpriv_sta->ampdu_enable = _FALSE;
+
+		phtpriv_sta->sgi_20m = _FALSE;
+		phtpriv_sta->sgi_40m = _FALSE;
+		psta->cmn.bw_mode = CHANNEL_WIDTH_20;
+		phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	}
+
+	phtpriv_sta->ldpc_cap = cur_ldpc_cap;
+	phtpriv_sta->stbc_cap = cur_stbc_cap;
+
+	/* Rx AMPDU */
+	send_delba(padapter, 0, psta->cmn.mac_addr);/* recipient */
+
+	/* TX AMPDU */
+	send_delba(padapter, 1, psta->cmn.mac_addr);/*  */ /* originator */
+	phtpriv_sta->agg_enable_bitmap = 0x0;/* reset */
+	phtpriv_sta->candidate_tid_bitmap = 0x0;/* reset */
+#endif /* CONFIG_80211N_HT */
+
+#ifdef CONFIG_80211AC_VHT
+	update_sta_vht_info_apmode(padapter, psta);
+#endif
+	psta->cmn.ra_info.is_support_sgi = query_ra_short_GI(psta, rtw_get_tx_bw_mode(padapter, psta));
+	update_ldpc_stbc_cap(psta);
+
+	/* todo: init other variables */
+
+	_rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+
+	/* add ratid */
+	/* add_RATid(padapter, psta); */ /* move to ap_sta_info_defer_update() */
+
+	/* ap mode */
+	rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _TRUE);
+
+	_enter_critical_bh(&psta->lock, &irqL);
+	psta->state |= _FW_LINKED;
+	_exit_critical_bh(&psta->lock, &irqL);
+
+
+}
+
+static void update_ap_info(_adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+#ifdef CONFIG_80211N_HT
+	struct ht_priv	*phtpriv_ap = &pmlmepriv->htpriv;
+#endif /* CONFIG_80211N_HT */
+
+	psta->wireless_mode = pmlmeext->cur_wireless_mode;
+
+	psta->bssratelen = rtw_get_rateset_len(pnetwork->SupportedRates);
+	_rtw_memcpy(psta->bssrateset, pnetwork->SupportedRates, psta->bssratelen);
+
+#ifdef CONFIG_80211N_HT
+	/* HT related cap */
+	if (phtpriv_ap->ht_option) {
+		/* check if sta supports rx ampdu */
+		/* phtpriv_ap->ampdu_enable = phtpriv_ap->ampdu_enable; */
+
+		/* check if sta support s Short GI 20M */
+		if ((phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20))
+			phtpriv_ap->sgi_20m = _TRUE;
+		/* check if sta support s Short GI 40M */
+		if ((phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_40))
+			phtpriv_ap->sgi_40m = _TRUE;
+
+		psta->qos_option = _TRUE;
+	} else {
+		phtpriv_ap->ampdu_enable = _FALSE;
+
+		phtpriv_ap->sgi_20m = _FALSE;
+		phtpriv_ap->sgi_40m = _FALSE;
+	}
+
+	psta->cmn.bw_mode = pmlmeext->cur_bwmode;
+	phtpriv_ap->ch_offset = pmlmeext->cur_ch_offset;
+
+	phtpriv_ap->agg_enable_bitmap = 0x0;/* reset */
+	phtpriv_ap->candidate_tid_bitmap = 0x0;/* reset */
+
+	_rtw_memcpy(&psta->htpriv, &pmlmepriv->htpriv, sizeof(struct ht_priv));
+
+#ifdef CONFIG_80211AC_VHT
+	_rtw_memcpy(&psta->vhtpriv, &pmlmepriv->vhtpriv, sizeof(struct vht_priv));
+#endif /* CONFIG_80211AC_VHT */
+
+#endif /* CONFIG_80211N_HT */
+
+	psta->state |= WIFI_AP_STATE; /* Aries, add,fix bug of flush_cam_entry at STOP AP mode , 0724 */
+}
+
+static void rtw_set_hw_wmm_param(_adapter *padapter)
+{
+	u8	ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime;
+	u8	acm_mask;
+	u16	TXOP;
+	u32	acParm, i;
+	u32	edca[4], inx[4];
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct xmit_priv		*pxmitpriv = &padapter->xmitpriv;
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+
+	acm_mask = 0;
+
+	if (is_supported_5g(pmlmeext->cur_wireless_mode) ||
+	    (pmlmeext->cur_wireless_mode & WIRELESS_11_24N))
+		aSifsTime = 16;
+	else
+		aSifsTime = 10;
+
+	if (pmlmeinfo->WMM_enable == 0) {
+		padapter->mlmepriv.acm_mask = 0;
+
+		AIFS = aSifsTime + (2 * pmlmeinfo->slotTime);
+
+		if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11A)) {
+			ECWMin = 4;
+			ECWMax = 10;
+		} else if (pmlmeext->cur_wireless_mode & WIRELESS_11B) {
+			ECWMin = 5;
+			ECWMax = 10;
+		} else {
+			ECWMin = 4;
+			ECWMax = 10;
+		}
+
+		TXOP = 0;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm));
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm));
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm));
+
+		ECWMin = 2;
+		ECWMax = 3;
+		TXOP = 0x2f;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm));
+
+	} else {
+		edca[0] = edca[1] = edca[2] = edca[3] = 0;
+
+		/*TODO:*/
+		acm_mask = 0;
+		padapter->mlmepriv.acm_mask = acm_mask;
+
+#if 0
+		/* BK */
+		/* AIFS = AIFSN * slot time + SIFS - r2t phy delay */
+#endif
+		AIFS = (7 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 4;
+		ECWMax = 10;
+		TXOP = 0;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm));
+		edca[XMIT_BK_QUEUE] = acParm;
+		RTW_INFO("WMM(BK): %x\n", acParm);
+
+		/* BE */
+		AIFS = (3 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 4;
+		ECWMax = 6;
+		TXOP = 0;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm));
+		edca[XMIT_BE_QUEUE] = acParm;
+		RTW_INFO("WMM(BE): %x\n", acParm);
+
+		/* VI */
+		AIFS = (1 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 3;
+		ECWMax = 4;
+		TXOP = 94;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm));
+		edca[XMIT_VI_QUEUE] = acParm;
+		RTW_INFO("WMM(VI): %x\n", acParm);
+
+		/* VO */
+		AIFS = (1 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 2;
+		ECWMax = 3;
+		TXOP = 47;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm));
+		edca[XMIT_VO_QUEUE] = acParm;
+		RTW_INFO("WMM(VO): %x\n", acParm);
+
+
+		if (padapter->registrypriv.acm_method == 1)
+			rtw_hal_set_hwreg(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask));
+		else
+			padapter->mlmepriv.acm_mask = acm_mask;
+
+		inx[0] = 0;
+		inx[1] = 1;
+		inx[2] = 2;
+		inx[3] = 3;
+
+		if (pregpriv->wifi_spec == 1) {
+			u32	j, tmp, change_inx = _FALSE;
+
+			/* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */
+			for (i = 0 ; i < 4 ; i++) {
+				for (j = i + 1 ; j < 4 ; j++) {
+					/* compare CW and AIFS */
+					if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF))
+						change_inx = _TRUE;
+					else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) {
+						/* compare TXOP */
+						if ((edca[j] >> 16) > (edca[i] >> 16))
+							change_inx = _TRUE;
+					}
+
+					if (change_inx) {
+						tmp = edca[i];
+						edca[i] = edca[j];
+						edca[j] = tmp;
+
+						tmp = inx[i];
+						inx[i] = inx[j];
+						inx[j] = tmp;
+
+						change_inx = _FALSE;
+					}
+				}
+			}
+		}
+
+		for (i = 0 ; i < 4 ; i++) {
+			pxmitpriv->wmm_para_seq[i] = inx[i];
+			RTW_INFO("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]);
+		}
+
+	}
+
+}
+
+static void update_hw_ht_param(_adapter *padapter)
+{
+	unsigned char		max_AMPDU_len;
+	unsigned char		min_MPDU_spacing;
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+
+	/* handle A-MPDU parameter field */
+	/*
+		AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+		AMPDU_para [4:2]:Min MPDU Start Spacing
+	*/
+	max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;
+
+	min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2;
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing));
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len));
+
+	/*  */
+	/* Config SM Power Save setting */
+	/*  */
+	pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2;
+	if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) {
+#if 0
+		u8 i;
+		/* update the MCS rates */
+		for (i = 0; i < 16; i++)
+			pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i];
+#endif
+		RTW_INFO("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __FUNCTION__);
+	}
+
+	/*  */
+	/* Config current HT Protection mode. */
+	/*  */
+	/* pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; */
+
+}
+
+static void rtw_ap_check_scan(_adapter *padapter)
+{
+	_irqL	irqL;
+	_list		*plist, *phead;
+	u32	delta_time, lifetime;
+	struct	wlan_network	*pnetwork = NULL;
+	WLAN_BSSID_EX *pbss = NULL;
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	_queue	*queue	= &(pmlmepriv->scanned_queue);
+	u8 do_scan = _FALSE;
+	u8 reason = RTW_AUTO_SCAN_REASON_UNSPECIFIED;
+
+	lifetime = SCANQUEUE_LIFETIME; /* 20 sec */
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+	phead = get_list_head(queue);
+	if (rtw_end_of_queue_search(phead, get_next(phead)) == _TRUE)
+		if (padapter->registrypriv.wifi_spec) {
+			do_scan = _TRUE;
+			reason |= RTW_AUTO_SCAN_REASON_2040_BSS;
+		}
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+#ifdef CONFIG_RTW_ACS
+	if (padapter->registrypriv.acs_auto_scan) {
+		do_scan = _TRUE;
+		reason |= RTW_AUTO_SCAN_REASON_ACS;
+		rtw_acs_start(padapter);
+	}
+#endif/*CONFIG_RTW_ACS*/
+
+	if (_TRUE == do_scan) {
+		RTW_INFO("%s : drv scans by itself and wait_completed\n", __func__);
+		rtw_drv_scan_by_self(padapter, reason);
+		rtw_scan_wait_completed(padapter);
+	}
+
+#ifdef CONFIG_RTW_ACS
+	if (padapter->registrypriv.acs_auto_scan)
+		rtw_acs_stop(padapter);
+#endif
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+
+		if (rtw_end_of_queue_search(phead, plist) == _TRUE)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		if (rtw_chset_search_ch(adapter_to_chset(padapter), pnetwork->network.Configuration.DSConfig) >= 0
+		    && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig) == _TRUE
+		    && _TRUE == rtw_validate_ssid(&(pnetwork->network.Ssid))) {
+			delta_time = (u32) rtw_get_passing_time_ms(pnetwork->last_scanned);
+
+			if (delta_time < lifetime) {
+
+				uint ie_len = 0;
+				u8 *pbuf = NULL;
+				u8 *ie = NULL;
+
+				pbss = &pnetwork->network;
+				ie = pbss->IEs;
+
+				/*check if HT CAP INFO IE exists or not*/
+				pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pbss->IELength - _BEACON_IE_OFFSET_));
+				if (pbuf == NULL) {
+					/* HT CAP INFO IE don't exist, it is b/g mode bss.*/
+
+					if (_FALSE == ATOMIC_READ(&pmlmepriv->olbc))
+						ATOMIC_SET(&pmlmepriv->olbc, _TRUE);
+
+					if (_FALSE == ATOMIC_READ(&pmlmepriv->olbc_ht))
+						ATOMIC_SET(&pmlmepriv->olbc_ht, _TRUE);
+					
+					if (padapter->registrypriv.wifi_spec)
+						RTW_INFO("%s: %s is a/b/g ap\n", __func__, pnetwork->network.Ssid.Ssid);
+				}
+			}
+		}
+
+		plist = get_next(plist);
+
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	pmlmepriv->num_sta_no_ht = 0; /* reset to 0 after ap do scanning*/
+
+}
+
+void rtw_start_bss_hdl_after_chbw_decided(_adapter *adapter)
+{
+	WLAN_BSSID_EX *pnetwork = &(adapter->mlmepriv.cur_network.network);
+	struct sta_info *sta = NULL;
+
+	/* update cur_wireless_mode */
+	update_wireless_mode(adapter);
+
+	/* update RRSR and RTS_INIT_RATE register after set channel and bandwidth */
+	UpdateBrateTbl(adapter, pnetwork->SupportedRates);
+	rtw_hal_set_hwreg(adapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates);
+
+	/* update capability after cur_wireless_mode updated */
+	update_capinfo(adapter, rtw_get_capability(pnetwork));
+
+	/* update bc/mc sta_info */
+	update_bmc_sta(adapter);
+
+	/* update AP's sta info */
+	sta = rtw_get_stainfo(&adapter->stapriv, pnetwork->MacAddress);
+	if (!sta) {
+		RTW_INFO(FUNC_ADPT_FMT" !sta for macaddr="MAC_FMT"\n", FUNC_ADPT_ARG(adapter), MAC_ARG(pnetwork->MacAddress));
+		rtw_warn_on(1);
+		return;
+	}
+
+	update_ap_info(adapter, sta);
+}
+
+void start_bss_network(_adapter *padapter, struct createbss_parm *parm)
+{
+#define DUMP_ADAPTERS_STATUS 0
+	u8 self_action = MLME_ACTION_UNKNOWN;
+	u8 val8;
+	u16 bcn_interval;
+	u32	acparm;
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct security_priv *psecuritypriv = &(padapter->securitypriv);
+	WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; /* used as input */
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network);
+	struct dvobj_priv *pdvobj = padapter->dvobj;
+	s16 req_ch = REQ_CH_NONE, req_bw = REQ_BW_NONE, req_offset = REQ_OFFSET_NONE;
+	bool ch_setting_changed = _FALSE;
+	u8 ch_to_set = 0, bw_to_set, offset_to_set;
+	u8 doiqk = _FALSE;
+	/* use for check ch bw offset can be allowed or not */
+	u8 chbw_allow = _TRUE;
+
+	if (MLME_IS_AP(padapter))
+		self_action = MLME_AP_STARTED;
+	else if (MLME_IS_MESH(padapter))
+		self_action = MLME_MESH_STARTED;
+	else
+		rtw_warn_on(1);
+
+	if (parm->req_ch != 0) {
+		/* bypass other setting, go checking ch, bw, offset */
+		req_ch = parm->req_ch;
+		req_bw = parm->req_bw;
+		req_offset = parm->req_offset;
+		goto chbw_decision;
+	} else {
+		/* inform this request comes from upper layer */
+		req_ch = 0;
+		_rtw_memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length);
+	}
+
+	bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod;
+
+	/* check if there is wps ie, */
+	/* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */
+	/* and at first time the security ie ( RSN/WPA IE) will not include in beacon. */
+	if (NULL == rtw_get_wps_ie(pnetwork->IEs + _FIXED_IE_LENGTH_, pnetwork->IELength - _FIXED_IE_LENGTH_, NULL, NULL))
+		pmlmeext->bstart_bss = _TRUE;
+
+	/* todo: update wmm, ht cap */
+	/* pmlmeinfo->WMM_enable; */
+	/* pmlmeinfo->HT_enable; */
+	if (pmlmepriv->qospriv.qos_option)
+		pmlmeinfo->WMM_enable = _TRUE;
+#ifdef CONFIG_80211N_HT
+	if (pmlmepriv->htpriv.ht_option) {
+		pmlmeinfo->WMM_enable = _TRUE;
+		pmlmeinfo->HT_enable = _TRUE;
+		/* pmlmeinfo->HT_info_enable = _TRUE; */
+		/* pmlmeinfo->HT_caps_enable = _TRUE; */
+
+		update_hw_ht_param(padapter);
+	}
+#endif /* #CONFIG_80211N_HT */
+
+#ifdef CONFIG_80211AC_VHT
+	if (pmlmepriv->vhtpriv.vht_option) {
+		pmlmeinfo->VHT_enable = _TRUE;
+		update_hw_vht_param(padapter);
+	}
+#endif /* CONFIG_80211AC_VHT */
+
+	if (pmlmepriv->cur_network.join_res != _TRUE) { /* setting only at  first time */
+		/* WEP Key will be set before this function, do not clear CAM. */
+		if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_))
+			flush_all_cam_entry(padapter);	/* clear CAM */
+	}
+
+	/* set MSR to AP_Mode		 */
+	Set_MSR(padapter, _HW_STATE_AP_);
+
+	/* Set BSSID REG */
+	rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pnetwork->MacAddress);
+
+	/* Set EDCA param reg */
+#ifdef CONFIG_CONCURRENT_MODE
+	acparm = 0x005ea42b;
+#else
+	acparm = 0x002F3217; /* VO */
+#endif
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm));
+	acparm = 0x005E4317; /* VI */
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm));
+	/* acparm = 0x00105320; */ /* BE */
+	acparm = 0x005ea42b;
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm));
+	acparm = 0x0000A444; /* BK */
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm));
+
+	/* Set Security */
+	val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf;
+	rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+	/* Beacon Control related register */
+	rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval));
+
+chbw_decision:
+	ch_setting_changed = rtw_ap_chbw_decision(padapter, req_ch, req_bw, req_offset
+		     , &ch_to_set, &bw_to_set, &offset_to_set, &chbw_allow);
+
+	/* let pnetwork_mlme == pnetwork_mlmeext */
+	_rtw_memcpy(pnetwork, pnetwork_mlmeext, pnetwork_mlmeext->Length);
+
+	rtw_start_bss_hdl_after_chbw_decided(padapter);
+
+#if defined(CONFIG_DFS_MASTER)
+	rtw_dfs_master_status_apply(padapter, self_action);
+#endif
+	rtw_hal_rcr_set_chk_bssid(padapter, self_action);
+
+#ifdef CONFIG_MCC_MODE
+	if (MCC_EN(padapter)) {
+		/* 
+		* due to check under rtw_ap_chbw_decision
+		* if under MCC mode, means req channel setting is the same as current channel setting
+		* if not under MCC mode, mean req channel setting is not the same as current channel setting
+		*/
+		if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) {
+				RTW_INFO(FUNC_ADPT_FMT": req channel setting is the same as current channel setting, go to update BCN\n"
+				, FUNC_ADPT_ARG(padapter));
+
+				goto update_beacon;
+
+		}
+	}
+
+	/* issue null data to AP for all interface connecting to AP before switch channel setting for softap */
+	rtw_hal_mcc_issue_null_data(padapter, chbw_allow, 1);
+#endif /* CONFIG_MCC_MODE */
+
+	if (!IS_CH_WAITING(adapter_to_rfctl(padapter))) {
+		doiqk = _TRUE;
+		rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk);
+	}
+
+	if (ch_to_set != 0) {
+		set_channel_bwmode(padapter, ch_to_set, offset_to_set, bw_to_set);
+		rtw_mi_update_union_chan_inf(padapter, ch_to_set, offset_to_set, bw_to_set);
+	}
+
+	doiqk = _FALSE;
+	rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk);
+
+#ifdef CONFIG_MCC_MODE
+	/* after set_channel_bwmode for backup IQK */
+	rtw_hal_set_mcc_setting_start_bss_network(padapter, chbw_allow);
+#endif
+
+	if (ch_setting_changed == _TRUE
+		&& (MLME_IS_GO(padapter) || MLME_IS_MESH(padapter)) /* pure AP is not needed*/
+	) {
+		#if defined(CONFIG_IOCTL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+		rtw_cfg80211_ch_switch_notify(padapter
+			, pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset
+			, pmlmepriv->htpriv.ht_option);
+		#endif
+	}
+
+	if (DUMP_ADAPTERS_STATUS) {
+		RTW_INFO(FUNC_ADPT_FMT" done\n", FUNC_ADPT_ARG(padapter));
+		dump_adapters_status(RTW_DBGDUMP , adapter_to_dvobj(padapter));
+	}
+
+update_beacon:
+	/* update beacon content only if bstart_bss is _TRUE */
+	if (_TRUE == pmlmeext->bstart_bss) {
+
+		_irqL irqL;
+
+		if ((ATOMIC_READ(&pmlmepriv->olbc) == _TRUE) || (ATOMIC_READ(&pmlmepriv->olbc_ht) == _TRUE)) {
+			/* AP is not starting a 40 MHz BSS in presence of an 802.11g BSS. */
+
+			pmlmepriv->ht_op_mode &= (~HT_INFO_OPERATION_MODE_OP_MODE_MASK);
+			pmlmepriv->ht_op_mode |= OP_MODE_MAY_BE_LEGACY_STAS;
+			update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _FALSE);
+		}
+
+		update_beacon(padapter, _TIM_IE_, NULL, _FALSE);
+
+#ifdef CONFIG_SWTIMER_BASED_TXBCN
+		_enter_critical_bh(&pdvobj->ap_if_q.lock, &irqL);
+		if (rtw_is_list_empty(&padapter->list)) {
+			rtw_list_insert_tail(&padapter->list, get_list_head(&pdvobj->ap_if_q));
+			pdvobj->nr_ap_if++;
+			pdvobj->inter_bcn_space = DEFAULT_BCN_INTERVAL / pdvobj->nr_ap_if;
+		}
+		_exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL);
+
+		rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pdvobj->inter_bcn_space));
+
+#endif /*CONFIG_SWTIMER_BASED_TXBCN*/
+
+	}
+
+	rtw_scan_wait_completed(padapter);
+
+	/* send beacon */
+	if (!rtw_mi_check_fwstate(padapter, _FW_UNDER_SURVEY)) {
+
+		/*update_beacon(padapter, _TIM_IE_, NULL, _TRUE);*/
+
+#if !defined(CONFIG_INTERRUPT_BASED_TXBCN)
+#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
+#ifdef CONFIG_SWTIMER_BASED_TXBCN
+		if (pdvobj->nr_ap_if == 1) {
+			RTW_INFO("start SW BCN TIMER!\n");
+			_set_timer(&pdvobj->txbcn_timer, bcn_interval);
+		}
+#else
+		/* other case will  tx beacon when bcn interrupt coming in. */
+		if (send_beacon(padapter) == _FAIL)
+			RTW_INFO("issue_beacon, fail!\n");
+#endif
+#endif
+#endif /* !defined(CONFIG_INTERRUPT_BASED_TXBCN) */
+	}
+
+	/*Set EDCA param reg after update cur_wireless_mode & update_capinfo*/
+	if (pregpriv->wifi_spec == 1)
+		rtw_set_hw_wmm_param(padapter);
+
+	/*pmlmeext->bstart_bss = _TRUE;*/
+}
+
+int rtw_check_beacon_data(_adapter *padapter, u8 *pbuf,  int len)
+{
+	int ret = _SUCCESS;
+	u8 *p;
+	u8 *pHT_caps_ie = NULL;
+	u8 *pHT_info_ie = NULL;
+	u16 cap, ht_cap = _FALSE;
+	uint ie_len = 0;
+	int group_cipher, pairwise_cipher;
+	u8	channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX];
+	int supportRateNum = 0;
+	u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01};
+	u8 wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+	u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
+	struct registry_priv *pregistrypriv = &padapter->registrypriv;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	WLAN_BSSID_EX *pbss_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 *ie = pbss_network->IEs;
+	u8 vht_cap = _FALSE;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
+	u8 rf_num = 0;
+
+	/* SSID */
+	/* Supported rates */
+	/* DS Params */
+	/* WLAN_EID_COUNTRY */
+	/* ERP Information element */
+	/* Extended supported rates */
+	/* WPA/WPA2 */
+	/* Wi-Fi Wireless Multimedia Extensions */
+	/* ht_capab, ht_oper */
+	/* WPS IE */
+
+	RTW_INFO("%s, len=%d\n", __FUNCTION__, len);
+
+	if (!MLME_IS_AP(padapter) && !MLME_IS_MESH(padapter))
+		return _FAIL;
+
+
+	if (len > MAX_IE_SZ)
+		return _FAIL;
+
+	pbss_network->IELength = len;
+
+	_rtw_memset(ie, 0, MAX_IE_SZ);
+
+	_rtw_memcpy(ie, pbuf, pbss_network->IELength);
+
+
+	if (pbss_network->InfrastructureMode != Ndis802_11APMode) {
+		rtw_warn_on(1);
+		return _FAIL;
+	}
+
+
+	rtw_ap_check_scan(padapter);
+
+
+	pbss_network->Rssi = 0;
+
+	_rtw_memcpy(pbss_network->MacAddress, adapter_mac_addr(padapter), ETH_ALEN);
+
+	/* beacon interval */
+	p = rtw_get_beacon_interval_from_ie(ie);/* ie + 8;	 */ /* 8: TimeStamp, 2: Beacon Interval 2:Capability */
+	/* pbss_network->Configuration.BeaconPeriod = le16_to_cpu(*(unsigned short*)p); */
+	pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p);
+
+	/* capability */
+	/* cap = *(unsigned short *)rtw_get_capability_from_ie(ie); */
+	/* cap = le16_to_cpu(cap); */
+	cap = RTW_GET_LE16(ie);
+
+	/* SSID */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0) {
+		_rtw_memset(&pbss_network->Ssid, 0, sizeof(NDIS_802_11_SSID));
+		_rtw_memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len);
+		pbss_network->Ssid.SsidLength = ie_len;
+#ifdef CONFIG_P2P
+		_rtw_memcpy(padapter->wdinfo.p2p_group_ssid, pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength);
+		padapter->wdinfo.p2p_group_ssid_len = pbss_network->Ssid.SsidLength;
+#endif
+	}
+
+	/* chnnel */
+	channel = 0;
+	pbss_network->Configuration.Length = 0;
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0)
+		channel = *(p + 2);
+
+	pbss_network->Configuration.DSConfig = channel;
+
+
+	_rtw_memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX);
+	/* get supported rates */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p !=  NULL) {
+		_rtw_memcpy(supportRate, p + 2, ie_len);
+		supportRateNum = ie_len;
+	}
+
+	/* get ext_supported rates */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_);
+	if (p !=  NULL) {
+		_rtw_memcpy(supportRate + supportRateNum, p + 2, ie_len);
+		supportRateNum += ie_len;
+
+	}
+
+	network_type = rtw_check_network_type(supportRate, supportRateNum, channel);
+
+	rtw_set_supported_rate(pbss_network->SupportedRates, network_type);
+
+
+	/* parsing ERP_IE */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0)
+		ERP_IE_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)p);
+
+	/* update privacy/security */
+	if (cap & BIT(4))
+		pbss_network->Privacy = 1;
+	else
+		pbss_network->Privacy = 0;
+
+	psecuritypriv->wpa_psk = 0;
+
+	/* wpa2 */
+	group_cipher = 0;
+	pairwise_cipher = 0;
+	psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_;
+	psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_;
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0) {
+		if (rtw_parse_wpa2_ie(p, ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+			psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+			psecuritypriv->dot8021xalg = 1;/* psk,  todo:802.1x */
+			psecuritypriv->wpa_psk |= BIT(1);
+
+			psecuritypriv->wpa2_group_cipher = group_cipher;
+			psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher;
+#if 0
+			switch (group_cipher) {
+			case WPA_CIPHER_NONE:
+				psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_;
+				break;
+			case WPA_CIPHER_WEP40:
+				psecuritypriv->wpa2_group_cipher = _WEP40_;
+				break;
+			case WPA_CIPHER_TKIP:
+				psecuritypriv->wpa2_group_cipher = _TKIP_;
+				break;
+			case WPA_CIPHER_CCMP:
+				psecuritypriv->wpa2_group_cipher = _AES_;
+				break;
+			case WPA_CIPHER_WEP104:
+				psecuritypriv->wpa2_group_cipher = _WEP104_;
+				break;
+			}
+
+			switch (pairwise_cipher) {
+			case WPA_CIPHER_NONE:
+				psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_;
+				break;
+			case WPA_CIPHER_WEP40:
+				psecuritypriv->wpa2_pairwise_cipher = _WEP40_;
+				break;
+			case WPA_CIPHER_TKIP:
+				psecuritypriv->wpa2_pairwise_cipher = _TKIP_;
+				break;
+			case WPA_CIPHER_CCMP:
+				psecuritypriv->wpa2_pairwise_cipher = _AES_;
+				break;
+			case WPA_CIPHER_WEP104:
+				psecuritypriv->wpa2_pairwise_cipher = _WEP104_;
+				break;
+			}
+#endif
+		}
+
+	}
+
+	/* wpa */
+	ie_len = 0;
+	group_cipher = 0;
+	pairwise_cipher = 0;
+	psecuritypriv->wpa_group_cipher = _NO_PRIVACY_;
+	psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_;
+	for (p = ie + _BEACON_IE_OFFSET_; ; p += (ie_len + 2)) {
+		p = rtw_get_ie(p, _SSN_IE_1_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
+		if ((p) && (_rtw_memcmp(p + 2, OUI1, 4))) {
+			if (rtw_parse_wpa_ie(p, ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+				psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+				psecuritypriv->dot8021xalg = 1;/* psk,  todo:802.1x */
+
+				psecuritypriv->wpa_psk |= BIT(0);
+
+				psecuritypriv->wpa_group_cipher = group_cipher;
+				psecuritypriv->wpa_pairwise_cipher = pairwise_cipher;
+
+#if 0
+				switch (group_cipher) {
+				case WPA_CIPHER_NONE:
+					psecuritypriv->wpa_group_cipher = _NO_PRIVACY_;
+					break;
+				case WPA_CIPHER_WEP40:
+					psecuritypriv->wpa_group_cipher = _WEP40_;
+					break;
+				case WPA_CIPHER_TKIP:
+					psecuritypriv->wpa_group_cipher = _TKIP_;
+					break;
+				case WPA_CIPHER_CCMP:
+					psecuritypriv->wpa_group_cipher = _AES_;
+					break;
+				case WPA_CIPHER_WEP104:
+					psecuritypriv->wpa_group_cipher = _WEP104_;
+					break;
+				}
+
+				switch (pairwise_cipher) {
+				case WPA_CIPHER_NONE:
+					psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_;
+					break;
+				case WPA_CIPHER_WEP40:
+					psecuritypriv->wpa_pairwise_cipher = _WEP40_;
+					break;
+				case WPA_CIPHER_TKIP:
+					psecuritypriv->wpa_pairwise_cipher = _TKIP_;
+					break;
+				case WPA_CIPHER_CCMP:
+					psecuritypriv->wpa_pairwise_cipher = _AES_;
+					break;
+				case WPA_CIPHER_WEP104:
+					psecuritypriv->wpa_pairwise_cipher = _WEP104_;
+					break;
+				}
+#endif
+			}
+
+			break;
+
+		}
+
+		if ((p == NULL) || (ie_len == 0))
+			break;
+
+	}
+
+	/* wmm */
+	ie_len = 0;
+	pmlmepriv->qospriv.qos_option = 0;
+	if (pregistrypriv->wmm_enable) {
+		for (p = ie + _BEACON_IE_OFFSET_; ; p += (ie_len + 2)) {
+			p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
+			if ((p) && _rtw_memcmp(p + 2, WMM_PARA_IE, 6)) {
+				pmlmepriv->qospriv.qos_option = 1;
+
+				*(p + 8) |= BIT(7); /* QoS Info, support U-APSD */
+
+				/* disable all ACM bits since the WMM admission control is not supported */
+				*(p + 10) &= ~BIT(4); /* BE */
+				*(p + 14) &= ~BIT(4); /* BK */
+				*(p + 18) &= ~BIT(4); /* VI */
+				*(p + 22) &= ~BIT(4); /* VO */
+
+				break;
+			}
+
+			if ((p == NULL) || (ie_len == 0))
+				break;
+		}
+	}
+#ifdef CONFIG_80211N_HT
+	/* parsing HT_CAP_IE */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0) {
+		u8 rf_type = 0;
+		HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor = MAX_AMPDU_FACTOR_64K;
+		struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2);
+
+		if (0) {
+			RTW_INFO(FUNC_ADPT_FMT" HT_CAP_IE from upper layer:\n", FUNC_ADPT_ARG(padapter));
+			dump_ht_cap_ie_content(RTW_DBGDUMP, p + 2, ie_len);
+		}
+
+		pHT_caps_ie = p;
+
+		ht_cap = _TRUE;
+		network_type |= WIRELESS_11_24N;
+
+		rtw_ht_use_default_setting(padapter);
+
+		/* Update HT Capabilities Info field */
+		if (pmlmepriv->htpriv.sgi_20m == _FALSE)
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_SGI_20);
+
+		if (pmlmepriv->htpriv.sgi_40m == _FALSE)
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_SGI_40);
+
+		if (!TEST_FLAG(pmlmepriv->htpriv.ldpc_cap, LDPC_HT_ENABLE_RX))
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_LDPC_CODING);
+
+		if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_TX))
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_TX_STBC);
+
+		if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_RX))
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_RX_STBC_3R);
+
+		/* Update A-MPDU Parameters field */
+		pht_cap->ampdu_params_info &= ~(IEEE80211_HT_CAP_AMPDU_FACTOR | IEEE80211_HT_CAP_AMPDU_DENSITY);
+
+		if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) ||
+		    (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP))
+			pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & (0x07 << 2));
+		else
+			pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00);
+
+		rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
+		pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & max_rx_ampdu_factor); /* set  Max Rx AMPDU size  to 64K */
+
+		_rtw_memcpy(&(pmlmeinfo->HT_caps), pht_cap, sizeof(struct HT_caps_element));
+
+		/* Update Supported MCS Set field */
+		{
+			struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
+			u8 rx_nss = 0;
+			int i;
+
+			rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+			rx_nss = rtw_min(rf_type_to_rf_rx_cnt(rf_type), hal_spec->rx_nss_num);
+
+			/* RX MCS Bitmask */
+			switch (rx_nss) {
+			case 1:
+				set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_1R);
+				break;
+			case 2:
+				set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_2R);
+				break;
+			case 3:
+				set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_3R);
+				break;
+			case 4:
+				set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_4R);
+				break;
+			default:
+				RTW_WARN("rf_type:%d or rx_nss:%u is not expected\n", rf_type, hal_spec->rx_nss_num);
+			}
+			for (i = 0; i < 10; i++)
+				*(HT_CAP_ELE_RX_MCS_MAP(pht_cap) + i) &= padapter->mlmeextpriv.default_supported_mcs_set[i];
+		}
+
+#ifdef CONFIG_BEAMFORMING
+		/* Use registry value to enable HT Beamforming. */
+		/* ToDo: use configure file to set these capability. */
+		pht_cap->tx_BF_cap_info = 0;
+
+		/* HT Beamformer */
+		if (TEST_FLAG(pmlmepriv->htpriv.beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) {
+			/* Transmit NDP Capable */
+			SET_HT_CAP_TXBF_TRANSMIT_NDP_CAP(pht_cap, 1);
+			/* Explicit Compressed Steering Capable */
+			SET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(pht_cap, 1);
+			/* Compressed Steering Number Antennas */
+			SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(pht_cap, 1);
+			rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMER_CAP, (u8 *)&rf_num);
+			SET_HT_CAP_TXBF_CHNL_ESTIMATION_NUM_ANTENNAS(pht_cap, rf_num);
+		}
+
+		/* HT Beamformee */
+		if (TEST_FLAG(pmlmepriv->htpriv.beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) {
+			/* Receive NDP Capable */
+			SET_HT_CAP_TXBF_RECEIVE_NDP_CAP(pht_cap, 1);
+			/* Explicit Compressed Beamforming Feedback Capable */
+			SET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(pht_cap, 2);
+			rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMEE_CAP, (u8 *)&rf_num);
+			SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(pht_cap, rf_num);
+		}
+#endif /* CONFIG_BEAMFORMING */
+
+		_rtw_memcpy(&pmlmepriv->htpriv.ht_cap, p + 2, ie_len);
+
+		if (0) {
+			RTW_INFO(FUNC_ADPT_FMT" HT_CAP_IE driver masked:\n", FUNC_ADPT_ARG(padapter));
+			dump_ht_cap_ie_content(RTW_DBGDUMP, p + 2, ie_len);
+		}
+	}
+
+	/* parsing HT_INFO_IE */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0) {
+		pHT_info_ie = p;
+		if (channel == 0)
+			pbss_network->Configuration.DSConfig = GET_HT_OP_ELE_PRI_CHL(pHT_info_ie + 2);
+		else if (channel != GET_HT_OP_ELE_PRI_CHL(pHT_info_ie + 2)) {
+			RTW_INFO(FUNC_ADPT_FMT" ch inconsistent, DSSS:%u, HT primary:%u\n"
+				, FUNC_ADPT_ARG(padapter), channel, GET_HT_OP_ELE_PRI_CHL(pHT_info_ie + 2));
+		}
+	}
+#endif /* CONFIG_80211N_HT */
+
+	switch (network_type) {
+	case WIRELESS_11B:
+		pbss_network->NetworkTypeInUse = Ndis802_11DS;
+		break;
+	case WIRELESS_11G:
+	case WIRELESS_11BG:
+	case WIRELESS_11G_24N:
+	case WIRELESS_11BG_24N:
+		pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+		break;
+	case WIRELESS_11A:
+		pbss_network->NetworkTypeInUse = Ndis802_11OFDM5;
+		break;
+	default:
+		pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+		break;
+	}
+
+	pmlmepriv->cur_network.network_type = network_type;
+
+#ifdef CONFIG_80211N_HT
+	pmlmepriv->htpriv.ht_option = _FALSE;
+
+	if ((psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) ||
+	    (psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) {
+		/* todo: */
+		/* ht_cap = _FALSE; */
+	}
+
+	/* ht_cap	 */
+	if (pregistrypriv->ht_enable && ht_cap == _TRUE) {
+		pmlmepriv->htpriv.ht_option = _TRUE;
+		pmlmepriv->qospriv.qos_option = 1;
+
+		pmlmepriv->htpriv.ampdu_enable = pregistrypriv->ampdu_enable ? _TRUE : _FALSE;
+
+		HT_caps_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_caps_ie);
+
+		HT_info_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_info_ie);
+	}
+#endif
+
+#ifdef CONFIG_80211AC_VHT
+
+	/* Parsing VHT CAP IE */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0)
+		vht_cap = _TRUE;
+	/* Parsing VHT OPERATION IE */
+
+	pmlmepriv->ori_vht_en = 0;
+	pmlmepriv->vhtpriv.vht_option = _FALSE;
+	/* if channel in 5G band, then add vht ie . */
+	if ((pbss_network->Configuration.DSConfig > 14)
+		&& (pmlmepriv->htpriv.ht_option == _TRUE)
+		&& REGSTY_IS_11AC_ENABLE(pregistrypriv)
+		&& hal_chk_proto_cap(padapter, PROTO_CAP_11AC)
+		&& (!rfctl->country_ent || COUNTRY_CHPLAN_EN_11AC(rfctl->country_ent))
+	) {
+		if (vht_cap == _TRUE) {
+			rtw_check_for_vht20(padapter, ie + _BEACON_IE_OFFSET_, pbss_network->IELength - _BEACON_IE_OFFSET_);
+			pmlmepriv->ori_vht_en = 1;
+			pmlmepriv->vhtpriv.vht_option = _TRUE;
+		} else if (REGSTY_IS_11AC_AUTO(pregistrypriv))
+			rtw_vht_ies_attach(padapter, pbss_network);
+	}
+#endif /* CONFIG_80211AC_VHT */
+
+	if(pbss_network->Configuration.DSConfig <= 14 && padapter->registrypriv.wifi_spec == 1) {
+		uint len = 0;
+
+		SET_EXT_CAPABILITY_ELE_BSS_COEXIST(pmlmepriv->ext_capab_ie_data, 1);
+		pmlmepriv->ext_capab_ie_len = 10;
+		rtw_set_ie(pbss_network->IEs + pbss_network->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len);
+		pbss_network->IELength += pmlmepriv->ext_capab_ie_len;
+	}
+
+	pbss_network->Length = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX *)pbss_network);
+
+	rtw_ies_get_chbw(pbss_network->IEs + _BEACON_IE_OFFSET_, pbss_network->IELength - _BEACON_IE_OFFSET_
+		, &pmlmepriv->ori_ch, &pmlmepriv->ori_bw, &pmlmepriv->ori_offset, 1, 1);
+	rtw_warn_on(pmlmepriv->ori_ch == 0);
+
+	{
+		/* alloc sta_info for ap itself */
+
+		struct sta_info *sta;
+
+		sta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+		if (!sta) {
+			sta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+			if (sta == NULL)
+				return _FAIL;
+		}
+	}
+
+	rtw_startbss_cmd(padapter, RTW_CMDF_WAIT_ACK);
+	{
+		int sk_band = RTW_GET_SCAN_BAND_SKIP(padapter);
+
+		if (sk_band)
+			RTW_CLR_SCAN_BAND_SKIP(padapter, sk_band);
+	}
+
+	rtw_indicate_connect(padapter);
+
+	pmlmepriv->cur_network.join_res = _TRUE;/* for check if already set beacon */
+
+	/* update bc/mc sta_info */
+	/* update_bmc_sta(padapter); */
+
+	return ret;
+
+}
+
+#if CONFIG_RTW_MACADDR_ACL
+void rtw_macaddr_acl_init(_adapter *adapter)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl = &stapriv->acl_list;
+	_queue *acl_node_q = &acl->acl_node_q;
+	int i;
+	_irqL irqL;
+
+	_enter_critical_bh(&(acl_node_q->lock), &irqL);
+	_rtw_init_listhead(&(acl_node_q->queue));
+	acl->num = 0;
+	acl->mode = RTW_ACL_MODE_DISABLED;
+	for (i = 0; i < NUM_ACL; i++) {
+		_rtw_init_listhead(&acl->aclnode[i].list);
+		acl->aclnode[i].valid = _FALSE;
+	}
+	_exit_critical_bh(&(acl_node_q->lock), &irqL);
+}
+
+void rtw_macaddr_acl_deinit(_adapter *adapter)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl = &stapriv->acl_list;
+	_queue *acl_node_q = &acl->acl_node_q;
+	_irqL irqL;
+	_list *head, *list;
+	struct rtw_wlan_acl_node *acl_node;
+
+	_enter_critical_bh(&(acl_node_q->lock), &irqL);
+	head = get_list_head(acl_node_q);
+	list = get_next(head);
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		acl_node = LIST_CONTAINOR(list, struct rtw_wlan_acl_node, list);
+		list = get_next(list);
+
+		if (acl_node->valid == _TRUE) {
+			acl_node->valid = _FALSE;
+			rtw_list_delete(&acl_node->list);
+			acl->num--;
+		}
+	}
+	_exit_critical_bh(&(acl_node_q->lock), &irqL);
+
+	rtw_warn_on(acl->num);
+	acl->mode = RTW_ACL_MODE_DISABLED;
+}
+
+void rtw_set_macaddr_acl(_adapter *adapter, int mode)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl = &stapriv->acl_list;
+
+	RTW_INFO(FUNC_ADPT_FMT" mode=%d\n", FUNC_ADPT_ARG(adapter), mode);
+
+	acl->mode = mode;
+
+	if (mode == RTW_ACL_MODE_DISABLED)
+		rtw_macaddr_acl_deinit(adapter);
+}
+
+int rtw_acl_add_sta(_adapter *adapter, const u8 *addr)
+{
+	_irqL irqL;
+	_list *list, *head;
+	u8 existed = 0;
+	int i = -1, ret = 0;
+	struct rtw_wlan_acl_node *acl_node;
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl = &stapriv->acl_list;
+	_queue *acl_node_q = &acl->acl_node_q;
+
+	_enter_critical_bh(&(acl_node_q->lock), &irqL);
+
+	head = get_list_head(acl_node_q);
+	list = get_next(head);
+
+	/* search for existed entry */
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		acl_node = LIST_CONTAINOR(list, struct rtw_wlan_acl_node, list);
+		list = get_next(list);
+
+		if (_rtw_memcmp(acl_node->addr, addr, ETH_ALEN)) {
+			if (acl_node->valid == _TRUE) {
+				existed = 1;
+				break;
+			}
+		}
+	}
+	if (existed)
+		goto release_lock;
+
+	if (acl->num >= NUM_ACL)
+		goto release_lock;
+
+	/* find empty one and use */
+	for (i = 0; i < NUM_ACL; i++) {
+
+		acl_node = &acl->aclnode[i];
+		if (acl_node->valid == _FALSE) {
+
+			_rtw_init_listhead(&acl_node->list);
+			_rtw_memcpy(acl_node->addr, addr, ETH_ALEN);
+			acl_node->valid = _TRUE;
+
+			rtw_list_insert_tail(&acl_node->list, get_list_head(acl_node_q));
+			acl->num++;
+			break;
+		}
+	}
+
+release_lock:
+	_exit_critical_bh(&(acl_node_q->lock), &irqL);
+
+	if (!existed && (i < 0 || i >= NUM_ACL))
+		ret = -1;
+
+	RTW_INFO(FUNC_ADPT_FMT" "MAC_FMT" %s (acl_num=%d)\n"
+		 , FUNC_ADPT_ARG(adapter), MAC_ARG(addr)
+		, (existed ? "existed" : ((i < 0 || i >= NUM_ACL) ? "no room" : "added"))
+		 , acl->num);
+
+	return ret;
+}
+
+int rtw_acl_remove_sta(_adapter *adapter, const u8 *addr)
+{
+	_irqL irqL;
+	_list *list, *head;
+	int ret = 0;
+	struct rtw_wlan_acl_node *acl_node;
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl = &stapriv->acl_list;
+	_queue	*acl_node_q = &acl->acl_node_q;
+	u8 is_baddr = is_broadcast_mac_addr(addr);
+	u8 match = 0;
+
+	_enter_critical_bh(&(acl_node_q->lock), &irqL);
+
+	head = get_list_head(acl_node_q);
+	list = get_next(head);
+
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		acl_node = LIST_CONTAINOR(list, struct rtw_wlan_acl_node, list);
+		list = get_next(list);
+
+		if (is_baddr || _rtw_memcmp(acl_node->addr, addr, ETH_ALEN)) {
+			if (acl_node->valid == _TRUE) {
+				acl_node->valid = _FALSE;
+				rtw_list_delete(&acl_node->list);
+				acl->num--;
+				match = 1;
+			}
+		}
+	}
+
+	_exit_critical_bh(&(acl_node_q->lock), &irqL);
+
+	RTW_INFO(FUNC_ADPT_FMT" "MAC_FMT" %s (acl_num=%d)\n"
+		 , FUNC_ADPT_ARG(adapter), MAC_ARG(addr)
+		 , is_baddr ? "clear all" : (match ? "match" : "no found")
+		 , acl->num);
+
+	return ret;
+}
+#endif /* CONFIG_RTW_MACADDR_ACL */
+
+u8 rtw_ap_set_pairwise_key(_adapter *padapter, struct sta_info *psta)
+{
+	struct cmd_obj			*ph2c;
+	struct set_stakey_parm	*psetstakey_para;
+	struct cmd_priv			*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm));
+	if (psetstakey_para == NULL) {
+		rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+
+
+	psetstakey_para->algorithm = (u8)psta->dot118021XPrivacy;
+
+	_rtw_memcpy(psetstakey_para->addr, psta->cmn.mac_addr, ETH_ALEN);
+
+	_rtw_memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16);
+
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+	return res;
+
+}
+
+static int rtw_ap_set_key(_adapter *padapter, u8 *key, u8 alg, int keyid, u8 set_tx)
+{
+	u8 keylen;
+	struct cmd_obj *pcmd;
+	struct setkey_parm *psetkeyparm;
+	struct cmd_priv	*pcmdpriv = &(padapter->cmdpriv);
+	int res = _SUCCESS;
+
+	/* RTW_INFO("%s\n", __FUNCTION__); */
+
+	pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm));
+	if (psetkeyparm == NULL) {
+		rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm));
+
+	psetkeyparm->keyid = (u8)keyid;
+	if (is_wep_enc(alg))
+		padapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid);
+
+	psetkeyparm->algorithm = alg;
+
+	psetkeyparm->set_tx = set_tx;
+
+	switch (alg) {
+	case _WEP40_:
+		keylen = 5;
+		break;
+	case _WEP104_:
+		keylen = 13;
+		break;
+	case _TKIP_:
+	case _TKIP_WTMIC_:
+	case _AES_:
+	default:
+		keylen = 16;
+	}
+
+	_rtw_memcpy(&(psetkeyparm->key[0]), key, keylen);
+
+	pcmd->cmdcode = _SetKey_CMD_;
+	pcmd->parmbuf = (u8 *)psetkeyparm;
+	pcmd->cmdsz = (sizeof(struct setkey_parm));
+	pcmd->rsp = NULL;
+	pcmd->rspsz = 0;
+
+
+	_rtw_init_listhead(&pcmd->list);
+
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+	return res;
+}
+
+int rtw_ap_set_group_key(_adapter *padapter, u8 *key, u8 alg, int keyid)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	return rtw_ap_set_key(padapter, key, alg, keyid, 1);
+}
+
+int rtw_ap_set_wep_key(_adapter *padapter, u8 *key, u8 keylen, int keyid, u8 set_tx)
+{
+	u8 alg;
+
+	switch (keylen) {
+	case 5:
+		alg = _WEP40_;
+		break;
+	case 13:
+		alg = _WEP104_;
+		break;
+	default:
+		alg = _NO_PRIVACY_;
+	}
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	return rtw_ap_set_key(padapter, key, alg, keyid, set_tx);
+}
+
+u8 rtw_ap_bmc_frames_hdl(_adapter *padapter)
+{
+#define HIQ_XMIT_COUNTS (6)
+	_irqL irqL;
+	struct sta_info *psta_bmc;
+	_list	*xmitframe_plist, *xmitframe_phead;
+	struct xmit_frame *pxmitframe = NULL;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	struct sta_priv  *pstapriv = &padapter->stapriv;
+	bool update_tim = _FALSE;
+
+
+	if (padapter->registrypriv.wifi_spec != 1)
+		return H2C_SUCCESS;
+
+
+	psta_bmc = rtw_get_bcmc_stainfo(padapter);
+	if (!psta_bmc)
+		return H2C_SUCCESS;
+
+
+	_enter_critical_bh(&pxmitpriv->lock, &irqL);
+
+	if ((pstapriv->tim_bitmap & BIT(0)) && (psta_bmc->sleepq_len > 0)) {
+		int tx_counts = 0;
+
+		_update_beacon(padapter, _TIM_IE_, NULL, _FALSE, "update TIM with TIB=1");
+
+		RTW_INFO("sleepq_len of bmc_sta = %d\n", psta_bmc->sleepq_len);
+
+		xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
+		xmitframe_plist = get_next(xmitframe_phead);
+
+		while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) {
+			pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+			xmitframe_plist = get_next(xmitframe_plist);
+
+			rtw_list_delete(&pxmitframe->list);
+
+			psta_bmc->sleepq_len--;
+			tx_counts++;
+
+			if (psta_bmc->sleepq_len > 0)
+				pxmitframe->attrib.mdata = 1;
+			else
+				pxmitframe->attrib.mdata = 0;
+
+			if (tx_counts == HIQ_XMIT_COUNTS)
+				pxmitframe->attrib.mdata = 0;
+
+			pxmitframe->attrib.triggered = 1;
+
+			if (xmitframe_hiq_filter(pxmitframe) == _TRUE)
+				pxmitframe->attrib.qsel = QSLT_HIGH;/*HIQ*/
+
+			rtw_hal_xmitframe_enqueue(padapter, pxmitframe);
+
+			if (tx_counts == HIQ_XMIT_COUNTS)
+				break;
+
+		}
+
+	} else {
+		if (psta_bmc->sleepq_len == 0) {
+
+			/*RTW_INFO("sleepq_len of bmc_sta = %d\n", psta_bmc->sleepq_len);*/
+
+			if (pstapriv->tim_bitmap & BIT(0))
+				update_tim = _TRUE;
+
+			pstapriv->tim_bitmap &= ~BIT(0);
+			pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+			if (update_tim == _TRUE) {
+				RTW_INFO("clear TIB\n");
+				_update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "bmc sleepq and HIQ empty");
+			}
+		}
+	}
+
+	_exit_critical_bh(&pxmitpriv->lock, &irqL);
+
+#if 0
+	/* HIQ Check */
+	rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty);
+
+	while (_FALSE == empty && rtw_get_passing_time_ms(start) < 3000) {
+		rtw_msleep_os(100);
+		rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty);
+	}
+
+
+	printk("check if hiq empty=%d\n", empty);
+#endif
+
+	return H2C_SUCCESS;
+}
+
+#ifdef CONFIG_NATIVEAP_MLME
+
+static void associated_stainfo_update(_adapter *padapter, struct sta_info *psta, u32 sta_info_type)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	RTW_INFO("%s: "MAC_FMT", updated_type=0x%x\n", __func__, MAC_ARG(psta->cmn.mac_addr), sta_info_type);
+
+	if (sta_info_type & STA_INFO_UPDATE_BW) {
+
+		if ((psta->flags & WLAN_STA_HT) && !psta->ht_20mhz_set) {
+			if (pmlmepriv->sw_to_20mhz) {
+				psta->cmn.bw_mode = CHANNEL_WIDTH_20;
+				/*psta->htpriv.ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;*/
+				psta->htpriv.sgi_40m = _FALSE;
+			} else {
+				/*TODO: Switch back to 40MHZ?80MHZ*/
+			}
+		}
+	}
+
+	/*
+		if (sta_info_type & STA_INFO_UPDATE_RATE) {
+
+		}
+	*/
+
+	if (sta_info_type & STA_INFO_UPDATE_PROTECTION_MODE)
+		VCS_update(padapter, psta);
+
+	/*
+		if (sta_info_type & STA_INFO_UPDATE_CAP) {
+
+		}
+
+		if (sta_info_type & STA_INFO_UPDATE_HT_CAP) {
+
+		}
+
+		if (sta_info_type & STA_INFO_UPDATE_VHT_CAP) {
+
+		}
+	*/
+
+}
+
+static void update_bcn_ext_capab_ie(_adapter *padapter)
+{
+	sint ie_len = 0;
+	unsigned char	*pbuf;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	u8 *ie = pnetwork->IEs;
+	u8 null_extcap_data[8] = {0};
+
+	pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_CAP_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+	if (pbuf && ie_len > 0)
+		rtw_remove_bcn_ie(padapter, pnetwork, _EXT_CAP_IE_);
+
+	if ((pmlmepriv->ext_capab_ie_len > 0) &&
+	    (_rtw_memcmp(pmlmepriv->ext_capab_ie_data, null_extcap_data, sizeof(null_extcap_data)) == _FALSE))
+		rtw_add_bcn_ie(padapter, pnetwork, _EXT_CAP_IE_, pmlmepriv->ext_capab_ie_data, pmlmepriv->ext_capab_ie_len);
+
+}
+
+static void update_bcn_erpinfo_ie(_adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	unsigned char *p, *ie = pnetwork->IEs;
+	u32 len = 0;
+
+	RTW_INFO("%s, ERP_enable=%d\n", __FUNCTION__, pmlmeinfo->ERP_enable);
+
+	if (!pmlmeinfo->ERP_enable)
+		return;
+
+	/* parsing ERP_IE */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+	if (p && len > 0) {
+		PNDIS_802_11_VARIABLE_IEs pIE = (PNDIS_802_11_VARIABLE_IEs)p;
+
+		if (pmlmepriv->num_sta_non_erp == 1)
+			pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT | RTW_ERP_INFO_USE_PROTECTION;
+		else
+			pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT | RTW_ERP_INFO_USE_PROTECTION);
+
+		if (pmlmepriv->num_sta_no_short_preamble > 0)
+			pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE;
+		else
+			pIE->data[0] &= ~(RTW_ERP_INFO_BARKER_PREAMBLE_MODE);
+
+		ERP_IE_handler(padapter, pIE);
+	}
+
+}
+
+static void update_bcn_htcap_ie(_adapter *padapter)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_htinfo_ie(_adapter *padapter)
+{
+	/*
+	u8 beacon_updated = _FALSE;
+	u32 sta_info_update_type = STA_INFO_UPDATE_NONE;
+	*/
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	unsigned char *p, *ie = pnetwork->IEs;
+	u32 len = 0;
+
+	if (pmlmepriv->htpriv.ht_option == _FALSE)
+		return;
+
+	if (pmlmeinfo->HT_info_enable != 1)
+		return;
+
+
+	RTW_INFO("%s current operation mode=0x%X\n",
+		 __FUNCTION__, pmlmepriv->ht_op_mode);
+
+	RTW_INFO("num_sta_40mhz_intolerant(%d), 20mhz_width_req(%d), intolerant_ch_rpt(%d), olbc(%d)\n",
+		pmlmepriv->num_sta_40mhz_intolerant, pmlmepriv->ht_20mhz_width_req, pmlmepriv->ht_intolerant_ch_reported, ATOMIC_READ(&pmlmepriv->olbc));
+
+	/*parsing HT_INFO_IE, currently only update ht_op_mode - pht_info->infos[1] & pht_info->infos[2] for wifi logo test*/
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+	if (p && len > 0) {
+		struct HT_info_element *pht_info = NULL;
+
+		pht_info = (struct HT_info_element *)(p + 2);
+
+		/* for STA Channel Width/Secondary Channel Offset*/
+		if ((pmlmepriv->sw_to_20mhz == 0) && (pmlmeext->cur_channel <= 14)) {
+			if ((pmlmepriv->num_sta_40mhz_intolerant > 0) || (pmlmepriv->ht_20mhz_width_req == _TRUE)
+			    || (pmlmepriv->ht_intolerant_ch_reported == _TRUE) || (ATOMIC_READ(&pmlmepriv->olbc) == _TRUE)) {
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(pht_info, 0);
+				SET_HT_OP_ELE_STA_CHL_WIDTH(pht_info, 0);
+
+				pmlmepriv->sw_to_20mhz = 1;
+				/*
+				sta_info_update_type |= STA_INFO_UPDATE_BW;
+				beacon_updated = _TRUE;
+				*/
+
+				RTW_INFO("%s:switching to 20Mhz\n", __FUNCTION__);
+
+				/*TODO : cur_bwmode/cur_ch_offset switches to 20Mhz*/
+			}
+		} else {
+
+			if ((pmlmepriv->num_sta_40mhz_intolerant == 0) && (pmlmepriv->ht_20mhz_width_req == _FALSE)
+			    && (pmlmepriv->ht_intolerant_ch_reported == _FALSE) && (ATOMIC_READ(&pmlmepriv->olbc) == _FALSE)) {
+
+				if (pmlmeext->cur_bwmode >= CHANNEL_WIDTH_40) {
+
+					SET_HT_OP_ELE_STA_CHL_WIDTH(pht_info, 1);
+
+					SET_HT_OP_ELE_2ND_CHL_OFFSET(pht_info,
+						(pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ?
+						HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE : HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW);
+
+					pmlmepriv->sw_to_20mhz = 0;
+					/*
+					sta_info_update_type |= STA_INFO_UPDATE_BW;
+					beacon_updated = _TRUE;
+					*/
+
+					RTW_INFO("%s:switching back to 40Mhz\n", __FUNCTION__);
+				}
+			}
+		}
+
+		/* to update  ht_op_mode*/
+		*(u16 *)(pht_info->infos + 1) = cpu_to_le16(pmlmepriv->ht_op_mode);
+
+	}
+
+	/*associated_clients_update(padapter, beacon_updated, sta_info_update_type);*/
+
+}
+
+static void update_bcn_rsn_ie(_adapter *padapter)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_wpa_ie(_adapter *padapter)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_wmm_ie(_adapter *padapter)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_wps_ie(_adapter *padapter)
+{
+	u8 *pwps_ie = NULL, *pwps_ie_src, *premainder_ie, *pbackup_remainder_ie = NULL;
+	uint wps_ielen = 0, wps_offset, remainder_ielen;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	unsigned char *ie = pnetwork->IEs;
+	u32 ielen = pnetwork->IELength;
+
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	pwps_ie = rtw_get_wps_ie(ie + _FIXED_IE_LENGTH_, ielen - _FIXED_IE_LENGTH_, NULL, &wps_ielen);
+
+	if (pwps_ie == NULL || wps_ielen == 0)
+		return;
+
+	pwps_ie_src = pmlmepriv->wps_beacon_ie;
+	if (pwps_ie_src == NULL)
+		return;
+
+	wps_offset = (uint)(pwps_ie - ie);
+
+	premainder_ie = pwps_ie + wps_ielen;
+
+	remainder_ielen = ielen - wps_offset - wps_ielen;
+
+	if (remainder_ielen > 0) {
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if (pbackup_remainder_ie)
+			_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */
+	if ((wps_offset + wps_ielen + 2 + remainder_ielen) <= MAX_IE_SZ) {
+		_rtw_memcpy(pwps_ie, pwps_ie_src, wps_ielen + 2);
+		pwps_ie += (wps_ielen + 2);
+
+		if (pbackup_remainder_ie)
+			_rtw_memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen);
+
+		/* update IELength */
+		pnetwork->IELength = wps_offset + (wps_ielen + 2) + remainder_ielen;
+	}
+
+	if (pbackup_remainder_ie)
+		rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+
+	/* deal with the case without set_tx_beacon_cmd() in update_beacon() */
+#if defined(CONFIG_INTERRUPT_BASED_TXBCN) || defined(CONFIG_PCI_HCI)
+	if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
+		u8 sr = 0;
+		rtw_get_wps_attr_content(pwps_ie_src,  wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL);
+
+		if (sr) {
+			set_fwstate(pmlmepriv, WIFI_UNDER_WPS);
+			RTW_INFO("%s, set WIFI_UNDER_WPS\n", __func__);
+		} else {
+			clr_fwstate(pmlmepriv, WIFI_UNDER_WPS);
+			RTW_INFO("%s, clr WIFI_UNDER_WPS\n", __func__);
+		}
+	}
+#endif
+}
+
+static void update_bcn_p2p_ie(_adapter *padapter)
+{
+
+}
+
+static void update_bcn_vendor_spec_ie(_adapter *padapter, u8 *oui)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	if (_rtw_memcmp(RTW_WPA_OUI, oui, 4))
+		update_bcn_wpa_ie(padapter);
+	else if (_rtw_memcmp(WMM_OUI, oui, 4))
+		update_bcn_wmm_ie(padapter);
+	else if (_rtw_memcmp(WPS_OUI, oui, 4))
+		update_bcn_wps_ie(padapter);
+	else if (_rtw_memcmp(P2P_OUI, oui, 4))
+		update_bcn_p2p_ie(padapter);
+	else
+		RTW_INFO("unknown OUI type!\n");
+
+
+}
+
+void _update_beacon(_adapter *padapter, u8 ie_id, u8 *oui, u8 tx, const char *tag)
+{
+	_irqL irqL;
+	struct mlme_priv *pmlmepriv;
+	struct mlme_ext_priv *pmlmeext;
+
+	if (!padapter)
+		return;
+
+	pmlmepriv = &(padapter->mlmepriv);
+	pmlmeext = &(padapter->mlmeextpriv);
+
+	if (pmlmeext->bstart_bss == _FALSE)
+		return;
+
+	_enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+
+	switch (ie_id) {
+	case _TIM_IE_:
+		update_BCNTIM(padapter);
+		break;
+
+	case _ERPINFO_IE_:
+		update_bcn_erpinfo_ie(padapter);
+		break;
+
+	case _HT_CAPABILITY_IE_:
+		update_bcn_htcap_ie(padapter);
+		break;
+
+	case _RSN_IE_2_:
+		update_bcn_rsn_ie(padapter);
+		break;
+
+	case _HT_ADD_INFO_IE_:
+		update_bcn_htinfo_ie(padapter);
+		break;
+
+	case _EXT_CAP_IE_:
+		update_bcn_ext_capab_ie(padapter);
+		break;
+
+	case _VENDOR_SPECIFIC_IE_:
+		update_bcn_vendor_spec_ie(padapter, oui);
+		break;
+
+	case 0xFF:
+	default:
+		break;
+	}
+
+	pmlmepriv->update_bcn = _TRUE;
+
+	_exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+
+#ifndef CONFIG_INTERRUPT_BASED_TXBCN
+#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
+	if (tx) {
+		/* send_beacon(padapter); */ /* send_beacon must execute on TSR level */
+		if (0)
+			RTW_INFO(FUNC_ADPT_FMT" ie_id:%u - %s\n", FUNC_ADPT_ARG(padapter), ie_id, tag);
+		set_tx_beacon_cmd(padapter);
+	}
+#else
+	{
+		/* PCI will issue beacon when BCN interrupt occurs.		 */
+	}
+#endif
+#endif /* !CONFIG_INTERRUPT_BASED_TXBCN */
+}
+
+#ifdef CONFIG_80211N_HT
+
+void rtw_process_public_act_bsscoex(_adapter *padapter, u8 *pframe, uint frame_len)
+{
+	struct sta_info *psta;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 beacon_updated = _FALSE;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+	uint frame_body_len = frame_len - sizeof(struct rtw_ieee80211_hdr_3addr);
+	u8 category, action;
+
+	psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe));
+	if (psta == NULL)
+		return;
+
+
+	category = frame_body[0];
+	action = frame_body[1];
+
+	if (frame_body_len > 0) {
+		if ((frame_body[2] == EID_BSSCoexistence) && (frame_body[3] > 0)) {
+			u8 ie_data = frame_body[4];
+
+			if (ie_data & RTW_WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
+				if (psta->ht_40mhz_intolerant == 0) {
+					psta->ht_40mhz_intolerant = 1;
+					pmlmepriv->num_sta_40mhz_intolerant++;
+					beacon_updated = _TRUE;
+				}
+			} else if (ie_data & RTW_WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ)	{
+				if (pmlmepriv->ht_20mhz_width_req == _FALSE) {
+					pmlmepriv->ht_20mhz_width_req = _TRUE;
+					beacon_updated = _TRUE;
+				}
+			} else
+				beacon_updated = _FALSE;
+		}
+	}
+
+	if (frame_body_len > 8) {
+		/* if EID_BSSIntolerantChlReport ie exists */
+		if ((frame_body[5] == EID_BSSIntolerantChlReport) && (frame_body[6] > 0)) {
+			/*todo:*/
+			if (pmlmepriv->ht_intolerant_ch_reported == _FALSE) {
+				pmlmepriv->ht_intolerant_ch_reported = _TRUE;
+				beacon_updated = _TRUE;
+			}
+		}
+	}
+
+	if (beacon_updated) {
+
+		update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE);
+
+		associated_stainfo_update(padapter, psta, STA_INFO_UPDATE_BW);
+	}
+
+
+
+}
+
+void rtw_process_ht_action_smps(_adapter *padapter, u8 *ta, u8 ctrl_field)
+{
+	u8 e_field, m_field;
+	struct sta_info *psta;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	psta = rtw_get_stainfo(pstapriv, ta);
+	if (psta == NULL)
+		return;
+
+	e_field = (ctrl_field & BIT(0)) ? 1 : 0;
+	m_field = (ctrl_field & BIT(1)) ? 1 : 0;
+
+	if (e_field) {
+
+		/* enable */
+		/* 0:static SMPS, 1:dynamic SMPS, 3:SMPS disabled, 2:reserved*/
+
+		if (m_field) /*mode*/
+			psta->htpriv.smps_cap = 1;
+		else
+			psta->htpriv.smps_cap = 0;
+	} else {
+		/*disable*/
+		psta->htpriv.smps_cap = 3;
+	}
+
+	rtw_dm_ra_mask_wk_cmd(padapter, (u8 *)psta);
+
+}
+
+/*
+op_mode
+Set to 0 (HT pure) under the followign conditions
+	- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+	- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+	in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+	however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+	(currently non-GF HT station is considered as non-HT STA also)
+*/
+int rtw_ht_operation_update(_adapter *padapter)
+{
+	u16 cur_op_mode, new_op_mode;
+	int op_mode_changes = 0;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct ht_priv	*phtpriv_ap = &pmlmepriv->htpriv;
+
+	if (pmlmepriv->htpriv.ht_option == _FALSE)
+		return 0;
+
+	/*if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed)
+		return 0;*/
+
+	RTW_INFO("%s current operation mode=0x%X\n",
+		 __FUNCTION__, pmlmepriv->ht_op_mode);
+
+	if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
+	    && pmlmepriv->num_sta_ht_no_gf) {
+		pmlmepriv->ht_op_mode |=
+			HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+		op_mode_changes++;
+	} else if ((pmlmepriv->ht_op_mode &
+		    HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+		   pmlmepriv->num_sta_ht_no_gf == 0) {
+		pmlmepriv->ht_op_mode &=
+			~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+		op_mode_changes++;
+	}
+
+	if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+	    (pmlmepriv->num_sta_no_ht || ATOMIC_READ(&pmlmepriv->olbc_ht))) {
+		pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+		op_mode_changes++;
+	} else if ((pmlmepriv->ht_op_mode &
+		    HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+		   (pmlmepriv->num_sta_no_ht == 0 && !ATOMIC_READ(&pmlmepriv->olbc_ht))) {
+		pmlmepriv->ht_op_mode &=
+			~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+		op_mode_changes++;
+	}
+
+	/* Note: currently we switch to the MIXED op mode if HT non-greenfield
+	 * station is associated. Probably it's a theoretical case, since
+	 * it looks like all known HT STAs support greenfield.
+	 */
+	new_op_mode = 0;
+	if (pmlmepriv->num_sta_no_ht /*||
+	    (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)*/)
+		new_op_mode = OP_MODE_MIXED;
+	else if ((phtpriv_ap->ht_cap.cap_info & IEEE80211_HT_CAP_SUP_WIDTH)
+		 && pmlmepriv->num_sta_ht_20mhz)
+		new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+	else if (ATOMIC_READ(&pmlmepriv->olbc_ht))
+		new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+	else
+		new_op_mode = OP_MODE_PURE;
+
+	cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+	if (cur_op_mode != new_op_mode) {
+		pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+		pmlmepriv->ht_op_mode |= new_op_mode;
+		op_mode_changes++;
+	}
+
+	RTW_INFO("%s new operation mode=0x%X changes=%d\n",
+		 __FUNCTION__, pmlmepriv->ht_op_mode, op_mode_changes);
+
+	return op_mode_changes;
+
+}
+
+#endif /* CONFIG_80211N_HT */
+
+void associated_clients_update(_adapter *padapter, u8 updated, u32 sta_info_type)
+{
+	/* update associcated stations cap. */
+	if (updated == _TRUE) {
+		_irqL irqL;
+		_list	*phead, *plist;
+		struct sta_info *psta = NULL;
+		struct sta_priv *pstapriv = &padapter->stapriv;
+
+		_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+		phead = &pstapriv->asoc_list;
+		plist = get_next(phead);
+
+		/* check asoc_queue */
+		while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+			psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+			plist = get_next(plist);
+
+			associated_stainfo_update(padapter, psta, sta_info_type);
+		}
+
+		_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	}
+
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void bss_cap_update_on_sta_join(_adapter *padapter, struct sta_info *psta)
+{
+	u8 beacon_updated = _FALSE;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+
+#if 0
+	if (!(psta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
+	    !psta->no_short_preamble_set) {
+		psta->no_short_preamble_set = 1;
+		pmlmepriv->num_sta_no_short_preamble++;
+		if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+		    (pmlmepriv->num_sta_no_short_preamble == 1))
+			ieee802_11_set_beacons(hapd->iface);
+	}
+#endif
+
+
+	if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) {
+		if (!psta->no_short_preamble_set) {
+			psta->no_short_preamble_set = 1;
+
+			pmlmepriv->num_sta_no_short_preamble++;
+
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+			    (pmlmepriv->num_sta_no_short_preamble == 1))
+				beacon_updated = _TRUE;
+		}
+	} else {
+		if (psta->no_short_preamble_set) {
+			psta->no_short_preamble_set = 0;
+
+			pmlmepriv->num_sta_no_short_preamble--;
+
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+			    (pmlmepriv->num_sta_no_short_preamble == 0))
+				beacon_updated = _TRUE;
+		}
+	}
+
+#if 0
+	if (psta->flags & WLAN_STA_NONERP && !psta->nonerp_set) {
+		psta->nonerp_set = 1;
+		pmlmepriv->num_sta_non_erp++;
+		if (pmlmepriv->num_sta_non_erp == 1)
+			ieee802_11_set_beacons(hapd->iface);
+	}
+#endif
+
+	if (psta->flags & WLAN_STA_NONERP) {
+		if (!psta->nonerp_set) {
+			psta->nonerp_set = 1;
+
+			pmlmepriv->num_sta_non_erp++;
+
+			if (pmlmepriv->num_sta_non_erp == 1) {
+				beacon_updated = _TRUE;
+				update_beacon(padapter, _ERPINFO_IE_, NULL, _FALSE);
+			}
+		}
+
+	} else {
+		if (psta->nonerp_set) {
+			psta->nonerp_set = 0;
+
+			pmlmepriv->num_sta_non_erp--;
+
+			if (pmlmepriv->num_sta_non_erp == 0) {
+				beacon_updated = _TRUE;
+				update_beacon(padapter, _ERPINFO_IE_, NULL, _FALSE);
+			}
+		}
+
+	}
+
+
+#if 0
+	if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT) &&
+	    !psta->no_short_slot_time_set) {
+		psta->no_short_slot_time_set = 1;
+		pmlmepriv->num_sta_no_short_slot_time++;
+		if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+		    (pmlmepriv->num_sta_no_short_slot_time == 1))
+			ieee802_11_set_beacons(hapd->iface);
+	}
+#endif
+
+	if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) {
+		if (!psta->no_short_slot_time_set) {
+			psta->no_short_slot_time_set = 1;
+
+			pmlmepriv->num_sta_no_short_slot_time++;
+
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+			    (pmlmepriv->num_sta_no_short_slot_time == 1))
+				beacon_updated = _TRUE;
+		}
+	} else {
+		if (psta->no_short_slot_time_set) {
+			psta->no_short_slot_time_set = 0;
+
+			pmlmepriv->num_sta_no_short_slot_time--;
+
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+			    (pmlmepriv->num_sta_no_short_slot_time == 0))
+				beacon_updated = _TRUE;
+		}
+	}
+
+#ifdef CONFIG_80211N_HT
+	if (psta->flags & WLAN_STA_HT) {
+		u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info);
+
+		RTW_INFO("HT: STA " MAC_FMT " HT Capabilities Info: 0x%04x\n",
+			MAC_ARG(psta->cmn.mac_addr), ht_capab);
+
+		if (psta->no_ht_set) {
+			psta->no_ht_set = 0;
+			pmlmepriv->num_sta_no_ht--;
+		}
+
+		if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) {
+			if (!psta->no_ht_gf_set) {
+				psta->no_ht_gf_set = 1;
+				pmlmepriv->num_sta_ht_no_gf++;
+			}
+			RTW_INFO("%s STA " MAC_FMT " - no "
+				 "greenfield, num of non-gf stations %d\n",
+				 __FUNCTION__, MAC_ARG(psta->cmn.mac_addr),
+				 pmlmepriv->num_sta_ht_no_gf);
+		}
+
+		if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) {
+			if (!psta->ht_20mhz_set) {
+				psta->ht_20mhz_set = 1;
+				pmlmepriv->num_sta_ht_20mhz++;
+			}
+			RTW_INFO("%s STA " MAC_FMT " - 20 MHz HT, "
+				 "num of 20MHz HT STAs %d\n",
+				 __FUNCTION__, MAC_ARG(psta->cmn.mac_addr),
+				 pmlmepriv->num_sta_ht_20mhz);
+		}
+
+	} else {
+		if (!psta->no_ht_set) {
+			psta->no_ht_set = 1;
+			pmlmepriv->num_sta_no_ht++;
+		}
+		if (pmlmepriv->htpriv.ht_option == _TRUE) {
+			RTW_INFO("%s STA " MAC_FMT
+				 " - no HT, num of non-HT stations %d\n",
+				 __FUNCTION__, MAC_ARG(psta->cmn.mac_addr),
+				 pmlmepriv->num_sta_no_ht);
+		}
+	}
+
+	if (rtw_ht_operation_update(padapter) > 0) {
+		update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, _FALSE);
+		update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _FALSE);
+		beacon_updated = _TRUE;
+	}
+#endif /* CONFIG_80211N_HT */
+
+	if (beacon_updated)
+		update_beacon(padapter, 0xFF, NULL, _TRUE);
+
+	/* update associcated stations cap. */
+	associated_clients_update(padapter,  beacon_updated, STA_INFO_UPDATE_ALL);
+
+	RTW_INFO("%s, updated=%d\n", __func__, beacon_updated);
+
+}
+
+u8 bss_cap_update_on_sta_leave(_adapter *padapter, struct sta_info *psta)
+{
+	u8 beacon_updated = _FALSE;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+	if (!psta)
+		return beacon_updated;
+
+	if (pstapriv->tim_bitmap & BIT(psta->cmn.aid)) {
+		pstapriv->tim_bitmap &= (~ BIT(psta->cmn.aid));
+		beacon_updated = _TRUE;
+		update_beacon(padapter, _TIM_IE_, NULL, _FALSE);
+	}
+
+	if (psta->no_short_preamble_set) {
+		psta->no_short_preamble_set = 0;
+		pmlmepriv->num_sta_no_short_preamble--;
+		if (pmlmeext->cur_wireless_mode > WIRELESS_11B
+		    && pmlmepriv->num_sta_no_short_preamble == 0)
+			beacon_updated = _TRUE;
+	}
+
+	if (psta->nonerp_set) {
+		psta->nonerp_set = 0;
+		pmlmepriv->num_sta_non_erp--;
+		if (pmlmepriv->num_sta_non_erp == 0) {
+			beacon_updated = _TRUE;
+			update_beacon(padapter, _ERPINFO_IE_, NULL, _FALSE);
+		}
+	}
+
+	if (psta->no_short_slot_time_set) {
+		psta->no_short_slot_time_set = 0;
+		pmlmepriv->num_sta_no_short_slot_time--;
+		if (pmlmeext->cur_wireless_mode > WIRELESS_11B
+		    && pmlmepriv->num_sta_no_short_slot_time == 0)
+			beacon_updated = _TRUE;
+	}
+
+#ifdef CONFIG_80211N_HT
+	if (psta->no_ht_gf_set) {
+		psta->no_ht_gf_set = 0;
+		pmlmepriv->num_sta_ht_no_gf--;
+	}
+
+	if (psta->no_ht_set) {
+		psta->no_ht_set = 0;
+		pmlmepriv->num_sta_no_ht--;
+	}
+
+	if (psta->ht_20mhz_set) {
+		psta->ht_20mhz_set = 0;
+		pmlmepriv->num_sta_ht_20mhz--;
+	}
+
+	if (rtw_ht_operation_update(padapter) > 0) {
+		update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, _FALSE);
+		update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _FALSE);
+	}
+#endif /* CONFIG_80211N_HT */
+
+	if (beacon_updated == _TRUE)
+		update_beacon(padapter, 0xFF, NULL, _TRUE);
+
+#if 0
+	/* update associated stations cap. */
+	associated_clients_update(padapter,  beacon_updated, STA_INFO_UPDATE_ALL); /* move it to avoid deadlock */
+#endif
+
+	RTW_INFO("%s, updated=%d\n", __func__, beacon_updated);
+
+	return beacon_updated;
+
+}
+
+u8 ap_free_sta(_adapter *padapter, struct sta_info *psta, bool active, u16 reason, bool enqueue)
+{
+	_irqL irqL;
+	u8 beacon_updated = _FALSE;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	if (!psta)
+		return beacon_updated;
+
+	if (active == _TRUE) {
+#ifdef CONFIG_80211N_HT
+		/* tear down Rx AMPDU */
+		send_delba(padapter, 0, psta->cmn.mac_addr);/* recipient */
+
+		/* tear down TX AMPDU */
+		send_delba(padapter, 1, psta->cmn.mac_addr);/*  */ /* originator */
+
+#endif /* CONFIG_80211N_HT */
+
+		issue_deauth(padapter, psta->cmn.mac_addr, reason);
+	}
+
+#ifdef CONFIG_BEAMFORMING
+	beamforming_wk_cmd(padapter, BEAMFORMING_CTRL_LEAVE, psta->cmn.mac_addr, ETH_ALEN, 1);
+#endif
+
+	psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+	psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+
+	/* clear cam entry / key */
+	rtw_clearstakey_cmd(padapter, psta, enqueue);
+
+
+	_enter_critical_bh(&psta->lock, &irqL);
+	psta->state &= ~_FW_LINKED;
+	_exit_critical_bh(&psta->lock, &irqL);
+
+	{
+#ifdef CONFIG_IOCTL_CFG80211
+		#ifdef COMPAT_KERNEL_RELEASE
+		rtw_cfg80211_indicate_sta_disassoc(padapter, psta->cmn.mac_addr, reason);
+		#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER)
+		rtw_cfg80211_indicate_sta_disassoc(padapter, psta->cmn.mac_addr, reason);
+		#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) */
+		/* will call rtw_cfg80211_indicate_sta_disassoc() in cmd_thread for old API context */
+		#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) */
+#else
+		rtw_indicate_sta_disassoc_event(padapter, psta);
+#endif
+	}
+
+	report_del_sta_event(padapter, psta->cmn.mac_addr, reason, enqueue, _FALSE);
+
+	beacon_updated = bss_cap_update_on_sta_leave(padapter, psta);
+
+	/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);					 */
+	rtw_free_stainfo(padapter, psta);
+	/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
+
+
+	return beacon_updated;
+
+}
+
+int rtw_ap_inform_ch_switch(_adapter *padapter, u8 new_ch, u8 ch_offset)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+	if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
+		return ret;
+
+	RTW_INFO(FUNC_NDEV_FMT" with ch:%u, offset:%u\n",
+		 FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset);
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	/* for each sta in asoc_queue */
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		issue_action_spct_ch_switch(padapter, psta->cmn.mac_addr, new_ch, ch_offset);
+		psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2);
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset);
+
+	return ret;
+}
+
+int rtw_sta_flush(_adapter *padapter, bool enqueue)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	u8 flush_num = 0;
+	char flush_list[NUM_STA];
+	int i;
+
+	if (!MLME_IS_AP(padapter) && !MLME_IS_MESH(padapter))
+		return ret;
+
+	RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
+	/* pick sta from sta asoc_queue */
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		int stainfo_offset;
+
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		rtw_list_delete(&psta->asoc_list);
+		pstapriv->asoc_list_cnt--;
+
+		stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+		if (stainfo_offset_valid(stainfo_offset))
+			flush_list[flush_num++] = stainfo_offset;
+		else
+			rtw_warn_on(1);
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	/* call ap_free_sta() for each sta picked */
+	for (i = 0; i < flush_num; i++) {
+		psta = rtw_get_stainfo_by_offset(pstapriv, flush_list[i]);
+		ap_free_sta(padapter, psta, _TRUE, WLAN_REASON_DEAUTH_LEAVING, enqueue);
+	}
+
+	issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING);
+
+	associated_clients_update(padapter, _TRUE, STA_INFO_UPDATE_ALL);
+
+	return ret;
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void sta_info_update(_adapter *padapter, struct sta_info *psta)
+{
+	int flags = psta->flags;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+
+	/* update wmm cap. */
+	if (WLAN_STA_WME & flags)
+		psta->qos_option = 1;
+	else
+		psta->qos_option = 0;
+
+	if (pmlmepriv->qospriv.qos_option == 0)
+		psta->qos_option = 0;
+
+
+#ifdef CONFIG_80211N_HT
+	/* update 802.11n ht cap. */
+	if (WLAN_STA_HT & flags) {
+		psta->htpriv.ht_option = _TRUE;
+		psta->qos_option = 1;
+
+		psta->htpriv.smps_cap = (psta->htpriv.ht_cap.cap_info & IEEE80211_HT_CAP_SM_PS) >> 2;
+	} else
+		psta->htpriv.ht_option = _FALSE;
+
+	if (pmlmepriv->htpriv.ht_option == _FALSE)
+		psta->htpriv.ht_option = _FALSE;
+#endif
+
+#ifdef CONFIG_80211AC_VHT
+	/* update 802.11AC vht cap. */
+	if (WLAN_STA_VHT & flags)
+		psta->vhtpriv.vht_option = _TRUE;
+	else
+		psta->vhtpriv.vht_option = _FALSE;
+
+	if (pmlmepriv->vhtpriv.vht_option == _FALSE)
+		psta->vhtpriv.vht_option = _FALSE;
+#endif
+
+	update_sta_info_apmode(padapter, psta);
+}
+
+/* called >= TSR LEVEL for USB or SDIO Interface*/
+void ap_sta_info_defer_update(_adapter *padapter, struct sta_info *psta)
+{
+	if (psta->state & _FW_LINKED)
+		rtw_hal_update_ra_mask(psta); /* DM_RATR_STA_INIT */
+}
+/* restore hw setting from sw data structures */
+void rtw_ap_restore_network(_adapter *padapter)
+{
+	struct mlme_priv *mlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct sta_info *psta;
+	struct security_priv *psecuritypriv = &(padapter->securitypriv);
+	_irqL irqL;
+	_list	*phead, *plist;
+	u8 chk_alive_num = 0;
+	char chk_alive_list[NUM_STA];
+	int i;
+
+	rtw_setopmode_cmd(padapter, Ndis802_11APMode, _FALSE);
+
+	set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+	rtw_startbss_cmd(padapter, RTW_CMDF_DIRECTLY);
+
+	if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
+	    (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) {
+		/* restore group key, WEP keys is restored in ips_leave() */
+		rtw_set_key(padapter, psecuritypriv, psecuritypriv->dot118021XGrpKeyid, 0, _FALSE);
+	}
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		int stainfo_offset;
+
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+		if (stainfo_offset_valid(stainfo_offset))
+			chk_alive_list[chk_alive_num++] = stainfo_offset;
+	}
+
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	for (i = 0; i < chk_alive_num; i++) {
+		psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
+
+		if (psta == NULL)
+			RTW_INFO(FUNC_ADPT_FMT" sta_info is null\n", FUNC_ADPT_ARG(padapter));
+		else if (psta->state & _FW_LINKED) {
+			rtw_sta_media_status_rpt(padapter, psta, 1);
+			Update_RA_Entry(padapter, psta);
+			/* pairwise key */
+			/* per sta pairwise key and settings */
+			if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
+			    (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_))
+				rtw_setstakey_cmd(padapter, psta, UNICAST_KEY, _FALSE);
+		}
+	}
+
+}
+
+void start_ap_mode(_adapter *padapter)
+{
+	int i;
+	struct sta_info *psta = NULL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+	pmlmepriv->update_bcn = _FALSE;
+
+	/*init_mlme_ap_info(padapter);*/
+
+	pmlmeext->bstart_bss = _FALSE;
+
+	pmlmepriv->num_sta_non_erp = 0;
+
+	pmlmepriv->num_sta_no_short_slot_time = 0;
+
+	pmlmepriv->num_sta_no_short_preamble = 0;
+
+	pmlmepriv->num_sta_ht_no_gf = 0;
+#ifdef CONFIG_80211N_HT
+	pmlmepriv->num_sta_no_ht = 0;
+#endif /* CONFIG_80211N_HT */
+	pmlmeinfo->HT_info_enable = 0;
+	pmlmeinfo->HT_caps_enable = 0;
+	pmlmeinfo->HT_enable = 0;
+
+	pmlmepriv->num_sta_ht_20mhz = 0;
+	pmlmepriv->num_sta_40mhz_intolerant = 0;
+	ATOMIC_SET(&pmlmepriv->olbc, _FALSE);
+	ATOMIC_SET(&pmlmepriv->olbc_ht, _FALSE);
+
+#ifdef CONFIG_80211N_HT
+	pmlmepriv->ht_20mhz_width_req = _FALSE;
+	pmlmepriv->ht_intolerant_ch_reported = _FALSE;
+	pmlmepriv->ht_op_mode = 0;
+	pmlmepriv->sw_to_20mhz = 0;
+#endif
+
+	_rtw_memset(pmlmepriv->ext_capab_ie_data, 0, sizeof(pmlmepriv->ext_capab_ie_data));
+	pmlmepriv->ext_capab_ie_len = 0;
+
+#ifdef CONFIG_CONCURRENT_MODE
+	psecuritypriv->dot118021x_bmc_cam_id = INVALID_SEC_MAC_CAM_ID;
+#endif
+
+	for (i = 0 ;  i < NUM_STA ; i++)
+		pstapriv->sta_aid[i] = NULL;
+
+#if CONFIG_RTW_MACADDR_ACL
+	rtw_macaddr_acl_init(padapter);
+#endif
+
+	psta = rtw_get_bcmc_stainfo(padapter);
+	/*_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);*/
+	if (psta)
+		rtw_free_stainfo(padapter, psta);
+	/*_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);*/
+
+	rtw_init_bcmc_stainfo(padapter);
+
+	if (rtw_mi_get_ap_num(padapter))
+		RTW_SET_SCAN_BAND_SKIP(padapter, BAND_5G);
+
+}
+
+void rtw_ap_bcmc_sta_flush(_adapter *padapter)
+{
+#ifdef CONFIG_CONCURRENT_MODE
+	int cam_id = -1;
+	u8 *addr = adapter_mac_addr(padapter);
+
+	cam_id = rtw_iface_bcmc_id_get(padapter);
+	if (cam_id != INVALID_SEC_MAC_CAM_ID) {
+		RTW_PRINT("clear group key for "ADPT_FMT" addr:"MAC_FMT", camid:%d\n",
+			ADPT_ARG(padapter), MAC_ARG(addr), cam_id);
+		clear_cam_entry(padapter, cam_id);
+		rtw_camid_free(padapter, cam_id);
+		rtw_iface_bcmc_id_set(padapter, INVALID_SEC_MAC_CAM_ID);	/*init default value*/
+	}
+#else
+	invalidate_cam_all(padapter);
+#endif
+}
+
+void stop_ap_mode(_adapter *padapter)
+{
+	u8 self_action = MLME_ACTION_UNKNOWN;
+	_irqL irqL;
+	struct sta_info *psta = NULL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct dvobj_priv *pdvobj = padapter->dvobj;
+
+	RTW_INFO("%s -"ADPT_FMT"\n", __func__, ADPT_ARG(padapter));
+
+	if (MLME_IS_AP(padapter))
+		self_action = MLME_AP_STOPPED;
+	else if (MLME_IS_MESH(padapter))
+		self_action = MLME_MESH_STOPPED;
+	else
+		rtw_warn_on(1);
+
+	pmlmepriv->update_bcn = _FALSE;
+	/*pmlmeext->bstart_bss = _FALSE;*/
+	padapter->netif_up = _FALSE;
+	/* _rtw_spinlock_free(&pmlmepriv->bcn_update_lock); */
+
+	/* reset and init security priv , this can refine with rtw_reset_securitypriv */
+	_rtw_memset((unsigned char *)&padapter->securitypriv, 0, sizeof(struct security_priv));
+	padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+	padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+
+#ifdef CONFIG_DFS_MASTER
+	rtw_dfs_master_status_apply(padapter, self_action);
+#endif
+
+	/* free scan queue */
+	rtw_free_network_queue(padapter, _TRUE);
+
+#if CONFIG_RTW_MACADDR_ACL
+	rtw_macaddr_acl_deinit(padapter);
+#endif
+
+	rtw_sta_flush(padapter, _TRUE);
+	rtw_ap_bcmc_sta_flush(padapter);
+
+	/* free_assoc_sta_resources	 */
+	rtw_free_all_stainfo(padapter);
+
+	psta = rtw_get_bcmc_stainfo(padapter);
+	if (psta) {
+		rtw_sta_mstatus_disc_rpt(padapter, psta->cmn.mac_id);
+		/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);		 */
+		rtw_free_stainfo(padapter, psta);
+		/*_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);*/
+	}
+
+	rtw_free_mlme_priv_ie_data(pmlmepriv);
+
+#ifdef CONFIG_SWTIMER_BASED_TXBCN
+	if (pmlmeext->bstart_bss == _TRUE) {
+		_enter_critical_bh(&pdvobj->ap_if_q.lock, &irqL);
+		pdvobj->nr_ap_if--;
+		if (pdvobj->nr_ap_if > 0)
+			pdvobj->inter_bcn_space = DEFAULT_BCN_INTERVAL / pdvobj->nr_ap_if;
+		else
+			pdvobj->inter_bcn_space = DEFAULT_BCN_INTERVAL;
+
+		rtw_list_delete(&padapter->list);
+		_exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL);
+
+		rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pdvobj->inter_bcn_space));
+
+		if (pdvobj->nr_ap_if == 0)
+			_cancel_timer_ex(&pdvobj->txbcn_timer);
+	}
+#endif
+
+	pmlmeext->bstart_bss = _FALSE;
+
+	rtw_hal_rcr_set_chk_bssid(padapter, self_action);
+
+#ifdef CONFIG_BT_COEXIST
+	rtw_btcoex_MediaStatusNotify(padapter, 0); /* disconnect */
+#endif
+
+}
+
+#endif /* CONFIG_NATIVEAP_MLME */
+
+void rtw_ap_update_bss_chbw(_adapter *adapter, WLAN_BSSID_EX *bss, u8 ch, u8 bw, u8 offset)
+{
+#define UPDATE_VHT_CAP 1
+#define UPDATE_HT_CAP 1
+#ifdef CONFIG_80211AC_VHT
+	struct vht_priv *vhtpriv = &adapter->mlmepriv.vhtpriv;
+#endif
+	{
+		u8 *p;
+		int ie_len;
+		u8 old_ch = bss->Configuration.DSConfig;
+		bool change_band = _FALSE;
+
+		if ((ch <= 14 && old_ch >= 36) || (ch >= 36 && old_ch <= 14))
+			change_band = _TRUE;
+
+		/* update channel in IE */
+		p = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _DSSET_IE_, &ie_len, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		if (p && ie_len > 0)
+			*(p + 2) = ch;
+
+		bss->Configuration.DSConfig = ch;
+
+		/* band is changed, update ERP, support rate, ext support rate IE */
+		if (change_band == _TRUE)
+			change_band_update_ie(adapter, bss, ch);
+	}
+
+#ifdef CONFIG_80211AC_VHT
+	if (vhtpriv->vht_option == _TRUE) {
+		u8 *vht_cap_ie, *vht_op_ie;
+		int vht_cap_ielen, vht_op_ielen;
+		u8	center_freq;
+
+		vht_cap_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_VHTCapability, &vht_cap_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		vht_op_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_VHTOperation, &vht_op_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		center_freq = rtw_get_center_ch(ch, bw, offset);
+
+		/* update vht cap ie */
+		if (vht_cap_ie && vht_cap_ielen) {
+			#if UPDATE_VHT_CAP
+			/* if ((bw == CHANNEL_WIDTH_160 || bw == CHANNEL_WIDTH_80_80) && pvhtpriv->sgi_160m)
+				SET_VHT_CAPABILITY_ELE_SHORT_GI160M(pvht_cap_ie + 2, 1);
+			else */
+				SET_VHT_CAPABILITY_ELE_SHORT_GI160M(vht_cap_ie + 2, 0);
+
+			if (bw >= CHANNEL_WIDTH_80 && vhtpriv->sgi_80m)
+				SET_VHT_CAPABILITY_ELE_SHORT_GI80M(vht_cap_ie + 2, 1);
+			else
+				SET_VHT_CAPABILITY_ELE_SHORT_GI80M(vht_cap_ie + 2, 0);
+			#endif
+		}
+
+		/* update vht op ie */
+		if (vht_op_ie && vht_op_ielen) {
+			if (bw < CHANNEL_WIDTH_80) {
+				SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0);
+			} else if (bw == CHANNEL_WIDTH_80) {
+				SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 1);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, center_freq);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0);
+			} else {
+				RTW_ERR(FUNC_ADPT_FMT" unsupported BW:%u\n", FUNC_ADPT_ARG(adapter), bw);
+				rtw_warn_on(1);
+			}
+		}
+	}
+#endif /* CONFIG_80211AC_VHT */
+#ifdef CONFIG_80211N_HT
+	{
+		struct ht_priv	*htpriv = &adapter->mlmepriv.htpriv;
+		u8 *ht_cap_ie, *ht_op_ie;
+		int ht_cap_ielen, ht_op_ielen;
+
+		ht_cap_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_HTCapability, &ht_cap_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		ht_op_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_HTInfo, &ht_op_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+
+		/* update ht cap ie */
+		if (ht_cap_ie && ht_cap_ielen) {
+			#if UPDATE_HT_CAP
+			if (bw >= CHANNEL_WIDTH_40)
+				SET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2, 1);
+			else
+				SET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2, 0);
+
+			if (bw >= CHANNEL_WIDTH_40 && htpriv->sgi_40m)
+				SET_HT_CAP_ELE_SHORT_GI40M(ht_cap_ie + 2, 1);
+			else
+				SET_HT_CAP_ELE_SHORT_GI40M(ht_cap_ie + 2, 0);
+
+			if (htpriv->sgi_20m)
+				SET_HT_CAP_ELE_SHORT_GI20M(ht_cap_ie + 2, 1);
+			else
+				SET_HT_CAP_ELE_SHORT_GI20M(ht_cap_ie + 2, 0);
+			#endif
+		}
+
+		/* update ht op ie */
+		if (ht_op_ie && ht_op_ielen) {
+			SET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2, ch);
+			switch (offset) {
+			case HAL_PRIME_CHNL_OFFSET_LOWER:
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCA);
+				break;
+			case HAL_PRIME_CHNL_OFFSET_UPPER:
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCB);
+				break;
+			case HAL_PRIME_CHNL_OFFSET_DONT_CARE:
+			default:
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCN);
+				break;
+			}
+
+			if (bw >= CHANNEL_WIDTH_40)
+				SET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2, 1);
+			else
+				SET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2, 0);
+		}
+	}
+#endif /* CONFIG_80211N_HT */
+}
+
+/*
+* return _TRUE if ch setting differs from mlmeext.network
+*/
+bool rtw_ap_chbw_decision(_adapter *adapter, s16 req_ch, s8 req_bw, s8 req_offset
+			  , u8 *ch, u8 *bw, u8 *offset, u8 *chbw_allow)
+{
+	RT_CHANNEL_INFO *chset = adapter_to_chset(adapter);
+	u8 cur_ie_ch, cur_ie_bw, cur_ie_offset;
+	u8 dec_ch, dec_bw, dec_offset;
+	u8 u_ch = 0, u_offset, u_bw;
+	bool changed = _FALSE;
+	struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
+	WLAN_BSSID_EX *network = &(mlmeext->mlmext_info.network);
+	struct mi_state mstate;
+	bool set_u_ch = _FALSE, set_dec_ch = _FALSE;
+
+	rtw_ies_get_chbw(BSS_EX_TLV_IES(network), BSS_EX_TLV_IES_LEN(network)
+		, &cur_ie_ch, &cur_ie_bw, &cur_ie_offset, 1, 1);
+
+#ifdef CONFIG_MCC_MODE
+	if (MCC_EN(adapter)) {
+		if (rtw_hal_check_mcc_status(adapter, MCC_STATUS_DOING_MCC)) {
+			/* check channel settings are the same */
+			if (cur_ie_ch == mlmeext->cur_channel
+				&& cur_ie_bw == mlmeext->cur_bwmode
+					&& cur_ie_offset == mlmeext->cur_ch_offset) {
+
+
+					RTW_INFO(FUNC_ADPT_FMT"req ch settings are the same as current ch setting, go to exit\n"
+						, FUNC_ADPT_ARG(adapter));
+
+					*chbw_allow = _FALSE;
+					goto exit;
+			} else {
+					RTW_INFO(FUNC_ADPT_FMT"request channel settings are not the same as current channel setting(%d,%d,%d,%d,%d,%d), restart MCC\n"
+						, FUNC_ADPT_ARG(adapter)
+						, cur_ie_ch, cur_ie_bw, cur_ie_bw
+						, mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset);
+
+				rtw_hal_set_mcc_setting_disconnect(adapter);
+			}
+		}	
+	}
+#endif /* CONFIG_MCC_MODE */
+
+	if (req_ch == 0) {
+		/* request comes from upper layer, use cur_ie values */
+		dec_ch = cur_ie_ch;
+		dec_bw = cur_ie_bw;
+		dec_offset = cur_ie_offset;
+	} else {
+		/* use chbw of cur_ie updated with specifying req as temporary decision */
+		dec_ch = (req_ch <= REQ_CH_NONE) ? cur_ie_ch : req_ch;
+		dec_bw = (req_bw <= REQ_BW_NONE) ? cur_ie_bw : req_bw;
+		dec_offset = (req_offset <= REQ_OFFSET_NONE) ? cur_ie_offset : req_offset;
+	}
+
+	rtw_mi_status_no_self(adapter, &mstate);
+	RTW_INFO(FUNC_ADPT_FMT" ld_sta_num:%u, lg_sta_num%u, ap_num:%u, mesh_num:%u\n"
+		, FUNC_ADPT_ARG(adapter), MSTATE_STA_LD_NUM(&mstate), MSTATE_STA_LG_NUM(&mstate)
+		, MSTATE_AP_NUM(&mstate), MSTATE_MESH_NUM(&mstate));
+
+	if (MSTATE_STA_LD_NUM(&mstate) || MSTATE_AP_NUM(&mstate) || MSTATE_MESH_NUM(&mstate)) {
+		/* has linked STA or AP/Mesh mode */
+
+		rtw_warn_on(!rtw_mi_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset));
+
+		RTW_INFO(FUNC_ADPT_FMT" union no self: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+		RTW_INFO(FUNC_ADPT_FMT" req: %d,%d,%d\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset);
+
+		rtw_adjust_chbw(adapter, u_ch, &dec_bw, &dec_offset);
+
+#ifdef CONFIG_MCC_MODE
+		if (MCC_EN(adapter)) {
+			if (!rtw_is_chbw_grouped(u_ch, u_bw, u_offset, dec_ch, dec_bw, dec_offset)) {
+				mlmeext->cur_channel = *ch = dec_ch;
+				mlmeext->cur_bwmode = *bw = dec_bw;
+				mlmeext->cur_ch_offset = *offset = dec_offset;
+				/* channel bw offset can not be allowed, need MCC */
+				*chbw_allow = _FALSE;
+				RTW_INFO(FUNC_ADPT_FMT" enable mcc: %u,%u,%u\n", FUNC_ADPT_ARG(adapter)
+					 , *ch, *bw, *offset);
+				goto exit;
+			} else
+				/* channel bw offset can be allowed, not need MCC */
+				*chbw_allow = _TRUE;
+		}
+#endif /* CONFIG_MCC_MODE */
+
+		/* follow */
+		rtw_chset_sync_chbw(chset
+			, &dec_ch, &dec_bw, &dec_offset
+			, &u_ch, &u_bw, &u_offset);
+
+		set_u_ch = _TRUE;
+	} else if (MSTATE_STA_LG_NUM(&mstate)) {
+		/* has linking STA */
+
+		rtw_warn_on(!rtw_mi_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset));
+
+		RTW_INFO(FUNC_ADPT_FMT" union no self: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+		RTW_INFO(FUNC_ADPT_FMT" req: %d,%d,%d\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset);
+
+		rtw_adjust_chbw(adapter, dec_ch, &dec_bw, &dec_offset);
+
+		if (rtw_is_chbw_grouped(u_ch, u_bw, u_offset, dec_ch, dec_bw, dec_offset)) {
+
+			rtw_chset_sync_chbw(chset
+				, &dec_ch, &dec_bw, &dec_offset
+				, &u_ch, &u_bw, &u_offset);
+
+			set_u_ch = _TRUE;
+
+			/* channel bw offset can be allowed, not need MCC */
+			*chbw_allow = _TRUE;
+		} else {
+#ifdef CONFIG_MCC_MODE
+			if (MCC_EN(adapter)) {
+				mlmeext->cur_channel = *ch = dec_ch;
+				mlmeext->cur_bwmode = *bw = dec_bw;
+				mlmeext->cur_ch_offset = *offset = dec_offset;
+
+				/* channel bw offset can not be allowed, need MCC */
+				*chbw_allow = _FALSE;
+				RTW_INFO(FUNC_ADPT_FMT" enable mcc: %u,%u,%u\n", FUNC_ADPT_ARG(adapter)
+					 , *ch, *bw, *offset);
+				goto exit;
+			}
+#endif /* CONFIG_MCC_MODE */
+
+			/* set this for possible ch change when join down*/
+			set_fwstate(&adapter->mlmepriv, WIFI_OP_CH_SWITCHING);
+		}
+	} else {
+		/* single AP/Mesh mode */
+
+		RTW_INFO(FUNC_ADPT_FMT" req: %d,%d,%d\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset);
+
+		if (req_ch <= REQ_CH_NONE) /* channel is not specified */
+			goto choose_chbw;
+
+		if (rtw_chset_search_ch(chset, dec_ch) < 0) {
+			RTW_WARN(FUNC_ADPT_FMT" ch:%u doesn't fit in chplan\n", FUNC_ADPT_ARG(adapter), req_ch);
+			*chbw_allow = _FALSE;
+			goto exit;
+		}
+
+		/* check temporary decision first */
+		rtw_adjust_chbw(adapter, dec_ch, &dec_bw, &dec_offset);
+		if (!rtw_get_offset_by_chbw(dec_ch, dec_bw, &dec_offset)
+			&& req_bw > REQ_BW_NONE
+		) {
+			RTW_WARN(FUNC_ADPT_FMT" req: %u,%u has no valid offset\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw);
+			*chbw_allow = _FALSE;
+			goto exit;
+		}
+
+		while (!rtw_chset_is_chbw_valid(chset, dec_ch, dec_bw, dec_offset)
+			|| (rtw_odm_dfs_domain_unknown(adapter) && rtw_is_dfs_chbw(dec_ch, dec_bw, dec_offset))
+			|| rtw_chset_is_ch_non_ocp(chset, dec_ch, dec_bw, dec_offset)
+		) {
+			dec_bw--;
+			if (dec_bw == CHANNEL_WIDTH_20) {
+				dec_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+				break;
+			}
+		}
+
+		if (rtw_odm_dfs_domain_unknown(adapter) && rtw_is_dfs_chbw(dec_ch, dec_bw, dec_offset)) {
+			RTW_WARN(FUNC_ADPT_FMT" DFS channel %u can't be used\n", FUNC_ADPT_ARG(adapter), dec_ch);
+			if (req_ch > 0) {
+				/* specific channel and not from IE => don't change channel setting */
+				*chbw_allow = _FALSE;
+				goto exit;
+			}
+			goto choose_chbw;
+		}
+
+		if (rtw_chset_is_ch_non_ocp(chset, dec_ch, dec_bw, dec_offset) == _FALSE)
+			goto update_bss_chbw;
+		RTW_WARN(FUNC_ADPT_FMT" DFS channel %u under non ocp\n", FUNC_ADPT_ARG(adapter), dec_ch);
+
+choose_chbw:
+		req_ch = req_ch >= 0 ? dec_ch : 0;
+		if (req_bw <= REQ_BW_NONE)
+			req_bw = cur_ie_bw;
+
+#if defined(CONFIG_DFS_MASTER)
+		if (!rtw_odm_dfs_domain_unknown(adapter)) {
+			/* choose 5G DFS channel for debug */
+			if (adapter_to_rfctl(adapter)->dbg_dfs_master_choose_dfs_ch_first
+				&& rtw_choose_shortest_waiting_ch(adapter, req_ch, req_bw, &dec_ch, &dec_bw, &dec_offset, RTW_CHF_2G | RTW_CHF_NON_DFS) == _TRUE)
+				RTW_INFO(FUNC_ADPT_FMT" choose 5G DFS channel for debug\n", FUNC_ADPT_ARG(adapter));
+			else if (adapter_to_rfctl(adapter)->dfs_ch_sel_d_flags
+				&& rtw_choose_shortest_waiting_ch(adapter, req_ch, req_bw, &dec_ch, &dec_bw, &dec_offset, adapter_to_rfctl(adapter)->dfs_ch_sel_d_flags) == _TRUE)
+				RTW_INFO(FUNC_ADPT_FMT" choose with dfs_ch_sel_d_flags:0x%02x for debug\n", FUNC_ADPT_ARG(adapter), adapter_to_rfctl(adapter)->dfs_ch_sel_d_flags);
+			else if (rtw_choose_shortest_waiting_ch(adapter, req_ch, req_bw, &dec_ch, &dec_bw, &dec_offset, 0) == _FALSE) {
+				RTW_WARN(FUNC_ADPT_FMT" no available channel\n", FUNC_ADPT_ARG(adapter));
+				*chbw_allow = _FALSE;
+				goto exit;
+			}
+		} else
+#endif /* defined(CONFIG_DFS_MASTER) */
+		if (rtw_choose_shortest_waiting_ch(adapter, req_ch, req_bw, &dec_ch, &dec_bw, &dec_offset, RTW_CHF_DFS) == _FALSE) {
+			RTW_WARN(FUNC_ADPT_FMT" no available channel\n", FUNC_ADPT_ARG(adapter));
+			*chbw_allow = _FALSE;
+			goto exit;
+		}
+
+update_bss_chbw:
+		/* channel bw offset can be allowed for single AP, not need MCC */
+		*chbw_allow = _TRUE;
+		set_dec_ch = _TRUE;
+	}
+
+	if (rtw_mi_check_fwstate(adapter, _FW_UNDER_SURVEY)) {
+		/* scanning, leave ch setting to scan state machine */
+		set_u_ch = set_dec_ch = _FALSE;
+	}
+
+	/* ch setting differs from mlmeext.network IE */
+	if (cur_ie_ch != dec_ch
+		|| cur_ie_bw != dec_bw
+		|| cur_ie_offset != dec_offset)
+		changed = _TRUE;
+
+	/* ch setting differs from existing one */
+	if (check_fwstate(&adapter->mlmepriv, WIFI_ASOC_STATE)
+		&& (mlmeext->cur_channel != dec_ch
+			|| mlmeext->cur_bwmode != dec_bw
+			|| mlmeext->cur_ch_offset != dec_offset)
+	) {
+		if (rtw_linked_check(adapter) == _TRUE) {
+			#ifdef CONFIG_SPCT_CH_SWITCH
+			if (1)
+				rtw_ap_inform_ch_switch(adapter, dec_ch, dec_offset);
+			else
+			#endif
+				rtw_sta_flush(adapter, _FALSE);
+		}
+	}
+
+	mlmeext->cur_channel = dec_ch;
+	mlmeext->cur_bwmode = dec_bw;
+	mlmeext->cur_ch_offset = dec_offset;
+
+	rtw_ap_update_bss_chbw(adapter, network, dec_ch, dec_bw, dec_offset);
+
+	if (u_ch != 0)
+		RTW_INFO(FUNC_ADPT_FMT" union: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+
+	RTW_INFO(FUNC_ADPT_FMT" dec: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw, dec_offset);
+
+	if (set_u_ch == _TRUE) {
+		*ch = u_ch;
+		*bw = u_bw;
+		*offset = u_offset;
+	} else if (set_dec_ch == _TRUE) {
+		*ch = dec_ch;
+		*bw = dec_bw;
+		*offset = dec_offset;
+	}
+exit:
+	return changed;
+}
+
+u8 rtw_ap_sta_linking_state_check(_adapter *adapter)
+{
+	struct sta_info *psta;
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	struct sta_priv *pstapriv = &adapter->stapriv;
+	int i;
+	_list *plist, *phead;
+	_irqL irqL;
+	u8 rst = _FALSE;
+
+	if (!MLME_IS_AP(adapter) && !MLME_IS_MESH(adapter))
+		return _FALSE;
+
+	if (pstapriv->auth_list_cnt !=0)
+		return _TRUE;
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+		if (!(psta->state &_FW_LINKED)) {
+			rst = _TRUE;
+			break;
+		}
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	return rst;
+}
+
+/*#define DBG_SWTIMER_BASED_TXBCN*/
+#ifdef CONFIG_SWTIMER_BASED_TXBCN
+void tx_beacon_handlder(struct dvobj_priv *pdvobj)
+{
+#define BEACON_EARLY_TIME		20	/* unit:TU*/
+	_irqL irqL;
+	_list	*plist, *phead;
+	u32 timestamp[2];
+	u32 bcn_interval_us; /* unit : usec */
+	u64 time;
+	u32 cur_tick, time_offset; /* unit : usec */
+	u32 inter_bcn_space_us; /* unit : usec */
+	u32 txbcn_timer_ms; /* unit : ms */
+	int nr_vap, idx, bcn_idx;
+	int i;
+	u8 val8, late = 0;
+	_adapter *padapter = NULL;
+
+	i = 0;
+
+	/* get first ap mode interface */
+	_enter_critical_bh(&pdvobj->ap_if_q.lock, &irqL);
+	if (rtw_is_list_empty(&pdvobj->ap_if_q.queue) || (pdvobj->nr_ap_if == 0)) {
+		RTW_INFO("[%s] ERROR: ap_if_q is empty!or nr_ap = %d\n", __func__, pdvobj->nr_ap_if);
+		_exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL);
+		return;
+	} else
+		padapter = LIST_CONTAINOR(get_next(&(pdvobj->ap_if_q.queue)), struct _ADAPTER, list);
+	_exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL);
+
+	if (NULL == padapter) {
+		RTW_INFO("[%s] ERROR: no any ap interface!\n", __func__);
+		return;
+	}
+
+
+	bcn_interval_us = DEFAULT_BCN_INTERVAL * NET80211_TU_TO_US;
+	if (0 == bcn_interval_us) {
+		RTW_INFO("[%s] ERROR: beacon interval = 0\n", __func__);
+		return;
+	}
+
+	/* read TSF */
+	timestamp[1] = rtw_read32(padapter, 0x560 + 4);
+	timestamp[0] = rtw_read32(padapter, 0x560);
+	while (timestamp[1]) {
+		time = (0xFFFFFFFF % bcn_interval_us + 1) * timestamp[1] + timestamp[0];
+		timestamp[0] = (u32)time;
+		timestamp[1] = (u32)(time >> 32);
+	}
+	cur_tick = timestamp[0] % bcn_interval_us;
+
+
+	_enter_critical_bh(&pdvobj->ap_if_q.lock, &irqL);
+
+	nr_vap = (pdvobj->nr_ap_if - 1);
+	if (nr_vap > 0) {
+		inter_bcn_space_us = pdvobj->inter_bcn_space * NET80211_TU_TO_US; /* beacon_interval / (nr_vap+1); */
+		idx = cur_tick / inter_bcn_space_us;
+		if (idx < nr_vap)	/* if (idx < (nr_vap+1))*/
+			bcn_idx = idx + 1;	/* bcn_idx = (idx + 1) % (nr_vap+1);*/
+		else
+			bcn_idx = 0;
+
+		/* to get padapter based on bcn_idx */
+		padapter = NULL;
+		phead = get_list_head(&pdvobj->ap_if_q);
+		plist = get_next(phead);
+		while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+			padapter = LIST_CONTAINOR(plist, struct _ADAPTER, list);
+
+			plist = get_next(plist);
+
+			if (i == bcn_idx)
+				break;
+
+			i++;
+		}
+		if ((NULL == padapter) || (i > pdvobj->nr_ap_if)) {
+			RTW_INFO("[%s] ERROR: nr_ap_if = %d, padapter=%p, bcn_idx=%d, index=%d\n",
+				__func__, pdvobj->nr_ap_if, padapter, bcn_idx, i);
+			_exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL);
+			return;
+		}
+#ifdef DBG_SWTIMER_BASED_TXBCN
+		RTW_INFO("BCN_IDX=%d, cur_tick=%d, padapter=%p\n", bcn_idx, cur_tick, padapter);
+#endif
+		if (((idx + 2 == nr_vap + 1) && (idx < nr_vap + 1)) || (0 == bcn_idx)) {
+			time_offset = bcn_interval_us - cur_tick - BEACON_EARLY_TIME * NET80211_TU_TO_US;
+			if ((s32)time_offset < 0)
+				time_offset += inter_bcn_space_us;
+
+		} else {
+			time_offset = (idx + 2) * inter_bcn_space_us - cur_tick - BEACON_EARLY_TIME * NET80211_TU_TO_US;
+			if (time_offset > (inter_bcn_space_us + (inter_bcn_space_us >> 1))) {
+				time_offset -= inter_bcn_space_us;
+				late = 1;
+			}
+		}
+	} else
+		/*#endif*/ { /* MBSSID */
+		time_offset = 2 * bcn_interval_us - cur_tick - BEACON_EARLY_TIME * NET80211_TU_TO_US;
+		if (time_offset > (bcn_interval_us + (bcn_interval_us >> 1))) {
+			time_offset -= bcn_interval_us;
+			late = 1;
+		}
+	}
+	_exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL);
+
+#ifdef DBG_SWTIMER_BASED_TXBCN
+	RTW_INFO("set sw bcn timer %d us\n", time_offset);
+#endif
+	txbcn_timer_ms = time_offset / NET80211_TU_TO_US;
+	_set_timer(&pdvobj->txbcn_timer, txbcn_timer_ms);
+
+	if (padapter) {
+#ifdef CONFIG_BCN_RECOVERY
+		rtw_ap_bcn_recovery(padapter);
+#endif /*CONFIG_BCN_RECOVERY*/
+
+#ifdef CONFIG_BCN_XMIT_PROTECT
+		rtw_ap_bcn_queue_empty_check(padapter, txbcn_timer_ms);
+#endif /*CONFIG_BCN_XMIT_PROTECT*/
+
+#ifdef DBG_SWTIMER_BASED_TXBCN
+		RTW_INFO("padapter=%p, PORT=%d\n", padapter, padapter->hw_port);
+#endif
+		/* bypass TX BCN queue if op ch is switching/waiting */
+		if (!check_fwstate(&padapter->mlmepriv, WIFI_OP_CH_SWITCHING)
+			&& !IS_CH_WAITING(adapter_to_rfctl(padapter))
+		) {
+			/*update_beacon(padapter, _TIM_IE_, NULL, _FALSE);*/
+			/*issue_beacon(padapter, 0);*/
+			send_beacon(padapter);
+		}
+	}
+
+#if 0
+	/* handle any buffered BC/MC frames*/
+	/* Don't dynamically change DIS_ATIM due to HW will auto send ACQ after HIQ empty.*/
+	val8 = *((unsigned char *)priv->beaconbuf + priv->timoffset + 4);
+	if (val8 & 0x01) {
+		process_mcast_dzqueue(priv);
+		priv->pkt_in_dtimQ = 0;
+	}
+#endif
+
+}
+
+void tx_beacon_timer_handlder(void *ctx)
+{
+	struct dvobj_priv *pdvobj = (struct dvobj_priv *)ctx;
+	_adapter *padapter = pdvobj->padapters[0];
+
+	if (padapter)
+		set_tx_beacon_cmd(padapter);
+}
+#endif
+
+void rtw_ap_acdata_control(_adapter *padapter, u8 power_mode)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 sta_alive_num = 0, i;
+	char sta_alive_list[NUM_STA];
+
+#ifdef CONFIG_MCC_MODE
+	if (MCC_EN(padapter) && rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC))
+		/* driver doesn't access macid sleep reg under MCC */
+		return;
+#endif
+
+	/*RTW_INFO(FUNC_ADPT_FMT " associated sta num:%d, make macid_%s!!\n",
+				FUNC_ADPT_ARG(padapter), pstapriv->asoc_list_cnt, power_mode ? "sleep" : "wakeup");*/
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		int stainfo_offset;
+
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+		if (stainfo_offset_valid(stainfo_offset))
+			sta_alive_list[sta_alive_num++] = stainfo_offset;
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	for (i = 0; i < sta_alive_num; i++) {
+		psta = rtw_get_stainfo_by_offset(pstapriv, sta_alive_list[i]);
+
+		if (psta) {
+			if (power_mode)
+				rtw_hal_macid_sleep(padapter, psta->cmn.mac_id);
+			else
+				rtw_hal_macid_wakeup(padapter, psta->cmn.mac_id);
+		}
+	}
+}
+
+void rtw_ap_parse_sta_capability(_adapter *adapter, struct sta_info *sta, u8 *cap)
+{
+	sta->capability = RTW_GET_LE16(cap);
+	if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+		sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+	else
+		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+}
+
+u16 rtw_ap_parse_sta_supported_rates(_adapter *adapter, struct sta_info *sta, u8 *tlv_ies, u16 tlv_ies_len)
+{
+	u8 rate_set[16];
+	u8 rate_num;
+	int i;
+	u16 status = _STATS_SUCCESSFUL_;
+
+	rtw_ies_get_supported_rate(tlv_ies, tlv_ies_len, rate_set, &rate_num);
+	if (rate_num == 0) {
+		RTW_INFO(FUNC_ADPT_FMT" sta "MAC_FMT" with no supported rate\n"
+			, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));
+		status = _STATS_FAILURE_;
+		goto exit;
+	}
+
+	_rtw_memcpy(sta->bssrateset, rate_set, rate_num);
+	sta->bssratelen = rate_num;
+
+	if (MLME_IS_AP(adapter)) {
+		/* this function force only CCK rates to be bassic rate... */
+		UpdateBrateTblForSoftAP(sta->bssrateset, sta->bssratelen);
+	}
+
+	/* if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) */ /* ? */
+	sta->flags |= WLAN_STA_NONERP;
+	for (i = 0; i < sta->bssratelen; i++) {
+		if ((sta->bssrateset[i] & 0x7f) > 22) {
+			sta->flags &= ~WLAN_STA_NONERP;
+			break;
+		}
+	}
+
+exit:
+	return status;
+}
+
+u16 rtw_ap_parse_sta_security_ie(_adapter *adapter, struct sta_info *sta, struct rtw_ieee802_11_elems *elems)
+{
+	struct security_priv *sec = &adapter->securitypriv;
+	u8 *wpa_ie;
+	int wpa_ie_len;
+	int group_cipher = 0, pairwise_cipher = 0;
+	u16 status = _STATS_SUCCESSFUL_;
+
+	sta->dot8021xalg = 0;
+	sta->wpa_psk = 0;
+	sta->wpa_group_cipher = 0;
+	sta->wpa2_group_cipher = 0;
+	sta->wpa_pairwise_cipher = 0;
+	sta->wpa2_pairwise_cipher = 0;
+	_rtw_memset(sta->wpa_ie, 0, sizeof(sta->wpa_ie));
+
+	if ((sec->wpa_psk & BIT(1)) && elems->rsn_ie) {
+		wpa_ie = elems->rsn_ie;
+		wpa_ie_len = elems->rsn_ie_len;
+
+		if (rtw_parse_wpa2_ie(wpa_ie - 2, wpa_ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+			sta->dot8021xalg = 1;/* psk, todo:802.1x */
+			sta->wpa_psk |= BIT(1);
+
+			sta->wpa2_group_cipher = group_cipher & sec->wpa2_group_cipher;
+			sta->wpa2_pairwise_cipher = pairwise_cipher & sec->wpa2_pairwise_cipher;
+
+			if (!sta->wpa2_group_cipher)
+				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+
+			if (!sta->wpa2_pairwise_cipher)
+				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+		} else
+			status = WLAN_STATUS_INVALID_IE;
+
+	}
+	else if ((sec->wpa_psk & BIT(0)) && elems->wpa_ie) {
+		wpa_ie = elems->wpa_ie;
+		wpa_ie_len = elems->wpa_ie_len;
+
+		if (rtw_parse_wpa_ie(wpa_ie - 2, wpa_ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+			sta->dot8021xalg = 1;/* psk, todo:802.1x */
+			sta->wpa_psk |= BIT(0);
+
+			sta->wpa_group_cipher = group_cipher & sec->wpa_group_cipher;
+			sta->wpa_pairwise_cipher = pairwise_cipher & sec->wpa_pairwise_cipher;
+
+			if (!sta->wpa_group_cipher)
+				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+
+			if (!sta->wpa_pairwise_cipher)
+				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+		} else
+			status = WLAN_STATUS_INVALID_IE;
+
+	} else {
+		wpa_ie = NULL;
+		wpa_ie_len = 0;
+	}
+
+	if (status != _STATS_SUCCESSFUL_)
+		goto exit;
+
+	if (!MLME_IS_AP(adapter))
+		goto exit;
+
+	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+	/* if (hapd->conf->wps_state && wpa_ie == NULL) { */ /* todo: to check ap if supporting WPS */
+	if (wpa_ie == NULL) {
+		if (elems->wps_ie) {
+			RTW_INFO("STA included WPS IE in "
+				 "(Re)Association Request - assume WPS is "
+				 "used\n");
+			sta->flags |= WLAN_STA_WPS;
+			/* wpabuf_free(sta->wps_ie); */
+			/* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */
+			/*				elems.wps_ie_len - 4); */
+		} else {
+			RTW_INFO("STA did not include WPA/RSN IE "
+				 "in (Re)Association Request - possible WPS "
+				 "use\n");
+			sta->flags |= WLAN_STA_MAYBE_WPS;
+		}
+
+		/* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */
+		/* that the selected registrar of AP is _FLASE */
+		if ((sec->wpa_psk > 0)
+			&& (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))
+		) {
+			struct mlme_priv *mlme = &adapter->mlmepriv;
+
+			if (mlme->wps_beacon_ie) {
+				u8 selected_registrar = 0;
+
+				rtw_get_wps_attr_content(mlme->wps_beacon_ie, mlme->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR, &selected_registrar, NULL);
+
+				if (!selected_registrar) {
+					RTW_INFO("selected_registrar is _FALSE , or AP is not ready to do WPS\n");
+					status = _STATS_UNABLE_HANDLE_STA_;
+					goto exit;
+				}
+			}
+		}
+
+	} else {
+		int copy_len;
+
+		if (sec->wpa_psk == 0) {
+			RTW_INFO("STA " MAC_FMT
+				": WPA/RSN IE in association request, but AP don't support WPA/RSN\n",
+				MAC_ARG(sta->cmn.mac_addr));
+			status = WLAN_STATUS_INVALID_IE;
+			goto exit;
+		}
+
+		if (elems->wps_ie) {
+			RTW_INFO("STA included WPS IE in "
+				 "(Re)Association Request - WPS is "
+				 "used\n");
+			sta->flags |= WLAN_STA_WPS;
+			copy_len = 0;
+		} else
+			copy_len = ((wpa_ie_len + 2) > sizeof(sta->wpa_ie)) ? (sizeof(sta->wpa_ie)) : (wpa_ie_len + 2);
+
+		if (copy_len > 0)
+			_rtw_memcpy(sta->wpa_ie, wpa_ie - 2, copy_len);
+	}
+
+exit:
+	return status;
+}
+
+void rtw_ap_parse_sta_wmm_ie(_adapter *adapter, struct sta_info *sta, u8 *tlv_ies, u16 tlv_ies_len)
+{
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
+	u8 *p;
+
+	sta->flags &= ~WLAN_STA_WME;
+	sta->qos_option = 0;
+	sta->qos_info = 0;
+	sta->has_legacy_ac = _TRUE;
+	sta->uapsd_vo = 0;
+	sta->uapsd_vi = 0;
+	sta->uapsd_be = 0;
+	sta->uapsd_bk = 0;
+
+	if (!mlme->qospriv.qos_option)
+		goto exit;
+
+	p = rtw_get_ie_ex(tlv_ies, tlv_ies_len, WLAN_EID_VENDOR_SPECIFIC, WMM_IE, 6, NULL, NULL);
+	if (!p)
+		goto exit;
+
+	sta->flags |= WLAN_STA_WME;
+	sta->qos_option = 1;
+	sta->qos_info = *(p + 8);
+	sta->max_sp_len = (sta->qos_info >> 5) & 0x3;
+
+	if ((sta->qos_info & 0xf) != 0xf)
+		sta->has_legacy_ac = _TRUE;
+	else
+		sta->has_legacy_ac = _FALSE;
+
+	if (sta->qos_info & 0xf) {
+		if (sta->qos_info & BIT(0))
+			sta->uapsd_vo = BIT(0) | BIT(1);
+		else
+			sta->uapsd_vo = 0;
+
+		if (sta->qos_info & BIT(1))
+			sta->uapsd_vi = BIT(0) | BIT(1);
+		else
+			sta->uapsd_vi = 0;
+
+		if (sta->qos_info & BIT(2))
+			sta->uapsd_bk = BIT(0) | BIT(1);
+		else
+			sta->uapsd_bk = 0;
+
+		if (sta->qos_info & BIT(3))
+			sta->uapsd_be = BIT(0) | BIT(1);
+		else
+			sta->uapsd_be = 0;
+	}
+
+exit:
+	return;
+}
+
+void rtw_ap_parse_sta_ht_ie(_adapter *adapter, struct sta_info *sta, struct rtw_ieee802_11_elems *elems)
+{
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+
+	sta->flags &= ~WLAN_STA_HT;
+
+#ifdef CONFIG_80211N_HT
+	if (mlme->htpriv.ht_option == _FALSE)
+		goto exit;
+
+	/* save HT capabilities in the sta object */
+	_rtw_memset(&sta->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap));
+	if (elems->ht_capabilities && elems->ht_capabilities_len >= sizeof(struct rtw_ieee80211_ht_cap)) {
+		sta->flags |= WLAN_STA_HT;
+		sta->flags |= WLAN_STA_WME;
+		_rtw_memcpy(&sta->htpriv.ht_cap, elems->ht_capabilities, sizeof(struct rtw_ieee80211_ht_cap));
+	}
+exit:
+#endif
+
+	return;
+}
+
+void rtw_ap_parse_sta_vht_ie(_adapter *adapter, struct sta_info *sta, struct rtw_ieee802_11_elems *elems)
+{
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+
+	sta->flags &= ~WLAN_STA_VHT;
+
+#ifdef CONFIG_80211AC_VHT
+	if (mlme->vhtpriv.vht_option == _FALSE)
+		goto exit;
+
+	_rtw_memset(&sta->vhtpriv, 0, sizeof(struct vht_priv));
+	if (elems->vht_capabilities && elems->vht_capabilities_len == 12) {
+		sta->flags |= WLAN_STA_VHT;
+		_rtw_memcpy(sta->vhtpriv.vht_cap, elems->vht_capabilities, 12);
+
+		if (elems->vht_op_mode_notify && elems->vht_op_mode_notify_len == 1)
+			_rtw_memcpy(&sta->vhtpriv.vht_op_mode_notify, elems->vht_op_mode_notify, 1);
+		else /* for Frame without Operating Mode notify ie; default: 80M */
+			sta->vhtpriv.vht_op_mode_notify = CHANNEL_WIDTH_80;
+	}
+exit:
+#endif
+
+	return;
+}
+#endif /* CONFIG_AP_MODE */
+
diff --git a/core/rtw_beamforming.c b/core/rtw_beamforming.c
new file mode 100644
index 0000000..adf718a
--- /dev/null
+++ b/core/rtw_beamforming.c
@@ -0,0 +1,3155 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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 _RTW_BEAMFORMING_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+#ifdef CONFIG_BEAMFORMING
+
+#ifdef RTW_BEAMFORMING_VERSION_2
+
+struct ndpa_sta_info {
+	u16 aid:12;
+	u16 feedback_type:1;
+	u16 nc_index:3;
+};
+
+static void _get_txvector_parameter(PADAPTER adapter, struct sta_info *sta, u8 *g_id, u16 *p_aid)
+{
+	struct mlme_priv *mlme;
+	u16 aid;
+	u8 *bssid;
+	u16 val16;
+	u8 i;
+
+
+	mlme = &adapter->mlmepriv;
+
+	if (check_fwstate(mlme, WIFI_AP_STATE)) {
+		/*
+		 * Sent by an AP and addressed to a STA associated with that AP
+		 * or sent by a DLS or TDLS STA in a direct path to
+		 * a DLS or TDLS peer STA
+		 */
+
+		aid = sta->cmn.aid;
+		bssid = adapter_mac_addr(adapter);
+		RTW_INFO("%s: AID=0x%x BSSID=" MAC_FMT "\n",
+			 __FUNCTION__, sta->cmn.aid, MAC_ARG(bssid));
+
+		/* AID[0:8] */
+		aid &= 0x1FF;
+		/* BSSID[44:47] xor BSSID[40:43] */
+		val16 = ((bssid[5] & 0xF0) >> 4) ^ (bssid[5] & 0xF);
+		/* (dec(AID[0:8]) + dec(BSSID)*2^5) mod 2^9 */
+		*p_aid = (aid + (val16 << 5)) & 0x1FF;
+		*g_id = 63;
+	} else if ((check_fwstate(mlme, WIFI_ADHOC_STATE) == _TRUE)
+		   || (check_fwstate(mlme, WIFI_ADHOC_MASTER_STATE) == _TRUE)) {
+		/*
+		 * Otherwise, includes
+		 * 1. Sent to an IBSS STA
+		 * 2. Sent by an AP to a non associated STA
+		 * 3. Sent to a STA for which it is not known
+		 *    which condition is applicable
+		 */
+		*p_aid = 0;
+		*g_id = 63;
+	} else {
+		/* Addressed to AP */
+		bssid = sta->cmn.mac_addr;
+		RTW_INFO("%s: BSSID=" MAC_FMT "\n", __FUNCTION__, MAC_ARG(bssid));
+
+		/* BSSID[39:47] */
+		*p_aid = (bssid[5] << 1) | (bssid[4] >> 7);
+		*g_id = 0;
+	}
+
+	RTW_INFO("%s: GROUP_ID=0x%02x PARTIAL_AID=0x%04x\n",
+		 __FUNCTION__, *g_id, *p_aid);
+}
+
+/*
+ * Parameters
+ *	adapter		struct _adapter*
+ *	sta		struct sta_info*
+ *	sta_bf_cap	beamforming capabe of sta
+ *	sounding_dim	Number of Sounding Dimensions
+ *	comp_steering	Compressed Steering Number of Beamformer Antennas Supported
+ */
+static void _get_sta_beamform_cap(PADAPTER adapter, struct sta_info *sta,
+	u8 *sta_bf_cap, u8 *sounding_dim, u8 *comp_steering)
+{
+	struct beamforming_info *info;
+	struct ht_priv *ht;
+#ifdef CONFIG_80211AC_VHT
+	struct vht_priv *vht;
+#endif /* CONFIG_80211AC_VHT */
+	u16 bf_cap;
+
+
+	*sta_bf_cap = 0;
+	*sounding_dim = 0;
+	*comp_steering = 0;
+
+	info = GET_BEAMFORM_INFO(adapter);
+	ht = &adapter->mlmepriv.htpriv;
+#ifdef CONFIG_80211AC_VHT
+	vht = &adapter->mlmepriv.vhtpriv;
+#endif /* CONFIG_80211AC_VHT */
+
+	if (is_supported_ht(sta->wireless_mode) == _TRUE) {
+		/* HT */
+		bf_cap = ht->beamform_cap;
+
+		if (TEST_FLAG(bf_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) {
+			info->beamforming_cap |= BEAMFORMEE_CAP_HT_EXPLICIT;
+			*sta_bf_cap |= BEAMFORMER_CAP_HT_EXPLICIT;
+			*sounding_dim = (bf_cap & BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP) >> 6;
+		}
+		if (TEST_FLAG(bf_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) {
+			info->beamforming_cap |= BEAMFORMER_CAP_HT_EXPLICIT;
+			*sta_bf_cap |= BEAMFORMEE_CAP_HT_EXPLICIT;
+			*comp_steering = (bf_cap & BEAMFORMING_HT_BEAMFORMER_STEER_NUM) >> 4;
+		}
+	}
+
+#ifdef CONFIG_80211AC_VHT
+	if (is_supported_vht(sta->wireless_mode) == _TRUE) {
+		/* VHT */
+		bf_cap = vht->beamform_cap;
+
+		/* We are SU Beamformee because the STA is SU Beamformer */
+		if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) {
+			info->beamforming_cap |= BEAMFORMEE_CAP_VHT_SU;
+			*sta_bf_cap |= BEAMFORMER_CAP_VHT_SU;
+
+			/* We are MU Beamformee because the STA is MU Beamformer */
+			if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) {
+				info->beamforming_cap |= BEAMFORMEE_CAP_VHT_MU;
+				*sta_bf_cap |= BEAMFORMER_CAP_VHT_MU;
+			}
+
+			*sounding_dim = (bf_cap & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM) >> 12;
+		}
+		/* We are SU Beamformer because the STA is SU Beamformee */
+		if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) {
+			info->beamforming_cap |= BEAMFORMER_CAP_VHT_SU;
+			*sta_bf_cap |= BEAMFORMEE_CAP_VHT_SU;
+
+			/* We are MU Beamformer because the STA is MU Beamformee */
+			if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) {
+				info->beamforming_cap |= BEAMFORMER_CAP_VHT_MU;
+				*sta_bf_cap |= BEAMFORMEE_CAP_VHT_MU;
+			}
+
+			*comp_steering = (bf_cap & BEAMFORMING_VHT_BEAMFORMER_STS_CAP) >> 8;
+		}
+	}
+#endif /* CONFIG_80211AC_VHT */
+}
+
+static u8 _send_ht_ndpa_packet(PADAPTER adapter, u8 *ra, enum channel_width bw)
+{
+	/* General */
+	struct xmit_priv		*pxmitpriv;
+	struct mlme_ext_priv		*pmlmeext;
+	struct mlme_ext_info		*pmlmeinfo;
+	struct xmit_frame		*pmgntframe;
+	/* Beamforming */
+	struct beamforming_info		*info;
+	struct beamformee_entry		*bfee;
+	struct ndpa_sta_info		sta_info;
+	u8 ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xE0, 0x4C};
+	/* MISC */
+	struct pkt_attrib		*attrib;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	enum MGN_RATE txrate;
+	u8 *pframe;
+	u16 duration = 0;
+	u8 aSifsTime = 0;
+
+
+	RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra));
+
+	pxmitpriv = &adapter->xmitpriv;
+	pmlmeext = &adapter->mlmeextpriv;
+	pmlmeinfo = &pmlmeext->mlmext_info;
+	bfee = rtw_bf_bfee_get_entry_by_addr(adapter, ra);
+	if (!bfee) {
+		RTW_ERR("%s: Cann't find beamformee entry!\n", __FUNCTION__);
+		return _FALSE;
+	}
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (!pmgntframe) {
+		RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);
+		return _FALSE;
+	}
+
+	txrate = beamforming_get_htndp_tx_rate(GET_PDM_ODM(adapter), bfee->comp_steering_num_of_bfer);
+
+	/* update attribute */
+	attrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(adapter, attrib);
+	/*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */
+	attrib->subtype = WIFI_ACTION_NOACK;
+	attrib->bwmode = bw;
+	/*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */
+	attrib->order = 1;
+	attrib->rate = (u8)txrate;
+	attrib->bf_pkt_type = 0;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	/* Frame control */
+	pwlanhdr->frame_ctl = 0;
+	set_frame_sub_type(pframe, attrib->subtype);
+	set_order_bit(pframe);
+
+	/* Duration */
+	if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
+		aSifsTime = 10;
+	else
+		aSifsTime = 16;
+	duration = 2 * aSifsTime + 40;
+	if (bw == CHANNEL_WIDTH_40)
+		duration += 87;
+	else
+		duration += 180;
+	set_duration(pframe, duration);
+
+	/* DA */
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+	/* SA */
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
+	/* BSSID */
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
+
+	/* HT control field */
+	SET_HT_CTRL_CSI_STEERING(pframe + 24, 3);
+	SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1);
+
+	/*
+	 * Frame Body
+	 * Category field: vender-specific value, 0x7F
+	 * OUI: 0x00E04C
+	 */
+	_rtw_memcpy(pframe + 28, ActionHdr, 4);
+
+	attrib->pktlen = 32;
+	attrib->last_txcmdsz = attrib->pktlen;
+
+	dump_mgntframe(adapter, pmgntframe);
+
+	return _TRUE;
+}
+
+static u8 _send_vht_ndpa_packet(PADAPTER adapter, u8 *ra, u16 aid, enum channel_width bw)
+{
+	/* General */
+	struct xmit_priv		*pxmitpriv;
+	struct mlme_ext_priv		*pmlmeext;
+	struct xmit_frame		*pmgntframe;
+	/* Beamforming */
+	struct beamforming_info		*info;
+	struct beamformee_entry		*bfee;
+	struct ndpa_sta_info		sta_info;
+	/* MISC */
+	struct pkt_attrib		*attrib;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	u8 *pframe;
+	enum MGN_RATE txrate;
+	u16 duration = 0;
+	u8 sequence = 0, aSifsTime = 0;
+
+
+	RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra));
+
+	pxmitpriv = &adapter->xmitpriv;
+	pmlmeext = &adapter->mlmeextpriv;
+	info = GET_BEAMFORM_INFO(adapter);
+	bfee = rtw_bf_bfee_get_entry_by_addr(adapter, ra);
+	if (!bfee) {
+		RTW_ERR("%s: Cann't find beamformee entry!\n", __FUNCTION__);
+		return _FALSE;
+	}
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (!pmgntframe) {
+		RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);
+		return _FALSE;
+	}
+
+	txrate = beamforming_get_vht_ndp_tx_rate(GET_PDM_ODM(adapter), bfee->comp_steering_num_of_bfer);
+
+	/* update attribute */
+	attrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(adapter, attrib);
+	/*pattrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */
+	attrib->subtype = WIFI_NDPA;
+	attrib->bwmode = bw;
+	/*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */
+	attrib->rate = (u8)txrate;
+	attrib->bf_pkt_type = 0;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET);
+	pframe = pmgntframe->buf_addr + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	/* Frame control */
+	pwlanhdr->frame_ctl = 0;
+	set_frame_sub_type(pframe, attrib->subtype);
+
+	/* Duration */
+	if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode))
+		aSifsTime = 16;
+	else
+		aSifsTime = 10;
+	duration = 2 * aSifsTime + 44;
+	if (bw == CHANNEL_WIDTH_80)
+		duration += 40;
+	else if (bw == CHANNEL_WIDTH_40)
+		duration += 87;
+	else
+		duration += 180;
+	set_duration(pframe, duration);
+
+	/* RA */
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+
+	/* TA */
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
+
+	/* Sounding Sequence, bit0~1 is reserved */
+	sequence = info->sounding_sequence << 2;
+	if (info->sounding_sequence >= 0x3f)
+		info->sounding_sequence = 0;
+	else
+		info->sounding_sequence++;
+	_rtw_memcpy(pframe + 16, &sequence, 1);
+
+	/* STA Info */
+	/*
+	 * "AID12" Equal to 0 if the STA is an AP, mesh STA or
+	 * STA that is a member of an IBSS
+	 */
+	if (check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _FALSE)
+		aid = 0;
+	sta_info.aid = aid;
+	/* "Feedback Type" set to 0 for SU */
+	sta_info.feedback_type = 0;
+	/* "Nc Index" reserved if the Feedback Type field indicates SU */
+	sta_info.nc_index = 0;
+	_rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2);
+
+	attrib->pktlen = 19;
+	attrib->last_txcmdsz = attrib->pktlen;
+
+	dump_mgntframe(adapter, pmgntframe);
+
+	return _TRUE;
+}
+
+static u8 _send_vht_mu_ndpa_packet(PADAPTER adapter, enum channel_width bw)
+{
+	/* General */
+	struct xmit_priv		*pxmitpriv;
+	struct mlme_ext_priv		*pmlmeext;
+	struct xmit_frame		*pmgntframe;
+	/* Beamforming */
+	struct beamforming_info		*info;
+	struct sounding_info		*sounding;
+	struct beamformee_entry		*bfee;
+	struct ndpa_sta_info		sta_info;
+	/* MISC */
+	struct pkt_attrib		*attrib;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	enum MGN_RATE txrate;
+	u8 *pframe;
+	u8 *ra = NULL;
+	u16 duration = 0;
+	u8 sequence = 0, aSifsTime = 0;
+	u8 i;
+
+
+	RTW_INFO("+%s\n", __FUNCTION__);
+
+	pxmitpriv = &adapter->xmitpriv;
+	pmlmeext = &adapter->mlmeextpriv;
+	info = GET_BEAMFORM_INFO(adapter);
+	sounding = &info->sounding_info;
+
+	txrate = MGN_VHT2SS_MCS0;
+
+	/*
+	 * Fill the first MU BFee entry (STA1) MAC addr to destination address then
+	 * HW will change A1 to broadcast addr.
+	 * 2015.05.28. Suggested by SD1 Chunchu.
+	 */
+	bfee = &info->bfee_entry[sounding->mu_sounding_list[0]];
+	ra = bfee->mac_addr;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (!pmgntframe) {
+		RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);
+		return _FALSE;
+	}
+
+	/* update attribute */
+	attrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(adapter, attrib);
+	/*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */
+	attrib->subtype = WIFI_NDPA;
+	attrib->bwmode = bw;
+	/*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */
+	attrib->rate = (u8)txrate;
+	/* Set TxBFPktType of Tx desc to unicast type if there is only one MU STA for HW design */
+	if (info->sounding_info.candidate_mu_bfee_cnt > 1)
+		attrib->bf_pkt_type = 1;
+	else
+		attrib->bf_pkt_type = 0;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET);
+	pframe = pmgntframe->buf_addr + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	/* Frame control */
+	pwlanhdr->frame_ctl = 0;
+	set_frame_sub_type(pframe, attrib->subtype);
+
+	/* Duration */
+	if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode))
+		aSifsTime = 16;
+	else
+		aSifsTime = 10;
+	duration = 2 * aSifsTime + 44;
+	if (bw == CHANNEL_WIDTH_80)
+		duration += 40;
+	else if (bw == CHANNEL_WIDTH_40)
+		duration += 87;
+	else
+		duration += 180;
+	set_duration(pframe, duration);
+
+	/* RA */
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+
+	/* TA */
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
+
+	/* Sounding Sequence, bit0~1 is reserved */
+	sequence = info->sounding_sequence << 2;
+	if (info->sounding_sequence >= 0x3f)
+		info->sounding_sequence = 0;
+	else
+		info->sounding_sequence++;
+	_rtw_memcpy(pframe + 16, &sequence, 1);
+
+	attrib->pktlen = 17;
+
+	/*
+	 * Construct STA info. for multiple STAs
+	 * STA Info1, ..., STA Info n
+	 */
+	for (i = 0; i < sounding->candidate_mu_bfee_cnt; i++) {
+		bfee = &info->bfee_entry[sounding->mu_sounding_list[i]];
+		sta_info.aid = bfee->aid;
+		sta_info.feedback_type = 1; /* 1'b1: MU */
+		sta_info.nc_index = 0;
+		_rtw_memcpy(pframe + attrib->pktlen, (u8 *)&sta_info, 2);
+		attrib->pktlen += 2;
+	}
+
+	attrib->last_txcmdsz = attrib->pktlen;
+
+	dump_mgntframe(adapter, pmgntframe);
+
+	return _TRUE;
+}
+
+static u8 _send_bf_report_poll(PADAPTER adapter, u8 *ra, u8 bFinalPoll)
+{
+	/* General */
+	struct xmit_priv *pxmitpriv;
+	struct xmit_frame *pmgntframe;
+	/* MISC */
+	struct pkt_attrib *attrib;
+	struct rtw_ieee80211_hdr *pwlanhdr;
+	u8 *pframe;
+
+
+	RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra));
+
+	pxmitpriv = &adapter->xmitpriv;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (!pmgntframe) {
+		RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);
+		return _FALSE;
+	}
+
+	/* update attribute */
+	attrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(adapter, attrib);
+	/*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */
+	attrib->subtype = WIFI_BF_REPORT_POLL;
+	attrib->bwmode = CHANNEL_WIDTH_20;
+	/*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */
+	attrib->rate = MGN_6M;
+	if (bFinalPoll)
+		attrib->bf_pkt_type = 3;
+	else
+		attrib->bf_pkt_type = 2;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET);
+	pframe = pmgntframe->buf_addr + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	/* Frame control */
+	pwlanhdr->frame_ctl = 0;
+	set_frame_sub_type(pframe, attrib->subtype);
+
+	/* Duration */
+	set_duration(pframe, 100);
+
+	/* RA */
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+
+	/* TA */
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
+
+	/* Feedback Segment Retransmission Bitmap */
+	pframe[16] = 0xFF;
+
+	attrib->pktlen = 17;
+	attrib->last_txcmdsz = attrib->pktlen;
+
+	dump_mgntframe(adapter, pmgntframe);
+
+	return _TRUE;
+}
+
+static void _sounding_update_min_period(PADAPTER adapter, u16 period, u8 leave)
+{
+	struct beamforming_info *info;
+	struct beamformee_entry *bfee;
+	u8 i = 0;
+	u16 min_val = 0xFFFF;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	if (_TRUE == leave) {
+		/*
+		 * When a BFee left,
+		 * we need to find the latest min sounding period
+		 * from the remaining BFees
+		 */
+		for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
+			bfee = &info->bfee_entry[i];
+			if ((bfee->used == _TRUE)
+			    && (bfee->sound_period < min_val))
+				min_val = bfee->sound_period;
+		}
+
+		if (min_val == 0xFFFF)
+			info->sounding_info.min_sounding_period = 0;
+		else
+			info->sounding_info.min_sounding_period = min_val;
+	} else {
+		if ((info->sounding_info.min_sounding_period == 0)
+		    || (period < info->sounding_info.min_sounding_period))
+			info->sounding_info.min_sounding_period = period;
+	}
+}
+
+static void _sounding_init(struct sounding_info *sounding)
+{
+	_rtw_memset(sounding->su_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_SU);
+	_rtw_memset(sounding->mu_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_MU);
+	sounding->state = SOUNDING_STATE_NONE;
+	sounding->su_bfee_curidx = 0xFF;
+	sounding->candidate_mu_bfee_cnt = 0;
+	sounding->min_sounding_period = 0;
+	sounding->sound_remain_cnt_per_period = 0;
+}
+
+static void _sounding_reset_vars(PADAPTER adapter)
+{
+	struct beamforming_info	*info;
+	struct sounding_info *sounding;
+	u8 idx;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+	sounding = &info->sounding_info;
+
+	_rtw_memset(sounding->su_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_SU);
+	_rtw_memset(sounding->mu_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_MU);
+	sounding->su_bfee_curidx = 0xFF;
+	sounding->candidate_mu_bfee_cnt = 0;
+
+	/* Clear bSound flag for the new period */
+	for (idx = 0; idx < MAX_BEAMFORMEE_ENTRY_NUM; idx++) {
+		if ((info->bfee_entry[idx].used == _TRUE)
+		    && (info->bfee_entry[idx].sounding == _TRUE)) {
+			info->bfee_entry[idx].sounding = _FALSE;
+			info->bfee_entry[idx].bCandidateSoundingPeer = _FALSE;
+		}
+	}
+}
+
+/*
+ * Return
+ *	0	Prepare sounding list OK
+ *	-1	Fail to prepare sounding list, because no beamformee need to souding
+ *	-2	Fail to prepare sounding list, because beamformee state not ready
+ *
+ */
+static int _sounding_get_list(PADAPTER adapter)
+{
+	struct beamforming_info	*info;
+	struct sounding_info *sounding;
+	struct beamformee_entry *bfee;
+	u8 i, mu_idx = 0, su_idx = 0, not_ready = 0;
+	int ret = 0;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+	sounding = &info->sounding_info;
+
+	/* Add MU BFee list first because MU priority is higher than SU */
+	for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
+		bfee = &info->bfee_entry[i];
+		if (bfee->used == _FALSE)
+			continue;
+
+		if (bfee->state != BEAMFORM_ENTRY_HW_STATE_ADDED) {
+			RTW_ERR("%s: Invalid BFee idx(%d) Hw state=%d\n", __FUNCTION__, i, bfee->state);
+			not_ready++;
+			continue;
+		}
+
+		/*
+		 * Decrease BFee's SoundCnt per period
+		 * If the remain count is 0,
+		 * then it can be sounded at this time
+		 */
+		if (bfee->SoundCnt) {
+			bfee->SoundCnt--;
+			if (bfee->SoundCnt)
+				continue;
+		}
+
+		/*
+		 * <tynli_Note>
+		 *	If the STA supports MU BFee capability then we add it to MUSoundingList directly
+		 *	because we can only sound one STA by unicast NDPA with MU cap enabled to get correct channel info.
+		 *	Suggested by BB team Luke Lee. 2015.11.25.
+		 */
+		if (bfee->cap & BEAMFORMEE_CAP_VHT_MU) {
+			/* MU BFee */
+			if (mu_idx >= MAX_NUM_BEAMFORMEE_MU) {
+				RTW_ERR("%s: Too much MU bfee entry(Limit:%d)\n", __FUNCTION__, MAX_NUM_BEAMFORMEE_MU);
+				continue;
+			}
+
+			if (bfee->bApplySounding == _TRUE) {
+				bfee->bCandidateSoundingPeer = _TRUE;
+				bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, sounding->min_sounding_period);
+				sounding->mu_sounding_list[mu_idx] = i;
+				mu_idx++;
+			}
+		} else if (bfee->cap & (BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) {
+			/* SU BFee (HT/VHT) */
+			if (su_idx >= MAX_NUM_BEAMFORMEE_SU) {
+				RTW_ERR("%s: Too much SU bfee entry(Limit:%d)\n", __FUNCTION__, MAX_NUM_BEAMFORMEE_SU);
+				continue;
+			}
+
+			if (bfee->bDeleteSounding == _TRUE) {
+				sounding->su_sounding_list[su_idx] = i;
+				su_idx++;
+			} else if ((bfee->bApplySounding == _TRUE)
+			    && (bfee->bSuspendSUCap == _FALSE)) {
+				bfee->bCandidateSoundingPeer = _TRUE;
+				bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, sounding->min_sounding_period);
+				sounding->su_sounding_list[su_idx] = i;
+				su_idx++;
+			}
+		}
+	}
+
+	sounding->candidate_mu_bfee_cnt = mu_idx;
+
+	if (su_idx + mu_idx == 0) {
+		ret = -1;
+		if (not_ready)
+			ret = -2;
+	}
+
+	RTW_INFO("-%s: There are %d SU and %d MU BFees in this sounding period\n", __FUNCTION__, su_idx, mu_idx);
+
+	return ret;
+}
+
+static void _sounding_handler(PADAPTER adapter)
+{
+	struct beamforming_info	*info;
+	struct sounding_info *sounding;
+	struct beamformee_entry *bfee;
+	u8 su_idx, i;
+	u32 timeout_period = 0;
+	u8 set_timer = _FALSE;
+	int ret = 0;
+	static u16 wait_cnt = 0;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+	sounding = &info->sounding_info;
+
+	RTW_DBG("+%s: state=%d\n", __FUNCTION__, sounding->state);
+	if ((sounding->state != SOUNDING_STATE_INIT)
+	    && (sounding->state != SOUNDING_STATE_SU_SOUNDDOWN)
+	    && (sounding->state != SOUNDING_STATE_MU_SOUNDDOWN)
+	    && (sounding->state != SOUNDING_STATE_SOUNDING_TIMEOUT)) {
+		RTW_WARN("%s: Invalid State(%d) and return!\n", __FUNCTION__, sounding->state);
+		return;
+	}
+
+	if (sounding->state == SOUNDING_STATE_INIT) {
+		RTW_INFO("%s: Sounding start\n", __FUNCTION__);
+
+		/* Init Var */
+		_sounding_reset_vars(adapter);
+
+		/* Get the sounding list of this sounding period */
+		ret = _sounding_get_list(adapter);
+		if (ret == -1) {
+			wait_cnt = 0;
+			sounding->state = SOUNDING_STATE_NONE;
+			RTW_ERR("%s: No BFees found, set to SOUNDING_STATE_NONE\n", __FUNCTION__);
+			info->sounding_running--;
+			return;
+		}
+		if (ret == -2) {
+			RTW_WARN("%s: Temporarily cann't find BFee to sounding\n", __FUNCTION__);
+			if (wait_cnt < 5) {
+				wait_cnt++;
+			} else {
+				wait_cnt = 0;
+				sounding->state = SOUNDING_STATE_NONE;
+				RTW_ERR("%s: Wait changing state timeout!! Set to SOUNDING_STATE_NONE\n", __FUNCTION__);
+			}
+			info->sounding_running--;
+			return;
+		}
+		if (ret != 0) {
+			wait_cnt = 0;
+			RTW_ERR("%s: Unkown state(%d)!\n", __FUNCTION__, ret);
+			info->sounding_running--;
+			return;
+
+		}
+
+		wait_cnt = 0;
+
+		if (check_fwstate(&adapter->mlmepriv, WIFI_SITE_MONITOR) == _TRUE) {
+			RTW_INFO("%s: Sounding abort! scanning APs...\n", __FUNCTION__);
+			info->sounding_running--;
+			return;
+		}
+
+		rtw_ps_deny(adapter, PS_DENY_BEAMFORMING);
+		LeaveAllPowerSaveModeDirect(adapter);
+	}
+
+	/* Get non-sound SU BFee index */
+	for (i = 0; i < MAX_NUM_BEAMFORMEE_SU; i++) {
+		su_idx = sounding->su_sounding_list[i];
+		if (su_idx >= MAX_BEAMFORMEE_ENTRY_NUM)
+			continue;
+		bfee = &info->bfee_entry[su_idx];
+		if (_FALSE == bfee->sounding)
+			break;
+	}
+	if (i < MAX_NUM_BEAMFORMEE_SU) {
+		sounding->su_bfee_curidx = su_idx;
+		/* Set to sounding start state */
+		sounding->state = SOUNDING_STATE_SU_START;
+		RTW_DBG("%s: Set to SOUNDING_STATE_SU_START\n", __FUNCTION__);
+
+		bfee->sounding = _TRUE;
+		/* Reset sounding timeout flag for the new sounding */
+		bfee->bSoundingTimeout = _FALSE;
+
+		if (_TRUE == bfee->bDeleteSounding) {
+			u8 res = _FALSE;
+			rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 0);
+			return;
+		}
+
+		/* Start SU sounding */
+		if (bfee->cap & BEAMFORMEE_CAP_VHT_SU)
+			_send_vht_ndpa_packet(adapter, bfee->mac_addr, bfee->aid, bfee->sound_bw);
+		else if (bfee->cap & BEAMFORMEE_CAP_HT_EXPLICIT)
+			_send_ht_ndpa_packet(adapter, bfee->mac_addr, bfee->sound_bw);
+
+		/* Set sounding timeout timer */
+		_set_timer(&info->sounding_timeout_timer, SU_SOUNDING_TIMEOUT);
+		return;
+	}
+
+	if (sounding->candidate_mu_bfee_cnt > 0) {
+		/*
+		 * If there is no SU BFee then find MU BFee and perform MU sounding
+		 *
+		 * <tynli_note> Need to check the MU starting condition. 2015.12.15.
+		 */
+		sounding->state = SOUNDING_STATE_MU_START;
+		RTW_DBG("%s: Set to SOUNDING_STATE_MU_START\n", __FUNCTION__);
+
+		/* Update MU BFee info */
+		for (i = 0; i < sounding->candidate_mu_bfee_cnt; i++) {
+			bfee = &info->bfee_entry[sounding->mu_sounding_list[i]];
+			bfee->sounding = _TRUE;
+		}
+
+		/* Send MU NDPA */
+		bfee = &info->bfee_entry[sounding->mu_sounding_list[0]];
+		_send_vht_mu_ndpa_packet(adapter, bfee->sound_bw);
+
+		/* Send BF report poll if more than 1 MU STA */
+		for (i = 1; i < sounding->candidate_mu_bfee_cnt; i++) {
+			bfee = &info->bfee_entry[sounding->mu_sounding_list[i]];
+
+			if (i == (sounding->candidate_mu_bfee_cnt - 1))/* The last STA*/
+				_send_bf_report_poll(adapter, bfee->mac_addr, _TRUE);
+			else
+				_send_bf_report_poll(adapter, bfee->mac_addr, _FALSE);
+		}
+
+		sounding->candidate_mu_bfee_cnt = 0;
+
+		/* Set sounding timeout timer */
+		_set_timer(&info->sounding_timeout_timer, MU_SOUNDING_TIMEOUT);
+		return;
+	}
+
+	info->sounding_running--;
+	sounding->state = SOUNDING_STATE_INIT;
+	RTW_INFO("%s: Sounding finished!\n", __FUNCTION__);
+	rtw_ps_deny_cancel(adapter, PS_DENY_BEAMFORMING);
+}
+
+static void _sounding_force_stop(PADAPTER adapter)
+{
+	struct beamforming_info	*info;
+	struct sounding_info *sounding;
+
+	info = GET_BEAMFORM_INFO(adapter);
+	sounding = &info->sounding_info;
+
+	if ((sounding->state == SOUNDING_STATE_SU_START)
+	    || (sounding->state == SOUNDING_STATE_MU_START)) {
+		u8 res = _FALSE;
+		_cancel_timer_ex(&info->sounding_timeout_timer);
+		rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 1);
+		return;
+	}
+
+	info->sounding_running--;
+	sounding->state = SOUNDING_STATE_INIT;
+	RTW_INFO("%s: Sounding finished!\n", __FUNCTION__);
+	rtw_ps_deny_cancel(adapter, PS_DENY_BEAMFORMING);
+}
+
+static void _sounding_timer_handler(void *FunctionContext)
+{
+	PADAPTER adapter;
+	struct beamforming_info	*info;
+	struct sounding_info *sounding;
+	static u8 delay = 0;
+
+
+	RTW_DBG("+%s\n", __FUNCTION__);
+
+	adapter = (PADAPTER)FunctionContext;
+	info = GET_BEAMFORM_INFO(adapter);
+	sounding = &info->sounding_info;
+
+	if (SOUNDING_STATE_NONE == sounding->state) {
+		RTW_INFO("%s: Stop!\n", __FUNCTION__);
+		if (info->sounding_running)
+			RTW_WARN("%s: souding_running=%d when thread stop!\n",
+				 __FUNCTION__, info->sounding_running);
+		return;
+	}
+
+	_set_timer(&info->sounding_timer, sounding->min_sounding_period);
+
+	if (!info->sounding_running) {
+		if (SOUNDING_STATE_INIT != sounding->state) {
+			RTW_WARN("%s: state(%d) != SOUNDING_STATE_INIT!!\n", __FUNCTION__, sounding->state);
+			sounding->state = SOUNDING_STATE_INIT;
+		}
+		delay = 0;
+		info->sounding_running++;
+		rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 1);
+	} else {
+		if (delay != 0xFF)
+			delay++;
+		RTW_WARN("%s: souding is still processing...(state:%d, running:%d, delay:%d)\n",
+			 __FUNCTION__, sounding->state, info->sounding_running, delay);
+		if (delay > 3) {
+			RTW_WARN("%s: Stop sounding!!\n", __FUNCTION__);
+			_sounding_force_stop(adapter);
+		}
+	}
+}
+
+static void _sounding_timeout_timer_handler(void *FunctionContext)
+{
+	PADAPTER adapter;
+	struct beamforming_info	*info;
+	struct sounding_info *sounding;
+	struct beamformee_entry *bfee;
+
+
+	RTW_WARN("+%s\n", __FUNCTION__);
+
+	adapter = (PADAPTER)FunctionContext;
+	info = GET_BEAMFORM_INFO(adapter);
+	sounding = &info->sounding_info;
+
+	if (SOUNDING_STATE_SU_START == sounding->state) {
+		sounding->state = SOUNDING_STATE_SOUNDING_TIMEOUT;
+		RTW_ERR("%s: Set to SU SOUNDING_STATE_SOUNDING_TIMEOUT\n", __FUNCTION__);
+		/* SU BFee */
+		bfee = &info->bfee_entry[sounding->su_bfee_curidx];
+		bfee->bSoundingTimeout = _TRUE;
+		RTW_WARN("%s: The BFee entry[%d] is Sounding Timeout!\n", __FUNCTION__, sounding->su_bfee_curidx);
+	} else if (SOUNDING_STATE_MU_START == sounding->state) {
+		sounding->state = SOUNDING_STATE_SOUNDING_TIMEOUT;
+		RTW_ERR("%s: Set to MU SOUNDING_STATE_SOUNDING_TIMEOUT\n", __FUNCTION__);
+	} else {
+		RTW_WARN("%s: unexpected sounding state:0x%02x\n", __FUNCTION__, sounding->state);
+		return;
+	}
+
+	rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 1);
+}
+
+static struct beamformer_entry *_bfer_get_free_entry(PADAPTER adapter)
+{
+	u8 i = 0;
+	struct beamforming_info *info;
+	struct beamformer_entry *bfer;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) {
+		bfer = &info->bfer_entry[i];
+		if (bfer->used == _FALSE)
+			return bfer;
+	}
+
+	return NULL;
+}
+
+static struct beamformer_entry *_bfer_get_entry_by_addr(PADAPTER adapter, u8 *ra)
+{
+	u8 i = 0;
+	struct beamforming_info *info;
+	struct beamformer_entry *bfer;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) {
+		bfer = &info->bfer_entry[i];
+		if (bfer->used == _FALSE)
+			continue;
+		if (_rtw_memcmp(ra, bfer->mac_addr, ETH_ALEN) == _TRUE)
+			return bfer;
+	}
+
+	return NULL;
+}
+
+static struct beamformer_entry *_bfer_add_entry(PADAPTER adapter,
+	struct sta_info *sta, u8 bf_cap, u8 sounding_dim, u8 comp_steering)
+{
+	struct mlme_priv *mlme;
+	struct beamforming_info *info;
+	struct beamformer_entry *bfer;
+	u8 *bssid;
+	u16 val16;
+	u8 i;
+
+
+	mlme = &adapter->mlmepriv;
+	info = GET_BEAMFORM_INFO(adapter);
+
+	bfer = _bfer_get_entry_by_addr(adapter, sta->cmn.mac_addr);
+	if (!bfer) {
+		bfer = _bfer_get_free_entry(adapter);
+		if (!bfer)
+			return NULL;
+	}
+
+	bfer->used = _TRUE;
+	_get_txvector_parameter(adapter, sta, &bfer->g_id, &bfer->p_aid);
+	_rtw_memcpy(bfer->mac_addr, sta->cmn.mac_addr, ETH_ALEN);
+	bfer->cap = bf_cap;
+	bfer->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT;
+	bfer->NumofSoundingDim = sounding_dim;
+
+	if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_MU)) {
+		info->beamformer_mu_cnt += 1;
+		bfer->aid = sta->cmn.aid;
+	} else if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) {
+		info->beamformer_su_cnt += 1;
+
+		/* Record HW idx info */
+		for (i = 0; i < MAX_NUM_BEAMFORMER_SU; i++) {
+			if ((info->beamformer_su_reg_maping & BIT(i)) == 0) {
+				info->beamformer_su_reg_maping |= BIT(i);
+				bfer->su_reg_index = i;
+				break;
+			}
+		}
+		RTW_INFO("%s: Add BFer entry beamformer_su_reg_maping=%#x, su_reg_index=%d\n",
+			 __FUNCTION__, info->beamformer_su_reg_maping, bfer->su_reg_index);
+	}
+
+	return bfer;
+}
+
+static void _bfer_remove_entry(PADAPTER adapter, struct beamformer_entry *entry)
+{
+	struct beamforming_info *info;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	entry->state = BEAMFORM_ENTRY_HW_STATE_DELETE_INIT;
+
+	if (TEST_FLAG(entry->cap, BEAMFORMER_CAP_VHT_MU)) {
+		info->beamformer_mu_cnt -= 1;
+		_rtw_memset(entry->gid_valid, 0, 8);
+		_rtw_memset(entry->user_position, 0, 16);
+	} else if (TEST_FLAG(entry->cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) {
+		info->beamformer_su_cnt -= 1;
+	}
+
+	if (info->beamformer_mu_cnt == 0)
+		info->beamforming_cap &= ~BEAMFORMEE_CAP_VHT_MU;
+	if (info->beamformer_su_cnt == 0)
+		info->beamforming_cap &= ~(BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT);
+}
+
+static u8 _bfer_set_entry_gid(PADAPTER adapter, u8 *addr, u8 *gid, u8 *position)
+{
+	struct beamformer_entry bfer;
+
+	memset(&bfer, 0, sizeof(bfer));
+	memcpy(bfer.mac_addr, addr, 6);
+
+	/* Parsing Membership Status Array */
+	memcpy(bfer.gid_valid, gid, 8);
+
+	/* Parsing User Position Array */
+	memcpy(bfer.user_position, position, 16);
+
+	/* Config HW GID table */
+	rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_GID_TABLE, (u8 *) &bfer,
+			sizeof(bfer), 1);
+
+	return _SUCCESS;
+}
+
+static struct beamformee_entry *_bfee_get_free_entry(PADAPTER adapter)
+{
+	u8 i = 0;
+	struct beamforming_info *info;
+	struct beamformee_entry *bfee;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
+		bfee = &info->bfee_entry[i];
+		if (bfee->used == _FALSE)
+			return bfee;
+	}
+
+	return NULL;
+}
+
+static struct beamformee_entry *_bfee_get_entry_by_addr(PADAPTER adapter, u8 *ra)
+{
+	u8 i = 0;
+	struct beamforming_info *info;
+	struct beamformee_entry *bfee;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
+		bfee = &info->bfee_entry[i];
+		if (bfee->used == _FALSE)
+			continue;
+		if (_rtw_memcmp(ra, bfee->mac_addr, ETH_ALEN) == _TRUE)
+			return bfee;
+	}
+
+	return NULL;
+}
+
+static u8 _bfee_get_first_su_entry_idx(PADAPTER adapter, struct beamformee_entry *ignore)
+{
+	struct beamforming_info *info;
+	struct beamformee_entry *bfee;
+	u8 i;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
+		bfee = &info->bfee_entry[i];
+		if (ignore && (bfee == ignore))
+			continue;
+		if (bfee->used == _FALSE)
+			continue;
+		if ((!TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_MU))
+		    && TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT))
+			return i;
+	}
+
+	return 0xFF;
+}
+
+/*
+ * Description:
+ *	Get the first entry index of MU Beamformee.
+ *
+ * Return Value:
+ *	Index of the first MU sta, or 0xFF for invalid index.
+ *
+ * 2015.05.25. Created by tynli.
+ *
+ */
+static u8 _bfee_get_first_mu_entry_idx(PADAPTER adapter, struct beamformee_entry *ignore)
+{
+	struct beamforming_info *info;
+	struct beamformee_entry *bfee;
+	u8 i;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
+		bfee = &info->bfee_entry[i];
+		if (ignore && (bfee == ignore))
+			continue;
+		if (bfee->used == _FALSE)
+			continue;
+		if (TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_MU))
+			return i;
+	}
+
+	return 0xFF;
+}
+
+static struct beamformee_entry *_bfee_add_entry(PADAPTER adapter,
+	struct sta_info *sta, u8 bf_cap, u8 sounding_dim, u8 comp_steering)
+{
+	struct mlme_priv *mlme;
+	struct beamforming_info *info;
+	struct beamformee_entry *bfee;
+	u8 *bssid;
+	u16 val16;
+	u8 i;
+
+
+	mlme = &adapter->mlmepriv;
+	info = GET_BEAMFORM_INFO(adapter);
+
+	bfee = _bfee_get_entry_by_addr(adapter, sta->cmn.mac_addr);
+	if (!bfee) {
+		bfee = _bfee_get_free_entry(adapter);
+		if (!bfee)
+			return NULL;
+	}
+
+	bfee->used = _TRUE;
+	bfee->aid = sta->cmn.aid;
+	bfee->mac_id = sta->cmn.mac_id;
+	bfee->sound_bw = sta->cmn.bw_mode;
+
+	_get_txvector_parameter(adapter, sta, &bfee->g_id, &bfee->p_aid);
+	sta->cmn.bf_info.g_id = bfee->g_id;
+	sta->cmn.bf_info.p_aid = bfee->p_aid;
+
+	_rtw_memcpy(bfee->mac_addr, sta->cmn.mac_addr, ETH_ALEN);
+	bfee->txbf = _FALSE;
+	bfee->sounding = _FALSE;
+	bfee->sound_period = 40;
+	_sounding_update_min_period(adapter, bfee->sound_period, _FALSE);
+	bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, info->sounding_info.min_sounding_period);
+	bfee->cap = bf_cap;
+	bfee->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT;
+
+	bfee->bCandidateSoundingPeer = _FALSE;
+	bfee->bSoundingTimeout = _FALSE;
+	bfee->bDeleteSounding = _FALSE;
+	bfee->bApplySounding = _TRUE;
+
+	bfee->tx_timestamp = 0;
+	bfee->tx_bytes = 0;
+
+	bfee->LogStatusFailCnt = 0;
+	bfee->NumofSoundingDim = sounding_dim;
+	bfee->comp_steering_num_of_bfer = comp_steering;
+	bfee->bSuspendSUCap = _FALSE;
+
+	if (TEST_FLAG(bf_cap, BEAMFORMEE_CAP_VHT_MU)) {
+		info->beamformee_mu_cnt += 1;
+		info->first_mu_bfee_index = _bfee_get_first_mu_entry_idx(adapter, NULL);
+
+		if (_TRUE == info->bEnableSUTxBFWorkAround) {
+			/* When the first MU BFee added, discard SU BFee bfee's capability */
+			if ((info->beamformee_mu_cnt == 1) && (info->beamformee_su_cnt > 0)) {
+				if (info->TargetSUBFee) {
+					info->TargetSUBFee->bSuspendSUCap = _TRUE;
+					info->TargetSUBFee->bDeleteSounding = _TRUE;
+				} else {
+					RTW_ERR("%s: UNEXPECTED!! info->TargetSUBFee is NULL!", __FUNCTION__);
+				}
+				info->TargetSUBFee = NULL;
+				_rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));
+				rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 0);
+			}
+		}
+
+		/* Record HW idx info */
+		for (i = 0; i < MAX_NUM_BEAMFORMEE_MU; i++) {
+			if ((info->beamformee_mu_reg_maping & BIT(i)) == 0) {
+				info->beamformee_mu_reg_maping |= BIT(i);
+				bfee->mu_reg_index = i;
+				break;
+			}
+		}
+		RTW_INFO("%s: Add BFee entry beamformee_mu_reg_maping=%#x, mu_reg_index=%d\n",
+			 __FUNCTION__, info->beamformee_mu_reg_maping, bfee->mu_reg_index);
+
+	} else if (TEST_FLAG(bf_cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) {
+		info->beamformee_su_cnt += 1;
+
+		if (_TRUE == info->bEnableSUTxBFWorkAround) {
+			/* Record the first SU BFee index. We only allow the first SU BFee to be sound */
+			if ((info->beamformee_su_cnt == 1) && (info->beamformee_mu_cnt == 0)) {
+				info->TargetSUBFee = bfee;
+				_rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));
+				bfee->bSuspendSUCap = _FALSE;
+			} else {
+				bfee->bSuspendSUCap = _TRUE;
+			}
+		}
+
+		/* Record HW idx info */
+		for (i = 0; i < MAX_NUM_BEAMFORMEE_SU; i++) {
+			if ((info->beamformee_su_reg_maping & BIT(i)) == 0) {
+				info->beamformee_su_reg_maping |= BIT(i);
+				bfee->su_reg_index = i;
+				break;
+			}
+		}
+		RTW_INFO("%s: Add BFee entry beamformee_su_reg_maping=%#x, su_reg_index=%d\n",
+			 __FUNCTION__, info->beamformee_su_reg_maping, bfee->su_reg_index);
+	}
+
+	return bfee;
+}
+
+static void _bfee_remove_entry(PADAPTER adapter, struct beamformee_entry *entry)
+{
+	struct beamforming_info *info;
+	u8 idx;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	entry->state = BEAMFORM_ENTRY_HW_STATE_DELETE_INIT;
+
+	if (TEST_FLAG(entry->cap, BEAMFORMEE_CAP_VHT_MU)) {
+		info->beamformee_mu_cnt -= 1;
+		info->first_mu_bfee_index = _bfee_get_first_mu_entry_idx(adapter, entry);
+
+		if (_TRUE == info->bEnableSUTxBFWorkAround) {
+			if ((info->beamformee_mu_cnt == 0) && (info->beamformee_su_cnt > 0)) {
+				idx = _bfee_get_first_su_entry_idx(adapter, NULL);
+				info->TargetSUBFee = &info->bfee_entry[idx];
+				_rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));
+				info->TargetSUBFee->bSuspendSUCap = _FALSE;
+			}
+		}
+	} else if (TEST_FLAG(entry->cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) {
+		info->beamformee_su_cnt -= 1;
+
+		/* When the target SU BFee leaves, disable workaround */
+		if ((_TRUE == info->bEnableSUTxBFWorkAround)
+		    && (entry == info->TargetSUBFee)) {
+			entry->bSuspendSUCap = _TRUE;
+			info->TargetSUBFee = NULL;
+			_rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));
+			rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 0);
+		}
+	}
+
+	if (info->beamformee_mu_cnt == 0)
+		info->beamforming_cap &= ~BEAMFORMER_CAP_VHT_MU;
+	if (info->beamformee_su_cnt == 0)
+		info->beamforming_cap &= ~(BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT);
+
+	_sounding_update_min_period(adapter, 0, _TRUE);
+}
+
+static enum beamforming_cap _bfee_get_entry_cap_by_macid(PADAPTER adapter, u8 macid)
+{
+	struct beamforming_info *info;
+	struct beamformee_entry *bfee;
+	u8 i;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) {
+		bfee = &info->bfee_entry[i];
+		if (bfee->used == _FALSE)
+			continue;
+		if (bfee->mac_id == macid)
+			return bfee->cap;
+	}
+
+	return BEAMFORMING_CAP_NONE;
+}
+
+static void _beamforming_enter(PADAPTER adapter, void *p)
+{
+	struct mlme_priv *mlme;
+	struct ht_priv *htpriv;
+#ifdef CONFIG_80211AC_VHT
+	struct vht_priv *vhtpriv;
+#endif
+	struct mlme_ext_priv *mlme_ext;
+	struct sta_info *sta, *sta_copy;
+	struct beamforming_info *info;
+	struct beamformer_entry *bfer = NULL;
+	struct beamformee_entry *bfee = NULL;
+	u8 wireless_mode;
+	u8 sta_bf_cap;
+	u8 sounding_dim = 0; /* number of sounding dimensions */
+	u8 comp_steering_num = 0; /* compressed steering number */
+
+
+	mlme = &adapter->mlmepriv;
+	htpriv = &mlme->htpriv;
+#ifdef CONFIG_80211AC_VHT
+	vhtpriv = &mlme->vhtpriv;
+#endif
+	mlme_ext = &adapter->mlmeextpriv;
+	info = GET_BEAMFORM_INFO(adapter);
+
+	sta_copy = (struct sta_info *)p;
+	sta = rtw_get_stainfo(&adapter->stapriv, sta_copy->cmn.mac_addr);
+	if (!sta) {
+		RTW_ERR("%s: Cann't find STA info for " MAC_FMT "\n",
+			__FUNCTION__, MAC_ARG(sta_copy->cmn.mac_addr));
+		return;
+	}
+	if (sta != sta_copy) {
+		RTW_WARN("%s: Origin sta(fake)=%p realsta=%p for " MAC_FMT "\n",
+		__FUNCTION__, sta_copy, sta, MAC_ARG(sta_copy->cmn.mac_addr));
+	}
+
+	/* The current setting does not support Beaforming */
+	wireless_mode = sta->wireless_mode;
+	if ((is_supported_ht(wireless_mode) == _FALSE)
+	    && (is_supported_vht(wireless_mode) == _FALSE)) {
+		RTW_WARN("%s: Not support HT or VHT mode\n", __FUNCTION__);
+		return;
+	}
+
+	if ((0 == htpriv->beamform_cap)
+#ifdef CONFIG_80211AC_VHT
+	    && (0 == vhtpriv->beamform_cap)
+#endif
+	   ) {
+		RTW_INFO("The configuration disabled Beamforming! Skip...\n");
+		return;
+	}
+
+	_get_sta_beamform_cap(adapter, sta,
+			      &sta_bf_cap, &sounding_dim, &comp_steering_num);
+	RTW_INFO("STA Beamforming Capability=0x%02X\n", sta_bf_cap);
+	if (sta_bf_cap == BEAMFORMING_CAP_NONE)
+		return;
+	if ((sta_bf_cap & BEAMFORMEE_CAP_HT_EXPLICIT)
+	    || (sta_bf_cap & BEAMFORMEE_CAP_VHT_SU)
+	    || (sta_bf_cap & BEAMFORMEE_CAP_VHT_MU))
+		sta_bf_cap |= BEAMFORMEE_CAP;
+	if ((sta_bf_cap & BEAMFORMER_CAP_HT_EXPLICIT)
+	    || (sta_bf_cap & BEAMFORMER_CAP_VHT_SU)
+	    || (sta_bf_cap & BEAMFORMER_CAP_VHT_MU))
+		sta_bf_cap |= BEAMFORMER_CAP;
+
+	if (sta_bf_cap & BEAMFORMER_CAP) {
+		/* The other side is beamformer */
+		bfer = _bfer_add_entry(adapter, sta, sta_bf_cap, sounding_dim, comp_steering_num);
+		if (!bfer)
+			RTW_ERR("%s: Fail to allocate bfer entry!\n", __FUNCTION__);
+	}
+	if (sta_bf_cap & BEAMFORMEE_CAP) {
+		/* The other side is beamformee */
+		bfee = _bfee_add_entry(adapter, sta, sta_bf_cap, sounding_dim, comp_steering_num);
+		if (!bfee)
+			RTW_ERR("%s: Fail to allocate bfee entry!\n", __FUNCTION__);
+	}
+	if (!bfer && !bfee)
+		return;
+
+	rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_ENTER, (u8*)sta);
+
+	/* Perform sounding if there is BFee */
+	if ((info->beamformee_su_cnt != 0)
+	    || (info->beamformee_mu_cnt != 0)) {
+		if (SOUNDING_STATE_NONE == info->sounding_info.state) {
+			info->sounding_info.state = SOUNDING_STATE_INIT;
+			/* Start sounding after 2 sec */
+			_set_timer(&info->sounding_timer, 2000);
+		}
+	}
+}
+
+static void _beamforming_reset(PADAPTER adapter)
+{
+	RTW_ERR("%s: Not ready!!\n", __FUNCTION__);
+}
+
+static void _beamforming_leave(PADAPTER adapter, u8 *ra)
+{
+	struct beamforming_info *info;
+	struct beamformer_entry *bfer = NULL;
+	struct beamformee_entry *bfee = NULL;
+	u8 bHwStateAddInit = _FALSE;
+
+
+	RTW_INFO("+%s\n", __FUNCTION__);
+
+	info = GET_BEAMFORM_INFO(adapter);
+	bfer = _bfer_get_entry_by_addr(adapter, ra);
+	bfee = _bfee_get_entry_by_addr(adapter, ra);
+
+	if (!bfer && !bfee) {
+		RTW_WARN("%s: " MAC_FMT " is neither beamforming ee or er!!\n",
+			__FUNCTION__, MAC_ARG(ra));
+		return;
+	}
+
+	if (bfer)
+		_bfer_remove_entry(adapter, bfer);
+
+	if (bfee)
+		_bfee_remove_entry(adapter, bfee);
+
+	rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, ra);
+
+	/* Stop sounding if there is no any BFee */
+	if ((info->beamformee_su_cnt == 0)
+	    && (info->beamformee_mu_cnt == 0)) {
+		_cancel_timer_ex(&info->sounding_timer);
+		_sounding_init(&info->sounding_info);
+	}
+
+	RTW_INFO("-%s\n", __FUNCTION__);
+}
+
+static void _beamforming_sounding_down(PADAPTER adapter, u8 status)
+{
+	struct beamforming_info	*info;
+	struct sounding_info *sounding;
+	struct beamformee_entry *bfee;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+	sounding = &info->sounding_info;
+
+	RTW_INFO("+%s: sounding=%d, status=0x%02x\n", __FUNCTION__, sounding->state, status);
+
+	if (sounding->state == SOUNDING_STATE_MU_START) {
+		RTW_INFO("%s: MU sounding done\n", __FUNCTION__);
+		sounding->state = SOUNDING_STATE_MU_SOUNDDOWN;
+		RTW_INFO("%s: Set to SOUNDING_STATE_MU_SOUNDDOWN\n", __FUNCTION__);
+		info->SetHalSoundownOnDemandCnt++;
+		rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status);
+	} else if (sounding->state == SOUNDING_STATE_SU_START) {
+		RTW_INFO("%s: SU entry[%d] sounding down\n", __FUNCTION__, sounding->su_bfee_curidx);
+		bfee = &info->bfee_entry[sounding->su_bfee_curidx];
+		sounding->state = SOUNDING_STATE_SU_SOUNDDOWN;
+		RTW_INFO("%s: Set to SOUNDING_STATE_SU_SOUNDDOWN\n", __FUNCTION__);
+
+		/*
+		 * <tynli_note>
+		 *	bfee->bSoundingTimeout this flag still cannot avoid
+		 *	old sound down event happens in the new sounding period.
+		 *	2015.12.10
+		 */
+		if (_TRUE == bfee->bSoundingTimeout) {
+			RTW_WARN("%s: The entry[%d] is bSoundingTimeout!\n", __FUNCTION__, sounding->su_bfee_curidx);
+			bfee->bSoundingTimeout = _FALSE;
+			return;
+		}
+
+		if (_TRUE == status) {
+			/* success */
+			bfee->LogStatusFailCnt = 0;
+			info->SetHalSoundownOnDemandCnt++;
+			rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status);
+		} else if (_TRUE == bfee->bDeleteSounding) {
+			RTW_WARN("%s: Delete entry[%d] sounding info!\n", __FUNCTION__, sounding->su_bfee_curidx);
+			rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status);
+			bfee->bDeleteSounding = _FALSE;
+		} else {
+			bfee->LogStatusFailCnt++;
+			RTW_WARN("%s: LogStatusFailCnt=%d\n", __FUNCTION__, bfee->LogStatusFailCnt);
+			if (bfee->LogStatusFailCnt > 30) {
+				RTW_ERR("%s: LogStatusFailCnt > 30, Stop SOUNDING!!\n", __FUNCTION__);
+				rtw_bf_cmd(adapter, BEAMFORMING_CTRL_LEAVE, bfee->mac_addr, ETH_ALEN, 1);
+			}
+		}
+	} else {
+		RTW_WARN("%s: unexpected sounding state:0x%02x\n", __FUNCTION__, sounding->state);
+		return;
+	}
+
+	rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 0);
+}
+
+static void _c2h_snd_txbf(PADAPTER adapter, u8 *buf, u8 buf_len)
+{
+	struct beamforming_info	*info;
+	u8 res;
+
+	info = GET_BEAMFORM_INFO(adapter);
+
+	_cancel_timer_ex(&info->sounding_timeout_timer);
+
+	res = C2H_SND_TXBF_GET_SND_RESULT(buf) ? _TRUE : _FALSE;
+	RTW_INFO("+%s: %s\n", __FUNCTION__, res==_TRUE?"Success":"Fail!");
+
+	rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 1);
+}
+
+/*
+ * Description:
+ *	This function is for phydm only
+ */
+enum beamforming_cap rtw_bf_bfee_get_entry_cap_by_macid(void *mlme, u8 macid)
+{
+	PADAPTER adapter;
+	enum beamforming_cap cap = BEAMFORMING_CAP_NONE;
+
+
+	adapter = mlme_to_adapter((struct mlme_priv *)mlme);
+	cap = _bfee_get_entry_cap_by_macid(adapter, macid);
+
+	return cap;
+}
+
+struct beamformer_entry *rtw_bf_bfer_get_entry_by_addr(PADAPTER adapter, u8 *ra)
+{
+	return _bfer_get_entry_by_addr(adapter, ra);
+}
+
+struct beamformee_entry *rtw_bf_bfee_get_entry_by_addr(PADAPTER adapter, u8 *ra)
+{
+	return _bfee_get_entry_by_addr(adapter, ra);
+}
+
+void rtw_bf_get_ndpa_packet(PADAPTER adapter, union recv_frame *precv_frame)
+{
+	RTW_DBG("+%s\n", __FUNCTION__);
+}
+
+u32 rtw_bf_get_report_packet(PADAPTER adapter, union recv_frame *precv_frame)
+{
+	u32 ret = _SUCCESS;
+	struct beamforming_info *info;
+	struct beamformee_entry *bfee = NULL;
+	u8 *pframe;
+	u32 frame_len;
+	u8 *ta;
+	u8 *frame_body;
+	u8 category, action;
+	u8 *pMIMOCtrlField, *pCSIMatrix;
+	u8 Nc = 0, Nr = 0, CH_W = 0, Ng = 0, CodeBook = 0;
+	u16 CSIMatrixLen = 0;
+
+
+	RTW_INFO("+%s\n", __FUNCTION__);
+
+	info = GET_BEAMFORM_INFO(adapter);
+	pframe = precv_frame->u.hdr.rx_data;
+	frame_len = precv_frame->u.hdr.len;
+
+	/* Memory comparison to see if CSI report is the same with previous one */
+	ta = get_addr2_ptr(pframe);
+	bfee = _bfee_get_entry_by_addr(adapter, ta);
+	if (!bfee)
+		return _FAIL;
+
+	frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+	category = frame_body[0];
+	action = frame_body[1];
+
+	if ((category == RTW_WLAN_CATEGORY_VHT)
+	    && (action == RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING)) {
+		pMIMOCtrlField = pframe + 26;
+		Nc = (*pMIMOCtrlField) & 0x7;
+		Nr = ((*pMIMOCtrlField) & 0x38) >> 3;
+		CH_W =  (((*pMIMOCtrlField) & 0xC0) >> 6);
+		Ng = (*(pMIMOCtrlField+1)) & 0x3;
+		CodeBook = ((*(pMIMOCtrlField+1)) & 0x4) >> 2;
+		/*
+		 * 24+(1+1+3)+2
+		 * ==> MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)
+		 */
+		pCSIMatrix = pMIMOCtrlField + 3 + Nc;
+		CSIMatrixLen = frame_len - 26 - 3 - Nc;
+		info->TargetCSIInfo.bVHT = _TRUE;
+	} else if ((category == RTW_WLAN_CATEGORY_HT)
+		   && (action == RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING)) {
+		pMIMOCtrlField = pframe + 26;
+		Nc = (*pMIMOCtrlField) & 0x3;
+		Nr = ((*pMIMOCtrlField) & 0xC) >> 2;
+		CH_W = ((*pMIMOCtrlField) & 0x10) >> 4;
+		Ng = ((*pMIMOCtrlField) & 0x60) >> 5;
+		CodeBook = ((*(pMIMOCtrlField+1)) & 0x6) >> 1;
+		/*
+		 * 24+(1+1+6)+2
+		 * ==> MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)
+		 */
+		pCSIMatrix = pMIMOCtrlField + 6 + Nr;
+		CSIMatrixLen = frame_len  - 26 - 6 - Nr;
+		info->TargetCSIInfo.bVHT = _FALSE;
+	}
+
+	/* Update current CSI report info */
+	if ((_TRUE == info->bEnableSUTxBFWorkAround)
+	    && (info->TargetSUBFee == bfee)) {
+		if ((info->TargetCSIInfo.Nc != Nc) || (info->TargetCSIInfo.Nr != Nr) ||
+			(info->TargetCSIInfo.ChnlWidth != CH_W) || (info->TargetCSIInfo.Ng != Ng) ||
+			(info->TargetCSIInfo.CodeBook != CodeBook)) {
+			info->TargetCSIInfo.Nc = Nc;
+			info->TargetCSIInfo.Nr = Nr;
+			info->TargetCSIInfo.ChnlWidth = CH_W;
+			info->TargetCSIInfo.Ng = Ng;
+			info->TargetCSIInfo.CodeBook = CodeBook;
+
+			rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 1);
+		}
+	}
+
+	RTW_INFO("%s: pkt type=%d-%d, Nc=%d, Nr=%d, CH_W=%d, Ng=%d, CodeBook=%d\n",
+		 __FUNCTION__, category, action, Nc, Nr, CH_W, Ng, CodeBook);
+
+	return ret;
+}
+
+u8 rtw_bf_send_vht_gid_mgnt_packet(PADAPTER adapter, u8 *ra, u8 *gid, u8 *position)
+{
+	/* General */
+	struct xmit_priv *xmitpriv;
+	struct mlme_priv *mlmepriv;
+	struct xmit_frame *pmgntframe;
+	/* MISC */
+	struct pkt_attrib *attrib;
+	struct rtw_ieee80211_hdr *wlanhdr;
+	u8 *pframe, *ptr;
+
+
+	xmitpriv = &adapter->xmitpriv;
+	mlmepriv = &adapter->mlmepriv;
+
+	pmgntframe = alloc_mgtxmitframe(xmitpriv);
+	if (!pmgntframe)
+		return _FALSE;
+
+	/* update attribute */
+	attrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(adapter, attrib);
+	attrib->rate = MGN_6M;
+	attrib->bwmode = CHANNEL_WIDTH_20;
+	attrib->subtype = WIFI_ACTION;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)pmgntframe->buf_addr + TXDESC_OFFSET;
+	wlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	wlanhdr->frame_ctl = 0;
+	set_frame_sub_type(pframe, attrib->subtype);
+	set_duration(pframe, 0);
+	SetFragNum(pframe, 0);
+	SetSeqNum(pframe, 0);
+
+	_rtw_memcpy(wlanhdr->addr1, ra, ETH_ALEN);
+	_rtw_memcpy(wlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
+	_rtw_memcpy(wlanhdr->addr3, get_bssid(mlmepriv), ETH_ALEN);
+
+	pframe[24] = RTW_WLAN_CATEGORY_VHT;
+	pframe[25] = RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT;
+	/* Set Membership Status Array */
+	ptr = pframe + 26;
+	_rtw_memcpy(ptr, gid, 8);
+	/* Set User Position Array */
+	ptr = pframe + 34;
+	_rtw_memcpy(ptr, position, 16);
+
+	attrib->pktlen = 54;
+	attrib->last_txcmdsz = attrib->pktlen;
+
+	dump_mgntframe(adapter, pmgntframe);
+
+	return _TRUE;
+}
+
+/*
+ * Description:
+ *	On VHT GID management frame by an MU beamformee.
+ */
+void rtw_bf_get_vht_gid_mgnt_packet(PADAPTER adapter, union recv_frame *precv_frame)
+{
+	u8 *pframe;
+	u8 *ta, *gid, *position;
+
+
+	RTW_DBG("+%s\n", __FUNCTION__);
+
+	pframe = precv_frame->u.hdr.rx_data;
+
+	/* Get address by Addr2 */
+	ta = get_addr2_ptr(pframe);
+	/* Remove signaling TA */
+	ta[0] &= 0xFE;
+
+	/* Membership Status Array */
+	gid = pframe + 26;
+	/* User Position Array */
+	position= pframe + 34;
+
+	_bfer_set_entry_gid(adapter, ta, gid, position);
+}
+
+void rtw_bf_init(PADAPTER adapter)
+{
+	struct beamforming_info	*info;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+	info->beamforming_cap = BEAMFORMING_CAP_NONE;
+	info->beamforming_state = BEAMFORMING_STATE_IDLE;
+/*
+	info->bfee_entry[MAX_BEAMFORMEE_ENTRY_NUM];
+	info->bfer_entry[MAX_BEAMFORMER_ENTRY_NUM];
+*/
+	info->sounding_sequence = 0;
+	info->beamformee_su_cnt = 0;
+	info->beamformer_su_cnt = 0;
+	info->beamformee_su_reg_maping = 0;
+	info->beamformer_su_reg_maping = 0;
+	info->beamformee_mu_cnt = 0;
+	info->beamformer_mu_cnt = 0;
+	info->beamformee_mu_reg_maping = 0;
+	info->first_mu_bfee_index = 0xFF;
+	info->mu_bfer_curidx = 0xFF;
+	info->cur_csi_rpt_rate = HALMAC_OFDM24;
+
+	_sounding_init(&info->sounding_info);
+	rtw_init_timer(&info->sounding_timer, adapter, _sounding_timer_handler, adapter);
+	rtw_init_timer(&info->sounding_timeout_timer, adapter, _sounding_timeout_timer_handler, adapter);
+
+	info->SetHalBFEnterOnDemandCnt = 0;
+	info->SetHalBFLeaveOnDemandCnt = 0;
+	info->SetHalSoundownOnDemandCnt = 0;
+
+	info->bEnableSUTxBFWorkAround = _TRUE;
+	info->TargetSUBFee = NULL;
+
+	info->sounding_running = 0;
+}
+
+void rtw_bf_cmd_hdl(PADAPTER adapter, u8 type, u8 *pbuf)
+{
+	switch (type) {
+	case BEAMFORMING_CTRL_ENTER:
+		_beamforming_enter(adapter, pbuf);
+		break;
+
+	case BEAMFORMING_CTRL_LEAVE:
+		if (pbuf == NULL)
+			_beamforming_reset(adapter);
+		else
+			_beamforming_leave(adapter, pbuf);
+		break;
+
+	case BEAMFORMING_CTRL_START_PERIOD:
+		_sounding_handler(adapter);
+		break;
+
+	case BEAMFORMING_CTRL_END_PERIOD:
+		_beamforming_sounding_down(adapter, *pbuf);
+		break;
+
+	case BEAMFORMING_CTRL_SET_GID_TABLE:
+		rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_SET_GID_TABLE, pbuf);
+		break;
+
+	case BEAMFORMING_CTRL_SET_CSI_REPORT:
+		rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_CSI_REPORT, pbuf);
+		break;
+
+	default:
+		break;
+	}
+}
+
+u8 rtw_bf_cmd(PADAPTER adapter, s32 type, u8 *pbuf, s32 size, u8 enqueue)
+{
+	struct cmd_obj *ph2c;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &adapter->cmdpriv;
+	u8 *wk_buf;
+	u8 res = _SUCCESS;
+
+
+	if (!enqueue) {
+		rtw_bf_cmd_hdl(adapter, type, pbuf);
+		goto exit;
+	}
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	if (pbuf != NULL) {
+		wk_buf = rtw_zmalloc(size);
+		if (wk_buf == NULL) {
+			rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));
+			rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));
+			res = _FAIL;
+			goto exit;
+		}
+
+		_rtw_memcpy(wk_buf, pbuf, size);
+	} else {
+		wk_buf = NULL;
+		size = 0;
+	}
+
+	pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID;
+	pdrvextra_cmd_parm->type = type;
+	pdrvextra_cmd_parm->size = size;
+	pdrvextra_cmd_parm->pbuf = wk_buf;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+	return res;
+}
+
+void rtw_bf_update_attrib(PADAPTER adapter, struct pkt_attrib *attrib, struct sta_info *sta)
+{
+	if (sta) {
+		attrib->txbf_g_id = sta->cmn.bf_info.g_id;
+		attrib->txbf_p_aid = sta->cmn.bf_info.p_aid;
+	}
+}
+
+void rtw_bf_c2h_handler(PADAPTER adapter, u8 id, u8 *buf, u8 buf_len)
+{
+	switch (id) {
+	case CMD_ID_C2H_SND_TXBF:
+		_c2h_snd_txbf(adapter, buf, buf_len);
+		break;
+	}
+}
+
+#define toMbps(bytes, secs)	(rtw_division64(bytes >> 17, secs))
+void rtw_bf_update_traffic(PADAPTER adapter)
+{
+	struct beamforming_info	*info;
+	struct sounding_info *sounding;
+	struct beamformee_entry *bfee;
+	struct sta_info *sta;
+	u8 bfee_cnt, sounding_idx, i;
+	u16 tp[MAX_BEAMFORMEE_ENTRY_NUM] = {0};
+	u8 tx_rate[MAX_BEAMFORMEE_ENTRY_NUM] = {0};
+	u64 tx_bytes, last_bytes;
+	u32 time;
+	systime last_timestamp;
+	u8 set_timer = _FALSE;
+
+
+	info = GET_BEAMFORM_INFO(adapter);
+	sounding = &info->sounding_info;
+
+	/* Check any bfee exist? */
+	bfee_cnt = info->beamformee_su_cnt + info->beamformee_mu_cnt;
+	if (bfee_cnt == 0)
+		return;
+
+	for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
+		bfee = &info->bfee_entry[i];
+		if (_FALSE == bfee->used)
+			continue;
+
+		sta = rtw_get_stainfo(&adapter->stapriv, bfee->mac_addr);
+		if (!sta) {
+			RTW_ERR("%s: Cann't find sta_info for " MAC_FMT "!\n", __FUNCTION__, MAC_ARG(bfee->mac_addr));
+			continue;
+		}
+
+		last_timestamp = bfee->tx_timestamp;
+		last_bytes = bfee->tx_bytes;
+		bfee->tx_timestamp = rtw_get_current_time();
+		bfee->tx_bytes = sta->sta_stats.tx_bytes;
+		if (last_timestamp) {
+			if (bfee->tx_bytes >= last_bytes)
+				tx_bytes = bfee->tx_bytes - last_bytes;
+			else
+				tx_bytes = bfee->tx_bytes + (~last_bytes);
+			time = rtw_get_time_interval_ms(last_timestamp, bfee->tx_timestamp);
+			time = (time > 1000) ? time/1000 : 1;
+			tp[i] = toMbps(tx_bytes, time);
+			tx_rate[i] = rtw_get_current_tx_rate(adapter, sta);
+			RTW_INFO("%s: BFee idx(%d), MadId(%d), TxTP=%lld bytes (%d Mbps), txrate=%d\n",
+				 __FUNCTION__, i, bfee->mac_id, tx_bytes, tp[i], tx_rate[i]);
+		}
+	}
+
+	sounding_idx = phydm_get_beamforming_sounding_info(GET_PDM_ODM(adapter), tp, MAX_BEAMFORMEE_ENTRY_NUM, tx_rate);
+
+	for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
+		bfee = &info->bfee_entry[i];
+		if (_FALSE == bfee->used) {
+			if (sounding_idx & BIT(i))
+				RTW_WARN("%s: bfee(%d) not in used but need sounding?!\n", __FUNCTION__, i);
+			continue;
+		}
+
+		if (sounding_idx & BIT(i)) {
+			if (_FALSE == bfee->bApplySounding) {
+				bfee->bApplySounding = _TRUE;
+				bfee->SoundCnt = 0;
+				set_timer = _TRUE;
+			}
+		} else {
+			if (_TRUE == bfee->bApplySounding) {
+				bfee->bApplySounding = _FALSE;
+				bfee->bDeleteSounding = _TRUE;
+				bfee->SoundCnt = 0;
+				set_timer = _TRUE;
+			}
+		}
+	}
+
+	if (_TRUE == set_timer) {
+		if (SOUNDING_STATE_NONE == info->sounding_info.state) {
+			info->sounding_info.state = SOUNDING_STATE_INIT;
+			_set_timer(&info->sounding_timer, 0);
+		}
+	}
+}
+
+#else /* !RTW_BEAMFORMING_VERSION_2 */
+
+#if (BEAMFORMING_SUPPORT == 0) /*for diver defined beamforming*/
+struct beamforming_entry	*beamforming_get_entry_by_addr(struct mlme_priv *pmlmepriv, u8 *ra, u8 *idx)
+{
+	u8	i = 0;
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+
+	for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) {
+		if (pBeamInfo->beamforming_entry[i].bUsed &&
+		    (_rtw_memcmp(ra, pBeamInfo->beamforming_entry[i].mac_addr, ETH_ALEN))) {
+			*idx = i;
+			return &(pBeamInfo->beamforming_entry[i]);
+		}
+	}
+
+	return NULL;
+}
+
+BEAMFORMING_CAP beamforming_get_entry_beam_cap_by_mac_id(PVOID pmlmepriv , u8 mac_id)
+{
+	u8	i = 0;
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO((struct mlme_priv *)pmlmepriv);
+	BEAMFORMING_CAP		BeamformEntryCap = BEAMFORMING_CAP_NONE;
+
+	for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) {
+		if (pBeamInfo->beamforming_entry[i].bUsed &&
+		    (mac_id == pBeamInfo->beamforming_entry[i].mac_id)) {
+			BeamformEntryCap =  pBeamInfo->beamforming_entry[i].beamforming_entry_cap;
+			i = BEAMFORMING_ENTRY_NUM;
+		}
+	}
+
+	return BeamformEntryCap;
+}
+
+struct beamforming_entry	*beamforming_get_free_entry(struct mlme_priv *pmlmepriv, u8 *idx)
+{
+	u8	i = 0;
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+
+	for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) {
+		if (pBeamInfo->beamforming_entry[i].bUsed == _FALSE) {
+			*idx = i;
+			return &(pBeamInfo->beamforming_entry[i]);
+		}
+	}
+	return NULL;
+}
+
+
+struct beamforming_entry	*beamforming_add_entry(PADAPTER adapter, u8 *ra, u16 aid,
+	u16 mac_id, enum channel_width bw, BEAMFORMING_CAP beamfrom_cap, u8 *idx)
+{
+	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
+	struct beamforming_entry	*pEntry = beamforming_get_free_entry(pmlmepriv, idx);
+
+	if (pEntry != NULL) {
+		pEntry->bUsed = _TRUE;
+		pEntry->aid = aid;
+		pEntry->mac_id = mac_id;
+		pEntry->sound_bw = bw;
+		if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+			u16	BSSID = ((*(adapter_mac_addr(adapter) + 5) & 0xf0) >> 4) ^
+				(*(adapter_mac_addr(adapter) + 5) & 0xf); /* BSSID[44:47] xor BSSID[40:43] */
+			pEntry->p_aid = (aid + BSSID * 32) & 0x1ff;		/* (dec(A) + dec(B)*32) mod 512 */
+			pEntry->g_id = 63;
+		} else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
+			pEntry->p_aid = 0;
+			pEntry->g_id = 63;
+		} else {
+			pEntry->p_aid =  ra[5];						/* BSSID[39:47] */
+			pEntry->p_aid = (pEntry->p_aid << 1) | (ra[4] >> 7);
+			pEntry->g_id = 0;
+		}
+		_rtw_memcpy(pEntry->mac_addr, ra, ETH_ALEN);
+		pEntry->bSound = _FALSE;
+
+		/* 3 TODO SW/FW sound period */
+		pEntry->sound_period = 200;
+		pEntry->beamforming_entry_cap = beamfrom_cap;
+		pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
+
+
+		pEntry->PreLogSeq = 0;	/*Modified by Jeffery @2015-04-13*/
+		pEntry->LogSeq = 0;		/*Modified by Jeffery @2014-10-29*/
+		pEntry->LogRetryCnt = 0;	/*Modified by Jeffery @2014-10-29*/
+		pEntry->LogSuccess = 0;	/*LogSuccess is NOT needed to be accumulated, so  LogSuccessCnt->LogSuccess, 2015-04-13, Jeffery*/
+		pEntry->ClockResetTimes = 0;	/*Modified by Jeffery @2015-04-13*/
+		pEntry->LogStatusFailCnt = 0;
+
+		return pEntry;
+	} else
+		return NULL;
+}
+
+BOOLEAN	beamforming_remove_entry(struct mlme_priv *pmlmepriv, u8 *ra, u8 *idx)
+{
+	struct beamforming_entry	*pEntry = beamforming_get_entry_by_addr(pmlmepriv, ra, idx);
+
+	if (pEntry != NULL) {
+		pEntry->bUsed = _FALSE;
+		pEntry->beamforming_entry_cap = BEAMFORMING_CAP_NONE;
+		pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
+		return _TRUE;
+	} else
+		return _FALSE;
+}
+
+/* Used for BeamformingStart_V1 */
+void	beamforming_dym_ndpa_rate(PADAPTER adapter)
+{
+	u16	NDPARate = MGN_6M;
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(adapter);
+	s8 min_rssi = 0;
+
+	min_rssi = rtw_phydm_get_min_rssi(adapter);
+	if (min_rssi > 30) /* link RSSI > 30% */
+		NDPARate = MGN_24M;
+	else
+		NDPARate = MGN_6M;
+
+	/* BW = CHANNEL_WIDTH_20; */
+	NDPARate = NDPARate << 8;
+	rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_RATE, (u8 *)&NDPARate);
+}
+
+void beamforming_dym_period(PADAPTER Adapter)
+{
+	u8	Idx;
+	BOOLEAN	bChangePeriod = _FALSE;
+	u16	SoundPeriod_SW, SoundPeriod_FW;
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(Adapter);
+	struct dvobj_priv	*pdvobjpriv = adapter_to_dvobj(Adapter);
+	struct beamforming_entry	*pBeamformEntry;
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO((&Adapter->mlmepriv));
+	struct sounding_info		*pSoundInfo = &(pBeamInfo->sounding_info);
+
+	/* 3 TODO  per-client throughput caculation. */
+
+	if (pdvobjpriv->traffic_stat.cur_tx_tp + pdvobjpriv->traffic_stat.cur_rx_tp > 2) {
+		SoundPeriod_SW = 32 * 20;
+		SoundPeriod_FW = 2;
+	} else {
+		SoundPeriod_SW = 32 * 2000;
+		SoundPeriod_FW = 200;
+	}
+
+	for (Idx = 0; Idx < BEAMFORMING_ENTRY_NUM; Idx++) {
+		pBeamformEntry = pBeamInfo->beamforming_entry + Idx;
+		if (pBeamformEntry->bDefaultCSI) {
+			SoundPeriod_SW = 32 * 2000;
+			SoundPeriod_FW = 200;
+		}
+
+		if (pBeamformEntry->beamforming_entry_cap & (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP_VHT_SU)) {
+			if (pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER) {
+				if (pBeamformEntry->sound_period != SoundPeriod_FW) {
+					pBeamformEntry->sound_period = SoundPeriod_FW;
+					bChangePeriod = _TRUE;	/* Only FW sounding need to send H2C packet to change sound period. */
+				}
+			} else if (pBeamformEntry->sound_period != SoundPeriod_SW)
+				pBeamformEntry->sound_period = SoundPeriod_SW;
+		}
+	}
+
+	if (bChangePeriod)
+		rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&Idx);
+}
+
+BOOLEAN	issue_ht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, enum channel_width bw, u8 qidx)
+{
+	struct xmit_frame		*pmgntframe;
+	struct pkt_attrib		*pattrib;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	struct xmit_priv		*pxmitpriv = &(Adapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8	ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c};
+	u8	*pframe;
+	u16	*fctrl;
+	u16	duration = 0;
+	u8	aSifsTime = 0;
+	u8	NDPTxRate = 0;
+
+	RTW_INFO("%s: issue_ht_sw_ndpa_packet!\n", __func__);
+
+	NDPTxRate = MGN_MCS8;
+	RTW_INFO("%s: NDPTxRate =%d\n", __func__, NDPTxRate);
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+
+	if (pmgntframe == NULL)
+		return _FALSE;
+
+	/*update attribute*/
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(Adapter, pattrib);
+	pattrib->qsel = QSLT_MGNT;
+	pattrib->rate = NDPTxRate;
+	pattrib->bwmode = bw;
+	pattrib->order = 1;
+	pattrib->subtype = WIFI_ACTION_NOACK;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &pwlanhdr->frame_ctl;
+	*(fctrl) = 0;
+
+	set_order_bit(pframe);
+	set_frame_sub_type(pframe, WIFI_ACTION_NOACK);
+
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
+		aSifsTime = 10;
+	else
+		aSifsTime = 16;
+
+	duration = 2 * aSifsTime + 40;
+
+	if (bw == CHANNEL_WIDTH_40)
+		duration += 87;
+	else
+		duration += 180;
+
+	set_duration(pframe, duration);
+
+	/*HT control field*/
+	SET_HT_CTRL_CSI_STEERING(pframe + 24, 3);
+	SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1);
+
+	_rtw_memcpy(pframe + 28, ActionHdr, 4);
+
+	pattrib->pktlen = 32;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(Adapter, pmgntframe);
+
+	return _TRUE;
+
+
+}
+BOOLEAN	issue_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, enum channel_width bw, u8 qidx)
+{
+	struct xmit_frame		*pmgntframe;
+	struct pkt_attrib		*pattrib;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	struct xmit_priv		*pxmitpriv = &(Adapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8	ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c};
+	u8	*pframe;
+	u16	*fctrl;
+	u16	duration = 0;
+	u8	aSifsTime = 0;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+
+	if (pmgntframe == NULL)
+		return _FALSE;
+
+	/*update attribute*/
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(Adapter, pattrib);
+
+	if (qidx == BCN_QUEUE_INX)
+		pattrib->qsel = QSLT_BEACON;
+	pattrib->rate = MGN_MCS8;
+	pattrib->bwmode = bw;
+	pattrib->order = 1;
+	pattrib->subtype = WIFI_ACTION_NOACK;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &pwlanhdr->frame_ctl;
+	*(fctrl) = 0;
+
+	set_order_bit(pframe);
+	set_frame_sub_type(pframe, WIFI_ACTION_NOACK);
+
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
+		aSifsTime = 10;
+	else
+		aSifsTime = 16;
+
+	duration = 2 * aSifsTime + 40;
+
+	if (bw == CHANNEL_WIDTH_40)
+		duration += 87;
+	else
+		duration += 180;
+
+	set_duration(pframe, duration);
+
+	/* HT control field */
+	SET_HT_CTRL_CSI_STEERING(pframe + 24, 3);
+	SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1);
+
+	_rtw_memcpy(pframe + 28, ActionHdr, 4);
+
+	pattrib->pktlen = 32;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(Adapter, pmgntframe);
+
+	return _TRUE;
+}
+
+BOOLEAN	beamforming_send_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, enum channel_width bw, u8 qidx)
+{
+	return issue_ht_ndpa_packet(Adapter, ra, bw, qidx);
+}
+BOOLEAN	issue_vht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, enum channel_width bw, u8 qidx)
+{
+	struct xmit_frame		*pmgntframe;
+	struct pkt_attrib		*pattrib;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	struct xmit_priv		*pxmitpriv = &(Adapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct mlme_priv		*pmlmepriv = &(Adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct rtw_ndpa_sta_info	sta_info;
+	u8		 NDPTxRate = 0;
+
+	u8	*pframe;
+	u16	*fctrl;
+	u16	duration = 0;
+	u8	sequence = 0, aSifsTime = 0;
+
+	RTW_INFO("%s: issue_vht_sw_ndpa_packet!\n", __func__);
+
+
+	NDPTxRate = MGN_VHT2SS_MCS0;
+	RTW_INFO("%s: NDPTxRate =%d\n", __func__, NDPTxRate);
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+
+	if (pmgntframe == NULL) {
+		RTW_INFO("%s, alloc mgnt frame fail\n", __func__);
+		return _FALSE;
+	}
+
+	/*update attribute*/
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(Adapter, pattrib);
+	pattrib->qsel = QSLT_MGNT;
+	pattrib->rate = NDPTxRate;
+	pattrib->bwmode = bw;
+	pattrib->subtype = WIFI_NDPA;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &pwlanhdr->frame_ctl;
+	*(fctrl) = 0;
+
+	set_frame_sub_type(pframe, WIFI_NDPA);
+
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN);
+
+	if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode))
+		aSifsTime = 16;
+	else
+		aSifsTime = 10;
+
+	duration = 2 * aSifsTime + 44;
+
+	if (bw == CHANNEL_WIDTH_80)
+		duration += 40;
+	else if (bw == CHANNEL_WIDTH_40)
+		duration += 87;
+	else
+		duration += 180;
+
+	set_duration(pframe, duration);
+
+	sequence = pBeamInfo->sounding_sequence << 2;
+	if (pBeamInfo->sounding_sequence >= 0x3f)
+		pBeamInfo->sounding_sequence = 0;
+	else
+		pBeamInfo->sounding_sequence++;
+
+	_rtw_memcpy(pframe + 16, &sequence, 1);
+	if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE))
+		aid = 0;
+
+	sta_info.aid = aid;
+	sta_info.feedback_type = 0;
+	sta_info.nc_index = 0;
+
+	_rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2);
+
+	pattrib->pktlen = 19;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(Adapter, pmgntframe);
+
+
+	return _TRUE;
+
+}
+BOOLEAN	issue_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, enum channel_width bw, u8 qidx)
+{
+	struct xmit_frame		*pmgntframe;
+	struct pkt_attrib		*pattrib;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	struct xmit_priv		*pxmitpriv = &(Adapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct mlme_priv		*pmlmepriv = &(Adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct rtw_ndpa_sta_info	sta_info;
+	u8	*pframe;
+	u16	*fctrl;
+	u16	duration = 0;
+	u8	sequence = 0, aSifsTime = 0;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return _FALSE;
+
+	/*update attribute*/
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(Adapter, pattrib);
+
+	if (qidx == BCN_QUEUE_INX)
+		pattrib->qsel = QSLT_BEACON;
+	pattrib->rate = MGN_VHT2SS_MCS0;
+	pattrib->bwmode = bw;
+	pattrib->subtype = WIFI_NDPA;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &pwlanhdr->frame_ctl;
+	*(fctrl) = 0;
+
+	set_frame_sub_type(pframe, WIFI_NDPA);
+
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN);
+
+	if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode))
+		aSifsTime = 16;
+	else
+		aSifsTime = 10;
+
+	duration = 2 * aSifsTime + 44;
+
+	if (bw == CHANNEL_WIDTH_80)
+		duration += 40;
+	else if (bw == CHANNEL_WIDTH_40)
+		duration += 87;
+	else
+		duration += 180;
+
+	set_duration(pframe, duration);
+
+	sequence = pBeamInfo->sounding_sequence << 2;
+	if (pBeamInfo->sounding_sequence >= 0x3f)
+		pBeamInfo->sounding_sequence = 0;
+	else
+		pBeamInfo->sounding_sequence++;
+
+	_rtw_memcpy(pframe + 16, &sequence, 1);
+
+	if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE))
+		aid = 0;
+
+	sta_info.aid = aid;
+	sta_info.feedback_type = 0;
+	sta_info.nc_index = 0;
+
+	_rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2);
+
+	pattrib->pktlen = 19;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(Adapter, pmgntframe);
+
+	return _TRUE;
+}
+
+BOOLEAN	beamforming_send_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, enum channel_width bw, u8 qidx)
+{
+	return issue_vht_ndpa_packet(Adapter, ra, aid, bw, qidx);
+}
+
+BOOLEAN	beamfomring_bSounding(struct beamforming_info *pBeamInfo)
+{
+	BOOLEAN		bSounding = _FALSE;
+
+	if ((beamforming_get_beamform_cap(pBeamInfo) & BEAMFORMER_CAP) == 0)
+		bSounding = _FALSE;
+	else
+		bSounding = _TRUE;
+
+	return bSounding;
+}
+
+u8	beamforming_sounding_idx(struct beamforming_info *pBeamInfo)
+{
+	u8	idx = 0;
+	u8	i;
+
+	for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) {
+		if (pBeamInfo->beamforming_entry[i].bUsed &&
+		    (_FALSE == pBeamInfo->beamforming_entry[i].bSound)) {
+			idx = i;
+			break;
+		}
+	}
+
+	return idx;
+}
+
+SOUNDING_MODE	beamforming_sounding_mode(struct beamforming_info *pBeamInfo, u8 idx)
+{
+	struct beamforming_entry	BeamEntry = pBeamInfo->beamforming_entry[idx];
+	SOUNDING_MODE	mode;
+
+	if (BeamEntry.beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU)
+		mode = SOUNDING_FW_VHT_TIMER;
+	else if (BeamEntry.beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)
+		mode = SOUNDING_FW_HT_TIMER;
+	else
+		mode = SOUNDING_STOP_All_TIMER;
+
+	return mode;
+}
+
+u16	beamforming_sounding_time(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx)
+{
+	u16						sounding_time = 0xffff;
+	struct beamforming_entry	BeamEntry = pBeamInfo->beamforming_entry[idx];
+
+	sounding_time = BeamEntry.sound_period;
+
+	return sounding_time;
+}
+
+enum channel_width	beamforming_sounding_bw(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx)
+{
+	enum channel_width				sounding_bw = CHANNEL_WIDTH_20;
+	struct beamforming_entry		BeamEntry = pBeamInfo->beamforming_entry[idx];
+
+	sounding_bw = BeamEntry.sound_bw;
+
+	return sounding_bw;
+}
+
+BOOLEAN	beamforming_select_beam_entry(struct beamforming_info *pBeamInfo)
+{
+	struct sounding_info		*pSoundInfo = &(pBeamInfo->sounding_info);
+
+	pSoundInfo->sound_idx = beamforming_sounding_idx(pBeamInfo);
+
+	if (pSoundInfo->sound_idx < BEAMFORMING_ENTRY_NUM)
+		pSoundInfo->sound_mode = beamforming_sounding_mode(pBeamInfo, pSoundInfo->sound_idx);
+	else
+		pSoundInfo->sound_mode = SOUNDING_STOP_All_TIMER;
+
+	if (SOUNDING_STOP_All_TIMER == pSoundInfo->sound_mode)
+		return _FALSE;
+	else {
+		pSoundInfo->sound_bw = beamforming_sounding_bw(pBeamInfo, pSoundInfo->sound_mode, pSoundInfo->sound_idx);
+		pSoundInfo->sound_period = beamforming_sounding_time(pBeamInfo, pSoundInfo->sound_mode, pSoundInfo->sound_idx);
+		return _TRUE;
+	}
+}
+
+BOOLEAN	beamforming_start_fw(PADAPTER adapter, u8 idx)
+{
+	u8						*RA = NULL;
+	struct beamforming_entry	*pEntry;
+	BOOLEAN					ret = _TRUE;
+	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+
+	pEntry = &(pBeamInfo->beamforming_entry[idx]);
+	if (pEntry->bUsed == _FALSE) {
+		RTW_INFO("Skip Beamforming, no entry for Idx =%d\n", idx);
+		return _FALSE;
+	}
+
+	pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;
+	pEntry->bSound = _TRUE;
+	rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&idx);
+
+	return _TRUE;
+}
+
+void	beamforming_end_fw(PADAPTER adapter)
+{
+	u8	idx = 0;
+
+	rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&idx);
+
+	RTW_INFO("%s\n", __FUNCTION__);
+}
+
+BOOLEAN	beamforming_start_period(PADAPTER adapter)
+{
+	BOOLEAN	ret = _TRUE;
+	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct sounding_info		*pSoundInfo = &(pBeamInfo->sounding_info);
+
+	beamforming_dym_ndpa_rate(adapter);
+
+	beamforming_select_beam_entry(pBeamInfo);
+
+	if (pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER)
+		ret = beamforming_start_fw(adapter, pSoundInfo->sound_idx);
+	else
+		ret = _FALSE;
+
+	RTW_INFO("%s Idx %d Mode %d BW %d Period %d\n", __FUNCTION__,
+		pSoundInfo->sound_idx, pSoundInfo->sound_mode, pSoundInfo->sound_bw, pSoundInfo->sound_period);
+
+	return ret;
+}
+
+void	beamforming_end_period(PADAPTER adapter)
+{
+	u8						idx = 0;
+	struct beamforming_entry	*pBeamformEntry;
+	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct sounding_info		*pSoundInfo = &(pBeamInfo->sounding_info);
+
+
+	if (pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER)
+		beamforming_end_fw(adapter);
+}
+
+void	beamforming_notify(PADAPTER adapter)
+{
+	BOOLEAN		bSounding = _FALSE;
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(&(adapter->mlmepriv));
+
+	bSounding = beamfomring_bSounding(pBeamInfo);
+
+	if (pBeamInfo->beamforming_state == BEAMFORMING_STATE_IDLE) {
+		if (bSounding) {
+			if (beamforming_start_period(adapter) == _TRUE)
+				pBeamInfo->beamforming_state = BEAMFORMING_STATE_START;
+		}
+	} else if (pBeamInfo->beamforming_state == BEAMFORMING_STATE_START) {
+		if (bSounding) {
+			if (beamforming_start_period(adapter) == _FALSE)
+				pBeamInfo->beamforming_state = BEAMFORMING_STATE_END;
+		} else {
+			beamforming_end_period(adapter);
+			pBeamInfo->beamforming_state = BEAMFORMING_STATE_END;
+		}
+	} else if (pBeamInfo->beamforming_state == BEAMFORMING_STATE_END) {
+		if (bSounding) {
+			if (beamforming_start_period(adapter) == _TRUE)
+				pBeamInfo->beamforming_state = BEAMFORMING_STATE_START;
+		}
+	} else
+		RTW_INFO("%s BeamformState %d\n", __FUNCTION__, pBeamInfo->beamforming_state);
+
+	RTW_INFO("%s BeamformState %d bSounding %d\n", __FUNCTION__, pBeamInfo->beamforming_state, bSounding);
+}
+
+BOOLEAN	beamforming_init_entry(PADAPTER	adapter, struct sta_info *psta, u8 *idx)
+{
+	struct mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+	struct ht_priv		*phtpriv = &(pmlmepriv->htpriv);
+#ifdef CONFIG_80211AC_VHT
+	struct vht_priv		*pvhtpriv = &(pmlmepriv->vhtpriv);
+#endif
+	struct mlme_ext_priv	*pmlmeext = &(adapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct beamforming_entry	*pBeamformEntry = NULL;
+	u8	*ra;
+	u16	aid, mac_id;
+	u8	wireless_mode;
+	enum channel_width	bw = CHANNEL_WIDTH_20;
+	BEAMFORMING_CAP	beamform_cap = BEAMFORMING_CAP_NONE;
+
+	/* The current setting does not support Beaforming */
+	if (0 == phtpriv->beamform_cap
+#ifdef CONFIG_80211AC_VHT
+	    && 0 == pvhtpriv->beamform_cap
+#endif
+	   ) {
+		RTW_INFO("The configuration disabled Beamforming! Skip...\n");
+		return _FALSE;
+	}
+
+	aid = psta->cmn.aid;
+	ra = psta->cmn.mac_addr;
+	mac_id = psta->cmn.mac_id;
+	wireless_mode = psta->wireless_mode;
+	bw = psta->cmn.bw_mode;
+
+	if (is_supported_ht(wireless_mode) || is_supported_vht(wireless_mode)) {
+		/* 3 */ /* HT */
+		u8	cur_beamform;
+
+		cur_beamform = psta->htpriv.beamform_cap;
+
+		/* We are Beamformee because the STA is Beamformer */
+		if (TEST_FLAG(cur_beamform, BEAMFORMING_HT_BEAMFORMER_ENABLE))
+			beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMEE_CAP_HT_EXPLICIT);
+
+		/* We are Beamformer because the STA is Beamformee */
+		if (TEST_FLAG(cur_beamform, BEAMFORMING_HT_BEAMFORMEE_ENABLE))
+			beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMER_CAP_HT_EXPLICIT);
+#ifdef CONFIG_80211AC_VHT
+		if (is_supported_vht(wireless_mode)) {
+			/* 3 */ /* VHT */
+			cur_beamform = psta->vhtpriv.beamform_cap;
+
+			/* We are Beamformee because the STA is Beamformer */
+			if (TEST_FLAG(cur_beamform, BEAMFORMING_VHT_BEAMFORMER_ENABLE))
+				beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMEE_CAP_VHT_SU);
+			/* We are Beamformer because the STA is Beamformee */
+			if (TEST_FLAG(cur_beamform, BEAMFORMING_VHT_BEAMFORMEE_ENABLE))
+				beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMER_CAP_VHT_SU);
+		}
+#endif /* CONFIG_80211AC_VHT */
+
+		if (beamform_cap == BEAMFORMING_CAP_NONE)
+			return _FALSE;
+
+		RTW_INFO("Beamforming Config Capability = 0x%02X\n", beamform_cap);
+
+		pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ra, idx);
+		if (pBeamformEntry == NULL) {
+			pBeamformEntry = beamforming_add_entry(adapter, ra, aid, mac_id, bw, beamform_cap, idx);
+			if (pBeamformEntry == NULL)
+				return _FALSE;
+			else
+				pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
+		} else {
+			/* Entry has been created. If entry is initialing or progressing then errors occur. */
+			if (pBeamformEntry->beamforming_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED &&
+			    pBeamformEntry->beamforming_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED) {
+				RTW_INFO("Error State of Beamforming");
+				return _FALSE;
+			} else
+				pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
+		}
+
+		pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
+		psta->cmn.bf_info.p_aid = pBeamformEntry->p_aid;
+		psta->cmn.bf_info.g_id = pBeamformEntry->g_id;
+
+		RTW_INFO("%s Idx %d\n", __FUNCTION__, *idx);
+	} else
+		return _FALSE;
+
+	return _SUCCESS;
+}
+
+void	beamforming_deinit_entry(PADAPTER adapter, u8 *ra)
+{
+	u8	idx = 0;
+	struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+
+	if (beamforming_remove_entry(pmlmepriv, ra, &idx) == _TRUE)
+		rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, (u8 *)&idx);
+
+	RTW_INFO("%s Idx %d\n", __FUNCTION__, idx);
+}
+
+void	beamforming_reset(PADAPTER adapter)
+{
+	u8	idx = 0;
+	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+
+	for (idx = 0; idx < BEAMFORMING_ENTRY_NUM; idx++) {
+		if (pBeamInfo->beamforming_entry[idx].bUsed == _TRUE) {
+			pBeamInfo->beamforming_entry[idx].bUsed = _FALSE;
+			pBeamInfo->beamforming_entry[idx].beamforming_entry_cap = BEAMFORMING_CAP_NONE;
+			pBeamInfo->beamforming_entry[idx].beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
+			rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, (u8 *)&idx);
+		}
+	}
+
+	RTW_INFO("%s\n", __FUNCTION__);
+}
+
+void beamforming_sounding_fail(PADAPTER Adapter)
+{
+	struct mlme_priv			*pmlmepriv = &(Adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct beamforming_entry	*pEntry = &(pBeamInfo->beamforming_entry[pBeamInfo->beamforming_cur_idx]);
+
+	pEntry->bSound = _FALSE;
+	rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&pBeamInfo->beamforming_cur_idx);
+	beamforming_deinit_entry(Adapter, pEntry->mac_addr);
+}
+
+void	beamforming_check_sounding_success(PADAPTER Adapter, BOOLEAN status)
+{
+	struct mlme_priv			*pmlmepriv = &(Adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct beamforming_entry	*pEntry = &(pBeamInfo->beamforming_entry[pBeamInfo->beamforming_cur_idx]);
+
+	if (status == 1)
+		pEntry->LogStatusFailCnt = 0;
+	else {
+		pEntry->LogStatusFailCnt++;
+		RTW_INFO("%s LogStatusFailCnt %d\n", __FUNCTION__, pEntry->LogStatusFailCnt);
+	}
+	if (pEntry->LogStatusFailCnt > 20) {
+		RTW_INFO("%s LogStatusFailCnt > 20, Stop SOUNDING\n", __FUNCTION__);
+		/* pEntry->bSound = _FALSE; */
+		/* rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&pBeamInfo->beamforming_cur_idx); */
+		/* beamforming_deinit_entry(Adapter, pEntry->mac_addr); */
+		beamforming_wk_cmd(Adapter, BEAMFORMING_CTRL_SOUNDING_FAIL, NULL, 0, 1);
+	}
+}
+
+void	beamforming_enter(PADAPTER adapter, PVOID psta)
+{
+	u8	idx = 0xff;
+
+	if (beamforming_init_entry(adapter, (struct sta_info *)psta, &idx))
+		rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_ENTER, (u8 *)&idx);
+
+	/* RTW_INFO("%s Idx %d\n", __FUNCTION__, idx); */
+}
+
+void	beamforming_leave(PADAPTER adapter, u8 *ra)
+{
+	if (ra == NULL)
+		beamforming_reset(adapter);
+	else
+		beamforming_deinit_entry(adapter, ra);
+
+	beamforming_notify(adapter);
+}
+
+BEAMFORMING_CAP beamforming_get_beamform_cap(struct beamforming_info	*pBeamInfo)
+{
+	u8	i;
+	BOOLEAN				bSelfBeamformer = _FALSE;
+	BOOLEAN				bSelfBeamformee = _FALSE;
+	struct beamforming_entry	beamforming_entry;
+	BEAMFORMING_CAP		beamform_cap = BEAMFORMING_CAP_NONE;
+
+	for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) {
+		beamforming_entry = pBeamInfo->beamforming_entry[i];
+
+		if (beamforming_entry.bUsed) {
+			if ((beamforming_entry.beamforming_entry_cap & BEAMFORMEE_CAP_VHT_SU) ||
+			    (beamforming_entry.beamforming_entry_cap & BEAMFORMEE_CAP_HT_EXPLICIT))
+				bSelfBeamformee = _TRUE;
+			if ((beamforming_entry.beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU) ||
+			    (beamforming_entry.beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT))
+				bSelfBeamformer = _TRUE;
+		}
+
+		if (bSelfBeamformer && bSelfBeamformee)
+			i = BEAMFORMING_ENTRY_NUM;
+	}
+
+	if (bSelfBeamformer)
+		beamform_cap |= BEAMFORMER_CAP;
+	if (bSelfBeamformee)
+		beamform_cap |= BEAMFORMEE_CAP;
+
+	return beamform_cap;
+}
+
+void	beamforming_watchdog(PADAPTER Adapter)
+{
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO((&(Adapter->mlmepriv)));
+
+	if (pBeamInfo->beamforming_state != BEAMFORMING_STATE_START)
+		return;
+
+	beamforming_dym_period(Adapter);
+	beamforming_dym_ndpa_rate(Adapter);
+}
+#endif/* #if (BEAMFORMING_SUPPORT ==0) - for diver defined beamforming*/
+
+u32	rtw_beamforming_get_report_frame(PADAPTER	 Adapter, union recv_frame *precv_frame)
+{
+	u32	ret = _SUCCESS;
+#if (BEAMFORMING_SUPPORT == 1)
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(Adapter);
+	struct PHY_DM_STRUCT		*pDM_Odm = &(pHalData->odmpriv);
+
+	ret = beamforming_get_report_frame(pDM_Odm, precv_frame);
+
+#else /*(BEAMFORMING_SUPPORT == 0)- for drv beamfoming*/
+	struct beamforming_entry	*pBeamformEntry = NULL;
+	struct mlme_priv			*pmlmepriv = &(Adapter->mlmepriv);
+	u8	*pframe = precv_frame->u.hdr.rx_data;
+	u32	frame_len = precv_frame->u.hdr.len;
+	u8	*ta;
+	u8	idx, offset;
+
+	/*RTW_INFO("rtw_beamforming_get_report_frame\n");*/
+
+	/*Memory comparison to see if CSI report is the same with previous one*/
+	ta = get_addr2_ptr(pframe);
+	pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ta, &idx);
+	if (pBeamformEntry->beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU)
+		offset = 31;	/*24+(1+1+3)+2  MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)*/
+	else if (pBeamformEntry->beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)
+		offset = 34;	/*24+(1+1+6)+2  MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)*/
+	else
+		return ret;
+
+	/*RTW_INFO("%s MacId %d offset=%d\n", __FUNCTION__, pBeamformEntry->mac_id, offset);*/
+
+	if (_rtw_memcmp(pBeamformEntry->PreCsiReport + offset, pframe + offset, frame_len - offset) == _FALSE)
+		pBeamformEntry->DefaultCsiCnt = 0;
+	else
+		pBeamformEntry->DefaultCsiCnt++;
+
+	_rtw_memcpy(&pBeamformEntry->PreCsiReport, pframe, frame_len);
+
+	pBeamformEntry->bDefaultCSI = _FALSE;
+
+	if (pBeamformEntry->DefaultCsiCnt > 20)
+		pBeamformEntry->bDefaultCSI = _TRUE;
+	else
+		pBeamformEntry->bDefaultCSI = _FALSE;
+#endif
+	return ret;
+}
+
+void	rtw_beamforming_get_ndpa_frame(PADAPTER	 Adapter, union recv_frame *precv_frame)
+{
+#if (BEAMFORMING_SUPPORT == 1)
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(Adapter);
+	struct PHY_DM_STRUCT		*pDM_Odm = &(pHalData->odmpriv);
+
+	beamforming_get_ndpa_frame(pDM_Odm, precv_frame);
+
+#else /*(BEAMFORMING_SUPPORT == 0)- for drv beamfoming*/
+	u8	*ta;
+	u8	idx, Sequence;
+	u8	*pframe = precv_frame->u.hdr.rx_data;
+	struct mlme_priv			*pmlmepriv = &(Adapter->mlmepriv);
+	struct beamforming_entry	*pBeamformEntry = NULL;
+
+	/*RTW_INFO("rtw_beamforming_get_ndpa_frame\n");*/
+
+	if (IS_HARDWARE_TYPE_8812(Adapter) == _FALSE)
+		return;
+	else if (get_frame_sub_type(pframe) != WIFI_NDPA)
+		return;
+
+	ta = get_addr2_ptr(pframe);
+	/*Remove signaling TA. */
+	ta[0] = ta[0] & 0xFE;
+
+	pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ta, &idx);
+
+	if (pBeamformEntry == NULL)
+		return;
+	else if (!(pBeamformEntry->beamforming_entry_cap & BEAMFORMEE_CAP_VHT_SU))
+		return;
+	/*LogSuccess: As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is NO LONGER needed !2015-04-10, Jeffery*/
+	/*ClockResetTimes: While BFer entry always doesn't receive our CSI, clock will reset again and again.So ClockResetTimes is limited to 5 times.2015-04-13, Jeffery*/
+	else if ((pBeamformEntry->LogSuccess == 1) || (pBeamformEntry->ClockResetTimes == 5)) {
+		RTW_INFO("[%s] LogSeq=%d, PreLogSeq=%d\n", __func__, pBeamformEntry->LogSeq, pBeamformEntry->PreLogSeq);
+		return;
+	}
+
+	Sequence = (pframe[16]) >> 2;
+	RTW_INFO("[%s] Start, Sequence=%d, LogSeq=%d, PreLogSeq=%d, LogRetryCnt=%d, ClockResetTimes=%d, LogSuccess=%d\n",
+		__func__, Sequence, pBeamformEntry->LogSeq, pBeamformEntry->PreLogSeq, pBeamformEntry->LogRetryCnt, pBeamformEntry->ClockResetTimes, pBeamformEntry->LogSuccess);
+
+	if ((pBeamformEntry->LogSeq != 0) && (pBeamformEntry->PreLogSeq != 0)) {
+		/*Success condition*/
+		if ((pBeamformEntry->LogSeq != Sequence) && (pBeamformEntry->PreLogSeq != pBeamformEntry->LogSeq)) {
+			/* break option for clcok reset, 2015-03-30, Jeffery */
+			pBeamformEntry->LogRetryCnt = 0;
+			/*As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is no longer needed.*/
+			/*That is, LogSuccess is NOT needed to be reset to zero, 2015-04-13, Jeffery*/
+			pBeamformEntry->LogSuccess = 1;
+
+		} else {/*Fail condition*/
+
+			if (pBeamformEntry->LogRetryCnt == 5) {
+				pBeamformEntry->ClockResetTimes++;
+				pBeamformEntry->LogRetryCnt = 0;
+
+				RTW_INFO("[%s] Clock Reset!!! ClockResetTimes=%d\n",  __func__, pBeamformEntry->ClockResetTimes);
+				beamforming_wk_cmd(Adapter, BEAMFORMING_CTRL_SOUNDING_CLK, NULL, 0, 1);
+
+			} else
+				pBeamformEntry->LogRetryCnt++;
+		}
+	}
+
+	/*Update LogSeq & PreLogSeq*/
+	pBeamformEntry->PreLogSeq = pBeamformEntry->LogSeq;
+	pBeamformEntry->LogSeq = Sequence;
+
+#endif
+
+}
+
+
+
+
+void	beamforming_wk_hdl(_adapter *padapter, u8 type, u8 *pbuf)
+{
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
+	struct PHY_DM_STRUCT		*pDM_Odm = &(pHalData->odmpriv);
+
+#if (BEAMFORMING_SUPPORT == 1) /*(BEAMFORMING_SUPPORT == 1)- for PHYDM beamfoming*/
+	switch (type) {
+	case BEAMFORMING_CTRL_ENTER: {
+		struct sta_info	*psta = (PVOID)pbuf;
+		u16			staIdx = psta->cmn.mac_id;
+
+		beamforming_enter(pDM_Odm, staIdx);
+		break;
+	}
+	case BEAMFORMING_CTRL_LEAVE:
+		beamforming_leave(pDM_Odm, pbuf);
+		break;
+	default:
+		break;
+
+	}
+#else /*(BEAMFORMING_SUPPORT == 0)- for drv beamfoming*/
+	switch (type) {
+	case BEAMFORMING_CTRL_ENTER:
+		beamforming_enter(padapter, (PVOID)pbuf);
+		break;
+
+	case BEAMFORMING_CTRL_LEAVE:
+		beamforming_leave(padapter, pbuf);
+		break;
+
+	case BEAMFORMING_CTRL_SOUNDING_FAIL:
+		beamforming_sounding_fail(padapter);
+		break;
+
+	case BEAMFORMING_CTRL_SOUNDING_CLK:
+		rtw_hal_set_hwreg(padapter, HW_VAR_SOUNDING_CLK, NULL);
+		break;
+
+	default:
+		break;
+	}
+#endif
+}
+
+u8	beamforming_wk_cmd(_adapter *padapter, s32 type, u8 *pbuf, s32 size, u8 enqueue)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8	res = _SUCCESS;
+
+	/*20170214 ad_hoc mode and mp_mode not support BF*/
+	if ((padapter->registrypriv.mp_mode == 1)
+		|| (pmlmeinfo->state == WIFI_FW_ADHOC_STATE))
+		return res;
+
+	if (enqueue) {
+		u8	*wk_buf;
+
+		ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (ph2c == NULL) {
+			res = _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+		if (pdrvextra_cmd_parm == NULL) {
+			rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+			res = _FAIL;
+			goto exit;
+		}
+
+		if (pbuf != NULL) {
+			wk_buf = rtw_zmalloc(size);
+			if (wk_buf == NULL) {
+				rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));
+				rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));
+				res = _FAIL;
+				goto exit;
+			}
+
+			_rtw_memcpy(wk_buf, pbuf, size);
+		} else {
+			wk_buf = NULL;
+			size = 0;
+		}
+
+		pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID;
+		pdrvextra_cmd_parm->type = type;
+		pdrvextra_cmd_parm->size = size;
+		pdrvextra_cmd_parm->pbuf = wk_buf;
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	} else
+		beamforming_wk_hdl(padapter, type, pbuf);
+
+exit:
+
+
+	return res;
+}
+
+void update_attrib_txbf_info(_adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta)
+{
+	if (psta) {
+		pattrib->txbf_g_id = psta->cmn.bf_info.g_id;
+		pattrib->txbf_p_aid = psta->cmn.bf_info.p_aid;
+	}
+}
+#endif /* !RTW_BEAMFORMING_VERSION_2 */
+
+#endif /* CONFIG_BEAMFORMING */
diff --git a/core/rtw_br_ext.c b/core/rtw_br_ext.c
new file mode 100644
index 0000000..6509df3
--- /dev/null
+++ b/core/rtw_br_ext.c
@@ -0,0 +1,1580 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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 _RTW_BR_EXT_C_
+
+#ifdef __KERNEL__
+	#include <linux/if_arp.h>
+	#include <net/ip.h>
+	#include <net/ipx.h>
+	#include <linux/atalk.h>
+	#include <linux/udp.h>
+	#include <linux/if_pppox.h>
+#endif
+
+#if 1	/* rtw_wifi_driver */
+	#include <drv_types.h>
+#else	/* rtw_wifi_driver */
+	#include "./8192cd_cfg.h"
+
+	#ifndef __KERNEL__
+		#include "./sys-support.h"
+	#endif
+
+	#include "./8192cd.h"
+	#include "./8192cd_headers.h"
+	#include "./8192cd_br_ext.h"
+	#include "./8192cd_debug.h"
+#endif /* rtw_wifi_driver */
+
+#ifdef CL_IPV6_PASS
+	#ifdef __KERNEL__
+		#include <linux/ipv6.h>
+		#include <linux/icmpv6.h>
+		#include <net/ndisc.h>
+		#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24))
+			#include <net/ip6_checksum.h>
+		#else
+			#include <net/checksum.h>
+		#endif
+	#endif
+#endif
+
+#ifdef CONFIG_BR_EXT
+
+/* #define BR_EXT_DEBUG */
+
+#define NAT25_IPV4		01
+#define NAT25_IPV6		02
+#define NAT25_IPX		03
+#define NAT25_APPLE		04
+#define NAT25_PPPOE		05
+
+#define RTL_RELAY_TAG_LEN (ETH_ALEN)
+#define TAG_HDR_LEN		4
+
+#define MAGIC_CODE		0x8186
+#define MAGIC_CODE_LEN	2
+#define WAIT_TIME_PPPOE	5	/* waiting time for pppoe server in sec */
+
+/*-----------------------------------------------------------------
+  How database records network address:
+           0    1    2    3    4    5    6    7    8    9   10
+        |----|----|----|----|----|----|----|----|----|----|----|
+  IPv4  |type|                             |      IP addr      |
+  IPX   |type|      Net addr     |          Node addr          |
+  IPX   |type|      Net addr     |Sckt addr|
+  Apple |type| Network |node|
+  PPPoE |type|   SID   |           AC MAC            |
+-----------------------------------------------------------------*/
+
+
+/* Find a tag in pppoe frame and return the pointer */
+static __inline__ unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type)
+{
+	unsigned char *cur_ptr, *start_ptr;
+	unsigned short tagLen, tagType;
+
+	start_ptr = cur_ptr = (unsigned char *)ph->tag;
+	while ((cur_ptr - start_ptr) < ntohs(ph->length)) {
+		/* prevent un-alignment access */
+		tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]);
+		tagLen  = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]);
+		if (tagType == type)
+			return cur_ptr;
+		cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen;
+	}
+	return 0;
+}
+
+
+static __inline__ int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag)
+{
+	struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+	int data_len;
+
+	data_len = tag->tag_len + TAG_HDR_LEN;
+	if (skb_tailroom(skb) < data_len) {
+		_DEBUG_ERR("skb_tailroom() failed in add SID tag!\n");
+		return -1;
+	}
+
+	skb_put(skb, data_len);
+	/* have a room for new tag */
+	memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length));
+	ph->length = htons(ntohs(ph->length) + data_len);
+	memcpy((unsigned char *)ph->tag, tag, data_len);
+	return data_len;
+}
+
+static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len)
+{
+	int tail_len;
+	unsigned long end, tail;
+
+	if ((src + len) > skb_tail_pointer(skb) || skb->len < len)
+		return -1;
+
+	tail = (unsigned long)skb_tail_pointer(skb);
+	end = (unsigned long)src + len;
+	if (tail < end)
+		return -1;
+
+	tail_len = (int)(tail - end);
+	if (tail_len > 0)
+		memmove(src, src + len, tail_len);
+
+	skb_trim(skb, skb->len - len);
+	return 0;
+}
+
+static __inline__ unsigned long __nat25_timeout(_adapter *priv)
+{
+	unsigned long timeout;
+
+	timeout = jiffies - NAT25_AGEING_TIME * HZ;
+
+	return timeout;
+}
+
+
+static __inline__ int  __nat25_has_expired(_adapter *priv,
+		struct nat25_network_db_entry *fdb)
+{
+	if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv)))
+		return 1;
+
+	return 0;
+}
+
+
+static __inline__ void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr,
+		unsigned int *ipAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPV4;
+	memcpy(networkAddr + 7, (unsigned char *)ipAddr, 4);
+}
+
+
+static __inline__ void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr,
+		unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPX;
+	memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4);
+	memcpy(networkAddr + 5, ipxNodeAddr, 6);
+}
+
+
+static __inline__ void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr,
+		unsigned int *ipxNetAddr, unsigned short *ipxSocketAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPX;
+	memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4);
+	memcpy(networkAddr + 5, (unsigned char *)ipxSocketAddr, 2);
+}
+
+
+static __inline__ void __nat25_generate_apple_network_addr(unsigned char *networkAddr,
+		unsigned short *network, unsigned char *node)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_APPLE;
+	memcpy(networkAddr + 1, (unsigned char *)network, 2);
+	networkAddr[3] = *node;
+}
+
+
+static __inline__ void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr,
+		unsigned char *ac_mac, unsigned short *sid)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_PPPOE;
+	memcpy(networkAddr + 1, (unsigned char *)sid, 2);
+	memcpy(networkAddr + 3, (unsigned char *)ac_mac, 6);
+}
+
+
+#ifdef CL_IPV6_PASS
+static  void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr,
+		unsigned int *ipAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPV6;
+	memcpy(networkAddr + 1, (unsigned char *)ipAddr, 16);
+}
+
+
+static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b)
+{
+	while (len > 0) {
+		if (*data == tag && *(data + 1) == len8b && len >= len8b * 8)
+			return data + 2;
+
+		len -= (*(data + 1)) * 8;
+		data += (*(data + 1)) * 8;
+	}
+	return NULL;
+}
+
+
+static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac)
+{
+	struct icmp6hdr *icmphdr = (struct icmp6hdr *)data;
+	unsigned char *mac;
+
+	if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) {
+		if (len >= 8) {
+			mac = scan_tlv(&data[8], len - 8, 1, 1);
+			if (mac) {
+				RTW_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+					replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+				memcpy(mac, replace_mac, 6);
+				return 1;
+			}
+		}
+	} else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) {
+		if (len >= 16) {
+			mac = scan_tlv(&data[16], len - 16, 1, 1);
+			if (mac) {
+				RTW_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+					replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+				memcpy(mac, replace_mac, 6);
+				return 1;
+			}
+		}
+	} else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
+		if (len >= 24) {
+			mac = scan_tlv(&data[24], len - 24, 1, 1);
+			if (mac) {
+				RTW_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+					replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+				memcpy(mac, replace_mac, 6);
+				return 1;
+			}
+		}
+	} else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) {
+		if (len >= 24) {
+			mac = scan_tlv(&data[24], len - 24, 2, 1);
+			if (mac) {
+				RTW_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+					replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+				memcpy(mac, replace_mac, 6);
+				return 1;
+			}
+		}
+	} else if (icmphdr->icmp6_type == NDISC_REDIRECT) {
+		if (len >= 40) {
+			mac = scan_tlv(&data[40], len - 40, 2, 1);
+			if (mac) {
+				RTW_INFO("Redirect,  replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+					replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+				memcpy(mac, replace_mac, 6);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+
+static void convert_ipv6_mac_to_mc(struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
+	unsigned char *dst_mac = skb->data;
+
+	/* dst_mac[0] = 0xff; */
+	/* dst_mac[1] = 0xff; */
+	/*modified by qinjunjie,ipv6 multicast address ix 0x33-33-xx-xx-xx-xx*/
+	dst_mac[0] = 0x33;
+	dst_mac[1] = 0x33;
+	memcpy(&dst_mac[2], &iph->daddr.s6_addr32[3], 4);
+#if defined(__LINUX_2_6__)
+	/*modified by qinjunjie,warning:should not remove next line*/
+	skb->pkt_type = PACKET_MULTICAST;
+#endif
+}
+#endif /* CL_IPV6_PASS */
+
+
+static __inline__ int __nat25_network_hash(unsigned char *networkAddr)
+{
+	if (networkAddr[0] == NAT25_IPV4) {
+		unsigned long x;
+
+		x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	} else if (networkAddr[0] == NAT25_IPX) {
+		unsigned long x;
+
+		x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+		    networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	} else if (networkAddr[0] == NAT25_APPLE) {
+		unsigned long x;
+
+		x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	} else if (networkAddr[0] == NAT25_PPPOE) {
+		unsigned long x;
+
+		x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	}
+#ifdef CL_IPV6_PASS
+	else if (networkAddr[0] == NAT25_IPV6) {
+		unsigned long x;
+
+		x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+		    networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^
+		    networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^
+		    networkAddr[16];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	}
+#endif
+	else {
+		unsigned long x = 0;
+		int i;
+
+		for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++)
+			x ^= networkAddr[i];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	}
+}
+
+
+static __inline__ void __network_hash_link(_adapter *priv,
+		struct nat25_network_db_entry *ent, int hash)
+{
+	/* Caller must _enter_critical_bh already! */
+	/* _irqL irqL; */
+	/* _enter_critical_bh(&priv->br_ext_lock, &irqL); */
+
+	ent->next_hash = priv->nethash[hash];
+	if (ent->next_hash != NULL)
+		ent->next_hash->pprev_hash = &ent->next_hash;
+	priv->nethash[hash] = ent;
+	ent->pprev_hash = &priv->nethash[hash];
+
+	/* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+}
+
+
+static __inline__ void __network_hash_unlink(struct nat25_network_db_entry *ent)
+{
+	/* Caller must _enter_critical_bh already! */
+	/* _irqL irqL; */
+	/* _enter_critical_bh(&priv->br_ext_lock, &irqL); */
+
+	*(ent->pprev_hash) = ent->next_hash;
+	if (ent->next_hash != NULL)
+		ent->next_hash->pprev_hash = ent->pprev_hash;
+	ent->next_hash = NULL;
+	ent->pprev_hash = NULL;
+
+	/* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+}
+
+
+static int __nat25_db_network_lookup_and_replace(_adapter *priv,
+		struct sk_buff *skb, unsigned char *networkAddr)
+{
+	struct nat25_network_db_entry *db;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	db = priv->nethash[__nat25_network_hash(networkAddr)];
+	while (db != NULL) {
+		if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+			if (!__nat25_has_expired(priv, db)) {
+				/* replace the destination mac address */
+				memcpy(skb->data, db->macAddr, ETH_ALEN);
+				atomic_inc(&db->use_count);
+
+#ifdef CL_IPV6_PASS
+				RTW_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+					 "%02x%02x%02x%02x%02x%02x\n",
+					 db->macAddr[0],
+					 db->macAddr[1],
+					 db->macAddr[2],
+					 db->macAddr[3],
+					 db->macAddr[4],
+					 db->macAddr[5],
+					 db->networkAddr[0],
+					 db->networkAddr[1],
+					 db->networkAddr[2],
+					 db->networkAddr[3],
+					 db->networkAddr[4],
+					 db->networkAddr[5],
+					 db->networkAddr[6],
+					 db->networkAddr[7],
+					 db->networkAddr[8],
+					 db->networkAddr[9],
+					 db->networkAddr[10],
+					 db->networkAddr[11],
+					 db->networkAddr[12],
+					 db->networkAddr[13],
+					 db->networkAddr[14],
+					 db->networkAddr[15],
+					 db->networkAddr[16]);
+#else
+				RTW_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+					 db->macAddr[0],
+					 db->macAddr[1],
+					 db->macAddr[2],
+					 db->macAddr[3],
+					 db->macAddr[4],
+					 db->macAddr[5],
+					 db->networkAddr[0],
+					 db->networkAddr[1],
+					 db->networkAddr[2],
+					 db->networkAddr[3],
+					 db->networkAddr[4],
+					 db->networkAddr[5],
+					 db->networkAddr[6],
+					 db->networkAddr[7],
+					 db->networkAddr[8],
+					 db->networkAddr[9],
+					 db->networkAddr[10]);
+#endif
+			}
+			_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			return 1;
+		}
+
+		db = db->next_hash;
+	}
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+	return 0;
+}
+
+
+static void __nat25_db_network_insert(_adapter *priv,
+		      unsigned char *macAddr, unsigned char *networkAddr)
+{
+	struct nat25_network_db_entry *db;
+	int hash;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	hash = __nat25_network_hash(networkAddr);
+	db = priv->nethash[hash];
+	while (db != NULL) {
+		if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+			memcpy(db->macAddr, macAddr, ETH_ALEN);
+			db->ageing_timer = jiffies;
+			_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			return;
+		}
+
+		db = db->next_hash;
+	}
+
+	db = (struct nat25_network_db_entry *) rtw_malloc(sizeof(*db));
+	if (db == NULL) {
+		_exit_critical_bh(&priv->br_ext_lock, &irqL);
+		return;
+	}
+
+	memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN);
+	memcpy(db->macAddr, macAddr, ETH_ALEN);
+	atomic_set(&db->use_count, 1);
+	db->ageing_timer = jiffies;
+
+	__network_hash_link(priv, db, hash);
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+static void __nat25_db_print(_adapter *priv)
+{
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+#ifdef BR_EXT_DEBUG
+	static int counter = 0;
+	int i, j;
+	struct nat25_network_db_entry *db;
+
+	counter++;
+	if ((counter % 16) != 0)
+		return;
+
+	for (i = 0, j = 0; i < NAT25_HASH_SIZE; i++) {
+		db = priv->nethash[i];
+
+		while (db != NULL) {
+#ifdef CL_IPV6_PASS
+			panic_printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+				     "%02x%02x%02x%02x%02x%02x\n",
+				     j,
+				     i,
+				     atomic_read(&db->use_count),
+				     db->macAddr[0],
+				     db->macAddr[1],
+				     db->macAddr[2],
+				     db->macAddr[3],
+				     db->macAddr[4],
+				     db->macAddr[5],
+				     db->networkAddr[0],
+				     db->networkAddr[1],
+				     db->networkAddr[2],
+				     db->networkAddr[3],
+				     db->networkAddr[4],
+				     db->networkAddr[5],
+				     db->networkAddr[6],
+				     db->networkAddr[7],
+				     db->networkAddr[8],
+				     db->networkAddr[9],
+				     db->networkAddr[10],
+				     db->networkAddr[11],
+				     db->networkAddr[12],
+				     db->networkAddr[13],
+				     db->networkAddr[14],
+				     db->networkAddr[15],
+				     db->networkAddr[16]);
+#else
+			panic_printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+				     j,
+				     i,
+				     atomic_read(&db->use_count),
+				     db->macAddr[0],
+				     db->macAddr[1],
+				     db->macAddr[2],
+				     db->macAddr[3],
+				     db->macAddr[4],
+				     db->macAddr[5],
+				     db->networkAddr[0],
+				     db->networkAddr[1],
+				     db->networkAddr[2],
+				     db->networkAddr[3],
+				     db->networkAddr[4],
+				     db->networkAddr[5],
+				     db->networkAddr[6],
+				     db->networkAddr[7],
+				     db->networkAddr[8],
+				     db->networkAddr[9],
+				     db->networkAddr[10]);
+#endif
+			j++;
+
+			db = db->next_hash;
+		}
+	}
+#endif
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+
+
+/*
+ *	NAT2.5 interface
+ */
+
+void nat25_db_cleanup(_adapter *priv)
+{
+	int i;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	for (i = 0; i < NAT25_HASH_SIZE; i++) {
+		struct nat25_network_db_entry *f;
+		f = priv->nethash[i];
+		while (f != NULL) {
+			struct nat25_network_db_entry *g;
+
+			g = f->next_hash;
+			if (priv->scdb_entry == f) {
+				memset(priv->scdb_mac, 0, ETH_ALEN);
+				memset(priv->scdb_ip, 0, 4);
+				priv->scdb_entry = NULL;
+			}
+			__network_hash_unlink(f);
+			rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry));
+
+			f = g;
+		}
+	}
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+void nat25_db_expire(_adapter *priv)
+{
+	int i;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	/* if(!priv->ethBrExtInfo.nat25_disable) */
+	{
+		for (i = 0; i < NAT25_HASH_SIZE; i++) {
+			struct nat25_network_db_entry *f;
+			f = priv->nethash[i];
+
+			while (f != NULL) {
+				struct nat25_network_db_entry *g;
+				g = f->next_hash;
+
+				if (__nat25_has_expired(priv, f)) {
+					if (atomic_dec_and_test(&f->use_count)) {
+#ifdef BR_EXT_DEBUG
+#ifdef CL_IPV6_PASS
+						panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+							"%02x%02x%02x%02x%02x%02x\n",
+							     i,
+							     f->macAddr[0],
+							     f->macAddr[1],
+							     f->macAddr[2],
+							     f->macAddr[3],
+							     f->macAddr[4],
+							     f->macAddr[5],
+							     f->networkAddr[0],
+							     f->networkAddr[1],
+							     f->networkAddr[2],
+							     f->networkAddr[3],
+							     f->networkAddr[4],
+							     f->networkAddr[5],
+							     f->networkAddr[6],
+							     f->networkAddr[7],
+							     f->networkAddr[8],
+							     f->networkAddr[9],
+							     f->networkAddr[10],
+							     f->networkAddr[11],
+							     f->networkAddr[12],
+							     f->networkAddr[13],
+							     f->networkAddr[14],
+							     f->networkAddr[15],
+							f->networkAddr[16]);
+#else
+
+						panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+							     i,
+							     f->macAddr[0],
+							     f->macAddr[1],
+							     f->macAddr[2],
+							     f->macAddr[3],
+							     f->macAddr[4],
+							     f->macAddr[5],
+							     f->networkAddr[0],
+							     f->networkAddr[1],
+							     f->networkAddr[2],
+							     f->networkAddr[3],
+							     f->networkAddr[4],
+							     f->networkAddr[5],
+							     f->networkAddr[6],
+							     f->networkAddr[7],
+							     f->networkAddr[8],
+							     f->networkAddr[9],
+							f->networkAddr[10]);
+#endif
+#endif
+						if (priv->scdb_entry == f) {
+							memset(priv->scdb_mac, 0, ETH_ALEN);
+							memset(priv->scdb_ip, 0, 4);
+							priv->scdb_entry = NULL;
+						}
+						__network_hash_unlink(f);
+						rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry));
+					}
+				}
+
+				f = g;
+			}
+		}
+	}
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+#ifdef SUPPORT_TX_MCAST2UNI
+static int checkIPMcAndReplace(_adapter *priv, struct sk_buff *skb, unsigned int *dst_ip)
+{
+	struct stat_info	*pstat;
+	struct list_head	*phead, *plist;
+	int i;
+
+	phead = &priv->asoc_list;
+	plist = phead->next;
+
+	while (plist != phead) {
+		pstat = list_entry(plist, struct stat_info, asoc_list);
+		plist = plist->next;
+
+		if (pstat->ipmc_num == 0)
+			continue;
+
+		for (i = 0; i < MAX_IP_MC_ENTRY; i++) {
+			if (pstat->ipmc[i].used && !memcmp(&pstat->ipmc[i].mcmac[3], ((unsigned char *)dst_ip) + 1, 3)) {
+				memcpy(skb->data, pstat->ipmc[i].mcmac, ETH_ALEN);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+#endif
+
+int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method)
+{
+	unsigned short protocol;
+	unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+
+	if (skb == NULL)
+		return -1;
+
+	if ((method <= NAT25_MIN) || (method >= NAT25_MAX))
+		return -1;
+
+	protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN));
+
+	/*---------------------------------------------------*/
+	/*                 Handle IP frame                  */
+	/*---------------------------------------------------*/
+	if (protocol == __constant_htons(ETH_P_IP)) {
+		struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+		if (((unsigned char *)(iph) + (iph->ihl << 2)) >= (skb->data + ETH_HLEN + skb->len)) {
+			DEBUG_WARN("NAT25: malformed IP packet !\n");
+			return -1;
+		}
+
+		switch (method) {
+		case NAT25_CHECK:
+			return -1;
+
+		case NAT25_INSERT: {
+			/* some muticast with source IP is all zero, maybe other case is illegal */
+			/* in class A, B, C, host address is all zero or all one is illegal */
+			if (iph->saddr == 0)
+				return 0;
+			RTW_INFO("NAT25: Insert IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr);
+			__nat25_generate_ipv4_network_addr(networkAddr, &iph->saddr);
+			/* record source IP address and , source mac address into db */
+			__nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr);
+
+			__nat25_db_print(priv);
+		}
+		return 0;
+
+		case NAT25_LOOKUP: {
+			RTW_INFO("NAT25: Lookup IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr);
+#ifdef SUPPORT_TX_MCAST2UNI
+			if (priv->pshare->rf_ft_var.mc2u_disable ||
+			    ((((OPMODE & (WIFI_STATION_STATE | WIFI_ASOC_STATE))
+			       == (WIFI_STATION_STATE | WIFI_ASOC_STATE)) &&
+			      !checkIPMcAndReplace(priv, skb, &iph->daddr)) ||
+			     (OPMODE & WIFI_ADHOC_STATE)))
+#endif
+			{
+				__nat25_generate_ipv4_network_addr(networkAddr, &iph->daddr);
+
+				if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) {
+					if (*((unsigned char *)&iph->daddr + 3) == 0xff) {
+						/* L2 is unicast but L3 is broadcast, make L2 bacome broadcast */
+						RTW_INFO("NAT25: Set DA as boardcast\n");
+						memset(skb->data, 0xff, ETH_ALEN);
+					} else {
+						/* forward unknow IP packet to upper TCP/IP */
+						RTW_INFO("NAT25: Replace DA with BR's MAC\n");
+						if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac + 4)) == 0) {
+							void netdev_br_init(struct net_device *netdev);
+							printk("Re-init netdev_br_init() due to br_mac==0!\n");
+							netdev_br_init(priv->pnetdev);
+						}
+						memcpy(skb->data, priv->br_mac, ETH_ALEN);
+					}
+				}
+			}
+		}
+		return 0;
+
+		default:
+			return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*                 Handle ARP frame                 */
+	/*---------------------------------------------------*/
+	else if (protocol == __constant_htons(ETH_P_ARP)) {
+		struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN);
+		unsigned char *arp_ptr = (unsigned char *)(arp + 1);
+		unsigned int *sender, *target;
+
+		if (arp->ar_pro != __constant_htons(ETH_P_IP)) {
+			DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", htons(arp->ar_pro));
+			return -1;
+		}
+
+		switch (method) {
+		case NAT25_CHECK:
+			return 0;	/* skb_copy for all ARP frame */
+
+		case NAT25_INSERT: {
+			RTW_INFO("NAT25: Insert ARP, MAC=%02x%02x%02x%02x%02x%02x\n", arp_ptr[0],
+				arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]);
+
+			/* change to ARP sender mac address to wlan STA address */
+			memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN);
+
+			arp_ptr += arp->ar_hln;
+			sender = (unsigned int *)arp_ptr;
+
+			__nat25_generate_ipv4_network_addr(networkAddr, sender);
+
+			__nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr);
+
+			__nat25_db_print(priv);
+		}
+		return 0;
+
+		case NAT25_LOOKUP: {
+			RTW_INFO("NAT25: Lookup ARP\n");
+
+			arp_ptr += arp->ar_hln;
+			sender = (unsigned int *)arp_ptr;
+			arp_ptr += (arp->ar_hln + arp->ar_pln);
+			target = (unsigned int *)arp_ptr;
+
+			__nat25_generate_ipv4_network_addr(networkAddr, target);
+
+			__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+			/* change to ARP target mac address to Lookup result */
+			arp_ptr = (unsigned char *)(arp + 1);
+			arp_ptr += (arp->ar_hln + arp->ar_pln);
+			memcpy(arp_ptr, skb->data, ETH_ALEN);
+		}
+		return 0;
+
+		default:
+			return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*         Handle IPX and Apple Talk frame          */
+	/*---------------------------------------------------*/
+	else if ((protocol == __constant_htons(ETH_P_IPX)) ||
+		 (protocol == __constant_htons(ETH_P_ATALK)) ||
+		 (protocol == __constant_htons(ETH_P_AARP))) {
+		unsigned char ipx_header[2] = {0xFF, 0xFF};
+		struct ipxhdr	*ipx = NULL;
+		struct elapaarp	*ea = NULL;
+		struct ddpehdr	*ddp = NULL;
+		unsigned char *framePtr = skb->data + ETH_HLEN;
+
+		if (protocol == __constant_htons(ETH_P_IPX)) {
+			RTW_INFO("NAT25: Protocol=IPX (Ethernet II)\n");
+			ipx = (struct ipxhdr *)framePtr;
+		} else { /* if(protocol <= __constant_htons(ETH_FRAME_LEN)) */
+			if (!memcmp(ipx_header, framePtr, 2)) {
+				RTW_INFO("NAT25: Protocol=IPX (Ethernet 802.3)\n");
+				ipx = (struct ipxhdr *)framePtr;
+			} else {
+				unsigned char ipx_8022_type =  0xE0;
+				unsigned char snap_8022_type = 0xAA;
+
+				if (*framePtr == snap_8022_type) {
+					unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37};		/* IPX SNAP ID */
+					unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3};	/* Apple Talk AARP SNAP ID */
+					unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B};	/* Apple Talk DDP SNAP ID */
+
+					framePtr += 3;	/* eliminate the 802.2 header */
+
+					if (!memcmp(ipx_snap_id, framePtr, 5)) {
+						framePtr += 5;	/* eliminate the SNAP header */
+
+						RTW_INFO("NAT25: Protocol=IPX (Ethernet SNAP)\n");
+						ipx = (struct ipxhdr *)framePtr;
+					} else if (!memcmp(aarp_snap_id, framePtr, 5)) {
+						framePtr += 5;	/* eliminate the SNAP header */
+
+						ea = (struct elapaarp *)framePtr;
+					} else if (!memcmp(ddp_snap_id, framePtr, 5)) {
+						framePtr += 5;	/* eliminate the SNAP header */
+
+						ddp = (struct ddpehdr *)framePtr;
+					} else {
+						DEBUG_WARN("NAT25: Protocol=Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0],
+							framePtr[1], framePtr[2], framePtr[3], framePtr[4]);
+						return -1;
+					}
+				} else if (*framePtr == ipx_8022_type) {
+					framePtr += 3;	/* eliminate the 802.2 header */
+
+					if (!memcmp(ipx_header, framePtr, 2)) {
+						RTW_INFO("NAT25: Protocol=IPX (Ethernet 802.2)\n");
+						ipx = (struct ipxhdr *)framePtr;
+					} else
+						return -1;
+				}
+			}
+		}
+
+		/*   IPX  */
+		if (ipx != NULL) {
+			switch (method) {
+			case NAT25_CHECK:
+				if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) {
+					RTW_INFO("NAT25: Check IPX skb_copy\n");
+					return 0;
+				}
+				return -1;
+
+			case NAT25_INSERT: {
+				RTW_INFO("NAT25: Insert IPX, Dest=%08x,%02x%02x%02x%02x%02x%02x,%04x Source=%08x,%02x%02x%02x%02x%02x%02x,%04x\n",
+					 ipx->ipx_dest.net,
+					 ipx->ipx_dest.node[0],
+					 ipx->ipx_dest.node[1],
+					 ipx->ipx_dest.node[2],
+					 ipx->ipx_dest.node[3],
+					 ipx->ipx_dest.node[4],
+					 ipx->ipx_dest.node[5],
+					 ipx->ipx_dest.sock,
+					 ipx->ipx_source.net,
+					 ipx->ipx_source.node[0],
+					 ipx->ipx_source.node[1],
+					 ipx->ipx_source.node[2],
+					 ipx->ipx_source.node[3],
+					 ipx->ipx_source.node[4],
+					 ipx->ipx_source.node[5],
+					 ipx->ipx_source.sock);
+
+				if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) {
+					RTW_INFO("NAT25: Use IPX Net, and Socket as network addr\n");
+
+					__nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock);
+
+					/* change IPX source node addr to wlan STA address */
+					memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN);
+				} else
+					__nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node);
+
+				__nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr);
+
+				__nat25_db_print(priv);
+			}
+			return 0;
+
+			case NAT25_LOOKUP: {
+				if (!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN)) {
+					RTW_INFO("NAT25: Lookup IPX, Modify Destination IPX Node addr\n");
+
+					__nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock);
+
+					__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+					/* replace IPX destination node addr with Lookup destination MAC addr */
+					memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN);
+				} else {
+					__nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node);
+
+					__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+				}
+			}
+			return 0;
+
+			default:
+				return -1;
+			}
+		}
+
+		/*   AARP  */
+		else if (ea != NULL) {
+			/* Sanity check fields. */
+			if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) {
+				DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n");
+				return -1;
+			}
+
+			switch (method) {
+			case NAT25_CHECK:
+				return 0;
+
+			case NAT25_INSERT: {
+				/* change to AARP source mac address to wlan STA address */
+				memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN);
+
+				RTW_INFO("NAT25: Insert AARP, Source=%d,%d Destination=%d,%d\n",
+					 ea->pa_src_net,
+					 ea->pa_src_node,
+					 ea->pa_dst_net,
+					 ea->pa_dst_node);
+
+				__nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node);
+
+				__nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr);
+
+				__nat25_db_print(priv);
+			}
+			return 0;
+
+			case NAT25_LOOKUP: {
+				RTW_INFO("NAT25: Lookup AARP, Source=%d,%d Destination=%d,%d\n",
+					 ea->pa_src_net,
+					 ea->pa_src_node,
+					 ea->pa_dst_net,
+					 ea->pa_dst_node);
+
+				__nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node);
+
+				__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+				/* change to AARP destination mac address to Lookup result */
+				memcpy(ea->hw_dst, skb->data, ETH_ALEN);
+			}
+			return 0;
+
+			default:
+				return -1;
+			}
+		}
+
+		/*   DDP  */
+		else if (ddp != NULL) {
+			switch (method) {
+			case NAT25_CHECK:
+				return -1;
+
+			case NAT25_INSERT: {
+				RTW_INFO("NAT25: Insert DDP, Source=%d,%d Destination=%d,%d\n",
+					 ddp->deh_snet,
+					 ddp->deh_snode,
+					 ddp->deh_dnet,
+					 ddp->deh_dnode);
+
+				__nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode);
+
+				__nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr);
+
+				__nat25_db_print(priv);
+			}
+			return 0;
+
+			case NAT25_LOOKUP: {
+				RTW_INFO("NAT25: Lookup DDP, Source=%d,%d Destination=%d,%d\n",
+					 ddp->deh_snet,
+					 ddp->deh_snode,
+					 ddp->deh_dnet,
+					 ddp->deh_dnode);
+
+				__nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode);
+
+				__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+			}
+			return 0;
+
+			default:
+				return -1;
+			}
+		}
+
+		return -1;
+	}
+
+	/*---------------------------------------------------*/
+	/*                Handle PPPoE frame                */
+	/*---------------------------------------------------*/
+	else if ((protocol == __constant_htons(ETH_P_PPP_DISC)) ||
+		 (protocol == __constant_htons(ETH_P_PPP_SES))) {
+		struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+		unsigned short *pMagic;
+
+		switch (method) {
+		case NAT25_CHECK:
+			if (ph->sid == 0)
+				return 0;
+			return 1;
+
+		case NAT25_INSERT:
+			if (ph->sid == 0) {	/* Discovery phase according to tag */
+				if (ph->code == PADI_CODE || ph->code == PADR_CODE) {
+					if (priv->ethBrExtInfo.addPPPoETag) {
+						struct pppoe_tag *tag, *pOldTag;
+						unsigned char tag_buf[40];
+						int old_tag_len = 0;
+
+						tag = (struct pppoe_tag *)tag_buf;
+						pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
+						if (pOldTag) { /* if SID existed, copy old value and delete it */
+							old_tag_len = ntohs(pOldTag->tag_len);
+							if (old_tag_len + TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN > sizeof(tag_buf)) {
+								DEBUG_ERR("SID tag length too long!\n");
+								return -1;
+							}
+
+							memcpy(tag->tag_data + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN,
+							       pOldTag->tag_data, old_tag_len);
+
+							if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN + old_tag_len) < 0) {
+								DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n");
+								return -1;
+							}
+							ph->length = htons(ntohs(ph->length) - TAG_HDR_LEN - old_tag_len);
+						}
+
+						tag->tag_type = PTT_RELAY_SID;
+						tag->tag_len = htons(MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN + old_tag_len);
+
+						/* insert the magic_code+client mac in relay tag */
+						pMagic = (unsigned short *)tag->tag_data;
+						*pMagic = htons(MAGIC_CODE);
+						memcpy(tag->tag_data + MAGIC_CODE_LEN, skb->data + ETH_ALEN, ETH_ALEN);
+
+						/* Add relay tag */
+						if (__nat25_add_pppoe_tag(skb, tag) < 0)
+							return -1;
+
+						RTW_INFO("NAT25: Insert PPPoE, forward %s packet\n",
+							(ph->code == PADI_CODE ? "PADI" : "PADR"));
+					} else { /* not add relay tag */
+						if (priv->pppoe_connection_in_progress &&
+						    memcmp(skb->data + ETH_ALEN, priv->pppoe_addr, ETH_ALEN))	 {
+							DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n");
+							return -2;
+						}
+
+						if (priv->pppoe_connection_in_progress == 0)
+							memcpy(priv->pppoe_addr, skb->data + ETH_ALEN, ETH_ALEN);
+
+						priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+					}
+				} else
+					return -1;
+			} else {	/* session phase */
+				RTW_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name);
+
+				__nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid));
+
+				__nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr);
+
+				__nat25_db_print(priv);
+
+				if (!priv->ethBrExtInfo.addPPPoETag &&
+				    priv->pppoe_connection_in_progress &&
+				    !memcmp(skb->data + ETH_ALEN, priv->pppoe_addr, ETH_ALEN))
+					priv->pppoe_connection_in_progress = 0;
+			}
+			return 0;
+
+		case NAT25_LOOKUP:
+			if (ph->code == PADO_CODE || ph->code == PADS_CODE) {
+				if (priv->ethBrExtInfo.addPPPoETag) {
+					struct pppoe_tag *tag;
+					unsigned char *ptr;
+					unsigned short tagType, tagLen;
+					int offset = 0;
+
+					ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
+					if (ptr == 0) {
+						DEBUG_ERR("Fail to find PTT_RELAY_SID in FADO!\n");
+						return -1;
+					}
+
+					tag = (struct pppoe_tag *)ptr;
+					tagType = (unsigned short)((ptr[0] << 8) + ptr[1]);
+					tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]);
+
+					if ((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN))) {
+						DEBUG_ERR("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen);
+						return -1;
+					}
+
+					pMagic = (unsigned short *)tag->tag_data;
+					if (ntohs(*pMagic) != MAGIC_CODE) {
+						DEBUG_ERR("Can't find MAGIC_CODE in %s packet!\n",
+							(ph->code == PADO_CODE ? "PADO" : "PADS"));
+						return -1;
+					}
+
+					memcpy(skb->data, tag->tag_data + MAGIC_CODE_LEN, ETH_ALEN);
+
+					if (tagLen > MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN)
+						offset = TAG_HDR_LEN;
+
+					if (skb_pull_and_merge(skb, ptr + offset, TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN - offset) < 0) {
+						DEBUG_ERR("call skb_pull_and_merge() failed in PADO packet!\n");
+						return -1;
+					}
+					ph->length = htons(ntohs(ph->length) - (TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN - offset));
+					if (offset > 0)
+						tag->tag_len = htons(tagLen - MAGIC_CODE_LEN - RTL_RELAY_TAG_LEN);
+
+					RTW_INFO("NAT25: Lookup PPPoE, forward %s Packet from %s\n",
+						(ph->code == PADO_CODE ? "PADO" : "PADS"),	skb->dev->name);
+				} else { /* not add relay tag */
+					if (!priv->pppoe_connection_in_progress) {
+						DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n");
+						return -1;
+					}
+					memcpy(skb->data, priv->pppoe_addr, ETH_ALEN);
+					priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+				}
+			} else {
+				if (ph->sid != 0) {
+					RTW_INFO("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name);
+					__nat25_generate_pppoe_network_addr(networkAddr, skb->data + ETH_ALEN, &(ph->sid));
+
+					__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+					__nat25_db_print(priv);
+				} else
+					return -1;
+
+			}
+			return 0;
+
+		default:
+			return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*                 Handle EAP frame                 */
+	/*---------------------------------------------------*/
+	else if (protocol == __constant_htons(0x888e)) {
+		switch (method) {
+		case NAT25_CHECK:
+			return -1;
+
+		case NAT25_INSERT:
+			return 0;
+
+		case NAT25_LOOKUP:
+			return 0;
+
+		default:
+			return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*         Handle C-Media proprietary frame         */
+	/*---------------------------------------------------*/
+	else if ((protocol == __constant_htons(0xe2ae)) ||
+		 (protocol == __constant_htons(0xe2af))) {
+		switch (method) {
+		case NAT25_CHECK:
+			return -1;
+
+		case NAT25_INSERT:
+			return 0;
+
+		case NAT25_LOOKUP:
+			return 0;
+
+		default:
+			return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*         Handle IPV6 frame      							 */
+	/*---------------------------------------------------*/
+#ifdef CL_IPV6_PASS
+	else if (protocol == __constant_htons(ETH_P_IPV6)) {
+		struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
+
+		if (sizeof(*iph) >= (skb->len - ETH_HLEN)) {
+			DEBUG_WARN("NAT25: malformed IPv6 packet !\n");
+			return -1;
+		}
+
+		switch (method) {
+		case NAT25_CHECK:
+			if (skb->data[0] & 1)
+				return 0;
+			return -1;
+
+		case NAT25_INSERT: {
+			RTW_INFO("NAT25: Insert IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x,"
+				" DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
+				iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
+				iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
+				iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
+				iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
+
+			if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) {
+				__nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr);
+				__nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr);
+				__nat25_db_print(priv);
+
+				if (iph->nexthdr == IPPROTO_ICMPV6 &&
+				    skb->len > (ETH_HLEN +  sizeof(*iph) + 4)) {
+					if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph),
+						skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) {
+						struct icmp6hdr  *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph));
+						hdr->icmp6_cksum = 0;
+						hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr,
+							iph->payload_len,
+							IPPROTO_ICMPV6,
+							csum_partial((__u8 *)hdr, iph->payload_len, 0));
+					}
+				}
+			}
+		}
+		return 0;
+
+		case NAT25_LOOKUP:
+			RTW_INFO("NAT25: Lookup IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x,"
+				 " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
+				iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
+				iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
+				iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
+				iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
+
+
+			__nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->daddr);
+			if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) {
+#ifdef SUPPORT_RX_UNI2MCAST
+				if (iph->daddr.s6_addr[0] == 0xff)
+					convert_ipv6_mac_to_mc(skb);
+#endif
+			}
+			return 0;
+
+		default:
+			return -1;
+		}
+	}
+#endif /* CL_IPV6_PASS */
+
+	return -1;
+}
+
+
+int nat25_handle_frame(_adapter *priv, struct sk_buff *skb)
+{
+#ifdef BR_EXT_DEBUG
+	if ((!priv->ethBrExtInfo.nat25_disable) && (!(skb->data[0] & 1))) {
+		panic_printk("NAT25: Input Frame: DA=%02x%02x%02x%02x%02x%02x SA=%02x%02x%02x%02x%02x%02x\n",
+			     skb->data[0],
+			     skb->data[1],
+			     skb->data[2],
+			     skb->data[3],
+			     skb->data[4],
+			     skb->data[5],
+			     skb->data[6],
+			     skb->data[7],
+			     skb->data[8],
+			     skb->data[9],
+			     skb->data[10],
+			     skb->data[11]);
+	}
+#endif
+
+	if (!(skb->data[0] & 1)) {
+		int is_vlan_tag = 0, i, retval = 0;
+		unsigned short vlan_hdr = 0;
+
+		if (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_8021Q)) {
+			is_vlan_tag = 1;
+			vlan_hdr = *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2));
+			for (i = 0; i < 6; i++)
+				*((unsigned short *)(skb->data + ETH_ALEN * 2 + 2 - i * 2)) = *((unsigned short *)(skb->data + ETH_ALEN * 2 - 2 - i * 2));
+			skb_pull(skb, 4);
+		}
+
+		if (!priv->ethBrExtInfo.nat25_disable) {
+			_irqL irqL;
+			_enter_critical_bh(&priv->br_ext_lock, &irqL);
+			/*
+			 *	This function look up the destination network address from
+			 *	the NAT2.5 database. Return value = -1 means that the
+			 *	corresponding network protocol is NOT support.
+			 */
+			if (!priv->ethBrExtInfo.nat25sc_disable &&
+			    (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_IP)) &&
+			    !memcmp(priv->scdb_ip, skb->data + ETH_HLEN + 16, 4)) {
+				memcpy(skb->data, priv->scdb_mac, ETH_ALEN);
+
+				_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			} else {
+				_exit_critical_bh(&priv->br_ext_lock, &irqL);
+
+				retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
+			}
+		} else {
+			if (((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_IP)) &&
+			     !memcmp(priv->br_ip, skb->data + ETH_HLEN + 16, 4)) ||
+			    ((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_ARP)) &&
+			     !memcmp(priv->br_ip, skb->data + ETH_HLEN + 24, 4))) {
+				/* for traffic to upper TCP/IP */
+				retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
+			}
+		}
+
+		if (is_vlan_tag) {
+			skb_push(skb, 4);
+			for (i = 0; i < 6; i++)
+				*((unsigned short *)(skb->data + i * 2)) = *((unsigned short *)(skb->data + 4 + i * 2));
+			*((unsigned short *)(skb->data + ETH_ALEN * 2)) = __constant_htons(ETH_P_8021Q);
+			*((unsigned short *)(skb->data + ETH_ALEN * 2 + 2)) = vlan_hdr;
+		}
+
+		if (retval == -1) {
+			/* DEBUG_ERR("NAT25: Lookup fail!\n"); */
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+#if 0
+void mac_clone(_adapter *priv, unsigned char *addr)
+{
+	struct sockaddr sa;
+
+	memcpy(sa.sa_data, addr, ETH_ALEN);
+	RTW_INFO("MAC Clone: Addr=%02x%02x%02x%02x%02x%02x\n",
+		 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+	rtl8192cd_set_hwaddr(priv->dev, &sa);
+}
+
+
+int mac_clone_handle_frame(_adapter *priv, struct sk_buff *skb)
+{
+	if (priv->ethBrExtInfo.macclone_enable && !priv->macclone_completed) {
+		if (!(skb->data[ETH_ALEN] & 1)) {	/* check any other particular MAC add */
+			if (memcmp(skb->data + ETH_ALEN, GET_MY_HWADDR(priv), ETH_ALEN) &&
+			    ((priv->dev->br_port) &&
+			     memcmp(skb->data + ETH_ALEN, priv->br_mac, ETH_ALEN))) {
+				mac_clone(priv, skb->data + ETH_ALEN);
+				priv->macclone_completed = 1;
+			}
+		}
+	}
+
+	return 0;
+}
+#endif /* 0 */
+
+#define SERVER_PORT			67
+#define CLIENT_PORT			68
+#define DHCP_MAGIC			0x63825363
+#define BROADCAST_FLAG		0x8000
+
+struct dhcpMessage {
+	u_int8_t op;
+	u_int8_t htype;
+	u_int8_t hlen;
+	u_int8_t hops;
+	u_int32_t xid;
+	u_int16_t secs;
+	u_int16_t flags;
+	u_int32_t ciaddr;
+	u_int32_t yiaddr;
+	u_int32_t siaddr;
+	u_int32_t giaddr;
+	u_int8_t chaddr[16];
+	u_int8_t sname[64];
+	u_int8_t file[128];
+	u_int32_t cookie;
+	u_int8_t options[308]; /* 312 - cookie */
+};
+
+void dhcp_flag_bcast(_adapter *priv, struct sk_buff *skb)
+{
+	if (skb == NULL)
+		return;
+
+	if (!priv->ethBrExtInfo.dhcp_bcst_disable) {
+		unsigned short protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN));
+
+		if (protocol == __constant_htons(ETH_P_IP)) { /* IP */
+			struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+			if (iph->protocol == IPPROTO_UDP) { /* UDP */
+				struct udphdr *udph = (struct udphdr *)((SIZE_PTR)iph + (iph->ihl << 2));
+
+				if ((udph->source == __constant_htons(CLIENT_PORT))
+				    && (udph->dest == __constant_htons(SERVER_PORT))) { /* DHCP request */
+					struct dhcpMessage *dhcph =
+						(struct dhcpMessage *)((SIZE_PTR)udph + sizeof(struct udphdr));
+
+					if (dhcph->cookie == __constant_htonl(DHCP_MAGIC)) { /* match magic word */
+						if (!(dhcph->flags & htons(BROADCAST_FLAG))) { /* if not broadcast */
+							register int sum = 0;
+
+							RTW_INFO("DHCP: change flag of DHCP request to broadcast.\n");
+							/* or BROADCAST flag */
+							dhcph->flags |= htons(BROADCAST_FLAG);
+							/* recalculate checksum */
+							sum = ~(udph->check) & 0xffff;
+							sum += dhcph->flags;
+							while (sum >> 16)
+								sum = (sum & 0xffff) + (sum >> 16);
+							udph->check = ~sum;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+
+void *scdb_findEntry(_adapter *priv, unsigned char *macAddr,
+		     unsigned char *ipAddr)
+{
+	unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+	struct nat25_network_db_entry *db;
+	int hash;
+	/* _irqL irqL; */
+	/* _enter_critical_bh(&priv->br_ext_lock, &irqL); */
+
+	__nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr);
+	hash = __nat25_network_hash(networkAddr);
+	db = priv->nethash[hash];
+	while (db != NULL) {
+		if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+			/* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+			return (void *)db;
+		}
+
+		db = db->next_hash;
+	}
+
+	/* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+	return NULL;
+}
+
+#endif /* CONFIG_BR_EXT */
diff --git a/core/rtw_bt_mp.c b/core/rtw_bt_mp.c
new file mode 100644
index 0000000..9b4fc24
--- /dev/null
+++ b/core/rtw_bt_mp.c
@@ -0,0 +1,1575 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2017 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ *****************************************************************************/
+
+
+#include <drv_types.h>
+#include <rtw_bt_mp.h>
+
+#if defined(CONFIG_RTL8723B)
+	#include <rtl8723b_hal.h>
+#endif
+
+#if defined(CONFIG_RTL8723B) || defined(CONFIG_RTL8821A)
+void MPh2c_timeout_handle(void *FunctionContext)
+{
+	PADAPTER pAdapter;
+	PMPT_CONTEXT pMptCtx;
+
+
+	RTW_INFO("[MPT], MPh2c_timeout_handle\n");
+
+	pAdapter = (PADAPTER)FunctionContext;
+	pMptCtx = &pAdapter->mppriv.mpt_ctx;
+
+	pMptCtx->bMPh2c_timeout = _TRUE;
+
+	if ((_FALSE == pMptCtx->MptH2cRspEvent)
+	    || ((_TRUE == pMptCtx->MptH2cRspEvent)
+		&& (_FALSE == pMptCtx->MptBtC2hEvent)))
+		_rtw_up_sema(&pMptCtx->MPh2c_Sema);
+}
+
+u32 WaitC2Hevent(PADAPTER pAdapter, u8 *C2H_event, u32 delay_time)
+{
+	PMPT_CONTEXT		pMptCtx = &(pAdapter->mppriv.mpt_ctx);
+	pMptCtx->bMPh2c_timeout = _FALSE;
+
+	if (pAdapter->registrypriv.mp_mode == 0) {
+		RTW_INFO("[MPT], Error!! WaitC2Hevent mp_mode == 0!!\n");
+		return _FALSE;
+	}
+
+	_set_timer(&pMptCtx->MPh2c_timeout_timer, delay_time);
+
+	_rtw_down_sema(&pMptCtx->MPh2c_Sema);
+
+	if (pMptCtx->bMPh2c_timeout == _TRUE) {
+		*C2H_event = _FALSE;
+
+		return _FALSE;
+	}
+
+	/* for safty, cancel timer here again */
+	_cancel_timer_ex(&pMptCtx->MPh2c_timeout_timer);
+
+	return _TRUE;
+}
+
+BT_CTRL_STATUS
+mptbt_CheckC2hFrame(
+	PADAPTER		Adapter,
+	PBT_H2C			pH2c,
+	PBT_EXT_C2H		pExtC2h
+)
+{
+	BT_CTRL_STATUS	c2hStatus = BT_STATUS_C2H_SUCCESS;
+
+	/* RTW_INFO("[MPT], MPT rsp C2H hex: %x %x %x  %x %x %x\n"), pExtC2h , pExtC2h+1 ,pExtC2h+2 ,pExtC2h+3 ,pExtC2h+4 ,pExtC2h+5); */
+
+	RTW_INFO("[MPT], statusCode = 0x%x\n", pExtC2h->statusCode);
+	RTW_INFO("[MPT], retLen = %d\n", pExtC2h->retLen);
+	RTW_INFO("[MPT], opCodeVer : req/rsp=%d/%d\n", pH2c->opCodeVer, pExtC2h->opCodeVer);
+	RTW_INFO("[MPT], reqNum : req/rsp=%d/%d\n", pH2c->reqNum, pExtC2h->reqNum);
+	if (pExtC2h->reqNum != pH2c->reqNum) {
+		c2hStatus = BT_STATUS_C2H_REQNUM_MISMATCH;
+		RTW_INFO("[MPT], Error!! C2H reqNum Mismatch!!\n");
+	} else if (pExtC2h->opCodeVer != pH2c->opCodeVer) {
+		c2hStatus = BT_STATUS_OPCODE_L_VERSION_MISMATCH;
+		RTW_INFO("[MPT], Error!! OPCode version L mismatch!!\n");
+	}
+
+	return c2hStatus;
+}
+
+BT_CTRL_STATUS
+mptbt_SendH2c(
+	PADAPTER	Adapter,
+	PBT_H2C	pH2c,
+	u2Byte		h2cCmdLen
+)
+{
+	/* KIRQL				OldIrql = KeGetCurrentIrql(); */
+	BT_CTRL_STATUS	h2cStatus = BT_STATUS_H2C_SUCCESS;
+	PMPT_CONTEXT		pMptCtx = &(Adapter->mppriv.mpt_ctx);
+	u1Byte				i;
+
+	RTW_INFO("[MPT], mptbt_SendH2c()=========>\n");
+
+	/* PlatformResetEvent(&pMptCtx->MptH2cRspEvent); */
+	/* PlatformResetEvent(&pMptCtx->MptBtC2hEvent); */
+
+	/*	if(OldIrql == PASSIVE_LEVEL)
+	 *	{ */
+	/* RTPRINT_DATA(FMPBT, FMPBT_H2C_CONTENT, ("[MPT], MPT H2C hex:\n"), pH2c, h2cCmdLen); */
+
+	for (i = 0; i < BT_H2C_MAX_RETRY; i++) {
+		RTW_INFO("[MPT], Send H2C command to wifi!!!\n");
+
+		pMptCtx->MptH2cRspEvent = _FALSE;
+		pMptCtx->MptBtC2hEvent = _FALSE;
+
+#if defined(CONFIG_RTL8723B)
+		rtl8723b_set_FwBtMpOper_cmd(Adapter, pH2c->opCode, pH2c->opCodeVer, pH2c->reqNum, pH2c->buf);
+#endif
+		pMptCtx->h2cReqNum++;
+		pMptCtx->h2cReqNum %= 16;
+
+		if (WaitC2Hevent(Adapter, &pMptCtx->MptH2cRspEvent, 100)) {
+			RTW_INFO("[MPT], Received WiFi MptH2cRspEvent!!!\n");
+			if (WaitC2Hevent(Adapter, &pMptCtx->MptBtC2hEvent, 400)) {
+				RTW_INFO("[MPT], Received MptBtC2hEvent!!!\n");
+				break;
+			} else {
+				RTW_INFO("[MPT], Error!!BT MptBtC2hEvent timeout!!\n");
+				h2cStatus = BT_STATUS_H2C_BT_NO_RSP;
+			}
+		} else {
+			RTW_INFO("[MPT], Error!!WiFi  MptH2cRspEvent timeout!!\n");
+			h2cStatus = BT_STATUS_H2C_TIMTOUT;
+		}
+	}
+	/*	}
+	 *	else
+	 *	{
+	 * 		RT_ASSERT(FALSE, ("[MPT],  mptbt_SendH2c() can only run under PASSIVE_LEVEL!!\n"));
+	 *		h2cStatus = BT_STATUS_WRONG_LEVEL;
+	 *	} */
+
+	RTW_INFO("[MPT], mptbt_SendH2c()<=========\n");
+	return h2cStatus;
+}
+
+
+
+BT_CTRL_STATUS
+mptbt_CheckBtRspStatus(
+	PADAPTER			Adapter,
+	PBT_EXT_C2H			pExtC2h
+)
+{
+	BT_CTRL_STATUS	retStatus = BT_OP_STATUS_SUCCESS;
+
+	switch (pExtC2h->statusCode) {
+	case BT_OP_STATUS_SUCCESS:
+		retStatus = BT_STATUS_BT_OP_SUCCESS;
+		RTW_INFO("[MPT], BT status : BT_STATUS_SUCCESS\n");
+		break;
+	case BT_OP_STATUS_VERSION_MISMATCH:
+		retStatus = BT_STATUS_OPCODE_L_VERSION_MISMATCH;
+		RTW_INFO("[MPT], BT status : BT_STATUS_OPCODE_L_VERSION_MISMATCH\n");
+		break;
+	case BT_OP_STATUS_UNKNOWN_OPCODE:
+		retStatus = BT_STATUS_UNKNOWN_OPCODE_L;
+		RTW_INFO("[MPT], BT status : BT_STATUS_UNKNOWN_OPCODE_L\n");
+		break;
+	case BT_OP_STATUS_ERROR_PARAMETER:
+		retStatus = BT_STATUS_PARAMETER_FORMAT_ERROR_L;
+		RTW_INFO("[MPT], BT status : BT_STATUS_PARAMETER_FORMAT_ERROR_L\n");
+		break;
+	default:
+		retStatus = BT_STATUS_UNKNOWN_STATUS_L;
+		RTW_INFO("[MPT], BT status : BT_STATUS_UNKNOWN_STATUS_L\n");
+		break;
+	}
+
+	return retStatus;
+}
+
+
+
+BT_CTRL_STATUS
+mptbt_BtFwOpCodeProcess(
+	PADAPTER		Adapter,
+	u1Byte			btFwOpCode,
+	u1Byte			opCodeVer,
+	pu1Byte			pH2cPar,
+	u1Byte			h2cParaLen
+)
+{
+	u1Byte				H2C_Parameter[6] = {0};
+	PBT_H2C				pH2c = (PBT_H2C)&H2C_Parameter[0];
+	PMPT_CONTEXT		pMptCtx = &(Adapter->mppriv.mpt_ctx);
+	PBT_EXT_C2H			pExtC2h = (PBT_EXT_C2H)&pMptCtx->c2hBuf[0];
+	u2Byte				paraLen = 0, i;
+	BT_CTRL_STATUS	h2cStatus = BT_STATUS_H2C_SUCCESS, c2hStatus = BT_STATUS_C2H_SUCCESS;
+	BT_CTRL_STATUS	retStatus = BT_STATUS_H2C_BT_NO_RSP;
+
+	if (Adapter->registrypriv.mp_mode == 0) {
+		RTW_INFO("[MPT], Error!! mptbt_BtFwOpCodeProces mp_mode == 0!!\n");
+		return _FALSE;
+	}
+
+	pH2c->opCode = btFwOpCode;
+	pH2c->opCodeVer = opCodeVer;
+	pH2c->reqNum = pMptCtx->h2cReqNum;
+	/* PlatformMoveMemory(&pH2c->buf[0], pH2cPar, h2cParaLen); */
+	/* _rtw_memcpy(&pH2c->buf[0], pH2cPar, h2cParaLen); */
+	_rtw_memcpy(pH2c->buf, pH2cPar, h2cParaLen);
+
+	RTW_INFO("[MPT], pH2c->opCode=%d\n", pH2c->opCode);
+	RTW_INFO("[MPT], pH2c->opCodeVer=%d\n", pH2c->opCodeVer);
+	RTW_INFO("[MPT], pH2c->reqNum=%d\n", pH2c->reqNum);
+	RTW_INFO("[MPT], h2c parameter length=%d\n", h2cParaLen);
+	for (i = 0; i < h2cParaLen; i++)
+		RTW_INFO("[MPT], parameter[%d]=0x%02x\n", i, pH2c->buf[i]);
+
+	h2cStatus = mptbt_SendH2c(Adapter, pH2c, h2cParaLen + 2);
+	if (BT_STATUS_H2C_SUCCESS == h2cStatus) {
+		/* if reach here, it means H2C get the correct c2h response, */
+		c2hStatus = mptbt_CheckC2hFrame(Adapter, pH2c, pExtC2h);
+		if (BT_STATUS_C2H_SUCCESS == c2hStatus)
+			retStatus = mptbt_CheckBtRspStatus(Adapter, pExtC2h);
+		else {
+			RTW_INFO("[MPT], Error!! C2H failed for pH2c->opCode=%d\n", pH2c->opCode);
+			/* check c2h status error, return error status code to upper layer. */
+			retStatus = c2hStatus;
+		}
+	} else {
+		RTW_INFO("[MPT], Error!! H2C failed for pH2c->opCode=%d\n", pH2c->opCode);
+		/* check h2c status error, return error status code to upper layer. */
+		retStatus = h2cStatus;
+	}
+
+	return retStatus;
+}
+
+
+
+
+u2Byte
+mptbt_BtReady(
+	PADAPTER		Adapter,
+	PBT_REQ_CMD	pBtReq,
+	PBT_RSP_CMD	pBtRsp
+)
+{
+	u1Byte				h2cParaBuf[6] = {0};
+	u1Byte				h2cParaLen = 0;
+	u2Byte				paraLen = 0;
+	u1Byte				retStatus = BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer = 0;
+	PMPT_CONTEXT		pMptCtx = &(Adapter->mppriv.mpt_ctx);
+	PBT_EXT_C2H			pExtC2h = (PBT_EXT_C2H)&pMptCtx->c2hBuf[0];
+	u1Byte				i;
+	u1Byte				btFwVer = 0, bdAddr[6] = {0};
+	u2Byte				btRealFwVer = 0;
+	pu2Byte			pu2Tmp = NULL;
+
+	/*  */
+	/* check upper layer parameters */
+	/*  */
+
+	/* 1. check upper layer opcode version */
+	if (pBtReq->opCodeVer != 1) {
+		RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+
+	pBtRsp->pParamStart[0] = MP_BT_NOT_READY;
+	paraLen = 10;
+	/*  */
+	/* execute lower layer opcodes */
+	/*  */
+
+	/* Get BT FW version */
+	/* fill h2c parameters */
+	btOpcode = BT_LO_OP_GET_BT_VERSION;
+	/* execute h2c and check respond c2h from bt fw is correct or not */
+	retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	} else {
+		pu2Tmp = (pu2Byte)&pExtC2h->buf[0];
+		btRealFwVer = *pu2Tmp;
+		btFwVer = pExtC2h->buf[1];
+		RTW_INFO("[MPT], btRealFwVer=0x%x, btFwVer=0x%x\n", btRealFwVer, btFwVer);
+	}
+
+	/* Get BD Address */
+	/* fill h2c parameters */
+	btOpcode = BT_LO_OP_GET_BD_ADDR_L;
+	/* execute h2c and check respond c2h from bt fw is correct or not */
+	retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	} else {
+		bdAddr[5] = pExtC2h->buf[0];
+		bdAddr[4] = pExtC2h->buf[1];
+		bdAddr[3] = pExtC2h->buf[2];
+	}
+
+	/* fill h2c parameters */
+	btOpcode = BT_LO_OP_GET_BD_ADDR_H;
+	/* execute h2c and check respond c2h from bt fw is correct or not */
+	retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	} else {
+		bdAddr[2] = pExtC2h->buf[0];
+		bdAddr[1] = pExtC2h->buf[1];
+		bdAddr[0] = pExtC2h->buf[2];
+	}
+	RTW_INFO("[MPT], Local BDAddr:");
+	for (i = 0; i < 6; i++)
+		RTW_INFO(" 0x%x ", bdAddr[i]);
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	pBtRsp->pParamStart[0] = MP_BT_READY;
+	pu2Tmp = (pu2Byte)&pBtRsp->pParamStart[1];
+	*pu2Tmp = btRealFwVer;
+	pBtRsp->pParamStart[3] = btFwVer;
+	for (i = 0; i < 6; i++)
+		pBtRsp->pParamStart[4 + i] = bdAddr[5 - i];
+
+	return paraLen;
+}
+
+void mptbt_close_WiFiRF(PADAPTER Adapter)
+{
+	phy_set_bb_reg(Adapter, 0x824, 0xF, 0x0);
+	phy_set_bb_reg(Adapter, 0x824, 0x700000, 0x0);
+	phy_set_rf_reg(Adapter, RF_PATH_A, 0x0, 0xF0000, 0x0);
+}
+
+void mptbt_open_WiFiRF(PADAPTER	Adapter)
+{
+	phy_set_bb_reg(Adapter, 0x824, 0x700000, 0x3);
+	phy_set_bb_reg(Adapter, 0x824, 0xF, 0x2);
+	phy_set_rf_reg(Adapter, RF_PATH_A, 0x0, 0xF0000, 0x3);
+}
+
+u4Byte mptbt_switch_RF(PADAPTER	Adapter, u1Byte	Enter)
+{
+	u2Byte	tmp_2byte = 0;
+
+	/* Enter test mode */
+	if (Enter) {
+		/* 1>. close WiFi RF */
+		mptbt_close_WiFiRF(Adapter);
+
+		/* 2>. change ant switch to BT */
+		tmp_2byte = rtw_read16(Adapter, 0x860);
+		tmp_2byte = tmp_2byte | BIT(9);
+		tmp_2byte = tmp_2byte & (~BIT(8));
+		rtw_write16(Adapter, 0x860, tmp_2byte);
+		rtw_write16(Adapter, 0x870, 0x300);
+	} else {
+		/* 1>. Open WiFi RF */
+		mptbt_open_WiFiRF(Adapter);
+
+		/* 2>. change ant switch back */
+		tmp_2byte = rtw_read16(Adapter, 0x860);
+		tmp_2byte = tmp_2byte | BIT(8);
+		tmp_2byte = tmp_2byte & (~BIT(9));
+		rtw_write16(Adapter, 0x860, tmp_2byte);
+		rtw_write16(Adapter, 0x870, 0x300);
+	}
+
+	return 0;
+}
+
+u2Byte
+mptbt_BtSetMode(
+	PADAPTER		Adapter,
+	PBT_REQ_CMD	pBtReq,
+	PBT_RSP_CMD	pBtRsp
+)
+{
+	u1Byte				h2cParaBuf[6] = {0};
+	u1Byte				h2cParaLen = 0;
+	u2Byte				paraLen = 0;
+	u1Byte				retStatus = BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer = 0;
+	u1Byte				btModeToSet = 0;
+
+	/*  */
+	/* check upper layer parameters */
+	/*  */
+	/* 1. check upper layer opcode version */
+	if (pBtReq->opCodeVer != 1) {
+		RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+	/* 2. check upper layer parameter length */
+	if (1 == pBtReq->paraLength) {
+		btModeToSet = pBtReq->pParamStart[0];
+		RTW_INFO("[MPT], BtTestMode=%d\n", btModeToSet);
+	} else {
+		RTW_INFO("[MPT], Error!! wrong parameter length=%d (should be 1)\n", pBtReq->paraLength);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+
+	/*  */
+	/* execute lower layer opcodes */
+	/*  */
+
+	/* 1. fill h2c parameters	 */
+	/* check bt mode */
+	btOpcode = BT_LO_OP_SET_BT_MODE;
+	if (btModeToSet >= MP_BT_MODE_MAX) {
+		pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	} else {
+		mptbt_switch_RF(Adapter, 1);
+
+		h2cParaBuf[0] = btModeToSet;
+		h2cParaLen = 1;
+		/* 2. execute h2c and check respond c2h from bt fw is correct or not */
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+
+	/* 3. construct respond status code and data. */
+	if (BT_STATUS_BT_OP_SUCCESS == retStatus)
+		pBtRsp->status = BT_STATUS_SUCCESS;
+	else {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+	}
+
+	return paraLen;
+}
+
+
+VOID
+MPTBT_FwC2hBtMpCtrl(
+	PADAPTER	Adapter,
+	pu1Byte	tmpBuf,
+	u1Byte		length
+)
+{
+	u32 i;
+	PMPT_CONTEXT	pMptCtx = &(Adapter->mppriv.mpt_ctx);
+	PBT_EXT_C2H pExtC2h = (PBT_EXT_C2H)tmpBuf;
+
+	if (GET_HAL_DATA(Adapter)->bBTFWReady == _FALSE || Adapter->registrypriv.mp_mode == 0) {
+		/* RTW_INFO("Ignore C2H BT MP Info since not in MP mode\n"); */
+		return;
+	}
+	if (length > 32 || length < 3) {
+		RTW_INFO("\n [MPT], pExtC2h->buf hex: length=%d > 32 || < 3\n", length);
+		return;
+	}
+
+	/* cancel_timeout for h2c handle */
+	_cancel_timer_ex(&pMptCtx->MPh2c_timeout_timer);
+
+	for (i = 0; i < length; i++)
+		RTW_INFO("[MPT], %s, buf[%d]=0x%02x ", __FUNCTION__, i, tmpBuf[i]);
+	RTW_INFO("[MPT], pExtC2h->extendId=0x%x\n", pExtC2h->extendId);
+
+	switch (pExtC2h->extendId) {
+	case EXT_C2H_WIFI_FW_ACTIVE_RSP:
+		RTW_INFO("[MPT], EXT_C2H_WIFI_FW_ACTIVE_RSP\n");
+#if 0
+		RTW_INFO("[MPT], pExtC2h->buf hex:\n");
+		for (i = 0; i < (length - 3); i++)
+			RTW_INFO(" 0x%x ", pExtC2h->buf[i]);
+#endif
+		if ((_FALSE == pMptCtx->bMPh2c_timeout)
+		    && (_FALSE == pMptCtx->MptH2cRspEvent)) {
+			pMptCtx->MptH2cRspEvent = _TRUE;
+			_rtw_up_sema(&pMptCtx->MPh2c_Sema);
+		}
+		break;
+
+	case EXT_C2H_TRIG_BY_BT_FW:
+		RTW_INFO("[MPT], EXT_C2H_TRIG_BY_BT_FW\n");
+		_rtw_memcpy(&pMptCtx->c2hBuf[0], tmpBuf, length);
+		RTW_INFO("[MPT], pExtC2h->statusCode=0x%x\n", pExtC2h->statusCode);
+		RTW_INFO("[MPT], pExtC2h->retLen=0x%x\n", pExtC2h->retLen);
+		RTW_INFO("[MPT], pExtC2h->opCodeVer=0x%x\n", pExtC2h->opCodeVer);
+		RTW_INFO("[MPT], pExtC2h->reqNum=0x%x\n", pExtC2h->reqNum);
+		for (i = 0; i < (length - 3); i++)
+			RTW_INFO("[MPT], pExtC2h->buf[%d]=0x%02x\n", i, pExtC2h->buf[i]);
+
+		if ((_FALSE == pMptCtx->bMPh2c_timeout)
+		    && (_TRUE == pMptCtx->MptH2cRspEvent)
+		    && (_FALSE == pMptCtx->MptBtC2hEvent)) {
+			pMptCtx->MptBtC2hEvent = _TRUE;
+			_rtw_up_sema(&pMptCtx->MPh2c_Sema);
+		}
+		break;
+
+	default:
+		RTW_INFO("[MPT], EXT_C2H Target not found,pExtC2h->extendId =%d ,pExtC2h->reqNum=%d\n", pExtC2h->extendId, pExtC2h->reqNum);
+		break;
+	}
+
+
+
+}
+
+
+u2Byte
+mptbt_BtGetGeneral(
+	IN	PADAPTER		Adapter,
+	IN	PBT_REQ_CMD	pBtReq,
+	IN	PBT_RSP_CMD	pBtRsp
+)
+{
+	PMPT_CONTEXT		pMptCtx = &(Adapter->mppriv.mpt_ctx);
+	PBT_EXT_C2H		pExtC2h = (PBT_EXT_C2H)&pMptCtx->c2hBuf[0];
+	u1Byte				h2cParaBuf[6] = {0};
+	u1Byte				h2cParaLen = 0;
+	u2Byte				paraLen = 0;
+	u1Byte				retStatus = BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode, bdAddr[6] = {0};
+	u1Byte				btOpcodeVer = 0;
+	u1Byte				getType = 0, i;
+	u2Byte				getParaLen = 0, validParaLen = 0;
+	u1Byte				regType = 0, reportType = 0;
+	u4Byte				regAddr = 0, regValue = 0;
+	pu4Byte			pu4Tmp;
+	pu2Byte			pu2Tmp;
+	pu1Byte			pu1Tmp;
+
+	/*  */
+	/* check upper layer parameters */
+	/*  */
+
+	/* check upper layer opcode version */
+	if (pBtReq->opCodeVer != 1) {
+		RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+	/* check upper layer parameter length */
+	if (pBtReq->paraLength < 1) {
+		RTW_INFO("[MPT], Error!! wrong parameter length=%d (should larger than 1)\n", pBtReq->paraLength);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+	getParaLen = pBtReq->paraLength - 1;
+	getType = pBtReq->pParamStart[0];
+
+	RTW_INFO("[MPT], getType=%d, getParaLen=%d\n", getType, getParaLen);
+
+	/* check parameter first */
+	switch (getType) {
+	case BT_GGET_REG:
+		RTW_INFO("[MPT], [BT_GGET_REG]\n");
+		validParaLen = 5;
+		if (getParaLen == validParaLen) {
+			btOpcode = BT_LO_OP_READ_REG;
+			regType = pBtReq->pParamStart[1];
+			pu4Tmp = (pu4Byte)&pBtReq->pParamStart[2];
+			regAddr = *pu4Tmp;
+			RTW_INFO("[MPT], BT_GGET_REG regType=0x%02x, regAddr=0x%08x!!\n",
+				 regType, regAddr);
+			if (regType >= BT_REG_MAX) {
+				pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+				return paraLen;
+			} else {
+				if (((BT_REG_RF == regType) && (regAddr > 0x7f)) ||
+				    ((BT_REG_MODEM == regType) && (regAddr > 0x1ff)) ||
+				    ((BT_REG_BLUEWIZE == regType) && (regAddr > 0xfff)) ||
+				    ((BT_REG_VENDOR == regType) && (regAddr > 0xfff)) ||
+				    ((BT_REG_LE == regType) && (regAddr > 0xfff))) {
+					pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+					return paraLen;
+				}
+			}
+		}
+		break;
+	case BT_GGET_STATUS:
+		RTW_INFO("[MPT], [BT_GGET_STATUS]\n");
+		validParaLen = 0;
+		break;
+	case BT_GGET_REPORT:
+		RTW_INFO("[MPT], [BT_GGET_REPORT]\n");
+		validParaLen = 1;
+		if (getParaLen == validParaLen) {
+			reportType = pBtReq->pParamStart[1];
+			RTW_INFO("[MPT], BT_GGET_REPORT reportType=0x%x!!\n", reportType);
+			if (reportType >= BT_REPORT_MAX) {
+				pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+				return paraLen;
+			}
+		}
+		break;
+	default: {
+		RTW_INFO("[MPT], Error!! getType=%d, out of range\n", getType);
+		pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	break;
+	}
+	if (getParaLen != validParaLen) {
+		RTW_INFO("[MPT], Error!! wrong parameter length=%d for BT_GET_GEN_CMD cmd id=0x%x, paraLen should=0x%x\n",
+			 getParaLen, getType, validParaLen);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+
+	/*  */
+	/* execute lower layer opcodes */
+	/*  */
+	if (BT_GGET_REG == getType) {
+		/* fill h2c parameters */
+		/* here we should write reg value first then write the address, adviced by Austin */
+		btOpcode = BT_LO_OP_READ_REG;
+		h2cParaBuf[0] = regType;
+		h2cParaBuf[1] = pBtReq->pParamStart[2];
+		h2cParaBuf[2] = pBtReq->pParamStart[3];
+		h2cParaLen = 3;
+		/* execute h2c and check respond c2h from bt fw is correct or not */
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* construct respond status code and data. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+
+		pu2Tmp = (pu2Byte)&pExtC2h->buf[0];
+		regValue = *pu2Tmp;
+		RTW_INFO("[MPT], read reg regType=0x%02x, regAddr=0x%08x, regValue=0x%04x\n",
+			 regType, regAddr, regValue);
+
+		pu4Tmp = (pu4Byte)&pBtRsp->pParamStart[0];
+		*pu4Tmp = regValue;
+		paraLen = 4;
+	} else if (BT_GGET_STATUS == getType) {
+		btOpcode = BT_LO_OP_GET_BT_STATUS;
+		h2cParaLen = 0;
+		/* execute h2c and check respond c2h from bt fw is correct or not */
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* construct respond status code and data. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+
+		pBtRsp->pParamStart[0] = pExtC2h->buf[0];
+		pBtRsp->pParamStart[1] = pExtC2h->buf[1];
+		RTW_INFO("[MPT], read bt status, testMode=0x%x, testStatus=0x%x\n",
+			 pBtRsp->pParamStart[0], pBtRsp->pParamStart[1]);
+		paraLen = 2;
+	} else if (BT_GGET_REPORT == getType) {
+		switch (reportType) {
+		case BT_REPORT_RX_PACKET_CNT: {
+			RTW_INFO("[MPT], [Rx Packet Counts]\n");
+			btOpcode = BT_LO_OP_GET_RX_PKT_CNT_L;
+			h2cParaLen = 0;
+			/* execute h2c and check respond c2h from bt fw is correct or not */
+			retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+			/* construct respond status code and data. */
+			if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+				pBtRsp->status = ((btOpcode << 8) | retStatus);
+				RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+				return paraLen;
+			}
+			pBtRsp->pParamStart[0] = pExtC2h->buf[0];
+			pBtRsp->pParamStart[1] = pExtC2h->buf[1];
+
+			btOpcode = BT_LO_OP_GET_RX_PKT_CNT_H;
+			h2cParaLen = 0;
+			/* execute h2c and check respond c2h from bt fw is correct or not */
+			retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+			/* construct respond status code and data. */
+			if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+				pBtRsp->status = ((btOpcode << 8) | retStatus);
+				RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+				return paraLen;
+			}
+			pBtRsp->pParamStart[2] = pExtC2h->buf[0];
+			pBtRsp->pParamStart[3] = pExtC2h->buf[1];
+			paraLen = 4;
+		}
+		break;
+		case BT_REPORT_RX_ERROR_BITS: {
+			RTW_INFO("[MPT], [Rx Error Bits]\n");
+			btOpcode = BT_LO_OP_GET_RX_ERROR_BITS_L;
+			h2cParaLen = 0;
+			/* execute h2c and check respond c2h from bt fw is correct or not */
+			retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+			/* construct respond status code and data. */
+			if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+				pBtRsp->status = ((btOpcode << 8) | retStatus);
+				RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+				return paraLen;
+			}
+			pBtRsp->pParamStart[0] = pExtC2h->buf[0];
+			pBtRsp->pParamStart[1] = pExtC2h->buf[1];
+
+			btOpcode = BT_LO_OP_GET_RX_ERROR_BITS_H;
+			h2cParaLen = 0;
+			/* execute h2c and check respond c2h from bt fw is correct or not */
+			retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+			/* construct respond status code and data. */
+			if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+				pBtRsp->status = ((btOpcode << 8) | retStatus);
+				RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+				return paraLen;
+			}
+			pBtRsp->pParamStart[2] = pExtC2h->buf[0];
+			pBtRsp->pParamStart[3] = pExtC2h->buf[1];
+			paraLen = 4;
+		}
+		break;
+		case BT_REPORT_RSSI: {
+			RTW_INFO("[MPT], [RSSI]\n");
+			btOpcode = BT_LO_OP_GET_RSSI;
+			h2cParaLen = 0;
+			/* execute h2c and check respond c2h from bt fw is correct or not */
+			retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+			/* construct respond status code and data. */
+			if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+				pBtRsp->status = ((btOpcode << 8) | retStatus);
+				RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+				return paraLen;
+			}
+			pBtRsp->pParamStart[0] = pExtC2h->buf[0];
+			pBtRsp->pParamStart[1] = pExtC2h->buf[1];
+			paraLen = 2;
+		}
+		break;
+		case BT_REPORT_CFO_HDR_QUALITY: {
+			RTW_INFO("[MPT], [CFO & Header Quality]\n");
+			btOpcode = BT_LO_OP_GET_CFO_HDR_QUALITY_L;
+			h2cParaLen = 0;
+			/* execute h2c and check respond c2h from bt fw is correct or not */
+			retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+			/* construct respond status code and data. */
+			if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+				pBtRsp->status = ((btOpcode << 8) | retStatus);
+				RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+				return paraLen;
+			}
+			pBtRsp->pParamStart[0] = pExtC2h->buf[0];
+			pBtRsp->pParamStart[1] = pExtC2h->buf[1];
+
+			btOpcode = BT_LO_OP_GET_CFO_HDR_QUALITY_H;
+			h2cParaLen = 0;
+			/* execute h2c and check respond c2h from bt fw is correct or not */
+			retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+			/* construct respond status code and data. */
+			if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+				pBtRsp->status = ((btOpcode << 8) | retStatus);
+				RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+				return paraLen;
+			}
+			pBtRsp->pParamStart[2] = pExtC2h->buf[0];
+			pBtRsp->pParamStart[3] = pExtC2h->buf[1];
+			paraLen = 4;
+		}
+		break;
+		case BT_REPORT_CONNECT_TARGET_BD_ADDR: {
+			RTW_INFO("[MPT], [Connected Target BD ADDR]\n");
+			btOpcode = BT_LO_OP_GET_TARGET_BD_ADDR_L;
+			h2cParaLen = 0;
+			/* execute h2c and check respond c2h from bt fw is correct or not */
+			retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+			/* construct respond status code and data. */
+			if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+				pBtRsp->status = ((btOpcode << 8) | retStatus);
+				RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+				return paraLen;
+			}
+			bdAddr[5] = pExtC2h->buf[0];
+			bdAddr[4] = pExtC2h->buf[1];
+			bdAddr[3] = pExtC2h->buf[2];
+
+			btOpcode = BT_LO_OP_GET_TARGET_BD_ADDR_H;
+			h2cParaLen = 0;
+			/* execute h2c and check respond c2h from bt fw is correct or not */
+			retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+			/* construct respond status code and data. */
+			if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+				pBtRsp->status = ((btOpcode << 8) | retStatus);
+				RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+				return paraLen;
+			}
+			bdAddr[2] = pExtC2h->buf[0];
+			bdAddr[1] = pExtC2h->buf[1];
+			bdAddr[0] = pExtC2h->buf[2];
+
+			RTW_INFO("[MPT], Connected Target BDAddr:%s", bdAddr);
+			for (i = 0; i < 6; i++)
+				pBtRsp->pParamStart[i] = bdAddr[5 - i];
+			paraLen = 6;
+		}
+		break;
+		default:
+			pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+			return paraLen;
+			break;
+		}
+	}
+
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	return paraLen;
+}
+
+
+
+u2Byte
+mptbt_BtSetGeneral(
+	IN	PADAPTER		Adapter,
+	IN	PBT_REQ_CMD	pBtReq,
+	IN	PBT_RSP_CMD	pBtRsp
+)
+{
+	u1Byte				h2cParaBuf[6] = {0};
+	u1Byte				h2cParaLen = 0;
+	u2Byte				paraLen = 0;
+	u1Byte				retStatus = BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer = 0;
+	u1Byte				setType = 0;
+	u2Byte				setParaLen = 0, validParaLen = 0;
+	u1Byte				regType = 0, bdAddr[6] = {0}, calVal = 0;
+	u4Byte				regAddr = 0, regValue = 0;
+	pu4Byte			pu4Tmp;
+	pu2Byte			pu2Tmp;
+	pu1Byte			pu1Tmp;
+
+	/*  */
+	/* check upper layer parameters */
+	/*  */
+
+	/* check upper layer opcode version */
+	if (pBtReq->opCodeVer != 1) {
+		RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+	/* check upper layer parameter length */
+	if (pBtReq->paraLength < 1) {
+		RTW_INFO("[MPT], Error!! wrong parameter length=%d (should larger than 1)\n", pBtReq->paraLength);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+	setParaLen = pBtReq->paraLength - 1;
+	setType = pBtReq->pParamStart[0];
+
+	RTW_INFO("[MPT], setType=%d, setParaLen=%d\n", setType, setParaLen);
+
+	/* check parameter first */
+	switch (setType) {
+	case BT_GSET_REG:
+		RTW_INFO("[MPT], [BT_GSET_REG]\n");
+		validParaLen = 9;
+		if (setParaLen == validParaLen) {
+			btOpcode = BT_LO_OP_WRITE_REG_VALUE;
+			regType = pBtReq->pParamStart[1];
+			pu4Tmp = (pu4Byte)&pBtReq->pParamStart[2];
+			regAddr = *pu4Tmp;
+			pu4Tmp = (pu4Byte)&pBtReq->pParamStart[6];
+			regValue = *pu4Tmp;
+			RTW_INFO("[MPT], BT_GSET_REG regType=0x%x, regAddr=0x%x, regValue=0x%x!!\n",
+				 regType, regAddr, regValue);
+			if (regType >= BT_REG_MAX) {
+				pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+				return paraLen;
+			} else {
+				if (((BT_REG_RF == regType) && (regAddr > 0x7f)) ||
+				    ((BT_REG_MODEM == regType) && (regAddr > 0x1ff)) ||
+				    ((BT_REG_BLUEWIZE == regType) && (regAddr > 0xfff)) ||
+				    ((BT_REG_VENDOR == regType) && (regAddr > 0xfff)) ||
+				    ((BT_REG_LE == regType) && (regAddr > 0xfff))) {
+					pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+					return paraLen;
+				}
+			}
+		}
+		break;
+	case BT_GSET_RESET:
+		RTW_INFO("[MPT], [BT_GSET_RESET]\n");
+		validParaLen = 0;
+		break;
+	case BT_GSET_TARGET_BD_ADDR:
+		RTW_INFO("[MPT], [BT_GSET_TARGET_BD_ADDR]\n");
+		validParaLen = 6;
+		if (setParaLen == validParaLen) {
+			btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_H;
+			if ((pBtReq->pParamStart[1] == 0) &&
+			    (pBtReq->pParamStart[2] == 0) &&
+			    (pBtReq->pParamStart[3] == 0) &&
+			    (pBtReq->pParamStart[4] == 0) &&
+			    (pBtReq->pParamStart[5] == 0) &&
+			    (pBtReq->pParamStart[6] == 0)) {
+				RTW_INFO("[MPT], Error!! targetBDAddr=all zero\n");
+				pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+				return paraLen;
+			}
+			if ((pBtReq->pParamStart[1] == 0xff) &&
+			    (pBtReq->pParamStart[2] == 0xff) &&
+			    (pBtReq->pParamStart[3] == 0xff) &&
+			    (pBtReq->pParamStart[4] == 0xff) &&
+			    (pBtReq->pParamStart[5] == 0xff) &&
+			    (pBtReq->pParamStart[6] == 0xff)) {
+				RTW_INFO("[MPT], Error!! targetBDAddr=all 0xf\n");
+				pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+				return paraLen;
+			}
+			bdAddr[0] = pBtReq->pParamStart[6];
+			bdAddr[1] = pBtReq->pParamStart[5];
+			bdAddr[2] = pBtReq->pParamStart[4];
+			bdAddr[3] = pBtReq->pParamStart[3];
+			bdAddr[4] = pBtReq->pParamStart[2];
+			bdAddr[5] = pBtReq->pParamStart[1];
+			RTW_INFO("[MPT], target BDAddr:%x,%x,%x,%x,%x,%x\n",
+				bdAddr[0], bdAddr[1], bdAddr[2], bdAddr[3], bdAddr[4], bdAddr[5]);
+		}
+		break;
+	case BT_GSET_TX_PWR_FINETUNE:
+		RTW_INFO("[MPT], [BT_GSET_TX_PWR_FINETUNE]\n");
+		validParaLen = 1;
+		if (setParaLen == validParaLen) {
+			btOpcode = BT_LO_OP_SET_TX_POWER_CALIBRATION;
+			calVal = pBtReq->pParamStart[1];
+			if ((calVal < 1) || (calVal > 9)) {
+				pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+				return paraLen;
+			}
+			RTW_INFO("[MPT], calVal=%d\n", calVal);
+		}
+		break;
+	case BT_SET_TRACKING_INTERVAL:
+		RTW_INFO("[MPT], [BT_SET_TRACKING_INTERVAL] setParaLen =%d\n", setParaLen);
+
+		validParaLen = 1;
+		if (setParaLen == validParaLen)
+			calVal = pBtReq->pParamStart[1];
+		break;
+	case BT_SET_THERMAL_METER:
+		RTW_INFO("[MPT], [BT_SET_THERMAL_METER] setParaLen =%d\n", setParaLen);
+		validParaLen = 1;
+		if (setParaLen == validParaLen)
+			calVal = pBtReq->pParamStart[1];
+		break;
+	case BT_ENABLE_CFO_TRACKING:
+		RTW_INFO("[MPT], [BT_ENABLE_CFO_TRACKING] setParaLen =%d\n", setParaLen);
+		validParaLen = 1;
+		if (setParaLen == validParaLen)
+			calVal = pBtReq->pParamStart[1];
+		break;
+	case BT_GSET_UPDATE_BT_PATCH:
+
+		break;
+	default: {
+		RTW_INFO("[MPT], Error!! setType=%d, out of range\n", setType);
+		pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	break;
+	}
+	if (setParaLen != validParaLen) {
+		RTW_INFO("[MPT], Error!! wrong parameter length=%d for BT_SET_GEN_CMD cmd id=0x%x, paraLen should=0x%x\n",
+			 setParaLen, setType, validParaLen);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+
+	/*  */
+	/* execute lower layer opcodes */
+	/*  */
+	if (BT_GSET_REG == setType) {
+		/* fill h2c parameters */
+		/* here we should write reg value first then write the address, adviced by Austin */
+		btOpcode = BT_LO_OP_WRITE_REG_VALUE;
+		h2cParaBuf[0] = pBtReq->pParamStart[6];
+		h2cParaBuf[1] = pBtReq->pParamStart[7];
+		h2cParaBuf[2] = pBtReq->pParamStart[8];
+		h2cParaLen = 3;
+		/* execute h2c and check respond c2h from bt fw is correct or not */
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* construct respond status code and data. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+
+		/* write reg address */
+		btOpcode = BT_LO_OP_WRITE_REG_ADDR;
+		h2cParaBuf[0] = regType;
+		h2cParaBuf[1] = pBtReq->pParamStart[2];
+		h2cParaBuf[2] = pBtReq->pParamStart[3];
+		h2cParaLen = 3;
+		/* execute h2c and check respond c2h from bt fw is correct or not */
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* construct respond status code and data. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+	} else if (BT_GSET_RESET == setType) {
+		btOpcode = BT_LO_OP_RESET;
+		h2cParaLen = 0;
+		/* execute h2c and check respond c2h from bt fw is correct or not */
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* construct respond status code and data. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+	} else if (BT_GSET_TARGET_BD_ADDR == setType) {
+		/* fill h2c parameters */
+		btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_L;
+		h2cParaBuf[0] = pBtReq->pParamStart[1];
+		h2cParaBuf[1] = pBtReq->pParamStart[2];
+		h2cParaBuf[2] = pBtReq->pParamStart[3];
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* ckeck bt return status. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+
+		btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_H;
+		h2cParaBuf[0] = pBtReq->pParamStart[4];
+		h2cParaBuf[1] = pBtReq->pParamStart[5];
+		h2cParaBuf[2] = pBtReq->pParamStart[6];
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* ckeck bt return status. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+	} else if (BT_GSET_TX_PWR_FINETUNE == setType) {
+		/* fill h2c parameters */
+		btOpcode = BT_LO_OP_SET_TX_POWER_CALIBRATION;
+		h2cParaBuf[0] = calVal;
+		h2cParaLen = 1;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* ckeck bt return status. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+	} else if (BT_SET_TRACKING_INTERVAL == setType) {
+		/*	BT_LO_OP_SET_TRACKING_INTERVAL								= 0x22, */
+		/*	BT_LO_OP_SET_THERMAL_METER									= 0x23, */
+		/*	BT_LO_OP_ENABLE_CFO_TRACKING									= 0x24, */
+		btOpcode = BT_LO_OP_SET_TRACKING_INTERVAL;
+		h2cParaBuf[0] = calVal;
+		h2cParaLen = 1;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* ckeck bt return status. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+	} else if (BT_SET_THERMAL_METER == setType) {
+		btOpcode = BT_LO_OP_SET_THERMAL_METER;
+		h2cParaBuf[0] = calVal;
+		h2cParaLen = 1;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* ckeck bt return status. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+	} else if (BT_ENABLE_CFO_TRACKING == setType) {
+		btOpcode = BT_LO_OP_ENABLE_CFO_TRACKING;
+		h2cParaBuf[0] = calVal;
+		h2cParaLen = 1;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		/* ckeck bt return status. */
+		if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+			pBtRsp->status = ((btOpcode << 8) | retStatus);
+			RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+			return paraLen;
+		}
+	}
+
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	return paraLen;
+}
+
+
+
+u2Byte
+mptbt_BtSetTxRxPars(
+	IN	PADAPTER		Adapter,
+	IN	PBT_REQ_CMD	pBtReq,
+	IN	PBT_RSP_CMD	pBtRsp
+)
+{
+	u1Byte				h2cParaBuf[6] = {0};
+	u1Byte				h2cParaLen = 0;
+	u2Byte				paraLen = 0;
+	u1Byte				retStatus = BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer = 0;
+	PBT_TXRX_PARAMETERS pTxRxPars = (PBT_TXRX_PARAMETERS)&pBtReq->pParamStart[0];
+	u2Byte				lenTxRx = sizeof(BT_TXRX_PARAMETERS);
+	u1Byte				i;
+	u1Byte				bdAddr[6] = {0};
+
+	/*  */
+	/* check upper layer parameters */
+	/*  */
+
+	/* 1. check upper layer opcode version */
+	if (pBtReq->opCodeVer != 1) {
+		RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+	/* 2. check upper layer parameter length */
+	if (pBtReq->paraLength == sizeof(BT_TXRX_PARAMETERS)) {
+		RTW_INFO("[MPT], pTxRxPars->txrxChannel=0x%x\n", pTxRxPars->txrxChannel);
+		RTW_INFO("[MPT], pTxRxPars->txrxTxPktCnt=0x%8x\n", pTxRxPars->txrxTxPktCnt);
+		RTW_INFO("[MPT], pTxRxPars->txrxTxPktInterval=0x%x\n", pTxRxPars->txrxTxPktInterval);
+		RTW_INFO("[MPT], pTxRxPars->txrxPayloadType=0x%x\n", pTxRxPars->txrxPayloadType);
+		RTW_INFO("[MPT], pTxRxPars->txrxPktType=0x%x\n", pTxRxPars->txrxPktType);
+		RTW_INFO("[MPT], pTxRxPars->txrxPayloadLen=0x%x\n", pTxRxPars->txrxPayloadLen);
+		RTW_INFO("[MPT], pTxRxPars->txrxPktHeader=0x%x\n", pTxRxPars->txrxPktHeader);
+		RTW_INFO("[MPT], pTxRxPars->txrxWhitenCoeff=0x%x\n", pTxRxPars->txrxWhitenCoeff);
+		bdAddr[0] = pTxRxPars->txrxBdaddr[5];
+		bdAddr[1] = pTxRxPars->txrxBdaddr[4];
+		bdAddr[2] = pTxRxPars->txrxBdaddr[3];
+		bdAddr[3] = pTxRxPars->txrxBdaddr[2];
+		bdAddr[4] = pTxRxPars->txrxBdaddr[1];
+		bdAddr[5] = pTxRxPars->txrxBdaddr[0];
+		RTW_INFO("[MPT], pTxRxPars->txrxBdaddr: %s", &bdAddr[0]);
+		RTW_INFO("[MPT], pTxRxPars->txrxTxGainIndex=0x%x\n", pTxRxPars->txrxTxGainIndex);
+	} else {
+		RTW_INFO("[MPT], Error!! pBtReq->paraLength=%d, correct Len=%d\n", pBtReq->paraLength, lenTxRx);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+
+	/*  */
+	/* execute lower layer opcodes */
+	/*  */
+
+	/* fill h2c parameters */
+	btOpcode = BT_LO_OP_SET_PKT_HEADER;
+	if (pTxRxPars->txrxPktHeader > 0x3ffff) {
+		RTW_INFO("[MPT], Error!! pTxRxPars->txrxPktHeader=0x%x is out of range, (should be between 0x0~0x3ffff)\n", pTxRxPars->txrxPktHeader);
+		pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	} else {
+		h2cParaBuf[0] = (u1Byte)(pTxRxPars->txrxPktHeader & 0xff);
+		h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxPktHeader & 0xff00) >> 8);
+		h2cParaBuf[2] = (u1Byte)((pTxRxPars->txrxPktHeader & 0xff0000) >> 16);
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	}
+
+	/* fill h2c parameters */
+	btOpcode = BT_LO_OP_SET_PKT_TYPE_LEN;
+	{
+		u2Byte	payloadLenLimit = 0;
+		switch (pTxRxPars->txrxPktType) {
+		case MP_BT_PKT_DH1:
+			payloadLenLimit = 27 * 8;
+			break;
+		case MP_BT_PKT_DH3:
+			payloadLenLimit = 183 * 8;
+			break;
+		case MP_BT_PKT_DH5:
+			payloadLenLimit = 339 * 8;
+			break;
+		case MP_BT_PKT_2DH1:
+			payloadLenLimit = 54 * 8;
+			break;
+		case MP_BT_PKT_2DH3:
+			payloadLenLimit = 367 * 8;
+			break;
+		case MP_BT_PKT_2DH5:
+			payloadLenLimit = 679 * 8;
+			break;
+		case MP_BT_PKT_3DH1:
+			payloadLenLimit = 83 * 8;
+			break;
+		case MP_BT_PKT_3DH3:
+			payloadLenLimit = 552 * 8;
+			break;
+		case MP_BT_PKT_3DH5:
+			payloadLenLimit = 1021 * 8;
+			break;
+		case MP_BT_PKT_LE:
+			payloadLenLimit = 39 * 8;
+			break;
+		default: {
+			RTW_INFO("[MPT], Error!! Unknown pTxRxPars->txrxPktType=0x%x\n", pTxRxPars->txrxPktType);
+			pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+			return paraLen;
+		}
+		break;
+		}
+
+		if (pTxRxPars->txrxPayloadLen > payloadLenLimit) {
+			RTW_INFO("[MPT], Error!! pTxRxPars->txrxPayloadLen=0x%x, (should smaller than %d)\n",
+				 pTxRxPars->txrxPayloadLen, payloadLenLimit);
+			pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+			return paraLen;
+		}
+
+		h2cParaBuf[0] = pTxRxPars->txrxPktType;
+		h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxPayloadLen & 0xff));
+		h2cParaBuf[2] = (u1Byte)((pTxRxPars->txrxPayloadLen & 0xff00) >> 8);
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	}
+
+	/* fill h2c parameters */
+	btOpcode = BT_LO_OP_SET_PKT_CNT_L_PL_TYPE;
+	if (pTxRxPars->txrxPayloadType > MP_BT_PAYLOAD_MAX) {
+		RTW_INFO("[MPT], Error!! pTxRxPars->txrxPayloadType=0x%x, (should be between 0~4)\n", pTxRxPars->txrxPayloadType);
+		pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	} else {
+		h2cParaBuf[0] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff));
+		h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff00) >> 8);
+		h2cParaBuf[2] = pTxRxPars->txrxPayloadType;
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	}
+
+	/* fill h2c parameters */
+	btOpcode = BT_LO_OP_SET_PKT_CNT_H_PKT_INTV;
+	if (pTxRxPars->txrxTxPktInterval > 15) {
+		RTW_INFO("[MPT], Error!! pTxRxPars->txrxTxPktInterval=0x%x, (should be between 0~15)\n", pTxRxPars->txrxTxPktInterval);
+		pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	} else {
+		h2cParaBuf[0] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff0000) >> 16);
+		h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff000000) >> 24);
+		h2cParaBuf[2] = pTxRxPars->txrxTxPktInterval;
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	}
+
+	/* fill h2c parameters */
+	btOpcode = BT_LO_OP_SET_WHITENCOEFF;
+	{
+		h2cParaBuf[0] = pTxRxPars->txrxWhitenCoeff;
+		h2cParaLen = 1;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	}
+
+
+	/* fill h2c parameters */
+	btOpcode = BT_LO_OP_SET_CHNL_TX_GAIN;
+	if ((pTxRxPars->txrxChannel > 78) ||
+	    (pTxRxPars->txrxTxGainIndex > 7)) {
+		RTW_INFO("[MPT], Error!! pTxRxPars->txrxChannel=0x%x, (should be between 0~78)\n", pTxRxPars->txrxChannel);
+		RTW_INFO("[MPT], Error!! pTxRxPars->txrxTxGainIndex=0x%x, (should be between 0~7)\n", pTxRxPars->txrxTxGainIndex);
+		pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	} else {
+		h2cParaBuf[0] = pTxRxPars->txrxChannel;
+		h2cParaBuf[1] = pTxRxPars->txrxTxGainIndex;
+		h2cParaLen = 2;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	}
+
+	/* fill h2c parameters */
+	btOpcode = BT_LO_OP_SET_BD_ADDR_L;
+	if ((pTxRxPars->txrxBdaddr[0] == 0) &&
+	    (pTxRxPars->txrxBdaddr[1] == 0) &&
+	    (pTxRxPars->txrxBdaddr[2] == 0) &&
+	    (pTxRxPars->txrxBdaddr[3] == 0) &&
+	    (pTxRxPars->txrxBdaddr[4] == 0) &&
+	    (pTxRxPars->txrxBdaddr[5] == 0)) {
+		RTW_INFO("[MPT], Error!! pTxRxPars->txrxBdaddr=all zero\n");
+		pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	if ((pTxRxPars->txrxBdaddr[0] == 0xff) &&
+	    (pTxRxPars->txrxBdaddr[1] == 0xff) &&
+	    (pTxRxPars->txrxBdaddr[2] == 0xff) &&
+	    (pTxRxPars->txrxBdaddr[3] == 0xff) &&
+	    (pTxRxPars->txrxBdaddr[4] == 0xff) &&
+	    (pTxRxPars->txrxBdaddr[5] == 0xff)) {
+		RTW_INFO("[MPT], Error!! pTxRxPars->txrxBdaddr=all 0xf\n");
+		pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+
+	{
+		h2cParaBuf[0] = pTxRxPars->txrxBdaddr[0];
+		h2cParaBuf[1] = pTxRxPars->txrxBdaddr[1];
+		h2cParaBuf[2] = pTxRxPars->txrxBdaddr[2];
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	}
+
+	btOpcode = BT_LO_OP_SET_BD_ADDR_H;
+	{
+		h2cParaBuf[0] = pTxRxPars->txrxBdaddr[3];
+		h2cParaBuf[1] = pTxRxPars->txrxBdaddr[4];
+		h2cParaBuf[2] = pTxRxPars->txrxBdaddr[5];
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	/* ckeck bt return status. */
+	if (BT_STATUS_BT_OP_SUCCESS != retStatus) {
+		pBtRsp->status = ((btOpcode << 8) | retStatus);
+		RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status);
+		return paraLen;
+	}
+
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	return paraLen;
+}
+
+
+
+u2Byte
+mptbt_BtTestCtrl(
+	IN	PADAPTER		Adapter,
+	IN	PBT_REQ_CMD	pBtReq,
+	IN	PBT_RSP_CMD	pBtRsp
+)
+{
+	u1Byte				h2cParaBuf[6] = {0};
+	u1Byte				h2cParaLen = 0;
+	u2Byte				paraLen = 0;
+	u1Byte				retStatus = BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer = 0;
+	u1Byte				testCtrl = 0;
+
+	/*  */
+	/* check upper layer parameters */
+	/*  */
+
+	/* 1. check upper layer opcode version */
+	if (pBtReq->opCodeVer != 1) {
+		RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
<