From 166b35f10126c79cb32dd7667cee9cb302648e1b Mon Sep 17 00:00:00 2001 From: "jiabin.chen" Date: Sun, 11 Sep 2022 11:26:33 +0800 Subject: [PATCH] wifi: dhd load fw change to request firmware [2/3] PD#SWPL-95664 Problem: dhd 515 driver is not ok Solution: update driver and change request firmware Verify: t7 Change-Id: I05f7a7856e4b0832ebcc6bff0b4523eb49d124e1 Signed-off-by: jiabin.chen --- bcmdhd.101.10.361.x/Makefile | 114 +- bcmdhd.101.10.361.x/bcmbloom.c | 2 + bcmdhd.101.10.361.x/bcmevent.c | 4 +- bcmdhd.101.10.361.x/bcmsdh_linux.c | 6 + bcmdhd.101.10.361.x/bcmsdh_sdmmc.c | 36 +- bcmdhd.101.10.361.x/bcmsdh_sdmmc_linux.c | 6 +- bcmdhd.101.10.361.x/bcmutils.c | 4 +- bcmdhd.101.10.361.x/bcmxtlv.c | 2 + bcmdhd.101.10.361.x/dbus.c | 463 ++- bcmdhd.101.10.361.x/dbus_usb.c | 63 +- bcmdhd.101.10.361.x/dbus_usb_linux.c | 130 +- bcmdhd.101.10.361.x/dhd.h | 100 +- bcmdhd.101.10.361.x/dhd_bus.h | 7 +- bcmdhd.101.10.361.x/dhd_ccode.c | 12 +- bcmdhd.101.10.361.x/dhd_cdc.c | 101 +- bcmdhd.101.10.361.x/dhd_common.c | 255 +- bcmdhd.101.10.361.x/dhd_config.c | 881 +++-- bcmdhd.101.10.361.x/dhd_config.h | 36 +- bcmdhd.101.10.361.x/dhd_flowring.c | 33 + bcmdhd.101.10.361.x/dhd_flowring.h | 1 + bcmdhd.101.10.361.x/dhd_fwtrace.c | 16 +- bcmdhd.101.10.361.x/dhd_gpio.c | 102 +- bcmdhd.101.10.361.x/dhd_linux.c | 1179 ++++--- bcmdhd.101.10.361.x/dhd_linux.h | 6 +- bcmdhd.101.10.361.x/dhd_linux_exportfs.c | 44 +- bcmdhd.101.10.361.x/dhd_linux_pktdump.c | 201 +- bcmdhd.101.10.361.x/dhd_linux_pktdump.h | 3 + bcmdhd.101.10.361.x/dhd_linux_platdev.c | 45 +- bcmdhd.101.10.361.x/dhd_macdbg.c | 5 - bcmdhd.101.10.361.x/dhd_msgbuf.c | 4 - bcmdhd.101.10.361.x/dhd_pcie.c | 137 +- bcmdhd.101.10.361.x/dhd_pcie_linux.c | 36 +- bcmdhd.101.10.361.x/dhd_pktlog.c | 8 +- bcmdhd.101.10.361.x/dhd_plat.h | 2 +- bcmdhd.101.10.361.x/dhd_proto.h | 4 + bcmdhd.101.10.361.x/dhd_sdio.c | 302 +- bcmdhd.101.10.361.x/dhd_static_buf.c | 38 +- bcmdhd.101.10.361.x/dhd_wlfc.c | 3 + bcmdhd.101.10.361.x/include/bcmdefs.h | 4 + bcmdhd.101.10.361.x/include/bcmevent.h | 107 +- bcmdhd.101.10.361.x/include/bcmsdh.h | 1 + bcmdhd.101.10.361.x/include/bcmsdh_sdmmc.h | 13 +- .../include/bcmwifi_channels.h | 2 +- bcmdhd.101.10.361.x/include/dbus.h | 41 +- bcmdhd.101.10.361.x/include/epivers.h | 2 +- bcmdhd.101.10.361.x/include/linux_osl.h | 12 +- bcmdhd.101.10.361.x/include/linuxver.h | 23 + bcmdhd.101.10.361.x/include/wlioctl.h | 148 +- bcmdhd.101.10.361.x/linux_osl.c | 82 +- bcmdhd.101.10.361.x/wl_android.c | 452 ++- bcmdhd.101.10.361.x/wl_android.h | 16 +- bcmdhd.101.10.361.x/wl_android_ext.c | 719 ++-- bcmdhd.101.10.361.x/wl_android_ext.h | 46 +- bcmdhd.101.10.361.x/wl_bam.c | 18 +- bcmdhd.101.10.361.x/wl_cfg80211.c | 542 ++- bcmdhd.101.10.361.x/wl_cfg80211.h | 24 + bcmdhd.101.10.361.x/wl_cfgnan.h | 19 +- bcmdhd.101.10.361.x/wl_cfgp2p.c | 59 +- bcmdhd.101.10.361.x/wl_cfgp2p.h | 5 + bcmdhd.101.10.361.x/wl_cfgscan.c | 55 +- bcmdhd.101.10.361.x/wl_cfgscan.h | 2 +- bcmdhd.101.10.361.x/wl_cfgvendor.c | 1986 +++++++++-- bcmdhd.101.10.361.x/wl_cfgvendor.h | 137 +- bcmdhd.101.10.361.x/wl_cfgvif.c | 202 +- bcmdhd.101.10.361.x/wl_cfgvif.h | 8 + bcmdhd.101.10.361.x/wl_escan.c | 142 +- bcmdhd.101.10.361.x/wl_escan.h | 7 +- bcmdhd.101.10.361.x/wl_event.c | 4 +- bcmdhd.101.10.361.x/wl_iapsta.c | 3133 ++++++++++++----- bcmdhd.101.10.361.x/wl_iapsta.h | 26 +- bcmdhd.101.10.361.x/wl_iw.c | 238 +- bcmdhd.101.10.361.x/wl_roam.c | 6 +- bcmdhd.101.10.361.x/wl_timer.c | 611 ++++ bcmdhd.101.10.361.x/wl_timer.h | 8 + bcmdhd.101.10.361.x/wldev_common.c | 28 +- 75 files changed, 9816 insertions(+), 3503 deletions(-) create mode 100755 bcmdhd.101.10.361.x/wl_timer.c create mode 100755 bcmdhd.101.10.361.x/wl_timer.h diff --git a/bcmdhd.101.10.361.x/Makefile b/bcmdhd.101.10.361.x/Makefile index 2884d7f..92f46e6 100755 --- a/bcmdhd.101.10.361.x/Makefile +++ b/bcmdhd.101.10.361.x/Makefile @@ -32,12 +32,17 @@ CONFIG_DHD_USE_STATIC_BUF := y #CONFIG_BCMDHD_STATIC_BUF_IN_DHD := y CONFIG_BCMDHD_AUTO_SELECT := y CONFIG_BCMDHD_DEBUG := y +#CONFIG_BCMDHD_RECONNECT := y #CONFIG_BCMDHD_TIMESTAMP := y #CONFIG_BCMDHD_WAPI := y #CONFIG_BCMDHD_RANDOM_MAC := y -#CONFIG_BCMDHD_MULTIPLE_DRIVER := y +CONFIG_BCMDHD_REQUEST_FW := y +#CONFIG_BCMDHD_DWDS := y CONFIG_BCMDHD_TPUT := y +#CONFIG_BCMDHD_MULTIPLE_DRIVER := y +#CONFIG_BCMDHD_ADAPTER_INDEX := 0 + CONFIG_MACH_PLATFORM := y #CONFIG_BCMDHD_DTS := y @@ -47,30 +52,33 @@ endif DHDCFLAGS = -Wall -Wstrict-prototypes -Wno-date-time \ -Dlinux -DLINUX -DBCMDRIVER \ - -Wno-unknown-warning-option -Wno-unused-but-set-variable \ - -Wno-uninitialized -Wno-error -Wno-format-security \ - -Wno-implicit-fallthrough \ + -Wno-unused-but-set-variable \ + -Wno-maybe-uninitialized -Wno-error -Wno-format-security \ + -Wno-unknown-warning-option -Wno-sometimes-uninitialized \ + -Wno-parentheses-equality -Wno-implicit-fallthrough \ -DBCMDONGLEHOST -DBCMDMA32 -DBCMFILEIMAGE \ -DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DGET_OTP_MAC_ENABLE \ -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY \ + -DPKTPRIO_OVERRIDE \ -DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DDHDTCPACK_SUPPRESS \ -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DOEM_ANDROID \ -DMULTIPLE_SUPPLICANT -DTSQ_MULTIPLIER -DMFP -DDHD_8021X_DUMP \ -DPOWERUP_MAX_RETRY=1 -DIFACE_HANG_FORCE_DEV_CLOSE -DWAIT_DEQUEUE \ -DUSE_NEW_RSPEC_DEFS \ -DWL_EXT_IAPSTA -DWL_ESCAN -DCCODE_LIST -DSUSPEND_EVENT \ - -DEAPOL_RESEND -DEAPOL_DYNAMATIC_RESEND \ + -DKEY_INSTALL_CHECK \ -DENABLE_INSMOD_NO_FW_LOAD -DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \ +DHDOFILES = aiutils.o siutils.o sbutils.o \ + bcmutils.o bcmwifi_channels.o bcmxtlv.o bcm_app_utils.o bcmstdlib_s.o \ dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o \ dhd_common.o dhd_ip.o dhd_linux_wq.o dhd_custom_gpio.o \ bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o \ dhd_debug_linux.o dhd_debug.o dhd_mschdbg.o dhd_dbg_ring.o \ - hnd_pktq.o hnd_pktpool.o bcmxtlv.o linux_pkt.o bcmstdlib_s.o frag.o \ + hnd_pktq.o hnd_pktpool.o linux_pkt.o frag.o \ dhd_linux_exportfs.o dhd_linux_pktdump.o dhd_mschdbg.o \ dhd_config.o dhd_ccode.o wl_event.o wl_android_ext.o \ - wl_iapsta.o wl_escan.o + wl_iapsta.o wl_escan.o wl_timer.o ifneq ($(CONFIG_WIRELESS_EXT),) DHDOFILES += wl_iw.o @@ -79,7 +87,7 @@ endif ifneq ($(CONFIG_CFG80211),) DHDOFILES += wl_cfg80211.o wl_cfgscan.o wl_cfgp2p.o DHDOFILES += wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o - DHDOFILES += dhd_cfg80211.o wl_cfgvif.o + DHDOFILES += dhd_cfg80211.o wl_cfgvif.o wl_roam.o DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 @@ -88,27 +96,27 @@ ifneq ($(CONFIG_CFG80211),) DHDCFLAGS += -DESCAN_RESULT_PATCH -DESCAN_BUF_OVERFLOW_MGMT DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8 - DHDCFLAGS += -DWL_VIRTUAL_APSTA + DHDCFLAGS += -DWL_VIRTUAL_APSTA -DSTA_MGMT DHDCFLAGS += -DPNO_SUPPORT -DEXPLICIT_DISCIF_CLEANUP DHDCFLAGS += -DDHD_USE_SCAN_WAKELOCK DHDCFLAGS += -DSPECIFIC_MAC_GEN_SCHEME DHDCFLAGS += -DWL_IFACE_MGMT - DHDCFLAGS += -DWLFBT - DHDCFLAGS += -DWL_EXT_RECONNECT - DHDCFLAGS += -DDHD_LOSSLESS_ROAMING + DHDCFLAGS += -DWLFBT -DWL_GCMP_SUPPORT + DHDCFLAGS += -DROAM_CHANNEL_CACHE -DDHD_LOSSLESS_ROAMING -DWL_ROAM_WAR DHDCFLAGS += -DGTK_OFFLOAD_SUPPORT + DHDCFLAGS += -DRESTART_AP_WAR DHDCFLAGS += -DWL_STATIC_IF DHDCFLAGS += -DWL_CLIENT_SAE -DWL_OWE endif #BCMDHD_SDIO ifneq ($(CONFIG_BCMDHD_SDIO),) -BUS_TYPE := "sdio" +BUS_TYPE := sdio DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DMMC_SW_RESET -DBCMLXSDMMC \ -DUSE_SDIOFIFO_IOVAR -DSDTEST \ -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256 \ - -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DRXFRAME_THREAD \ - -DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS \ + -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DBCMSDIOH_STATIC_COPY_BUF \ + -DRXFRAME_THREAD -DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS \ -DBCMSDIO_RXLIM_POST -DBCMSDIO_TXSEQ_SYNC -DCONSOLE_DPC \ -DBCMSDIO_INTSTATUS_WAR ifeq ($(CONFIG_BCMDHD_OOB),y) @@ -125,7 +133,7 @@ endif #BCMDHD_PCIE ifneq ($(CONFIG_BCMDHD_PCIE),) -BUS_TYPE := "pcie" +BUS_TYPE := pcie DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1 \ -DDONGLE_ENABLE_ISOLATION DHDCFLAGS += -DDHD_LB -DDHD_LB_RXP -DDHD_LB_STATS -DDHD_LB_TXP @@ -149,10 +157,15 @@ endif #BCMDHD_USB ifneq ($(CONFIG_BCMDHD_USB),) -BUS_TYPE := "usb" +BUS_TYPE := usb DHDCFLAGS += -DUSBOS_TX_THREAD -DBCMDBUS -DBCMTRXV2 -DDBUS_USB_LOOPBACK \ -DBDC -DHDCFLAGS += -DBCM_REQUEST_FW -DEXTERNAL_FW_PATH +DHDCFLAGS += -DINSMOD_FW_LOAD +DHDCFLAGS += -DBCM_REQUEST_FW +DHDCFLAGS += -DSHOW_LOGTRACE +ifneq ($(CONFIG_BCMDHD_REQUEST_FW),y) + DHDCFLAGS += -DEXTERNAL_FW_PATH +endif CONFIG_BCMDHD_NO_POWER_OFF := y ifneq ($(CONFIG_BCMDHD_CUSB),) DHDCFLAGS += -DBCMUSBDEV_COMPOSITE @@ -168,9 +181,17 @@ endif ifeq ($(CONFIG_BCMDHD_MULTIPLE_DRIVER),y) DHDCFLAGS += -DBCMDHD_MDRIVER +ifneq ($(CONFIG_BCMDHD_ADAPTER_INDEX),) + CONFIG_BCMDHD_STATIC_BUF_IN_DHD := y + MODULE_NAME := dhd$(BUS_TYPE)_$(CONFIG_BCMDHD_ADAPTER_INDEX) + DHDCFLAGS += -DADAPTER_IDX=$(CONFIG_BCMDHD_ADAPTER_INDEX) + DHDCFLAGS += -DBUS_TYPE=\"-$(BUS_TYPE)-$(CONFIG_BCMDHD_ADAPTER_INDEX)\" + DHDCFLAGS += -DDHD_LOG_PREFIX=\"[dhd-$(BUS_TYPE)-$(CONFIG_BCMDHD_ADAPTER_INDEX)]\" +else + MODULE_NAME := dhd$(BUS_TYPE) DHDCFLAGS += -DBUS_TYPE=\"-$(BUS_TYPE)\" DHDCFLAGS += -DDHD_LOG_PREFIX=\"[dhd-$(BUS_TYPE)]\" - MODULE_NAME := dhd$(BUS_TYPE) +endif else DHDCFLAGS += -DBUS_TYPE=\"\" endif @@ -202,14 +223,15 @@ endif ifneq ($(CONFIG_BCMDHD_ANDROID_VERSION),) DHDCFLAGS += -DANDROID_VERSION=$(CONFIG_BCMDHD_ANDROID_VERSION) DHDCFLAGS += -DDHD_NOTIFY_MAC_CHANGED + DHDCFLAGS += -DANDROID_BKPORT ifneq ($(CONFIG_CFG80211),) DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT -DLINKSTAT_SUPPORT DHDCFLAGS += -DCUSTOM_COUNTRY_CODE -DDHD_GET_VALID_CHANNELS DHDCFLAGS += -DDEBUGABILITY -DDBG_PKT_MON DHDCFLAGS += -DDHD_LOG_DUMP -DDHD_FW_COREDUMP DHDCFLAGS += -DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT - DHDCFLAGS += -DDHD_WAKE_STATUS - DHDOFILES += dhd_rtt.o bcm_app_utils.o + DHDCFLAGS += -DDHD_WAKE_STATUS -DWL_LATENCY_MODE + DHDOFILES += dhd_rtt.o endif else DHDCFLAGS += -DANDROID_VERSION=0 @@ -253,18 +275,40 @@ endif DHDCFLAGS :=$(filter-out -DWL_STATIC_IF,$(DHDCFLAGS)) endif +# EasyMesh ifeq ($(CONFIG_BCMDHD_EASYMESH),y) DHDCFLAGS :=$(filter-out -DDHD_FW_COREDUMP,$(DHDCFLAGS)) DHDCFLAGS :=$(filter-out -DDHD_LOG_DUMP,$(DHDCFLAGS)) - DHDCFLAGS += -DWLEASYMESH -DWL_STATIC_IF -DWLDWDS -DFOURADDR_AUTO_BRG + DHDCFLAGS += -DWLEASYMESH + CONFIG_BCMDHD_DWDS := y endif -#CSI_SUPPORT +# DWDS +ifeq ($(CONFIG_BCMDHD_DWDS),y) +ifneq ($(CONFIG_CFG80211),) + DHDCFLAGS += -DWLDWDS -DFOURADDR_AUTO_BRG +ifneq ($(CONFIG_BCMDHD_SDIO),) + DHDCFLAGS += -DRXF_DEQUEUE_ON_BUSY +endif + DHDCFLAGS += -DWL_STATIC_IF +endif +endif + +# CSI_SUPPORT ifeq ($(CONFIG_CSI_SUPPORT),y) DHDCFLAGS += -DCSI_SUPPORT DHDOFILES += dhd_csi.o endif +# For CONNECTION_IMPROVE +ifeq ($(CONFIG_BCMDHD_RECONNECT),y) + DHDCFLAGS += -DEAPOL_RESEND -DEAPOL_RESEND_M4 +ifneq ($(CONFIG_CFG80211),) + DHDCFLAGS += -DWL_EXT_RECONNECT -DWL_REASSOC_BCAST + DHDCFLAGS += -DWL_EXT_DISCONNECT_RECONNECT +endif +endif + # For TPUT_IMPROVE ifeq ($(CONFIG_BCMDHD_TPUT),y) DHDCFLAGS += -DDHD_TPUT_PATCH @@ -289,6 +333,9 @@ endif # For WAPI ifeq ($(CONFIG_BCMDHD_WAPI),y) DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI +ifeq ($(CONFIG_BCMDHD_ANDROID_VERSION),11) + DHDCFLAGS += -DCFG80211_WAPI_BKPORT +endif endif # For scan random mac @@ -307,6 +354,10 @@ endif # For Module auto-selection ifeq ($(CONFIG_BCMDHD_AUTO_SELECT),y) DHDCFLAGS += -DUPDATE_MODULE_NAME +ifeq ($(CONFIG_BCMDHD_REQUEST_FW),y) +# DHDCFLAGS += -DFW_AMPAK_PATH="\"ampak\"" + DHDCFLAGS += -DMODULE_PATH +endif ifneq ($(CONFIG_BCMDHD_SDIO),) DHDCFLAGS += -DGET_OTP_MODULE_NAME -DCOMPAT_OLD_MODULE endif @@ -331,6 +382,20 @@ endif # endif +ifeq ($(CONFIG_BCMDHD_REQUEST_FW),y) + DHDCFLAGS += -DDHD_LINUX_STD_FW_API + DHDCFLAGS += -DDHD_FW_NAME="\"fw_bcmdhd.bin\"" + DHDCFLAGS += -DDHD_NVRAM_NAME="\"nvram.txt\"" + DHDCFLAGS += -DDHD_CLM_NAME="\"clm_bcmdhd.blob\"" +else + DHDCFLAGS += -DDHD_SUPPORT_VFS_CALL +ifeq ($(CONFIG_BCMDHD_FW_PATH),) + DHDCFLAGS += -DCONFIG_BCMDHD_FW_PATH="\"/system/etc/firmware/fw_bcmdhd.bin\"" + DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH="\"/system/etc/firmware/nvram.txt\"" + DHDCFLAGS += -DCONFIG_BCMDHD_CLM_PATH="\"/system/etc/firmware/clm_bcmdhd.blob\"" +endif +endif + ifeq ($(CONFIG_BCMDHD_AG),y) DHDCFLAGS += -DBAND_AG endif @@ -383,7 +448,6 @@ bcmdhd_sdio: bcmdhd_usb: $(warning "building BCMDHD_USB..........") $(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules CONFIG_BCMDHD_USB=y - mv dhd.ko dhd_usb.ko clean: $(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(ARCH) clean diff --git a/bcmdhd.101.10.361.x/bcmbloom.c b/bcmdhd.101.10.361.x/bcmbloom.c index 7660c88..2fe8a4a 100755 --- a/bcmdhd.101.10.361.x/bcmbloom.c +++ b/bcmdhd.101.10.361.x/bcmbloom.c @@ -24,7 +24,9 @@ #include #include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)) #include +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) */ #ifdef BCMDRIVER #include diff --git a/bcmdhd.101.10.361.x/bcmevent.c b/bcmdhd.101.10.361.x/bcmevent.c index a8cafcb..61009d3 100755 --- a/bcmdhd.101.10.361.x/bcmevent.c +++ b/bcmdhd.101.10.361.x/bcmevent.c @@ -241,9 +241,7 @@ static const bcmevent_name_str_t bcmevent_names[] = { BCMEVENT_NAME(WLC_E_AUTH_START), #endif /* WL_CLIENT_SAE */ #ifdef WL_TWT - BCMEVENT_NAME(WLC_E_TWT_SETUP), - BCMEVENT_NAME(WLC_E_TWT_TEARDOWN), - BCMEVENT_NAME(WLC_E_TWT_INFO_FRM) + BCMEVENT_NAME(WLC_E_TWT), #endif /* WL_TWT */ }; diff --git a/bcmdhd.101.10.361.x/bcmsdh_linux.c b/bcmdhd.101.10.361.x/bcmsdh_linux.c index d297118..5bd32c5 100755 --- a/bcmdhd.101.10.361.x/bcmsdh_linux.c +++ b/bcmdhd.101.10.361.x/bcmsdh_linux.c @@ -346,6 +346,12 @@ bcmsdh_unregister(void) bcmsdh_unregister_client_driver(); } +void *bcmsdh_get_dev(bcmsdh_info_t *sdh) +{ + bcmsdh_os_info_t *bcmsdh_osinfo = sdh->os_cxt; + return bcmsdh_osinfo->dev; +} + void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh) { #if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) diff --git a/bcmdhd.101.10.361.x/bcmsdh_sdmmc.c b/bcmdhd.101.10.361.x/bcmsdh_sdmmc.c index 596c02f..d0e6abb 100755 --- a/bcmdhd.101.10.361.x/bcmsdh_sdmmc.c +++ b/bcmdhd.101.10.361.x/bcmsdh_sdmmc.c @@ -103,6 +103,8 @@ extern PBCMSDH_SDMMC_INSTANCE gInstance; #define CUSTOM_SDIO_F1_BLKSIZE DEFAULT_SDIO_F1_BLKSIZE #endif +#define COPY_BUF_SIZE (SDPCM_MAXGLOM_SIZE * 1600) + #define MAX_IO_RW_EXTENDED_BLK 511 uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ @@ -209,6 +211,14 @@ sdioh_attach(osl_t *osh, struct sdio_func *func) return NULL; } bzero((char *)sd, sizeof(sdioh_info_t)); +#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF) + sd->copy_buf = MALLOC(osh, COPY_BUF_SIZE); + if (sd->copy_buf == NULL) { + sd_err(("%s: MALLOC of %d-byte copy_buf failed\n", + __FUNCTION__, COPY_BUF_SIZE)); + goto fail; + } +#endif sd->osh = osh; sd->fake_func0.num = 0; sd->fake_func0.card = func->card; @@ -273,6 +283,9 @@ sdioh_attach(osl_t *osh, struct sdio_func *func) return sd; fail: +#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF) + MFREE(sd->osh, sd->copy_buf, COPY_BUF_SIZE); +#endif MFREE(sd->osh, sd, sizeof(sdioh_info_t)); return NULL; } @@ -301,6 +314,9 @@ sdioh_detach(osl_t *osh, sdioh_info_t *sd) sd->func[1] = NULL; sd->func[2] = NULL; +#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF) + MFREE(sd->osh, sd->copy_buf, COPY_BUF_SIZE); +#endif MFREE(sd->osh, sd, sizeof(sdioh_info_t)); } return SDIOH_API_RC_SUCCESS; @@ -1102,8 +1118,7 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by } if (err_ret) { - if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ) - || (err_ret == -EIO))) { + if (regaddr == 0x1001F) { /* XXX: Read/Write to SBSDIO_FUNC1_SLEEPCSR could return -110(timeout) * or -84(CRC) error in case the host tries to wake the device up. * Skip error log message if err code is -110 or -84 when accessing @@ -1365,7 +1380,8 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func return SDIOH_API_RC_FAIL; } } - } else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) { + } + else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) { for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { ttl_len += PKTLEN(sd->osh, pnext); } @@ -1374,16 +1390,20 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext); pkt_len = PKTLEN(sd->osh, pnext); - if (!localbuf) { +#ifdef BCMSDIOH_STATIC_COPY_BUF + if (ttl_len <= COPY_BUF_SIZE) + localbuf = sd->copy_buf; +#else localbuf = (uint8 *)MALLOC(sd->osh, ttl_len); +#endif if (localbuf == NULL) { - sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n", - __FUNCTION__, (write) ? "TX" : "RX")); + sd_err(("%s: %s localbuf malloc FAILED ttl_len=%d\n", + __FUNCTION__, (write) ? "TX" : "RX", ttl_len)); + ttl_len -= pkt_len; goto txglomfail; } } - bcopy(buf, (localbuf + local_plen), pkt_len); local_plen += pkt_len; if (PKTNEXT(sd->osh, pnext)) @@ -1428,8 +1448,10 @@ txglomfail: return SDIOH_API_RC_FAIL; } +#ifndef BCMSDIOH_STATIC_COPY_BUF if (localbuf) MFREE(sd->osh, localbuf, ttl_len); +#endif #ifndef PKT_STATICS if (sd_msglevel & SDH_COST_VAL) diff --git a/bcmdhd.101.10.361.x/bcmsdh_sdmmc_linux.c b/bcmdhd.101.10.361.x/bcmsdh_sdmmc_linux.c index 1dfb408..09307fd 100755 --- a/bcmdhd.101.10.361.x/bcmsdh_sdmmc_linux.c +++ b/bcmdhd.101.10.361.x/bcmsdh_sdmmc_linux.c @@ -91,8 +91,12 @@ static int sdioh_probe(struct sdio_func *func) adapter->bus_num = host_idx; adapter->slot_num = rca; adapter->sdio_func = func; - } else + } else { sd_err(("can't find adapter info for this chip\n")); +#ifdef ADAPTER_IDX + goto fail; +#endif + } #ifdef WL_CFG80211 wl_cfg80211_set_parent_dev(&func->dev); diff --git a/bcmdhd.101.10.361.x/bcmutils.c b/bcmdhd.101.10.361.x/bcmutils.c index 929056f..63d237e 100755 --- a/bcmdhd.101.10.361.x/bcmutils.c +++ b/bcmdhd.101.10.361.x/bcmutils.c @@ -23,7 +23,9 @@ #include #include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)) #include +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) */ #ifdef BCMDRIVER #include #include @@ -4930,7 +4932,7 @@ BCMPOSTTRAPFN(bcm_bitcount)(const uint8 *bitmap, uint length) return bitcount; } -void +static void dump_nvram(char *varbuf, int column, unsigned int n, unsigned int len) { unsigned int m; diff --git a/bcmdhd.101.10.361.x/bcmxtlv.c b/bcmdhd.101.10.361.x/bcmxtlv.c index ddc6351..91d5747 100755 --- a/bcmdhd.101.10.361.x/bcmxtlv.c +++ b/bcmdhd.101.10.361.x/bcmxtlv.c @@ -24,7 +24,9 @@ #include #include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)) #include +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) */ #ifdef BCMDRIVER #include diff --git a/bcmdhd.101.10.361.x/dbus.c b/bcmdhd.101.10.361.x/dbus.c index f86a864..a3da591 100755 --- a/bcmdhd.101.10.361.x/dbus.c +++ b/bcmdhd.101.10.361.x/dbus.c @@ -31,6 +31,7 @@ */ +#include #include "osl.h" #include "dbus.h" #include @@ -41,7 +42,12 @@ #include #endif #include +#ifdef WL_CFG80211 +#include +#include +#endif +#include #if defined(BCM_REQUEST_FW) #include #include @@ -93,7 +99,7 @@ typedef struct dhd_bus { bool txoverride; /* flow control related */ bool rxoff; bool tx_timer_ticking; - + uint ctl_completed; dbus_irbq_t *rx_q; dbus_irbq_t *tx_q; @@ -113,6 +119,7 @@ typedef struct dhd_bus { #endif char *fw_path; /* module_param: path to firmware image */ char *nv_path; /* module_param: path to nvram vars file */ + uint64 last_suspend_end_time; } dhd_bus_t; struct exec_parms { @@ -151,10 +158,11 @@ static void dbus_if_pktfree(void *handle, void *p, bool send); static struct dbus_irb *dbus_if_getirb(void *cbarg, bool send); static void dbus_if_rxerr_indicate(void *handle, bool on); -void * dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen); -void dhd_dbus_disconnect_cb(void *arg); -void dbus_detach(dhd_bus_t *pub); +static int dbus_suspend(void *context); +static int dbus_resume(void *context); +static void * dhd_dbus_probe_cb(uint16 bus_no, uint16 slot, uint32 hdrlen); +static void dhd_dbus_disconnect_cb(void *arg); +static void dbus_detach(dhd_bus_t *pub); /** functions in this file that are called by lower DBUS levels, e.g. dbus_usb.c */ static dbus_intf_callbacks_t dbus_intf_cbs = { @@ -179,10 +187,6 @@ static dbus_intf_callbacks_t dbus_intf_cbs = { * can be called inside disconnect() */ static dbus_intf_t *g_busintf = NULL; -static probe_cb_t probe_cb = NULL; -static disconnect_cb_t disconnect_cb = NULL; -static void *probe_arg = NULL; -static void *disc_arg = NULL; #if defined(BCM_REQUEST_FW) int8 *nonfwnvram = NULL; /* stand-alone multi-nvram given with driver load */ @@ -200,9 +204,6 @@ static int dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size static int dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb); static int dbus_rxirbs_fill(dhd_bus_t *dhd_bus); static int dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info); -static void dbus_disconnect(void *handle); -static void *dbus_probe(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen); #if defined(BCM_REQUEST_FW) extern char * dngl_firmware; @@ -601,7 +602,7 @@ check_file(osl_t *osh, unsigned char *headers) #ifdef EXTERNAL_FW_PATH static int -dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) +dbus_get_fw_nvram(dhd_bus_t *dhd_bus) { int bcmerror = -1, i; uint len, total_len; @@ -616,6 +617,8 @@ dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) struct trx_header *hdr; uint32 img_offset = 0; int offset = 0; + char *pfw_path = dhd_bus->fw_path; + char *pnv_path = dhd_bus->nv_path; /* For Get nvram */ file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); @@ -748,11 +751,11 @@ err: * the dongle */ static int -dbus_do_download(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) +dbus_do_download(dhd_bus_t *dhd_bus) { int err = DBUS_OK; - err = dbus_get_fw_nvram(dhd_bus, pfw_path, pnv_path); + err = dbus_get_fw_nvram(dhd_bus); if (err) { DBUSERR(("dbus_do_download: fail to get nvram %d\n", err)); return err; @@ -860,7 +863,12 @@ dbus_get_nvram(dhd_bus_t *dhd_bus) nvram_words_pad = 4 - dhd_bus->nvram_len % 4; len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad; +#if defined(CONFIG_DHD_USE_STATIC_BUF) + dhd_bus->image = (uint8*)DHD_OS_PREALLOC(dhd_bus->dhd, + DHD_PREALLOC_MEMDUMP_RAM, len); +#else dhd_bus->image = MALLOC(dhd_bus->pub.osh, len); +#endif /* CONFIG_DHD_USE_STATIC_BUF */ dhd_bus->image_len = len; if (dhd_bus->image == NULL) { DBUSERR(("%s: malloc failed!\n", __FUNCTION__)); @@ -939,7 +947,7 @@ dbus_do_download(dhd_bus_t *dhd_bus) #if defined(BCM_REQUEST_FW) dhd_bus->firmware = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid, dhd_bus->pub.attrib.chiprev, &dhd_bus->fw, &dhd_bus->fwlen, - DBUS_FIRMWARE, 0, 0); + DBUS_FIRMWARE, 0, 0, dhd_bus->fw_path); if (!dhd_bus->firmware) return DBUS_ERR; #endif @@ -965,7 +973,7 @@ dbus_do_download(dhd_bus_t *dhd_bus) nonfwnvramlen = 0; dhd_bus->nvfile = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid, dhd_bus->pub.attrib.chiprev, (void *)&temp_nvram, &temp_len, - DBUS_NVFILE, boardtype, boardrev); + DBUS_NVFILE, boardtype, boardrev, dhd_bus->nv_path); if (dhd_bus->nvfile) { int8 *tmp = MALLOC(dhd_bus->pub.osh, temp_len); if (tmp) { @@ -996,7 +1004,11 @@ dbus_do_download(dhd_bus_t *dhd_bus) err = DBUS_ERR; if (dhd_bus->nvram) { +#if defined(CONFIG_DHD_USE_STATIC_BUF) + DHD_OS_PREFREE(dhd_bus->dhd, dhd_bus->image, dhd_bus->image_len); +#else MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len); +#endif /* CONFIG_DHD_USE_STATIC_BUF */ dhd_bus->image = dhd_bus->fw; dhd_bus->image_len = (uint32)dhd_bus->fwlen; } @@ -1030,16 +1042,6 @@ fail: #endif /* EXTERNAL_FW_PATH */ #endif -/** required for DBUS deregistration */ -static void -dbus_disconnect(void *handle) -{ - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (disconnect_cb) - disconnect_cb(disc_arg); -} - /** * This function is called when the sent irb times out without a tx response status. * DBUS adds reliability by resending timed out IRBs DBUS_TX_RETRY_LIMIT times. @@ -1371,22 +1373,17 @@ dbus_if_getirb(void *cbarg, bool send) return irb; } -/** - * Called as part of DBUS bus registration. Calls back into higher level (e.g. dhd_linux.c) probe - * function. +/* Register/Unregister functions are called by the main DHD entry + * point (e.g. module insertion) to link with the bus driver, in + * order to look for or await the device. */ -static void * -dbus_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, - uint16 slot, uint32 hdrlen) -{ - DBUSTRACE(("%s\n", __FUNCTION__)); - if (probe_cb) { - disc_arg = probe_cb(probe_arg, desc, bustype, bus_no, slot, hdrlen); - return disc_arg; - } - return (void *)DBUS_ERR; -} +static dbus_driver_t dhd_dbus = { + dhd_dbus_probe_cb, + dhd_dbus_disconnect_cb, + dbus_suspend, + dbus_resume +}; /** * As part of initialization, higher level (e.g. dhd_linux.c) requests DBUS to prepare for @@ -1399,12 +1396,7 @@ dhd_bus_register(void) DBUSTRACE(("%s: Enter\n", __FUNCTION__)); - probe_cb = dhd_dbus_probe_cb; - disconnect_cb = dhd_dbus_disconnect_cb; - probe_arg = NULL; - - err = dbus_bus_register(0xa5c, 0x48f, dbus_probe, /* call lower DBUS level register function */ - dbus_disconnect, NULL, &g_busintf, NULL, NULL); + err = dbus_bus_register(&dhd_dbus, &g_busintf); /* Device not detected */ if (err == DBUS_ERR_NODEVICE) @@ -1414,11 +1406,10 @@ dhd_bus_register(void) } dhd_pub_t *g_pub = NULL; +bool net_attached = FALSE; void dhd_bus_unregister(void) { - int ret; - DBUSTRACE(("%s\n", __FUNCTION__)); DHD_MUTEX_LOCK(); @@ -1428,11 +1419,8 @@ dhd_bus_unregister(void) dhd_dbus_disconnect_cb(g_pub->bus); } } - probe_cb = NULL; DHD_MUTEX_UNLOCK(); - ret = dbus_bus_deregister(); - disconnect_cb = NULL; - probe_arg = NULL; + dbus_bus_deregister(); } /** As part of initialization, data structures have to be allocated and initialized */ @@ -1598,7 +1586,7 @@ int dbus_dlneeded(dhd_bus_t *pub) } #if defined(BCM_REQUEST_FW) -int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path) +int dbus_download_firmware(dhd_bus_t *pub) { dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; int err = DBUS_OK; @@ -1611,11 +1599,7 @@ int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path) DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate)); dhd_bus->pub.busstate = DBUS_STATE_DL_PENDING; -#ifdef EXTERNAL_FW_PATH - err = dbus_do_download(dhd_bus, pfw_path, pnv_path); -#else err = dbus_do_download(dhd_bus); -#endif /* EXTERNAL_FW_PATH */ if (err == DBUS_OK) { dhd_bus->pub.busstate = DBUS_STATE_DL_DONE; } else { @@ -1716,24 +1700,19 @@ dbus_stop(struct dhd_bus *pub) return DBUS_ERR; } -int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf) -{ - return dbus_send_pkt(dbus, pktbuf, pktbuf /* pktinfo */); -} - int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info) { return dbus_send_irb(pub, buf, len, NULL, info); } -int +static int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info) { return dbus_send_irb(pub, NULL, 0, pkt, info); } -int +static int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len) { dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; @@ -1754,7 +1733,7 @@ dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len) return DBUS_ERR; } -int +static int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len) { dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; @@ -1766,6 +1745,8 @@ dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len) dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { if (dhd_bus->drvintf && dhd_bus->drvintf->recv_ctl) return dhd_bus->drvintf->recv_ctl(dhd_bus->bus_info, buf, len); + } else { + DBUSERR(("%s: bustate=%d\n", __FUNCTION__, dhd_bus->pub.busstate)); } return DBUS_ERR; @@ -1804,8 +1785,9 @@ dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx) return DBUS_ERR; } +#ifdef INTR_EP_ENABLE /** only called by dhd_cdc.c (Dec 2012) */ -int +static int dbus_poll_intr(dbus_pub_t *pub) { dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; @@ -1823,6 +1805,7 @@ dbus_poll_intr(dbus_pub_t *pub) } return status; } +#endif /* INTR_EP_ENABLE */ /** called by nobody (Dec 2012) */ void * @@ -2459,7 +2442,8 @@ dhd_dbus_ctl_complete(void *handle, int type, int status) dhd->tx_ctlerrs++; } - dhd_prot_ctl_complete(dhd); + dhd->bus->ctl_completed = TRUE; + dhd_os_ioctl_resp_wake(dhd); } static void @@ -2467,21 +2451,26 @@ dhd_dbus_state_change(void *handle, int state) { dhd_pub_t *dhd = (dhd_pub_t *)handle; unsigned long flags; + wifi_adapter_info_t *adapter; if (dhd == NULL) { DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); return; } + adapter = (wifi_adapter_info_t *)dhd->adapter; + if (dhd->busstate == DHD_BUS_SUSPEND && state == DBUS_STATE_DOWN) { + DBUSERR(("%s: switch state %d to %d\n", __FUNCTION__, state, DBUS_STATE_SLEEP)); + state = DBUS_STATE_SLEEP; + } switch (state) { - case DBUS_STATE_DL_NEEDED: DBUSERR(("%s: firmware request cannot be handled\n", __FUNCTION__)); break; case DBUS_STATE_DOWN: - DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__)); DHD_LINUX_GENERAL_LOCK(dhd, flags); dhd_txflowcontrol(dhd, ALL_INTERFACES, ON); + DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__)); dhd->busstate = DHD_BUS_DOWN; DHD_LINUX_GENERAL_UNLOCK(dhd, flags); break; @@ -2492,13 +2481,6 @@ dhd_dbus_state_change(void *handle, int state) dhd->busstate = DHD_BUS_DATA; DHD_LINUX_GENERAL_UNLOCK(dhd, flags); break; - case DBUS_STATE_SLEEP: - DBUSTRACE(("%s: DBUS is suspend\n", __FUNCTION__)); - DHD_LINUX_GENERAL_LOCK(dhd, flags); - dhd_txflowcontrol(dhd, ALL_INTERFACES, ON); - dhd->busstate = DHD_BUS_SUSPEND; - DHD_LINUX_GENERAL_UNLOCK(dhd, flags); - break; default: break; } @@ -2586,6 +2568,12 @@ dhd_bus_chiprev(struct dhd_bus *bus) return bus->pub.attrib.chiprev; } +struct device * +dhd_bus_to_dev(struct dhd_bus *bus) +{ + return dbus_get_dev(); +} + void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) { @@ -2605,7 +2593,91 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pktbuf) DBUSTRACE(("txoff\n")); return BCME_EPERM; } - return dbus_send_txdata(&bus->pub, pktbuf); + return dbus_send_pkt(&bus->pub, pktbuf, pktbuf); +} + +int +dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) +{ + int timeleft = 0; + int ret = -1; + + DBUSTRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) + return -EIO; + + bus->ctl_completed = FALSE; + ret = dbus_send_ctl(bus, (void *)msg, msglen); + if (ret) { + DBUSERR(("%s: dbus_send_ctl error %d\n", __FUNCTION__, ret)); + return ret; + } + + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed); + if ((!timeleft) || (!bus->ctl_completed)) { + DBUSERR(("%s: Txctl timeleft %d ctl_completed %d\n", + __FUNCTION__, timeleft, bus->ctl_completed)); + ret = -1; + } + +#ifdef INTR_EP_ENABLE + /* If the ctl write is successfully completed, wait for an acknowledgement + * that indicates that it is now ok to do ctl read from the dongle + */ + if (ret != -1) { + bus->ctl_completed = FALSE; + if (dbus_poll_intr(bus->pub)) { + DBUSERR(("%s: dbus_poll_intr not submitted\n", __FUNCTION__)); + } else { + /* interrupt polling is sucessfully submitted. Wait for dongle to send + * interrupt + */ + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed); + if (!timeleft) { + DBUSERR(("%s: intr poll wait timed out\n", __FUNCTION__)); + } + } + } +#endif /* INTR_EP_ENABLE */ + + return ret; +} + +int +dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) +{ + int timeleft; + int ret = -1; + + DBUSTRACE(("%s: Enter\n", __FUNCTION__)); + + if (bus->dhd->dongle_reset) + return -EIO; + + bus->ctl_completed = FALSE; + ret = dbus_recv_ctl(bus, (uchar*)msg, msglen); + if (ret) { + DBUSERR(("%s: dbus_recv_ctl error %d\n", __FUNCTION__, ret)); + goto done; + } + + timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed); + if ((!timeleft) || (!bus->ctl_completed)) { + DBUSERR(("%s: Rxctl timeleft %d ctl_completed %d\n", __FUNCTION__, + timeleft, bus->ctl_completed)); + ret = -ETIMEDOUT; + goto done; + } + + /* XXX FIX: Must return cdc_len, not len, because after query_ioctl() + * it subtracts sizeof(cdc_ioctl_t); The other approach is + * to have dbus_recv_ctl() return actual len. + */ + ret = msglen; + +done: + return ret; } static void @@ -2635,7 +2707,8 @@ dhd_dbus_advertise_bus_remove(dhd_pub_t *dhdp) int timeleft; DHD_LINUX_GENERAL_LOCK(dhdp, flags); - dhdp->busstate = DHD_BUS_REMOVE; + if (dhdp->busstate != DHD_BUS_SUSPEND) + dhdp->busstate = DHD_BUS_REMOVE; DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); @@ -2728,27 +2801,160 @@ dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, } +static int +dhd_dbus_sync_dongle(dhd_pub_t *pub, int dlneeded) +{ + int ret = 0; + + if (dlneeded == 0) { + ret = dbus_up(pub->bus); + if (ret) { + DBUSERR(("%s: dbus_up failed!!\n", __FUNCTION__)); + goto exit; + } + ret = dhd_sync_with_dongle(pub); + if (ret < 0) { + DBUSERR(("%s: failed with code ret=%d\n", __FUNCTION__, ret)); + goto exit; + } + } + +exit: + return ret; +} + +static int +dbus_suspend(void *context) +{ + int ret = 0; + +#if defined(LINUX) + dhd_bus_t *bus = (dhd_bus_t*)context; + unsigned long flags; + + DBUSERR(("%s Enter\n", __FUNCTION__)); + if (bus->dhd == NULL) { + DBUSERR(("bus not inited\n")); + return BCME_ERROR; + } + if (bus->dhd->prot == NULL) { + DBUSERR(("prot is not inited\n")); + return BCME_ERROR; + } + + if (bus->dhd->up == FALSE) { + return BCME_OK; + } + + DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); + if (bus->dhd->busstate != DHD_BUS_DATA && bus->dhd->busstate != DHD_BUS_SUSPEND) { + DBUSERR(("not in a readystate to LPBK is not inited\n")); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + return BCME_ERROR; + } + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + if (bus->dhd->dongle_reset) { + DBUSERR(("Dongle is in reset state.\n")); + return -EIO; + } + + DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); + /* stop all interface network queue. */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); + bus->dhd->busstate = DHD_BUS_SUSPEND; +#if defined(LINUX) || defined(linux) + if (DHD_BUS_BUSY_CHECK_IN_TX(bus->dhd)) { + DBUSERR(("Tx Request is not ended\n")); + bus->dhd->busstate = DHD_BUS_DATA; + /* resume all interface network queue. */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + return -EBUSY; + } +#endif /* LINUX || linux */ + DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + + ret = dhd_os_check_wakelock_all(bus->dhd); + + DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); + if (ret) { + bus->dhd->busstate = DHD_BUS_DATA; + /* resume all interface network queue. */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); + } else { + bus->last_suspend_end_time = OSL_LOCALTIME_NS(); + } + bus->dhd->hostsleep = 2; + DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd); + dhd_os_busbusy_wake(bus->dhd); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + +#endif /* LINUX */ + DBUSERR(("%s Exit ret=%d\n", __FUNCTION__, ret)); + return ret; +} + +static int +dbus_resume(void *context) +{ + dhd_bus_t *bus = (dhd_bus_t*)context; + ulong flags; + int dlneeded = 0; + int ret = 0; + + DBUSERR(("%s Enter\n", __FUNCTION__)); + + if (bus->dhd->up == FALSE) { + return BCME_OK; + } + + dlneeded = dbus_dlneeded(bus); + if (dlneeded == 0) { + ret = dbus_up(bus); + if (ret) { + DBUSERR(("%s: dbus_up failed!!\n", __FUNCTION__)); + } + } + + DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); + DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); + + DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); + DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd); + bus->dhd->hostsleep = 0; + bus->dhd->busstate = DHD_BUS_DATA; + dhd_os_busbusy_wake(bus->dhd); + /* resume all interface network queue. */ + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); + DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); +// dhd_conf_set_suspend_resume(bus->dhd, 0); + + return 0; +} + /* * hdrlen is space to reserve in pkt headroom for DBUS */ -void * -dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen) +static void * +dhd_dbus_probe_cb(uint16 bus_no, uint16 slot, uint32 hdrlen) { osl_t *osh = NULL; dhd_bus_t *bus = NULL; dhd_pub_t *pub = NULL; uint rxsz; - int dlneeded = 0; + int dlneeded = 0, ret = DBUS_OK; wifi_adapter_info_t *adapter = NULL; + bool net_attach_now = TRUE; DBUSTRACE(("%s: Enter\n", __FUNCTION__)); - adapter = dhd_wifi_platform_get_adapter(bustype, bus_no, slot); + adapter = dhd_wifi_platform_get_adapter(USB_BUS, bus_no, slot); if (!g_pub) { /* Ask the OS interface part for an OSL handle */ - if (!(osh = osl_attach(NULL, bustype, TRUE))) { + if (!(osh = osl_attach(NULL, USB_BUS, TRUE))) { DBUSERR(("%s: OSL attach failed\n", __FUNCTION__)); goto fail; } @@ -2775,37 +2981,57 @@ dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, bus->dhd = pub; dlneeded = dbus_dlneeded(bus); - if (dlneeded >= 0) { - if (!g_pub) { - dhd_conf_reset(pub); - dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev); - dhd_conf_preinit(pub); - } + if (dlneeded >= 0 && !g_pub) { + dhd_conf_reset(pub); + dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev); + dhd_conf_preinit(pub); } - if (g_pub || dhd_download_fw_on_driverload) { - if (dlneeded == 0) { +#if defined(BCMDHD_MODULAR) && defined(INSMOD_FW_LOAD) + if (1) +#else + if (g_pub || dhd_download_fw_on_driverload) +#endif + { + if (dlneeded == 0) wifi_set_adapter_status(adapter, WIFI_STATUS_FW_READY); #ifdef BCM_REQUEST_FW - } else if (dlneeded > 0) { + else if (dlneeded > 0) { + struct dhd_conf *conf = pub->conf; + unsigned long flags; + bool suspended; wifi_clr_adapter_status(adapter, WIFI_STATUS_FW_READY); + suspended = conf->suspended; dhd_set_path(bus->dhd); - if (dbus_download_firmware(bus, bus->fw_path, bus->nv_path) != DBUS_OK) + conf->suspended = suspended; + if (dbus_download_firmware(bus) != DBUS_OK) goto fail; - bus->dhd->busstate = DHD_BUS_LOAD; + DHD_LINUX_GENERAL_LOCK(pub, flags); + if (bus->dhd->busstate != DHD_BUS_SUSPEND) + bus->dhd->busstate = DHD_BUS_LOAD; + DHD_LINUX_GENERAL_UNLOCK(pub, flags); + } #endif - } else { + else { goto fail; } } - } else { + } + else { DBUSERR(("%s: dbus_attach failed\n", __FUNCTION__)); + goto fail; } - if (!g_pub) { - /* Ok, have the per-port tell the stack we're open for business */ - if (dhd_attach_net(bus->dhd, TRUE) != 0) - { +#if defined(BCMDHD_MODULAR) && defined(INSMOD_FW_LOAD) + if (dlneeded > 0) + net_attach_now = FALSE; +#endif + + if (!net_attached && (net_attach_now || (dlneeded == 0))) { + if (dhd_dbus_sync_dongle(pub, dlneeded)) { + goto fail; + } + if (dhd_attach_net(bus->dhd, TRUE) != 0) { DBUSERR(("%s: Net attach failed!!\n", __FUNCTION__)); goto fail; } @@ -2813,14 +3039,31 @@ dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, #if defined(MULTIPLE_SUPPLICANT) wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe #endif + net_attached = TRUE; + } + else if (net_attached && (pub->up == 1) && (dlneeded == 0)) { + // kernel resume case + pub->hostsleep = 0; + ret = dhd_dbus_sync_dongle(pub, dlneeded); +#ifdef WL_CFG80211 + __wl_cfg80211_up_resume(pub); + wl_cfgp2p_start_p2p_device_resume(pub); +#endif + dhd_conf_set_suspend_resume(pub, 0); + if (ret != DBUS_OK) + goto fail; + } + + if (!g_pub) { g_pub = pub; } DBUSTRACE(("%s: Exit\n", __FUNCTION__)); - wifi_clr_adapter_status(adapter, WIFI_STATUS_DETTACH); - wifi_set_adapter_status(adapter, WIFI_STATUS_ATTACH); - wake_up_interruptible(&adapter->status_event); - /* This is passed to dhd_dbus_disconnect_cb */ + if (net_attached) { + wifi_set_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED); + wake_up_interruptible(&adapter->status_event); + /* This is passed to dhd_dbus_disconnect_cb */ + } return bus; fail: @@ -2843,7 +3086,7 @@ fail: return NULL; } -void +static void dhd_dbus_disconnect_cb(void *arg) { dhd_bus_t *bus = (dhd_bus_t *)arg; @@ -2869,8 +3112,6 @@ dhd_dbus_disconnect_cb(void *arg) dhd_dbus_advertise_bus_remove(bus->dhd); dbus_detach(pub->bus); pub->bus = NULL; - wifi_clr_adapter_status(adapter, WIFI_STATUS_ATTACH); - wifi_set_adapter_status(adapter, WIFI_STATUS_DETTACH); wake_up_interruptible(&adapter->status_event); } else { osh = pub->osh; @@ -2881,6 +3122,8 @@ dhd_dbus_disconnect_cb(void *arg) } dhd_free(pub); g_pub = NULL; + net_attached = FALSE; + wifi_clr_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED); if (MALLOCED(osh)) { DBUSERR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); } @@ -2907,6 +3150,7 @@ bcm_dbus_module_exit(void) } EXPORT_SYMBOL(dbus_pnp_sleep); +EXPORT_SYMBOL(dhd_bus_register); EXPORT_SYMBOL(dbus_get_devinfo); EXPORT_SYMBOL(dbus_detach); EXPORT_SYMBOL(dbus_get_attrib); @@ -2919,6 +3163,7 @@ EXPORT_SYMBOL(dbus_get_device_speed); EXPORT_SYMBOL(dbus_send_pkt); EXPORT_SYMBOL(dbus_recv_ctl); EXPORT_SYMBOL(dbus_attach); +EXPORT_SYMBOL(dhd_bus_unregister); MODULE_LICENSE("GPL"); diff --git a/bcmdhd.101.10.361.x/dbus_usb.c b/bcmdhd.101.10.361.x/dbus_usb.c index 5cee418..9683483 100755 --- a/bcmdhd.101.10.361.x/dbus_usb.c +++ b/bcmdhd.101.10.361.x/dbus_usb.c @@ -55,6 +55,9 @@ module_param(dbus_msglevel, int, 0); #define USB_DLGO_SPINWAIT 100 /* wait after DL_GO (ms) */ #define TEST_CHIP 0x4328 +/* driver info, initialized when bcmsdh_register is called */ +static dbus_driver_t drvinfo = {NULL, NULL, NULL, NULL}; + typedef struct { dbus_pub_t *pub; @@ -147,10 +150,6 @@ const bcm_iovar_t dhdusb_iovars[] = { * attach() is not called at probe and detach() * can be called inside disconnect() */ -static probe_cb_t probe_cb = NULL; -static disconnect_cb_t disconnect_cb = NULL; -static void *probe_arg = NULL; -static void *disc_arg = NULL; static dbus_intf_t *g_dbusintf = NULL; static dbus_intf_t dbus_usb_intf; /** functions called by higher layer DBUS into lower layer */ @@ -160,8 +159,7 @@ static dbus_intf_t dbus_usb_intf; /** functions called by higher layer DBUS into */ static void *dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs); static void dbus_usb_detach(dbus_pub_t *pub, void *info); -static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen); +static void * dbus_usb_probe(uint16 bus_no, uint16 slot, uint32 hdrlen); /* functions */ @@ -170,12 +168,10 @@ static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype, * lower level DBUS functions to call (in both dbus_usb.c and dbus_usb_os.c). */ static void * -dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, - uint16 slot, uint32 hdrlen) +dbus_usb_probe(uint16 bus_no, uint16 slot, uint32 hdrlen) { DBUSTRACE(("%s(): \n", __FUNCTION__)); - if (probe_cb) { - + if (drvinfo.probe) { if (g_dbusintf != NULL) { /* First, initialize all lower-level functions as default * so that dbus.c simply calls directly to dbus_usb_os.c. @@ -191,32 +187,55 @@ dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, dbus_usb_intf.dlrun = dbus_usb_dlrun; } - disc_arg = probe_cb(probe_arg, "DBUS USB", USB_BUS, bus_no, slot, hdrlen); - return disc_arg; + return drvinfo.probe(bus_no, slot, hdrlen); } return NULL; } +static int +dbus_usb_suspend(void *handle) +{ + DBUSTRACE(("%s(): \n", __FUNCTION__)); + + if (drvinfo.suspend) + return drvinfo.suspend(handle); + + return BCME_OK; +} + +static int +dbus_usb_resume(void *handle) +{ + DBUSTRACE(("%s(): \n", __FUNCTION__)); + + if (drvinfo.resume) + drvinfo.resume(handle); + + return 0; +} + +static dbus_driver_t dhd_usb_dbus = { + dbus_usb_probe, + dbus_usb_disconnect, + dbus_usb_suspend, + dbus_usb_resume +}; + /** * On return, *intf contains this or lower-level DBUS functions to be called by higher * level (dbus.c) */ int -dbus_bus_register(int vid, int pid, probe_cb_t prcb, - disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) +dbus_bus_register(dbus_driver_t *driver, dbus_intf_t **intf) { int err; DBUSTRACE(("%s(): \n", __FUNCTION__)); - probe_cb = prcb; - disconnect_cb = discb; - probe_arg = prarg; - + drvinfo = *driver; *intf = &dbus_usb_intf; - err = dbus_bus_osl_register(vid, pid, dbus_usb_probe, - dbus_usb_disconnect, NULL, &g_dbusintf, param1, param2); + err = dbus_bus_osl_register(&dhd_usb_dbus, &g_dbusintf); ASSERT(g_dbusintf); return err; @@ -292,8 +311,8 @@ void dbus_usb_disconnect(void *handle) { DBUSTRACE(("%s(): \n", __FUNCTION__)); - if (disconnect_cb) - disconnect_cb(disc_arg); + if (drvinfo.remove) + drvinfo.remove(handle); } /** diff --git a/bcmdhd.101.10.361.x/dbus_usb_linux.c b/bcmdhd.101.10.361.x/dbus_usb_linux.c index 0bd7181..3630bfc 100755 --- a/bcmdhd.101.10.361.x/dbus_usb_linux.c +++ b/bcmdhd.101.10.361.x/dbus_usb_linux.c @@ -511,6 +511,9 @@ typedef struct { struct usb_interface *intf; } probe_info_t; +/* driver info, initialized when bcmsdh_register is called */ +static dbus_driver_t drvinfo = {NULL, NULL, NULL, NULL}; + /* * USB Linux dbus_intf_t */ @@ -588,9 +591,6 @@ static dbus_intf_t dbus_usbos_intf = { }; static probe_info_t g_probe_info; -static probe_cb_t probe_cb = NULL; -static disconnect_cb_t disconnect_cb = NULL; -static void *probe_arg = NULL; static void *disc_arg = NULL; @@ -1232,26 +1232,46 @@ static int dbus_usbos_suspend(struct usb_interface *intf, pm_message_t message) { - DBUSERR(("%s suspend state: %d\n", __FUNCTION__, g_probe_info.suspend_state)); + usbos_info_t *usbos_info = (usbos_info_t *) g_probe_info.usbos_info; + int err = 0; + + printf("%s Enter\n", __FUNCTION__); + /* DHD for full dongle model */ g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPEND_PENDING; - dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_SLEEP); + if (drvinfo.suspend && disc_arg) + err = drvinfo.suspend(disc_arg); + if (err) { + printf("%s: err=%d\n", __FUNCTION__, err); +// g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; +// return err; + } + usbos_info->pub->busstate = DBUS_STATE_SLEEP; + dbus_usbos_cancel_all_urbs((usbos_info_t*)g_probe_info.usbos_info); g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPENDED; - return 0; + printf("%s Exit err=%d\n", __FUNCTION__, err); + return err; } /** * The resume method is called to tell the driver that the device has been resumed and the driver * can return to normal operation. URBs may once more be submitted. */ -static int dbus_usbos_resume(struct usb_interface *intf) +static int +dbus_usbos_resume(struct usb_interface *intf) { - DBUSERR(("%s Device resumed\n", __FUNCTION__)); + usbos_info_t *usbos_info = (usbos_info_t *) g_probe_info.usbos_info; + + printf("%s Enter\n", __FUNCTION__); - dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_UP); g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; + if (drvinfo.resume && disc_arg) + drvinfo.resume(disc_arg); + usbos_info->pub->busstate = DBUS_STATE_UP; + + printf("%s Exit\n", __FUNCTION__); return 0; } @@ -1259,13 +1279,16 @@ static int dbus_usbos_resume(struct usb_interface *intf) * This function is directly called by the Linux kernel, when the suspended device has been reset * instead of being resumed */ -static int dbus_usbos_reset_resume(struct usb_interface *intf) +static int +dbus_usbos_reset_resume(struct usb_interface *intf) { - DBUSERR(("%s Device reset resumed\n", __FUNCTION__)); + printf("%s Enter\n", __FUNCTION__); - /* The device may have lost power, so a firmware download may be required */ - dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_DL_NEEDED); g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; + if (drvinfo.resume && disc_arg) + drvinfo.resume(disc_arg); + + printf("%s Exit\n", __FUNCTION__); return 0; } @@ -1554,8 +1577,8 @@ DBUS_USBOS_PROBE() g_probe_info.device_speed = FULL_SPEED; DBUSERR(("full speed device detected\n")); } - if (g_probe_info.dereged == FALSE && probe_cb) { - disc_arg = probe_cb(probe_arg, "", USB_BUS, usb->bus->busnum, usb->portnum, 0); + if (g_probe_info.dereged == FALSE && drvinfo.probe) { + disc_arg = drvinfo.probe(usb->bus->busnum, usb->portnum, 0); } g_probe_info.disc_cb_done = FALSE; @@ -1616,8 +1639,8 @@ DBUS_USBOS_DISCONNECT() if (probe_usb_init_data) { usbos_info = (usbos_info_t *) probe_usb_init_data->usbos_info; if (usbos_info) { - if ((probe_usb_init_data->dereged == FALSE) && disconnect_cb && disc_arg) { - disconnect_cb(disc_arg); + if ((probe_usb_init_data->dereged == FALSE) && drvinfo.remove && disc_arg) { + drvinfo.remove(disc_arg); disc_arg = NULL; probe_usb_init_data->disc_cb_done = TRUE; } @@ -2554,18 +2577,11 @@ dbus_usbos_state_change(void *bus, int state) } int -dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, - disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) +dbus_bus_osl_register(dbus_driver_t *driver, dbus_intf_t **intf) { bzero(&g_probe_info, sizeof(probe_info_t)); - probe_cb = prcb; - disconnect_cb = discb; - probe_arg = prarg; - - devid_table[0].idVendor = vid; - devid_table[0].idProduct = pid; - + drvinfo = *driver; *intf = &dbus_usbos_intf; USB_REGISTER(); @@ -2579,8 +2595,8 @@ dbus_bus_osl_deregister() g_probe_info.dereged = TRUE; DHD_MUTEX_LOCK(); - if (disconnect_cb && disc_arg && (g_probe_info.disc_cb_done == FALSE)) { - disconnect_cb(disc_arg); + if (drvinfo.remove && disc_arg && (g_probe_info.disc_cb_done == FALSE)) { + drvinfo.remove(disc_arg); disc_arg = NULL; } DHD_MUTEX_UNLOCK(); @@ -3182,8 +3198,10 @@ dbus_request_firmware(const char *name, const struct firmware **firmware) return *firmware != NULL ? 0 : -ENOENT; } +#ifndef DHD_LINUX_STD_FW_API static void * -dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev) +dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, + uint16 boardtype, uint16 boardrev, char *path) { const struct firmware *firmware = NULL; #ifndef OEM_ANDROID @@ -3246,11 +3264,12 @@ dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_FW_PATH); #endif /* OEM_ANDROID */ - ret = dbus_request_firmware(file_name, &firmware); + ret = dbus_request_firmware(path, &firmware); if (ret) { - DBUSERR(("fail to request firmware %s\n", file_name)); + DBUSERR(("fail to request firmware %s\n", path)); return NULL; - } + } else + DBUSERR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, path, firmware->size)); *fwlen = firmware->size; *fw = (uint8 *)firmware->data; @@ -3259,7 +3278,8 @@ dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype } static void * -dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev) +dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, + uint16 boardtype, uint16 boardrev, char *path) { const struct firmware *firmware = NULL; #ifndef OEM_ANDROID @@ -3327,9 +3347,9 @@ dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_NVRAM_PATH); #endif /* OEM_ANDROID */ - ret = dbus_request_firmware(file_name, &firmware); + ret = dbus_request_firmware(path, &firmware); if (ret) { - DBUSERR(("fail to request nvram %s\n", file_name)); + DBUSERR(("fail to request nvram %s\n", path)); #ifndef OEM_ANDROID /* Load generic nvram file */ @@ -3340,10 +3360,11 @@ dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype #endif /* OEM_ANDROID */ if (ret) { - DBUSERR(("fail to request nvram %s\n", file_name)); + DBUSERR(("fail to request nvram %s\n", path)); return NULL; } - } + } else + DBUSERR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, path, firmware->size)); *fwlen = firmware->size; *fw = (uint8 *)firmware->data; @@ -3352,17 +3373,39 @@ dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype void * dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype, - uint16 boardrev) + uint16 boardrev, char *path) { switch (type) { case DBUS_FIRMWARE: - return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev); + return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev, path); case DBUS_NVFILE: - return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev); + return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev, path); default: return NULL; } } +#else +void * +dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype, + uint16 boardrev, char *path) +{ + const struct firmware *firmware = NULL; + int err = DBUS_OK; + + err = dbus_request_firmware(path, &firmware); + if (err) { + DBUSERR(("fail to request firmware %s\n", path)); + return NULL; + } else { + DBUSERR(("%s: %s (%zu bytes) open success\n", + __FUNCTION__, path, firmware->size)); + } + + *fwlen = firmware->size; + *fw = (uint8 *)firmware->data; + return (void *)firmware; +} +#endif void dbus_release_fw_nvfile(void *firmware) @@ -3403,3 +3446,10 @@ dbus_usbos_intf_wlan(struct usb_device *usb) return intf_wlan; } #endif /* BCMUSBDEV_COMPOSITE */ + +#ifdef LINUX +struct device * dbus_get_dev(void) +{ + return &g_probe_info.usb->dev; +} +#endif /* LINUX */ \ No newline at end of file diff --git a/bcmdhd.101.10.361.x/dhd.h b/bcmdhd.101.10.361.x/dhd.h index fd53811..0832c45 100755 --- a/bcmdhd.101.10.361.x/dhd.h +++ b/bcmdhd.101.10.361.x/dhd.h @@ -34,6 +34,7 @@ #define _dhd_h_ #if defined(LINUX) +#include #include #include #include @@ -46,6 +47,8 @@ #include #include #include +#include +#include #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) #include #elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) @@ -1928,6 +1931,9 @@ typedef struct dhd_pub { struct dhd_conf *conf; /* Bus module handle */ void *adapter; /* adapter information, interrupt, fw path etc. */ void *event_params; +#ifdef WL_TIMER + void *timer_params; +#endif /* WL_TIMER */ #ifdef BCMDBUS bool dhd_remove; #endif /* BCMDBUS */ @@ -2726,6 +2732,8 @@ void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size); #endif /* DHD_FW_COREDUMP */ #if defined(linux) || defined(LINUX) +int dhd_os_get_img_fwreq(const struct firmware **fw, char *file_path); +void dhd_os_close_img_fwreq(const struct firmware *fw); #if defined(DHD_SSSR_DUMP) void dhd_write_sssr_dump(dhd_pub_t *dhdp, uint32 dump_mode); #endif /* DHD_SSSR_DUMP */ @@ -3697,8 +3705,8 @@ extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags); #ifdef DBG_PKT_MON /* Enable DHD PKT MON spin lock/unlock */ -#define DHD_PKT_MON_LOCK(lock, flags) (flags) = osl_spin_lock(lock) -#define DHD_PKT_MON_UNLOCK(lock, flags) osl_spin_unlock(lock, (flags)) +#define DHD_PKT_MON_LOCK(lock, flags) (flags) = osl_mutex_lock(lock) +#define DHD_PKT_MON_UNLOCK(lock, flags) osl_mutex_unlock(lock, (flags)) #endif /* DBG_PKT_MON */ #ifdef DHD_PKT_LOGGING @@ -4649,6 +4657,94 @@ int dhd_awdl_llc_to_eth_hdr(struct dhd_pub *dhd, struct ether_header *eh, void * #error "DHD_DEBUGABILITY_LOG_DUMP_RING without DEBUGABILITY" #endif /* DEBUGABILITY */ #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */ + +#if defined(__linux__) +#ifdef DHD_SUPPORT_VFS_CALL +static INLINE struct file *dhd_filp_open(const char *filename, int flags, int mode) +{ + return filp_open(filename, flags, mode); +} + +static INLINE int dhd_filp_close(void *image, void *id) +{ + return filp_close((struct file *)image, id); +} + +static INLINE int dhd_i_size_read(const struct inode *inode) +{ + return i_size_read(inode); +} + +static INLINE int dhd_kernel_read_compat(struct file *fp, loff_t pos, void *buf, size_t count) +{ + return kernel_read_compat(fp, pos, buf, count); +} + +static INLINE int dhd_vfs_read(struct file *filep, char *buf, size_t size, loff_t *pos) +{ + return vfs_read(filep, buf, size, pos); +} + +static INLINE int dhd_vfs_write(struct file *filep, char *buf, size_t size, loff_t *pos) +{ + return vfs_write(filep, buf, size, pos); +} + +static INLINE int dhd_vfs_fsync(struct file *filep, int datasync) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + return vfs_fsync(filep, datasync); +#else + return vfs_fsync(filep, filep->f_path.dentry, 0); +#endif +} + +static INLINE int dhd_vfs_stat(char *buf, struct kstat *stat) +{ + return vfs_stat(buf, stat); +} + +static INLINE int dhd_kern_path(char *name, int flags, struct path *file_path) +{ + return kern_path(name, flags, file_path); +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)) +#define DHD_VFS_INODE(dir) (dir->d_inode) +#else +#define DHD_VFS_INODE(dir) d_inode(dir) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) +#define DHD_VFS_UNLINK(dir, b, c) vfs_unlink(DHD_VFS_INODE(dir), b) +#else +#define DHD_VFS_UNLINK(dir, b, c) vfs_unlink(DHD_VFS_INODE(dir), b, c) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */ + +#else +#define DHD_VFS_UNLINK(dir, b, c) 0 + +static INLINE struct file *dhd_filp_open(const char *filename, int flags, int mode) + { return NULL; } +static INLINE int dhd_filp_close(void *image, void *id) + { return 0; } +static INLINE int dhd_i_size_read(const struct inode *inode) + { return 0; } +static INLINE int dhd_kernel_read_compat(struct file *fp, loff_t pos, void *buf, size_t count) + { return 0; } +static INLINE int dhd_vfs_read(struct file *filep, char *buf, size_t size, loff_t *pos) + { return 0; } +static INLINE int dhd_vfs_write(struct file *filep, char *buf, size_t size, loff_t *pos) + { return 0; } +static INLINE int dhd_vfs_fsync(struct file *filep, int datasync) + { return 0; } +static INLINE int dhd_vfs_stat(char *buf, struct kstat *stat) + { return 0; } +static INLINE int dhd_kern_path(char *name, int flags, struct path *file_path) + { return 0; } +#endif /* DHD_SUPPORT_VFS_CALL */ +#endif /* __linux__ */ + #ifdef WL_MONITOR void dhd_set_monitor(dhd_pub_t *pub, int ifidx, int val); #endif /* WL_MONITOR */ diff --git a/bcmdhd.101.10.361.x/dhd_bus.h b/bcmdhd.101.10.361.x/dhd_bus.h index 5618b02..295f1ba 100755 --- a/bcmdhd.101.10.361.x/dhd_bus.h +++ b/bcmdhd.101.10.361.x/dhd_bus.h @@ -31,8 +31,6 @@ extern int dbus_up(struct dhd_bus *pub); extern int dbus_stop(struct dhd_bus *pub); -extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len); -extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len); /* * Exported from dhd bus module (dhd_usb, dhd_sdio) */ @@ -90,6 +88,7 @@ extern int dhd_bus_oob_intr_register(dhd_pub_t *dhdp); extern void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp); extern void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable); extern int dhd_bus_get_oob_irq_num(dhd_pub_t *dhdp); +extern struct device * dhd_bus_to_dev(struct dhd_bus *bus); extern void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub); extern void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub); extern bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub); @@ -251,8 +250,6 @@ extern void dhd_bus_aer_config(struct dhd_bus *bus); static INLINE void dhd_bus_aer_config(struct dhd_bus *bus) { } #endif /* LINUX || linux */ -extern struct device * dhd_bus_to_dev(struct dhd_bus *bus); - extern int dhdpcie_cto_init(struct dhd_bus *bus, bool enable); extern int dhdpcie_cto_cfg_init(struct dhd_bus *bus, bool enable); @@ -312,7 +309,7 @@ static INLINE bool dhd_bus_check_driver_up(void) { return FALSE; } static INLINE void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val) { } static INLINE int dhd_bus_get_linkdown(dhd_pub_t *dhdp) { return 0; } static INLINE int dhd_bus_get_cto(dhd_pub_t *dhdp) { return 0; } -extern INLINE int dhd_bus_checkdied(struct dhd_bus *bus, char *data, uint size) { return 0; } +static INLINE int dhd_bus_checkdied(struct dhd_bus *bus, char *data, uint size) { return 0; } #endif /* BCMPCIE */ #if defined(BCMPCIE) && defined(EWP_ETD_PRSRV_LOGS) diff --git a/bcmdhd.101.10.361.x/dhd_ccode.c b/bcmdhd.101.10.361.x/dhd_ccode.c index 62b9eec..90d6dea 100755 --- a/bcmdhd.101.10.361.x/dhd_ccode.c +++ b/bcmdhd.101.10.361.x/dhd_ccode.c @@ -16,7 +16,7 @@ #define CCODE_4359C0 #endif #if defined(BCMPCIE) -#define CCODE_4375B4 +//#define CCODE_4375B4 #endif #ifdef BCMDBUS #define CCODE_4358U @@ -232,7 +232,7 @@ const ccode_list_map_t ccode_list_map[] = { {BCM4354_CHIP_ID, 2, ccode_4356a2, "XZ/11"}, {BCM4356_CHIP_ID, 2, ccode_4356a2, "XZ/11"}, {BCM4359_CHIP_ID, 9, ccode_4359c0, "XZ/11"}, - {BCM4375_CHIP_ID, 5, ccode_4375b4, "XZ/11"}, + {BCM4375_CHIP_ID, 5, ccode_4375b4, ""}, #endif #ifdef BCMDBUS {BCM43569_CHIP_ID, 2, ccode_4358u, "XW/0"}, @@ -264,9 +264,11 @@ dhd_ccode_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec) } } - if (bcmerror && ccode_ww && strlen(ccode_ww)>=4) { - memcpy(cspec->ccode, ccode_ww, 2); - cspec->rev = (int)simple_strtol(ccode_ww+3, NULL, 0); + if (dhd->op_mode != DHD_FLAG_MFG_MODE) { + if (bcmerror && ccode_ww && strlen(ccode_ww)>=4) { + memcpy(cspec->ccode, ccode_ww, 2); + cspec->rev = (int)simple_strtol(ccode_ww+3, NULL, 0); + } } return bcmerror; diff --git a/bcmdhd.101.10.361.x/dhd_cdc.c b/bcmdhd.101.10.361.x/dhd_cdc.c index 0152c18..a81d49f 100755 --- a/bcmdhd.101.10.361.x/dhd_cdc.c +++ b/bcmdhd.101.10.361.x/dhd_cdc.c @@ -71,9 +71,6 @@ typedef struct dhd_prot { uint16 reqid; uint8 pending; uint32 lastcmd; -#ifdef BCMDBUS - uint ctl_completed; -#endif /* BCMDBUS */ uint8 bus_header[BUS_HEADER_LEN]; cdc_ioctl_t msg; unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; @@ -89,9 +86,6 @@ dhd_prot_get_ioctl_trans_id(dhd_pub_t *dhdp) static int dhdcdc_msg(dhd_pub_t *dhd) { -#ifdef BCMDBUS - int timeout = 0; -#endif /* BCMDBUS */ int err = 0; dhd_prot_t *prot = dhd->prot; int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); @@ -108,46 +102,8 @@ dhdcdc_msg(dhd_pub_t *dhd) len = CDC_MAX_MSG_SIZE; /* Send request */ -#ifdef BCMDBUS - prot->ctl_completed = FALSE; - err = dbus_send_ctl(dhd->bus, (void *)&prot->msg, len); - if (err) { - DHD_ERROR(("dbus_send_ctl error=0x%x\n", err)); - DHD_OS_WAKE_UNLOCK(dhd); - return err; - } -#else err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); -#endif /* BCMDBUS */ -#ifdef BCMDBUS - timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed); - if ((!timeout) || (!prot->ctl_completed)) { - DHD_ERROR(("Txctl timeout %d ctl_completed %d\n", - timeout, prot->ctl_completed)); - DHD_ERROR(("Txctl wait timed out\n")); - err = -1; - } -#endif /* BCMDBUS */ -#if defined(BCMDBUS) && defined(INTR_EP_ENABLE) - /* If the ctl write is successfully completed, wait for an acknowledgement - * that indicates that it is now ok to do ctl read from the dongle - */ - if (err != -1) { - prot->ctl_completed = FALSE; - if (dbus_poll_intr(dhd->dbus)) { - DHD_ERROR(("dbus_poll_intr not submitted\n")); - } else { - /* interrupt polling is sucessfully submitted. Wait for dongle to send - * interrupt - */ - timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed); - if (!timeout) { - DHD_ERROR(("intr poll wait timed out\n")); - } - } - } -#endif /* defined(BCMDBUS) && defined(INTR_EP_ENABLE) */ DHD_OS_WAKE_UNLOCK(dhd); return err; } @@ -155,9 +111,6 @@ dhdcdc_msg(dhd_pub_t *dhd) static int dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) { -#ifdef BCMDBUS - int timeout = 0; -#endif /* BCMDBUS */ int ret; int cdc_len = len + sizeof(cdc_ioctl_t); dhd_prot_t *prot = dhd->prot; @@ -165,29 +118,7 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); do { -#ifdef BCMDBUS - prot->ctl_completed = FALSE; - ret = dbus_recv_ctl(dhd->bus, (uchar*)&prot->msg, cdc_len); - if (ret) { - DHD_ERROR(("dbus_recv_ctl error=0x%x(%d)\n", ret, ret)); - goto done; - } - timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed); - if ((!timeout) || (!prot->ctl_completed)) { - DHD_ERROR(("Rxctl timeout %d ctl_completed %d\n", - timeout, prot->ctl_completed)); - ret = -ETIMEDOUT; - goto done; - } - - /* XXX FIX: Must return cdc_len, not len, because after query_ioctl() - * it subtracts sizeof(cdc_ioctl_t); The other approach is - * to have dbus_recv_ctl() return actual len. - */ - ret = cdc_len; -#else ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); -#endif /* BCMDBUS */ if (ret < 0) break; } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); @@ -197,9 +128,6 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) ret = len; } -#ifdef BCMDBUS -done: -#endif /* BCMDBUS */ return ret; } @@ -403,24 +331,6 @@ done: return ret; } -#ifdef BCMDBUS -int -dhd_prot_ctl_complete(dhd_pub_t *dhd) -{ - dhd_prot_t *prot; - - if (dhd == NULL) - return BCME_ERROR; - - prot = dhd->prot; - - ASSERT(prot); - prot->ctl_completed = TRUE; - dhd_os_ioctl_resp_wake(dhd); - return 0; -} -#endif /* BCMDBUS */ - /* XXX: due to overlays this should not be called directly; call dhd_wl_ioctl() instead */ int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) @@ -640,6 +550,17 @@ exit: return 0; } +#ifdef DHD_LOSSLESS_ROAMING +int dhd_update_sdio_data_prio_map(dhd_pub_t *dhdp) +{ + const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + + bcopy(prio2tid, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); + + return BCME_OK; +} +#endif // DHD_LOSSLESS_ROAMING + int dhd_prot_attach(dhd_pub_t *dhd) { diff --git a/bcmdhd.101.10.361.x/dhd_common.c b/bcmdhd.101.10.361.x/dhd_common.c index a8f8ef6..7c83e58 100755 --- a/bcmdhd.101.10.361.x/dhd_common.c +++ b/bcmdhd.101.10.361.x/dhd_common.c @@ -5154,16 +5154,11 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, event_name, reason, bcn_mute_miti_evnt_data->uatbtt_count)); } break; - - case WLC_E_TWT_SETUP: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - case WLC_E_TWT_TEARDOWN: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - case WLC_E_TWT_INFO_FRM: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); +#ifdef WL_TWT + case WLC_E_TWT: + DHD_EVENT(("MACEVENT: %s, type:%d\n", event_name, reason)); break; +#endif /* WL_TWT */ default: DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n", event_name, event_type, eabuf, (int)status, (int)reason, @@ -7804,6 +7799,82 @@ static int traffic_mgmt_add_dwm_filter(dhd_pub_t *dhd, } #endif /* BCM_ROUTER_DHD */ +#ifdef DHD_LINUX_STD_FW_API +int dhd_get_download_buffer(dhd_pub_t *dhd, char *file_path, download_type_t component, + char ** buffer, int *length) +{ + int ret = BCME_ERROR; + const struct firmware *fw = NULL; +#ifdef SUPPORT_OTA_UPDATE + uint8 *buf = NULL; + int len = 0; + ota_update_info_t *ota_info = &dhd->ota_update_info; +#endif /* SUPPORT_OTA_UPDATE */ + +#ifdef SUPPORT_OTA_UPDATE + if (component == CLM_BLOB) { + if (ota_info->clm_len) { + DHD_ERROR(("Using OTA CLM_BLOB\n")); + buf = ota_info->clm_buf; + len = ota_info->clm_len; + } + } + else if (component == NVRAM) { + if (ota_info->nvram_len) { + DHD_ERROR(("Using OTA NVRAM.\n")); + buf = ota_info->nvram_buf; + len = ota_info->nvram_len; + } + } +#endif /* SUPPORT_OTA_UPDATE */ + +#ifdef SUPPORT_OTA_UPDATE + if (len) { + *buffer = (char *)buf; + *length = len; + } + else +#endif /* SUPPORT_OTA_UPDATE */ + { + if (file_path) { + ret = dhd_os_get_img_fwreq(&fw, file_path); + if (ret < 0) { + DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n", + ret)); + goto err; + } else { + if ((fw->size <= 0 || fw->size > *length)) { + DHD_ERROR(("fw->size = %zu, *length = %d\n", fw->size, *length)); + *length = fw->size; + goto err; + } + *buffer = VMALLOCZ(dhd->osh, fw->size); + if (*buffer == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", + __FUNCTION__, (int)fw->size)); + ret = BCME_NOMEM; + goto err; + } + *length = fw->size; + ret = memcpy_s(*buffer, fw->size, fw->data, fw->size); + if (ret != BCME_OK) { + DHD_ERROR(("%s: memcpy_s failed, err : %d\n", + __FUNCTION__, ret)); + goto err; + } + ret = BCME_OK; + } + } + } +err: + if (fw) { + dhd_os_close_img_fwreq(fw); + } + return ret; +} + +#else + /* Given filename and download type, returns a buffer pointer and length * for download to f/w. Type can be FW or NVRAM. * @@ -7923,6 +7994,7 @@ err: return ret; } +#endif /* DHD_LINUX_STD_FW_API */ int dhd_download_2_dongle(dhd_pub_t *dhd, char *iovar, uint16 flag, uint16 dload_type, @@ -7963,9 +8035,9 @@ dhd_download_blob(dhd_pub_t *dhd, unsigned char *buf, { int chunk_len; -#if !defined(LINUX) && !defined(linux) +#if (!defined(LINUX) && !defined(linux)) || defined(DHD_LINUX_STD_FW_API) int cumulative_len = 0; -#endif /* !LINUX && !linux */ +#endif /* !LINUX && !linux || DHD_LINUX_STD_FW_API */ int size2alloc; unsigned char *new_buf; int err = 0, data_offset; @@ -7977,7 +8049,7 @@ dhd_download_blob(dhd_pub_t *dhd, unsigned char *buf, if ((new_buf = (unsigned char *)MALLOCZ(dhd->osh, size2alloc)) != NULL) { do { -#if !defined(LINUX) && !defined(linux) +#if (!defined(LINUX) && !defined(linux)) || defined(DHD_LINUX_STD_FW_API) if (len >= MAX_CHUNK_LEN) chunk_len = MAX_CHUNK_LEN; else @@ -7994,7 +8066,7 @@ dhd_download_blob(dhd_pub_t *dhd, unsigned char *buf, err = BCME_ERROR; goto exit; } -#endif /* !LINUX && !linux */ +#endif /* !LINUX && !linux || DHD_LINUX_STD_FW_API */ if (len - chunk_len == 0) dl_flag |= DL_END; @@ -8005,13 +8077,13 @@ dhd_download_blob(dhd_pub_t *dhd, unsigned char *buf, len = len - chunk_len; } while ((len > 0) && (err == 0)); -#if !defined(LINUX) && !defined(linux) +#if (!defined(LINUX) && !defined(linux)) || defined(DHD_LINUX_STD_FW_API) MFREE(dhd->osh, new_buf, size2alloc); #endif /* !LINUX && !linux */ } else { err = BCME_NOMEM; } -#if defined(LINUX) || defined(linux) +#if (defined(LINUX) || defined(linux)) && !defined(DHD_LINUX_STD_FW_API) exit: if (new_buf) { MFREE(dhd->osh, new_buf, size2alloc); @@ -8258,7 +8330,7 @@ int dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) { char *clm_blob_path; - int len; + int len = 0, memblock_len = 0; char *memblock = NULL; int err = BCME_OK; char iovbuf[WLC_IOCTL_SMLEN]; @@ -8272,7 +8344,11 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) clm_blob_path = clm_path; DHD_TRACE(("clm path from module param:%s\n", clm_path)); } else { +#ifdef DHD_LINUX_STD_FW_API + clm_blob_path = DHD_CLM_NAME; +#else clm_blob_path = VENDOR_PATH CONFIG_BCMDHD_CLM_PATH; +#endif /* DHD_LINUX_STD_FW_API */ } /* If CLM blob file is found on the filesystem, download the file. @@ -8280,11 +8356,21 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) * validate the country code before proceeding with the initialization. * If country code is not valid, fail the initialization. */ -#if !defined(LINUX) && !defined(linux) +#if (!defined(LINUX) && !defined(linux)) || defined(DHD_LINUX_STD_FW_API) len = MAX_CLM_BUF_SIZE; dhd_get_download_buffer(dhd, clm_blob_path, CLM_BLOB, &memblock, &len); +#ifdef DHD_LINUX_STD_FW_API + memblock_len = len; +#else + memblock_len = MAX_CLM_BUF_SIZE; +#endif /* DHD_LINUX_STD_FW_API */ #else memblock = dhd_os_open_image1(dhd, (char *)clm_blob_path); + len = dhd_os_get_image_size(memblock); + BCM_REFERENCE(memblock_len); +#endif /* !LINUX && !linux || DHD_LINUX_STD_FW_API */ + +#if defined(LINUX) || defined(linux) if (memblock == NULL) { printf("%s: Ignore clm file %s\n", __FUNCTION__, clm_path); #if defined(DHD_BLOB_EXISTENCE_CHECK) @@ -8301,8 +8387,6 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) #endif /* DHD_BLOB_EXISTENCE_CHECK */ goto exit; } - - len = dhd_os_get_image_size(memblock); #endif /* !LINUX && !linux */ if ((len > 0) && (len < MAX_CLM_BUF_SIZE) && memblock) { @@ -8368,10 +8452,10 @@ dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) exit: if (memblock) { -#if defined(LINUX) || defined(linux) +#if (defined(LINUX) || defined(linux)) && !defined(DHD_LINUX_STD_FW_API) dhd_os_close_image1(dhd, memblock); #else - dhd_free_download_buffer(dhd, memblock, MAX_CLM_BUF_SIZE); + dhd_free_download_buffer(dhd, memblock, memblock_len); #endif /* LINUX || linux */ } @@ -8384,7 +8468,11 @@ void dhd_free_download_buffer(dhd_pub_t *dhd, void *buffer, int length) #ifdef CACHE_FW_IMAGES return; #endif +#if defined(DHD_LINUX_STD_FW_API) + VMFREE(dhd->osh, buffer, length); +#else MFREE(dhd->osh, buffer, length); +#endif /* DHD_LINUX_STD_FW_API */ } #ifdef REPORT_FATAL_TIMEOUTS @@ -9063,8 +9151,13 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, int32 i = 0; uint8 *pfw_id = NULL; uint32 fwid = 0; +#ifdef DHD_LINUX_STD_FW_API + int err = 0; + const struct firmware *fw = NULL; +#else void *file = NULL; int file_len = 0; +#endif /* DHD_LINUX_STD_FW_API */ char fwid_str[FWID_STR_LEN]; uint32 hdr_logstrs_size = 0; @@ -9097,6 +9190,23 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, * both logstrs.bin and fw bin */ +#ifdef DHD_LINUX_STD_FW_API + err = dhd_os_get_img_fwreq(&fw, st_str_file_path); + if (err < 0) { + DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n", + err)); + goto error; + } + memset(fwid_str, 0, sizeof(fwid_str)); + err = memcpy_s(fwid_str, (sizeof(fwid_str) - 1), + &(fw->data[fw->size - (sizeof(fwid_str) - 1)]), + (sizeof(fwid_str) - 1)); + if (err) { + DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n", + __FUNCTION__, err)); + goto error; + } +#else /* read the FWID from fw bin */ file = dhd_os_open_image1(NULL, st_str_file_path); if (!file) { @@ -9119,6 +9229,7 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, DHD_ERROR(("%s: read fw file failed !\n", __FUNCTION__)); goto error; } +#endif /* DHD_LINUX_STD_FW_API */ pfw_id = (uint8 *)bcmstrnstr(fwid_str, sizeof(fwid_str) - 1, FWID_STR_1, strlen(FWID_STR_1)); if (!pfw_id) { @@ -9156,9 +9267,15 @@ dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, hdr_logstrs_size = hdr->logstrs_size; error: +#ifdef DHD_LINUX_STD_FW_API + if (fw) { + dhd_os_close_img_fwreq(fw); + } +#else if (file) { dhd_os_close_image1(NULL, file); } +#endif /* DHD_LINUX_STD_FW_API */ if (match_fail) { return BCME_DECERR; } @@ -9223,6 +9340,101 @@ error: return BCME_OK; } /* dhd_parse_logstrs_file */ +#ifdef DHD_LINUX_STD_FW_API +int dhd_parse_map_file(osl_t *osh, void *ptr, uint32 *ramstart, uint32 *rodata_start, + uint32 *rodata_end) +{ + char *raw_fmts = NULL, *raw_fmts_loc = NULL; + uint32 read_size = READ_NUM_BYTES, offset = 0; + int error = 0; + char * cptr = NULL; + char c; + uint8 count = 0; + uint32 size = 0; + + *ramstart = 0; + *rodata_start = 0; + *rodata_end = 0; + size = (uint32)(((struct firmware *)ptr)->size); + + /* Allocate 1 byte more than read_size to terminate it with NULL */ + raw_fmts = MALLOCZ(osh, read_size + 1); + if (raw_fmts == NULL) { + DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", __FUNCTION__)); + goto fail; + } + + /* read ram start, rodata_start and rodata_end values from map file */ + while (count != ALL_MAP_VAL) + { + /* Bound check for size before doing memcpy() */ + if ((offset + read_size) > size) { + read_size = size - offset; + } + + error = memcpy_s(raw_fmts, read_size, + (((char *)((struct firmware *)ptr)->data) + offset), read_size); + if (error) { + DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n", + __FUNCTION__, error)); + goto fail; + } + /* End raw_fmts with NULL as strstr expects NULL terminated strings */ + raw_fmts[read_size] = '\0'; + + /* Get ramstart address */ + raw_fmts_loc = raw_fmts; + if (!(count & RAMSTART_BIT) && + (cptr = bcmstrnstr(raw_fmts_loc, read_size, ramstart_str, + strlen(ramstart_str)))) { + cptr = cptr - BYTES_AHEAD_NUM; + sscanf(cptr, "%x %c text_start", ramstart, &c); + count |= RAMSTART_BIT; + } + + /* Get ram rodata start address */ + raw_fmts_loc = raw_fmts; + if (!(count & RDSTART_BIT) && + (cptr = bcmstrnstr(raw_fmts_loc, read_size, rodata_start_str, + strlen(rodata_start_str)))) { + cptr = cptr - BYTES_AHEAD_NUM; + sscanf(cptr, "%x %c rodata_start", rodata_start, &c); + count |= RDSTART_BIT; + } + + /* Get ram rodata end address */ + raw_fmts_loc = raw_fmts; + if (!(count & RDEND_BIT) && + (cptr = bcmstrnstr(raw_fmts_loc, read_size, rodata_end_str, + strlen(rodata_end_str)))) { + cptr = cptr - BYTES_AHEAD_NUM; + sscanf(cptr, "%x %c rodata_end", rodata_end, &c); + count |= RDEND_BIT; + } + + if ((offset + read_size) >= size) { + break; + } + + memset(raw_fmts, 0, read_size); + offset += (read_size - GO_BACK_FILE_POS_NUM_BYTES); + } + +fail: + if (raw_fmts) { + MFREE(osh, raw_fmts, read_size + 1); + raw_fmts = NULL; + } + if (count == ALL_MAP_VAL) { + return BCME_OK; + } + else { + DHD_ERROR(("%s: readmap error 0X%x \n", __FUNCTION__, + count)); + return BCME_ERROR; + } +} /* dhd_parse_map_file */ +#else int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart, uint32 *rodata_start, uint32 *rodata_end) { @@ -9320,6 +9532,7 @@ fail: } } /* dhd_parse_map_file */ +#endif /* DHD_LINUX_STD_FW_API */ #ifdef PCIE_FULL_DONGLE int diff --git a/bcmdhd.101.10.361.x/dhd_config.c b/bcmdhd.101.10.361.x/dhd_config.c index 0c623d6..5433abd 100755 --- a/bcmdhd.101.10.361.x/dhd_config.c +++ b/bcmdhd.101.10.361.x/dhd_config.c @@ -67,6 +67,10 @@ uint dump_msg_level = 0; #define MAXSZ_BUF 4096 #define MAXSZ_CONFIG 8192 +extern uint wl_reassoc_support; +#ifdef BTC_WAR +extern int btc_war; +#endif /* BTC_WAR */ #if defined(BCMSDIO) && defined(DYNAMIC_MAX_HDR_READ) extern uint firstread; #endif @@ -140,9 +144,9 @@ const chip_name_map_t chip_name_map[] = { {BCM4375_CHIP_ID, 5, DONT_CARE, "bcm4375b4_pcie_ag", "ap6275hh3"}, #endif #ifdef BCMDBUS - {BCM43143_CHIP_ID, 2, DONT_CARE, "bcm43143b0", ""}, - {BCM43242_CHIP_ID, 1, DONT_CARE, "bcm43242a1_ag", ""}, - {BCM43569_CHIP_ID, 2, DONT_CARE, "bcm4358u_ag", "ap62x8"}, + {BCM43143_CHIP_ID, 2, DONT_CARE, "bcm43143b0", ""}, + {BCM43242_CHIP_ID, 1, DONT_CARE, "bcm43242a1_ag", ""}, + {BCM43569_CHIP_ID, 2, DONT_CARE, "bcm4358u_ag", "ap62x8"}, #endif }; @@ -213,6 +217,91 @@ const chip_cisaddr_map_t chip_cisaddr_map[] = { extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); #endif +#ifdef WL_CFG80211 +bool +dhd_conf_legacy_chip_check(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + + if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || + chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || + chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4371_CHIP_ID || + chip == BCM43430_CHIP_ID || + chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID || + chip == BCM4359_CHIP_ID || + chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID || + chip == BCM43569_CHIP_ID) { + return true; + } + + return false; +} + +bool +dhd_conf_new_chip_check(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + + if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || + chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || + chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4371_CHIP_ID || + chip == BCM43430_CHIP_ID || + chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID || + chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID || + chip == BCM43569_CHIP_ID) { + return false; + } + + return true; +} + +bool +dhd_conf_extsae_chip(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + + if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || + chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || + chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID || + chip == BCM43569_CHIP_ID) { + return false; + } + + return true; +} +#endif + +#ifdef BCMSDIO +bool +dhd_conf_disable_slpauto(dhd_pub_t *dhd) +{ + uint chip = dhd->conf->chip; + + if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || + chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || + chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || + chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || + chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || + chip == BCM4371_CHIP_ID || + chip == BCM43430_CHIP_ID || + chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID || + chip == BCM4359_CHIP_ID) { + return false; + } + + return true; +} +#endif + void dhd_conf_free_chip_nv_path_list(wl_chip_nv_path_list_ctrl_t *chip_nv_list) { @@ -691,7 +780,7 @@ dhd_conf_match_chip(dhd_pub_t *dhd, uint ag_type) chiprev = dhd->conf->chiprev; for (i=0; ichip == chip && row->chiprev == chiprev && (row->ag_type == ag_type || ag_type == DONT_CARE || row->ag_type == DONT_CARE)) { @@ -724,7 +813,7 @@ dhd_conf_match_module(dhd_pub_t *dhd) #ifdef BCMSDIO for (i=0; idevid == devid && row->chip == chip && row->chiprev == chiprev && !strcmp(row->module_name, dhd->conf->module_name)) { return row; @@ -734,7 +823,7 @@ dhd_conf_match_module(dhd_pub_t *dhd) #ifdef BCMPCIE for (i=0; idevid == devid && row->chip == chip && row->chiprev == chiprev && row->svid == svid && row->ssid == ssid) { return row; @@ -746,21 +835,65 @@ dhd_conf_match_module(dhd_pub_t *dhd) } #endif -int -dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) +char * +dhd_conf_get_chip_name(dhd_pub_t *dhd, int ag_type, bool *chip_map_v2) { #ifdef UPDATE_MODULE_NAME - const module_name_map_t* row_module = NULL; + const module_name_map_t *row_module = NULL; +#endif + const chip_name_map_t *row_chip = NULL; + char *name = NULL; + + *chip_map_v2 = FALSE; +#ifdef UPDATE_MODULE_NAME + row_module = dhd_conf_match_module(dhd); + if (row_module && strlen(row_module->chip_name)) { + name = row_module->chip_name; + } else +#endif + { + row_chip = dhd_conf_match_chip(dhd, ag_type); + if (row_chip && strlen(row_chip->chip_name)) { + name = row_chip->chip_name; + } + } + + return name; +} + +char * +dhd_conf_get_module_name(dhd_pub_t *dhd, int ag_type) +{ +#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME) + const module_name_map_t *row_module = NULL; +#endif + const chip_name_map_t *row_chip = NULL; + char *name = NULL; + +#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME) + row_module = dhd_conf_match_module(dhd); + if (row_module && strlen(row_module->module_name)) { + name = row_module->module_name; + } else #endif - const chip_name_map_t* row_chip = NULL; + { + row_chip = dhd_conf_match_chip(dhd, ag_type); + if (row_chip && strlen(row_chip->module_name)) { + name = row_chip->module_name; + } + } + + return name; +} + +int +dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) +{ int fw_type, ag_type; - uint chip, chiprev; - char *name_ptr; + char *name_ptr, *chip_name = NULL; + bool chip_map_v2; int i; - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - if (fw_path[0] == '\0') { #ifdef CONFIG_BCMDHD_FW_PATH bcm_strncpy_s(fw_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1); @@ -811,36 +944,10 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) fw_type = FW_TYPE_EZMESH; #endif /* WLEASYMESH */ - row_chip = dhd_conf_match_chip(dhd, ag_type); - if (row_chip && strlen(row_chip->chip_name)) { - strcpy(name_ptr, "fw_"); - strcat(name_ptr, row_chip->chip_name); -#ifdef BCMUSBDEV_COMPOSITE - strcat(name_ptr, "_cusb"); -#endif - if (fw_type == FW_TYPE_APSTA) - strcat(name_ptr, "_apsta.bin"); - else if (fw_type == FW_TYPE_P2P) - strcat(name_ptr, "_p2p.bin"); - else if (fw_type == FW_TYPE_MESH) - strcat(name_ptr, "_mesh.bin"); - else if (fw_type == FW_TYPE_EZMESH) - strcat(name_ptr, "_ezmesh.bin"); - else if (fw_type == FW_TYPE_ES) - strcat(name_ptr, "_es.bin"); - else if (fw_type == FW_TYPE_MFG) - strcat(name_ptr, "_mfg.bin"); - else if (fw_type == FW_TYPE_MINIME) - strcat(name_ptr, "_minime.bin"); - else - strcat(name_ptr, ".bin"); - } - -#ifdef UPDATE_MODULE_NAME - row_module = dhd_conf_match_module(dhd); - if (row_module && strlen(row_module->chip_name)) { + chip_name = dhd_conf_get_chip_name(dhd, ag_type, &chip_map_v2); + if (chip_name) { strcpy(name_ptr, "fw_"); - strcat(name_ptr, row_module->chip_name); + strcat(name_ptr, chip_name); #ifdef BCMUSBDEV_COMPOSITE strcat(name_ptr, "_cusb"); #endif @@ -861,7 +968,6 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) else strcat(name_ptr, ".bin"); } -#endif dhd->conf->fw_type = fw_type; @@ -877,17 +983,10 @@ dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) void dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path, int ag_type) { -#ifdef UPDATE_MODULE_NAME - const module_name_map_t* row_module = NULL; -#endif - const chip_name_map_t* row_chip = NULL; - uint chip, chiprev; - char *name_ptr; + char *name_ptr, *chip_name = NULL; + bool chip_map_v2; int i; - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - if (clm_path[0] == '\0') { CONFIG_MSG("clm path is null\n"); return; @@ -904,34 +1003,21 @@ dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path, int ag_type) } name_ptr = &clm_path[i]; - row_chip = dhd_conf_match_chip(dhd, ag_type); - if (row_chip && strlen(row_chip->chip_name)) { + chip_name = dhd_conf_get_chip_name(dhd, ag_type, &chip_map_v2); + if (chip_name) { strcpy(name_ptr, "clm_"); - strcat(name_ptr, row_chip->chip_name); + strcat(name_ptr, chip_name); strcat(name_ptr, ".blob"); } -#ifdef UPDATE_MODULE_NAME - row_module = dhd_conf_match_module(dhd); - if (row_module && strlen(row_module->chip_name)) { - strcpy(name_ptr, "clm_"); - strcat(name_ptr, row_module->chip_name); - strcat(name_ptr, ".blob"); - } -#endif - CONFIG_TRACE("clm_path=%s\n", clm_path); } void dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type) { -#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME) - const module_name_map_t* row_module = NULL; -#endif - const chip_name_map_t* row_chip = NULL; uint chip, chiprev; - char *name_ptr, nv_name[32]; + char *name_ptr, *module_name = NULL, nv_name[32]; int i; chip = dhd->conf->chip; @@ -959,10 +1045,10 @@ dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type) } name_ptr = &nv_path[i]; - row_chip = dhd_conf_match_chip(dhd, ag_type); - if (row_chip && strlen(row_chip->module_name)) { + module_name = dhd_conf_get_module_name(dhd, ag_type); + if (module_name) { strcpy(name_ptr, "nvram_"); - strcat(name_ptr, row_chip->module_name); + strcat(name_ptr, module_name); #ifdef BCMUSBDEV_COMPOSITE strcat(name_ptr, "_cusb"); #endif @@ -979,26 +1065,17 @@ dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type) if (dhd->conf->chip == BCM4359_CHIP_ID) { struct file *fp; // compatible for AP6398S and AP6398SA - fp = filp_open(nv_path, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(nv_path, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { strcpy(name_ptr, nv_name); } else { - filp_close((struct file *)fp, NULL); + dhd_filp_close((struct file *)fp, NULL); } } #endif } #endif -#if defined(BCMPCIE) && defined(UPDATE_MODULE_NAME) - row_module = dhd_conf_match_module(dhd); - if (row_module && strlen(row_module->module_name)) { - strcpy(name_ptr, "nvram_"); - strcat(name_ptr, row_module->module_name); - strcat(name_ptr, ".txt"); - } -#endif - for (i=0; iconf->nv_by_chip.count; i++) { if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip && chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) { @@ -1039,17 +1116,10 @@ dhd_conf_copy_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_pat void dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path) { -#ifdef UPDATE_MODULE_NAME - const module_name_map_t* row_module = NULL; -#endif - const chip_name_map_t* row_chip = NULL; - uint chip, chiprev; - char *name_ptr; + char *name_ptr, *chip_name = NULL; + bool chip_map_v2; int i; - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - if (conf_path[0] == '\0') { CONFIG_MSG("config path is null\n"); return; @@ -1066,21 +1136,12 @@ dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path) } name_ptr = &conf_path[i]; - row_chip = dhd_conf_match_chip(dhd, DONT_CARE); - if (row_chip && strlen(row_chip->chip_name)) { - strcpy(name_ptr, "config_"); - strcat(name_ptr, row_chip->chip_name); - strcat(name_ptr, ".txt"); - } - -#ifdef UPDATE_MODULE_NAME - row_module = dhd_conf_match_module(dhd); - if (row_module && strlen(row_module->chip_name)) { + chip_name = dhd_conf_get_chip_name(dhd, DONT_CARE, &chip_map_v2); + if (chip_name) { strcpy(name_ptr, "config_"); - strcat(name_ptr, row_module->chip_name); + strcat(name_ptr, chip_name); strcat(name_ptr, ".txt"); } -#endif CONFIG_TRACE("config_path=%s\n", conf_path); } @@ -1147,7 +1208,10 @@ dhd_conf_set_tput_patch(dhd_pub_t *dhd) if (conf->tput_patch) { conf->mtu = 1500; - conf->pktsetsum = TRUE; +/* set pktsetsum false by default since this will cause to + * the checksum is wrong of downloaded file +*/ + conf->pktsetsum = FALSE; #ifdef BCMSDIO conf->dhd_dpc_prio = 98; /* need to check if CPU can support multi-core first, @@ -1252,6 +1316,70 @@ dhd_conf_dump_tput_patch(dhd_pub_t *dhd) } #endif /* DHD_TPUT_PATCH */ +#ifdef DHD_LINUX_STD_FW_API +#define FIRMWARE_CLASS_PATH "/sys/module/firmware_class/parameters/path" +static void +dhd_conf_get_filename(char *pFilename) +{ + const char *pName = NULL; + + if ((pFilename) && (*pFilename)) { + // back/reverse search the '/' + pName = strrchr(pFilename, '/'); + if (NULL == pName) { + pName = pFilename; + } else { + if (pName[1]) { + pName++; + } else { + pName = NULL; + } + } + } + + if (pName) + strcpy(pFilename, pName); + + return; +} + +static void +dhd_conf_add_filepath(dhd_pub_t *dhd, char *pFilename) +{ + char path[WLC_IOCTL_SMLEN]; + char *name_ptr, *module_name = NULL; + + if (strlen(pFilename)) { + name_ptr = path; + strcpy(name_ptr, ""); +#ifdef FW_AMPAK_PATH + strcat(name_ptr, "/"); + strcat(name_ptr, FW_AMPAK_PATH); +#endif +#ifdef MODULE_PATH +#if defined(BCMSDIO) && defined(GET_OTP_MODULE_NAME) + if (strlen(dhd->conf->module_name)) + module_name = dhd->conf->module_name; + else +#endif + { + module_name = dhd_conf_get_module_name(dhd, DONT_CARE); + } +#endif + if (module_name) { + strcat(name_ptr, "/"); + strcat(name_ptr, module_name); + } + strcat(name_ptr, "/"); + strcat(name_ptr, pFilename); + strcpy(pFilename, path); + } + + return; +} + +#endif /* DHD_LINUX_STD_FW_API */ + void dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path) { @@ -1260,6 +1388,14 @@ dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path) /* External conf takes precedence if specified */ dhd_conf_preinit(dhd); +#ifdef DHD_LINUX_STD_FW_API + // preprocess the filename to only left 'name' + dhd_conf_get_filename(fw_path); + dhd_conf_get_filename(nv_path); + dhd_conf_get_filename(dhd->clm_path); + dhd_conf_get_filename(dhd->conf_path); +#endif + if (dhd->conf_path[0] == '\0') { dhd_conf_copy_path(dhd, "config.txt", dhd->conf_path, nv_path); } @@ -1270,11 +1406,6 @@ dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path) dhd_conf_set_conf_name_by_chip(dhd, dhd->conf_path); #endif - dhd_conf_read_config(dhd, dhd->conf_path); -#ifdef DHD_TPUT_PATCH - dhd_conf_dump_tput_patch(dhd); -#endif - ag_type = dhd_conf_set_fw_name_by_chip(dhd, fw_path); dhd_conf_set_nv_name_by_chip(dhd, nv_path, ag_type); dhd_conf_set_clm_name_by_chip(dhd, dhd->clm_path, ag_type); @@ -1283,10 +1414,23 @@ dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path) dhd_conf_set_nv_name_by_mac(dhd, nv_path); #endif +#ifdef DHD_LINUX_STD_FW_API + // preprocess the filename to only left 'name' + dhd_conf_add_filepath(dhd, fw_path); + dhd_conf_add_filepath(dhd, nv_path); + dhd_conf_add_filepath(dhd, dhd->clm_path); + dhd_conf_add_filepath(dhd, dhd->conf_path); +#endif + CONFIG_MSG("Final fw_path=%s\n", fw_path); CONFIG_MSG("Final nv_path=%s\n", nv_path); CONFIG_MSG("Final clm_path=%s\n", dhd->clm_path); CONFIG_MSG("Final conf_path=%s\n", dhd->conf_path); + + dhd_conf_read_config(dhd, dhd->conf_path); +#ifdef DHD_TPUT_PATCH + dhd_conf_dump_tput_patch(dhd); +#endif } int @@ -1298,17 +1442,17 @@ dhd_conf_set_intiovar(dhd_pub_t *dhd, int ifidx, uint cmd, char *name, int val, if (val >= def) { if (down) { - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0) + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, ifidx)) < 0) CONFIG_ERROR("WLC_DOWN setting failed %d\n", ret); } if (cmd == WLC_SET_VAR) { CONFIG_TRACE("set %s %d\n", name, val); bcm_mkiovar(name, (char *)&val, sizeof(val), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx)) < 0) CONFIG_ERROR("%s setting failed %d\n", name, ret); } else { CONFIG_TRACE("set %s %d %d\n", name, cmd, val); - if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0) + if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, ifidx)) < 0) CONFIG_ERROR("%s setting failed %d\n", name, ret); } } @@ -1404,13 +1548,147 @@ dhd_conf_get_iovar(dhd_pub_t *dhd, int ifidx, int cmd, char *name, } else { CONFIG_ERROR("mkiovar %s failed\n", name); } - } else { - ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, FALSE, 0); - if (ret < 0) - CONFIG_ERROR("get iovar %s failed %d\n", name, ret); + } else { + ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, FALSE, 0); + if (ret < 0) + CONFIG_ERROR("get iovar %s failed %d\n", name, ret); + } + + return ret; +} + +static int +dhd_conf_get_ioctl_ver(dhd_pub_t *dhd) +{ + int ret = 0; + s32 val = 0; + + dhd->conf->ioctl_ver = WLC_IOCTL_VERSION; + ret = dhd_conf_get_iovar(dhd, 0, WLC_GET_VERSION, "WLC_GET_VERSION", + (char *)&val, sizeof(val)); + if (ret) { + return ret; + } + val = dtoh32(val); + if (val != WLC_IOCTL_VERSION && val != 1) { + CONFIG_ERROR("Version mismatch, please upgrade. Got %d, expected %d or 1\n", + val, WLC_IOCTL_VERSION); + return BCME_VERSION; + } + dhd->conf->ioctl_ver = val; + CONFIG_TRACE("ioctl_ver=%d\n", dhd->conf->ioctl_ver); + + return ret; +} + +int +dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec) +{ + int bcmerror = -1; + + memset(cspec, 0, sizeof(wl_country_t)); + bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t)); + if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t), + FALSE, 0)) < 0) + CONFIG_ERROR("country code getting failed %d\n", bcmerror); + + return bcmerror; +} + +int +dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec) +{ + int bcmerror = -1; + struct dhd_conf *conf = dhd->conf; + country_list_t *country = conf->country_head; + +#ifdef CCODE_LIST + bcmerror = dhd_ccode_map_country_list(dhd, cspec); +#endif + // **:XZ/11 => return XZ/11 if not found + // **:**/0 => return user specified ccode if not found, but set regrev 0 + while (country != NULL) { + if (!strncmp("**", country->cspec.country_abbrev, 2)) { + if (!strncmp("**", country->cspec.ccode, 2)) { + cspec->rev = 0; + bcmerror = 0; + break; + } + memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ); + cspec->rev = country->cspec.rev; + bcmerror = 0; + break; + } else if (!strncmp(cspec->country_abbrev, + country->cspec.country_abbrev, 2)) { + memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ); + cspec->rev = country->cspec.rev; + bcmerror = 0; + break; + } + country = country->next; + } + + if (!bcmerror) + CONFIG_MSG("%s/%d\n", cspec->ccode, cspec->rev); + + return bcmerror; +} + +int +dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec) +{ + int bcmerror = -1; + + memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t)); + + CONFIG_MSG("set country %s, revision %d\n", cspec->ccode, cspec->rev); + bcmerror = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "country", (char *)cspec, + sizeof(wl_country_t), FALSE); + dhd_conf_get_country(dhd, cspec); + CONFIG_MSG("Country code: %s (%s/%d)\n", + cspec->country_abbrev, cspec->ccode, cspec->rev); + + return bcmerror; +} + +int +dhd_conf_fix_country(dhd_pub_t *dhd) +{ + int bcmerror = -1; + int band; + wl_uint32_list_t *list; + u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; + wl_country_t cspec; + + if (!(dhd && dhd->conf)) { + return bcmerror; + } + + memset(valid_chan_list, 0, sizeof(valid_chan_list)); + list = (wl_uint32_list_t *)(void *) valid_chan_list; + list->count = htod32(WL_NUMCHANNELS); + if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, valid_chan_list, + sizeof(valid_chan_list), FALSE, 0)) < 0) { + CONFIG_ERROR("get channels failed with %d\n", bcmerror); + } + + band = dhd_conf_get_band(dhd); + + if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G || band==-1) && + dtoh32(list->count)<11)) { + CONFIG_ERROR("bcmerror=%d, # of channels %d\n", + bcmerror, dtoh32(list->count)); + dhd_conf_map_country_list(dhd, &dhd->conf->cspec); + if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) { + strcpy(cspec.country_abbrev, "US"); + cspec.rev = 0; + strcpy(cspec.ccode, "US"); + dhd_conf_map_country_list(dhd, &cspec); + dhd_conf_set_country(dhd, &cspec); + } } - return ret; + return bcmerror; } static int @@ -1620,6 +1898,34 @@ dhd_conf_scan_mac(dhd_pub_t * dhd, char *cmd, char *buf) } #endif +int +dhd_conf_country(dhd_pub_t *dhd, char *cmd, char *buf) +{ + wl_country_t cspec = {{0}, 0, {0}}; + wl_country_t cur_cspec = {{0}, 0, {0}}; + int err = 0; + + if (buf) { + dhd_conf_get_country(dhd, &cur_cspec); + strlcpy(cspec.country_abbrev, buf, WL_CCODE_LEN + 1); + strlcpy(cspec.ccode, buf, WL_CCODE_LEN + 1); + dhd_conf_map_country_list(dhd, &cspec); + if (!memcmp(&cspec.ccode, &cur_cspec.ccode, WL_CCODE_LEN + 1) && + (cspec.rev == cur_cspec.rev)) { + CONFIG_MSG("country code = %s/%d is already configured\n", + cspec.ccode, cspec.rev); + return 0; + } + err = dhd_conf_set_country(dhd, &cspec); + if (!err) { + dhd_conf_fix_country(dhd); + } + dhd_conf_get_country(dhd, &dhd->dhd_cspec); + } + + return err; +} + typedef int (tpl_parse_t)(dhd_pub_t *dhd, char *name, char *buf); typedef struct iovar_tpl_t { @@ -1635,6 +1941,7 @@ const iovar_tpl_t iovar_tpl_list[] = { #ifndef SUPPORT_RANDOM_MAC_SCAN {WLC_SET_VAR, "scanmac", dhd_conf_scan_mac}, #endif + {WLC_SET_VAR, "country", dhd_conf_country}, }; static int iovar_tpl_parse(const iovar_tpl_t *tpl, int tpl_count, @@ -1725,116 +2032,6 @@ dhd_conf_get_band(dhd_pub_t *dhd) return band; } -int -dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec) -{ - int bcmerror = -1; - - memset(cspec, 0, sizeof(wl_country_t)); - bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t)); - if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t), - FALSE, 0)) < 0) - CONFIG_ERROR("country code getting failed %d\n", bcmerror); - - return bcmerror; -} - -int -dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec) -{ - int bcmerror = -1; - struct dhd_conf *conf = dhd->conf; - country_list_t *country = conf->country_head; - -#ifdef CCODE_LIST - bcmerror = dhd_ccode_map_country_list(dhd, cspec); -#endif - // **:XZ/11 => return XZ/11 if not found - // **:**/0 => return user specified ccode if not found, but set regrev 0 - while (country != NULL) { - if (!strncmp("**", country->cspec.country_abbrev, 2)) { - if (!strncmp("**", country->cspec.ccode, 2)) { - cspec->rev = 0; - bcmerror = 0; - break; - } - memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ); - cspec->rev = country->cspec.rev; - bcmerror = 0; - break; - } else if (!strncmp(cspec->country_abbrev, - country->cspec.country_abbrev, 2)) { - memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ); - cspec->rev = country->cspec.rev; - bcmerror = 0; - break; - } - country = country->next; - } - - if (!bcmerror) - CONFIG_MSG("%s/%d\n", cspec->ccode, cspec->rev); - - return bcmerror; -} - -int -dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec) -{ - int bcmerror = -1; - - memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t)); - - CONFIG_MSG("set country %s, revision %d\n", cspec->ccode, cspec->rev); - bcmerror = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "country", (char *)cspec, - sizeof(wl_country_t), FALSE); - dhd_conf_get_country(dhd, cspec); - CONFIG_MSG("Country code: %s (%s/%d)\n", - cspec->country_abbrev, cspec->ccode, cspec->rev); - - return bcmerror; -} - -int -dhd_conf_fix_country(dhd_pub_t *dhd) -{ - int bcmerror = -1; - int band; - wl_uint32_list_t *list; - u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; - wl_country_t cspec; - - if (!(dhd && dhd->conf)) { - return bcmerror; - } - - memset(valid_chan_list, 0, sizeof(valid_chan_list)); - list = (wl_uint32_list_t *)(void *) valid_chan_list; - list->count = htod32(WL_NUMCHANNELS); - if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, valid_chan_list, - sizeof(valid_chan_list), FALSE, 0)) < 0) { - CONFIG_ERROR("get channels failed with %d\n", bcmerror); - } - - band = dhd_conf_get_band(dhd); - - if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G || band==-1) && - dtoh32(list->count)<11)) { - CONFIG_ERROR("bcmerror=%d, # of channels %d\n", - bcmerror, dtoh32(list->count)); - dhd_conf_map_country_list(dhd, &dhd->conf->cspec); - if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) { - strcpy(cspec.country_abbrev, "US"); - cspec.rev = 0; - strcpy(cspec.ccode, "US"); - dhd_conf_map_country_list(dhd, &cspec); - dhd_conf_set_country(dhd, &cspec); - } - } - - return bcmerror; -} - bool dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel) { @@ -1857,39 +2054,39 @@ dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel) } int -dhd_conf_set_roam(dhd_pub_t *dhd) +dhd_conf_set_roam(dhd_pub_t *dhd, int ifidx) { int bcmerror = -1; struct dhd_conf *conf = dhd->conf; uint wnm_bsstrans_resp = 0; if (dhd->conf->chip == BCM4359_CHIP_ID) { - dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "wnm_bsstrans_resp", + dhd_conf_get_iovar(dhd, ifidx, WLC_GET_VAR, "wnm_bsstrans_resp", (char *)&wnm_bsstrans_resp, sizeof(wnm_bsstrans_resp)); if (wnm_bsstrans_resp == WL_BSSTRANS_POLICY_PRODUCT) { dhd->wbtext_policy = WL_BSSTRANS_POLICY_ROAM_ALWAYS; - dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "wnm_bsstrans_resp", + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "wnm_bsstrans_resp", WL_BSSTRANS_POLICY_ROAM_ALWAYS, 0, FALSE); } } dhd_roam_disable = conf->roam_off; - dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "roam_off", dhd->conf->roam_off, 0, FALSE); + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "roam_off", dhd->conf->roam_off, 0, FALSE); if (!conf->roam_off || !conf->roam_off_suspend) { CONFIG_MSG("set roam_trigger %d\n", conf->roam_trigger[0]); - dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_TRIGGER, "WLC_SET_ROAM_TRIGGER", + dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_ROAM_TRIGGER, "WLC_SET_ROAM_TRIGGER", (char *)conf->roam_trigger, sizeof(conf->roam_trigger), FALSE); CONFIG_MSG("set roam_scan_period %d\n", conf->roam_scan_period[0]); - dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_SCAN_PERIOD, "WLC_SET_ROAM_SCAN_PERIOD", + dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_ROAM_SCAN_PERIOD, "WLC_SET_ROAM_SCAN_PERIOD", (char *)conf->roam_scan_period, sizeof(conf->roam_scan_period), FALSE); CONFIG_MSG("set roam_delta %d\n", conf->roam_delta[0]); - dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_DELTA, "WLC_SET_ROAM_DELTA", + dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_ROAM_DELTA, "WLC_SET_ROAM_DELTA", (char *)conf->roam_delta, sizeof(conf->roam_delta), FALSE); - dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "fullroamperiod", + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "fullroamperiod", dhd->conf->fullroamperiod, 1, FALSE); } @@ -2184,9 +2381,8 @@ dhd_conf_add_pkt_filter(dhd_pub_t *dhd) * Case 3: magic pkt and event wake up * 1) dhd_master_mode=1 * 2) pkt_filter_delete=100, 102, 103, 104, 105, 106, 107 - * 3) pkt_filter_add=141 0 0 0 0xFFFFFFFFFFFF 0x000000000000 - * 4) magic_pkt_filter_add=141 0 1 12 - * 5) rekey_offload=1 + * 3) magic_pkt_filter_add=141 0 1 12 + * 4) rekey_offload=1 */ for(i=0; iconf->pkt_filter_add.count; i++) { dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i]; @@ -2525,7 +2721,7 @@ int dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period, char *packet, bool bcast) { - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + wl_mkeep_alive_pkt_v1_t *mkeep_alive_pktp; int ret = 0, len_bytes=0, buf_len=0; char *buf = NULL, *iovar_buf = NULL; uint8 *pdata; @@ -2542,8 +2738,8 @@ dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period, CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN); goto exit; } - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf; - mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION); + mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *)buf; + mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION_1); mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); mkeep_alive_pktp->keep_alive_id = id; buf_len += WL_MKEEP_ALIVE_FIXED_LEN; @@ -2786,7 +2982,7 @@ dhd_conf_suspend_resume_sta(dhd_pub_t *dhd, int ifidx, int suspend) #endif } else { - dhd_conf_get_iovar(dhd, 0, WLC_GET_PM, "WLC_GET_PM", (char *)&pm, sizeof(pm)); + dhd_conf_get_iovar(dhd, ifidx, WLC_GET_PM, "WLC_GET_PM", (char *)&pm, sizeof(pm)); CONFIG_TRACE("PM in suspend = %d\n", pm); if (conf->pm >= 0) pm = conf->pm; @@ -3436,7 +3632,15 @@ dhd_conf_read_roam_params(dhd_pub_t *dhd, char *full_param, uint len_param) else if (!strncmp("fullroamperiod=", full_param, len_param)) { conf->fullroamperiod = (int)simple_strtol(data, NULL, 10); CONFIG_MSG("fullroamperiod = %d\n", conf->fullroamperiod); - } else + } + else if (!strncmp("wl_reassoc_support=", full_param, len_param)) { + if (!strncmp(data, "0", 1)) + wl_reassoc_support = FALSE; + else + wl_reassoc_support = TRUE; + CONFIG_MSG("wl_reassoc_support = %d\n", wl_reassoc_support); + } + else return false; return true; @@ -3775,11 +3979,10 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param) dhd_doflow = TRUE; CONFIG_MSG("dhd_doflow = %d\n", dhd_doflow); } - else if (!strncmp("dhd_slpauto=", full_param, len_param) || - !strncmp("kso_enable=", full_param, len_param)) { + else if (!strncmp("dhd_slpauto=", full_param, len_param)) { if (!strncmp(data, "0", 1)) dhd_slpauto = FALSE; - else + else if (dhd_conf_disable_slpauto(dhd)) dhd_slpauto = TRUE; CONFIG_MSG("dhd_slpauto = %d\n", dhd_slpauto); } @@ -3947,6 +4150,10 @@ dhd_conf_read_pcie_params(dhd_pub_t *dhd, char *full_param, uint len_param) conf->d2h_intr_control = (int)simple_strtol(data, NULL, 10); CONFIG_MSG("d2h_intr_control = %d\n", conf->d2h_intr_control); } + else if (!strncmp("enq_hdr_pkt=", full_param, len_param)) { + conf->enq_hdr_pkt = (int)simple_strtol(data, NULL, 0); + CONFIG_MSG("enq_hdr_pkt = 0x%x\n", conf->enq_hdr_pkt); + } else return false; @@ -4189,6 +4396,12 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) conf->in4way = (int)simple_strtol(data, NULL, 0); CONFIG_MSG("in4way = 0x%x\n", conf->in4way); } +#ifdef BTC_WAR + else if (!strncmp("btc_war=", full_param, len_param)) { + btc_war = (int)simple_strtol(data, NULL, 0); + CONFIG_MSG("btc_war = 0x%x\n", btc_war); + } +#endif /* BTC_WAR */ else if (!strncmp("war=", full_param, len_param)) { conf->war = (int)simple_strtol(data, NULL, 0); CONFIG_MSG("war = 0x%x\n", conf->war); @@ -4376,33 +4589,37 @@ int dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path) { int bcmerror = -1, chip_match = -1; - uint len = 0, start_pos=0, end_pos=0; - void *image = NULL; + uint len = 0, memblock_len = 0, start_pos=0, end_pos=0; char *memblock = NULL; char *bufp, *pick = NULL, *pch; bool conf_file_exists; uint len_param; + len = MAXSZ_CONFIG; + conf_file_exists = ((conf_path != NULL) && (conf_path[0] != '\0')); if (!conf_file_exists) { CONFIG_MSG("config path %s\n", conf_path); return (0); } - if (conf_file_exists) { - image = dhd_os_open_image1(dhd, conf_path); - if (image == NULL) { - CONFIG_MSG("Ignore config file %s\n", conf_path); - goto err; - } - } + if (conf_file_exists) + bcmerror = dhd_get_download_buffer(dhd, conf_path, NVRAM, &memblock, + (int *)&len); + else + bcmerror = dhd_get_download_buffer(dhd, NULL, NVRAM, &memblock, (int *)&len); - memblock = MALLOC(dhd->osh, MAXSZ_CONFIG); - if (memblock == NULL) { - CONFIG_ERROR("Failed to allocate memory %d bytes\n", MAXSZ_CONFIG); + if (bcmerror != BCME_OK) { + CONFIG_MSG("Ignore config file %s\n", conf_path); goto err; } +#ifdef DHD_LINUX_STD_FW_API + memblock_len = len; +#else + memblock_len = MAXSZ_CONFIG; +#endif /* DHD_LINUX_STD_FW_API */ + pick = MALLOC(dhd->osh, MAXSZ_BUF); if (!pick) { CONFIG_ERROR("Failed to allocate memory %d bytes\n", MAXSZ_BUF); @@ -4410,9 +4627,6 @@ dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path) } /* Read variables */ - if (conf_file_exists) { - len = dhd_os_get_image_block(memblock, MAXSZ_CONFIG, image); - } if (len > 0 && len < MAXSZ_CONFIG) { bufp = (char *)memblock; bufp[len] = 0; @@ -4496,10 +4710,7 @@ err: MFREE(dhd->osh, pick, MAXSZ_BUF); if (memblock) - MFREE(dhd->osh, memblock, MAXSZ_CONFIG); - - if (image) - dhd_os_close_image1(dhd, image); + dhd_free_download_buffer(dhd, memblock, memblock_len); return bcmerror; } @@ -4630,7 +4841,7 @@ dhd_conf_compat_vht(dhd_pub_t *dhd) int dhd_conf_compat_func(dhd_pub_t *dhd) { - const module_name_map_t* row = NULL; + const module_name_map_t *row = NULL; row = dhd_conf_match_module(dhd); if (row && row->compat_func) { @@ -4641,29 +4852,45 @@ dhd_conf_compat_func(dhd_pub_t *dhd) } #endif +void +dhd_conf_preinit_ioctls_sta(dhd_pub_t *dhd, int ifidx) +{ + struct dhd_conf *conf = dhd->conf; + int pm; + + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE); +#ifdef NO_POWER_SAVE + pm = PM_OFF; +#else + if (conf->pm >= 0) + pm = conf->pm; + else + pm = PM_FAST; +#endif + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE); + dhd_conf_set_intiovar(dhd, ifidx, WLC_SET_VAR, "assoc_retry_max", 10, 0, FALSE); + dhd_conf_set_roam(dhd, ifidx); +} + void dhd_conf_postinit_ioctls(dhd_pub_t *dhd) { struct dhd_conf *conf = dhd->conf; - char wl_preinit[] = "assoc_retry_max=10"; + char wl_preinit[] = ""; #ifdef NO_POWER_SAVE char wl_no_power_save[] = "mpc=0, 86=0"; dhd_conf_set_wl_cmd(dhd, wl_no_power_save, FALSE); #endif + dhd_conf_get_ioctl_ver(dhd); dhd_conf_set_intiovar(dhd, 0, WLC_UP, "WLC_UP", 0, 0, FALSE); - dhd_conf_map_country_list(dhd, &conf->cspec); - dhd_conf_set_country(dhd, &conf->cspec); - dhd_conf_fix_country(dhd); - dhd_conf_get_country(dhd, &dhd->dhd_cspec); + dhd_conf_country(dhd, "country", conf->cspec.country_abbrev); dhd_conf_set_intiovar(dhd, 0, WLC_SET_BAND, "WLC_SET_BAND", conf->band, 0, FALSE); - dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE); - dhd_conf_set_intiovar(dhd, 0, WLC_SET_PM, "WLC_SET_PM", conf->pm, 0, FALSE); dhd_conf_set_intiovar(dhd, 0, WLC_SET_SRL, "WLC_SET_SRL", conf->srl, 0, FALSE); dhd_conf_set_intiovar(dhd, 0, WLC_SET_LRL, "WLC_SET_LRL", conf->lrl, 0, FALSE); dhd_conf_set_bw_cap(dhd); - dhd_conf_set_roam(dhd); + dhd_conf_set_roam(dhd, 0); #if defined(BCMPCIE) dhd_conf_set_intiovar(dhd, 0, WLC_SET_VAR, "bus:deepsleep_disable", @@ -4689,10 +4916,10 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd) dhd_conf_set_intiovar(dhd, 0, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG", conf->frameburst, 0, FALSE); + dhd_conf_preinit_ioctls_sta(dhd, 0); dhd_conf_set_wl_cmd(dhd, wl_preinit, TRUE); #if defined(BCMSDIO) - if (conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID || - conf->chip == BCM4375_CHIP_ID) { + if (conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID) { char ampdu_mpdu[] = "ampdu_mpdu=32"; dhd_conf_set_wl_cmd(dhd, ampdu_mpdu, TRUE); } else { @@ -4720,6 +4947,12 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd) char txack_alive[] = "txack_alive=0"; dhd_conf_set_wl_cmd(dhd, txack_alive, TRUE); } +#ifdef WLDWDS + { + char dwds[] = "dwds=1"; + dhd_conf_set_wl_cmd(dhd, dwds, TRUE); + } +#endif /* WLDWDS */ #if defined(WLEASYMESH) if (conf->fw_type == FW_TYPE_EZMESH) { if (conf->chip == BCM4359_CHIP_ID) { @@ -4759,13 +4992,11 @@ dhd_conf_postinit_ioctls(dhd_pub_t *dhd) } -int -dhd_conf_preinit(dhd_pub_t *dhd) +void +dhd_conf_free_preinit(dhd_pub_t *dhd) { struct dhd_conf *conf = dhd->conf; - CONFIG_TRACE("Enter\n"); - #ifdef SET_FWNV_BY_MAC dhd_conf_free_mac_list(&conf->fw_by_mac); dhd_conf_free_mac_list(&conf->nv_by_mac); @@ -4795,13 +5026,24 @@ dhd_conf_preinit(dhd_pub_t *dhd) kfree(conf->vndr_ie_assocreq); conf->vndr_ie_assocreq = NULL; } +} + +int +dhd_conf_preinit(dhd_pub_t *dhd) +{ + struct dhd_conf *conf = dhd->conf; + + CONFIG_TRACE("Enter\n"); + + dhd_conf_free_preinit(dhd); conf->band = -1; memset(&conf->bw_cap, -1, sizeof(conf->bw_cap)); if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) { strcpy(conf->cspec.country_abbrev, "ALL"); strcpy(conf->cspec.ccode, "ALL"); conf->cspec.rev = 0; - } else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID || + } + else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID || conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID || conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID || @@ -4809,12 +5051,14 @@ dhd_conf_preinit(dhd_pub_t *dhd) strcpy(conf->cspec.country_abbrev, "CN"); strcpy(conf->cspec.ccode, "CN"); conf->cspec.rev = 38; - } else { + } + else { strcpy(conf->cspec.country_abbrev, "CN"); strcpy(conf->cspec.ccode, "CN"); conf->cspec.rev = 0; } memset(&conf->channels, 0, sizeof(wl_channel_list_t)); + conf->ioctl_ver = WLC_IOCTL_VERSION; conf->roam_off = 1; conf->roam_off_suspend = 1; conf->roam_trigger[0] = -65; @@ -4879,6 +5123,7 @@ dhd_conf_preinit(dhd_pub_t *dhd) conf->flow_ring_queue_threshold = FLOW_RING_QUEUE_THRESHOLD; conf->d2h_intr_method = -1; conf->d2h_intr_control = -1; + conf->enq_hdr_pkt = 0; #endif conf->dpc_cpucore = -1; conf->rxf_cpucore = -1; @@ -5058,9 +5303,7 @@ dhd_conf_preinit(dhd_pub_t *dhd) init_waitqueue_head(&conf->event_complete); #if defined(BCMSDIO) && defined(CUSTOMER_HW_AMLOGIC) - if (conf->chip != BCM43752_CHIP_ID) { - dhd_slpauto = FALSE; - } + dhd_slpauto = dhd_conf_disable_slpauto(dhd); conf->txglom_mode = SDPCM_TXGLOM_CPY; conf->rekey_offload = TRUE; #endif @@ -5073,35 +5316,7 @@ dhd_conf_reset(dhd_pub_t *dhd) { struct dhd_conf *conf = dhd->conf; -#ifdef SET_FWNV_BY_MAC - dhd_conf_free_mac_list(&conf->fw_by_mac); - dhd_conf_free_mac_list(&conf->nv_by_mac); -#endif - dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip); - dhd_conf_free_country_list(conf); - dhd_conf_free_mchan_list(conf); -#ifdef PKT_FILTER_SUPPORT - if (conf->magic_pkt_filter_add) { - kfree(conf->magic_pkt_filter_add); - conf->magic_pkt_filter_add = NULL; - } -#endif - if (conf->wl_preinit) { - kfree(conf->wl_preinit); - conf->wl_preinit = NULL; - } - if (conf->wl_suspend) { - kfree(conf->wl_suspend); - conf->wl_suspend = NULL; - } - if (conf->wl_resume) { - kfree(conf->wl_resume); - conf->wl_resume = NULL; - } - if (conf->vndr_ie_assocreq) { - kfree(conf->vndr_ie_assocreq); - conf->vndr_ie_assocreq = NULL; - } + dhd_conf_free_preinit(dhd); memset(conf, 0, sizeof(dhd_conf_t)); return 0; } @@ -5141,35 +5356,7 @@ dhd_conf_detach(dhd_pub_t *dhd) CONFIG_TRACE("Enter\n"); if (dhd->conf) { -#ifdef SET_FWNV_BY_MAC - dhd_conf_free_mac_list(&conf->fw_by_mac); - dhd_conf_free_mac_list(&conf->nv_by_mac); -#endif - dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip); - dhd_conf_free_country_list(conf); - dhd_conf_free_mchan_list(conf); -#ifdef PKT_FILTER_SUPPORT - if (conf->magic_pkt_filter_add) { - kfree(conf->magic_pkt_filter_add); - conf->magic_pkt_filter_add = NULL; - } -#endif - if (conf->wl_preinit) { - kfree(conf->wl_preinit); - conf->wl_preinit = NULL; - } - if (conf->wl_suspend) { - kfree(conf->wl_suspend); - conf->wl_suspend = NULL; - } - if (conf->wl_resume) { - kfree(conf->wl_resume); - conf->wl_resume = NULL; - } - if (conf->vndr_ie_assocreq) { - kfree(conf->vndr_ie_assocreq); - conf->vndr_ie_assocreq = NULL; - } + dhd_conf_free_preinit(dhd); MFREE(dhd->osh, conf, sizeof(dhd_conf_t)); } dhd->conf = NULL; diff --git a/bcmdhd.101.10.361.x/dhd_config.h b/bcmdhd.101.10.361.x/dhd_config.h index 306c2b8..b7153b2 100755 --- a/bcmdhd.101.10.361.x/dhd_config.h +++ b/bcmdhd.101.10.361.x/dhd_config.h @@ -21,7 +21,11 @@ #define FW_TYPE_AG 1 #define FW_PATH_AUTO_SELECT 1 +#ifdef BCMDHD_MDRIVER #define CONFIG_PATH_AUTO_SELECT +#else +#define CONFIG_PATH_AUTO_SELECT +#endif extern char firmware_path[MOD_PARAM_PATHLEN]; #if defined(BCMSDIO) || defined(BCMPCIE) extern uint dhd_rxbound; @@ -63,9 +67,10 @@ typedef struct wl_chip_nv_path_list_ctrl { struct wl_chip_nv_path *m_chip_nv_path_head; } wl_chip_nv_path_list_ctrl_t; +#define MAX_CTRL_CHANSPECS 256 typedef struct wl_channel_list { uint32 count; - uint32 channel[WL_NUMCHANNELS]; + uint32 channel[MAX_CTRL_CHANSPECS]; } wl_channel_list_t; typedef struct wmes_param { @@ -181,9 +186,17 @@ enum conn_state { CONN_STATE_4WAY_M2 = 19, CONN_STATE_4WAY_M3 = 20, CONN_STATE_4WAY_M4 = 21, - CONN_STATE_CONNECTED = 22, - CONN_STATE_GROUPKEY_M1 = 23, - CONN_STATE_GROUPKEY_M2 = 24, + CONN_STATE_ADD_KEY = 22, + CONN_STATE_CONNECTED = 23, + CONN_STATE_GROUPKEY_M1 = 24, + CONN_STATE_GROUPKEY_M2 = 25, +}; + +enum enq_pkt_type { + ENQ_PKT_TYPE_EAPOL = (1 << (0)), + ENQ_PKT_TYPE_ARP = (1 << (1)), + ENQ_PKT_TYPE_DHCP = (1 << (2)), + ENQ_PKT_TYPE_ICMP = (1 << (3)), }; typedef struct dhd_conf { @@ -205,6 +218,7 @@ typedef struct dhd_conf { #endif wl_chip_nv_path_list_ctrl_t nv_by_chip; country_list_t *country_head; + int ioctl_ver; int band; int bw_cap[2]; wl_country_t cspec; @@ -283,6 +297,7 @@ typedef struct dhd_conf { int flow_ring_queue_threshold; int d2h_intr_method; int d2h_intr_control; + int enq_hdr_pkt; #endif int dpc_cpucore; int rxf_cpucore; @@ -386,17 +401,20 @@ void dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable); int dhd_conf_get_otp(dhd_pub_t *dhd, si_t *sih); bool dhd_conf_legacy_msi_chip(dhd_pub_t *dhd); #endif +#ifdef WL_CFG80211 +bool dhd_conf_legacy_chip_check(dhd_pub_t *dhd); +bool dhd_conf_new_chip_check(dhd_pub_t *dhd); +bool dhd_conf_extsae_chip(dhd_pub_t *dhd); +#endif void dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path); int dhd_conf_set_intiovar(dhd_pub_t *dhd, int ifidx, uint cmd, char *name, int val, int def, bool down); int dhd_conf_get_band(dhd_pub_t *dhd); -int dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec); +int dhd_conf_country(dhd_pub_t *dhd, char *cmd, char *buf); int dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec); -int dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec); #ifdef CCODE_LIST int dhd_ccode_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec); #endif -int dhd_conf_fix_country(dhd_pub_t *dhd); bool dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel); void dhd_conf_set_wme(dhd_pub_t *dhd, int ifidx, int mode); void dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int go, int source); @@ -408,6 +426,7 @@ int dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev); uint dhd_conf_get_chip(void *context); uint dhd_conf_get_chiprev(void *context); int dhd_conf_get_pm(dhd_pub_t *dhd); +int dhd_conf_reg2args(dhd_pub_t *dhd, char *cmd, bool set, uint32 index, uint32 *val); int dhd_conf_check_hostsleep(dhd_pub_t *dhd, int cmd, void *buf, int len, int *hostsleep_set, int *hostsleep_val, int *ret); void dhd_conf_get_hostsleep(dhd_pub_t *dhd, @@ -426,6 +445,9 @@ void dhd_conf_tput_monitor(dhd_pub_t *dhd); uint dhd_conf_get_insuspend(dhd_pub_t *dhd, uint mask); int dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend); void dhd_conf_postinit_ioctls(dhd_pub_t *dhd); +#ifdef WL_STATIC_IF +void dhd_conf_preinit_ioctls_sta(dhd_pub_t *dhd, int ifidx); +#endif /* WL_STATIC_IF */ int dhd_conf_preinit(dhd_pub_t *dhd); int dhd_conf_reset(dhd_pub_t *dhd); int dhd_conf_attach(dhd_pub_t *dhd); diff --git a/bcmdhd.101.10.361.x/dhd_flowring.c b/bcmdhd.101.10.361.x/dhd_flowring.c index 0841176..12218c2 100755 --- a/bcmdhd.101.10.361.x/dhd_flowring.c +++ b/bcmdhd.101.10.361.x/dhd_flowring.c @@ -210,6 +210,39 @@ done: return ret; } +int BCMFASTPATH +(dhd_flow_queue_enqueue_head)(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt) +{ + int ret = BCME_OK; + + ASSERT(queue != NULL); + + if (dhd_flow_queue_throttle(queue)) { + queue->failures++; + ret = (*queue->cb)(queue, pkt); + goto done; + } + + if (queue->head) { + FLOW_QUEUE_PKT_SETNEXT(pkt, queue->head); + queue->head = pkt; + + } else { + queue->head = pkt; + FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); + queue->tail = pkt; /* at tail */ + } + + queue->len++; + /* increment parent's cummulative length */ + DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_CLEN_PTR(queue)); + /* increment grandparent's cummulative length */ + DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_L2CLEN_PTR(queue)); + +done: + return ret; +} + /** Dequeue an 802.3 packet from a flow ring's queue, from head (FIFO) */ void * BCMFASTPATH(dhd_flow_queue_dequeue)(dhd_pub_t *dhdp, flow_queue_t *queue) diff --git a/bcmdhd.101.10.361.x/dhd_flowring.h b/bcmdhd.101.10.361.x/dhd_flowring.h index 873ca68..404ea4c 100755 --- a/bcmdhd.101.10.361.x/dhd_flowring.h +++ b/bcmdhd.101.10.361.x/dhd_flowring.h @@ -307,6 +307,7 @@ extern void dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max); extern void dhd_flow_queue_reinit(dhd_pub_t *dhdp, flow_queue_t *queue, int max); extern void dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb); extern int dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt); +extern int dhd_flow_queue_enqueue_head(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt); extern void * dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue); extern void dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt); diff --git a/bcmdhd.101.10.361.x/dhd_fwtrace.c b/bcmdhd.101.10.361.x/dhd_fwtrace.c index 4737b43..4ff2551 100755 --- a/bcmdhd.101.10.361.x/dhd_fwtrace.c +++ b/bcmdhd.101.10.361.x/dhd_fwtrace.c @@ -105,7 +105,7 @@ dhd_fwtrace_detach(dhd_pub_t *dhdp) /* close the file if valid */ if (!(IS_ERR_OR_NULL(dhdp->fwtrace_info->fw_trace_fp))) { - (void) filp_close(dhdp->fwtrace_info->fw_trace_fp, 0); + (void) dhd_filp_close(dhdp->fwtrace_info->fw_trace_fp, 0); } mutex_destroy(&dhdp->fwtrace_info->fwtrace_lock); @@ -229,7 +229,7 @@ fwtrace_write_to_file(uint8 *buf, uint16 buf_len, dhd_pub_t *dhdp) // Get the file size // if the size + buf_len > TRACE_FILE_SIZE, then write to a different file. // - error = vfs_stat(fwtrace_info->trace_file, &stat); + error = dhd_vfs_stat(fwtrace_info->trace_file, &stat); if (error) { DHD_ERROR(("vfs_stat has failed with error code = %d\n", error)); goto done; @@ -243,7 +243,7 @@ fwtrace_write_to_file(uint8 *buf, uint16 buf_len, dhd_pub_t *dhdp) pos = fwtrace_info->fw_trace_fp->f_pos; /* Write buf to file */ - ret_val_1 = vfs_write(fwtrace_info->fw_trace_fp, + ret_val_1 = dhd_vfs_write(fwtrace_info->fw_trace_fp, (char *) buf, (uint32) buf_len, &pos); if (ret_val_1 < 0) { DHD_ERROR(("write file error, err = %d\n", ret_val_1)); @@ -253,7 +253,7 @@ fwtrace_write_to_file(uint8 *buf, uint16 buf_len, dhd_pub_t *dhdp) fwtrace_info->fw_trace_fp->f_pos = pos; /* Sync file from filesystem to physical media */ - ret_val_1 = vfs_fsync(fwtrace_info->fw_trace_fp, 0); + ret_val_1 = dhd_vfs_fsync(fwtrace_info->fw_trace_fp, 0); if (ret_val_1 < 0) { DHD_ERROR(("sync file error, error = %d\n", ret_val_1)); ret_val = BCME_ERROR; @@ -330,7 +330,7 @@ fwtrace_open_file(uint32 fw_trace_enabled, dhd_pub_t *dhdp) if (fw_trace_enabled) { if (!(IS_ERR_OR_NULL(fwtrace_info->fw_trace_fp))) { - (void) filp_close(fwtrace_info->fw_trace_fp, 0); + (void) dhd_filp_close(fwtrace_info->fw_trace_fp, 0); } DHD_INFO((" *** Creating the trace file \n")); @@ -348,9 +348,9 @@ fwtrace_open_file(uint32 fw_trace_enabled, dhd_pub_t *dhdp) ts_str); fwtrace_info->fw_trace_fp = - filp_open(fwtrace_info->trace_file, file_mode, 0664); + dhd_filp_open(fwtrace_info->trace_file, file_mode, 0664); - if (IS_ERR(fwtrace_info->fw_trace_fp)) { + if (IS_ERR(fwtrace_info->fw_trace_fp) || (fwtrace_info->fw_trace_fp == NULL)) { DHD_ERROR(("Unable to create the fw trace file file: %s\n", fwtrace_info->trace_file)); ret_val = BCME_ERROR; @@ -368,7 +368,7 @@ fwtrace_close_file(dhd_pub_t *dhdp) int ret_val = BCME_OK; if (!(IS_ERR_OR_NULL(dhdp->fwtrace_info->fw_trace_fp))) { - (void) filp_close(dhdp->fwtrace_info->fw_trace_fp, 0); + (void) dhd_filp_close(dhdp->fwtrace_info->fw_trace_fp, 0); } dhdp->fwtrace_info->fw_trace_fp = NULL; diff --git a/bcmdhd.101.10.361.x/dhd_gpio.c b/bcmdhd.101.10.361.x/dhd_gpio.c index 60c04be..26d6824 100755 --- a/bcmdhd.101.10.361.x/dhd_gpio.c +++ b/bcmdhd.101.10.361.x/dhd_gpio.c @@ -15,7 +15,7 @@ extern int dhd_static_buf_init(void); extern void dhd_static_buf_exit(void); #endif /* DHD_STATIC_IN_DRIVER */ -#ifdef BCMDHD_MDRIVER +#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) extern void *bcmdhd_mem_prealloc(uint bus_type, int index, int section, unsigned long size); #else @@ -77,8 +77,8 @@ dhd_wlan_set_power(int on, wifi_adapter_info_t *adapter) } #ifdef CUSTOMER_HW_AMLOGIC #ifdef BCMSDIO - extern_wifi_set_enable(0); - mdelay(200); +// extern_wifi_set_enable(0); +// mdelay(200); extern_wifi_set_enable(1); mdelay(200); // sdio_reinit(); @@ -174,12 +174,14 @@ dhd_wlan_set_power(int on, wifi_adapter_info_t *adapter) return err; } -static int dhd_wlan_set_reset(int onoff) +static int +dhd_wlan_set_reset(int onoff) { return 0; } -static int dhd_wlan_set_carddetect(int present) +static int +dhd_wlan_set_carddetect(int present) { int err = 0; @@ -203,8 +205,8 @@ static int dhd_wlan_set_carddetect(int present) err = sdhci_force_presence_change(&sdmmc_channel, 0); #endif /* CUSTOMER_HW_PLATFORM */ #ifdef CUSTOMER_HW_AMLOGIC - extern_wifi_set_enable(0); - mdelay(200); +// extern_wifi_set_enable(0); +// mdelay(200); #endif #elif defined(BCMPCIE) printf("======== Card detection to remove PCIE card! ========\n"); @@ -219,7 +221,8 @@ static int dhd_wlan_set_carddetect(int present) return err; } -static int dhd_wlan_get_mac_addr(unsigned char *buf, int ifidx) +static int +dhd_wlan_get_mac_addr(unsigned char *buf, int ifidx) { int err = 0; @@ -338,7 +341,8 @@ struct wifi_platform_data dhd_wlan_control = { .get_country_code = dhd_wlan_get_country_code, }; -int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) +static int +dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) { #ifdef BCMDHD_DTS char wlan_node[32]; @@ -375,7 +379,7 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) #ifdef CUSTOMER_HW_AMLOGIC #if defined(BCMPCIE) - printf("======== Card detection to detect PCIE card! ========\n"); +// printf("======== Card detection to detect PCIE card! ========\n"); // pci_remove_reinit(0x14e4, 0x43ec, 1); #endif #endif @@ -383,8 +387,8 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) if (gpio_wl_reg_on >= 0) { err = gpio_request(gpio_wl_reg_on, "WL_REG_ON"); if (err < 0) { - printf("%s: gpio_request(%d) for WL_REG_ON failed\n", - __FUNCTION__, gpio_wl_reg_on); + printf("%s: gpio_request(%d) for WL_REG_ON failed %d\n", + __FUNCTION__, gpio_wl_reg_on, err); gpio_wl_reg_on = -1; } } @@ -394,22 +398,22 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) if (gpio_wl_host_wake >= 0) { err = gpio_request(gpio_wl_host_wake, "bcmdhd"); if (err < 0) { - printf("%s: gpio_request(%d) for WL_HOST_WAKE failed\n", - __FUNCTION__, gpio_wl_host_wake); + printf("%s: gpio_request(%d) for WL_HOST_WAKE failed %d\n", + __FUNCTION__, gpio_wl_host_wake, err); return -1; } adapter->gpio_wl_host_wake = gpio_wl_host_wake; err = gpio_direction_input(gpio_wl_host_wake); if (err < 0) { - printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed\n", - __FUNCTION__, gpio_wl_host_wake); + printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed %d\n", + __FUNCTION__, gpio_wl_host_wake, err); gpio_free(gpio_wl_host_wake); return -1; } host_oob_irq = gpio_to_irq(gpio_wl_host_wake); if (host_oob_irq < 0) { - printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed\n", - __FUNCTION__, gpio_wl_host_wake); + printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed %d\n", + __FUNCTION__, gpio_wl_host_wake, host_oob_irq); gpio_free(gpio_wl_host_wake); return -1; } @@ -450,7 +454,8 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter) return 0; } -static void dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter) +static void +dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter) { int gpio_wl_reg_on = adapter->gpio_wl_reg_on; #ifdef CUSTOMER_OOB @@ -471,25 +476,68 @@ static void dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter) #endif /* CUSTOMER_OOB */ } -int dhd_wlan_init_plat_data(wifi_adapter_info_t *adapter) +#if defined(BCMDHD_MDRIVER) +static void +dhd_wlan_init_adapter(wifi_adapter_info_t *adapter) +{ +#ifdef ADAPTER_IDX + if (ADAPTER_IDX == 0) { + adapter->bus_num = 1; + adapter->slot_num = 1; + } else if (ADAPTER_IDX == 1) { + adapter->bus_num = 2; + adapter->slot_num = 1; + } + adapter->index = ADAPTER_IDX; +#ifdef BCMSDIO + adapter->bus_type = SDIO_BUS; +#elif defined(BCMPCIE) + adapter->bus_type = PCI_BUS; +#elif defined(BCMDBUS) + adapter->bus_type = USB_BUS; +#endif + printf("bus_type=%d, bus_num=%d, slot_num=%d\n", + adapter->bus_type, adapter->bus_num, adapter->slot_num); +#endif /* ADAPTER_IDX */ + +#ifdef DHD_STATIC_IN_DRIVER + adapter->index = 0; +#elif !defined(ADAPTER_IDX) +#ifdef BCMSDIO + adapter->index = 0; +#elif defined(BCMPCIE) + adapter->index = 1; +#elif defined(BCMDBUS) + adapter->index = 2; +#endif +#endif /* DHD_STATIC_IN_DRIVER */ +} +#endif /* BCMDHD_MDRIVER */ + +int +dhd_wlan_init_plat_data(wifi_adapter_info_t *adapter) { int err = 0; - printf("======== %s ========\n", __FUNCTION__); - if (adapter->index == -1) { - adapter->index = 0; - } +#ifdef BCMDHD_MDRIVER + dhd_wlan_init_adapter(adapter); +#endif /* BCMDHD_MDRIVER */ + err = dhd_wlan_init_gpio(adapter); + if (err) + goto exit; #ifdef DHD_STATIC_IN_DRIVER - dhd_static_buf_init(); + err = dhd_static_buf_init(); #endif + +exit: return err; } -void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter) +void +dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter) { - printf("======== %s ========\n", __FUNCTION__); #ifdef DHD_STATIC_IN_DRIVER dhd_static_buf_exit(); #endif diff --git a/bcmdhd.101.10.361.x/dhd_linux.c b/bcmdhd.101.10.361.x/dhd_linux.c index 5323f4f..d257ddb 100755 --- a/bcmdhd.101.10.361.x/dhd_linux.c +++ b/bcmdhd.101.10.361.x/dhd_linux.c @@ -636,8 +636,8 @@ extern void dhd_netdev_free(struct net_device *ndev); static dhd_if_t * dhd_get_ifp_by_ndev(dhd_pub_t *dhdp, struct net_device *ndev); #if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG) -static void dhd_bridge_dev_set(dhd_info_t * dhd, int ifidx, struct net_device * dev); -#endif /* defiend(WLDWDS) && defined(FOURADDR_AUTO_BRG) */ +static void dhd_bridge_dev_set(dhd_info_t *dhd, int ifidx, struct net_device *sdev); +#endif /* WLDWDS && FOURADDR_AUTO_BRG */ #if (defined(DHD_WET) || defined(DHD_MCAST_REGEN) || defined(DHD_L2_FILTER)) /* update rx_pkt_chainable state of dhd interface */ @@ -840,20 +840,19 @@ module_param(tpoweron_scale, uint, 0644); #endif /* FORCE_TPOWERON */ #ifdef SHOW_LOGTRACE -#if defined(CUSTOMER_HW4_DEBUG) -#define WIFI_PATH "/etc/wifi/" -static char *logstrs_path = VENDOR_PATH WIFI_PATH"logstrs.bin"; -char *st_str_file_path = VENDOR_PATH WIFI_PATH"rtecdc.bin"; -static char *map_file_path = VENDOR_PATH WIFI_PATH"rtecdc.map"; -static char *rom_st_str_file_path = VENDOR_PATH WIFI_PATH"roml.bin"; -static char *rom_map_file_path = VENDOR_PATH WIFI_PATH"roml.map"; +#ifdef DHD_LINUX_STD_FW_API +static char *logstrs_path = "logstrs.bin"; +char *st_str_file_path = "rtecdc.bin"; +static char *map_file_path = "rtecdc.map"; +static char *rom_st_str_file_path = "roml.bin"; +static char *rom_map_file_path = "roml.map"; #else static char *logstrs_path = PLATFORM_PATH"logstrs.bin"; char *st_str_file_path = PLATFORM_PATH"rtecdc.bin"; static char *map_file_path = PLATFORM_PATH"rtecdc.map"; static char *rom_st_str_file_path = PLATFORM_PATH"roml.bin"; static char *rom_map_file_path = PLATFORM_PATH"roml.map"; -#endif /* CUSTOMER_HW4_DEBUG */ +#endif /* DHD_LINUX_STD_FW_API */ static char *ram_file_str = "rtecdc"; static char *rom_file_str = "roml"; @@ -1182,6 +1181,9 @@ static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, voi dhd_conf_set_suspend_resume(dhd, suspend); DHD_OS_WAKE_LOCK_RESTORE(dhd); } else { +#ifdef BCMDBUS + if (dhd->busstate == DHD_BUS_DATA) { +#endif if (suspend_mode == PM_NOTIFIER || suspend_mode == SUSPEND_MODE_2) dhd_conf_set_suspend_resume(dhd, suspend); #if defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) @@ -1189,6 +1191,11 @@ static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, voi #endif /* defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) */ if (suspend_mode == PM_NOTIFIER) dhd_suspend_resume_helper(dhdinfo, suspend, 0); +#ifdef BCMDBUS + } else { + printf("%s: skip resume since bus suspeneded\n", __FUNCTION__); + } +#endif } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ @@ -3075,7 +3082,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr, bool skip_stop) dhd_ifname(&dhd->pub, ifidx), addr, ret)); goto exit; } else { - memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); + dev_addr_set(dhd->iflist[ifidx]->net, addr); if (ifidx == 0) memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); WL_MSG(dhd_ifname(&dhd->pub, ifidx), "MACID %pM is overwritten\n", addr); @@ -3265,7 +3272,7 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) struct wl_if_event_info info; #if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG) struct net_device *ndev = NULL; -#endif +#endif /* WLDWDS && FOURADDR_AUTO_BRG */ #else struct net_device *ndev; #endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ @@ -3318,13 +3325,13 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) mac_addr = NULL; } -#ifdef WLEASYMESH +#if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG) if ((ndev = wl_cfg80211_post_ifcreate(dhd->pub.info->iflist[0]->net, &info, mac_addr, if_event->name, true)) == NULL) #else if (wl_cfg80211_post_ifcreate(dhd->pub.info->iflist[0]->net, &info, mac_addr, NULL, true) == NULL) -#endif +#endif /* WLDWDS && FOURADDR_AUTO_BRG */ { /* Do the post interface create ops */ DHD_ERROR(("Post ifcreate ops failed. Returning \n")); @@ -3366,6 +3373,10 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) } #endif /* PCIE_FULL_DONGLE */ +#if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG) + dhd_bridge_dev_set(dhd, ifidx, ndev); +#endif /* WLDWDS && FOURADDR_AUTO_BRG */ + done: #ifdef DHD_AWDL if (ret != BCME_OK && is_awdl_iface) { @@ -3374,11 +3385,6 @@ done: #endif /* DHD_AWDL */ MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); -#if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG) - if (dhd->pub.info->iflist[ifidx]) { - dhd_bridge_dev_set(dhd, ifidx, ndev); - } -#endif /* defiend(WLDWDS) && defined(FOURADDR_AUTO_BRG) */ DHD_OS_WAKE_UNLOCK(&dhd->pub); dhd_net_if_unlock_local(dhd); @@ -3411,17 +3417,15 @@ dhd_ifdel_event_handler(void *handle, void *event_info, u8 event) ifidx = if_event->event.ifidx; DHD_TRACE(("Removing interface with idx %d\n", ifidx)); -#if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG) - if (dhd->pub.info->iflist[ifidx]) { - dhd_bridge_dev_set(dhd, ifidx, NULL); - } -#endif /* defiend(WLDWDS) && defined(FOURADDR_AUTO_BRG) */ if (!dhd->pub.info->iflist[ifidx]) { /* No matching netdev found */ DHD_ERROR(("Netdev not found! Do nothing.\n")); goto done; } +#if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG) + dhd_bridge_dev_set(dhd, ifidx, NULL); +#endif /* WLDWDS && FOURADDR_AUTO_BRG */ #if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) if (if_event->event.ifidx > 0) { /* Do the post interface del ops */ @@ -3522,7 +3526,7 @@ int dhd_op_if_update(dhd_pub_t *dhdpub, int ifidx) (unsigned char)buf[3], (unsigned char)buf[4], (unsigned char)buf[5])); memcpy(dhdinfo->iflist[ifp->idx]->mac_addr, buf, ETHER_ADDR_LEN); if (dhdinfo->iflist[ifp->idx]->net) { - memcpy(dhdinfo->iflist[ifp->idx]->net->dev_addr, buf, ETHER_ADDR_LEN); + dev_addr_set(dhdinfo->iflist[ifp->idx]->net, buf); } } @@ -3665,7 +3669,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr) * available). Store the address and return. macaddr will be applied * from interface create context. */ - (void)memcpy_s(dev->dev_addr, ETH_ALEN, dhdif->mac_addr, ETH_ALEN); + dev_addr_set(dev, dhdif->mac_addr); #ifdef DHD_NOTIFY_MAC_CHANGED #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) dev_open(dev, NULL); @@ -4764,6 +4768,11 @@ dhd_bus_wakeup_work(dhd_pub_t *dhdp) static void __dhd_txflowcontrol(dhd_pub_t *dhdp, struct net_device *net, bool state) { + + if (net->reg_state != NETREG_REGISTERED) { + return; + } + if (state == ON) { if (!netif_queue_stopped(net)) { DHD_INFO(("%s: Stop Netif Queue\n", __FUNCTION__)); @@ -5670,7 +5679,7 @@ dhd_check_shinfo_nrfrags(dhd_pub_t *dhdp, void *pktbuf, shinfo = skb_shinfo(skb); if (shinfo->nr_frags) { -#ifdef CONFIG_64BIT +#ifdef BCMDMA64OSL DHD_ERROR(("!!Invalid nr_frags: %u pa.loaddr: 0x%llx pa.hiaddr: 0x%llx " "skb: 0x%llx skb_data: 0x%llx skb_head: 0x%llx skb_tail: 0x%llx " "skb_end: 0x%llx skb_len: %u shinfo: 0x%llx pktid: %u\n", @@ -9081,14 +9090,14 @@ dhd_check_filesystem_is_up(void) { struct file *fp; const char *clm = VENDOR_PATH CONFIG_BCMDHD_CLM_PATH; - fp = filp_open(clm, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(clm, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: filp_open(%s) failed(%d) schedule wl_accel_work\n", __FUNCTION__, clm, (int)IS_ERR(fp))); return FALSE; } - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); return TRUE; } @@ -9467,7 +9476,7 @@ dhd_open(struct net_device *net) #endif /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */ - memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); + dev_addr_set(net, dhd->pub.mac.octet); #ifdef TOE /* Get current TOE mode from dongle */ @@ -9592,15 +9601,16 @@ dhd_open(struct net_device *net) exit: mutex_unlock(&dhd->pub.ndev_op_sync); + if (ret) { + dhd_stop(net); + } else { #if defined(ENABLE_INSMOD_NO_FW_LOAD) && defined(NO_POWER_OFF_AFTER_OPEN) - dhd_download_fw_on_driverload = TRUE; - dhd_driver_init_done = TRUE; + dhd_download_fw_on_driverload = TRUE; + dhd_driver_init_done = TRUE; #elif defined(ENABLE_INSMOD_NO_FW_LOAD) && defined(ENABLE_INSMOD_NO_POWER_OFF) - dhd_download_fw_on_driverload = FALSE; - dhd_driver_init_done = TRUE; + dhd_download_fw_on_driverload = FALSE; + dhd_driver_init_done = TRUE; #endif - if (ret) { - dhd_stop(net); } DHD_OS_WAKE_UNLOCK(&dhd->pub); @@ -10463,15 +10473,22 @@ dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock) unregister_netdev(ifp->net); else unregister_netdevice(ifp->net); +#if defined(WLDWDS) && defined(WL_EXT_IAPSTA) + if (ifp->dwds) { + wl_ext_iapsta_dettach_dwds_netdev(ifp->net, ifidx, ifp->bssidx); + } else +#endif /* WLDWDS && WL_EXT_IAPSTA */ + { #ifdef WL_EXT_IAPSTA - wl_ext_iapsta_dettach_netdev(ifp->net, ifidx); + wl_ext_iapsta_dettach_netdev(ifp->net, ifidx); #endif /* WL_EXT_IAPSTA */ #ifdef WL_ESCAN - wl_escan_event_dettach(ifp->net, ifidx); + wl_escan_event_dettach(ifp->net, ifidx); #endif /* WL_ESCAN */ #ifdef WL_EVENT - wl_ext_event_dettach_netdev(ifp->net, ifidx); + wl_ext_event_dettach_netdev(ifp->net, ifidx); #endif /* WL_EVENT */ + } } ifp->net = NULL; DHD_GENERAL_LOCK(dhdpub, flags); @@ -10594,7 +10611,7 @@ dhd_os_write_file_posn(void *fp, unsigned long *posn, void *buf, if (!fp || !buf || buflen == 0) return -1; - if (vfs_write((struct file *)fp, buf, buflen, &wr_posn) < 0) + if (dhd_vfs_write((struct file *)fp, buf, buflen, &wr_posn) < 0) return -1; *posn = wr_posn; @@ -10610,7 +10627,7 @@ dhd_os_read_file(void *file, char *buf, uint32 size) if (!file || !buf) return -1; - return vfs_read(filep, buf, size, &filep->f_pos); + return dhd_vfs_read(filep, buf, size, &filep->f_pos); } int @@ -10626,46 +10643,269 @@ dhd_os_seek_file(void *file, int64 offset) return 0; } +#ifdef DHD_COREDUMP +#define PC_FOUND_BIT 0x01 +#define LR_FOUND_BIT 0x02 +#define ALL_ADDR_VAL (PC_FOUND_BIT | LR_FOUND_BIT) +#define READ_NUM_BYTES 1000 +#define DHD_FUNC_STR_LEN 80 static int -dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) +dhd_lookup_map(osl_t *osh, char *fname, uint32 pc, char *pc_fn, + uint32 lr, char *lr_fn) { +#ifdef DHD_LINUX_STD_FW_API + const struct firmware *fw = NULL; + uint32 size = 0, mem_offset = 0; +#else struct file *filep = NULL; #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - struct kstat stat; mm_segment_t fs; - int error = 0; #endif - char *raw_fmts = NULL; - int logstrs_size = 0; +#endif /* DHD_LINUX_STD_FW_API */ + char *raw_fmts = NULL, *raw_fmts_loc = NULL, *cptr = NULL; + uint32 read_size = READ_NUM_BYTES; + int err = BCME_ERROR; + uint32 addr = 0, addr1 = 0, addr2 = 0; + char type = '?', type1 = '?', type2 = '?'; + char func[DHD_FUNC_STR_LEN] = "\0"; + char func1[DHD_FUNC_STR_LEN] = "\0"; + char func2[DHD_FUNC_STR_LEN] = "\0"; + uint8 count = 0; + int num, len = 0, offset; - if (control_logtrace != LOGTRACE_PARSED_FMT) { - DHD_ERROR_NO_HW4(("%s : turned off logstr parsing\n", __FUNCTION__)); + DHD_TRACE(("%s: fname %s pc 0x%x lr 0x%x \n", + __FUNCTION__, fname, pc, lr)); + if (fname == NULL) { + DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__)); + return BCME_ERROR; + } + + /* Allocate 1 byte more than read_size to terminate it with NULL */ + raw_fmts = MALLOCZ(osh, read_size + 1); + if (raw_fmts == NULL) { + DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", + __FUNCTION__)); return BCME_ERROR; } +#ifdef DHD_LINUX_STD_FW_API + err = dhd_os_get_img_fwreq(&fw, fname); + if (err < 0) { + DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n", + err)); + goto fail; + } + size = fw->size; +#else #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) fs = get_fs(); set_fs(KERNEL_DS); #endif - filep = filp_open(logstrs_path, O_RDONLY, 0); - - if (IS_ERR(filep)) { - DHD_ERROR_NO_HW4(("%s: Failed to open the file %s \n", __FUNCTION__, logstrs_path)); + filep = dhd_filp_open(fname, O_RDONLY, 0); + if (IS_ERR(filep) || (filep == NULL)) { + DHD_ERROR(("%s: Failed to open %s \n", __FUNCTION__, fname)); goto fail; } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - error = vfs_stat(logstrs_path, &stat); - if (error) { - DHD_ERROR_NO_HW4(("%s: Failed to stat file %s \n", __FUNCTION__, logstrs_path)); - goto fail; +#endif /* DHD_LINUX_STD_FW_API */ + + if (pc_fn == NULL) { + count |= PC_FOUND_BIT; } - logstrs_size = (int) stat.size; + if (lr_fn == NULL) { + count |= LR_FOUND_BIT; + } + while (count != ALL_ADDR_VAL) + { +#ifdef DHD_LINUX_STD_FW_API + /* Bound check for size before doing memcpy() */ + if ((mem_offset + read_size) > size) { + read_size = size - mem_offset; + } + + err = memcpy_s(raw_fmts, read_size, + ((char *)(fw->data) + mem_offset), read_size); + if (err) { + DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n", + __FUNCTION__, err)); + goto fail; + } #else - logstrs_size = dhd_os_get_image_size(filep); + err = dhd_os_read_file(filep, raw_fmts, read_size); + if (err < 0) { + DHD_ERROR(("%s: map file read failed err:%d \n", + __FUNCTION__, err)); + goto fail; + } + +#endif /* DHD_LINUX_STD_FW_API */ + /* End raw_fmts with NULL as strstr expects NULL terminated + * strings + */ + raw_fmts[read_size] = '\0'; + raw_fmts_loc = raw_fmts; + offset = 0; + + while ((count != ALL_ADDR_VAL) && (offset < read_size)) + { + cptr = bcmstrtok(&raw_fmts_loc, "\n", 0); + if (cptr == NULL) { + DHD_TRACE(("%s: cptr is NULL, offset %d" + " raw_fmts_loc %s \n", + __FUNCTION__, offset, raw_fmts_loc)); + break; + } + DHD_TRACE(("%s: %s \n", __FUNCTION__, cptr)); + if ((type2 == 'A') || + (type2 == 'T') || + (type2 == 'W')) { + addr1 = addr2; + type1 = type2; + (void)memcpy_s(func1, DHD_FUNC_STR_LEN, + func2, DHD_FUNC_STR_LEN); + DHD_TRACE(("%s: %x %c %s \n", + __FUNCTION__, addr1, type1, func1)); + } + len = strlen(cptr); + num = sscanf(cptr, "%x %c %79s", &addr, &type, func); + DHD_TRACE(("%s: num %d addr %x type %c func %s \n", + __FUNCTION__, num, addr, type, func)); + if (num == 3) { + addr2 = addr; + type2 = type; + (void)memcpy_s(func2, DHD_FUNC_STR_LEN, + func, DHD_FUNC_STR_LEN); + } + + if (!(count & PC_FOUND_BIT) && + (pc >= addr1 && pc < addr2)) { + if ((cptr = strchr(func1, '$')) != NULL) { + (void)strncpy(func, cptr + 1, + DHD_FUNC_STR_LEN - 1); + } else { + (void)memcpy_s(func, DHD_FUNC_STR_LEN, + func1, DHD_FUNC_STR_LEN); + } + if ((cptr = strstr(func, "__bcmromfn")) + != NULL) { + *cptr = 0; + } + if (pc > addr1) { + sprintf(pc_fn, "%.68s+0x%x", + func, pc - addr1); + } else { + (void)memcpy_s(pc_fn, DHD_FUNC_STR_LEN, + func, DHD_FUNC_STR_LEN); + } + count |= PC_FOUND_BIT; + DHD_INFO(("%s: found addr1 %x pc %x" + " addr2 %x \n", + __FUNCTION__, addr1, pc, addr2)); + } + if (!(count & LR_FOUND_BIT) && + (lr >= addr1 && lr < addr2)) { + if ((cptr = strchr(func1, '$')) != NULL) { + (void)strncpy(func, cptr + 1, + DHD_FUNC_STR_LEN - 1); + } else { + (void)memcpy_s(func, DHD_FUNC_STR_LEN, + func1, DHD_FUNC_STR_LEN); + } + if ((cptr = strstr(func, "__bcmromfn")) + != NULL) { + *cptr = 0; + } + if (lr > addr1) { + sprintf(lr_fn, "%.68s+0x%x", + func, lr - addr1); + } else { + (void)memcpy_s(lr_fn, DHD_FUNC_STR_LEN, + func, DHD_FUNC_STR_LEN); + } + count |= LR_FOUND_BIT; + DHD_INFO(("%s: found addr1 %x lr %x" + " addr2 %x \n", + __FUNCTION__, addr1, lr, addr2)); + } + offset += (len + 1); + } +#ifdef DHD_LINUX_STD_FW_API + if ((mem_offset + read_size) >= size) { + break; + } + + memset(raw_fmts, 0, read_size); + mem_offset += (read_size -(len + 1)); +#else + if (err < (int)read_size) { + /* + * since we reset file pos back to earlier pos by + * bytes of one line we won't reach EOF. + * The reason for this is if string is spreaded across + * bytes, the read function should not miss it. + * So if ret value is less than read_size, reached EOF + * don't read further + */ + break; + } + memset(raw_fmts, 0, read_size); + /* + * go back to bytes of one line so that we won't miss + * the string and addr even if it comes as splited in next read. + */ + dhd_os_seek_file(filep, -(len + 1)); +#endif /* DHD_LINUX_STD_FW_API */ + DHD_TRACE(("%s: seek %d \n", __FUNCTION__, -(len + 1))); + } + +fail: +#ifdef DHD_LINUX_STD_FW_API + if (fw) { + dhd_os_close_img_fwreq(fw); + } +#else + if (!IS_ERR(filep)) + dhd_filp_close(filep, NULL); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) + set_fs(fs); #endif - if (logstrs_size <= 0) { - DHD_ERROR(("%s: get file size fails %d! \n", __FUNCTION__, logstrs_size)); + +#endif /* DHD_LINUX_STD_FW_API */ + if (!(count & PC_FOUND_BIT)) { + sprintf(pc_fn, "0x%08x", pc); + } + if (!(count & LR_FOUND_BIT)) { + sprintf(lr_fn, "0x%08x", lr); + } + return err; +} +#endif /* DHD_COREDUMP */ + +#ifdef DHD_LINUX_STD_FW_API +static int +dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) +{ + char *raw_fmts = NULL; + int logstrs_size = 0; + int error = 0; + const struct firmware *fw = NULL; + + if (control_logtrace != LOGTRACE_PARSED_FMT) { + DHD_ERROR_NO_HW4(("%s : turned off logstr parsing\n", __FUNCTION__)); + return BCME_ERROR; + } + + error = dhd_os_get_img_fwreq(&fw, logstrs_path); + if (error < 0) { + DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n", + error)); + goto fail; + } + + logstrs_size = (int)fw->size; + if (logstrs_size == 0) { + DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__)); goto fail; } @@ -10678,22 +10918,22 @@ dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) goto fail; } } - - if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) != logstrs_size) { - DHD_ERROR_NO_HW4(("%s: Failed to read file %s\n", __FUNCTION__, logstrs_path)); + error = memcpy_s(raw_fmts, logstrs_size, (char *)(fw->data), logstrs_size); + if (error) { + DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n", + __FUNCTION__, error)); goto fail; } - - if (dhd_parse_logstrs_file(osh, raw_fmts, logstrs_size, temp) - == BCME_OK) { - filp_close(filep, NULL); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(fs); -#endif + if (dhd_parse_logstrs_file(osh, raw_fmts, logstrs_size, temp) == BCME_OK) { + dhd_os_close_img_fwreq(fw); + DHD_ERROR(("%s: return ok\n", __FUNCTION__)); return BCME_OK; } fail: + if (fw) { + dhd_os_close_img_fwreq(fw); + } if (raw_fmts) { MFREE(osh, raw_fmts, logstrs_size); } @@ -10701,13 +10941,6 @@ fail: MFREE(osh, temp->fmts, temp->num_fmts * sizeof(char *)); } -fail1: - if (!IS_ERR(filep)) - filp_close(filep, NULL); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(fs); -#endif temp->fmts = NULL; temp->raw_fmts = NULL; @@ -10717,15 +10950,149 @@ fail1: static int dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, uint32 *rodata_end) +{ + int err = BCME_ERROR; + const struct firmware *fw = NULL; + + if (fname == NULL) { + DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__)); + return BCME_ERROR; + } + + err = dhd_os_get_img_fwreq(&fw, fname); + if (err < 0) { + DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n", + err)); + goto fail; + } + + if ((err = dhd_parse_map_file(osh, (struct firmware *)fw, ramstart, + rodata_start, rodata_end)) < 0) { + goto fail; + } + +fail: + if (fw) { + dhd_os_close_img_fwreq(fw); + } + + return err; +} + +static int +dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, char *map_file) +{ + char *raw_fmts = NULL; + uint32 logstrs_size = 0; + int error = 0; + uint32 ramstart = 0; + uint32 rodata_start = 0; + uint32 rodata_end = 0; + uint32 logfilebase = 0; + const struct firmware *fw = NULL; + + error = dhd_read_map(osh, map_file, &ramstart, &rodata_start, &rodata_end); + if (error != BCME_OK) { + DHD_ERROR(("readmap Error!! \n")); + /* don't do event log parsing in actual case */ + if (strstr(str_file, ram_file_str) != NULL) { + temp->raw_sstr = NULL; + } else if (strstr(str_file, rom_file_str) != NULL) { + temp->rom_raw_sstr = NULL; + } + return error; + } + DHD_ERROR(("ramstart: 0x%x, rodata_start: 0x%x, rodata_end:0x%x\n", + ramstart, rodata_start, rodata_end)); + + /* Full file size is huge. Just read required part */ + logstrs_size = rodata_end - rodata_start; + logfilebase = rodata_start - ramstart; + + if (logstrs_size == 0) { + DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__)); + goto fail1; + } + + if (strstr(str_file, ram_file_str) != NULL && temp->raw_sstr != NULL) { + raw_fmts = temp->raw_sstr; /* reuse already malloced raw_fmts */ + } else if (strstr(str_file, rom_file_str) != NULL && temp->rom_raw_sstr != NULL) { + raw_fmts = temp->rom_raw_sstr; /* reuse already malloced raw_fmts */ + } else { + raw_fmts = MALLOC(osh, logstrs_size); + + if (raw_fmts == NULL) { + DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", __FUNCTION__)); + goto fail; + } + } + + error = dhd_os_get_img_fwreq(&fw, str_file); + if (error < 0 || (fw == NULL) || (fw->size < logfilebase)) { + DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n", + error)); + goto fail; + } + + error = memcpy_s(raw_fmts, logstrs_size, (char *)((fw->data) + logfilebase), + logstrs_size); + if (error) { + DHD_ERROR(("%s: failed to copy raw_fmts, err=%d\n", + __FUNCTION__, error)); + goto fail; + } + + if (strstr(str_file, ram_file_str) != NULL) { + temp->raw_sstr = raw_fmts; + temp->raw_sstr_size = logstrs_size; + temp->rodata_start = rodata_start; + temp->rodata_end = rodata_end; + } else if (strstr(str_file, rom_file_str) != NULL) { + temp->rom_raw_sstr = raw_fmts; + temp->rom_raw_sstr_size = logstrs_size; + temp->rom_rodata_start = rodata_start; + temp->rom_rodata_end = rodata_end; + } + + if (fw) { + dhd_os_close_img_fwreq(fw); + } + + return BCME_OK; + +fail: + if (raw_fmts) { + MFREE(osh, raw_fmts, logstrs_size); + } + +fail1: + if (fw) { + dhd_os_close_img_fwreq(fw); + } + + if (strstr(str_file, ram_file_str) != NULL) { + temp->raw_sstr = NULL; + } else if (strstr(str_file, rom_file_str) != NULL) { + temp->rom_raw_sstr = NULL; + } + + return error; +} /* dhd_init_static_strs_array */ +#else +static int +dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) { struct file *filep = NULL; + struct kstat stat; #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) mm_segment_t fs; #endif - int err = BCME_ERROR; + char *raw_fmts = NULL; + int logstrs_size = 0; + int error = 0; - if (fname == NULL) { - DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__)); + if (control_logtrace != LOGTRACE_PARSED_FMT) { + DHD_ERROR_NO_HW4(("%s : turned off logstr parsing\n", __FUNCTION__)); return BCME_ERROR; } @@ -10734,63 +11101,82 @@ dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, set_fs(KERNEL_DS); #endif - filep = filp_open(fname, O_RDONLY, 0); - if (IS_ERR(filep)) { - DHD_ERROR_NO_HW4(("%s: Failed to open %s \n", __FUNCTION__, fname)); + filep = dhd_filp_open(logstrs_path, O_RDONLY, 0); + + if (IS_ERR(filep) || (filep == NULL)) { + DHD_ERROR_NO_HW4(("%s: Failed to open the file %s \n", + __FUNCTION__, logstrs_path)); goto fail; } + error = dhd_vfs_stat(logstrs_path, &stat); + if (error) { + DHD_ERROR_NO_HW4(("%s: Failed to stat file %s \n", __FUNCTION__, logstrs_path)); + goto fail; + } + logstrs_size = (int) stat.size; - if ((err = dhd_parse_map_file(osh, filep, ramstart, - rodata_start, rodata_end)) < 0) + if (logstrs_size == 0) { + DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__)); + goto fail1; + } + + if (temp->raw_fmts != NULL) { + raw_fmts = temp->raw_fmts; /* reuse already malloced raw_fmts */ + } else { + raw_fmts = MALLOC(osh, logstrs_size); + if (raw_fmts == NULL) { + DHD_ERROR(("%s: Failed to allocate memory \n", __FUNCTION__)); + goto fail; + } + } + + if (dhd_vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) != logstrs_size) { + DHD_ERROR_NO_HW4(("%s: Failed to read file %s\n", __FUNCTION__, logstrs_path)); goto fail; + } -fail: + if (dhd_parse_logstrs_file(osh, raw_fmts, logstrs_size, temp) + == BCME_OK) { + dhd_filp_close(filep, NULL); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) + set_fs(fs); +#endif + return BCME_OK; + } + + fail: + if (raw_fmts) { + MFREE(osh, raw_fmts, logstrs_size); + } + if (temp->fmts != NULL) { + MFREE(osh, temp->fmts, temp->num_fmts * sizeof(char *)); + } + + fail1: if (!IS_ERR(filep)) - filp_close(filep, NULL); + dhd_filp_close(filep, NULL); #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) set_fs(fs); #endif + temp->fmts = NULL; + temp->raw_fmts = NULL; - return err; + return BCME_ERROR; } -#ifdef DHD_COREDUMP -#define PC_FOUND_BIT 0x01 -#define LR_FOUND_BIT 0x02 -#define ALL_ADDR_VAL (PC_FOUND_BIT | LR_FOUND_BIT) -#define READ_NUM_BYTES 1000 -#define DHD_FUNC_STR_LEN 80 + static int -dhd_lookup_map(osl_t *osh, char *fname, uint32 pc, char *pc_fn, - uint32 lr, char *lr_fn) +dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, + uint32 *rodata_end) { struct file *filep = NULL; #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) mm_segment_t fs; #endif - char *raw_fmts = NULL, *raw_fmts_loc = NULL, *cptr = NULL; - uint32 read_size = READ_NUM_BYTES; int err = BCME_ERROR; - uint32 addr = 0, addr1 = 0, addr2 = 0; - char type = '?', type1 = '?', type2 = '?'; - char func[DHD_FUNC_STR_LEN] = "\0"; - char func1[DHD_FUNC_STR_LEN] = "\0"; - char func2[DHD_FUNC_STR_LEN] = "\0"; - uint8 count = 0; - int num, len = 0, offset; - - DHD_TRACE(("%s: fname %s pc 0x%x lr 0x%x \n", - __FUNCTION__, fname, pc, lr)); - if (fname == NULL) { - DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__)); - return BCME_ERROR; - } - /* Allocate 1 byte more than read_size to terminate it with NULL */ - raw_fmts = MALLOCZ(osh, read_size + 1); - if (raw_fmts == NULL) { - DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", - __FUNCTION__)); + if (fname == NULL) { + DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__)); return BCME_ERROR; } @@ -10799,155 +11185,26 @@ dhd_lookup_map(osl_t *osh, char *fname, uint32 pc, char *pc_fn, set_fs(KERNEL_DS); #endif - filep = filp_open(fname, O_RDONLY, 0); - if (IS_ERR(filep)) { - DHD_ERROR(("%s: Failed to open %s \n", __FUNCTION__, fname)); + filep = dhd_filp_open(fname, O_RDONLY, 0); + if (IS_ERR(filep) || (filep == NULL)) { + DHD_ERROR_NO_HW4(("%s: Failed to open %s \n", __FUNCTION__, fname)); goto fail; } - if (pc_fn == NULL) { - count |= PC_FOUND_BIT; - } - if (lr_fn == NULL) { - count |= LR_FOUND_BIT; - } - while (count != ALL_ADDR_VAL) - { - err = dhd_os_read_file(filep, raw_fmts, read_size); - if (err < 0) { - DHD_ERROR(("%s: map file read failed err:%d \n", - __FUNCTION__, err)); - goto fail; - } - - /* End raw_fmts with NULL as strstr expects NULL terminated - * strings - */ - raw_fmts[read_size] = '\0'; - raw_fmts_loc = raw_fmts; - offset = 0; - - while ((count != ALL_ADDR_VAL) && (offset < read_size)) - { - cptr = bcmstrtok(&raw_fmts_loc, "\n", 0); - if (cptr == NULL) { - DHD_TRACE(("%s: cptr is NULL, offset %d" - " raw_fmts_loc %s \n", - __FUNCTION__, offset, raw_fmts_loc)); - break; - } - DHD_TRACE(("%s: %s \n", __FUNCTION__, cptr)); - if ((type2 == 'A') || - (type2 == 'T') || - (type2 == 'W')) { - addr1 = addr2; - type1 = type2; - (void)memcpy_s(func1, DHD_FUNC_STR_LEN, - func2, DHD_FUNC_STR_LEN); - DHD_TRACE(("%s: %x %c %s \n", - __FUNCTION__, addr1, type1, func1)); - } - len = strlen(cptr); - num = sscanf(cptr, "%x %c %79s", &addr, &type, func); - DHD_TRACE(("%s: num %d addr %x type %c func %s \n", - __FUNCTION__, num, addr, type, func)); - if (num == 3) { - addr2 = addr; - type2 = type; - (void)memcpy_s(func2, DHD_FUNC_STR_LEN, - func, DHD_FUNC_STR_LEN); - } - - if (!(count & PC_FOUND_BIT) && - (pc >= addr1 && pc < addr2)) { - if ((cptr = strchr(func1, '$')) != NULL) { - (void)strncpy(func, cptr + 1, - DHD_FUNC_STR_LEN - 1); - } else { - (void)memcpy_s(func, DHD_FUNC_STR_LEN, - func1, DHD_FUNC_STR_LEN); - } - if ((cptr = strstr(func, "__bcmromfn")) - != NULL) { - *cptr = 0; - } - if (pc > addr1) { - sprintf(pc_fn, "%.68s+0x%x", - func, pc - addr1); - } else { - (void)memcpy_s(pc_fn, DHD_FUNC_STR_LEN, - func, DHD_FUNC_STR_LEN); - } - count |= PC_FOUND_BIT; - DHD_INFO(("%s: found addr1 %x pc %x" - " addr2 %x \n", - __FUNCTION__, addr1, pc, addr2)); - } - if (!(count & LR_FOUND_BIT) && - (lr >= addr1 && lr < addr2)) { - if ((cptr = strchr(func1, '$')) != NULL) { - (void)strncpy(func, cptr + 1, - DHD_FUNC_STR_LEN - 1); - } else { - (void)memcpy_s(func, DHD_FUNC_STR_LEN, - func1, DHD_FUNC_STR_LEN); - } - if ((cptr = strstr(func, "__bcmromfn")) - != NULL) { - *cptr = 0; - } - if (lr > addr1) { - sprintf(lr_fn, "%.68s+0x%x", - func, lr - addr1); - } else { - (void)memcpy_s(lr_fn, DHD_FUNC_STR_LEN, - func, DHD_FUNC_STR_LEN); - } - count |= LR_FOUND_BIT; - DHD_INFO(("%s: found addr1 %x lr %x" - " addr2 %x \n", - __FUNCTION__, addr1, lr, addr2)); - } - offset += (len + 1); - } - - if (err < (int)read_size) { - /* - * since we reset file pos back to earlier pos by - * bytes of one line we won't reach EOF. - * The reason for this is if string is spreaded across - * bytes, the read function should not miss it. - * So if ret value is less than read_size, reached EOF - * don't read further - */ - break; - } - memset(raw_fmts, 0, read_size); - /* - * go back to bytes of one line so that we won't miss - * the string and addr even if it comes as splited in next read. - */ - dhd_os_seek_file(filep, -(len + 1)); - DHD_TRACE(("%s: seek %d \n", __FUNCTION__, -(len + 1))); - } + if ((err = dhd_parse_map_file(osh, filep, ramstart, + rodata_start, rodata_end)) < 0) + goto fail; fail: if (!IS_ERR(filep)) - filp_close(filep, NULL); + dhd_filp_close(filep, NULL); #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) set_fs(fs); #endif - if (!(count & PC_FOUND_BIT)) { - sprintf(pc_fn, "0x%08x", pc); - } - if (!(count & LR_FOUND_BIT)) { - sprintf(lr_fn, "0x%08x", lr); - } return err; } -#endif /* DHD_COREDUMP */ static int dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, char *map_file) @@ -10983,8 +11240,8 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch set_fs(KERNEL_DS); #endif - filep = filp_open(str_file, O_RDONLY, 0); - if (IS_ERR(filep)) { + filep = dhd_filp_open(str_file, O_RDONLY, 0); + if (IS_ERR(filep) || (filep == NULL)) { DHD_ERROR(("%s: Failed to open the file %s \n", __FUNCTION__, str_file)); goto fail; } @@ -11021,7 +11278,7 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch } } - error = vfs_read(filep, raw_fmts, logstrs_size, (&filep->f_pos)); + error = dhd_vfs_read(filep, raw_fmts, logstrs_size, (&filep->f_pos)); if (error != logstrs_size) { DHD_ERROR(("%s: %s read failed %d \n", __FUNCTION__, str_file, error)); goto fail; @@ -11039,7 +11296,7 @@ dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ch temp->rom_rodata_end = rodata_end; } - filp_close(filep, NULL); + dhd_filp_close(filep, NULL); #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) set_fs(fs); #endif @@ -11053,7 +11310,7 @@ fail: fail1: if (!IS_ERR(filep)) - filp_close(filep, NULL); + dhd_filp_close(filep, NULL); #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) set_fs(fs); @@ -11067,7 +11324,7 @@ fail1: return error; } /* dhd_init_static_strs_array */ - +#endif /* DHD_LINUX_STD_FW_API */ #endif /* SHOW_LOGTRACE */ #ifdef BT_OVER_PCIE @@ -11463,6 +11720,12 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen goto fail; } #endif /* WL_EVENT */ +#ifdef WL_TIMER + if (wl_timer_attach(net) != 0) { + DHD_ERROR(("wl_ext_timer_attach failed\n")); + goto fail; + } +#endif /* WL_TIMER */ #ifdef WL_ESCAN /* Attach and link in the escan */ if (wl_escan_attach(net) != 0) { @@ -11517,7 +11780,11 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen dhd_os_start_logging(&dhd->pub, BT_LOG_RING_NAME, 3, 0, 0, 0); #endif /* !OEM_ANDROID && BTLOG */ #ifdef DBG_PKT_MON - dhd->pub.dbg->pkt_mon_lock = osl_spin_lock_init(dhd->pub.osh); + dhd->pub.dbg->pkt_mon_lock = osl_mutex_lock_init(dhd->pub.osh); + if (!dhd->pub.dbg->pkt_mon_lock) { + DHD_ERROR(("%s: pkt_mon_lock init failed !\n", __FUNCTION__)); + goto fail; + } #ifdef DBG_PKT_MON_INIT_DEFAULT dhd_os_dbg_attach_pkt_monitor(&dhd->pub); #endif /* DBG_PKT_MON_INIT_DEFAULT */ @@ -11625,13 +11892,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen } #endif /* DHD_PCIE_RUNTIMEPM */ -#ifdef SHOW_LOGTRACE - skb_queue_head_init(&dhd->evt_trace_queue); - - /* Create ring proc entries */ - dhd_dbg_ring_proc_create(&dhd->pub); -#endif /* SHOW_LOGTRACE */ - #ifdef BTLOG skb_queue_head_init(&dhd->bt_log_queue); #endif /* BTLOG */ @@ -11664,6 +11924,13 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen } #endif /* !BCMDBUS */ +#ifdef SHOW_LOGTRACE + skb_queue_head_init(&dhd->evt_trace_queue); + + /* Create ring proc entries */ + dhd_dbg_ring_proc_create(&dhd->pub); +#endif /* SHOW_LOGTRACE */ + dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; #if defined(CONFIG_PM_SLEEP) @@ -12019,12 +12286,17 @@ bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) /* set default firmware and nvram path for built-in type driver */ // if (!dhd_download_fw_on_driverload) { +#ifdef DHD_LINUX_STD_FW_API + fw = DHD_FW_NAME; + nv = DHD_NVRAM_NAME; +#else #ifdef CONFIG_BCMDHD_FW_PATH fw = VENDOR_PATH CONFIG_BCMDHD_FW_PATH; #endif /* CONFIG_BCMDHD_FW_PATH */ #ifdef CONFIG_BCMDHD_NVRAM_PATH nv = VENDOR_PATH CONFIG_BCMDHD_NVRAM_PATH; #endif /* CONFIG_BCMDHD_NVRAM_PATH */ +#endif /* DHD_LINUX_STD_FW_API */ // } /* check if we need to initialize the path */ @@ -13098,7 +13370,7 @@ static int dhd_preinit_config(dhd_pub_t *dhd, int ifidx) old_fs = get_fs(); set_fs(get_ds()); - if ((ret = vfs_stat(config_path, &stat))) { + if ((ret = dhd_vfs_stat(config_path, &stat))) { set_fs(old_fs); printk(KERN_ERR "%s: Failed to get information (%d)\n", config_path, ret); @@ -13561,12 +13833,8 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) else { bcmstrtok(&ptr, "\n", 0); /* Print fw version info */ - DHD_ERROR(("Firmware version = %s\n", buf)); strncpy(fw_version, buf, FW_VER_STR_LEN); fw_version[FW_VER_STR_LEN-1] = '\0'; -#if defined(BCMSDIO) || defined(BCMPCIE) - dhd_set_version_info(dhd, buf); -#endif /* BCMSDIO || BCMPCIE */ } /* query for 'wlc_ver' to get version info from firmware */ @@ -13581,14 +13849,12 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) dhd->wlc_ver_major = wlc_ver.wlc_ver_major; dhd->wlc_ver_minor = wlc_ver.wlc_ver_minor; } -#ifdef BOARD_HIKEY /* Set op_mode as MFG_MODE if WLTEST is present in "wl ver" */ if (strstr(fw_version, "WLTEST") != NULL) { DHD_ERROR(("%s: wl ver has WLTEST, setting op_mode as DHD_FLAG_MFG_MODE\n", __FUNCTION__)); op_mode = DHD_FLAG_MFG_MODE; } -#endif /* BOARD_HIKEY */ /* get a capabilities from firmware */ ret = dhd_get_fw_capabilities(dhd); @@ -13745,6 +14011,7 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n", dhd->op_mode, MAC2STRDBG(dhd->mac.octet))); + dhd_set_version_info(dhd, fw_version); #if defined(DHD_BLOB_EXISTENCE_CHECK) if (!dhd->is_blob) #endif /* DHD_BLOB_EXISTENCE_CHECK */ @@ -13937,6 +14204,10 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_LLR_MAP); #endif /* defined(BCMPCIE) && defined(EAPOL_PKT_PRIO) */ +#if defined(BCMSDIO) && defined(DHD_LOSSLESS_ROAMING) + dhd_update_sdio_data_prio_map(dhd); +#endif /* BCMSDIO && DHD_LOSSLESS_ROAMING */ + #ifdef ARP_OFFLOAD_SUPPORT DHD_ERROR(("arp_enable:%d arp_ol:%d\n", dhd->arpoe_enable, dhd->arpol_configured)); @@ -13948,60 +14219,64 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) */ #ifdef PKT_FILTER_SUPPORT /* Setup default defintions for pktfilter , enable in suspend */ - dhd->pktfilter_count = 6; - dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; - if (!FW_SUPPORTED(dhd, pf6)) { - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; - } else { - /* Immediately pkt filter TYPE 6 Discard IPv4/IPv6 Multicast Packet */ - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = DISCARD_IPV4_MCAST; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = DISCARD_IPV6_MCAST; - } - /* apply APP pktfilter */ - dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; + if (dhd_master_mode) { + dhd->pktfilter_count = 6; + dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; + if (!FW_SUPPORTED(dhd, pf6)) { + dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; + dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; + } else { + /* Immediately pkt filter TYPE 6 Discard IPv4/IPv6 Multicast Packet */ + dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = DISCARD_IPV4_MCAST; + dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = DISCARD_IPV6_MCAST; + } + /* apply APP pktfilter */ + dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; #ifdef BLOCK_IPV6_PACKET - /* Setup filter to allow only IPv4 unicast frames */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 " - HEX_PREF_STR UNI_FILTER_STR ZERO_ADDR_STR ETHER_TYPE_STR IPV6_FILTER_STR - " " - HEX_PREF_STR ZERO_ADDR_STR ZERO_ADDR_STR ETHER_TYPE_STR ZERO_TYPE_STR; + /* Setup filter to allow only IPv4 unicast frames */ + dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 " + HEX_PREF_STR UNI_FILTER_STR ZERO_ADDR_STR ETHER_TYPE_STR IPV6_FILTER_STR + " " + HEX_PREF_STR ZERO_ADDR_STR ZERO_ADDR_STR ETHER_TYPE_STR ZERO_TYPE_STR; #else - /* Setup filter to allow only unicast */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; + /* Setup filter to allow only unicast */ + dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; #endif /* BLOCK_IPV6_PACKET */ #ifdef PASS_IPV4_SUSPEND - /* XXX customer want to get IPv4 multicast packets */ - dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFF 0x01005E"; + /* XXX customer want to get IPv4 multicast packets */ + dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFF 0x01005E"; #else - /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ - dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL; + /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ + dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL; #endif /* PASS_IPV4_SUSPEND */ - if (FW_SUPPORTED(dhd, pf6)) { - /* Immediately pkt filter TYPE 6 Dicard Broadcast IP packet */ - dhd->pktfilter[DHD_IP4BCAST_DROP_FILTER_NUM] = DISCARD_IPV4_BCAST; - /* Immediately pkt filter TYPE 6 Dicard Cisco STP packet */ - dhd->pktfilter[DHD_LLC_STP_DROP_FILTER_NUM] = DISCARD_LLC_STP; - /* Immediately pkt filter TYPE 6 Dicard Cisco XID protocol */ - dhd->pktfilter[DHD_LLC_XID_DROP_FILTER_NUM] = DISCARD_LLC_XID; - /* Immediately pkt filter TYPE 6 Dicard NETBIOS packet(port 137) */ - dhd->pktfilter[DHD_UDPNETBIOS_DROP_FILTER_NUM] = DISCARD_UDPNETBIOS; - dhd->pktfilter_count = 11; - } + if (FW_SUPPORTED(dhd, pf6)) { + /* Immediately pkt filter TYPE 6 Dicard Broadcast IP packet */ + dhd->pktfilter[DHD_IP4BCAST_DROP_FILTER_NUM] = DISCARD_IPV4_BCAST; + /* Immediately pkt filter TYPE 6 Dicard Cisco STP packet */ + dhd->pktfilter[DHD_LLC_STP_DROP_FILTER_NUM] = DISCARD_LLC_STP; + /* Immediately pkt filter TYPE 6 Dicard Cisco XID protocol */ + dhd->pktfilter[DHD_LLC_XID_DROP_FILTER_NUM] = DISCARD_LLC_XID; + /* Immediately pkt filter TYPE 6 Dicard NETBIOS packet(port 137) */ + dhd->pktfilter[DHD_UDPNETBIOS_DROP_FILTER_NUM] = DISCARD_UDPNETBIOS; + dhd->pktfilter_count = 11; + } #ifdef GAN_LITE_NAT_KEEPALIVE_FILTER - dhd->pktfilter_count = 4; - /* Setup filter to block broadcast and NAT Keepalive packets */ - /* discard all broadcast packets */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0xffffff 0xffffff"; - /* discard NAT Keepalive packets */ - dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "102 0 0 36 0xffffffff 0x11940009"; - /* discard NAT Keepalive packets */ - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "104 0 0 38 0xffffffff 0x11940009"; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; + dhd->pktfilter_count = 4; + /* Setup filter to block broadcast and NAT Keepalive packets */ + /* discard all broadcast packets */ + dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0xffffff 0xffffff"; + /* discard NAT Keepalive packets */ + dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "102 0 0 36 0xffffffff 0x11940009"; + /* discard NAT Keepalive packets */ + dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "104 0 0 38 0xffffffff 0x11940009"; + dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; #endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ + } else + dhd_conf_discard_pkt_filter(dhd); + dhd_conf_add_pkt_filter(dhd); #if defined(SOFTAP) if (ap_fw_loaded) { @@ -14243,6 +14518,7 @@ dhd_optimised_preinit_ioctls(dhd_pub_t * dhd) dhd_set_bandlock(dhd); done: + dhd_conf_postinit_ioctls(dhd); if (iov_buf) { MFREE(dhd->osh, iov_buf, WLC_IOCTL_SMLEN); } @@ -14511,14 +14787,12 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) fw_version[FW_VER_STR_LEN-1] = '\0'; } -#ifdef BOARD_HIKEY /* Set op_mode as MFG_MODE if WLTEST is present in "wl ver" */ if (strstr(fw_version, "WLTEST") != NULL) { DHD_ERROR(("%s: wl ver has WLTEST, setting op_mode as DHD_FLAG_MFG_MODE\n", __FUNCTION__)); op_mode = DHD_FLAG_MFG_MODE; } -#endif /* BOARD_HIKEY */ if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || (op_mode == DHD_FLAG_MFG_MODE)) { @@ -15074,7 +15348,7 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) } #else /* OEM_ANDROID */ - if ((ret = dhd_apply_default_clm(dhd, clm_path)) < 0) { + if ((ret = dhd_apply_default_clm(dhd, dhd->clm_path)) < 0) { DHD_ERROR(("%s: CLM set failed. Abort initialization.\n", __FUNCTION__)); goto done; } @@ -15466,6 +15740,10 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_LLR_MAP); #endif /* defined(BCMPCIE) && defined(EAPOL_PKT_PRIO) */ +#if defined(BCMSDIO) && defined(DHD_LOSSLESS_ROAMING) + dhd_update_sdio_data_prio_map(dhd); +#endif /* BCMSDIO && DHD_LOSSLESS_ROAMING */ + #ifdef RSSI_MONITOR_SUPPORT setbit(mask, WLC_E_RSSI_LQM); #endif /* RSSI_MONITOR_SUPPORT */ @@ -15502,9 +15780,10 @@ dhd_legacy_preinit_ioctls(dhd_pub_t *dhd) setbit(mask, WLC_E_ADDTS_IND); setbit(mask, WLC_E_DELTS_IND); #endif /* WL_BCNRECV */ -#ifdef CUSTOMER_HW6 setbit(mask, WLC_E_COUNTRY_CODE_CHANGED); -#endif /* CUSTOMER_HW6 */ +#if defined(WL_TWT) || defined(WL_TWT_HAL_IF) + setbit(mask, WLC_E_TWT); +#endif /* WL_TWT || WL_TWT_HAL_IF */ /* Write updated Event mask */ eventmask_msg->ver = EVENTMSGS_VER; @@ -16694,7 +16973,7 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) * XXX Linux 2.6.25 does not like a blank MAC address, so use a * dummy address until the interface is brought up. */ - memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); + dev_addr_set(net, temp_addr); if (ifidx == 0) printf("%s\n", dhd_version); @@ -16734,16 +17013,23 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) } #endif /* BCM_ROUTER_DHD && HNDCTF */ +#if defined(WLDWDS) && defined(WL_EXT_IAPSTA) + if (ifp->dwds) { + wl_ext_iapsta_attach_dwds_netdev(net, ifidx, ifp->bssidx); + } else +#endif /* WLDWDS && WL_EXT_IAPSTA */ + { #ifdef WL_EVENT - wl_ext_event_attach_netdev(net, ifidx, ifp->bssidx); + wl_ext_event_attach_netdev(net, ifidx, ifp->bssidx); #endif /* WL_EVENT */ #ifdef WL_ESCAN - wl_escan_event_attach(net, ifidx); + wl_escan_event_attach(net, ifidx); #endif /* WL_ESCAN */ #ifdef WL_EXT_IAPSTA - wl_ext_iapsta_attach_netdev(net, ifidx, ifp->bssidx); - wl_ext_iapsta_attach_name(net, ifidx); + wl_ext_iapsta_attach_netdev(net, ifidx, ifp->bssidx); + wl_ext_iapsta_attach_name(net, ifidx); #endif /* WL_EXT_IAPSTA */ + } #if defined(CONFIG_TIZEN) net_stat_tizen_register(net); @@ -17002,6 +17288,9 @@ void dhd_detach(dhd_pub_t *dhdp) #ifdef WL_ESCAN wl_escan_detach(dev); #endif /* WL_ESCAN */ +#ifdef WL_TIMER + wl_timer_dettach(dhdp); +#endif /* WL_TIMER */ #ifdef WL_EVENT wl_ext_event_dettach(dhdp); #endif /* WL_EVENT */ @@ -17189,7 +17478,7 @@ void dhd_detach(dhd_pub_t *dhdp) if (dhdp->dbg) { #ifdef DBG_PKT_MON dhd_os_dbg_detach_pkt_monitor(dhdp); - osl_spin_lock_deinit(dhd->pub.osh, dhd->pub.dbg->pkt_mon_lock); + osl_mutex_lock_deinit(dhd->pub.osh, dhd->pub.dbg->pkt_mon_lock); #endif /* DBG_PKT_MON */ } #endif /* DEBUGABILITY */ @@ -18122,20 +18411,44 @@ exit: #endif /* DHD_PCIE_RUNTIMEPM */ +#ifdef DHD_LINUX_STD_FW_API +int +dhd_os_get_img_fwreq(const struct firmware **fw, char *file_path) +{ + int ret = BCME_ERROR; + + ret = request_firmware(fw, file_path, dhd_bus_to_dev(g_dhd_pub->bus)); + if (ret < 0) { + DHD_ERROR(("%s: request_firmware %s err: %d\n", __FUNCTION__, file_path, ret)); + /* convert to BCME_NOTFOUND error for error handling */ + ret = BCME_NOTFOUND; + } else + DHD_ERROR(("%s: %s (%zu bytes) open success\n", __FUNCTION__, file_path, (*fw)->size)); + + return ret; +} + +void +dhd_os_close_img_fwreq(const struct firmware *fw) +{ + release_firmware(fw); +} +#endif /* DHD_LINUX_STD_FW_API */ + void * dhd_os_open_image1(dhd_pub_t *pub, char *filename) { struct file *fp; int size; - fp = filp_open(filename, O_RDONLY, 0); + fp = dhd_filp_open(filename, O_RDONLY, 0); /* - * 2.6.11 (FC4) supports filp_open() but later revs don't? + * 2.6.11 (FC4) supports dhd_filp_open() but later revs don't? * Alternative: * fp = open_namei(AT_FDCWD, filename, O_RD, 0); * ??? */ - if (IS_ERR(fp)) { + if (IS_ERR(fp) || (fp == NULL)) { fp = NULL; goto err; } @@ -18146,7 +18459,7 @@ dhd_os_open_image1(dhd_pub_t *pub, char *filename) goto err; } - size = i_size_read(file_inode(fp)); + size = dhd_i_size_read(file_inode(fp)); if (size <= 0) { DHD_ERROR(("%s: %s file size invalid %d\n", __FUNCTION__, filename, size)); fp = NULL; @@ -18170,8 +18483,8 @@ dhd_os_get_image_block(char *buf, int len, void *image) return 0; } - size = i_size_read(file_inode(fp)); - rdlen = kernel_read_compat(fp, fp->f_pos, buf, MIN(len, size)); + size = dhd_i_size_read(file_inode(fp)); + rdlen = dhd_kernel_read_compat(fp, fp->f_pos, buf, MIN(len, size)); if (len >= size && size != rdlen) { return -EIO; @@ -18196,7 +18509,7 @@ dhd_os_gets_image(dhd_pub_t *pub, char *str, int len, void *image) if (!image) return 0; - rd_len = kernel_read_compat(fp, fp->f_pos, str, len); + rd_len = dhd_kernel_read_compat(fp, fp->f_pos, str, len); str_end = strnchr(str, len, '\n'); if (str_end == NULL) { goto err; @@ -18221,7 +18534,7 @@ dhd_os_get_image_size(void *image) return 0; } - size = i_size_read(file_inode(fp)); + size = dhd_i_size_read(file_inode(fp)); return size; } @@ -18230,7 +18543,7 @@ void dhd_os_close_image1(dhd_pub_t *pub, void *image) { if (image) { - filp_close((struct file *)image, NULL); + dhd_filp_close((struct file *)image, NULL); } } @@ -18905,10 +19218,6 @@ dhd_dev_get_feature_set(struct net_device *dev) feature_set |= WIFI_FEATURE_LINKSTAT; #endif /* LINKSTAT_SUPPORT */ -#ifdef CUSTOMER_HW_AMLOGIC - feature_set |= WIFI_FEATURE_SET_LATENCY_MODE; -#endif - #if defined(PNO_SUPPORT) && !defined(DISABLE_ANDROID_PNO) if (dhd_is_pno_supported(dhd)) { feature_set |= WIFI_FEATURE_PNO; @@ -20575,14 +20884,14 @@ int write_file(const char * file_name, uint32 flags, uint8 *buf, int size) #endif /* open file to write */ - fp = filp_open(file_name, flags, 0664); - if (IS_ERR(fp)) { + fp = dhd_filp_open(file_name, flags, 0664); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("open file error, err = %ld\n", PTR_ERR(fp))); goto exit; } /* Write buf to file */ - ret = vfs_write(fp, buf, size, &pos); + ret = dhd_vfs_write(fp, buf, size, &pos); if (ret < 0) { DHD_ERROR(("write file error, err = %d\n", ret)); goto exit; @@ -20590,7 +20899,7 @@ int write_file(const char * file_name, uint32 flags, uint8 *buf, int size) /* Sync file from filesystem to physical media */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) - ret = vfs_fsync(fp, 0); + ret = dhd_vfs_fsync(fp, 0); #else ret = vfs_fsync(fp, fp->f_path.dentry, 0); #endif @@ -20603,7 +20912,7 @@ int write_file(const char * file_name, uint32 flags, uint8 *buf, int size) exit: /* close file before return */ if (!IS_ERR(fp)) - filp_close(fp, current->files); + dhd_filp_close(fp, current->files); /* restore previous address limit */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) @@ -20795,14 +21104,14 @@ write_dump_to_file(dhd_pub_t *dhd, uint8 *buf, int size, char *fname) */ file_mode = O_CREAT | O_WRONLY | O_SYNC; { - struct file *fp = filp_open(memdump_path, file_mode, 0664); + struct file *fp = dhd_filp_open(memdump_path, file_mode, 0664); /* Check if it is live Brix image having /installmedia, else use /data */ - if (IS_ERR(fp)) { + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("open file %s, try /data/\n", memdump_path)); snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_" "%s", "/data/", fname, memdump_type, dhd->debug_dump_time_str); } else { - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); } } #else @@ -21663,7 +21972,7 @@ void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) return; i = snprintf(&info_string[i], sizeof(info_string) - i, - "\n Chip: %x Rev %x", dhd_conf_get_chip(dhdp), + "\n%s Chip: %x Rev %x", DHD_LOG_PREFIXS, dhd_conf_get_chip(dhdp), dhd_conf_get_chiprev(dhdp)); } @@ -22162,8 +22471,8 @@ dhd_get_rnd_info(dhd_pub_t *dhd) loff_t pos = 0; /* Read memdump info from the file */ - fp = filp_open(filepath, file_mode, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, file_mode, 0); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); #if defined(CONFIG_X86) && defined(OEM_ANDROID) /* Check if it is Live Brix Image */ @@ -22173,8 +22482,8 @@ dhd_get_rnd_info(dhd_pub_t *dhd) /* Try if it is Installed Brix Image */ filepath = RNDINFO_INST".in"; DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath)); - fp = filp_open(filepath, file_mode, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, file_mode, 0); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); goto err1; } @@ -22187,7 +22496,7 @@ dhd_get_rnd_info(dhd_pub_t *dhd) set_fs(KERNEL_DS); /* Handle success case */ - ret = vfs_read(fp, (char *)&dhd->rnd_len, sizeof(dhd->rnd_len), &pos); + ret = dhd_vfs_read(fp, (char *)&dhd->rnd_len, sizeof(dhd->rnd_len), &pos); if (ret < 0) { DHD_ERROR(("%s: rnd_len read error, ret=%d\n", __FUNCTION__, ret)); goto err2; @@ -22199,14 +22508,14 @@ dhd_get_rnd_info(dhd_pub_t *dhd) goto err2; } - ret = vfs_read(fp, (char *)dhd->rnd_buf, dhd->rnd_len, &pos); + ret = dhd_vfs_read(fp, (char *)dhd->rnd_buf, dhd->rnd_len, &pos); if (ret < 0) { DHD_ERROR(("%s: rnd_buf read error, ret=%d\n", __FUNCTION__, ret)); goto err3; } set_fs(old_fs); - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); DHD_ERROR(("%s: RND read from %s\n", __FUNCTION__, filepath)); return BCME_OK; @@ -22216,7 +22525,7 @@ err3: dhd->rnd_buf = NULL; err2: set_fs(old_fs); - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); err1: return BCME_ERROR; } @@ -22232,8 +22541,8 @@ dhd_dump_rnd_info(dhd_pub_t *dhd, uint8 *rnd_buf, uint32 rnd_len) loff_t pos = 0; /* Read memdump info from the file */ - fp = filp_open(filepath, file_mode, 0664); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, file_mode, 0664); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); #if defined(CONFIG_X86) && defined(OEM_ANDROID) /* Check if it is Live Brix Image */ @@ -22243,8 +22552,8 @@ dhd_dump_rnd_info(dhd_pub_t *dhd, uint8 *rnd_buf, uint32 rnd_len) /* Try if it is Installed Brix Image */ filepath = RNDINFO_INST".out"; DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath)); - fp = filp_open(filepath, file_mode, 0664); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, file_mode, 0664); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); goto err1; } @@ -22257,26 +22566,26 @@ dhd_dump_rnd_info(dhd_pub_t *dhd, uint8 *rnd_buf, uint32 rnd_len) set_fs(KERNEL_DS); /* Handle success case */ - ret = vfs_write(fp, (char *)&rnd_len, sizeof(rnd_len), &pos); + ret = dhd_vfs_write(fp, (char *)&rnd_len, sizeof(rnd_len), &pos); if (ret < 0) { DHD_ERROR(("%s: rnd_len write error, ret=%d\n", __FUNCTION__, ret)); goto err2; } - ret = vfs_write(fp, (char *)rnd_buf, rnd_len, &pos); + ret = dhd_vfs_write(fp, (char *)rnd_buf, rnd_len, &pos); if (ret < 0) { DHD_ERROR(("%s: rnd_buf write error, ret=%d\n", __FUNCTION__, ret)); goto err2; } set_fs(old_fs); - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); DHD_ERROR(("%s: RND written to %s\n", __FUNCTION__, filepath)); return BCME_OK; err2: set_fs(old_fs); - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); err1: return BCME_ERROR; @@ -24194,8 +24503,8 @@ do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type) else file_mode = O_CREAT | O_RDWR | O_SYNC; - fp = filp_open(dump_path, file_mode, 0664); - if (IS_ERR(fp)) { + fp = dhd_filp_open(dump_path, file_mode, 0664); + if (IS_ERR(fp) || (fp == NULL)) { /* If android installed image, try '/data' directory */ #if defined(CONFIG_X86) && defined(OEM_ANDROID) DHD_ERROR(("%s: File open error on Installed android image, trying /data...\n", @@ -24206,8 +24515,8 @@ do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type) sizeof(dump_path) - strlen(dump_path), "_%s", dhdp->debug_dump_time_str); } - fp = filp_open(dump_path, file_mode, 0664); - if (IS_ERR(fp)) { + fp = dhd_filp_open(dump_path, file_mode, 0664); + if (IS_ERR(fp) || (fp == NULL)) { ret = PTR_ERR(fp); DHD_ERROR(("open file error, err = %d\n", ret)); goto exit2; @@ -24221,7 +24530,7 @@ do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type) } #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - ret = vfs_stat(dump_path, &stat); + ret = dhd_vfs_stat(dump_path, &stat); if (ret < 0) { DHD_ERROR(("file stat error, err = %d\n", ret)); goto exit2; @@ -24390,7 +24699,7 @@ do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type) exit2: if (!IS_ERR(fp) && fp != NULL) { - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); DHD_ERROR(("%s: Finished writing log dump to file - '%s' \n", __FUNCTION__, dump_path)); } @@ -24425,7 +24734,7 @@ dhd_export_debug_data(void *mem_buf, void *fp, const void *user_buf, uint32 buf_ int ret = BCME_OK; if (fp) { - ret = vfs_write(fp, mem_buf, buf_len, (loff_t *)pos); + ret = dhd_vfs_write(fp, mem_buf, buf_len, (loff_t *)pos); if (ret < 0) { DHD_ERROR(("write file error, err = %d\n", ret)); goto exit; @@ -26326,8 +26635,8 @@ dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path) struct file *fp; char *filepath = VENDOR_PATH CONFIG_BCMDHD_CLM_PATH; - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: ----- blob file doesn't exist (%s) -----\n", __FUNCTION__, filepath)); dhdp->is_blob = FALSE; @@ -26339,7 +26648,7 @@ dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path) #else BCM_REFERENCE(fw_path); #endif /* SKIP_CONCATE_BLOB */ - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); } } #endif /* DHD_BLOB_EXISTENCE_CHECK */ @@ -26496,14 +26805,14 @@ dhd_write_file(const char *filepath, char *buf, int buf_len) #endif /* File is always created. */ - fp = filp_open(filepath, O_RDWR | O_CREAT, 0664); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, O_RDWR | O_CREAT, 0664); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: Couldn't open file '%s' err %ld\n", __FUNCTION__, filepath, PTR_ERR(fp))); ret = BCME_ERROR; } else { if (fp->f_mode & FMODE_WRITE) { - ret = vfs_write(fp, buf, buf_len, &fp->f_pos); + ret = dhd_vfs_write(fp, buf, buf_len, &fp->f_pos); if (ret < 0) { DHD_ERROR(("%s: Couldn't write file '%s'\n", __FUNCTION__, filepath)); @@ -26512,7 +26821,7 @@ dhd_write_file(const char *filepath, char *buf, int buf_len) ret = BCME_OK; } } - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); } /* restore previous address limit */ @@ -26538,8 +26847,8 @@ dhd_read_file(const char *filepath, char *buf, int buf_len) set_fs(KERNEL_DS); #endif - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) set_fs(old_fs); #endif @@ -26547,8 +26856,8 @@ dhd_read_file(const char *filepath, char *buf, int buf_len) return BCME_ERROR; } - ret = kernel_read_compat(fp, 0, buf, buf_len); - filp_close(fp, NULL); + ret = dhd_kernel_read_compat(fp, 0, buf, buf_len); + dhd_filp_close(fp, NULL); /* restore previous address limit */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) @@ -27361,7 +27670,11 @@ dhd_print_kirqstats(dhd_pub_t *dhd, unsigned int irq_num) char tmp_buf[KIRQ_PRINT_BUF_LEN]; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + desc = irq_data_to_desc(irq_get_irq_data(irq_num)); +#else desc = irq_to_desc(irq_num); +#endif // (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) if (!desc) { DHD_ERROR(("%s : irqdesc is not found \n", __FUNCTION__)); return; @@ -29344,27 +29657,15 @@ dhd_ring_whole_unlock(void *_ring) } /* END of DHD RING */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)) -#define DHD_VFS_INODE(dir) (dir->d_inode) -#else -#define DHD_VFS_INODE(dir) d_inode(dir) -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) -#define DHD_VFS_UNLINK(dir, b, c) vfs_unlink(DHD_VFS_INODE(dir), b) -#else -#define DHD_VFS_UNLINK(dir, b, c) vfs_unlink(DHD_VFS_INODE(dir), b, c) -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */ - #if ((defined DHD_DUMP_MNGR) || (defined DNGL_AXI_ERROR_LOGGING)) int dhd_file_delete(char *path) { - struct path file_path; + struct path file_path = {.dentry = 0}; int err; struct dentry *dir; - err = kern_path(path, 0, &file_path); + err = dhd_kern_path(path, 0, &file_path); if (err < 0) { DHD_ERROR(("Failed to get kern-path delete file: %s error: %d\n", path, err)); @@ -29823,65 +30124,69 @@ bool dhd_os_wd_timer_enabled(void *bus) #if defined(WLDWDS) && defined(FOURADDR_AUTO_BRG) /* This function is to automatically add/del interface to the bridged dev that priamy dev is in */ -static void dhd_bridge_dev_set(dhd_info_t *dhd, int ifidx, struct net_device *dev) +static void +dhd_bridge_dev_set(dhd_info_t *dhd, int ifidx, struct net_device *sdev) { - struct net_device *primary_ndev = NULL, *br_dev = NULL; - int cmd; - struct ifreq ifr; + struct net_device *pdev = NULL, *br_dev = NULL; + int i, err = 0; - /* add new interface to bridge dev */ - if (dev) { - int found = 0, i; - DHD_ERROR(("bssidx %d\n", dhd->pub.info->iflist[ifidx]->bssidx)); - for (i = 0 ; i < ifidx; i++) { - DHD_ERROR(("bssidx %d %d\n", i, dhd->pub.info->iflist[i]->bssidx)); - /* search the primary interface */ - if (dhd->pub.info->iflist[i]->bssidx == dhd->pub.info->iflist[ifidx]->bssidx) { - primary_ndev = dhd->pub.info->iflist[i]->net; - DHD_ERROR(("%dst is primary dev %s\n", i, primary_ndev->name)); - found = 1; + if (sdev) { + /* search the primary interface wlan1(wl0.1) with same bssidx */ + for (i = 0; i < ifidx; i++) { + if (dhd->iflist[i]->bssidx == dhd->iflist[ifidx]->bssidx) { + pdev = dhd->pub.info->iflist[i]->net; + WL_MSG(sdev->name, "found primary dev %s\n", pdev->name); break; } } - if (found == 0) { - DHD_ERROR(("Can not find primary dev %s\n", dev->name)); + if (!pdev) { + WL_MSG(sdev->name, "can not find primary dev\n"); return; } - cmd = SIOCBRADDIF; - ifr.ifr_ifindex = dev->ifindex; - } else { /* del interface from bridge dev */ - primary_ndev = dhd->pub.info->iflist[ifidx]->net; - cmd = SIOCBRDELIF; - ifr.ifr_ifindex = primary_ndev->ifindex; + } else { + pdev = dhd->iflist[ifidx]->net; } + /* if primary net device is bridged */ - if (primary_ndev->priv_flags & IFF_BRIDGE_PORT) { + if (pdev->priv_flags & IFF_BRIDGE_PORT) { rtnl_lock(); /* get bridge device */ - br_dev = netdev_master_upper_dev_get(primary_ndev); + br_dev = netdev_master_upper_dev_get(pdev); if (br_dev) { const struct net_device_ops *ops = br_dev->netdev_ops; - DHD_ERROR(("br %s pri %s\n", br_dev->name, primary_ndev->name)); if (ops) { - if (cmd == SIOCBRADDIF) { - DHD_ERROR(("br call ndo_add_slave\n")); - ops->ndo_add_slave(br_dev, dev); + if (sdev) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) + err = ops->ndo_add_slave(br_dev, sdev, NULL); +#else + err = ops->ndo_add_slave(br_dev, sdev); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */ + if (err) + WL_MSG(sdev->name, "add to %s failed %d\n", br_dev->name, err); + else + WL_MSG(sdev->name, "slave added to %s\n", br_dev->name); /* Also bring wds0.x interface up automatically */ - dev_change_flags(dev, dev->flags | IFF_UP); - } - else { - DHD_ERROR(("br call ndo_del_slave\n")); - ops->ndo_del_slave(br_dev, primary_ndev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) + dev_change_flags(sdev, sdev->flags | IFF_UP, NULL); +#else + dev_change_flags(sdev, sdev->flags | IFF_UP); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) */ + } else { + err = ops->ndo_del_slave(br_dev, pdev); + if (err) + WL_MSG(pdev->name, "del from %s failed %d\n", br_dev->name, err); + else + WL_MSG(pdev->name, "slave deleted from %s\n", br_dev->name); } } } else { - DHD_ERROR(("no br dev\n")); + WL_MSG(pdev->name, "not bridged\n"); } rtnl_unlock(); } else { - DHD_ERROR(("device %s is not bridged\n", primary_ndev->name)); + WL_MSG(pdev->name, "not bridged\n"); } } -#endif /* defiend(WLDWDS) && defined(FOURADDR_AUTO_BRG) */ +#endif /* WLDWDS && FOURADDR_AUTO_BRG */ diff --git a/bcmdhd.101.10.361.x/dhd_linux.h b/bcmdhd.101.10.361.x/dhd_linux.h index 531505d..565b1a4 100755 --- a/bcmdhd.101.10.361.x/dhd_linux.h +++ b/bcmdhd.101.10.361.x/dhd_linux.h @@ -67,9 +67,8 @@ /* dongle status */ enum wifi_adapter_status { WIFI_STATUS_POWER_ON = 0, - WIFI_STATUS_ATTACH, WIFI_STATUS_FW_READY, - WIFI_STATUS_DETTACH + WIFI_STATUS_NET_ATTACHED }; #define wifi_chk_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status)) #define wifi_get_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status)) @@ -407,6 +406,9 @@ typedef struct dhd_if { bool recv_reassoc_evt; bool post_roam_evt; #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */ +#ifdef WLDWDS + bool dwds; /* DWDS interface */ +#endif /* WLDWDS */ #ifdef WLEASYMESH uint8 _1905_al_ucast[ETHER_ADDR_LEN]; uint8 _1905_al_mcast[ETHER_ADDR_LEN]; diff --git a/bcmdhd.101.10.361.x/dhd_linux_exportfs.c b/bcmdhd.101.10.361.x/dhd_linux_exportfs.c index ef5b0cc..7377f4e 100755 --- a/bcmdhd.101.10.361.x/dhd_linux_exportfs.c +++ b/bcmdhd.101.10.361.x/dhd_linux_exportfs.c @@ -177,6 +177,7 @@ dhd_dbg_ring_proc_destroy(dhd_pub_t *dhdp) * ----------------------------------------------------------------------------- */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #if defined(DHD_TRACE_WAKE_LOCK) extern atomic_t trace_wklock_onoff; @@ -1030,6 +1031,7 @@ done: return ret; } #endif /* PWRSTATS_SYSFS */ +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ /* * Generic Attribute Structure for DHD. @@ -1046,6 +1048,7 @@ struct dhd_attr { ssize_t(*store)(struct dhd_info *, const char *, size_t count); }; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #if defined(DHD_TRACE_WAKE_LOCK) static struct dhd_attr dhd_attr_wklock = __ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff); @@ -1119,10 +1122,12 @@ static struct dhd_attr dhd_attr_nvram_path = static struct dhd_attr dhd_attr_pwrstats_path = __ATTR(power_stats, 0660, show_pwrstats_path, NULL); #endif /* PWRSTATS_SYSFS */ +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ #define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj) #define to_attr(a) container_of(a, struct dhd_attr, attr) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #ifdef DHD_MAC_ADDR_EXPORT struct ether_addr sysfs_mac_addr; static ssize_t @@ -1154,6 +1159,7 @@ set_mac_addr(struct dhd_info *dev, const char *buf, size_t count) static struct dhd_attr dhd_attr_macaddr = __ATTR(mac_addr, 0660, show_mac_addr, set_mac_addr); #endif /* DHD_MAC_ADDR_EXPORT */ +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ #ifdef DHD_FW_COREDUMP /* @@ -1185,8 +1191,8 @@ get_mem_val_from_file(void) int ret = 0; /* Read memdump info from the file */ - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); #if defined(CONFIG_X86) && defined(OEM_ANDROID) /* Check if it is Live Brix Image */ @@ -1196,8 +1202,8 @@ get_mem_val_from_file(void) /* Try if it is Installed Brix Image */ filepath = MEMDUMPINFO_INST; DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath)); - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); goto done; } @@ -1207,10 +1213,10 @@ get_mem_val_from_file(void) } /* Handle success case */ - ret = kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32)); + ret = dhd_kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32)); if (ret < 0) { DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret)); - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); goto done; } @@ -1218,7 +1224,7 @@ get_mem_val_from_file(void) p_mem_val[sizeof(uint32) - 1] = '\0'; mem_val = bcm_atoi(p_mem_val); - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); done: return mem_val; @@ -1262,6 +1268,7 @@ void dhd_get_memdump_info(dhd_pub_t *dhd) DHD_ERROR(("%s: MEMDUMP ENABLED = %u\n", __FUNCTION__, dhd->memdump_enabled)); } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #ifdef DHD_EXPORT_CNTL_FILE static ssize_t show_memdump_info(struct dhd_info *dev, char *buf) @@ -1303,6 +1310,7 @@ set_memdump_info(struct dhd_info *dev, const char *buf, size_t count) static struct dhd_attr dhd_attr_memdump = __ATTR(memdump, 0660, show_memdump_info, set_memdump_info); #endif /* DHD_EXPORT_CNTL_FILE */ +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ #endif /* DHD_FW_COREDUMP */ #ifdef BCMASSERT_LOG @@ -1327,11 +1335,11 @@ get_assert_val_from_file(void) * 2: Trigger Kernel crash by BUG() * File doesn't exist: Keep default value (1). */ - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); } else { - int ret = kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32)); + int ret = dhd_kernel_read_compat(fp, 0, (char *)&mem_val, sizeof(uint32)); if (ret < 0) { DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret)); } else { @@ -1340,7 +1348,7 @@ get_assert_val_from_file(void) mem_val = bcm_atoi(p_mem_val); DHD_ERROR(("%s: ASSERT ENABLED = %d\n", __FUNCTION__, mem_val)); } - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); } #ifdef CUSTOMER_HW4_DEBUG @@ -1362,6 +1370,7 @@ void dhd_get_assert_info(dhd_pub_t *dhd) #endif /* !DHD_EXPORT_CNTL_FILE */ } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #ifdef DHD_EXPORT_CNTL_FILE static ssize_t show_assert_info(struct dhd_info *dev, char *buf) @@ -1396,8 +1405,10 @@ set_assert_info(struct dhd_info *dev, const char *buf, size_t count) static struct dhd_attr dhd_attr_assert = __ATTR(assert, 0660, show_assert_info, set_assert_info); #endif /* DHD_EXPORT_CNTL_FILE */ +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ #endif /* BCMASSERT_LOG */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #ifdef DHD_EXPORT_CNTL_FILE #if defined(WRITE_WLANINFO) static ssize_t @@ -1889,10 +1900,12 @@ store_adps_bam_list(struct dhd_info *dev, const char *buf, size_t count) static struct dhd_attr dhd_attr_adps_bam = __ATTR(bad_ap_list, 0660, show_adps_bam_list, store_adps_bam_list); #endif /* DHD_ADPS_BAM_EXPORT && WL_BAM */ +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ -#ifdef DHD_SEND_HANG_PRIVCMD_ERRORS uint32 report_hang_privcmd_err = 1; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) +#ifdef DHD_SEND_HANG_PRIVCMD_ERRORS static ssize_t show_hang_privcmd_err(struct dhd_info *dev, char *buf) { @@ -2350,6 +2363,7 @@ static struct attribute *default_file_attrs[] = { #endif /* AGG_H2D_DB */ NULL }; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ /* * wifi kobject show function, the "attr" attribute specifices to which @@ -2406,7 +2420,9 @@ static struct sysfs_ops dhd_sysfs_ops = { static struct kobj_type dhd_ktype = { .sysfs_ops = &dhd_sysfs_ops, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) .default_attrs = default_file_attrs, +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ }; #ifdef CSI_SUPPORT @@ -2436,6 +2452,7 @@ static struct bin_attribute dhd_attr_csi = { * sysfs for dhd_lb */ #ifdef DHD_LB +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) #if defined(DHD_LB_TXP) static ssize_t show_lbtxp(struct dhd_info *dev, char *buf) @@ -2830,6 +2847,7 @@ static struct attribute *debug_lb_attrs[] = { &dhd_tx_cpu.attr, NULL }; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ #define to_dhd_lb(k) container_of(k, struct dhd_info, dhd_lb_kobj) @@ -2888,7 +2906,9 @@ static struct sysfs_ops dhd_sysfs_lb_ops = { static struct kobj_type dhd_lb_ktype = { .sysfs_ops = &dhd_sysfs_lb_ops, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) .default_attrs = debug_lb_attrs, +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) */ }; #endif /* DHD_LB */ diff --git a/bcmdhd.101.10.361.x/dhd_linux_pktdump.c b/bcmdhd.101.10.361.x/dhd_linux_pktdump.c index 66e0b44..028bc76 100755 --- a/bcmdhd.101.10.361.x/dhd_linux_pktdump.c +++ b/bcmdhd.101.10.361.x/dhd_linux_pktdump.c @@ -1047,13 +1047,34 @@ dhd_check_dhcp(uint8 *pktdata) return TRUE; } -#ifdef DHD_DHCP_DUMP #define BOOTP_CHADDR_LEN 16 #define BOOTP_SNAME_LEN 64 #define BOOTP_FILE_LEN 128 #define BOOTP_MIN_DHCP_OPT_LEN 312 #define BOOTP_MAGIC_COOKIE_LEN 4 +typedef struct bootp_fmt { + struct ipv4_hdr iph; + struct bcmudp_hdr udph; + uint8 op; + uint8 htype; + uint8 hlen; + uint8 hops; + uint32 transaction_id; + uint16 secs; + uint16 flags; + uint32 client_ip; + uint32 assigned_ip; + uint32 server_ip; + uint32 relay_ip; + uint8 hw_address[BOOTP_CHADDR_LEN]; + uint8 server_name[BOOTP_SNAME_LEN]; + uint8 file_name[BOOTP_FILE_LEN]; + uint8 options[BOOTP_MIN_DHCP_OPT_LEN]; +} PACKED_STRUCT bootp_fmt_t; +static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 }; + +#ifdef DHD_DHCP_DUMP #define DHCP_MSGTYPE_DISCOVER 1 #define DHCP_MSGTYPE_OFFER 2 #define DHCP_MSGTYPE_REQUEST 3 @@ -1077,27 +1098,6 @@ dhd_check_dhcp(uint8 *pktdata) } \ } while (0) -typedef struct bootp_fmt { - struct ipv4_hdr iph; - struct bcmudp_hdr udph; - uint8 op; - uint8 htype; - uint8 hlen; - uint8 hops; - uint32 transaction_id; - uint16 secs; - uint16 flags; - uint32 client_ip; - uint32 assigned_ip; - uint32 server_ip; - uint32 relay_ip; - uint8 hw_address[BOOTP_CHADDR_LEN]; - uint8 server_name[BOOTP_SNAME_LEN]; - uint8 file_name[BOOTP_FILE_LEN]; - uint8 options[BOOTP_MIN_DHCP_OPT_LEN]; -} PACKED_STRUCT bootp_fmt_t; - -static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 }; static char dhcp_ops[][10] = { "NA", "REQUEST", "REPLY" }; @@ -1576,3 +1576,160 @@ dhd_trx_pkt_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen, bool } } #endif /* DHD_RX_DUMP */ + +#ifdef BCMPCIE +static bool +dhd_is_eapol_pkt(dhd_pub_t *dhd, uint8 *pktdata, uint32 pktlen) +{ + eapol_header_t *eapol_hdr = (eapol_header_t *)pktdata; + + eapol_hdr = (eapol_header_t *)pktdata; + + if (eapol_hdr->type == EAP_PACKET) { + return TRUE; + } else if (eapol_hdr->type == EAPOL_START) { + return TRUE; + } else if (eapol_hdr->type == EAPOL_KEY) { + return TRUE; + } else { + return TRUE; + } + return FALSE; +} + +static bool +dhd_is_arp_pkt(dhd_pub_t *dhdp, uint8 *pktdata) +{ + uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN]; + struct bcmarp *arph = (struct bcmarp *)pkt; + uint16 opcode; + + /* validation check */ + if (arph->htype != hton16(HTYPE_ETHERNET) || + arph->hlen != ETHER_ADDR_LEN || + arph->plen != 4) { + return FALSE; + } + + opcode = ntoh16(arph->oper); + if (opcode == ARP_OPC_REQUEST) { + return TRUE; + } else if (opcode == ARP_OPC_REPLY) { + return TRUE; + } else { + return TRUE; + } + return FALSE; +} + +static bool +dhd_is_dhcp_pkt(dhd_pub_t *dhdp, uint8 *pktdata) +{ + bootp_fmt_t *b = (bootp_fmt_t *)&pktdata[ETHER_HDR_LEN]; + struct ipv4_hdr *iph = &b->iph; + uint8 *ptr, *opt, *end = (uint8 *) b + ntohs(b->iph.tot_len); + int len, opt_len; + + /* check IP header */ + if ((IPV4_HLEN(iph) < IPV4_HLEN_MIN) || + IP_VER(iph) != IP_VER_4 || + IPV4_PROT(iph) != IP_PROT_UDP) { + return FALSE; + } + + /* check UDP port for bootp (67, 68) */ + if (b->udph.src_port != htons(DHCP_PORT_SERVER) && + b->udph.src_port != htons(DHCP_PORT_CLIENT) && + b->udph.dst_port != htons(DHCP_PORT_SERVER) && + b->udph.dst_port != htons(DHCP_PORT_CLIENT)) { + return FALSE; + } + + /* check header length */ + if (ntohs(iph->tot_len) < ntohs(b->udph.len) + sizeof(struct bcmudp_hdr)) { + return FALSE; + } + + len = ntohs(b->udph.len) - sizeof(struct bcmudp_hdr); + opt_len = len - (sizeof(*b) - sizeof(struct ipv4_hdr) - + sizeof(struct bcmudp_hdr) - sizeof(b->options)); + + /* parse bootp options */ + if (opt_len >= BOOTP_MAGIC_COOKIE_LEN && + !memcmp(b->options, bootp_magic_cookie, BOOTP_MAGIC_COOKIE_LEN)) { + ptr = &b->options[BOOTP_MAGIC_COOKIE_LEN]; + while (ptr < end && *ptr != 0xff) { + opt = ptr++; + if (*opt == 0) { + continue; + } + ptr += *ptr + 1; + if (ptr >= end) { + break; + } + if (*opt == DHCP_OPT_MSGTYPE) { + if (opt[1]) { + return TRUE; + } + } + } + } + + return FALSE; +} + +static bool +dhd_is_icmp_pkt(dhd_pub_t *dhd, uint8 *pktdata, uint32 pktlen) +{ + uint8 *pkt; + struct ipv4_hdr *iph; + + pkt = (uint8 *)&pktdata[ETHER_HDR_LEN]; + iph = (struct ipv4_hdr *)pkt; + + /* check IP header */ + if ((IPV4_HLEN(iph) < IPV4_HLEN_MIN) || + IP_VER(iph) != IP_VER_4 || + IPV4_PROT(iph) != IP_PROT_ICMP) { + return FALSE; + } + + /* check header length */ + if (ntohs(iph->tot_len) - IPV4_HLEN(iph) < sizeof(struct bcmicmp_hdr)) { + return FALSE; + } + + return TRUE; +} + +bool +dhd_match_pkt_type(dhd_pub_t *dhd, uint8 *pktdata, uint32 pktlen) +{ + struct ether_header *eh; + uint16 ether_type; + bool match = FALSE; + + if (!pktdata || pktlen < ETHER_HDR_LEN) { + return match; + } + + eh = (struct ether_header *)pktdata; + ether_type = ntoh16(eh->ether_type); + if ((dhd->conf->enq_hdr_pkt & ENQ_PKT_TYPE_EAPOL) && + ether_type == ETHER_TYPE_802_1X) { + match = dhd_is_eapol_pkt(dhd, pktdata, pktlen); + } + else if ((dhd->conf->enq_hdr_pkt & ENQ_PKT_TYPE_ARP) && + ntoh16(eh->ether_type) == ETHER_TYPE_ARP) { + match = dhd_is_arp_pkt(dhd, pktdata); + } + else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { + if (dhd->conf->enq_hdr_pkt & ENQ_PKT_TYPE_ICMP) + match = dhd_is_icmp_pkt(dhd, pktdata, pktlen); + if (!match && dhd->conf->enq_hdr_pkt & ENQ_PKT_TYPE_DHCP) + match = dhd_is_dhcp_pkt(dhd, pktdata); + } + + return match; +} +#endif /* BCMPCIE */ diff --git a/bcmdhd.101.10.361.x/dhd_linux_pktdump.h b/bcmdhd.101.10.361.x/dhd_linux_pktdump.h index 7d7ce72..96a160a 100755 --- a/bcmdhd.101.10.361.x/dhd_linux_pktdump.h +++ b/bcmdhd.101.10.361.x/dhd_linux_pktdump.h @@ -59,6 +59,9 @@ enum pkt_type { extern msg_eapol_t dhd_is_4way_msg(uint8 *pktdata); extern void dhd_dump_pkt(dhd_pub_t *dhd, int ifidx, uint8 *pktdata, uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate); +#ifdef BCMPCIE +extern bool dhd_match_pkt_type(dhd_pub_t *dhd, uint8 *pktdata, uint32 pktlen); +#endif /* BCMPCIE */ #ifdef DHD_PKTDUMP_ROAM extern void dhd_dump_mod_pkt_timer(dhd_pub_t *dhdp, uint16 rsn); extern void dhd_dump_pkt_init(dhd_pub_t *dhdp); diff --git a/bcmdhd.101.10.361.x/dhd_linux_platdev.c b/bcmdhd.101.10.361.x/dhd_linux_platdev.c index adf6b2d..0457950 100755 --- a/bcmdhd.101.10.361.x/dhd_linux_platdev.c +++ b/bcmdhd.101.10.361.x/dhd_linux_platdev.c @@ -42,9 +42,6 @@ #else #include #endif /* CONFIG_WIFI_CONTROL_FUNC */ -#ifdef BCMDBUS -#include -#endif #ifdef CONFIG_DTS #include #include @@ -170,7 +167,7 @@ void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned return NULL; plat_data = adapter->wifi_plat_data; if (plat_data->mem_prealloc) { -#ifdef BCMDHD_MDRIVER +#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) alloc_ptr = plat_data->mem_prealloc(adapter->bus_type, adapter->index, section, size); #else alloc_ptr = plat_data->mem_prealloc(section, size); @@ -569,16 +566,7 @@ static int wifi_ctrlfunc_register_drv(void) return -ENOMEM; } adapter->name = "DHD generic adapter"; - adapter->index = -1; -#ifdef BCMDHD_MDRIVER -#ifdef BCMSDIO adapter->index = 0; -#elif defined(BCMPCIE) - adapter->index = 1; -#elif defined(BCMDBUS) - adapter->index = 2; -#endif -#endif adapter->bus_type = -1; adapter->bus_num = -1; adapter->slot_num = -1; @@ -771,10 +759,11 @@ static int dhd_wifi_platform_load_pcie(void) err = dhd_bus_register(); } else { #ifdef DHD_SUPPORT_HDM - if (dhd_download_fw_on_driverload || hdm_trigger_init) { + if (dhd_download_fw_on_driverload || hdm_trigger_init) #else - if (dhd_download_fw_on_driverload) { + if (dhd_download_fw_on_driverload) #endif /* DHD_SUPPORT_HDM */ + { /* power up all adapters */ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { int retry = POWERUP_MAX_RETRY; @@ -896,7 +885,9 @@ static int dhd_wifi_platform_load_sdio(void) for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { bool chip_up = FALSE; int retry = POWERUP_MAX_RETRY; +#ifndef DHD_INSMOD_NOWAIT struct semaphore dhd_chipup_sem; +#endif adapter = &dhd_wifi_platdata->adapters[i]; @@ -907,6 +898,18 @@ static int dhd_wifi_platform_load_sdio(void) adapter->bus_type, adapter->bus_num, adapter->slot_num)); do { +#ifdef DHD_INSMOD_NOWAIT + err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); + if (err) { + DHD_ERROR(("%s: wifi pwr on error ! \n", __FUNCTION__)); + wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); + continue; + } else { + wifi_platform_bus_enumerate(adapter, TRUE); + chip_up = TRUE; + break; + } +#else #ifndef CUSTOMER_HW_AMLOGIC sema_init(&dhd_chipup_sem, 0); err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem); @@ -946,6 +949,7 @@ static int dhd_wifi_platform_load_sdio(void) dhd_bus_unreg_sdio_notify(); wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); wifi_platform_bus_enumerate(adapter, FALSE); +#endif } while (retry--); if (!chip_up) { @@ -962,6 +966,7 @@ static int dhd_wifi_platform_load_sdio(void) goto fail; } +#ifndef DHD_INSMOD_NOWAIT /* * Wait till MMC sdio_register_driver callback called and made driver attach. * It's needed to make sync up exit from dhd insmod and @@ -973,6 +978,7 @@ static int dhd_wifi_platform_load_sdio(void) dhd_bus_unregister(); goto fail; } +#endif return err; @@ -1005,7 +1011,6 @@ static int dhd_wifi_platform_load_usb(void) wifi_adapter_info_t *adapter; s32 timeout = -1; int i; - enum wifi_adapter_status wait_status; #endif #if !defined(DHD_PRELOAD) @@ -1014,7 +1019,7 @@ static int dhd_wifi_platform_load_usb(void) adapter = &dhd_wifi_platdata->adapters[i]; wifi_platform_set_power(adapter, FALSE, 0); if (err) { - DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name)); + DHD_ERROR(("failed to wifi_platform_set_power off %s\n", adapter->name)); goto exit; } } @@ -1041,12 +1046,8 @@ static int dhd_wifi_platform_load_usb(void) DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name)); goto fail; } - if (dhd_download_fw_on_driverload) - wait_status = WIFI_STATUS_ATTACH; - else - wait_status = WIFI_STATUS_DETTACH; timeout = wait_event_interruptible_timeout(adapter->status_event, - wifi_get_adapter_status(adapter, wait_status), + wifi_get_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED), msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); if (timeout <= 0) { err = -1; diff --git a/bcmdhd.101.10.361.x/dhd_macdbg.c b/bcmdhd.101.10.361.x/dhd_macdbg.c index dd145df..6085bcd 100755 --- a/bcmdhd.101.10.361.x/dhd_macdbg.c +++ b/bcmdhd.101.10.361.x/dhd_macdbg.c @@ -26,13 +26,8 @@ #include "dhdioctl.h" #include -#ifdef BCMDBUS -#include -#define BUS_IOVAR_OP(a, b, c, d, e, f, g) dbus_iovar_op(a->dbus, b, c, d, e, f, g) -#else #include #define BUS_IOVAR_OP dhd_bus_iovar_op -#endif typedef struct _macdbg_info_t { dhd_pub_t *dhdp; diff --git a/bcmdhd.101.10.361.x/dhd_msgbuf.c b/bcmdhd.101.10.361.x/dhd_msgbuf.c index 12eb4e0..1b6b7ce 100755 --- a/bcmdhd.101.10.361.x/dhd_msgbuf.c +++ b/bcmdhd.101.10.361.x/dhd_msgbuf.c @@ -39,11 +39,7 @@ #include #include -#ifdef BCMDBUS -#include -#else #include -#endif /* BCMDBUS */ #include #include diff --git a/bcmdhd.101.10.361.x/dhd_pcie.c b/bcmdhd.101.10.361.x/dhd_pcie.c index f69951d..96bc798 100755 --- a/bcmdhd.101.10.361.x/dhd_pcie.c +++ b/bcmdhd.101.10.361.x/dhd_pcie.c @@ -102,6 +102,7 @@ #if defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON) #include #endif /* DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */ +#include #define EXTENDED_PCIE_DEBUG_DUMP 1 /* Enable Extended pcie registers dump */ @@ -3991,6 +3992,118 @@ exit: } #endif /* BCMINTERNAL */ +#ifdef DHD_LINUX_STD_FW_API +static int +dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) +{ + int bcmerror = BCME_ERROR; + int offset = 0; + int len = 0; + bool store_reset; + int offset_end = bus->ramsize; + const struct firmware *fw = NULL; + int buf_offset = 0, residual_len = 0; +#ifdef CHECK_DOWNLOAD_FW + uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct +#endif + +#if defined(DHD_FW_MEM_CORRUPTION) + if (dhd_bus_get_fw_mode(bus->dhd) == DHD_FLAG_MFG_MODE) { + dhd_tcm_test_enable = TRUE; + } else { + dhd_tcm_test_enable = FALSE; + } +#endif /* DHD_FW_MEM_CORRUPTION */ + DHD_ERROR(("%s: dhd_tcm_test_enable %u\n", __FUNCTION__, dhd_tcm_test_enable)); + /* TCM check */ + if (dhd_tcm_test_enable && !dhd_bus_tcm_test(bus)) { + DHD_ERROR(("dhd_bus_tcm_test failed\n")); + bcmerror = BCME_ERROR; + goto err; + } + + DHD_ERROR(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); + + /* check if CR4/CA7 */ + store_reset = (si_setcore(bus->sih, ARMCR4_CORE_ID, 0) || + si_setcore(bus->sih, ARMCA7_CORE_ID, 0)); + + bcmerror = dhd_os_get_img_fwreq(&fw, bus->fw_path); + if (bcmerror < 0) { + DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n", + bcmerror)); + goto err; + } +#ifdef CHECK_DOWNLOAD_FW + if (bus->dhd->conf->fwchk) { + memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); + if (memptr_tmp == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); + goto err; + } + } +#endif + residual_len = fw->size; + while (residual_len) { + len = MIN(residual_len, MEMBLOCK); + + /* if address is 0, store the reset instruction to be written in 0 */ + if (store_reset) { + ASSERT(offset == 0); + bus->resetinstr = *(((uint32*)fw->data + buf_offset)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + offset_end += offset; + store_reset = FALSE; + } + + bcmerror = dhdpcie_bus_membytes(bus, TRUE, offset, + (uint8 *)fw->data + buf_offset, len); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } +#ifdef CHECK_DOWNLOAD_FW + if (bus->dhd->conf->fwchk) { + bcmerror = dhdpcie_bus_membytes(bus, FALSE, offset, memptr_tmp, len); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + if (memcmp(memptr_tmp, (uint8 *)fw->data + buf_offset, len)) { + DHD_ERROR(("%s: Downloaded image is corrupted at 0x%08x\n", __FUNCTION__, offset)); + bcmerror = BCME_ERROR; + goto err; + } else + DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__)); + } +#endif + offset += MEMBLOCK; + + if (offset >= offset_end) { + DHD_ERROR(("%s: invalid address access to %x (offset end: %x)\n", + __FUNCTION__, offset, offset_end)); + bcmerror = BCME_ERROR; + goto err; + } + residual_len -= len; + buf_offset += len; + } +err: +#ifdef CHECK_DOWNLOAD_FW + if (memptr_tmp) + MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN); +#endif + if (fw) { + dhd_os_close_img_fwreq(fw); + } + return bcmerror; +} /* dhdpcie_download_code_file */ + +#else + /** * Downloads a file containing firmware into dongle memory. In case of a .bea file, the DHD * is updated with the event logging partitions within that file as well. @@ -4197,6 +4310,7 @@ err: return bcmerror; } /* dhdpcie_download_code_file */ +#endif /* DHD_LINUX_STD_FW_API */ #ifdef CUSTOMER_HW4_DEBUG #define MIN_NVRAMVARS_SIZE 128 @@ -4206,7 +4320,7 @@ static int dhdpcie_download_nvram(struct dhd_bus *bus) { int bcmerror = BCME_ERROR; - uint len; + uint len, memblock_len = 0; char * memblock = NULL; char *bufp; char *pnv_path; @@ -4253,6 +4367,11 @@ dhdpcie_download_nvram(struct dhd_bus *bus) } else { nvram_uefi_exists = TRUE; } +#ifdef DHD_LINUX_STD_FW_API + memblock_len = len; +#else + memblock_len = MAX_NVRAMBUF_SIZE; +#endif /* DHD_LINUX_STD_FW_API */ DHD_ERROR(("%s: dhd_get_download_buffer len %d\n", __FUNCTION__, len)); @@ -4313,7 +4432,7 @@ err: if (local_alloc) { MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); } else { - dhd_free_download_buffer(bus->dhd, memblock, MAX_NVRAMBUF_SIZE); + dhd_free_download_buffer(bus->dhd, memblock, memblock_len); } } @@ -5689,6 +5808,7 @@ BCMFASTPATH(dhd_bus_txdata)(struct dhd_bus *bus, void *txp, uint8 ifidx) void *ntxp = NULL; uint8 prio = PKTPRIO(txp); #endif + uint8 *pktdata = (uint8 *)PKTDATA(bus->dhd->osh, txp); if (!bus->dhd->flowid_allocator) { DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); @@ -5777,6 +5897,10 @@ BCMFASTPATH(dhd_bus_txdata)(struct dhd_bus *bus, void *txp, uint8 ifidx) } } #else /* !(defined(BCM_ROUTER_DHD) && defined(HNDCTF)) */ + if (dhd_match_pkt_type(bus->dhd, pktdata, (uint32)PKTLEN(bus->dhd->osh, txp))) { + if ((ret = dhd_flow_queue_enqueue_head(bus->dhd, queue, txp)) != BCME_OK) + txp_pend = txp; + } else if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp)) != BCME_OK) txp_pend = txp; #endif /* defined(BCM_ROUTER_DHD) && defined(HNDCTF */ @@ -5814,6 +5938,13 @@ BCMFASTPATH(dhd_bus_txdata)(struct dhd_bus *bus, void *txp, uint8 ifidx) } } #else /* !(defined(BCM_ROUTER_DHD) && defined(HNDCTF)) */ + if (dhd_match_pkt_type(bus->dhd, pktdata, (uint32)PKTLEN(bus->dhd->osh, txp))) { + if ((ret = dhd_flow_queue_enqueue_head(bus->dhd, queue, txp_pend)) != BCME_OK) { + DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); + txp = txp_pend; + goto toss; + } + } else if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp_pend)) != BCME_OK) { DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); txp = txp_pend; @@ -9571,7 +9702,7 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) /* Got D3 Ack. Suspend the bus */ #ifdef OEM_ANDROID if (active) { - DHD_ERROR(("%s():Suspend failed because of wakelock" + DHD_ERROR(("%s():Suspend failed because of wakelock " "restoring Dongle to D0\n", __FUNCTION__)); if (bus->dhd->dhd_watchdog_ms_backup) { diff --git a/bcmdhd.101.10.361.x/dhd_pcie_linux.c b/bcmdhd.101.10.361.x/dhd_pcie_linux.c index 2a18c7c..dbeab68 100755 --- a/bcmdhd.101.10.361.x/dhd_pcie_linux.c +++ b/bcmdhd.101.10.361.x/dhd_pcie_linux.c @@ -268,7 +268,7 @@ static const struct dev_pm_ops dhdpcie_pm_ops = { static struct pci_driver dhdpcie_driver = { node: {&dhdpcie_driver.node, &dhdpcie_driver.node}, - name: "pcieh", + name: "pcieh"BUS_TYPE, id_table: dhdpcie_pci_devid, probe: dhdpcie_pci_probe, remove: dhdpcie_pci_remove, @@ -1737,7 +1737,7 @@ dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info) { dhd_bus_t *bus = dhdpcie_info->bus; struct pci_dev *pdev = dhdpcie_info->bus->dev; - int host_irq_disabled; + int host_irq_disabled, err = 0; if (!bus->irq_registered) { snprintf(dhdpcie_info->pciname, sizeof(dhdpcie_info->pciname), @@ -1752,13 +1752,14 @@ dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info) } if (bus->d2h_intr_method == PCIE_MSI) - printf("%s: MSI enabled\n", __FUNCTION__); + printf("%s: MSI enabled, irq=%d\n", __FUNCTION__, pdev->irq); else - printf("%s: INTx enabled\n", __FUNCTION__); + printf("%s: INTx enabled, irq=%d\n", __FUNCTION__, pdev->irq); - if (request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED, - dhdpcie_info->pciname, bus) < 0) { - DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__)); + err = request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED, + dhdpcie_info->pciname, bus); + if (err < 0) { + DHD_ERROR(("%s: request_irq() failed with %d\n", __FUNCTION__, err)); if (bus->d2h_intr_method == PCIE_MSI) { dhdpcie_disable_msi(pdev); } @@ -2050,8 +2051,12 @@ int dhdpcie_init(struct pci_dev *pdev) adapter->bus_num = pdev->bus->number; adapter->slot_num = PCI_SLOT(pdev->devfn); adapter->pci_dev = pdev; - } else + } else { DHD_ERROR(("%s: can't find adapter info for this chip\n", __FUNCTION__)); +#ifdef ADAPTER_IDX + break; +#endif + } osl_static_mem_init(osh, adapter); /* allocate linux spcific pcie structure here */ @@ -2286,7 +2291,8 @@ int dhdpcie_init(struct pci_dev *pdev) if (dhdpcie_info) dhdpcie_detach(dhdpcie_info); - pci_disable_device(pdev); + if (adapter) + pci_disable_device(pdev); if (osh) osl_detach(osh); if (adapter != NULL) { @@ -2406,7 +2412,13 @@ dhdpcie_enable_irq(dhd_bus_t *bus) int dhdpcie_irq_disabled(dhd_bus_t *bus) { - struct irq_desc *desc = irq_to_desc(bus->dev->irq); + struct irq_desc *desc = NULL; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + desc = irq_data_to_desc(irq_get_irq_data(bus->dev->irq)); +#else + desc = irq_to_desc(bus->dev->irq); +#endif // (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) /* depth will be zero, if enabled */ return desc->depth; } @@ -3345,7 +3357,9 @@ dhd_dongle_mem_dump(void) dhd_bus_mem_dump(g_dhd_bus->dhd); return 0; } +#ifndef BCMDHD_MDRIVER EXPORT_SYMBOL(dhd_dongle_mem_dump); +#endif #endif /* DHD_FW_COREDUMP */ #ifdef CONFIG_ARCH_MSM @@ -3376,4 +3390,6 @@ dhd_bus_check_driver_up(void) return isup; } +#ifndef BCMDHD_MDRIVER EXPORT_SYMBOL(dhd_bus_check_driver_up); +#endif diff --git a/bcmdhd.101.10.361.x/dhd_pktlog.c b/bcmdhd.101.10.361.x/dhd_pktlog.c index 0d57344..d491cd0 100755 --- a/bcmdhd.101.10.361.x/dhd_pktlog.c +++ b/bcmdhd.101.10.361.x/dhd_pktlog.c @@ -1204,8 +1204,8 @@ dhd_pktlog_dump_write_file(dhd_pub_t *dhdp) set_fs(KERNEL_DS); file_mode = O_CREAT | O_WRONLY; - w_pcap_fp = filp_open(pktlogdump_path, file_mode, 0664); - if (IS_ERR(w_pcap_fp)) { + w_pcap_fp = dhd_filp_open(pktlogdump_path, file_mode, 0664); + if (IS_ERR(w_pcap_fp) || (w_pcap_fp == NULL)) { DHD_ERROR(("%s: Couldn't open file '%s' err %ld\n", __FUNCTION__, pktlogdump_path, PTR_ERR(w_pcap_fp))); ret = BCME_ERROR; @@ -1219,14 +1219,14 @@ dhd_pktlog_dump_write_file(dhd_pub_t *dhdp) } /* Sync file from filesystem to physical media */ - ret = vfs_fsync(w_pcap_fp, 0); + ret = dhd_vfs_fsync(w_pcap_fp, 0); if (ret < 0) { DHD_ERROR(("%s(): sync pcap file error, err = %d\n", __FUNCTION__, ret)); goto fail; } fail: if (!IS_ERR(w_pcap_fp)) { - filp_close(w_pcap_fp, NULL); + dhd_filp_close(w_pcap_fp, NULL); } set_fs(old_fs); diff --git a/bcmdhd.101.10.361.x/dhd_plat.h b/bcmdhd.101.10.361.x/dhd_plat.h index 8c07b5b..d9cd04f 100755 --- a/bcmdhd.101.10.361.x/dhd_plat.h +++ b/bcmdhd.101.10.361.x/dhd_plat.h @@ -38,7 +38,7 @@ struct wifi_platform_data { #ifdef DHD_COREDUMP int (*set_coredump)(const char *buf, int buf_len, const char *info); #endif /* DHD_COREDUMP */ -#ifdef BCMDHD_MDRIVER +#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) void *(*mem_prealloc)(uint bus_type, int index, int section, unsigned long size); #else void *(*mem_prealloc)(int section, unsigned long size); diff --git a/bcmdhd.101.10.361.x/dhd_proto.h b/bcmdhd.101.10.361.x/dhd_proto.h index 7f0b121..b7640ee 100755 --- a/bcmdhd.101.10.361.x/dhd_proto.h +++ b/bcmdhd.101.10.361.x/dhd_proto.h @@ -121,6 +121,10 @@ extern uint dhd_prot_hdrlen(dhd_pub_t *, void *txp); /* Remove any protocol-specific data header. */ extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); +#ifdef DHD_LOSSLESS_ROAMING +extern int dhd_update_sdio_data_prio_map(dhd_pub_t *dhdp); +#endif // DHD_LOSSLESS_ROAMING + /* Use protocol to issue ioctl to dongle */ extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); diff --git a/bcmdhd.101.10.361.x/dhd_sdio.c b/bcmdhd.101.10.361.x/dhd_sdio.c index 6fdb0e9..5de437e 100755 --- a/bcmdhd.101.10.361.x/dhd_sdio.c +++ b/bcmdhd.101.10.361.x/dhd_sdio.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #ifdef DHD_PKTDUMP_TOFW #include @@ -1198,14 +1199,14 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) int err = 0; int try_cnt = 0, try_max = CUSTOM_MAX_KSO_ATTEMPTS; struct dhd_conf *conf = bus->dhd->conf; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) && !defined(ANDROID13_KERNEL515_BKPORT) wifi_adapter_info_t *adapter = NULL; uint32 bus_type = -1, bus_num = -1, slot_num = -1; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) */ KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) && !defined(ANDROID13_KERNEL515_BKPORT) dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num); adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); sdio_retune_crc_disable(adapter->sdio_func); @@ -1334,7 +1335,7 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) #endif /* !defined(NDIS) */ exit: -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) && !defined(ANDROID13_KERNEL515_BKPORT) if (on) sdio_retune_release(adapter->sdio_func); sdio_retune_crc_enable(adapter->sdio_func); @@ -1968,6 +1969,9 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) #if defined(BCMSDIOH_STD) uint32 sd3_tuning_disable = FALSE; #endif /* BCMSDIOH_STD */ +#if defined(WL_EXT_IAPSTA) && defined(DHD_LOSSLESS_ROAMING) + int state; +#endif /* WL_EXT_IAPSTA && DHD_LOSSLESS_ROAMING */ DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n", (sleep ? "SLEEP" : "WAKE"), @@ -1990,6 +1994,13 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) if (bus->dpc_sched || bus->rxskip || pktq_n_pkts_tot(&bus->txq)) #endif /* DHD_USE_IDLECOUNT */ return BCME_BUSY; +#if defined(WL_EXT_IAPSTA) && defined(DHD_LOSSLESS_ROAMING) + state = wl_ext_any_sta_handshaking(bus->dhd); + if (state) { + DHD_ERROR(("handshaking %d\n", state)); + return BCME_BUSY; + } +#endif /* WL_EXT_IAPSTA && DHD_LOSSLESS_ROAMING */ #ifdef BT_OVER_SDIO /* @@ -2718,7 +2729,7 @@ static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt) /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */ frame = (uint8*)PKTDATA(osh, pkt); - DHD_INFO(("%s PKTLEN before postprocess %d", + DHD_INFO(("%s PKTLEN before postprocess %d\n", __FUNCTION__, PKTLEN(osh, pkt))); /* PKTLEN still includes tail_padding, so exclude it. @@ -3857,6 +3868,57 @@ xfer_done: return bcmerror; } +#if defined(BCMSDIO_RXLIM_POST) || defined(BCMSDIO_TXSEQ_SYNC) +static void +dhdsdio_txseq_sync(dhd_bus_t *bus, sdpcm_shared_t *sh) +{ + struct dhd_conf *conf = bus->dhd->conf; + + if (sh->flags & SDPCM_SHARED_RXLIM_POST) { +#ifdef BCMSDIO_RXLIM_POST + if (conf->rxlim_en) { + if (sh->msgtrace_addr) { + bus->rxlim_en = TRUE; + bus->rxlim_addr = sh->msgtrace_addr; + DHD_INFO(("%s: RXLIM_POST enabled with rxlim_addr=0x%x\n", + __FUNCTION__, bus->rxlim_addr)); + } else { + DHD_INFO(("%s: RXLIM_POST not enabled in fw\n", __FUNCTION__)); + } + } else +#endif /* BCMSDIO_RXLIM_POST */ +#ifdef BCMSDIO_TXSEQ_SYNC + if (conf->txseq_sync) { + uint8 val = 0; + sh->txseq_sync_addr = ltoh32(sh->txseq_sync_addr); + DHD_INFO(("%s: TXSEQ_SYNC enabled\n", __FUNCTION__)); + if (0 == dhdsdio_membytes(bus, FALSE, sh->txseq_sync_addr, (uint8 *)&val, 1)) { + if (bus->tx_seq != val) { + DHD_INFO(("%s: Sync tx_seq from %d to %d\n", + __FUNCTION__, bus->tx_seq, val)); + bus->tx_seq = val; + bus->tx_max = bus->tx_seq + 4; + } + } + } else +#endif /* BCMSDIO_TXSEQ_SYNC */ + { + DHD_INFO(("%s: rxlim_en and txseq_sync not enabled in config.txt\n", __FUNCTION__)); + } + sh->flags &= ~SDPCM_SHARED_RXLIM_POST; + } + else { +#ifdef BCMSDIO_RXLIM_POST + bus->rxlim_en = 0; +#endif /* BCMSDIO_RXLIM_POST */ +#ifdef BCMSDIO_TXSEQ_SYNC + conf->txseq_sync = FALSE; +#endif /* BCMSDIO_TXSEQ_SYNC */ + DHD_INFO(("%s: TXSEQ_SYNC and RXLIM_POST not supported in fw\n", __FUNCTION__)); + } +} +#endif /* BCMSDIO_RXLIM_POST || BCMSDIO_TXSEQ_SYNC */ + static int dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) { @@ -3923,41 +3985,9 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) sh->console_addr = ltoh32(sh->console_addr); sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); -#ifdef BCMSDIO_RXLIM_POST - if (sh->flags & SDPCM_SHARED_RXLIM_POST) { - if (bus->dhd->conf->rxlim_en) - bus->rxlim_en = !!sh->msgtrace_addr; - bus->rxlim_addr = sh->msgtrace_addr; - DHD_INFO(("%s: rxlim_en=%d, rxlim enable=%d, rxlim_addr=%d\n", - __FUNCTION__, - bus->dhd->conf->rxlim_en, bus->rxlim_en, bus->rxlim_addr)); - sh->flags &= ~SDPCM_SHARED_RXLIM_POST; - } else { - bus->rxlim_en = 0; - DHD_INFO(("%s: FW has no rx limit post support\n", __FUNCTION__)); - } -#endif /* BCMSDIO_RXLIM_POST */ - -#ifdef BCMSDIO_TXSEQ_SYNC - if (bus->dhd->conf->txseq_sync) { - sh->txseq_sync_addr = ltoh32(sh->txseq_sync_addr); - if (sh->flags & SDPCM_SHARED_TXSEQ_SYNC) { - uint8 val = 0; - DHD_INFO(("%s: TXSEQ_SYNC enabled in fw\n", __FUNCTION__)); - if (0 == dhdsdio_membytes(bus, FALSE, sh->txseq_sync_addr, (uint8 *)&val, 1)) { - if (bus->tx_seq != val) { - DHD_INFO(("%s: Sync tx_seq from %d to %d\n", - __FUNCTION__, bus->tx_seq, val)); - bus->tx_seq = val; - bus->tx_max = bus->tx_seq + 4; - } - } - sh->flags &= ~SDPCM_SHARED_TXSEQ_SYNC; - } else { - bus->dhd->conf->txseq_sync = FALSE; - } - } -#endif /* BCMSDIO_TXSEQ_SYNC */ +#if defined(BCMSDIO_RXLIM_POST) || defined(BCMSDIO_TXSEQ_SYNC) + dhdsdio_txseq_sync(bus, sh); +#endif /* * XXX - Allow a sdpcm_shared_t version mismatch between dhd structure @@ -8019,7 +8049,11 @@ clkwait: } else if (bus->clkstate == CLK_PENDING) { /* Awaiting I_CHIPACTIVE; don't resched */ } else if (bus->intstatus || bus->ipend || - (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || + (!bus->fcstate && (pktq_mlen(&bus->txq, ((~bus->flowcontrol) +#ifdef DHD_LOSSLESS_ROAMING + & bus->dhd->dequeue_prec_map +#endif /* DHD_LOSSLESS_ROAMING */ + ))) && DATAOK(bus)) || PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ resched = TRUE; } @@ -8594,6 +8628,13 @@ int dhd_bus_get_oob_irq_num(dhd_pub_t *dhdp) return irq_num; } +#ifdef LINUX +struct device *dhd_bus_to_dev(struct dhd_bus *bus) +{ + return (struct device *)bcmsdh_get_dev(bus->sdh); +} +#endif /* LINUX */ + void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub) { #ifdef LINUX @@ -10042,6 +10083,7 @@ dhdsdio_suspend(void *context) /* resume all interface network queue. */ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); } + bus->dhd->hostsleep = 2; DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd); dhd_os_busbusy_wake(bus->dhd); DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); @@ -10073,6 +10115,7 @@ dhdsdio_resume(void *context) DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd); + bus->dhd->hostsleep = 0; bus->dhd->busstate = DHD_BUS_DATA; dhd_os_busbusy_wake(bus->dhd); /* resume all interface network queue. */ @@ -10213,6 +10256,144 @@ err: } #endif /* BCMEMBEDIMAGE */ +#ifdef DHD_LINUX_STD_FW_API +static int +dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) +{ + int bcmerror = -1; + int offset = 0; + int len; + uint8 *memblock = NULL, *memptr; +#ifdef CHECK_DOWNLOAD_FW + uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct +#endif + uint memblock_size = MEMBLOCK; +#ifdef DHD_DEBUG_DOWNLOADTIME + unsigned long initial_jiffies = 0; + uint firmware_sz = 0; +#endif + int offset_end = bus->ramsize; + const struct firmware *fw = NULL; + int buf_offset = 0, residual_len = 0; + + DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); + + /* XXX: Should succeed in opening image if it is actually given through registry + * entry or in module param. + */ + bcmerror = dhd_os_get_img_fwreq(&fw, bus->fw_path); + if (bcmerror < 0) { + DHD_ERROR(("dhd_os_get_img(Request Firmware API) error : %d\n", + bcmerror)); + goto err; + } + residual_len = fw->size; + + /* Update the dongle image download block size depending on the F1 block size */ +#ifndef NDIS + if (sd_f1_blocksize == 512) + memblock_size = MAX_MEMBLOCK; +#endif /* !NDIS */ + + memptr = memblock = MALLOC(bus->dhd->osh, memblock_size + DHD_SDALIGN); + if (memblock == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, + memblock_size)); + goto err; + } + if ((uint32)(uintptr)memblock % DHD_SDALIGN) + memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); + +#ifdef CHECK_DOWNLOAD_FW + if (bus->dhd->conf->fwchk) { + memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); + if (memptr_tmp == NULL) { + DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); + goto err; + } + } +#endif + +#ifdef DHD_DEBUG_DOWNLOADTIME + initial_jiffies = jiffies; +#endif + + /* Download image */ + while (residual_len) { + len = MIN(residual_len, memblock_size); + bcopy((uint8 *)fw->data + buf_offset, (uint8 *)memptr, len); + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (offset == 0) { + bus->resetinstr = *(((uint32*)memptr)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + offset_end += offset; + } + } + + bcmerror = dhdsdio_membytes(bus, TRUE, offset, (uint8 *)memptr, len); + if (bcmerror) { + DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, memblock_size, offset)); + goto err; + } + +#ifdef CHECK_DOWNLOAD_FW + if (bus->dhd->conf->fwchk) { + bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + if (memcmp(memptr_tmp, memptr, len)) { + DHD_ERROR(("%s: Downloaded image is corrupted at 0x%08x\n", __FUNCTION__, offset)); + bcmerror = BCME_ERROR; + goto err; + } else + DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__)); + } +#endif + + offset += memblock_size; +#ifdef DHD_DEBUG_DOWNLOADTIME + firmware_sz += len; +#endif + if (offset >= offset_end) { + DHD_ERROR(("%s: invalid address access to %x (offset end: %x)\n", + __FUNCTION__, offset, offset_end)); + bcmerror = BCME_ERROR; + goto err; + } + residual_len -= len; + buf_offset += len; + } + +#ifdef DHD_DEBUG_DOWNLOADTIME + DHD_ERROR(("Firmware download time for %u bytes: %u ms\n", + firmware_sz, jiffies_to_msecs(jiffies - initial_jiffies))); +#endif + +err: + if (memblock) + MFREE(bus->dhd->osh, memblock, memblock_size + DHD_SDALIGN); +#ifdef CHECK_DOWNLOAD_FW + if (bus->dhd->conf->fwchk) { + if (memptr_tmp) + MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN); + } +#endif + + if (fw) { + dhd_os_close_img_fwreq(fw); + } + + return bcmerror; +} +#else static int dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) { @@ -10253,6 +10434,9 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) memblock_size)); goto err; } + if ((uint32)(uintptr)memblock % DHD_SDALIGN) + memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); + #ifdef CHECK_DOWNLOAD_FW if (bus->dhd->conf->fwchk) { memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); @@ -10262,8 +10446,6 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) } } #endif - if ((uint32)(uintptr)memblock % DHD_SDALIGN) - memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); #ifdef DHD_DEBUG_DOWNLOADTIME initial_jiffies = jiffies; @@ -10345,6 +10527,7 @@ err: return bcmerror; } +#endif /* DHD_LINUX_STD_FW_API */ #ifdef DHD_UCODE_DOWNLOAD /* Currently supported only for the chips in which ucode RAM is AXI addressable */ @@ -10480,8 +10663,7 @@ static int dhdsdio_download_nvram(struct dhd_bus *bus) { int bcmerror = -1; - uint len; - void * image = NULL; + uint len, memblock_len = 0; char * memblock = NULL; char *bufp; char *pnv_path; @@ -10491,24 +10673,21 @@ dhdsdio_download_nvram(struct dhd_bus *bus) nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); - /* For Get nvram from UEFI */ - if (nvram_file_exists) { - image = dhd_os_open_image1(bus->dhd, pnv_path); - if (image == NULL) { - printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path); - goto err; - } - } + len = MAX_NVRAMBUF_SIZE; + if (nvram_file_exists) + bcmerror = dhd_get_download_buffer(bus->dhd, pnv_path, NVRAM, &memblock, + (int *)&len); + else + bcmerror = dhd_get_download_buffer(bus->dhd, NULL, NVRAM, &memblock, (int *)&len); - memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); - if (memblock == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", - __FUNCTION__, MAX_NVRAMBUF_SIZE)); + if (bcmerror != BCME_OK) goto err; - } - /* For Get nvram from image or UEFI (when image == NULL ) */ - len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); +#ifdef DHD_LINUX_STD_FW_API + memblock_len = len; +#else + memblock_len = MAX_NVRAMBUF_SIZE; +#endif /* DHD_LINUX_STD_FW_API */ if (len > 0 && len < MAX_NVRAMBUF_SIZE) { bufp = (char *)memblock; @@ -10533,10 +10712,7 @@ dhdsdio_download_nvram(struct dhd_bus *bus) err: if (memblock) - MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); - - if (image) - dhd_os_close_image1(bus->dhd, image); + dhd_free_download_buffer(bus->dhd, memblock, memblock_len); return bcmerror; } diff --git a/bcmdhd.101.10.361.x/dhd_static_buf.c b/bcmdhd.101.10.361.x/dhd_static_buf.c index 4ff7e04..699b7c4 100755 --- a/bcmdhd.101.10.361.x/dhd_static_buf.c +++ b/bcmdhd.101.10.361.x/dhd_static_buf.c @@ -1,8 +1,22 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* - * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * drivers/amlogic/wifi/dhd_static_buf.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * */ +#define pr_fmt(fmt) "Wifi: %s: " fmt, __func__ + #include #include #include @@ -10,10 +24,10 @@ #include #include #include -#include +#include #include -#define DHD_STATIC_VERSION_STR "101.10.361.16 (wlan=r892223-20220401-1)" +#define DHD_STATIC_VERSION_STR "101.10.361.18 (wlan=r892223-20220519-1)" #define STATIC_ERROR_LEVEL (1 << 0) #define STATIC_TRACE_LEVEL (1 << 1) #define STATIC_MSG_LEVEL (1 << 0) @@ -179,21 +193,21 @@ void *wlan_static_dhd_event_ring_buf[MAX_NUM_ADAPTERS] = {NULL}; void *wlan_static_nan_event_ring_buf[MAX_NUM_ADAPTERS] = {NULL}; #if defined(BCMDHD_SDIO) || defined(BCMDHD_PCIE) -static struct sk_buff *wlan_static_skb[MAX_NUM_ADAPTERS][WLAN_SKB_BUF_NUM]; +static struct sk_buff *wlan_static_skb[MAX_NUM_ADAPTERS][WLAN_SKB_BUF_NUM] = {NULL}; #endif /* BCMDHD_SDIO | BCMDHD_PCIE */ void * bcmdhd_mem_prealloc( -#ifdef BCMDHD_MDRIVER +#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) uint bus_type, int index, #endif int section, unsigned long size) { -#ifndef BCMDHD_MDRIVER +#if !defined(BCMDHD_MDRIVER) || defined(DHD_STATIC_IN_DRIVER) int index = 0; #endif -#ifdef BCMDHD_MDRIVER +#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER) DHD_STATIC_MSG("bus_type %d, index %d, sectoin %d, size %ld\n", bus_type, index, section, size); #else @@ -348,7 +362,9 @@ bcmdhd_mem_prealloc( return NULL; } +#ifndef DHD_STATIC_IN_DRIVER EXPORT_SYMBOL(bcmdhd_mem_prealloc); +#endif static void dhd_deinit_wlan_mem(int index) @@ -612,9 +628,9 @@ err_mem_alloc: #ifdef DHD_STATIC_IN_DRIVER int #else -static int __init +int #endif -bcmdhd_init_wlan_mem(unsigned int all_buf)) +bcmdhd_init_wlan_mem(unsigned int all_buf) { int i, ret = 0; @@ -631,7 +647,7 @@ bcmdhd_init_wlan_mem(unsigned int all_buf)) dhd_deinit_wlan_mem(i); } - return 0; + return ret; } #ifdef DHD_STATIC_IN_DRIVER diff --git a/bcmdhd.101.10.361.x/dhd_wlfc.c b/bcmdhd.101.10.361.x/dhd_wlfc.c index 11283aa..0256ff6 100755 --- a/bcmdhd.101.10.361.x/dhd_wlfc.c +++ b/bcmdhd.101.10.361.x/dhd_wlfc.c @@ -1059,6 +1059,9 @@ _dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint dhdp = (dhd_pub_t *)ctx->dhdp; ASSERT(dhdp); + if (if_id >= WLFC_MAX_IFNUM) + return; + if (dhdp->skip_fc && dhdp->skip_fc((void *)dhdp, if_id)) return; diff --git a/bcmdhd.101.10.361.x/include/bcmdefs.h b/bcmdhd.101.10.361.x/include/bcmdefs.h index 58e1ca3..e8b14c4 100755 --- a/bcmdhd.101.10.361.x/include/bcmdefs.h +++ b/bcmdhd.101.10.361.x/include/bcmdefs.h @@ -24,6 +24,10 @@ #ifndef _bcmdefs_h_ #define _bcmdefs_h_ +#ifndef BCM_FLEX_ARRAY +#define BCM_FLEX_ARRAY (1) +#endif /* BCM_FLEX_ARRAY */ + /* * One doesn't need to include this file explicitly, gets included automatically if * typedefs.h is included. diff --git a/bcmdhd.101.10.361.x/include/bcmevent.h b/bcmdhd.101.10.361.x/include/bcmevent.h index e7876c7..a2fbbd6 100755 --- a/bcmdhd.101.10.361.x/include/bcmevent.h +++ b/bcmdhd.101.10.361.x/include/bcmevent.h @@ -313,11 +313,10 @@ typedef union bcm_event_msg_u { #define WLC_E_AP_BCN_DRIFT 192 /* Beacon Drift event */ #define WLC_E_PFN_SCAN_ALLGONE_EXT 193 /* last found PFN network gets lost. */ #define WLC_E_AUTH_START 194 /* notify upper layer to start auth */ -#define WLC_E_TWT_TEARDOWN 195 /* TWT Teardown Complete Event */ -#define WLC_E_TWT_INFO_FRM 196 /* TWT Info Event Notification */ -#define WLC_E_LAST 197 /* highest val + 1 for range checking */ -#if (WLC_E_LAST > 197) -#error "WLC_E_LAST: Invalid value for last event; must be <= 197." +#define WLC_E_TWT 195 /* TWT event */ +#define WLC_E_LAST 196 /* highest val + 1 for range checking */ +#if (WLC_E_LAST > 196) +#error "WLC_E_LAST: Invalid value for last event; must be <= 196." #endif /* WLC_E_LAST */ /* define an API for getting the string name of an event */ @@ -1229,6 +1228,35 @@ typedef struct { uint8 data[]; /* type specific data; could be empty */ } wl_event_fbt_t; +/* TWT Setup Completion is designed to notify the user of TWT Setup process + * status. When 'status' field is value of BCME_OK, the user must check the + * 'setup_cmd' field value in 'wl_twt_sdesc_t' structure that at the end of + * the event data to see the response from the TWT Responding STA; when + * 'status' field is value of BCME_ERROR or non BCME_OK, user must not use + * anything from 'wl_twt_sdesc_t' structure as it is the TWT Requesting STA's + * own TWT parameter. + */ + +#define WL_TWT_EVENT_HDR_LEN (SIZE_OF(wl_twt_event_t, version) + SIZE_OF(wl_twt_event_t, length)) +#define WL_TWT_EVENT_BASE_LEN sizeof(wl_twt_event_t) +typedef enum wl_twt_event_type { + WL_TWT_EVENT_SETUP = 1, + WL_TWT_EVENT_TEARDOWN = 2, + WL_TWT_EVENT_INFOFRM = 3, + WL_TWT_EVENT_NOTIFY = 4 +} wl_twt_event_type_t; + +#define WL_TWT_EVENT_VER 0u + +/* WLC_E_TWT event Main-event */ +typedef struct wl_twt_event { + uint16 version; + uint16 length; /* the byte count of fields from 'event_type' onwards */ + uint8 event_type; /* See sub event types in wl_twt_event_type_t */ + uint8 PAD[3]; + uint8 event_info[]; +} wl_twt_event_t; + /* TWT Setup Completion is designed to notify the user of TWT Setup process * status. When 'status' field is value of BCME_OK, the user must check the * 'setup_cmd' field value in 'wl_twt_sdesc_t' structure that at the end of @@ -1242,12 +1270,13 @@ typedef struct { /* TWT Setup Reason code */ typedef enum wl_twt_setup_rc { - WL_TWT_SETUP_RC_ACCEPT = 0, /* TWT Setup Accepted */ - WL_TWT_SETUP_RC_REJECT = 1, /* TWT Setup Rejected */ - WL_TWT_SETUP_RC_TIMEOUT = 2, /* TWT Setup Time-out */ - WL_TWT_SETUP_RC_IE = 3, /* TWT Setup IE Validation failed */ - WL_TWT_SETUP_RC_PARAMS = 4, /* TWT Setup IE Params invalid */ - WL_TWT_SETUP_RC_ERROR = 5, /* Generic Error cases */ + WL_TWT_SETUP_RC_ACCEPT = 0u, /* TWT Setup Accepted */ + WL_TWT_SETUP_RC_REJECT = 1u, /* TWT Setup Rejected */ + WL_TWT_SETUP_RC_TIMEOUT = 2u, /* TWT Setup Time-out */ + WL_TWT_SETUP_RC_IE = 3u, /* TWT Setup IE Validation failed */ + WL_TWT_SETUP_RC_PARAMS = 4u, /* TWT Setup IE Params invalid */ + /* Any new reason code add before this */ + WL_TWT_SETUP_RC_ERROR = 255u, /* Generic Error cases */ } wl_twt_setup_rc_t; /* TWT Setup Completion event data */ @@ -1256,7 +1285,8 @@ typedef struct wl_twt_setup_cplt { uint16 length; /* the byte count of fields from 'dialog' onwards */ uint8 dialog; /* Setup frame dialog token */ uint8 reason_code; /* see WL_TWT_SETUP_RC_XXXX */ - uint8 pad[2]; + uint8 configID; /* TWT Configuration ID */ + uint8 pad[1]; int32 status; /* wl_twt_sdesc_t desc; - defined in wlioctl.h */ } wl_twt_setup_cplt_t; @@ -1265,24 +1295,25 @@ typedef struct wl_twt_setup_cplt { /* TWT teardown Reason code */ typedef enum wl_twt_td_rc { - WL_TWT_TD_RC_SUCCESS = 0, /* Teardown complete Successful */ - WL_TWT_TD_RC_HOST = 1, /* Teardown triggered by Host */ - WL_TWT_TD_RC_PEER = 2, /* Peer initiated teardown */ - WL_TWT_TD_RC_MCHAN = 3, /* Teardown due to MCHAN Active */ - WL_TWT_TD_RC_MCNX = 4, /* Teardown due to MultiConnection */ - WL_TWT_TD_RC_SETUP_FAIL = 5, /* Setup fail midway. Teardown all connections */ - WL_TWT_TD_RC_SCHED = 6, /* Teardown by TWT Scheduler */ - WL_TWT_TD_RC_CSA = 7, /* Teardown due to CSA */ - WL_TWT_TD_RC_BTCX = 8, /* Teardown due to BTCX */ - WL_TWT_TD_RC_ERROR = 9, /* Generic Error cases */ + WL_TWT_TD_RC_HOST = 0u, /* Teardown triggered by Host */ + WL_TWT_TD_RC_PEER = 1u, /* Peer initiated teardown */ + WL_TWT_TD_RC_MCHAN = 2u, /* Teardown due to MCHAN Active */ + WL_TWT_TD_RC_MCNX = 3u, /* Teardown due to MultiConnection */ + WL_TWT_TD_RC_CSA = 4u, /* Teardown due to CSA */ + WL_TWT_TD_RC_BTCX = 5u, /* Teardown due to BTCX */ + WL_TWT_TD_RC_SETUP_FAIL = 6u, /* Setup fail midway. Teardown all connections */ + WL_TWT_TD_RC_SCHED = 7u, /* Teardown by TWT Scheduler */ + /* Any new reason code add before this */ + WL_TWT_TD_RC_ERROR = 255u, /* Generic Error cases */ } wl_twt_td_rc_t; /* TWT Teardown complete event data */ typedef struct wl_twt_teardown_cplt { uint16 version; - uint16 length; /* the byte count of fields from 'reason_code' onwards */ + uint16 length; /* the byte count of fields from 'reason_code' onwards */ uint8 reason_code; /* WL_TWT_TD_RC_XXXX */ - uint8 pad[3]; + uint8 configID; /* TWT Configuration ID */ + uint8 pad[2]; int32 status; /* wl_twt_teardesc_t; - defined in wlioctl.h */ } wl_twt_teardown_cplt_t; @@ -1291,21 +1322,39 @@ typedef struct wl_twt_teardown_cplt { /* TWT Info Reason code */ typedef enum wl_twt_info_rc { - WL_TWT_INFO_RC_HOST = 0, /* Host initiated Info complete */ - WL_TWT_INFO_RC_PEER = 1, /* Peer initiated TWT Info */ - WL_TWT_INFO_RC_ERROR = 2, /* generic error conditions */ + WL_TWT_INFO_RC_HOST = 0u, /* Host initiated Info complete */ + WL_TWT_INFO_RC_PEER = 1u, /* Peer initiated TWT Info */ + /* Any new reason code add before this */ + WL_TWT_INFO_RC_ERROR = 255u, /* generic error conditions */ } wl_twt_info_rc_t; /* TWT Info complete event data */ typedef struct wl_twt_info_cplt { uint16 version; uint16 length; /* the byte count of fields from 'reason_code' onwards */ - uint8 reason_code; /* WL_TWT_INFO_RC_XXXX */ - uint8 pad[3]; + uint8 reason_code; /* WL_TWT_INFO_RC_XXXX */ + uint8 configID; /* TWT Configuration ID */ + uint8 pad[2]; int32 status; /* wl_twt_infodesc_t; - defined in wlioctl.h */ } wl_twt_info_cplt_t; +#define WL_TWT_NOTIFY_VER 0u +#define WL_TWT_NOTIFY_LEN sizeof(wl_twt_notify_t) +#define WL_TWT_NOTIFY_HDR_LEN (SIZE_OF(wl_twt_notify_t, version) + SIZE_OF(wl_twt_notify_t, length)) + +typedef enum wl_twt_notification { + WL_TWT_NOTIF_ALLOW_TWT = 1, /* Dongle indication of allowing TWT setup */ +} wl_twt_notification_t; + +/* TWT notification event */ +typedef struct wl_twt_notify { + uint16 version; + uint16 length; /* the byte count of fields from 'reason_code' onwards */ + uint8 notification; + uint8 PAD[3]; +} wl_twt_notify_t; + #define WL_INVALID_IE_EVENT_VERSION 0 /* Invalid IE Event data */ diff --git a/bcmdhd.101.10.361.x/include/bcmsdh.h b/bcmdhd.101.10.361.x/include/bcmsdh.h index 81c3438..3ed679b 100755 --- a/bcmdhd.101.10.361.x/include/bcmsdh.h +++ b/bcmdhd.101.10.361.x/include/bcmsdh.h @@ -256,6 +256,7 @@ extern void bcmsdh_oob_intr_unregister(bcmsdh_info_t *sdh); extern void bcmsdh_oob_intr_set(bcmsdh_info_t *sdh, bool enable); extern int bcmsdh_get_oob_intr_num(bcmsdh_info_t *bcmsdh); #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ +extern void *bcmsdh_get_dev(bcmsdh_info_t *sdh); extern void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *sdh); extern void bcmsdh_dev_relax(bcmsdh_info_t *sdh); extern bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *sdh); diff --git a/bcmdhd.101.10.361.x/include/bcmsdh_sdmmc.h b/bcmdhd.101.10.361.x/include/bcmsdh_sdmmc.h index d9a67e0..c204ac5 100755 --- a/bcmdhd.101.10.361.x/include/bcmsdh_sdmmc.h +++ b/bcmdhd.101.10.361.x/include/bcmsdh_sdmmc.h @@ -24,7 +24,6 @@ #ifndef __BCMSDH_SDMMC_H__ #define __BCMSDH_SDMMC_H__ -#ifdef BCMDBG #define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) #define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0) #define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0) @@ -32,15 +31,6 @@ #define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0) #define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0) #define sd_cost(x) do { if (sd_msglevel & SDH_COST_VAL) printf x; } while (0) -#else -#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) -#define sd_trace(x) -#define sd_info(x) -#define sd_debug(x) -#define sd_data(x) -#define sd_ctrl(x) -#define sd_cost(x) do { if (sd_msglevel & SDH_COST_VAL) printf x; } while (0) -#endif #define sd_sync_dma(sd, read, nbytes) #define sd_init_dma(sd) @@ -95,6 +85,9 @@ struct sdioh_info { struct sdio_func *func[SDIOD_MAX_IOFUNCS]; uint sd_clk_rate; uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ +#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF) + uint8 *copy_buf; +#endif #ifdef PKT_STATICS uint32 sdio_spent_time_us; #endif diff --git a/bcmdhd.101.10.361.x/include/bcmwifi_channels.h b/bcmdhd.101.10.361.x/include/bcmwifi_channels.h index d3744de..2b41723 100755 --- a/bcmdhd.101.10.361.x/include/bcmwifi_channels.h +++ b/bcmdhd.101.10.361.x/include/bcmwifi_channels.h @@ -356,7 +356,7 @@ uint wf_chspec_first_20_sb(chanspec_t chspec); ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -#ifdef WL_BAND6G +#ifdef WL_6G_BAND #define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS2G(chspec) ? WLC_BAND_2G : CHSPEC_IS5G(chspec) ? \ WLC_BAND_5G : WLC_BAND_6G) #else diff --git a/bcmdhd.101.10.361.x/include/dbus.h b/bcmdhd.101.10.361.x/include/dbus.h index 7761dff..f6c878b 100755 --- a/bcmdhd.101.10.361.x/include/dbus.h +++ b/bcmdhd.101.10.361.x/include/dbus.h @@ -68,6 +68,10 @@ enum { DBUS_ERR_RXZLP }; +#define BCM_OTP_SIZE_43236 84 /* number of 16 bit values */ +#define BCM_OTP_SW_RGN_43236 24 /* start offset of SW config region */ +#define BCM_OTP_ADDR_43236 0x18000800 /* address of otp base */ + #define ERR_CBMASK_TXFAIL 0x00000001 #define ERR_CBMASK_RXFAIL 0x00000002 #define ERR_CBMASK_ALL 0xFFFFFFFF @@ -316,9 +320,9 @@ typedef struct dbus_pub { * For NDIS60, param2 is WdfDevice * Under Linux, param1 and param2 are NULL; */ -extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, - void *param1, void *param2); -extern int dbus_deregister(void); +//extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, +// void *param1, void *param2); +//extern int dbus_deregister(void); //extern int dbus_download_firmware(dbus_pub_t *pub); //extern int dbus_up(struct dhd_bus *pub); @@ -327,13 +331,13 @@ extern int dbus_down(dbus_pub_t *pub); extern int dbus_shutdown(dbus_pub_t *pub); extern void dbus_flowctrl_rx(dbus_pub_t *pub, bool on); -extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf); +//extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf); extern int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info); -extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info); +//extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info); //extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len); //extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len); -extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx); -extern int dbus_poll_intr(dbus_pub_t *pub); +//extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx); +//extern int dbus_poll_intr(dbus_pub_t *pub); extern int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats); extern int dbus_get_device_speed(dbus_pub_t *pub); extern int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config); @@ -407,6 +411,18 @@ typedef struct dbus_intf_callbacks { void (*rxerr_indicate)(void *cbarg, bool on); } dbus_intf_callbacks_t; +/* callback functions */ +typedef struct { + /* probe the device */ + void *(*probe)(uint16 bus, uint16 slot, uint32 hdrlen); + /* remove the device */ + void (*remove)(void *context); + /* can we suspend now */ + int (*suspend)(void *context); + /* resume from suspend */ + int (*resume)(void *context); +} dbus_driver_t; + /* * Porting: To support new bus, port these functions below */ @@ -415,8 +431,7 @@ typedef struct dbus_intf_callbacks { * Bus specific Interface * Implemented by dbus_usb.c/dbus_sdio.c */ -extern int dbus_bus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, - dbus_intf_t **intf, void *param1, void *param2); +extern int dbus_bus_register(dbus_driver_t *driver, dbus_intf_t **intf); extern int dbus_bus_deregister(void); extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp); @@ -424,8 +439,7 @@ extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp); * Bus-specific and OS-specific Interface * Implemented by dbus_usb_[linux/ndis].c/dbus_sdio_[linux/ndis].c */ -extern int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, - void *prarg, dbus_intf_t **intf, void *param1, void *param2); +extern int dbus_bus_osl_register(dbus_driver_t *driver, dbus_intf_t **intf); extern int dbus_bus_osl_deregister(void); /* @@ -439,7 +453,7 @@ extern int dbus_bus_osl_hw_deregister(void); extern uint usbdev_bulkin_eps(void); #if defined(BCM_REQUEST_FW) extern void *dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, - uint16 boardtype, uint16 boardrev); + uint16 boardtype, uint16 boardrev, char *path); extern void dbus_release_fw_nvfile(void *firmware); #endif /* #if defined(BCM_REQUEST_FW) */ @@ -624,4 +638,7 @@ void optimize_submit_rx_request(const dbus_pub_t *pub, int epn, struct ehci_qtd #endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */ void dbus_flowctrl_tx(void *dbi, bool on); +#ifdef LINUX +struct device * dbus_get_dev(void); +#endif /* LINUX */ #endif /* __DBUS_H__ */ diff --git a/bcmdhd.101.10.361.x/include/epivers.h b/bcmdhd.101.10.361.x/include/epivers.h index 2bd2901..dd72dc3 100755 --- a/bcmdhd.101.10.361.x/include/epivers.h +++ b/bcmdhd.101.10.361.x/include/epivers.h @@ -45,7 +45,7 @@ #elif (defined (BCMDBG_ASSERT) && !defined (BCMDBG_ASSERT_DISABLED)) #define EPI_VERSION_STR "101.10.361 (wlan=r892223 ASSRT)" #else -#define EPI_VERSION_STR "101.10.361.17 (wlan=r892223-20220415-1)(20220705-1)" +#define EPI_VERSION_STR "101.10.361.24 (wlan=r892223-20220913-1)" #endif /* BCMINTERNAL */ #endif /* _epivers_h_ */ diff --git a/bcmdhd.101.10.361.x/include/linux_osl.h b/bcmdhd.101.10.361.x/include/linux_osl.h index a0a0937..f9bd6c8 100755 --- a/bcmdhd.101.10.361.x/include/linux_osl.h +++ b/bcmdhd.101.10.361.x/include/linux_osl.h @@ -28,10 +28,14 @@ #define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) /* Linux Kernel: File Operations: start */ -extern void * osl_os_open_image(char * filename); -extern int osl_os_get_image_block(char * buf, int len, void * image); -extern void osl_os_close_image(void * image); -extern int osl_os_image_size(void *image); +static INLINE void * osl_os_open_image(char * filename) + { return NULL; } +static INLINE void osl_os_close_image(void * image) + { return; } +static INLINE int osl_os_get_image_block(char * buf, int len, void * image) + { return 0; } +static INLINE int osl_os_image_size(void *image) + { return 0; } /* Linux Kernel: File Operations: end */ #ifdef BCMDRIVER diff --git a/bcmdhd.101.10.361.x/include/linuxver.h b/bcmdhd.101.10.361.x/include/linuxver.h index 44f32ce..e697349 100755 --- a/bcmdhd.101.10.361.x/include/linuxver.h +++ b/bcmdhd.101.10.361.x/include/linuxver.h @@ -941,5 +941,28 @@ int kernel_read_compat(struct file *file, loff_t offset, char *addr, unsigned lo #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) #define netdev_tx_t int #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) +#define complete_and_exit(a, b) kthread_complete_and_exit(a, b) +#else +#define dev_addr_set(net, addr) memcpy(net->dev_addr, addr, ETHER_ADDR_LEN) +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(5, 17, 0) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) +#define netif_rx_ni(skb) netif_rx(skb) +#define pci_free_consistent(a, b, c, d) dma_free_coherent(&((struct pci_dev *)a)->dev, b, c, d) +#define pci_map_single(a, b, c, d) dma_map_single(&((struct pci_dev *)a)->dev, b, c, d) +#define pci_unmap_single(a, b, c, d) dma_unmap_single(&((struct pci_dev *)a)->dev, b, c, d) +#define pci_dma_mapping_error(a, b) dma_mapping_error(&((struct pci_dev *)a)->dev, b) +#ifndef PCI_DMA_TODEVICE +#define PCI_DMA_TODEVICE 1 +#define PCI_DMA_FROMDEVICE 2 +#endif +#endif + +#ifdef ANDROID_BKPORT +#if (ANDROID_VERSION >= 13) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 41)) +#define ANDROID13_KERNEL515_BKPORT +#define CFG80211_BKPORT_MLO +#endif /* ANDROID_VERSION >= 13 && KERNEL >= 5.15.41 */ +#endif /* ANDROID_BKPORT */ #endif /* _linuxver_h_ */ diff --git a/bcmdhd.101.10.361.x/include/wlioctl.h b/bcmdhd.101.10.361.x/include/wlioctl.h index 97f0148..72c9d9f 100755 --- a/bcmdhd.101.10.361.x/include/wlioctl.h +++ b/bcmdhd.101.10.361.x/include/wlioctl.h @@ -713,7 +713,7 @@ typedef struct wl_extdscan_params { #define WL_SCAN_PARAMS_SSID_MAX 10 -struct wl_scan_params { +typedef struct wl_scan_params_v1 { wlc_ssid_t ssid; /**< default: {0, ""} */ struct ether_addr bssid; /**< default: bcast */ int8 bss_type; /**< default: any, @@ -744,8 +744,13 @@ struct wl_scan_params { * parameter portion is assumed, otherwise ssid in * the fixed portion is ignored */ - uint16 channel_list[1]; /**< list of chanspecs */ -}; + uint16 channel_list[BCM_FLEX_ARRAY]; +} wl_scan_params_v1_t; + +/** size of wl_scan_params_v1 not including variable length array */ +#define WL_SCAN_PARAMS_V1_FIXED_SIZE (OFFSETOF(wl_scan_params_v1_t, channel_list)) +#define WL_MAX_ROAMSCAN_V1_DATSZ \ + (WL_SCAN_PARAMS_V1_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16))) /* changes in wl_scan_params_v2 as comapred to wl_scan_params (v1) * unit8 scantype to uint32 @@ -857,16 +862,16 @@ typedef struct wl_scan_params_v3 { #define WL_MAX_ROAMSCAN_V3_DATSZ \ (WL_SCAN_PARAMS_V3_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16))) -#define ISCAN_REQ_VERSION 1 +#define ISCAN_REQ_VERSION_V1 1 #define ISCAN_REQ_VERSION_V2 2 /** incremental scan struct */ -struct wl_iscan_params { +typedef struct wl_iscan_params_v1 { uint32 version; uint16 action; uint16 scan_duration; - struct wl_scan_params params; -}; + struct wl_scan_params_v1 params; +} wl_iscan_params_v1_t; /** incremental scan struct */ typedef struct wl_iscan_params_v2 { @@ -895,8 +900,9 @@ typedef struct wl_scan_results_v109 { uint32 buflen; uint32 version; uint32 count; - wl_bss_info_v109_t bss_info[1]; + wl_bss_info_v109_t bss_info[BCM_FLEX_ARRAY]; } wl_scan_results_v109_t; +#define WL_SCAN_RESULTS_V109_FIXED_SIZE (OFFSETOF(wl_scan_results_v109_t, bss_info)) typedef struct wl_scan_results_v2 { uint32 buflen; @@ -920,15 +926,15 @@ typedef struct iscan_buf { } iscan_buf_t; #endif /* SIMPLE_ISCAN */ #define ESCAN_REQ_VERSION 1 +#define ESCAN_REQ_VERSION_V1 1 #define ESCAN_REQ_VERSION_V2 2 -/** event scan reduces amount of SOC memory needed to store scan results */ -struct wl_escan_params { +typedef struct wl_escan_params_v1 { uint32 version; uint16 action; uint16 sync_id; - struct wl_scan_params params; -}; + struct wl_scan_params_v1 params; +} wl_escan_params_v1_t; typedef struct wl_escan_params_v2 { uint32 version; @@ -944,7 +950,7 @@ typedef struct wl_escan_params_v3 { wl_scan_params_v3_t params; } wl_escan_params_v3_t; -#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) +#define WL_ESCAN_PARAMS_V1_FIXED_SIZE (OFFSETOF(wl_escan_params_v1_t, params) + sizeof(wlc_ssid_t)) #define WL_ESCAN_PARAMS_V2_FIXED_SIZE (OFFSETOF(wl_escan_params_v2_t, params) + sizeof(wlc_ssid_t)) #define WL_ESCAN_PARAMS_V3_FIXED_SIZE (OFFSETOF(wl_escan_params_v3_t, params) + sizeof(wlc_ssid_t)) /* New scan version is defined then change old version of scan to @@ -967,9 +973,9 @@ typedef struct wl_escan_params_v2 wl_escan_params_t; typedef struct wl_iscan_params_v2 wl_iscan_params_t; #define WL_SCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_scan_params_t, channel_list)) #else -typedef struct wl_scan_params wl_scan_params_t; -typedef struct wl_escan_params wl_escan_params_t; -typedef struct wl_iscan_params wl_iscan_params_t; +typedef struct wl_scan_params_v1 wl_scan_params_t; +typedef struct wl_escan_params_v1 wl_escan_params_t; +typedef struct wl_iscan_params_v1 wl_iscan_params_t; #define WL_SCAN_PARAMS_FIXED_SIZE 64 #endif /* WL_SCAN_PARAMS_V3 */ @@ -979,8 +985,9 @@ typedef struct wl_escan_result_v109 { uint32 version; uint16 sync_id; uint16 bss_count; - wl_bss_info_v109_t bss_info[1]; + wl_bss_info_v109_t bss_info[BCM_FLEX_ARRAY]; } wl_escan_result_v109_t; +#define WL_ESCAN_RESULTS_V109_FIXED_SIZE (OFFSETOF(wl_escan_result_v109_t, bss_info)) /** event scan reduces amount of SOC memory needed to store scan results */ typedef struct wl_escan_result_v2 { @@ -2306,6 +2313,7 @@ typedef struct sta_info_v7 { #define WL_STA_VER_4 4 #define WL_STA_VER_5 5 +#define WL_STA_VER_6 6u /* FIXME: the user/branch should make the selection! */ #define WL_STA_VER WL_STA_VER_4 @@ -6230,6 +6238,15 @@ typedef struct wl_icmp_ipv6_cfg { #define WL_ICMP_CFG_IPV6_LEN(count) (WL_ICMP_CFG_IPV6_FIXED_LEN + \ ((count) * sizeof(struct ipv6_addr))) +typedef struct wl_mkeep_alive_pkt_v1 { + uint16 version; /* Version for mkeep_alive */ + uint16 length; /* length of fixed parameters in the structure */ + uint32 period_msec; /* high bit on means immediate send */ + uint16 len_bytes; + uint8 keep_alive_id; /* 0 - 3 for N = 4 */ + uint8 data[BCM_FLEX_ARRAY]; +} wl_mkeep_alive_pkt_v1_t; + typedef struct wl_mkeep_alive_pkt { uint16 version; /* Version for mkeep_alive */ uint16 length; /* length of fixed parameters in the structure */ @@ -6239,6 +6256,7 @@ typedef struct wl_mkeep_alive_pkt { uint8 data[1]; } wl_mkeep_alive_pkt_t; +#define WL_MKEEP_ALIVE_VERSION_1 1u #define WL_MKEEP_ALIVE_VERSION 1 #define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) /* 1/2 second precision since idle time is a seconds counter anyway */ @@ -21227,6 +21245,13 @@ typedef struct wl_hwa_cnts_v1 { */ /* TWT Setup descriptor */ + +/* Any change to wl_twt_sdesc is not possible without affecting this ROMed structure + * in various current branches. Hence to use new updated structure wl_twt_sdesc_v1 + * typecast it to wl_twt_sdesc_t and define WL_TWT_SDESC_TYPEDEF_HAS_ALIAS + * in required branches + */ +#ifndef WL_TWT_SDESC_TYPEDEF_HAS_ALIAS typedef struct wl_twt_sdesc { /* Setup Command. */ uint8 setup_cmd; /* See TWT_SETUP_CMD_XXXX in 802.11ah.h */ @@ -21248,6 +21273,7 @@ typedef struct wl_twt_sdesc { /* deprecated - to be removed */ uint16 li; } wl_twt_sdesc_t; +#endif /* WL_TWT_SDESC_TYPEDEF_HAS_ALIAS */ #define WL_TWT_SETUP_DESC_VER 1u @@ -21283,7 +21309,9 @@ typedef struct wl_twt_cdesc { uint16 version; /* structure version */ uint16 length; /* data length (starting after this field) */ uint8 negotiation_type; /* Negotiation Type: See macros TWT_NEGO_TYPE_X */ - uint8 PAD[3]; + uint8 configID; /* TWT Configuration ID */ + uint8 flow_flags; /* Flow Flags Configuration. See WL_TWT_FLOW_FLAG_XXXX */ + uint8 PAD; uint32 wake_time_h; /* target wake time - BSS TSF (us) */ uint32 wake_time_l; uint32 wake_dur; /* target wake duration in unit of microseconds */ @@ -21293,6 +21321,7 @@ typedef struct wl_twt_cdesc { uint32 wake_dur_min; /* Min. wake duration allowed for TWT Setup */ uint32 wake_dur_max; /* Max. wake duration allowed for TWT Setup */ uint32 avg_pkt_num; /* Average Number of Packets per interval */ + uint32 avg_pkt_size; /* Average packet size for TWT SP */ } wl_twt_cdesc_t; /* Flow flags */ @@ -21316,6 +21345,14 @@ typedef struct wl_twt_cdesc { #define WL_TWT_INV_BCAST_ID 0xFFu #define WL_TWT_INV_FLOW_ID 0xFFu +#define WL_TWT_INV_CONFIG_ID 0xFFu +#define WL_TWT_ALL_TWT_CONFIG_ID 0u /* ConfigID 0 corresponds to All TWT */ + +#define WL_TWT_INV_WAKE_DUR 0xFFFFFFFFu +#define WL_TWT_INV_WAKE_INT 0xFFFFFFFFu +#define WL_TWT_INV_PKT_NUM 0xFFFFFFFFu +#define WL_TWT_INV_PKT_SIZE 0xFFFFFFFFu +#define WL_TWT_INV_WAKE_TIME 0xFFFFFFFFu /* auto flow_id */ #define WL_TWT_SETUP_FLOW_ID_AUTO 0xFFu @@ -21332,10 +21369,11 @@ typedef struct wl_twt_cdesc { #define WL_TWT_STATS_MAX_BTWT WL_TWT_MAX_BTWT #define WL_TWT_STATS_MAX_ITWT WL_TWT_MAX_ITWT +/* TWT States */ #define WL_TWT_INACTIVE 0u /* Resource is not allotted */ -#define WL_TWT_RESERVED 1u /* Resource is allotted but HEB is not yet programmed */ -#define WL_TWT_ACTIVE 2u /* Resource is allotted and HEB is programmed */ -#define WL_TWT_SUSPEND 3u /* Resource is suspended and HEB released */ +#define WL_TWT_ACTIVE 1u /* Resource is allotted and HEB is programmed */ +#define WL_TWT_SUSPEND 2u /* Resource is suspended and HEB released */ +#define WL_TWT_RESERVED 3u /* Resource is allotted but HEB is not yet programmed */ /* Wake type */ /* TODO: not yet finalized */ @@ -21356,7 +21394,13 @@ typedef struct wl_twt_setup { uint16 length; /* data length (starting after this field) */ struct ether_addr peer; /* Peer address - leave it all 0s' for AP */ uint8 pad[2]; +#ifndef WL_TWT_SDESC_TYPEDEF_HAS_ALIAS /* Use either legacy structure or + * the new versioned structure + */ wl_twt_sdesc_t desc; /* Setup Descriptor */ +#else + struct wl_twt_sdesc_v1 desc; +#endif /* WL_TWT_SDESC_TYPEDEF_HAS_ALIAS */ uint16 dialog; /* Deprecated - to be removed */ uint8 pad1[2]; } wl_twt_setup_t; @@ -21392,11 +21436,13 @@ typedef struct wl_twt_teardown { struct ether_addr peer; /* leave it all 0s' for AP */ wl_twt_teardesc_t teardesc; /* Teardown descriptor */ - /* deprecated - to be removed */ + /* deprecated - to be removed - Start here */ uint8 flow_flags; uint8 flow_id; uint8 bid; - uint8 pad; + /* deprecated - to be removed - End here */ + + uint8 configID; /* TWT Configuration ID */ } wl_twt_teardown_t; /* twt information descriptor */ @@ -21430,7 +21476,8 @@ typedef struct wl_twt_info { uint16 length; /* data length (starting after this field) */ /* peer address */ struct ether_addr peer; /* leave it all 0s' for AP */ - uint8 pad[2]; + uint8 configID; /* TWT Configuration ID */ + uint8 pad[1]; wl_twt_infodesc_t infodesc; /* information descriptor */ /* deprecated - to be removed */ wl_twt_idesc_t desc; @@ -21446,10 +21493,19 @@ typedef struct wl_twt_info { typedef struct wl_twt_status { uint8 state; /* TWT State */ uint8 heb_id; /* HEB ID */ - uint8 PAD[2]; + uint8 configID; /* TWT Configuration ID */ + uint8 PAD[1]; struct ether_addr peer; uint8 PAD[2]; - wl_twt_sdesc_t desc; /* TWT Descriptor */ + uint32 avg_pkt_num; /* Average Packet number per TWT SP Interval */ + uint32 avg_pkt_size; /* Average Packet size for TWT SP */ +#ifndef WL_TWT_SDESC_TYPEDEF_HAS_ALIAS /* Use either legacy structure or + * the new versioned structure + */ + wl_twt_sdesc_t desc; /* Setup Descriptor */ +#else + struct wl_twt_sdesc_v1 desc; +#endif /* WL_TWT_SDESC_TYPEDEF_HAS_ALIAS */ } wl_twt_status_t; /* wl twt status output */ @@ -21468,7 +21524,8 @@ typedef struct wl_twt_status_cmd_v1 { uint16 version; uint16 length; struct ether_addr peer; - uint8 PAD[2]; + uint8 configID; + uint8 PAD; } wl_twt_status_cmd_v1_t; #define WL_TWT_PEER_STATS_VERSION_1 1u @@ -21501,6 +21558,40 @@ typedef struct wl_twt_stats_v1 { wl_twt_peer_stats_v1_t peer_stats_list[]; } wl_twt_stats_v1_t; +#define WL_TWT_PEER_STATS_VERSION_2 2u +typedef struct wl_twt_peer_stats_v2 { + uint16 version; + uint16 length; + struct ether_addr peer; + uint8 id; /* TWT session ID */ + uint8 flow_flags; + uint8 configID; /* TWT Configuration ID */ + uint8 PAD[3]; + uint32 sp_seq; /* sequence number of the service period */ + uint32 tx_ucast_pkts; /* Number of unicast Tx packets in TWT SPs */ + uint32 tx_pkts_min; /* Minimum number of Tx packets in a TWT SP */ + uint32 tx_pkts_max; /* Maximum number of Tx packets in a TWT SP */ + uint32 tx_pkts_avg; /* Average number of Tx packets in each TWT SP */ + uint32 tx_failures; /* Tx packets failure count */ + uint32 rx_ucast_pkts; /* Number of unicast Rx packets in TWT SPs */ + uint32 rx_pkts_min; /* Minimum number of Rx packets in a TWT SP */ + uint32 rx_pkts_max; /* Maximum number of Rx packets in a TWT SP */ + uint32 rx_pkts_avg; /* Average number of Rx packets in each TWT SP */ + uint32 rx_pkts_retried; /* retried Rx packets count */ + uint32 tx_pkt_sz_avg; /* Average Tx packet size in TWT SPs */ + uint32 rx_pkt_sz_avg; /* Average Rx Packet size in TWT SPs */ + uint32 eosp_dur_avg; /* Average Wake duration in SPs ended due to EOSP */ + uint32 eosp_count; /* Count of TWT SPs ended due to EOSP */ +} wl_twt_peer_stats_v2_t; + +#define WL_TWT_STATS_VERSION_2 2u +typedef struct wl_twt_stats_v2 { + uint16 version; + uint16 length; + uint32 num_stats; /* number of peer stats in the peer_stats_list */ + wl_twt_peer_stats_v2_t peer_stats_list[]; +} wl_twt_stats_v2_t; + #define WL_TWT_STATS_CMD_VERSION_1 1 #define WL_TWT_STATS_CMD_FLAGS_RESET (1u << 0u) /* HE TWT stats command */ @@ -21508,7 +21599,8 @@ typedef struct wl_twt_stats_cmd_v1 { uint16 version; uint16 length; struct ether_addr peer; - uint8 PAD[2]; + uint8 configID; /* TWT Configuration ID */ + uint8 PAD; uint16 flags; /* see WL_TWT_STATS_CMD_FLAGS */ uint8 num_fid; uint8 num_bid; diff --git a/bcmdhd.101.10.361.x/linux_osl.c b/bcmdhd.101.10.361.x/linux_osl.c index 4e7607c..6af4812 100755 --- a/bcmdhd.101.10.361.x/linux_osl.c +++ b/bcmdhd.101.10.361.x/linux_osl.c @@ -281,14 +281,15 @@ osl_error(int bcmerror) /* Array bounds covered by ASSERT in osl_attach */ return linuxbcmerrormap[-bcmerror]; } -#ifdef SHARED_OSL_CMN -osl_t * -osl_attach(void *pdev, uint bustype, bool pkttag, void **osl_cmn) -{ -#else + osl_t * -osl_attach(void *pdev, uint bustype, bool pkttag) +osl_attach(void *pdev, uint bustype, bool pkttag +#ifdef SHARED_OSL_CMN + , void **osl_cmn +#endif /* SHARED_OSL_CMN */ +) { +#ifndef SHARED_OSL_CMN void **osl_cmn = NULL; #endif /* SHARED_OSL_CMN */ osl_t *osh; @@ -1734,71 +1735,6 @@ osl_rand(void) return rand; } -/* Linux Kernel: File Operations: start */ -void * -osl_os_open_image(char *filename) -{ - struct file *fp; - - fp = filp_open(filename, O_RDONLY, 0); - /* - * 2.6.11 (FC4) supports filp_open() but later revs don't? - * Alternative: - * fp = open_namei(AT_FDCWD, filename, O_RD, 0); - * ??? - */ - if (IS_ERR(fp)) { - printf("ERROR %ld: Unable to open file %s\n", PTR_ERR(fp), filename); - fp = NULL; - } - - return fp; -} - -int -osl_os_get_image_block(char *buf, int len, void *image) -{ - struct file *fp = (struct file *)image; - int rdlen; - - if (fp == NULL) { - return 0; - } - - rdlen = kernel_read_compat(fp, fp->f_pos, buf, len); - if (rdlen > 0) { - fp->f_pos += rdlen; - } - - return rdlen; -} - -void -osl_os_close_image(void *image) -{ - struct file *fp = (struct file *)image; - - if (fp != NULL) { - filp_close(fp, NULL); - } -} - -int -osl_os_image_size(void *image) -{ - int len = 0, curroffset; - - if (image) { - /* store the current offset */ - curroffset = generic_file_llseek(image, 0, 1); - /* goto end of file to get length */ - len = generic_file_llseek(image, 0, 2); - /* restore back the offset */ - generic_file_llseek(image, curroffset, 0); - } - return len; -} - /* Linux Kernel: File Operations: end */ #if defined(AXI_TIMEOUTS_NIC) @@ -1955,7 +1891,11 @@ osl_timer_del(osl_t *osh, osl_timer_t *t) int kernel_read_compat(struct file *file, loff_t offset, char *addr, unsigned long count) { +#ifdef DHD_SUPPORT_VFS_CALL return (int)kernel_read(file, addr, (size_t)count, &offset); +#else + return 0; +#endif /* DHD_SUPPORT_VFS_CALL */ } #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) */ diff --git a/bcmdhd.101.10.361.x/wl_android.c b/bcmdhd.101.10.361.x/wl_android.c index 7a60390..6fe9efb 100755 --- a/bcmdhd.101.10.361.x/wl_android.c +++ b/bcmdhd.101.10.361.x/wl_android.c @@ -88,8 +88,6 @@ #define WL_BSSIDX_MAX 16 #endif /* WL_STATIC_IF */ -uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL; - #define ANDROID_ERROR_MSG(x, args...) \ do { \ if (android_msg_level & ANDROID_ERROR_LEVEL) { \ @@ -728,8 +726,24 @@ static const wl_natoe_sub_cmd_t natoe_cmd_list[] = { #define CMD_TWT_SETUP "TWT_SETUP" #define CMD_TWT_TEARDOWN "TWT_TEARDOWN" #define CMD_TWT_INFO "TWT_INFO_FRM" -#define CMD_TWT_STATUS_QUERY "TWT_STATUS" -#define CMD_TWT_CAPABILITY "TWT_CAP" +#define CMD_TWT_STATUS_QUERY "GET_TWT_STATUS" +#define CMD_TWT_CAPABILITY "GET_TWT_CAP" +#define CMD_TWT_GET_STATS "GET_TWT_STATISTICS" +#define CMD_TWT_CLR_STATS "CLEAR_TWT_STATISTICS" +#define WL_TWT_CMD_INVAL 255 + +/* setup command name to value conversion */ +static struct { + const char *name; + uint8 val; +} setup_cmd_val[] = { + {"request", TWT_SETUP_CMD_REQUEST_TWT}, + {"suggest", TWT_SETUP_CMD_SUGGEST_TWT}, + {"demand", TWT_SETUP_CMD_DEMAND_TWT}, + {"accept", TWT_SETUP_CMD_ACCEPT_TWT}, + {"alternate", TWT_SETUP_CMD_ALTER_TWT}, + {"reject", TWT_SETUP_CMD_REJECT_TWT} +}; #endif /* WL_TWT */ /* drv command info structure */ @@ -896,7 +910,9 @@ static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev, char *command, int total_len); static int wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp, uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size); +#ifdef WES_SUPPORT static int wl_android_wbtext_enable(struct net_device *dev, int mode); +#endif // WES_SUPPORT #endif /* WBTEXT */ #ifdef WES_SUPPORT /* wl_roam.c */ @@ -1677,14 +1693,6 @@ wl_android_set_band(struct net_device *dev, char *command) #ifdef CUSTOMER_HW4_PRIVATE_CMD #ifdef ROAM_API -#ifdef WBTEXT -static bool wl_android_check_wbtext_support(struct net_device *dev) -{ - dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); - return dhdp->wbtext_support; -} -#endif /* WBTEXT */ - static bool wl_android_check_wbtext_policy(struct net_device *dev) { @@ -4290,6 +4298,13 @@ static int wl_android_wbtext(struct net_device *dev, char *command, int total_le return error; } +#ifdef WES_SUPPORT +static bool wl_android_check_wbtext_support(struct net_device *dev) +{ + dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); + return dhdp->wbtext_support; +} + static int wl_android_wbtext_enable(struct net_device *dev, int mode) { @@ -4308,6 +4323,7 @@ wl_android_wbtext_enable(struct net_device *dev, int mode) return error; } +#endif /* WES_SUPPORT */ static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev, char *command, int total_len) @@ -4901,10 +4917,10 @@ int wl_android_wifi_on(struct net_device *dev) dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY); #ifdef BCMSDIO ret = dhd_net_bus_resume(dev, 0); + if (ret) + goto retry_power; #endif /* BCMSDIO */ -#ifdef BCMPCIE ret = dhd_net_bus_devreset(dev, FALSE); -#endif /* BCMPCIE */ #ifdef WBRC if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ONCE) { ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n", @@ -4921,14 +4937,30 @@ int wl_android_wifi_on(struct net_device *dev) ret = BCME_ERROR; } #endif /* WBRC */ + if (ret) + goto retry_power; +#if defined(BCMSDIO) || defined(BCMDBUS) +#ifdef BCMSDIO + dhd_net_bus_resume(dev, 1); +#endif /* BCMSDIO */ + ret = dhd_dev_init_ioctl(dev); + if (ret < 0) { + goto retry_bus; + } +#endif /* BCMSDIO || BCMDBUS */ if (ret == 0) { break; } +#if defined(BCMSDIO) || defined(BCMDBUS) +retry_bus: +#ifdef BCMSDIO + dhd_net_bus_suspend(dev); +#endif /* BCMSDIO */ +#endif /* BCMSDIO || BCMDBUS */ +retry_power: ANDROID_ERROR(("failed to power up wifi chip, retry again (%d left) **\n\n", retry)); -#ifdef BCMPCIE dhd_net_bus_devreset(dev, TRUE); -#endif /* BCMPCIE */ dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); #ifdef WBRC /* Inform BT reset which will internally wait till BT reset is done */ @@ -4944,41 +4976,16 @@ int wl_android_wifi_on(struct net_device *dev) #endif /* BCM_DETECT_TURN_ON_FAILURE */ goto exit; } -#if defined(BCMSDIO) || defined(BCMDBUS) - ret = dhd_net_bus_devreset(dev, FALSE); - if (ret) - goto err; -#ifdef BCMSDIO - dhd_net_bus_resume(dev, 1); -#endif /* BCMSDIO */ -#endif /* BCMSDIO || BCMDBUS */ -#if defined(BCMSDIO) || defined(BCMDBUS) - if (!ret) { - if (dhd_dev_init_ioctl(dev) < 0) { - ret = -EFAULT; - goto err; - } - } -#endif /* BCMSDIO || BCMDBUS */ g_wifi_on = TRUE; } exit: - WL_MSG(dev->name, "Success\n"); - dhd_net_if_unlock(dev); - return ret; - -#if defined(BCMSDIO) || defined(BCMDBUS) -err: - dhd_net_bus_devreset(dev, TRUE); -#ifdef BCMSDIO - dhd_net_bus_suspend(dev); -#endif /* BCMSDIO */ - dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); - WL_MSG(dev->name, "Failed\n"); + if (ret) + WL_MSG(dev->name, "Failed %d\n", ret); + else + WL_MSG(dev->name, "Success\n"); dhd_net_if_unlock(dev); return ret; -#endif /* BCMSDIO || BCMDBUS */ } int wl_android_wifi_off(struct net_device *dev, bool on_failure) @@ -10275,8 +10282,17 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr) exit: #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS if (ret) { - /* Avoid incrementing priv_cmd_errors in case of unsupported feature */ - if (ret != BCME_UNSUPPORTED) { + /* Avoid incrementing priv_cmd_errors in case of unsupported feature + * or BUSY state specific to TWT commands + */ + if ( +#ifdef WL_TWT + ((ret != BCME_BUSY) && + ((strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) || + (strnicmp(command, CMD_TWT_TEARDOWN, strlen(CMD_TWT_TEARDOWN)) == 0) || + (strnicmp(command, CMD_TWT_INFO, strlen(CMD_TWT_INFO)) == 0))) || +#endif /* WL_TWT */ + (ret != BCME_UNSUPPORTED)) { wl_android_check_priv_cmd_errors(net); } } else { @@ -11156,18 +11172,31 @@ wl_android_enable_p2p_6g(struct net_device *dev, int enable) #ifdef WL_TWT +static uint8 +wl_twt_cmd2val(const char *name) +{ + uint i; + + for (i = 0; i < ARRAYSIZE(setup_cmd_val); i ++) { + if (strcmp(name, setup_cmd_val[i].name) == 0) { + return setup_cmd_val[i].val; + } + } + + return WL_TWT_CMD_INVAL; +} + static int wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) { - wl_twt_config_t val; - s32 bw; + wl_twt_setup_t val; + s32 bw = 0; char *token, *pos; u8 mybuf[WLC_IOCTL_SMLEN] = {0}; u8 resp_buf[WLC_IOCTL_SMLEN] = {0}; - u64 twt; uint8 *rem = mybuf; uint16 rem_len = sizeof(mybuf); - int32 val32; + uint8 tmp; WL_DBG_MEM(("Enter. cmd:%s\n", command)); @@ -11181,126 +11210,129 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) val.version = WL_TWT_SETUP_VER; val.length = sizeof(val.version) + sizeof(val.length); - /* Default values, Overide Below */ - val.desc.wake_time_h = 0xFFFFFFFF; - val.desc.wake_time_l = 0xFFFFFFFF; - val.desc.wake_int_min = 0xFFFFFFFF; - val.desc.wake_int_max = 0xFFFFFFFF; - val.desc.wake_dur_min = 0xFFFFFFFF; - val.desc.wake_dur_max = 0xFFFFFFFF; - val.desc.avg_pkt_num = 0xFFFFFFFF; + val.desc.bid = WL_TWT_INV_BCAST_ID; + val.desc.flow_id = WL_TWT_INV_FLOW_ID; + val.desc.btwt_persistence = WL_TWT_INFINITE_BTWT_PERSIST; + val.desc.wake_type = WL_TWT_TIME_TYPE_AUTO; pos = command + sizeof(CMD_TWT_SETUP); - /* negotiation_type */ + /* setup_cmd */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Mandatory param negotiation type not present\n")); + ANDROID_ERROR(("Mandaory param setup_cmd not present\n")); bw = -EINVAL; goto exit; } - val.desc.negotiation_type = htod32((u32)bcm_atoi(token)); - /* Wake Duration */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Mandatory param wake Duration not present\n")); - bw = -EINVAL; - goto exit; + val.desc.setup_cmd = wl_twt_cmd2val(token); + if (val.desc.setup_cmd == WL_TWT_CMD_INVAL) { + ANDROID_ERROR(("Unrecognized TWT Setup command '%s'\n", token)); } - val.desc.wake_dur = htod32((u32)bcm_atoi(token)); + ANDROID_INFO(("TWT_SETUP val.desc.setup_cmd %s\n", token)); - /* Wake interval */ + /* negotiation_type */ token = strsep((char**)&pos, " "); if (!token) { - ANDROID_ERROR(("Mandaory param Wake Interval not present\n")); + ANDROID_ERROR(("Mandatory param negotiation type not present\n")); bw = -EINVAL; goto exit; } - val.desc.wake_int = htod32((u32)bcm_atoi(token)); - - /* Wake Time parameter */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("No Wake Time parameter provided, using default\n")); - } else { - twt = (u64)bcm_atoi(token); - val32 = htod32((u32)(twt >> 32)); - if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) { - val.desc.wake_time_h = htod32((u32)(twt >> 32)); - val.desc.wake_time_l = htod32((u32)twt); - } - } + val.desc.negotiation_type = htod32((u32)bcm_atoi(token)); + ANDROID_INFO(("TWT_SETUP val.desc.negotiation_type %d\n", val.desc.negotiation_type)); - /* Minimum allowed Wake interval */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("No Minimum allowed Wake interval provided, using default\n")); - } else { - val32 = htod32((u32)bcm_atoi(token)); - if (val32 != -1) { - val.desc.wake_int_min = htod32((u32)bcm_atoi(token)); - } - } - - /* Max Allowed Wake interval */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Maximum allowed Wake interval not provided, using default\n")); - } else { - val32 = htod32((u32)bcm_atoi(token)); - if (val32 != -1) { - val.desc.wake_int_max = htod32((u32)bcm_atoi(token)); - } - } - - /* Minimum allowed Wake duration */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n")); - } else { - val32 = htod32((u32)bcm_atoi(token)); - if (val32 != -1) { - val.desc.wake_dur_min = htod32((u32)bcm_atoi(token)); - } - } - - /* Maximum allowed Wake duration */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n")); - } else { - val32 = htod32((u32)bcm_atoi(token)); - if (val32 != -1) { - val.desc.wake_dur_max = htod32((u32)bcm_atoi(token)); - } - } + if (pos != NULL) { + ANDROID_INFO(("TWT_SETUP string %s\n", pos)); + while ((token = bcmstrtok(&pos, " ", 0)) != NULL) { + ANDROID_INFO(("TWT_SETUP token is %s\n", token)); - /* Average number of packets */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Average number of packets not provided, using default\n")); - } else { - val32 = htod32((u32)bcm_atoi(token)); - if (val32 != -1) { - val.desc.avg_pkt_num = htod32((u32)bcm_atoi(token)); - } - } - - /* a peer_address */ - token = strsep((char**)&pos, " "); - if (!token) { - ANDROID_ERROR(("Average number of packets not provided, using default\n")); - } else { - /* get peer mac */ - if (!bcm_ether_atoe(token, &val.peer)) { - ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__)); - bw = BCME_ERROR; - goto exit; + if (!strnicmp(token, "u", 1)) { + val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNANNOUNCED; + } + else if (!strnicmp(token, "t", 1)) { + val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER; + } + else if (!strnicmp(token, "n", 1)) { + val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNSOLICITED; + } + else if (!strnicmp(token, "p", 1)) { + token++; + val.desc.btwt_persistence = (int)simple_strtol(token, NULL, 0); + ANDROID_INFO(("TWT_SETUP broadcast persistence %d\n", + val.desc.btwt_persistence)); + } + /* Wake Duration */ + else if (!strnicmp(token, "-d", 2)) { + if ((token = bcmstrtok(&pos, " ", 0)) != NULL) { + val.desc.wake_dur = (int)simple_strtol(token, NULL, 0); + ANDROID_INFO(("TWT_SETUP val.desc.wake_dur %d\n", + val.desc.wake_dur)); + } + } + /* Wake Interval */ + else if (!strnicmp(token, "-i", 2)) { + if ((token = bcmstrtok(&pos, " ", 0)) != NULL) { + val.desc.wake_int = (int)simple_strtol(token, NULL, 0); + ANDROID_INFO(("TWT_SETUP val.desc.wake_int %d\n", + val.desc.wake_int)); + } + } + /* flow id */ + else if (!strnicmp(token, "-f", 2)) { + if ((token = bcmstrtok(&pos, " ", 0)) != NULL) { + val.desc.flow_id = (int)simple_strtol(token, NULL, 0); + ANDROID_INFO(("TWT_SETUP val.desc.flow_id %d\n", + val.desc.flow_id)); + } + } + else if (!strnicmp(token, "-b", 2)) { + if ((token = bcmstrtok(&pos, " ", 0)) != NULL) { + val.desc.bid = (int)simple_strtol(token, NULL, 0); + ANDROID_INFO(("TWT_SETUP val.desc.bid %d\n", val.desc.bid)); + } + } + else if (!strnicmp(token, "-r", 2)) { + if ((token = bcmstrtok(&pos, " ", 0)) != NULL) { + tmp = (int)simple_strtol(token, NULL, 0); + if (tmp > TWT_BCAST_FRAME_RECOMM_3) { + bw = -EINVAL; + goto exit; + } + val.desc.bid = tmp; + ANDROID_INFO(("TWT_SETUP frame recommendation %d\n", + val.desc.frame_recomm)); + } + } + else if (!strnicmp(token, "-s", 2)) { + if ((token = bcmstrtok(&pos, " ", 0)) != NULL) { + val.desc.duty_cycle_min = + (int)simple_strtol(token, NULL, 0); + ANDROID_INFO(("TWT_SETUP duty_cycle_min %d\n", + val.desc.duty_cycle_min)); + } + } + else if (!strnicmp(token, "-v", 2)) { + if ((token = bcmstrtok(&pos, " ", 0)) != NULL) { + val.desc.wake_int_max = (int)simple_strtol(token, NULL, 0); + ANDROID_INFO(("TWT_SETUP wake_int_max %d\n", + val.desc.wake_int_max)); + } + } + /* a peer_address */ + else if (!strnicmp(token, "-a", 2)) { + if ((token = bcmstrtok(&pos, " ", 0)) != NULL) { + if (!bcm_ether_atoe(token, &val.peer)) { + ANDROID_ERROR(("%s : Malformed peer addr\n", + __FUNCTION__)); + bw = -EINVAL; + goto exit; + } + } + } } } - bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG, + bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_SETUP, sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); if (bw != BCME_OK) { goto exit; @@ -11309,7 +11341,7 @@ wl_android_twt_setup(struct net_device *ndev, char *command, int total_len) bw = wldev_iovar_setbuf(ndev, "twt", mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL); if (bw < 0) { - ANDROID_ERROR(("twt config set failed. ret:%d\n", bw)); + ANDROID_ERROR(("twt setup failed. ret:%d\n", bw)); } exit: return bw; @@ -11918,6 +11950,116 @@ wl_android_twt_teardown(struct net_device *ndev, char *command, int total_len) exit: return bw; } + +/* wl twt stats result display version 2 */ +static int +wl_android_twt_stats_display_v2(wl_twt_stats_v2_t *stats, char *command, int total_len) +{ + u32 i; + wl_twt_peer_stats_v2_t *peer_stats; + int rem_len = 0, bytes_written = 0; + + rem_len = total_len; + for (i = 0; i < stats->num_stats; i++) { + peer_stats = &stats->peer_stats_list[i]; + + bytes_written = scnprintf(command, rem_len, + "%u %u %u %u %u", + peer_stats->eosp_dur_avg, peer_stats->tx_pkts_avg, peer_stats->rx_pkts_avg, + peer_stats->tx_pkt_sz_avg, peer_stats->rx_pkt_sz_avg); + CHECK_SCNPRINTF_RET_VAL(bytes_written); + command += bytes_written; + rem_len -= bytes_written; + } + + if ((total_len - rem_len) > 0) { + return (total_len - rem_len); + } else { + return BCME_ERROR; + } +} + +static int +wl_android_twt_stats(struct net_device *ndev, char *command, int total_len) +{ + wl_twt_stats_cmd_v1_t query; + wl_twt_stats_v2_t stats_v2; + int ret = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + char *token, *pos; + uint16 buflen = 0, bufstart = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(ndev); + + WL_DBG_MEM(("Enter. cmd:%s\n", command)); + + bzero(&query, sizeof(query)); + query.version = WL_TWT_STATS_CMD_VERSION_1; + query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer); + + /* Default values, Overide Below */ + query.num_bid = 0xFF; + query.num_fid = 0xFF; + + if (!(strnicmp(command, CMD_TWT_CLR_STATS, strlen(CMD_TWT_CLR_STATS)))) { + query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET; + pos = command + sizeof(CMD_TWT_CLR_STATS); + } else if (!(strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)))) { + pos = command + sizeof(CMD_TWT_GET_STATS); + } + + /* Config ID */ + token = strsep((char**)&pos, " "); + if (!token) { + ANDROID_ERROR(("Mandatory param config ID not present\n")); + ret = -EINVAL; + goto exit; + } + query.configID = (u8)bcm_atoi(token); + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + goto exit; + } + + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS, + sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(ndev, "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + ANDROID_ERROR(("twt status failed with err=%d \n", ret)); + goto exit; + } + + (void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2)); + + if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) { + if (!(strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)))) { + ANDROID_ERROR(("stats query ver %d, \n", dtoh16(stats_v2.version))); + ret = wl_android_twt_stats_display_v2((wl_twt_stats_v2_t*)iovresp, + command, total_len); + } + } else { + ret = BCME_UNSUPPORTED; + ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version))); + goto exit; + } + +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + + return ret; +} #endif /* WL_TWT */ int @@ -12885,6 +13027,10 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) else if (strnicmp(command, CMD_TWT_CAPABILITY, strlen(CMD_TWT_CAPABILITY)) == 0) { bytes_written = wl_android_twt_cap(net, command, priv_cmd.total_len); } + else if ((strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)) == 0) || + (strnicmp(command, CMD_TWT_CLR_STATS, strlen(CMD_TWT_CLR_STATS)) == 0)) { + bytes_written = wl_android_twt_stats(net, command, priv_cmd.total_len); + } #endif /* WL_TWT */ #ifdef WL_P2P_6G else if (strnicmp(command, CMD_ENABLE_6G_P2P, strlen(CMD_ENABLE_6G_P2P)) == 0) { @@ -13372,7 +13518,7 @@ wl_cfg80211_static_if_open(struct net_device *net) if (cfg->static_ndev_state[static_ifidx] != NDEV_STATE_FW_IF_CREATED) { #ifdef CUSTOM_MULTI_MAC if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1)) - memcpy(net->dev_addr, hw_ether, ETHER_ADDR_LEN); + dev_addr_set(net, hw_ether); #endif wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, net->dev_addr); if (!wdev) { @@ -13424,7 +13570,7 @@ wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg, wdev = new_ndev->ieee80211_ptr; ASSERT(wdev); wdev->iftype = iface_type; - (void)memcpy_s(new_ndev->dev_addr, ETH_ALEN, addr, ETH_ALEN); + dev_addr_set(new_ndev, addr); } cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_CREATED; diff --git a/bcmdhd.101.10.361.x/wl_android.h b/bcmdhd.101.10.361.x/wl_android.h index b08a18b..a93a520 100755 --- a/bcmdhd.101.10.361.x/wl_android.h +++ b/bcmdhd.101.10.361.x/wl_android.h @@ -29,10 +29,8 @@ #include #include #include +#include #ifdef WL_EXT_IAPSTA -#ifdef WL_ESCAN -#include -#endif /* WL_ESCAN */ #include #endif /* WL_IAPSTA */ #if defined(WL_EXT_IAPSTA) || defined(USE_IW) || defined(WL_ESCAN) || \ @@ -42,7 +40,7 @@ #endif #include #endif -#include +#include /* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL * automatically @@ -82,6 +80,9 @@ typedef struct _compat_android_wifi_priv_cmd { #define ANDROID_SCAN_LEVEL (1 << 3) #define ANDROID_DBG_LEVEL (1 << 4) #define ANDROID_TPUT_LEVEL (1 << 8) +#define ANDROID_AMPDU_LEVEL (1 << 9) +#define ANDROID_TVPM_LEVEL (1 << 10) +#define ANDROID_BTC_LEVEL (1 << 11) #define ANDROID_MSG_LEVEL (1 << 0) #define WL_MSG(name, arg1, args...) \ @@ -249,4 +250,11 @@ extern int wl_android_bcnrecv_event(struct net_device *ndev, #define WLC_ACS_BAND_INVALID 0xffffu #endif /* WL_SUPPORT_AUTO_CHANNEL */ #define WL_PRIV_CMD_LEN 64 +#define CHECK_SCNPRINTF_RET_VAL(ret) \ + { \ + if (ret < 0) { \ + WL_ERR(("scnprintf failed %d\n", ret)); \ + return BCME_ERROR; \ + } \ + } #endif /* _wl_android_ */ diff --git a/bcmdhd.101.10.361.x/wl_android_ext.c b/bcmdhd.101.10.361.x/wl_android_ext.c index 7899365..1c43178 100755 --- a/bcmdhd.101.10.361.x/wl_android_ext.c +++ b/bcmdhd.101.10.361.x/wl_android_ext.c @@ -32,6 +32,8 @@ #include #endif /* WL_ESCAN */ +uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL; + #define AEXT_ERROR(name, arg1, args...) \ do { \ if (android_msg_level & ANDROID_ERROR_LEVEL) { \ @@ -80,6 +82,9 @@ #define CMD_ROAM_TRIGGER "ROAM_TRIGGER" #define CMD_PM "PM" #define CMD_MONITOR "MONITOR" +#ifdef BTC_WAR +#define CMD_BTC_WAR "BTC_WAR" +#endif /* BTC_WAR */ #define CMD_SET_SUSPEND_BCN_LI_DTIM "SET_SUSPEND_BCN_LI_DTIM" #define CMD_WLMSGLEVEL "WLMSGLEVEL" #ifdef WL_EXT_IAPSTA @@ -179,7 +184,7 @@ const auth_name_map_t auth_name_map[] = { {WL_AUTH_SAE_KEY, WPA3_AUTH_SAE_PSK|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK, "wpa3sae/psk/sha256"}, {WL_AUTH_OPEN_SYSTEM, 0x20|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK, "wpa3/psk/sha256"}, {WL_AUTH_SAE_KEY, 0x20|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK, "wpa3sae/psk/sha256"}, - {WL_AUTH_OPEN_SYSTEM, WPA3_AUTH_OWE, "wpa3/owe"}, + {WL_AUTH_OPEN_SYSTEM, WPA3_AUTH_OWE, "owe"}, }; typedef struct wsec_name_map_t { @@ -317,9 +322,9 @@ wl_ext_chspec_to_legacy(chanspec_t chspec) } chanspec_t -wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec) +wl_ext_chspec_host_to_driver(struct dhd_pub *dhd, chanspec_t chanspec) { - if (ioctl_ver == 1) { + if (dhd->conf->ioctl_ver == 1) { chanspec = wl_ext_chspec_to_legacy(chanspec); if (chanspec == INVCHANSPEC) { return chanspec; @@ -331,7 +336,7 @@ wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec) } static void -wl_ext_ch_to_chanspec(int ioctl_ver, int ch, +wl_ext_ch_to_chanspec(struct dhd_pub *dhd, int ch, struct wl_join_params *join_params, size_t *join_params_size) { chanspec_t chanspec = 0; @@ -354,7 +359,7 @@ wl_ext_ch_to_chanspec(int ioctl_ver, int ch, join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; join_params->params.chanspec_list[0] |= chanspec; join_params->params.chanspec_list[0] = - wl_ext_chspec_host_to_driver(ioctl_ver, + wl_ext_chspec_host_to_driver(dhd, join_params->params.chanspec_list[0]); join_params->params.chanspec_num = @@ -399,10 +404,10 @@ wl_ext_chspec_from_legacy(chanspec_t legacy_chspec) } chanspec_t -wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec) +wl_ext_chspec_driver_to_host(struct dhd_pub *dhd, chanspec_t chanspec) { chanspec = dtohchanspec(chanspec); - if (ioctl_ver == 1) { + if (dhd->conf->ioctl_ver == 1) { chanspec = wl_ext_chspec_from_legacy(chanspec); } @@ -410,6 +415,30 @@ wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec) } #endif /* WL_EXT_IAPSTA || WL_CFG80211 || WL_ESCAN */ +chanspec_band_t +wl_ext_wlcband_to_chanspec_band(int band) +{ + chanspec_band_t chanspec_band = INVCHANSPEC; + + switch (band) { +#ifdef WL_6G_BAND + case WLC_BAND_6G: + chanspec_band = WL_CHANSPEC_BAND_6G; + break; +#endif /* WL_6G_BAND */ + case WLC_BAND_5G: + chanspec_band = WL_CHANSPEC_BAND_5G; + break; + case WLC_BAND_2G: + chanspec_band = WL_CHANSPEC_BAND_2G; + break; + default: + AEXT_ERROR("wlan", "Invalid Frequency Band\n"); + break; + } + return chanspec_band; +} + bool wl_ext_check_scan(struct net_device *dev, dhd_pub_t *dhdp) { @@ -526,28 +555,6 @@ wl_ext_wait_event_complete(struct dhd_pub *dhd, int ifidx) } } -int -wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver) -{ - int ret = 0; - s32 val = 0; - - val = 1; - ret = wl_ext_ioctl(dev, WLC_GET_VERSION, &val, sizeof(val), 0); - if (ret) { - return ret; - } - val = dtoh32(val); - if (val != WLC_IOCTL_VERSION && val != 1) { - AEXT_ERROR(dev->name, "Version mismatch, please upgrade. Got %d, expected %d or 1\n", - val, WLC_IOCTL_VERSION); - return BCME_VERSION; - } - *ioctl_ver = val; - - return ret; -} - void wl_ext_bss_iovar_war(struct net_device *ndev, s32 *val) { @@ -585,10 +592,11 @@ wl_ext_bss_iovar_war(struct net_device *ndev, s32 *val) } int -wl_ext_set_chanspec(struct net_device *dev, int ioctl_ver, - uint16 channel, chanspec_t *ret_chspec) +wl_ext_set_chanspec(struct net_device *dev, struct wl_chan_info *chan_info, + chanspec_t *ret_chspec) { - s32 _chan = channel; + struct dhd_pub *dhd = dhd_get_pub(dev); + s32 _chan = chan_info->chan; chanspec_t chspec = 0; chanspec_t fw_chspec = 0; u32 bw = WL_CHANSPEC_BW_20; @@ -599,53 +607,54 @@ wl_ext_set_chanspec(struct net_device *dev, int ioctl_ver, u32 band; u32 bw_cap; } param = {0, 0}; - uint band; + chanspec_band_t chanspec_band = 0; - if (_chan <= CH_MAX_2G_CHANNEL) - band = IEEE80211_BAND_2GHZ; - else - band = IEEE80211_BAND_5GHZ; + if ((chan_info->band != WLC_BAND_2G) && (chan_info->band != WLC_BAND_5G) && + (chan_info->band != WLC_BAND_6G)) { + AEXT_ERROR(dev->name, "bad band %d\n", chan_info->band); + return BCME_BADBAND; + } - if (band == IEEE80211_BAND_5GHZ) { - param.band = WLC_BAND_5G; - err = wl_ext_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), - iovar_buf, WLC_IOCTL_SMLEN, NULL); - if (err) { - if (err != BCME_UNSUPPORTED) { - AEXT_ERROR(dev->name, "bw_cap failed, %d\n", err); - return err; - } else { - err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap); - if (bw_cap != WLC_N_BW_20ALL) - bw = WL_CHANSPEC_BW_40; - } + param.band = chan_info->band; + err = wl_ext_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), + iovar_buf, WLC_IOCTL_SMLEN, NULL); + if (err) { + if (err != BCME_UNSUPPORTED) { + AEXT_ERROR(dev->name, "bw_cap failed, %d\n", err); + return err; } else { - if (WL_BW_CAP_80MHZ(iovar_buf[0])) - bw = WL_CHANSPEC_BW_80; - else if (WL_BW_CAP_40MHZ(iovar_buf[0])) + err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap); + if (bw_cap != WLC_N_BW_20ALL) bw = WL_CHANSPEC_BW_40; - else - bw = WL_CHANSPEC_BW_20; - } + } else { + if (WL_BW_CAP_80MHZ(iovar_buf[0])) + bw = WL_CHANSPEC_BW_80; + else if (WL_BW_CAP_40MHZ(iovar_buf[0])) + bw = WL_CHANSPEC_BW_40; + else + bw = WL_CHANSPEC_BW_20; } - else if (band == IEEE80211_BAND_2GHZ) - bw = WL_CHANSPEC_BW_20; set_channel: - chspec = wf_channel2chspec(_chan, bw); + chanspec_band = wl_ext_wlcband_to_chanspec_band(chan_info->band); + chspec = wf_create_chspec_from_primary(chan_info->chan, bw, chanspec_band); if (wf_chspec_valid(chspec)) { - fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec); + fw_chspec = wl_ext_chspec_host_to_driver(dhd, chspec); if (fw_chspec != INVCHANSPEC) { if ((err = wl_ext_iovar_setint(dev, "chanspec", fw_chspec)) == BCME_BADCHAN) { if (bw == WL_CHANSPEC_BW_80) goto change_bw; err = wl_ext_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), 1); - WL_MSG(dev->name, "channel %d\n", _chan); + WL_MSG(dev->name, "channel %s-%d\n", CHSPEC2BANDSTR(chspec), _chan); } else if (err) { AEXT_ERROR(dev->name, "failed to set chanspec error %d\n", err); } else - WL_MSG(dev->name, "channel %d, 0x%x\n", channel, chspec); + WL_MSG(dev->name, "channel %s-%d(0x%x %sMHz)\n", + CHSPEC2BANDSTR(chspec), chan_info->chan, chspec, + CHSPEC_IS20(chspec)?"20": + CHSPEC_IS40(chspec)?"40": + CHSPEC_IS80(chspec)?"80":"160"); } else { AEXT_ERROR(dev->name, "failed to convert host chanspec to fw chanspec\n"); err = BCME_ERROR; @@ -671,20 +680,39 @@ change_bw: static int wl_ext_channel(struct net_device *dev, char* command, int total_len) { + struct wl_chan_info chan_info; int ret; - int channel=0; + char band[16]=""; + int channel = 0; channel_info_t ci; int bytes_written = 0; chanspec_t fw_chspec; - int ioctl_ver = 0; AEXT_TRACE(dev->name, "cmd %s", command); - sscanf(command, "%*s %d", &channel); + sscanf(command, "%*s %d %s", &channel, band); + if (strnicmp(band, "band=auto", strlen("band=auto")) == 0) { + chan_info.band = WLC_BAND_AUTO; + } +#ifdef WL_6G_BAND + else if (strnicmp(band, "band=6g", strlen("band=6g")) == 0) { + chan_info.band = WLC_BAND_6G; + } +#endif /* WL_6G_BAND */ + else if (strnicmp(band, "band=5g", strlen("band=5g")) == 0) { + chan_info.band = WLC_BAND_5G; + } + else if (strnicmp(band, "band=2g", strlen("band=2g")) == 0) { + chan_info.band = WLC_BAND_2G; + } + else if (channel <= CH_MAX_2G_CHANNEL) + chan_info.band = WLC_BAND_2G; + else + chan_info.band = WLC_BAND_5G; if (channel > 0) { - wl_ext_get_ioctl_ver(dev, &ioctl_ver); - ret = wl_ext_set_chanspec(dev, ioctl_ver, channel, &fw_chspec); + chan_info.chan = channel; + ret = wl_ext_set_chanspec(dev, &chan_info, &fw_chspec); } else { if (!(ret = wl_ext_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t), FALSE))) { @@ -825,6 +853,30 @@ wl_ext_monitor(struct net_device *dev, char *command, int total_len) return ret; } +#ifdef BTC_WAR +extern int btc_war; +static int +wl_ext_btc_war(struct net_device *dev, char *command, int total_len) +{ + int user_btc_war = 0; + bool enable = FALSE; + + sscanf(command, "%*s %d", &user_btc_war); + + AEXT_TRACE(dev->name, "btc_war=%d, user_btc_war=%d\n", + btc_war, user_btc_war); + + if (btc_war >= 0) { + btc_war = user_btc_war; + if (btc_war > 0) + enable = TRUE; + wl_ext_btc_config(dev, enable); + } + + return 0; +} +#endif /* BTC_WAR */ + s32 wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info) { @@ -835,11 +887,8 @@ wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info) s32 err = 0; u32 chan_cnt = 0; s8 *iovar_buf = NULL; - int ioctl_ver = 0; char sec[64]; - wl_ext_get_ioctl_ver(dev, &ioctl_ver); - if (dhd->conf->chip == BCM43362_CHIP_ID) goto set_ssid; @@ -895,7 +944,7 @@ wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info) ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; ext_join_params->assoc.chanspec_list[0] |= chspec; ext_join_params->assoc.chanspec_list[0] = - wl_ext_chspec_host_to_driver(ioctl_ver, + wl_ext_chspec_host_to_driver(dhd, ext_join_params->assoc.chanspec_list[0]); } ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); @@ -932,7 +981,7 @@ set_ssid: else memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); - wl_ext_ch_to_chanspec(ioctl_ver, conn_info->channel, &join_params, &join_params_size); + wl_ext_ch_to_chanspec(dhd, conn_info->channel, &join_params, &join_params_size); AEXT_TRACE(dev->name, "join_param_size %zu\n", join_params_size); if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { @@ -1042,18 +1091,43 @@ wl_ext_get_sec(struct net_device *dev, int ifmode, char *sec, int total_len, boo } bool -wl_ext_dfs_chan(uint16 chan) +wl_ext_dfs_chan(struct wl_chan_info *chan_info) { - if (chan >= 52 && chan <= 144) + if (chan_info->band == WLC_BAND_5G && chan_info->chan >= 52 && chan_info->chan <= 144) return TRUE; return FALSE; } +bool +wl_ext_passive_chan(struct net_device *dev, struct wl_chan_info *chan_info) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + u32 chanspec; + s32 ret = BCME_OK; + + chanspec = wf_create_chspec_from_primary(chan_info->chan, + WL_CHANSPEC_BW_20, wl_ext_wlcband_to_chanspec_band(chan_info->band)); + + chanspec = wl_ext_chspec_host_to_driver(dhd, chanspec); + + ret = wldev_iovar_getint(dev, "per_chan_info", &chanspec); + if (!ret) { + if (chanspec & WL_CHAN_PASSIVE) + return TRUE; + } else { + if (chan_info->band == WLC_BAND_5G && chan_info->chan >= 52 && chan_info->chan <= 144) + return TRUE; + } + + return FALSE; +} + uint16 wl_ext_get_default_chan(struct net_device *dev, uint16 *chan_2g, uint16 *chan_5g, bool nodfs) { struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_chan_info chan_info; uint16 chan_tmp = 0, chan = 0; wl_uint32_list_t *list; u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; @@ -1075,7 +1149,11 @@ wl_ext_get_default_chan(struct net_device *dev, if (chan_tmp <= 13 && !*chan_2g) { *chan_2g = chan_tmp; } else if (chan_tmp >= 36 && chan_tmp <= 161 && !*chan_5g) { - if (wl_ext_dfs_chan(chan_tmp) && nodfs) + chan_info.band = WLC_BAND_5G; + chan_info.chan = chan_tmp; + if (wl_ext_dfs_chan(&chan_info) && nodfs) + continue; + else if (wl_ext_passive_chan(dev, &chan_info)) continue; else *chan_5g = chan_tmp; @@ -1157,69 +1235,6 @@ wl_ext_wlmsglevel(struct net_device *dev, char *command, int total_len) return ret; } -#ifdef WL_CFG80211 -bool -wl_legacy_chip_check(struct net_device *net) -{ - struct dhd_pub *dhd = dhd_get_pub(net); - uint chip; - - chip = dhd_conf_get_chip(dhd); - - if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || - chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || - chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || - chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || - chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || - chip == BCM4371_CHIP_ID || - chip == BCM43430_CHIP_ID || - chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID || - chip == BCM4359_CHIP_ID || - chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID || - chip == BCM43569_CHIP_ID) { - return true; - } - - return false; -} - -bool -wl_new_chip_check(struct net_device *net) -{ - struct dhd_pub *dhd = dhd_get_pub(net); - uint chip; - - chip = dhd_conf_get_chip(dhd); - - if (chip == BCM4359_CHIP_ID || chip == BCM43012_CHIP_ID || - chip == BCM43751_CHIP_ID || chip == BCM43752_CHIP_ID) { - return true; - } - - return false; -} - -bool -wl_extsae_chip(struct dhd_pub *dhd) -{ - uint chip; - - chip = dhd_conf_get_chip(dhd); - - if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID || - chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID || - chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID || - chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID || - chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID || - chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID || - chip == BCM43569_CHIP_ID) { - return false; - } - - return true; -} -#endif - #ifdef WLEASYMESH #define CMD_EASYMESH "EASYMESH" //Set map 4 and dwds 1 on wlan0 interface @@ -1434,7 +1449,7 @@ wl_ext_mkeep_alive(struct net_device *dev, char *data, char *command, int total_len) { struct dhd_pub *dhd = dhd_get_pub(dev); - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; + wl_mkeep_alive_pkt_v1_t *mkeep_alive_pktp; int ret = -1, i, ifidx, id, period=-1; char *packet = NULL, *buf = NULL; int bytes_written = 0; @@ -1462,7 +1477,7 @@ wl_ext_mkeep_alive(struct net_device *dev, char *data, char *command, ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf, total_len, NULL); if (!ret) { - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) buf; + mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *) buf; bytes_written += snprintf(command+bytes_written, total_len, "Id :%d\n" "Period (msec) :%d\n" @@ -1670,25 +1685,23 @@ static int wl_ext_recal(struct net_device *dev, char *data, char *command, int total_len) { + struct dhd_pub *dhd = dhd_get_pub(dev); int ret = 0, i, nchan, nssid = 0; - int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); - wl_scan_params_t *params = NULL; - int ioctl_ver; + int params_size = WL_SCAN_PARAMS_V1_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); + wl_scan_params_v1_t *params = NULL; char *p; AEXT_TRACE(dev->name, "Enter\n"); if (data) { params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); - params = (wl_scan_params_t *) kzalloc(params_size, GFP_KERNEL); + params = (wl_scan_params_v1_t *) kzalloc(params_size, GFP_KERNEL); if (params == NULL) { ret = -ENOMEM; goto exit; } memset(params, 0, params_size); - wl_ext_get_ioctl_ver(dev, &ioctl_ver); - memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); params->bss_type = DOT11_BSSTYPE_ANY; params->scan_type = 0; @@ -1709,7 +1722,7 @@ wl_ext_recal(struct net_device *dev, char *data, char *command, params->home_time = htod32(params->home_time); for (i = 0; i < nchan; i++) { - wl_ext_chspec_host_to_driver(ioctl_ver, params->channel_list[i]); + wl_ext_chspec_host_to_driver(dhd, params->channel_list[i]); } p = (char*)params->channel_list + nchan * sizeof(uint16); @@ -2485,22 +2498,6 @@ typedef struct csi_list { csi_config_t configs[1]; } csi_list_t; -static int -wl_ether_atoe(const char *a, struct ether_addr *n) -{ - char *c = NULL; - int i = 0; - - memset(n, 0, ETHER_ADDR_LEN); - for (;;) { - n->octet[i++] = (uint8)strtoul(a, &c, 16); - if (!*c++ || i == ETHER_ADDR_LEN) - break; - a = c; - } - return (i == ETHER_ADDR_LEN); -} - static int wl_ext_csi(struct net_device *dev, char *data, char *command, int total_len) { @@ -2520,7 +2517,7 @@ wl_ext_csi(struct net_device *dev, char *data, char *command, int total_len) if (data) { sscanf(data, "%s %d", mac, &period); - ret = wl_ether_atoe(mac, &ea); + ret = bcm_ether_atoe(mac, &ea); if (!ret) { AEXT_ERROR(dev->name, "rejecting mac=%s, ret=%d\n", mac, ret); goto exit; @@ -2618,6 +2615,34 @@ wl_ext_get_country(struct net_device *dev, char *data, char *command, return bytes_written; } +static int +wl_ext_disable_5g_band(struct net_device *dev, char *data, char *command, + int total_len) +{ +#ifdef WL_CFG80211 + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); +#endif + int ret = -1; + int val; + + if (data) { + val = (int)simple_strtol(data, NULL, 0); + ret = wl_ext_iovar_setint(dev, "disable_5g_band", val); +#ifdef WL_CFG80211 + if (!ret) + wl_update_wiphybands(cfg, true); +#endif + } else { + ret = wl_ext_iovar_getint(dev, "disable_5g_band", &val); + if (!ret) { + ret = snprintf(command, total_len, "%d", val); + AEXT_TRACE(dev->name, "command result is %s\n", command); + } + } + + return ret; +} + typedef int (wl_ext_tpl_parse_t)(struct net_device *dev, char *data, char *command, int total_len); @@ -2670,6 +2695,7 @@ const wl_ext_iovar_tpl_t wl_ext_iovar_tpl_list[] = { {WLC_GET_VAR, WLC_SET_VAR, "csi", wl_ext_csi}, #endif /* CSI_SUPPORT */ {WLC_GET_VAR, WLC_SET_VAR, "country", wl_ext_get_country}, + {WLC_GET_VAR, WLC_SET_VAR, "disable_5g_band", wl_ext_disable_5g_band}, }; /* @@ -2811,6 +2837,11 @@ wl_android_ext_priv_cmd(struct net_device *net, char *command, else if (strnicmp(command, CMD_MONITOR, strlen(CMD_MONITOR)) == 0) { *bytes_written = wl_ext_monitor(net, command, total_len); } +#ifdef BTC_WAR + else if (strnicmp(command, CMD_BTC_WAR, strlen(CMD_BTC_WAR)) == 0) { + *bytes_written = wl_ext_btc_war(net, command, total_len); + } +#endif /* BTC_WAR */ else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) { int bcn_li_dtim; bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10); @@ -2886,6 +2917,85 @@ wl_android_ext_priv_cmd(struct net_device *net, char *command, return ret; } +#define CH_MIN_5G_CHANNEL 34 +int +wl_construct_ctl_chanspec_list(struct net_device *dev, wl_uint32_list_t *chan_list) +{ + void *list; + u32 i, channel; + chanspec_t chspec = 0; + s32 err = BCME_OK; + bool legacy_chan_info = FALSE; + u16 list_count; + +#define LOCAL_BUF_LEN 4096 + list = kmalloc(LOCAL_BUF_LEN, GFP_KERNEL); + if (list == NULL) { + WL_ERR(("failed to allocate local buf\n")); + return -ENOMEM; + } + + err = wldev_iovar_getbuf(dev, "chan_info_list", NULL, + 0, list, LOCAL_BUF_LEN, NULL); + if (err == BCME_UNSUPPORTED) { + err = wl_ext_iovar_getbuf(dev, "chanspecs", NULL, + 0, list, LOCAL_BUF_LEN, NULL); + if (err != BCME_OK) { + WL_ERR(("get chanspecs err(%d)\n", err)); + kfree(list); + return err; + } + /* Update indicating legacy chan info usage */ + legacy_chan_info = TRUE; + } else if (err != BCME_OK) { + WL_ERR(("get chan_info_list err(%d)\n", err)); + kfree(list); + return err; + } + + list_count = legacy_chan_info ? ((wl_uint32_list_t *)list)->count : + ((wl_chanspec_list_v1_t *)list)->count; + for (i = 0; i < dtoh32(list_count); i++) { + if (legacy_chan_info) { + chspec = (chanspec_t)dtoh32(((wl_uint32_list_t *)list)->element[i]); + } else { + chspec = (chanspec_t)dtoh32 + (((wl_chanspec_list_v1_t *)list)->chspecs[i].chanspec); + } + chspec = wl_chspec_driver_to_host(chspec); + channel = wf_chspec_ctlchan(chspec); + + if (!CHSPEC_IS20(chspec)) { + continue; + } + if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) && + (channel <= CH_MAX_2G_CHANNEL)) { + chan_list->element[chan_list->count] = chspec; + chan_list->count++; + } +#ifdef WL_6G_BAND + else if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) && + (channel <= CH_MAX_6G_CHANNEL)) { + if (channel == 2) + continue; + chan_list->element[chan_list->count] = chspec; + chan_list->count++; + } +#endif /* WL_6G_BAND */ + else if (CHSPEC_IS5G(chspec) && (channel >= CH_MIN_5G_CHANNEL) && + (channel <= 165)) { + chan_list->element[chan_list->count] = chspec; + chan_list->count++; + } else { + continue; + } + } + + kfree(list); +#undef LOCAL_BUF_LEN + return err; +} + #if defined(WL_CFG80211) || defined(WL_ESCAN) int wl_ext_get_distance(struct net_device *net, u32 band) @@ -2938,52 +3048,86 @@ wl_ext_get_best_channel(struct net_device *net, #if defined(BSSCACHE) wl_bss_cache_ctrl_t *bss_cache_ctrl, #else - wl_scan_results_t *bss_list, + wl_scan_results_v109_t *bss_list, #endif /* BSSCACHE */ - int ioctl_ver, int *best_2g_ch, int *best_5g_ch -) + int *best_2g_ch, int *best_5g_ch, int *best_6g_ch) { + struct dhd_pub *dhd = dhd_get_pub(net); struct wl_bss_info *bi = NULL; /* must be initialized */ + struct wl_chan_info chan_info; s32 i, j; #if defined(BSSCACHE) wl_bss_cache_t *node; #endif /* BSSCACHE */ int b_band[CH_MAX_2G_CHANNEL]={0}, a_band1[4]={0}, a_band4[5]={0}; - s32 cen_ch, distance, distance_2g, distance_5g, ch, min_ap=999; - u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; +#ifdef WL_6G_BAND + int six_g_band5[24]={0}, six_g_band6[5]={0}, six_g_band7[18]={0}, six_g_band8[13]={0}; + s32 distance_6g; +#endif /* WL_6G_BAND */ + s32 cen_ch, distance, distance_2g, distance_5g, chanspec, min_ap=999; + u8 valid_chan_list[sizeof(u32)*(MAX_CTRL_CHANSPECS + 1)]; wl_uint32_list_t *list; int ret; - chanspec_t chanspec; - struct dhd_pub *dhd = dhd_get_pub(net); + chanspec_t chspec; + u32 channel; memset(b_band, -1, sizeof(b_band)); memset(a_band1, -1, sizeof(a_band1)); memset(a_band4, -1, sizeof(a_band4)); +#ifdef WL_6G_BAND + memset(six_g_band5, -1, sizeof(six_g_band5)); + memset(six_g_band6, -1, sizeof(six_g_band6)); + memset(six_g_band7, -1, sizeof(six_g_band7)); + memset(six_g_band8, -1, sizeof(six_g_band8)); +#endif /* WL_6G_BAND */ memset(valid_chan_list, 0, sizeof(valid_chan_list)); list = (wl_uint32_list_t *)(void *) valid_chan_list; - list->count = htod32(WL_NUMCHANNELS); - ret = wl_ext_ioctl(net, WLC_GET_VALID_CHANNELS, &valid_chan_list, - sizeof(valid_chan_list), 0); - if (ret<0) { + + ret = wl_construct_ctl_chanspec_list(net, list); + if (ret < 0) { AEXT_ERROR(net->name, "get channels failed with %d\n", ret); return 0; } else { - for (i = 0; i < dtoh32(list->count); i++) { - ch = dtoh32(list->element[i]); - if (!dhd_conf_match_channel(dhd, ch)) + for (i = 0; i < list->count; i++) { + chspec = list->element[i]; + channel = wf_chspec_ctlchan(chspec); + chan_info.band = CHSPEC2WLC_BAND(chspec); + chan_info.chan = channel; + if (wl_ext_passive_chan(net, &chan_info)) { continue; - if (ch < CH_MAX_2G_CHANNEL) - b_band[ch-1] = 0; - else if (ch <= 48) - a_band1[(ch-36)/4] = 0; - else if (ch >= 149 && ch <= 161) - a_band4[(ch-149)/4] = 0; + } + if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) && + (channel <= CH_MAX_2G_CHANNEL)) { + b_band[channel-1] = 0; + } +#ifdef WL_6G_BAND + else if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) && + (channel <= CH_MAX_6G_CHANNEL)) { + if (channel <= 93) + six_g_band5[(channel-1)/4] = 0; + else if (channel >= 97 && channel <= 109) + six_g_band6[(channel-97)/4] = 0; + else if (channel >= 117 && channel <= 181) + six_g_band7[(channel-117)/4] = 0; + else if (channel >= 189 && channel <= 221) + six_g_band8[(channel-189)/4] = 0; + } +#endif /* WL_6G_BAND */ + else if (CHSPEC_IS5G(chspec) && channel >= CH_MIN_5G_CHANNEL) { + if (channel <= 48) + a_band1[(channel-36)/4] = 0; + else if (channel >= 149 && channel <= 161) + a_band4[(channel-149)/4] = 0; + } } } distance_2g = wl_ext_get_distance(net, WLC_BAND_2G); distance_5g = wl_ext_get_distance(net, WLC_BAND_5G); +#ifdef WL_6G_BAND + distance_6g = wl_ext_get_distance(net, WLC_BAND_6G); +#endif /* WL_6G_BAND */ #if defined(BSSCACHE) node = bss_cache_ctrl->m_cache_head; @@ -2995,9 +3139,9 @@ wl_ext_get_best_channel(struct net_device *net, #if defined(BSSCACHE) bi = node->results.bss_info; #else - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info; #endif /* BSSCACHE */ - chanspec = wl_ext_chspec_driver_to_host(ioctl_ver, bi->chanspec); + chanspec = wl_ext_chspec_driver_to_host(dhd, bi->chanspec); cen_ch = CHSPEC_CHANNEL(bi->chanspec); distance = 0; if (CHSPEC_IS20(chanspec)) @@ -3015,14 +3159,45 @@ wl_ext_get_best_channel(struct net_device *net, if (b_band[j] >= 0 && abs(cen_ch-(1+j)) <= distance) b_band[j] += 1; } - } else { + } +#ifdef WL_6G_BAND + else if (CHSPEC_IS6G(chanspec)) { + distance += distance_6g; + if (cen_ch <= 93) { + for (j=0; j= 0 && abs(cen_ch-(93+j*4)) <= distance) + six_g_band5[j] += 1; + } + } + else if (channel >= 97 && channel <= 109) { + for (j=0; j= 0 && abs(cen_ch-(97+j*4)) <= distance) + six_g_band6[j] += 1; + } + } + else if (channel >= 117 && channel <= 181) { + for (j=0; j= 0 && abs(cen_ch-(117+j*4)) <= distance) + six_g_band7[j] += 1; + } + } + else if (channel >= 189 && channel <= 221) { + for (j=0; j= 0 && abs(cen_ch-(189+j*4)) <= distance) + six_g_band8[j] += 1; + } + } + } +#endif /* WL_6G_BAND */ + else { distance += distance_5g; if (cen_ch <= 48) { for (j=0; j= 0 && abs(cen_ch-(36+j*4)) <= distance) a_band1[j] += 1; } - } else if (cen_ch >= 149) { + } + else if (cen_ch >= 149) { for (j=0; j= 0 && abs(cen_ch-(149+j*4)) <= distance) a_band4[j] += 1; @@ -3056,27 +3231,80 @@ wl_ext_get_best_channel(struct net_device *net, *best_5g_ch = i*4 + 149; } } +#ifdef WL_6G_BAND + *best_6g_ch = 0; + min_ap = 999; + for (i=0; i= 0) { + min_ap = six_g_band5[i]; + *best_6g_ch = i*4 + 1; + } + } + for (i=0; i= 0) { + min_ap = six_g_band6[i]; + *best_6g_ch = i*4 + 97; + } + } + for (i=0; i= 0) { + min_ap = six_g_band7[i]; + *best_6g_ch = i*4 + 117; + } + } + for (i=0; i= 0) { + min_ap = six_g_band8[i]; + *best_6g_ch = i*4 + 189; + } + } +#endif /* WL_6G_BAND */ if (android_msg_level & ANDROID_INFO_LEVEL) { struct bcmstrbuf strbuf; char *tmp_buf = NULL; - tmp_buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); + tmp_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); if (tmp_buf == NULL) { AEXT_ERROR(net->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN); goto exit; } - bcm_binit(&strbuf, tmp_buf, WLC_IOCTL_SMLEN); + bcm_binit(&strbuf, tmp_buf, WLC_IOCTL_MEDLEN); + bcm_bprintf(&strbuf, "2g: "); for (j=0; jname, "\n%s", strbuf.origbuf); if (tmp_buf) { kfree(tmp_buf); @@ -3096,6 +3324,7 @@ wl_ext_fw_apcs(struct net_device *dev, uint32 band) int channel = 0, chosen = 0, retry = 0, ret = 0, spect = 0; u8 *reqbuf = NULL; uint32 buf_size; + chanspec_band_t acs_band = WLC_BAND_INVALID; ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect)); if (ret) { @@ -3118,35 +3347,20 @@ wl_ext_fw_apcs(struct net_device *dev, uint32 band) } memset(reqbuf, 0, CHANSPEC_BUF_SIZE); - if (band == WLC_BAND_AUTO) { - AEXT_INFO(dev->name, "ACS full channel scan \n"); - reqbuf[0] = htod32(0); - } else if (band == WLC_BAND_5G) { - AEXT_INFO(dev->name, "ACS 5G band scan \n"); - ret = wl_android_get_band_chanspecs(dev, (void *)reqbuf, CHANSPEC_BUF_SIZE, - WL_CHANSPEC_BAND_5G, false); - if (ret < 0) { - AEXT_ERROR(dev->name, "ACS 5g chanspec retreival failed! \n"); - goto done; - } - } else if (band == WLC_BAND_2G) { - /* - * If channel argument is not provided/ argument 20 is provided, - * Restrict channel to 2GHz, 20MHz BW, No SB - */ - AEXT_INFO(dev->name, "ACS 2G band scan \n"); - ret = wl_android_get_band_chanspecs(dev, (void *)reqbuf, CHANSPEC_BUF_SIZE, - WL_CHANSPEC_BAND_2G, false); - if (ret < 0) { - AEXT_ERROR(dev->name, "ACS 2g chanspec retreival failed! \n"); - goto done; - } - } else { - AEXT_ERROR(dev->name, "ACS: No band chosen\n"); + acs_band = wl_ext_wlcband_to_chanspec_band(band); + if (acs_band == INVCHANSPEC) { + acs_band = WL_CHANSPEC_BAND_2G; + } + + if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE, + acs_band, true)) < 0) { + WL_ERR(("ACS chanspec retrieval failed!\n")); goto done; } - buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE; + AEXT_INFO(dev->name, "ACS chanspec band 0x%x\n", acs_band); + + buf_size = CHANSPEC_BUF_SIZE; ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf, buf_size); if (ret < 0) { @@ -3156,7 +3370,7 @@ wl_ext_fw_apcs(struct net_device *dev, uint32 band) } /* Wait for auto channel selection, max 3000 ms */ - if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G)) { + if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G) || (band == WLC_BAND_6G)) { OSL_SLEEP(500); } else { /* @@ -3176,24 +3390,12 @@ wl_ext_fw_apcs(struct net_device *dev, uint32 band) chosen = dtoh32(chosen); } - if (chosen) { - int chosen_band; - int apcs_band; -#ifdef D11AC_IOTYPES - if (wl_cfg80211_get_ioctl_version() == 1) { - channel = LCHSPEC_CHANNEL((chanspec_t)chosen); - } else { - channel = CHSPEC_CHANNEL((chanspec_t)chosen); - } -#else - channel = CHSPEC_CHANNEL((chanspec_t)chosen); -#endif /* D11AC_IOTYPES */ - apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band; - chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G; - if (apcs_band == chosen_band) { - WL_MSG(dev->name, "selected channel = %d\n", channel); - break; - } + if (wf_chspec_valid((chanspec_t)chosen)) { + channel = wf_chspec_ctlchan((chanspec_t)chosen); + acs_band = CHSPEC_BAND((chanspec_t)chosen); + WL_MSG(dev->name, "selected channel = %d(band %d)\n", + channel, CHSPEC2WLC_BAND((chanspec_t)chosen)); + break; } AEXT_INFO(dev->name, "%d tried, ret = %d, chosen = 0x%x\n", (APCS_MAX_RETRY - retry), ret, chosen); @@ -3230,18 +3432,35 @@ wl_ext_drv_scan(struct net_device *dev, uint32 band, bool fast_scan) } memset(&scan_info, 0, sizeof(wl_scan_info_t)); if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) { - for (i=0; i<13; i++) - scan_info.channels.channel[i] = i + 1; + for (i=0; i<13; i++) { + scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(i+1, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G); + } cnt += 13; } if (band == WLC_BAND_5G || band == WLC_BAND_AUTO) { - for (i=0; i<4; i++) - scan_info.channels.channel[i+cnt] = 36 + i*4; + for (i=0; i<4; i++) { + scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(36+i*4, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G); + } cnt += 4; - for (i=0; i<4; i++) - scan_info.channels.channel[i+cnt] = 149 + i*4; + for (i=0; i<4; i++) { + scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(149+i*4, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G); + } cnt += 4; } +#ifdef WL_6G_BAND + if (band == WLC_BAND_6G || band == WLC_BAND_AUTO) { + for (i=0; i<59; i++) { + scan_info.channels.channel[i+cnt] = wf_create_chspec_from_primary(1+i*4, + WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_6G); + } + cnt += 59; + } +#endif /* WL_6G_BAND */ + if (band == WLC_BAND_2G) + fast_scan = FALSE; scan_info.channels.count = cnt; if (fast_scan) scan_info.scan_time = 40; @@ -3281,6 +3500,10 @@ wl_ext_drv_apcs(struct net_device *dev, uint32 band) if (escan->escan_state == ESCAN_STATE_IDLE) { if (band == WLC_BAND_5G) channel = escan->best_5g_ch; +#ifdef WL_6G_BAND + else if (band == WLC_BAND_6G) + channel = escan->best_6g_ch; +#endif /* WL_6G_BAND */ else channel = escan->best_2g_ch; WL_MSG(dev->name, "selected channel = %d\n", channel); @@ -3531,10 +3754,10 @@ exit: void wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, - wl_scan_results_t *ss_list) + wl_scan_results_v109_t *ss_list) { wl_rssi_cache_t *node, *prev, *leaf, **rssi_head; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int i, j, k; struct osl_timespec now, timeout; @@ -3560,7 +3783,7 @@ wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, node = *rssi_head; prev = NULL; k = 0; - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; for (;node;) { if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { AEXT_INFO("wlan", "Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n", @@ -3886,11 +4109,11 @@ wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, #if defined(RSSIAVG) wl_rssi_cache_ctrl_t *rssi_cache_ctrl, #endif /* RSSIAVG */ - wl_scan_results_t *ss_list) + wl_scan_results_v109_t *ss_list) { wl_bss_cache_t *node, *node_target = NULL, *prev, *leaf, **bss_head; wl_bss_cache_t *node_rssi_prev = NULL, *node_rssi = NULL; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int i, k=0, bss_num = 0; struct osl_timespec now, timeout; int16 rssi_min; @@ -3925,7 +4148,7 @@ wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, prev = NULL; node_target = NULL; node_rssi_prev = NULL; - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; // find the bss with same BSSID for (;node;) { diff --git a/bcmdhd.101.10.361.x/wl_android_ext.h b/bcmdhd.101.10.361.x/wl_android_ext.h index 1ebc33a..12590d2 100755 --- a/bcmdhd.101.10.361.x/wl_android_ext.h +++ b/bcmdhd.101.10.361.x/wl_android_ext.h @@ -1,6 +1,12 @@ #ifndef _wl_android_ext_ #define _wl_android_ext_ + +typedef struct wl_chan_info { + uint band; + uint16 chan; +} wl_chan_info_t; + typedef struct bcol_gtk_para { int enable; int ptk_len; @@ -10,6 +16,7 @@ typedef struct bcol_gtk_para { #define ACS_FW_BIT (1<<0) #define ACS_DRV_BIT (1<<1) int wl_ext_autochannel(struct net_device *dev, uint acs, uint32 band); +chanspec_band_t wl_ext_wlcband_to_chanspec_band(int band); int wl_android_ext_priv_cmd(struct net_device *net, char *command, int total_len, int *bytes_written); void wl_ext_get_sec(struct net_device *dev, int ifmode, char *sec, int total_len, bool dump); @@ -19,6 +26,7 @@ int wl_ext_set_scan_time(struct net_device *dev, int scan_time, void wl_ext_wait_event_complete(struct dhd_pub *dhd, int ifidx); int wl_ext_add_del_ie(struct net_device *dev, uint pktflag, char *ie_data, const char* add_del_cmd); #ifdef WL_ESCAN +int wl_construct_ctl_chanspec_list(struct net_device *dev, wl_uint32_list_t *chan_list); int wl_ext_drv_scan(struct net_device *dev, uint band, bool fast_scan); #endif #ifdef WL_EXT_GENL @@ -39,23 +47,19 @@ int wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name, int wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); -chanspec_t wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec); -chanspec_t wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec); -bool wl_ext_dfs_chan(uint16 chan); +chanspec_t wl_ext_chspec_driver_to_host(struct dhd_pub *dhd, chanspec_t chanspec); +chanspec_t wl_ext_chspec_host_to_driver(struct dhd_pub *dhd, chanspec_t chanspec); +bool wl_ext_dfs_chan(struct wl_chan_info *chan_info); +bool wl_ext_passive_chan(struct net_device *dev, struct wl_chan_info *chan_info); uint16 wl_ext_get_default_chan(struct net_device *dev, uint16 *chan_2g, uint16 *chan_5g, bool nodfs); -int wl_ext_set_chanspec(struct net_device *dev, int ioctl_ver, - uint16 channel, chanspec_t *ret_chspec); +int wl_ext_set_chanspec(struct net_device *dev, struct wl_chan_info *chan_info, + chanspec_t *ret_chspec); int wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver); #endif #if defined(WL_CFG80211) || defined(WL_ESCAN) void wl_ext_user_sync(struct dhd_pub *dhd, int ifidx, bool lock); #endif -#if defined(WL_CFG80211) -bool wl_legacy_chip_check(struct net_device *net); -bool wl_new_chip_check(struct net_device *net); -bool wl_extsae_chip(struct dhd_pub *dhd); -#endif #if defined(WL_EXT_IAPSTA) || defined(WL_CFG80211) void wl_ext_bss_iovar_war(struct net_device *dev, s32 *val); #endif /* WL_EXT_IAPSTA ||WL_CFG80211 */ @@ -117,7 +121,7 @@ void wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl); void wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl); void wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, u8 *bssid); void wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl); -void wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list); +void wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_v109_t *ss_list); int wl_update_connected_rssi_cache(struct net_device *net, wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg); int16 wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr); #endif @@ -145,7 +149,7 @@ typedef struct wl_bss_cache { struct wl_bss_cache *next; int dirty; struct osl_timespec tv; - wl_scan_results_t results; + wl_scan_results_v109_t results; } wl_bss_cache_t; typedef struct wl_bss_cache_ctrl { @@ -161,15 +165,27 @@ void wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, #if defined(RSSIAVG) wl_rssi_cache_ctrl_t *rssi_cache_ctrl, #endif - wl_scan_results_t *ss_list); + wl_scan_results_v109_t *ss_list); void wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl); #endif int wl_ext_get_best_channel(struct net_device *net, #if defined(BSSCACHE) wl_bss_cache_ctrl_t *bss_cache_ctrl, #else - wl_scan_results_t *bss_list, + wl_scan_results_v109_t *bss_list, #endif - int ioctl_ver, int *best_2g_ch, int *best_5g_ch + int *best_2g_ch, int *best_5g_ch, int *best_6g_ch ); + +#ifdef WL_6G_BAND +#define CHSPEC2BANDSTR(chspec) ((chspec && CHSPEC_IS2G(chspec)) ? "2g" : CHSPEC_IS5G(chspec) ? \ + "5g" : CHSPEC_IS6G(chspec) ? "6g" : "0g") +#define WLCBAND2STR(band) ((band == WLC_BAND_2G) ? "2g" : (band == WLC_BAND_5G) ? \ + "5g" : (band == WLC_BAND_6G) ? "6g" : "0g") +#else +#define CHSPEC2BANDSTR(chspec) ((chspec && CHSPEC_IS2G(chspec)) ? "2g" : CHSPEC_IS5G(chspec) ? \ + "5g" : "0g") +#define WLCBAND2STR(band) ((band == WLC_BAND_2G) ? "2g" : (band == WLC_BAND_5G) ? \ + "5g" : "0g") +#endif /* WL_6G_BAND */ #endif diff --git a/bcmdhd.101.10.361.x/wl_bam.c b/bcmdhd.101.10.361.x/wl_bam.c index ec9e91c..21d2bf5 100755 --- a/bcmdhd.101.10.361.x/wl_bam.c +++ b/bcmdhd.101.10.361.x/wl_bam.c @@ -160,7 +160,7 @@ wl_bad_ap_mngr_fparse(struct bcm_cfg80211 *cfg, struct file *fp) return BCME_NOMEM; } - ret = vfs_read(fp, buf, WL_BAD_AP_MAX_BUF_SIZE, &fp->f_pos); + ret = dhd_vfs_read(fp, buf, WL_BAD_AP_MAX_BUF_SIZE, &fp->f_pos); if (ret < 0) { WL_ERR(("%s: file read failed (%d)\n", __FUNCTION__, ret)); goto fail; @@ -236,8 +236,8 @@ wl_bad_ap_mngr_fread(struct bcm_cfg80211 *cfg, const char *fname) fs = get_fs(); set_fs(KERNEL_DS); - fp = filp_open(fname, O_RDONLY, 0); - if (IS_ERR(fp)) { + fp = dhd_filp_open(fname, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { fp = NULL; WL_ERR(("%s: file open failed(%d)\n", __FUNCTION__, ret)); goto fail; @@ -248,7 +248,7 @@ wl_bad_ap_mngr_fread(struct bcm_cfg80211 *cfg, const char *fname) } fail: if (fp) { - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); } set_fs(fs); @@ -283,8 +283,8 @@ wl_bad_ap_mngr_fwrite(struct bcm_cfg80211 *cfg, const char *fname) fs = get_fs(); set_fs(KERNEL_DS); - fp = filp_open(fname, O_CREAT | O_RDWR | O_TRUNC, 0666); - if (IS_ERR(fp)) { + fp = dhd_filp_open(fname, O_CREAT | O_RDWR | O_TRUNC, 0666); + if (IS_ERR(fp) || (fp == NULL)) { ret = PTR_ERR(fp); WL_ERR(("%s: file open failed(%d)\n", __FUNCTION__, ret)); fp = NULL; @@ -310,13 +310,13 @@ wl_bad_ap_mngr_fwrite(struct bcm_cfg80211 *cfg, const char *fname) #pragma GCC diagnostic pop #endif - ret = vfs_write(fp, tmp, len, &fp->f_pos); + ret = dhd_vfs_write(fp, tmp, len, &fp->f_pos); if (ret < 0) { WL_ERR(("%s: file write failed(%d)\n", __FUNCTION__, ret)); goto fail; } /* Sync file from filesystem to physical media */ - ret = vfs_fsync(fp, 0); + ret = dhd_vfs_fsync(fp, 0); if (ret < 0) { WL_ERR(("%s: sync file failed(%d)\n", __FUNCTION__, ret)); goto fail; @@ -324,7 +324,7 @@ wl_bad_ap_mngr_fwrite(struct bcm_cfg80211 *cfg, const char *fname) ret = BCME_OK; fail: if (fp) { - filp_close(fp, NULL); + dhd_filp_close(fp, NULL); } set_fs(fs); mutex_unlock(&cfg->bad_ap_mngr.fs_lock); diff --git a/bcmdhd.101.10.361.x/wl_cfg80211.c b/bcmdhd.101.10.361.x/wl_cfg80211.c index d646053..d8c92db 100755 --- a/bcmdhd.101.10.361.x/wl_cfg80211.c +++ b/bcmdhd.101.10.361.x/wl_cfg80211.c @@ -475,18 +475,34 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); #endif /* WL_CFG80211_P2P_DEV_IF */ static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, +#if defined(CFG80211_BKPORT_MLO) + int link_id, +#endif u8 key_idx, bool unicast, bool multicast); static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, +#if defined(CFG80211_BKPORT_MLO) + int link_id, +#endif u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params); static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, +#if defined(CFG80211_BKPORT_MLO) + int link_id, +#endif u8 key_idx, bool pairwise, const u8 *mac_addr); static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, +#if defined(CFG80211_BKPORT_MLO) + int link_id, +#endif u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *params)); static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *dev, u8 key_idx); + struct net_device *dev, +#if defined(CFG80211_BKPORT_MLO) + int link_id, +#endif + u8 key_idx); #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev, u64 cookie); @@ -579,10 +595,8 @@ static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, const wl_event_msg_t *e, void *data, bool completed); -#ifdef DHD_LOSSLESS_ROAMING static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, const wl_event_msg_t *e, void *data); -#endif /* DHD_LOSSLESS_ROAMING */ static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); #ifdef BT_WIFI_HANDOVER @@ -2291,7 +2305,7 @@ _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg) WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__, filename)); - fp = filp_open(filename, O_RDONLY, 0); + fp = dhd_filp_open(filename, O_RDONLY, 0); if (IS_ERR(fp) || (fp == NULL)) { WL_ERR(("%s: Couldn't read the file, err %ld,File [%s] No previous axi error \n", @@ -2299,8 +2313,8 @@ _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg) return ret; } - kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t)); - filp_close(fp, NULL); + dhd_kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t)); + dhd_filp_close(fp, NULL); /* Delete axi error info file */ if (dhd_file_delete(filename) < 0) { @@ -3182,7 +3196,7 @@ wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, if (addr) { ifflags |= WL_INTERFACE_MAC_USE; - if (wl_legacy_chip_check(ndev)) { + if (dhd_conf_legacy_chip_check(cfg->pub)) { iface.flags = ifflags; memcpy(&iface.mac_addr.octet, addr, ETH_ALEN); } @@ -3195,7 +3209,7 @@ wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, #endif /* WLEASYMESH */ /* Pass ver = 0 for fetching the interface_create iovar version */ - if (wl_legacy_chip_check(ndev)) { + if (dhd_conf_legacy_chip_check(cfg->pub)) { bzero(&iface_v0, sizeof(iface_v0)); iface_v0.ver = WL_INTERFACE_CREATE_VER_0; iface_v0.flags = iftype | ifflags; @@ -3719,15 +3733,19 @@ wl_cfg80211_post_ifcreate(struct net_device *ndev, #ifdef WLDWDS /* set wds0.x to 4addr interface here */ if (event->role == WLC_E_IF_ROLE_WDS) { - WL_MSG(ndev->name, "set vwdev 4addr to %s\n", event->name); + struct dhd_if *ifp = dhd_get_ifp(cfg->pub, event->ifidx); + ifp->dwds = TRUE; + WL_MSG(event->name, "set to 4addr\n"); wdev->use_4addr = true; } #endif /* WLDWDS */ SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy)); - memcpy(new_ndev->dev_addr, addr, ETH_ALEN); + dev_addr_set(new_ndev, addr); #ifdef WL_EXT_IAPSTA - wl_ext_iapsta_ifadding(new_ndev, event->ifidx); + if (event->role != WLC_E_IF_ROLE_WDS) { + wl_ext_iapsta_ifadding(new_ndev, event->ifidx); + } #endif /* WL_EXT_IAPSTA */ if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd) != BCME_OK) { @@ -4206,20 +4224,12 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, chan = params->channel; #endif /* WL_CFG80211_P2P_DEV_IF */ if (chan) { - u16 center_freq = chan->center_freq; #ifdef WL_EXT_IAPSTA - enum nl80211_band band; - s32 _chan; - _chan = ieee80211_frequency_to_channel(center_freq); + chanspec = wl_freq_to_chanspec(chan->center_freq); wl_ext_iapsta_update_iftype(dev, WL_IF_TYPE_IBSS); - _chan = wl_ext_iapsta_update_channel(dev, _chan); - if (CHANNEL_IS_5G(_chan)) - band = NL80211_BAND_5GHZ; - else - band = NL80211_BAND_2GHZ; - center_freq = ieee80211_channel_to_frequency(_chan, band); + chanspec = wl_ext_iapsta_update_channel(dev, chanspec); #endif /* WL_EXT_IAPSTA */ - cfg->channel = wl_freq_to_chanspec(center_freq); + cfg->channel = chanspec; } if (wl_get_drv_status(cfg, CONNECTED, dev)) { struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID); @@ -6216,14 +6226,16 @@ wl_conn_debug_info(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc if (!err) cur_rssi = dtoh32(scb_val.val); WL_MSG(dev->name, "Reconnecting with " MACDBG " ssid \"%s\", len (%d), " - "channel=%d(chan_cnt=%d), sec=%s, rssi=%d => %d\n", + "channel=%s-%d(chan_cnt=%d), sec=%s, rssi=%d => %d\n", MAC2STRDBG((u8*)(&info->bssid)), info->ssid, info->ssid_len, - wf_chspec_ctlchan(chanspec), chan_cnt, sec_info, cur_rssi, target_rssi); + CHSPEC2BANDSTR(chanspec), wf_chspec_ctlchan(chanspec), chan_cnt, + sec_info, cur_rssi, target_rssi); } else { WL_MSG(dev->name, "Connecting with " MACDBG " ssid \"%s\", len (%d), " - "channel=%d(chan_cnt=%d), sec=%s, rssi=%d\n", + "channel=%s-%d(chan_cnt=%d), sec=%s, rssi=%d\n", MAC2STRDBG((u8*)(&info->bssid)), info->ssid, info->ssid_len, - wf_chspec_ctlchan(chanspec), chan_cnt, sec_info, target_rssi); + CHSPEC2BANDSTR(chanspec), wf_chspec_ctlchan(chanspec), chan_cnt, + sec_info, target_rssi); } if (wl_dbg_level & WL_DBG_DBG) { WL_MSG(dev->name, "akm:0x%x auth:0x%x wpaver:0x%x pwise:0x%x gwise:0x%x\n", @@ -6276,7 +6288,7 @@ wl_handle_join(struct bcm_cfg80211 *cfg, } #ifdef WL_EXT_IAPSTA - wl_ext_iapsta_update_channel(dev, wf_chspec_ctlchan(assoc_info->chanspecs[0])); + wl_ext_iapsta_update_channel(dev, assoc_info->chanspecs[0]); #endif /* print relevant info for debug purpose */ wl_conn_debug_info(cfg, dev, assoc_info); @@ -6329,7 +6341,7 @@ wl_handle_reassoc(struct bcm_cfg80211 *cfg, struct net_device *dev, reassoc_params->chanspec_num = htod32(chan_cnt); #ifdef WL_EXT_IAPSTA - wl_ext_iapsta_update_channel(dev, wf_chspec_ctlchan(chanspec)); + wl_ext_iapsta_update_channel(dev, chanspec); #endif /* print relevant info for debug purpose */ wl_conn_debug_info(cfg, dev, info); @@ -6385,6 +6397,9 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if (assoc_info.reassoc) { /* Handle roam to same ESS */ +#ifdef DHD_LOSSLESS_ROAMING + wl_ext_send_event_msg(dev, WLC_E_ROAM_PREP, WLC_E_STATUS_SUCCESS, WLC_E_REASON_LOW_RSSI); +#endif if ((err = wl_handle_reassoc(cfg, dev, &assoc_info)) != BCME_OK) { goto fail; } @@ -6539,7 +6554,16 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, WL_TRACE_HW4(("Aborting the scan! \n")); wl_cfgscan_cancel_scan(cfg); } - if (conn_in_progress || connected || wdev->ssid_len) { + if (conn_in_progress || connected || +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + wdev->u.client.ssid_len +#else + wdev->ssid_len +#endif + ) { +#ifdef WL_EXT_IAPSTA + wl_ext_in4way_sync(dev, 0, WL_EXT_STATUS_PRE_DISCONNECTING, NULL); +#endif scbval.val = reason_code; memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); scbval.val = htod32(scbval.val); @@ -6584,7 +6608,13 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, * and issue disconnect indication if required. */ - if (wdev->current_bss || wdev->ssid_len) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + // terence 20220911: fix me + if (wdev->links[0].client.current_bss || wdev->u.client.ssid_len) +#else + if (wdev->current_bss || wdev->ssid_len) +#endif + { WL_INFORM_MEM(("report disconnect event\n")); CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL); } @@ -6689,6 +6719,9 @@ wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, +#if defined(CFG80211_BKPORT_MLO) + int link_id, +#endif u8 key_idx, bool unicast, bool multicast) { struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); @@ -6733,7 +6766,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, s32 bssidx; s32 mode = wl_get_mode_by_netdev(cfg, dev); - WL_MSG(dev->name, "key index (%d)\n", key_idx); + WL_MSG(dev->name, "key index (%d) for %pM\n", key_idx, mac_addr); if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); return BCME_ERROR; @@ -6900,6 +6933,9 @@ wl_cfg80211_block_arp(struct net_device *dev, int enable) static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, +#if defined(CFG80211_BKPORT_MLO) + int link_id, +#endif u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params) { @@ -7099,6 +7135,9 @@ exit: static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, +#if defined(CFG80211_BKPORT_MLO) + int link_id, +#endif u8 key_idx, bool pairwise, const u8 *mac_addr) { struct wl_wsec_key key; @@ -7162,6 +7201,9 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, /* NOTE : this function cannot work as is and is never called */ static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, +#if defined(CFG80211_BKPORT_MLO) + int link_id, +#endif u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params * params)) { @@ -7236,7 +7278,11 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *dev, u8 key_idx) + struct net_device *dev, +#if defined(CFG80211_BKPORT_MLO) + int link_id, +#endif + u8 key_idx) { #ifdef MFP /* Firmware seems to use hard coded index for Group Mgmt Key. @@ -10220,6 +10266,34 @@ exit: } #endif /* WL_SUPPORT_ACS */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) +static int +wl_cfg80211_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + unsigned int link_id, +#endif + struct cfg80211_chan_def *chandef) +{ + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + u32 chanspec = 0; + int ret = 0; + + RETURN_EIO_IF_NOT_UP(cfg); + if (NULL == wdev->netdev) { + /* the P2P interface may temporary use wdev without ndev */ + return -EINVAL; + } + + if ((ret = wldev_iovar_getint(wdev->netdev, "chanspec", (s32 *)&chanspec) != BCME_OK)) { + return ret; + } + if (!chandef || (wl_chspec_chandef(chanspec, chandef, wiphy) != BCME_OK)) { + return BCME_ERROR; + } + return 0; +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0) */ + static struct cfg80211_ops wl_cfg80211_ops = { .add_virtual_intf = wl_cfg80211_add_virtual_iface, .del_virtual_intf = wl_cfg80211_del_virtual_iface, @@ -10317,6 +10391,9 @@ static struct cfg80211_ops wl_cfg80211_ops = { .update_ft_ies = wl_cfg80211_update_ft_ies, #endif /* WLFBT */ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0) + .get_channel = wl_cfg80211_get_channel, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0) */ }; s32 wl_mode_to_nl80211_iftype(s32 mode) @@ -10341,6 +10418,35 @@ s32 wl_mode_to_nl80211_iftype(s32 mode) return err; } +static bool +wl_is_ccode_change_allowed(struct net_device *net) +{ + struct wireless_dev *wdev = ndev_to_wdev(net); + struct wiphy *wiphy = wdev->wiphy; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + struct net_info *iter, *next; + + /* Country code isn't allowed change on AP/GO, NDP established */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + for_each_ndev(cfg, iter, next) { + GCC_DIAGNOSTIC_POP(); + if (iter->ndev) { + if (wl_get_drv_status(cfg, AP_CREATED, iter->ndev)) { + WL_ERR(("AP active. skip coutry ccode change\n")); + return false; + } + } + } + +#ifdef WL_NAN + if (wl_cfgnan_is_enabled(cfg) && wl_cfgnan_is_dp_active(net)) { + WL_ERR(("NDP established. skip coutry ccode change\n")); + return false; + } +#endif /* WL_NAN */ + return true; +} + static bool wl_is_ccode_change_required(struct net_device *net, char *country_code, int revinfo) @@ -10419,6 +10525,73 @@ wl_cfg80211_cleanup_connection(struct net_device *net, bool user_enforced) #endif /* WL_NAN */ } +static int wl_copy_regd(const struct ieee80211_regdomain *regd_orig, + struct ieee80211_regdomain *regd_copy) +{ + int i; + + if (memcpy_s(regd_copy, sizeof(*regd_copy), regd_orig, sizeof(*regd_orig))) { + return BCME_ERROR; + } + for (i = 0; i < regd_orig->n_reg_rules; i++) { + if (memcpy_s(®d_copy->reg_rules[i], sizeof(regd_copy->reg_rules[i]), + ®d_orig->reg_rules[i], sizeof(regd_orig->reg_rules[i]))) { + return BCME_ERROR; + } + } + return BCME_OK; +} + +static void wl_notify_regd(struct wiphy *wiphy, char *country_code) +{ + struct ieee80211_regdomain *regd_copy = NULL; + int regd_len; + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); + + regd_len = sizeof(brcm_regdom) + (brcm_regdom.n_reg_rules * + sizeof(struct ieee80211_reg_rule)); + + regd_copy = (struct ieee80211_regdomain *)MALLOCZ(cfg->osh, regd_len); + if (!regd_copy) { + WL_ERR(("failed to alloc regd_copy\n")); + return; + } + + /* the upper layer function below requires non-const type */ + if (wl_copy_regd(&brcm_regdom, regd_copy)) { + WL_ERR(("failed to copy new regd\n")); + goto exit; + } + + if (country_code) { + if (memcpy_s(regd_copy->alpha2, sizeof(regd_copy->alpha2), + country_code, WL_CCODE_LEN)) { + WL_ERR(("failed to copy new ccode:%s\n", country_code)); + goto exit; + } + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) + if (rtnl_is_locked()) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + wiphy_lock(wiphy); + regulatory_set_wiphy_regd_sync(wiphy, regd_copy); + wiphy_unlock(wiphy); +#else + regulatory_set_wiphy_regd_sync_rtnl(wiphy, regd_copy); +#endif /* LINUX_VERSION > 5.12.0 */ + } else { + regulatory_set_wiphy_regd(wiphy, regd_copy); + } +#else + wiphy_apply_custom_regulatory(wiphy, regd_copy); +#endif /* LINUX_VERSION > 4.0.0 */ + +exit: + MFREE(cfg->osh, regd_copy, regd_len); + return; +} + s32 wl_cfg80211_set_country_code(struct net_device *net, char *country_code, bool notify, bool user_enforced, int revinfo) @@ -10440,12 +10613,25 @@ wl_cfg80211_set_country_code(struct net_device *net, char *country_code, goto exit; } + if (wl_is_ccode_change_allowed(net) == false) { + WL_ERR(("country code change isn't allowed during AP role/NAN connected\n")); + ret = BCME_EPERM; + goto exit; + } + wl_cfg80211_cleanup_connection(net, user_enforced); + /* Store before applying - so that if event comes earlier that is handled properly */ + if (strlcpy(cfg->country, country_code, WL_CCODE_LEN) >= WLC_CNTRY_BUF_SZ) { + WL_ERR(("country code copy failed :%d\n", ret)); + goto exit; + } + ret = wldev_set_country(net, country_code, notify, revinfo); if (ret < 0) { WL_ERR(("set country Failed :%d\n", ret)); + bzero(cfg->country, sizeof(cfg->country)); goto exit; } @@ -10455,10 +10641,12 @@ wl_cfg80211_set_country_code(struct net_device *net, char *country_code, */ if (!IS_REGDOM_SELF_MANAGED(wiphy)) { regulatory_hint(wiphy, country_code); + } else { + wl_notify_regd(wiphy, country_code); } exit: - return ret; + return OSL_ERROR(ret); } #ifdef CONFIG_CFG80211_INTERNAL_REGDB @@ -10546,12 +10734,10 @@ static void wl_config_custom_regulatory(struct wiphy *wiphy) { -#if defined(WL_SELF_MANAGED_REGDOM) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) +#if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) /* Use self managed regulatory domain */ wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED | REGULATORY_IGNORE_STALE_KICKOFF; - wiphy->regd = &brcm_regdom; WL_DBG(("Self managed regdom\n")); return; #else /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */ @@ -10565,7 +10751,7 @@ void wl_config_custom_regulatory(struct wiphy *wiphy) #else /* KERNEL VER >= 3.14 */ wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ - wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); + wl_notify_regd(wiphy, NULL); WL_DBG(("apply custom regulatory\n")); #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */ } @@ -10778,13 +10964,6 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS; #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */ - /* Now we can register wiphy with cfg80211 module */ - err = wiphy_register(wdev->wiphy); - if (unlikely(err < 0)) { - WL_ERR(("Couldn not register wiphy device (%d)\n", err)); - wiphy_free(wdev->wiphy); - } - #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \ (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS) /* Workaround for a cfg80211 bug */ @@ -10798,7 +10977,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) */ #if defined(WL_SAE) || defined(WL_CLIENT_SAE) - if (wl_extsae_chip(dhd)) + if (dhd_conf_extsae_chip(dhd)) wdev->wiphy->features |= NL80211_FEATURE_SAE; #endif /* WL_SAE || WL_CLIENT_SAE */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE) @@ -10816,6 +10995,23 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev wdev->wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN; #endif /* WL_SCAN_TYPE */ + /* Now we can register wiphy with cfg80211 module */ + err = wiphy_register(wdev->wiphy); + if (unlikely(err < 0)) { + WL_ERR(("Couldn not register wiphy device (%d)\n", err)); + wiphy_free(wdev->wiphy); + return err; + } + + /* set wiphy->regd through reg_process_self_managed_hints + * need to call it after wiphy_register + * since wiphy_register adds rdev to cfg80211_rdev_list + */ + if (IS_REGDOM_SELF_MANAGED(wdev->wiphy)) { + rtnl_lock(); + wl_notify_regd(wdev->wiphy, NULL); + rtnl_unlock(); + } return err; } @@ -10840,8 +11036,7 @@ static void wl_free_wdev(struct bcm_cfg80211 *cfg) wdev->wiphy->wowlan = NULL; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */ #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */ -#if defined(WL_SELF_MANAGED_REGDOM) && \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) +#if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) /* Making regd ptr NULL, to avoid reference/freeing by regulatory unregister */ wiphy->regd = NULL; #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */ @@ -12135,7 +12330,7 @@ wl_handle_assoc_fail(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as, bool compl memcpy(&emsg, as->event_msg, sizeof(wl_event_msg_t)); ret = wl_ext_in4way_sync(ndev, STA_REASSOC_RETRY, WL_EXT_STATUS_RECONNECT, &emsg); - if (ret) + if (ret == BCME_ERROR) return 0; } wl_ext_iapsta_enable_master_if(ndev, FALSE); @@ -12291,7 +12486,13 @@ wl_handle_link_down(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as) memcpy(&emsg, as->event_msg, sizeof(wl_event_msg_t)); ret = wl_ext_in4way_sync(ndev, STA_REASSOC_RETRY, WL_EXT_STATUS_RECONNECT, &emsg); - if (ret) + if (ret == BCME_BADADDR) { + u8 *curbssid = NULL; + curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID); + if (curbssid) + (void)memcpy_s(as->addr, ETH_ALEN, curbssid, ETH_ALEN); + } + else if (ret == BCME_ERROR) return 0; } #endif @@ -12668,6 +12869,22 @@ wl_notify_connect_status_sta(struct bcm_cfg80211 *cfg, goto exit; } +#ifdef WL_ROAM_WAR + if (event_type == WLC_E_JOIN) + bzero((u8*)&cfg->roaming_bssid, ETHER_ADDR_LEN); + else if (wl_get_drv_status(cfg, CONNECTED, ndev)) { + if (event_type == WLC_E_AUTH && ntoh32(e->status) == WLC_E_STATUS_SUCCESS) + bcopy(&e->addr, &cfg->roaming_bssid, ETHER_ADDR_LEN); + else if (event_type == WLC_E_DEAUTH && + !ETHER_ISNULLADDR(&cfg->roaming_bssid.octet) && + memcmp(&e->addr, &cfg->roaming_bssid, ETHER_ADDR_LEN)) { + WL_MSG(ndev->name, "skip WLC_E_DEAUTH(%pM), roaming_bssid %pM\n", + &e->addr, &cfg->roaming_bssid); + goto exit; + } + } +#endif /* WL_ROAM_WAR */ + if (wl_get_drv_status(cfg, CONNECTING, ndev)) { assoc_state = WL_STATE_ASSOCIATING; } else if (wl_get_drv_status(cfg, CONNECTED, ndev)) { @@ -13364,7 +13581,6 @@ update_bss_info_out: return err; } -#ifdef DHD_LOSSLESS_ROAMING static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -13372,14 +13588,14 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, struct wl_connect_info *conn_info = wl_to_conn(cfg); s32 err = 0; u8 *curbssid; - chanspec_t *chanspec; + chanspec_t *chanspec, cur_chanspec; scb_val_t scbval; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \ defined(WL_COMPAT_WIRELESS) struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); struct ieee80211_channel *notify_channel = NULL; u32 freq; - u32 cur_channel, cur_chanspec, orig_channel; + u32 cur_channel, orig_channel; #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */ #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \ (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \ @@ -13420,10 +13636,13 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, cur_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(cur_chanspec)); orig_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(*chanspec)); if (dhdp->conf->chip != BCM43569_CHIP_ID) { - if ((orig_channel == cur_channel) && + if (((orig_channel == cur_channel) && memcmp(ðer_null, &cfg->last_roamed_addr, ETHER_ADDR_LEN)) && ((memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) || (memcmp(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN) == 0))) { - WL_DBG(("BSS already present, Skipping roamed event to upper layer\n")); + WL_INFORM_MEM(("BSS already present, Skipping roamed event to upper layer\n")); + WL_INFORM_MEM(("orig_chan/cur_chan=%d/%d, addr/curbssid/last_roamed_addr=%pM/%pM/%pM\n", + orig_channel, cur_channel, + (const u8*)(&e->addr), curbssid, (const u8*)(&cfg->last_roamed_addr))); goto fail; } } @@ -13457,13 +13676,15 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, } rssi = dtoh32(scbval.val); - WL_MSG(ndev->name, "%pM(ch:%3d/%sMHz) => %pM(ch:%3d/%sMHz, rssi: %3d)\n", - curbssid, orig_channel, + WL_MSG(ndev->name, "%pM(chan=%s-%d/%sMHz) => %pM(chan=%s-%d/%sMHz, rssi: %3d)\n", + curbssid, + CHSPEC2BANDSTR(*chanspec), wf_chspec_ctlchan(*chanspec), CHSPEC_IS20(*chanspec)?"20": CHSPEC_IS40(*chanspec)?"40": CHSPEC_IS80(*chanspec)?"80": CHSPEC_IS160(*chanspec)?"160":"??", - (const u8*)(&e->addr), cur_channel, + (const u8*)(&e->addr), + CHSPEC2BANDSTR(cur_chanspec), wf_chspec_ctlchan(cur_chanspec), CHSPEC_IS20(cur_chanspec)?"20": CHSPEC_IS40(cur_chanspec)?"40": CHSPEC_IS80(cur_chanspec)?"80": @@ -13504,15 +13725,20 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, DHD_STATLOG_CTRL(dhdp, ST(REASSOC_INFORM), dhd_net2idx(dhdp->info, ndev), 0); #ifdef WL_EXT_IAPSTA - wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL); + wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_ROAMED, NULL); #endif #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \ (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \ defined(WL_FILS_ROAM_OFFLD) || defined(CFG80211_ROAM_API_GE_4_12) memset(&roam_info, 0, sizeof(struct cfg80211_roam_info)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + roam_info.links[0].channel = notify_channel; + roam_info.links[0].bssid = curbssid; +#else roam_info.channel = notify_channel; roam_info.bssid = curbssid; +#endif roam_info.req_ie = conn_info->req_ie; roam_info.req_ie_len = conn_info->req_ie_len; roam_info.resp_ie = conn_info->resp_ie; @@ -13565,12 +13791,15 @@ wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, return err; fail: +#ifdef WL_EXT_IAPSTA + if (err) + wl_ext_in4way_sync(ndev, STA_NO_BTC_IN4WAY, WL_EXT_STATUS_DISCONNECTED, NULL); +#endif #ifdef DHD_LOSSLESS_ROAMING wl_del_roam_timeout(cfg); #endif /* DHD_LOSSLESS_ROAMING */ return err; } -#endif /* DHD_LOSSLESS_ROAMING */ static bool wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, @@ -13706,10 +13935,21 @@ wl_fillup_resp_params(struct bcm_cfg80211 *cfg, struct net_device *ndev, resp_params = (struct cfg80211_connect_resp_params *)params; resp_params->status = status; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + resp_params->links[0].bssid = curbssid; + resp_params->links[0].bss = CFG80211_GET_BSS(wiphy, NULL, curbssid, + ssid->SSID, ssid->SSID_len); +#else resp_params->bssid = curbssid; resp_params->bss = CFG80211_GET_BSS(wiphy, NULL, curbssid, ssid->SSID, ssid->SSID_len); - if (!resp_params->bss) { +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + if (!resp_params->links[0].bss) +#else + if (!resp_params->bss) +#endif + { WL_ERR(("null bss\n")); return BCME_ERROR; } @@ -13819,7 +14059,12 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, completed = false; sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE; } - if (!ndev->ieee80211_ptr->ssid_len) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + if (!ndev->ieee80211_ptr->u.client.ssid_len) +#else + if (!ndev->ieee80211_ptr->ssid_len) +#endif + { /* In certain cases, the delayed cfg80211 work from * disconnect context will induce race conditions in * which the ssid_len will be cleared, but dhd is in @@ -13847,10 +14092,6 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, if (completed) { WL_MSG(ndev->name, "Report connect result - connection succeeded\n"); -#ifdef WL_EXT_IAPSTA - wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL); - wl_ext_iapsta_enable_master_if(ndev, TRUE); -#endif } else { WL_MSG(ndev->name, "Report connect result - connection failed\n"); #ifdef WL_EXT_IAPSTA @@ -13900,6 +14141,13 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev, #endif /* WAPI */ } +#ifdef WL_EXT_IAPSTA + if (completed) { + wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL); + wl_ext_iapsta_enable_master_if(ndev, TRUE); + } +#endif + exit: CLR_TS(cfg, conn_start); return err; @@ -14489,19 +14737,65 @@ exit: return err; } -#ifdef CUSTOMER_HW6 +static void +wl_map_brcm_specifc_country_code(char *country_code) +{ + /* If country code is default locale, change the domain to world domain + * Default locale formats: AA, ZZ, XA-XZ, QM-QZ + */ + if (!strcmp("AA", country_code) || !strcmp("ZZ", country_code) || + ((country_code[0] == 'X') && (country_code[1] >= 'A') && + (country_code[1] <= 'Z')) || ((country_code[0] == 'Q') && + (country_code[1] >= 'M') && (country_code[1] <= 'Z'))) { + WL_DBG(("locale mapped to world domain\n")); + country_code[0] = '0'; + country_code[1] = '0'; + } +} + static s32 wl_cfg80211_ccode_evt_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *event, void *data) { + dhd_pub_t *dhd = cfg->pub; s32 err = 0; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + char country_str[WLC_CNTRY_BUF_SZ] = { 0 }; + struct net_device *dev = bcmcfg_to_prmry_ndev(cfg); + + if (strlcpy(country_str, data, WL_CCODE_LEN + 1) >= WLC_CNTRY_BUF_SZ) { + return -EINVAL; + } + + if (strncmp(cfg->country, country_str, WL_CCODE_LEN) == 0) { + /* If country code is updated from command context, skip wiphy update */ + WL_MSG(dev->name, "No change in country (%s)\n", country_str); + return BCME_OK; + } + + WL_MSG(dev->name, "Updating new country %s\n", country_str); + dhd_conf_country(dhd, "country", country_str); + /* Indicate to upper layer for regdom change */ - WL_INFORM_MEM(("Received country code change event\n")); err = wl_update_wiphybands(cfg, true); + if (err != BCME_OK) { + WL_ERR(("update wiphy bands failed\n")); + return err; + } + + wl_map_brcm_specifc_country_code(country_str); + + if (!IS_REGDOM_SELF_MANAGED(wiphy)) { + err = regulatory_hint(wiphy, country_str); + if (err) { + WL_ERR(("update country change failed\n")); + return err; + } + WL_DBG_MEM(("regulatory hint notified for ccode change\n")); + } return err; } -#endif /* CUSTOMER_HW6 */ static void wl_init_conf(struct wl_conf *conf) { @@ -14605,9 +14899,7 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) cfg->evt_handler[WLC_E_ADPS] = wl_adps_event_handler; #endif /* WL_BAM */ cfg->evt_handler[WLC_E_PSK_SUP] = wl_cfg80211_sup_event_handler; -#ifdef CUSTOMER_HW6 cfg->evt_handler[WLC_E_COUNTRY_CODE_CHANGED] = wl_cfg80211_ccode_evt_handler; -#endif /* CUSTOMER_HW6 */ #ifdef WL_BCNRECV cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler; #endif /* WL_BCNRECV */ @@ -14628,9 +14920,11 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) cfg->evt_handler[WLC_E_BSS_LOAD] = wl_cfg80211_bssload_report_event_handler; #endif /* WL_CHAN_UTIL */ #ifdef WL_TWT - cfg->evt_handler[WLC_E_TWT_SETUP] = wl_notify_twt_event; - cfg->evt_handler[WLC_E_TWT_TEARDOWN] = wl_notify_twt_event; - cfg->evt_handler[WLC_E_TWT_INFO_FRM] = wl_notify_twt_event; + cfg->evt_handler[WLC_E_TWT] = wl_notify_twt_event; +#else +#ifdef WL_TWT_HAL_IF + cfg->evt_handler[WLC_E_TWT] = wl_cfgvendor_notify_twt_event; +#endif /* WL_TWT_HAL_IF */ #endif /* WL_TWT */ #ifdef WL_CLIENT_SAE cfg->evt_handler[WLC_E_JOIN_START] = wl_notify_start_auth; @@ -15010,7 +15304,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev = ndev_to_wdev(dev); if (!wdev) { - WL_ERR(("wdev null. Do nothing\n")); + WL_DBG(("wdev(%s) null. Do nothing\n", dev->name)); return NOTIFY_DONE; } @@ -15662,7 +15956,7 @@ wl_cfg80211_net_attach(struct net_device *primary_ndev) } #ifdef WL_STATIC_IF /* Register dummy n/w iface. FW init will happen only from dev_open */ -#ifdef WLEASYMESH +#ifdef WLDWDS ntype = NL80211_IFTYPE_AP; #else ntype = NL80211_IFTYPE_STATION; @@ -16049,7 +16343,7 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) #ifdef OEM_ANDROID if (cfg->event_workq == NULL) { - WL_ERR(("Event handler is not created\n")); + WL_ERR(("Event handler is not created (%s)\n", bcmevent_get_name(event_type))); return; } #endif /* OEM_ANDROID */ @@ -16888,13 +17182,7 @@ static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify) if (notify) { if (!IS_REGDOM_SELF_MANAGED(wiphy)) { WL_UPDATE_CUSTOM_REGULATORY(wiphy); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) - rtnl_unlock(); -#endif - wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) - rtnl_lock(); -#endif + wl_notify_regd(wiphy, NULL); } } @@ -16955,6 +17243,10 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) /* Start the event logging */ wl_add_remove_eventmsg(ndev, WLC_E_TRACE, TRUE); #endif /* SHOW_LOGTRACE */ +#if defined(BCMDBUS) + if (!dhd->dhd_console_ms) + wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE); +#endif (void)memcpy_s(wdev->wiphy->perm_addr, ETHER_ADDR_LEN, bcmcfg_to_prmry_ndev(cfg)->perm_addr, ETHER_ADDR_LEN); @@ -17111,6 +17403,77 @@ static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg) return err; } +#ifdef BCMDBUS +s32 +__wl_cfg80211_up_resume(dhd_pub_t *dhd) +{ + struct net_device *ndev = dhd_linux_get_primary_netdev(dhd); + struct bcm_cfg80211 *cfg; + struct wireless_dev *wdev; + s32 err = 0; +#ifdef WL_HOST_BAND_MGMT + s32 ret = 0; +#endif /* WL_HOST_BAND_MGMT */ + u16 wl_iftype = 0; + u16 wl_mode = 0; + + WL_DBG(("In\n")); + + if (!ndev) + return -EINVAL; + cfg = wl_get_cfg(ndev); + wdev = ndev->ieee80211_ptr; + if (!cfg || !wdev) + return -EINVAL; + +#if defined(BCMDONGLEHOST) + err = dhd_config_dongle(cfg); + if (unlikely(err)) + return err; +#endif /* defined(BCMDONGLEHOST) */ + +#ifdef SHOW_LOGTRACE + /* Start the event logging */ + wl_add_remove_eventmsg(ndev, WLC_E_TRACE, TRUE); +#endif /* SHOW_LOGTRACE */ +#if defined(BCMDBUS) + if (!dhd->dhd_console_ms) + wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE); +#endif + + if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) { + return -EINVAL; + } + if (!dhd->fw_preinit) { + err = wl_config_infra(cfg, ndev, wl_iftype); + if (unlikely(err && err != -EINPROGRESS)) { + WL_ERR(("wl_config_infra failed\n")); + if (err == -1) { + WL_ERR(("return error %d\n", err)); + return err; + } + } + } + +#ifdef WL_HOST_BAND_MGMT + /* By default the curr_band is initialized to BAND_AUTO */ + if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) { + if (ret == BCME_UNSUPPORTED) { + /* Don't fail the initialization, lets just + * fall back to the original method + */ + WL_ERR(("WL_HOST_BAND_MGMT defined, " + "but roam_band iovar not supported \n")); + } else { + WL_ERR(("roam_band failed. ret=%d", ret)); + err = -1; + } + } +#endif /* WL_HOST_BAND_MGMT */ + return err; +} +#endif /* BCMDBUS */ + static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) { s32 err = 0; @@ -17259,7 +17622,12 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); struct wireless_dev *wdev = ndev->ieee80211_ptr; struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid, - wdev->ssid, wdev->ssid_len); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + wdev->u.client.ssid, wdev->u.client.ssid_len +#else + wdev->ssid, wdev->ssid_len +#endif + ); BCM_REFERENCE(bss); @@ -17418,7 +17786,7 @@ s32 wl_cfg80211_up(struct net_device *net) if (init_roam_cache(cfg, ioctl_version) == 0) { /* Enable support for Roam cache */ cfg->rcc_enabled = true; - WL_ERR(("Roam channel cache enabled\n")); + WL_MSG(net->name, "Roam channel cache enabled\n"); } else { WL_ERR(("Failed to enable RCC.\n")); } @@ -19519,7 +19887,7 @@ wl_print_fw_ie_data(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssid bssidx, &cfg->ioctl_buf_sync); if (ret == BCME_OK) { ies = (vndr_ie_buf_t *)cfg->ioctl_buf; - WL_INFORM_MEM(("FW IE count:%d ", ies->iecount)); + WL_INFORM_MEM(("FW IE count:%d\n", ies->iecount)); #ifdef GET_FW_IE_DATA if (wl_dbg_level & WL_DBG_DBG) { int i = 0; @@ -22759,7 +23127,7 @@ wl_cfg80211_mgmt_auth_tx(struct net_device *dev, bcm_struct_cfgdev *cfgdev, ack = false; } else { err = wldev_iovar_setbuf(dev, "assoc_mgr_cmd", ambuf, param_len, - cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync); + cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync); if (unlikely(err)) { WL_ERR(("Failed to send auth(%d)\n", err)); ack = false; diff --git a/bcmdhd.101.10.361.x/wl_cfg80211.h b/bcmdhd.101.10.361.x/wl_cfg80211.h index 52faf2d..626fdc8 100755 --- a/bcmdhd.101.10.361.x/wl_cfg80211.h +++ b/bcmdhd.101.10.361.x/wl_cfg80211.h @@ -332,6 +332,13 @@ extern char *dhd_dbg_get_system_timestamp(void); #endif /* SUPPORT_AP_RADIO_PWRSAVE */ #ifdef BCMWAPI_WPI +#ifdef CFG80211_WAPI_BKPORT +#define IS_WAPI_VER(version) (version == NL80211_WAPI_VERSION_1) +#undef WLAN_AKM_SUITE_WAPI_PSK +#define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC13 +#undef WLAN_AKM_SUITE_WAPI_CERT +#define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC14 +#else #ifdef OEM_ANDROID #undef NL80211_WAPI_VERSION_1 #define NL80211_WAPI_VERSION_1 0 @@ -354,6 +361,7 @@ extern char *dhd_dbg_get_system_timestamp(void); #define NL80211_WAPI_VERSION_1 1 << 2 #define IS_WAPI_VER(version) (version & NL80211_WAPI_VERSION_1) #endif /* OEM_ANDROID */ +#endif /* CFG80211_WAPI_BKPORT */ #endif /* BCMWAPI_WPI */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) @@ -1955,6 +1963,13 @@ struct bcm_cfg80211 { bool p2p_6g_enabled; /* P2P 6G support enabled */ #endif /* WL_P2P_6G */ u32 halpid; + u8 country[WLC_CNTRY_BUF_SZ]; +#ifdef BCMDBUS + bool bus_resuming; +#endif /* BCMDBUS */ +#ifdef WL_ROAM_WAR + struct ether_addr roaming_bssid; +#endif /* WL_ROAM_WAR */ #if defined(RSSIAVG) wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl; @@ -1965,6 +1980,7 @@ struct bcm_cfg80211 { int autochannel; int best_2g_ch; int best_5g_ch; + int best_6g_ch; }; /* Max auth timeout allowed in case of EAP is 70sec, additional 5 sec for @@ -3078,6 +3094,14 @@ extern s32 wl_handle_auth_event(struct bcm_cfg80211 *cfg, struct net_device *nde extern bool wl_customer6_legacy_chip_check(struct bcm_cfg80211 *cfg, struct net_device *ndev); #endif /* CUSTOMER_HW6 */ +#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF) +extern s32 wl_cfgvendor_notify_twt_event(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +#endif /* !WL_TWT && WL_TWT_HAL_IF */ +#ifdef BCMDBUS +s32 +__wl_cfg80211_up_resume(dhd_pub_t *dhd); +#endif /* BCMDBUS */ void wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable); s32 wl_handle_join(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc_info_t *assoc_info); diff --git a/bcmdhd.101.10.361.x/wl_cfgnan.h b/bcmdhd.101.10.361.x/wl_cfgnan.h index be6a717..703e645 100755 --- a/bcmdhd.101.10.361.x/wl_cfgnan.h +++ b/bcmdhd.101.10.361.x/wl_cfgnan.h @@ -217,6 +217,7 @@ #define NAN_RNG_GEOFENCE_MAX_RETRY_CNT 3u +#define NAN_MAX_CHANNEL_INFO_SUPPORTED 4u /* * Discovery Beacon Interval config, * Default value is 128 msec in 2G DW and 176 msec in 2G/5G DW. @@ -384,6 +385,17 @@ typedef struct nan_mac_list { uint8 *list; } nan_mac_list_t; +typedef struct nan_channel_info { + uint32 channel; + uint32 bandwidth; + uint32 nss; +} nan_channel_info_t; + +typedef struct nan_ndl_sched_info { + uint32 num_channels; + nan_channel_info_t channel_info[NAN_MAX_CHANNEL_INFO_SUPPORTED]; +} nan_ndl_sched_info_t; + typedef struct wl_nan_sid_beacon_tune { uint8 sid_enable; /* flag for sending service id in beacon */ uint8 sid_count; /* Limit for number of SIDs to be included in Beacons */ @@ -946,7 +958,12 @@ typedef enum { NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL = 224, NAN_ATTRIBUTE_NSS = 225, NAN_ATTRIBUTE_ENABLE_RANGING = 226, - NAN_ATTRIBUTE_DW_EARLY_TERM = 227 + NAN_ATTRIBUTE_DW_EARLY_TERM = 227, + NAN_ATTRIBUTE_CHANNEL_INFO = 228, + NAN_ATTRIBUTE_NUM_CHANNELS = 229, + NAN_ATTRIBUTE_INSTANT_MODE_ENABLE = 230, + NAN_ATTRIBUTE_INSTANT_COMM_CHAN = 231, + NAN_ATTRIBUTE_MAX = 232 } NAN_ATTRIBUTE; enum geofence_suspend_reason { diff --git a/bcmdhd.101.10.361.x/wl_cfgp2p.c b/bcmdhd.101.10.361.x/wl_cfgp2p.c index 01a04f0..aec9646 100755 --- a/bcmdhd.101.10.361.x/wl_cfgp2p.c +++ b/bcmdhd.101.10.361.x/wl_cfgp2p.c @@ -705,7 +705,12 @@ wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg) BCM_REFERENCE(ndev); CFGP2P_DBG(("enter\n")); - if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0) { +#ifdef BCMDBUS + if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0 && !cfg->bus_resuming) +#else + if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0) +#endif /* BCMDBUS */ + { CFGP2P_ERR(("do nothing, already initialized\n")); goto exit; } @@ -732,6 +737,9 @@ wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg) * so that time, the ifidx returned in WLC_E_IF should be used for populating * the netinfo */ +#ifdef BCMDBUS + if (!cfg->bus_resuming) +#endif /* BCMDBUS */ ret = wl_alloc_netinfo(cfg, NULL, cfg->p2p_wdev, WL_IF_TYPE_STA, 0, bssidx, 0); if (unlikely(ret)) { goto exit; @@ -822,7 +830,12 @@ wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, } #endif /* WL_IFACE_MGMT */ - if (wl_get_p2p_status(cfg, DISCOVERY_ON)) { +#ifdef BCMDBUS + if (!cfg->bus_resuming && (wl_get_p2p_status(cfg, DISCOVERY_ON))) +#else + if (wl_get_p2p_status(cfg, DISCOVERY_ON)) +#endif /* BCMDBUS */ + { CFGP2P_DBG((" DISCOVERY is already initialized, we have nothing to do\n")); goto set_ie; } @@ -2403,7 +2416,7 @@ wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg) #endif /* Register with a dummy MAC addr */ - memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); + dev_addr_set(net, temp_addr); #ifndef WL_NEWCFG_PRIVCMD_SUPPORT wdev->wiphy = cfg->wdev->wiphy; @@ -2622,8 +2635,7 @@ wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg) #if defined(WL_NEWCFG_PRIVCMD_SUPPORT) if (cfg->p2p_net) - memcpy(cfg->p2p_net->dev_addr, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE), - ETHER_ADDR_LEN); + dev_addr_set(cfg->p2p_net, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE)); #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */ /* store p2p wdev ptr for further reference. */ @@ -2671,7 +2683,7 @@ wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) cfg->p2p_prb_noti = false; #endif - CFGP2P_DBG(("P2P interface started\n")); + printf("P2P interface started\n"); exit: return ret; @@ -2719,7 +2731,7 @@ wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) p2p_on(cfg) = false; - CFGP2P_DBG(("Exit. P2P interface stopped\n")); + printf("Exit. P2P interface stopped\n"); return; } @@ -2809,3 +2821,36 @@ wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request) } return false; } + +#ifdef BCMDBUS +int +wl_cfgp2p_start_p2p_device_resume(dhd_pub_t *dhd) +{ + int ret = 0; +#ifdef WL_CFG80211_P2P_DEV_IF + struct net_device *primary_ndev = dhd_linux_get_primary_netdev(dhd); + struct bcm_cfg80211 *cfg; + struct wiphy *wiphy; + + if (!primary_ndev) + return -EINVAL; + cfg = wl_get_cfg(primary_ndev); + if (!cfg) + return -EINVAL; + + RETURN_EIO_IF_NOT_UP(cfg); + if (!p2p_on(cfg)) + return -EINVAL; + + rtnl_lock(); + wiphy = bcmcfg_to_wiphy(cfg); + cfg->bus_resuming = TRUE; + ret = wl_cfgp2p_start_p2p_device(wiphy, cfg->wdev); + cfg->bus_resuming = FALSE; + printf("P2P interface resumed\n"); + rtnl_unlock(); +#endif + + return ret; +} +#endif /* BCMDBUS */ diff --git a/bcmdhd.101.10.361.x/wl_cfgp2p.h b/bcmdhd.101.10.361.x/wl_cfgp2p.h index 58a161a..33a3c1f 100755 --- a/bcmdhd.101.10.361.x/wl_cfgp2p.h +++ b/bcmdhd.101.10.361.x/wl_cfgp2p.h @@ -485,4 +485,9 @@ wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request); * instead of channel in actframe iovar. */ #define FW_MAJOR_VER_ACTFRAME_CHSPEC 14 + +#ifdef BCMDBUS +int +wl_cfgp2p_start_p2p_device_resume(dhd_pub_t *dhd); +#endif /* BCMDBUS */ #endif /* _wl_cfgp2p_h_ */ diff --git a/bcmdhd.101.10.361.x/wl_cfgscan.c b/bcmdhd.101.10.361.x/wl_cfgscan.c index 9287940..606f327 100755 --- a/bcmdhd.101.10.361.x/wl_cfgscan.c +++ b/bcmdhd.101.10.361.x/wl_cfgscan.c @@ -640,11 +640,11 @@ wl_inform_bss(struct bcm_cfg80211 *cfg) if (cfg->autochannel && ndev) { #if defined(BSSCACHE) - wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, ioctl_version, - &cfg->best_2g_ch, &cfg->best_5g_ch); + wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, + &cfg->best_2g_ch, &cfg->best_5g_ch, &cfg->best_6g_ch); #else - wl_ext_get_best_channel(ndev, bss_list, ioctl_version, - &cfg->best_2g_ch, &cfg->best_5g_ch); + wl_ext_get_best_channel(ndev, bss_list, + &cfg->best_2g_ch, &cfg->best_5g_ch, &cfg->best_6g_ch); #endif } @@ -1576,29 +1576,24 @@ chanspec_t wl_freq_to_chanspec(int freq) static void wl_cfgscan_populate_scan_channel(struct bcm_cfg80211 *cfg, struct ieee80211_channel **channels, u32 n_channels, - u16 *channel_list, u32 target_channel) + u16 *channel_list, struct wl_chan_info *chan_info) { - u32 i = 0; - u32 chanspec = 0; - u32 channel; + u32 i, chanspec = 0; for (i=0; icenter_freq); - if (channel != target_channel) - continue; - if (!dhd_conf_match_channel(cfg->pub, channel)) - return; - chanspec = wl_freq_to_chanspec(channels[i]->center_freq); if (chanspec == INVCHANSPEC) { WL_ERR(("Invalid chanspec! Skipping channel\n")); continue; } - - channel_list[0] = chanspec; - break; + if (chan_info->band == CHSPEC2WLC_BAND(chanspec) && + chan_info->chan == wf_chspec_ctlchan(chanspec)) { + channel_list[0] = chanspec; + break; + } } - WL_SCAN(("chan: %d, chanspec: %x\n", target_channel, chanspec)); + WL_SCAN(("chan: %s-%d, chanspec: %x\n", + WLCBAND2STR(chan_info->band), chan_info->chan, chanspec)); } #endif @@ -1768,6 +1763,7 @@ wl_scan_prep(struct bcm_cfg80211 *cfg, struct net_device *ndev, void *scan_param struct cfg80211_scan_request *request) { #ifdef SCAN_SUPPRESS + struct wl_chan_info chan_info; u32 channel; #endif wl_scan_params_t *params = NULL; @@ -1847,14 +1843,14 @@ wl_scan_prep(struct bcm_cfg80211 *cfg, struct net_device *ndev, void *scan_param cur_offset = channel_offset; /* Copy channel array if applicable */ #ifdef SCAN_SUPPRESS - channel = wl_ext_scan_suppress(ndev, scan_params, cfg->scan_params_v2); + channel = wl_ext_scan_suppress(ndev, scan_params, cfg->scan_params_v2, &chan_info); if (channel) { n_channels = 1; if ((n_channels > 0) && chan_list) { if (len >= (scan_param_size + (n_channels * sizeof(u16)))) { wl_cfgscan_populate_scan_channel(cfg, request->channels, request->n_channels, - chan_list, channel); + chan_list, &chan_info); cur_offset += (n_channels * (sizeof(u16))); } } @@ -2644,8 +2640,14 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } #ifdef WL_EXT_IAPSTA - if (wl_ext_in4way_sync(ndev, STA_FAKE_SCAN_IN_CONNECT, WL_EXT_STATUS_SCANNING, NULL)) { + err = wl_ext_in4way_sync(ndev, STA_FAKE_SCAN_IN_CONNECT, WL_EXT_STATUS_SCANNING, NULL); + if (err) { + wl_event_msg_t msg; mutex_lock(&cfg->scan_sync); + bzero(&msg, sizeof(wl_event_msg_t)); + msg.event_type = hton32(WLC_E_ESCAN_RESULT); + msg.status = hton32(WLC_E_STATUS_SUCCESS); + wl_cfg80211_event(ndev, &msg, NULL); goto scan_success; } #endif @@ -5562,7 +5564,7 @@ wl_get_assoc_channels(struct bcm_cfg80211 *cfg, } #endif /* ESCAN_CHANNEL_CACHE */ - WL_DBG_MEM(("channel cnt:%d\n", info->chan_cnt)); + WL_SCAN(("channel cnt:%d\n", info->chan_cnt)); return BCME_OK; } @@ -5584,7 +5586,7 @@ wl_cfgscan_is_dfs_set(wifi_band band) s32 wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band, - uint16 *list, uint32 *num_channels) + uint32 *list, uint32 *num_channels) { s32 err = BCME_OK; uint32 i, freq, list_count, count = 0; @@ -5606,13 +5608,16 @@ wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band, list_count = ((wl_chanspec_list_v1_t *)list)->count; for (i = 0; i < list_count; i++) { chspec = dtoh32(((wl_chanspec_list_v1_t *)list)->chspecs[i].chanspec); + if (!CHSPEC_IS20(chspec)) { + continue; + } chaninfo = dtoh32(((wl_chanspec_list_v1_t *)list)->chspecs[i].chaninfo); freq = wl_channel_to_frequency(wf_chspec_ctlchan(chspec), CHSPEC_BAND(chspec)); if (((band & WIFI_BAND_BG) && CHSPEC_IS2G(chspec)) || ((band & WIFI_BAND_6GHZ) && CHSPEC_IS6G(chspec))) { /* add 2g/6g channels */ - list[i] = freq; + list[count] = freq; count++; } /* handle 5g separately */ @@ -5627,7 +5632,7 @@ wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band, continue; } - list[i] = freq; + list[count] = freq; count++; } } diff --git a/bcmdhd.101.10.361.x/wl_cfgscan.h b/bcmdhd.101.10.361.x/wl_cfgscan.h index 7488332..edc3e0a 100755 --- a/bcmdhd.101.10.361.x/wl_cfgscan.h +++ b/bcmdhd.101.10.361.x/wl_cfgscan.h @@ -173,6 +173,6 @@ typedef enum { extern bool wl_cfgscan_is_dfs_set(wifi_band band); extern s32 wl_cfgscan_get_band_freq_list(struct bcm_cfg80211 *cfg, int band, - uint16 *list, uint32 *num_channels); + uint32 *list, uint32 *num_channels); #endif /* DHD_GET_VALID_CHANNELS */ #endif /* _wl_cfgscan_h_ */ diff --git a/bcmdhd.101.10.361.x/wl_cfgvendor.c b/bcmdhd.101.10.361.x/wl_cfgvendor.c index 62d3496..ab7e073 100755 --- a/bcmdhd.101.10.361.x/wl_cfgvendor.c +++ b/bcmdhd.101.10.361.x/wl_cfgvendor.c @@ -469,7 +469,11 @@ wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy, iter_cnt_to_send -= cnt; cache->tot_consumed += cnt; /* Push the data to the skb */ +#ifdef ANDROID13_KERNEL515_BKPORT + nla_put_nohdr(skb, cnt * sizeof(wifi_gscan_result_t), ptr); +#else nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr); +#endif if (cache->tot_consumed == cache->tot_count) { cache = cache->next; } @@ -1210,7 +1214,7 @@ wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy, { int err = 0, type, band; struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); - uint16 *reply = NULL; + uint32 *reply = NULL; uint32 reply_len = 0, num_channels, mem_needed; struct sk_buff *skb; dhd_pub_t *dhdp; @@ -2808,7 +2812,7 @@ wl_cfgvendor_priv_string_handler(struct wiphy *wiphy, ret = dhd_cfgvendor_priv_string_handler(cfg, wdev, nlioc, buf); if (ret) { - WL_ERR(("dhd_cfgvendor returned error %d", ret)); + WL_ERR(("dhd_cfgvendor returned error %d\n", ret)); vfree(buf); return ret; } @@ -7145,7 +7149,7 @@ static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy, dtoh32(cca_result->secs[0].congest_obss), dtoh32(cca_result->secs[0].interference))); } else { - WL_TRACE(("cca_get_stats is unsupported \n")); + WL_INFORM(("cca_get_stats is unsupported \n")); } /* If cca_get_stats is unsupported, cca_busy_time has zero value as initial value */ @@ -8520,12 +8524,12 @@ static int wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy *wiphy, #endif /* DBG_PKT_MON */ #ifdef KEEP_ALIVE +/* max size of IP packet for keep alive */ +#define MKEEP_ALIVE_IP_PKT_MAX 256 + static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) { - /* max size of IP packet for keep alive */ - const int MKEEP_ALIVE_IP_PKT_MAX = 256; - int ret = BCME_OK, rem, type; uint8 mkeep_alive_id = 0; uint8 *ip_pkt = NULL; @@ -8645,6 +8649,15 @@ static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_de #endif /* KEEP_ALIVE */ #if defined(PKT_FILTER_SUPPORT) && defined(APF) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) +const struct nla_policy apf_atrribute_policy[APF_ATTRIBUTE_MAX] = { + [APF_ATTRIBUTE_VERSION] = { .type = NLA_U32 }, + [APF_ATTRIBUTE_MAX_LEN] = { .type = NLA_U32 }, + [APF_ATTRIBUTE_PROGRAM] = { .type = NLA_BINARY }, + [APF_ATTRIBUTE_PROGRAM_LEN] = { .type = NLA_U32 }, +}; +#endif /* LINUX_VERSION >= 5.3 */ + static int wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int len) @@ -9033,247 +9046,1405 @@ exit: } #endif /* WL_SAR_TX_POWER */ -static struct wiphy_vendor_command wl_vendor_cmds [] = { - { - { - .vendor_id = OUI_BRCM, - .subcmd = BRCM_VENDOR_SCMD_PRIV_STR - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_priv_string_handler - }, -#ifdef BCM_PRIV_CMD_SUPPORT - { - { - .vendor_id = OUI_BRCM, - .subcmd = BRCM_VENDOR_SCMD_BCM_STR - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_priv_bcm_handler - }, -#endif /* BCM_PRIV_CMD_SUPPORT */ -#if defined(WL_SAE) || defined(WL_CLIENT_SAE) - { - { - .vendor_id = OUI_BRCM, - .subcmd = BRCM_VENDOR_SCMD_BCM_PSK - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_sae_password - }, -#endif /* WL_SAE || WL_CLIENT_SAE */ - { - { - .vendor_id = OUI_BRCM, - .subcmd = BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_connect_params_handler - }, - { - { - .vendor_id = OUI_BRCM, - .subcmd = BRCM_VENDOR_SCMD_SET_START_AP_PARAMS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_start_ap_params_handler - }, -#ifdef GSCAN_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_gscan_get_capabilities - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_scan_cfg - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_batch_scan_cfg - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_initiate_gscan - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_enable_full_scan_result - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_HOTLIST - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_hotlist_cfg - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_gscan_get_batch_results - }, -#endif /* GSCAN_SUPPORT */ -#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_gscan_get_channel_list - }, -#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ -#ifdef RTT_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_SET_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_set_config - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_CANCEL_CONFIG - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_cancel_config - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_GETCAPABILITY - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_get_capability - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_GETAVAILCHANNEL - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_get_responder_info - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_SET_RESPONDER - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_set_responder - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = RTT_SUBCMD_CANCEL_RESPONDER - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_rtt_cancel_responder - }, -#endif /* RTT_SUPPORT */ - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_get_feature_set - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_get_feature_set_matrix - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_RANDOM_MAC_OUI - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_rand_mac_oui - }, -#ifdef CUSTOM_FORCE_NODFS_FLAG - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_NODFS_CHANNELS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_nodfs_flag - }, -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = ANDR_WIFI_SET_COUNTRY - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_country - }, -#ifdef LINKSTAT_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = LSTATS_SUBCMD_GET_INFO - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_lstats_get_info - }, -#endif /* LINKSTAT_SUPPORT */ +#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF) +static int +wl_cfgvendor_twt_setup(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + wl_twt_config_t val; + s32 bw; + s32 type, rem_attr; + u8 mybuf[WLC_IOCTL_SMLEN] = {0}; + u8 resp_buf[WLC_IOCTL_SMLEN] = {0}; + const struct nlattr *iter; + uint8 *rem = mybuf; + uint16 rem_len = sizeof(mybuf); + + bzero(&val, sizeof(val)); + val.version = WL_TWT_SETUP_VER; + val.length = sizeof(val.version) + sizeof(val.length); + + /* Default values, Override Below */ + val.desc.flow_flags = 0; + val.desc.wake_time_h = 0xFFFFFFFF; + val.desc.wake_time_l = 0xFFFFFFFF; + val.desc.wake_int_min = 0xFFFFFFFF; + val.desc.wake_int_max = 0xFFFFFFFF; + val.desc.wake_dur_min = 0xFFFFFFFF; + val.desc.wake_dur_max = 0xFFFFFFFF; + val.desc.avg_pkt_num = 0xFFFFFFFF; + val.desc.avg_pkt_size = 0xFFFFFFFF; + + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + switch (type) { + case ANDR_TWT_ATTR_CONFIG_ID: + /* Config ID */ + val.desc.configID = nla_get_u8(iter); + break; + case ANDR_TWT_ATTR_NEGOTIATION_TYPE: + /* negotiation_type */ + val.desc.negotiation_type = nla_get_u8(iter); + break; + case ANDR_TWT_ATTR_TRIGGER_TYPE: + /* Trigger Type */ + if (nla_get_u8(iter) == 1) { + val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER; + } + break; + case ANDR_TWT_ATTR_WAKE_DURATION: + /* Wake Duration */ + val.desc.wake_dur = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKE_INTERVAL: + /* Wake interval */ + val.desc.wake_int = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKETIME_OFFSET: + /* Wake Time parameter */ + val.desc.wake_time_h = 0; + val.desc.wake_time_l = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKE_INTERVAL_MIN: + /* Minimum allowed Wake interval */ + val.desc.wake_int_min = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKE_INTERVAL_MAX: + /* Max Allowed Wake interval */ + val.desc.wake_int_max = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKE_DURATION_MIN: + /* Minimum allowed Wake duration */ + val.desc.wake_dur_min = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_WAKE_DURATION_MAX: + /* Maximum allowed Wake duration */ + val.desc.wake_dur_max = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_AVG_PKT_NUM: + /* Average number of packets */ + val.desc.avg_pkt_num = nla_get_u32(iter); + break; + case ANDR_TWT_ATTR_AVG_PKT_SIZE: + /* Average packets size */ + val.desc.avg_pkt_size = nla_get_u32(iter); + break; + default: + WL_ERR(("Invalid setup attribute type %d\n", type)); + break; + } + } -#ifdef GSCAN_SUPPORT - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_epno_cfg + bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG, + sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); + if (bw != BCME_OK) { + goto exit; + } - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_lazy_roam_cfg + bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt", + mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL); + if (bw < 0) { + WL_ERR(("twt config set failed. ret:%d\n", bw)); + } else { + WL_INFORM(("twt config setup succeeded, config ID %d " + "Negotiation type %d flow flags %d\n", val.desc.configID, + val.desc.negotiation_type, val.desc.flow_flags)); + } - }, - { - { - .vendor_id = OUI_GOOGLE, - .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM - }, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, +exit: + return bw; +} + +static int +wl_cfgvendor_twt_teardown(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + wl_twt_teardown_t val; + s32 bw; + s32 type, rem_attr; + u8 mybuf[WLC_IOCTL_SMLEN] = {0}; + u8 res_buf[WLC_IOCTL_SMLEN] = {0}; + const struct nlattr *iter; + uint8 *rem = mybuf; + uint16 rem_len = sizeof(mybuf); + + bzero(&val, sizeof(val)); + val.version = WL_TWT_TEARDOWN_VER; + val.length = sizeof(val.version) + sizeof(val.length); + + /* Default values, Override Below */ + val.teardesc.flow_id = 0xFF; + val.teardesc.bid = 0xFF; + + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + switch (type) { + case ANDR_TWT_ATTR_CONFIG_ID: + /* Config ID */ + val.configID = nla_get_u8(iter); + break; + case ANDR_TWT_ATTR_NEGOTIATION_TYPE: + /* negotiation_type */ + val.teardesc.negotiation_type = nla_get_u8(iter); + break; + case ANDR_TWT_ATTR_ALL_TWT: + /* all twt */ + val.teardesc.alltwt = nla_get_u8(iter); + break; + default: + WL_ERR(("Invalid teardown attribute type %d\n", type)); + break; + } + } + + bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN, + sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); + if (bw != BCME_OK) { + goto exit; + } + + bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt", + mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL); + if (bw < 0) { + WL_ERR(("twt teardown failed. ret:%d\n", bw)); + } else { + WL_INFORM(("twt teardown succeeded, config ID %d " + "Negotiation type %d alltwt %d\n", val.configID, + val.teardesc.negotiation_type, val.teardesc.alltwt)); + } + +exit: + return bw; +} + +static int +wl_cfgvendor_twt_info_frame(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + wl_twt_info_t val; + int bw; + s32 type, rem_attr; + const struct nlattr *iter; + u8 mybuf[WLC_IOCTL_SMLEN] = {0}; + u8 res_buf[WLC_IOCTL_SMLEN] = {0}; + uint8 *rem = mybuf; + uint16 rem_len = sizeof(mybuf); + uint32 val32 = 0; + + bzero(&val, sizeof(val)); + val.version = WL_TWT_INFO_VER; + val.length = sizeof(val.version) + sizeof(val.length); + + /* Default values, Override Below */ + val.infodesc.flow_id = 0xFF; + val.desc.next_twt_h = 0xFFFFFFFF; + val.desc.next_twt_l = 0xFFFFFFFF; + + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + if (type == ANDR_TWT_ATTR_CONFIG_ID) { + /* Config ID */ + val.configID = nla_get_u8(iter); + } else if (type == ANDR_TWT_ATTR_RESUME_TIME) { + /* Resume offset */ + val32 = nla_get_u32(iter); + if (!((val32 == 0) || (val32 == -1))) { + val.infodesc.next_twt_h = 0; + val.infodesc.next_twt_l = val32; + val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME; + } + } else if (type == ANDR_TWT_ATTR_ALL_TWT) { + /* all twt */ + val32 = (uint32)nla_get_u8(iter); + if (val32) { + val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT; + } + } else { + WL_ERR(("Invalid info frame attribute type %d\n", type)); + } + } + + bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO, + sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32); + if (bw != BCME_OK) { + goto exit; + } + + bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt", + mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL); + if (bw < 0) { + WL_ERR(("twt info frame failed. ret:%d\n", bw)); + } else { + WL_INFORM(("twt info frame succeeded, config ID %d\n", val.configID)); + } + +exit: + return bw; +} + +static int +wl_cfgvendor_twt_stats_update_v2(struct wiphy *wiphy, wl_twt_stats_v2_t *stats) +{ + u32 i; + wl_twt_peer_stats_v2_t *peer_stats; + struct sk_buff *skb; + int32 mem_needed; + int ret = BCME_OK; + + mem_needed = BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed)); + ret = -ENOMEM; + goto fail; + } + + ret = nla_put_u32(skb, ANDR_TWT_ATTR_NUM_PEER_STATS, stats->num_stats); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_NUM_PEER_STATS, ret:%d\n", ret)); + goto fail; + } + + for (i = 0; i < stats->num_stats; i++) { + peer_stats = &stats->peer_stats_list[i]; + + WL_INFORM_MEM(("%u %u %u %u %u", + peer_stats->eosp_dur_avg, peer_stats->tx_pkts_avg, peer_stats->rx_pkts_avg, + peer_stats->tx_pkt_sz_avg, peer_stats->rx_pkt_sz_avg)); + ret = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, peer_stats->configID); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_CONFIG_ID, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_NUM_TX, peer_stats->tx_pkts_avg); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_NUM_TX, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_SIZE_TX, peer_stats->tx_pkt_sz_avg); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_SIZE_TX, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_NUM_RX, peer_stats->rx_pkts_avg); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_NUM_RX, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_SIZE_RX, peer_stats->rx_pkt_sz_avg); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_SIZE_RX, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_EOSP_DUR, peer_stats->eosp_dur_avg); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_EOSP_DUR, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_EOSP_CNT, peer_stats->eosp_count); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_EOSP_CNT, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_NUM_SP, peer_stats->sp_seq); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_NUM_SP, ret:%d\n", ret)); + goto fail; + } + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) { + WL_ERR(("vendor command reply failed, ret=%d\n", ret)); + } + return ret; + +fail: + /* Free skb for failure cases */ + if (skb) { + kfree_skb(skb); + } + return ret; +} + +static int +wl_cfgvendor_twt_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len, bool clear_stats) +{ + wl_twt_stats_cmd_v1_t query; + wl_twt_stats_v2_t stats_v2; + s32 type, rem_attr; + const struct nlattr *iter; + int ret = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + uint16 buflen = 0, bufstart = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev)); + + bzero(&query, sizeof(query)); + query.version = WL_TWT_STATS_CMD_VERSION_1; + query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer); + + /* Default values, Override Below */ + query.num_bid = 0xFF; + query.num_fid = 0xFF; + + if (clear_stats) { + query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET; + } + nla_for_each_attr(iter, data, len, rem_attr) { + type = nla_type(iter); + if (type == ANDR_TWT_ATTR_CONFIG_ID) { + /* Config ID */ + query.configID = nla_get_u8(iter); + } else { + WL_ERR(("Invalid TWT stats attribute type %d\n", type)); + } + } + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + goto exit; + } + + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS, + sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + WL_ERR(("twt status failed with err=%d \n", ret)); + goto exit; + } + + (void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2)); + + if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) { + if (!clear_stats) { + WL_ERR(("stats query ver %d, \n", dtoh16(stats_v2.version))); + ret = wl_cfgvendor_twt_stats_update_v2(wiphy, (wl_twt_stats_v2_t*)iovresp); + } + } else { + ret = BCME_UNSUPPORTED; + WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version))); + goto exit; + } + +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + + return ret; +} + +static int +wl_cfgvendor_twt_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + return wl_cfgvendor_twt_stats(wiphy, wdev, data, len, false); +} + +static int +wl_cfgvendor_twt_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + return wl_cfgvendor_twt_stats(wiphy, wdev, data, len, true); +} + +static int +wl_cfgvendor_twt_update_cap(struct wiphy *wiphy, wl_twt_cap_t *result) +{ + struct sk_buff *skb; + int32 mem_needed; + int ret = BCME_OK; + + WL_INFORM_MEM(("TWT Capabilites Device,Peer 0x%04x 0x%04x\n", + result->device_cap, result->peer_cap)); + + mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed); + if (unlikely(!skb)) { + WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed)); + ret = -ENOMEM; + goto fail; + } + + ret = nla_put_u32(skb, ANDR_TWT_ATTR_DEVICE_CAP, result->device_cap); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_DEVICE_CAP, ret:%d\n", ret)); + goto fail; + } + ret = nla_put_u32(skb, ANDR_TWT_ATTR_PEER_CAP, result->peer_cap); + if (ret < 0) { + WL_ERR(("Failed to put ANDR_TWT_ATTR_PEER_CAP, ret:%d\n", ret)); + goto fail; + } + + ret = cfg80211_vendor_cmd_reply(skb); + if (unlikely(ret)) { + WL_ERR(("vendor command reply failed, ret=%d\n", ret)); + } + return ret; + +fail: + /* Free skb for failure cases */ + if (skb) { + kfree_skb(skb); + } + return ret; +} + +static int +wl_cfgvendor_twt_cap(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int len) +{ + int ret = BCME_OK; + char iovbuf[WLC_IOCTL_SMLEN] = {0, }; + uint8 *pxtlv = NULL; + uint8 *iovresp = NULL; + wl_twt_cap_cmd_t cmd_cap; + wl_twt_cap_t result; + + uint16 buflen = 0, bufstart = 0; + struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev)); + + bzero(&cmd_cap, sizeof(cmd_cap)); + + cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1; + cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer); + + iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN); + if (iovresp == NULL) { + WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__)); + goto exit; + } + + buflen = bufstart = WLC_IOCTL_SMLEN; + pxtlv = (uint8 *)iovbuf; + + ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP, + sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32); + if (ret != BCME_OK) { + WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret)); + goto exit; + } + + if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen, + iovresp, WLC_IOCTL_MEDLEN, NULL))) { + WL_ERR(("Getting twt status failed with err=%d \n", ret)); + goto exit; + } + + (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result)); + + if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) { + WL_ERR(("capability ver %d, \n", dtoh16(result.version))); + ret = wl_cfgvendor_twt_update_cap(wiphy, &result); + return ret; + } else { + ret = BCME_UNSUPPORTED; + WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version))); + goto exit; + } + +exit: + if (iovresp) { + MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN); + } + + return ret; +} + +static int +wl_cfgvendor_twt_update_setup_response(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_setup_cplt_t *setup_cplt = (wl_twt_setup_cplt_t *)event_data; + const wl_twt_sdesc_t *sdesc = (const wl_twt_sdesc_t *)&setup_cplt[1]; + + WL_DBG(("TWT_SETUP: status %d, reason %d, configID %d, setup_cmd %d, flow_flags 0x%x," + " flow_id %d, channel %d, negotiation_type %d, wake_time_h %u, wake_time_l %u," + " wake_dur %u, wake_int %u\n", + (int)setup_cplt->status, (int)setup_cplt->reason_code, (int)setup_cplt->configID, + (int)sdesc->setup_cmd, sdesc->flow_flags, (int)sdesc->flow_id, (int)sdesc->channel, + (int)sdesc->negotiation_type, sdesc->wake_time_h, sdesc->wake_time_l, + sdesc->wake_dur, sdesc->wake_int)); + + err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_SETUP); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, setup_cplt->configID); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, setup_cplt->reason_code); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(setup_cplt->status)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_NEGOTIATION_TYPE, sdesc->negotiation_type); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NEGOTIATION_TYPE failed\n")); + goto fail; + } + err = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_DURATION, sdesc->wake_dur); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_DURATION failed\n")); + goto fail; + } + err = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_INTERVAL, sdesc->wake_int); + if (unlikely(err)) { + WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_INTERVAL failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_TRIGGER_TYPE, + !!(sdesc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_TRIGGER_TYPE failed\n")); + goto fail; + } + +fail: + return err; +} + +static int +wl_cfgvendor_twt_update_teardown_response(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_teardown_cplt_t *td_cplt = (wl_twt_teardown_cplt_t *)event_data; + const wl_twt_teardesc_t *teardesc = (const wl_twt_teardesc_t *)&td_cplt[1]; + + WL_DBG(("TWT_TEARDOWN: status %d, reason %d, configID %d, flow_id %d, negotiation_type %d," + " bid %d, alltwt %d\n", (int)td_cplt->status, (int)td_cplt->reason_code, + (int)td_cplt->configID, (int)teardesc->flow_id, (int)teardesc->negotiation_type, + (int)teardesc->bid, (int)teardesc->alltwt)); + + err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_TEARDOWN); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, td_cplt->reason_code); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_REASON_CODE failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(td_cplt->status)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_STATUS failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, td_cplt->configID); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_CONFIG_ID failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_ALL_TWT, teardesc->alltwt); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_ALL_TWT failed\n")); + goto fail; + } + +fail: + return err; +} + +static int +wl_cfgvendor_twt_update_infoframe_response(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_info_cplt_t *info_cplt = (wl_twt_info_cplt_t *)event_data; + const wl_twt_infodesc_t *infodesc = (const wl_twt_infodesc_t *)&info_cplt[1]; + + WL_DBG(("TWT_INFOFRM: status %d, reason %d, configID %d, flow_flags 0x%x, flow_id %d," + " next_twt_h %u, next_twt_l %u\n", (int)info_cplt->status, + (int)info_cplt->reason_code, (int)info_cplt->configID, infodesc->flow_flags, + (int)infodesc->flow_id, infodesc->next_twt_h, infodesc->next_twt_l)); + + err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_INFO_FRM); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, info_cplt->reason_code); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(info_cplt->status)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, info_cplt->configID); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_ALL_TWT, + !!(infodesc->flow_flags & WL_TWT_INFO_FLAG_ALL_TWT)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_TWT_RESUMED failed\n")); + goto fail; + } + err = nla_put_u8(skb, ANDR_TWT_ATTR_TWT_RESUMED, + !!(infodesc->flow_flags & WL_TWT_INFO_FLAG_RESUME)); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_TWT_RESUMED failed\n")); + goto fail; + } + +fail: + return err; +} + +static int +wl_cfgvendor_twt_update_notify_response(struct sk_buff *skb, void *event_data) +{ + s32 err = BCME_OK; + const wl_twt_notify_t *notif_cplt = (wl_twt_notify_t *)event_data; + + WL_DBG(("TWT_NOTIFY: notification %d\n", (int)notif_cplt->notification)); + + err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_NOTIFY); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n")); + goto fail; + } + + err = nla_put_u8(skb, ANDR_TWT_ATTR_TWT_NOTIFICATION, notif_cplt->notification); + if (unlikely(err)) { + WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NOTIFICATION failed\n")); + goto fail; + } + +fail: + return err; +} + +s32 +wl_cfgvendor_notify_twt_event(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) +{ + struct sk_buff *skb = NULL; + gfp_t kflags; + struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); + int err = BCME_OK; + struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg); + const wl_twt_event_t *twt_event = (wl_twt_event_t *)data; + + kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; + skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), + BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_TWT, kflags); + if (!skb) { + WL_ERR(("skb alloc failed")); + err = BCME_NOMEM; + goto fail; + } + + switch (twt_event->event_type) { + case WL_TWT_EVENT_SETUP: + err = wl_cfgvendor_twt_update_setup_response(skb, + (void*)twt_event->event_info); + break; + case WL_TWT_EVENT_TEARDOWN: + err = wl_cfgvendor_twt_update_teardown_response(skb, + (void*)twt_event->event_info); + break; + case WL_TWT_EVENT_INFOFRM: + err = wl_cfgvendor_twt_update_infoframe_response(skb, + (void*)twt_event->event_info); + break; + case WL_TWT_EVENT_NOTIFY: + err = wl_cfgvendor_twt_update_notify_response(skb, + (void*)twt_event->event_info); + break; + default: + WL_ERR(("Invalid TWT sub event type %d", twt_event->event_type)); + err = BCME_UNSUPPORTED; + break; + } + + if (err) { + goto fail; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + cfg80211_vendor_event(skb, kflags); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ + WL_ERR(("Successfully sent TWT vendor event type %d\n", twt_event->event_type)); + return BCME_OK; + +fail: + /* Free skb for failure cases */ + if (skb) { + kfree_skb(skb); + } + + return err; +} +#endif /* !WL_TWT && WL_TWT_HAL_IF */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) +const struct nla_policy andr_wifi_attr_policy[ANDR_WIFI_ATTRIBUTE_MAX] = { + [ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET] = { .type = NLA_U32 }, + [ANDR_WIFI_ATTRIBUTE_FEATURE_SET] = { .type = NLA_U32 }, + [ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI] = { .type = NLA_NUL_STRING, .len = 3 }, + [ANDR_WIFI_ATTRIBUTE_NODFS_SET] = { .type = NLA_U32 }, + [ANDR_WIFI_ATTRIBUTE_COUNTRY] = { .type = NLA_NUL_STRING, .len = 3 }, + [ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE] = { .type = NLA_U8 }, + [ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE] = { .type = NLA_U32 }, + [ANDR_WIFI_ATTRIBUTE_LATENCY_MODE] = { .type = NLA_U32, .len = sizeof(uint32) }, + [ANDR_WIFI_ATTRIBUTE_RANDOM_MAC] = { .type = NLA_U32 }, + [ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO] = { .type = NLA_S8 }, + [ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION] = { .type = NLA_S8 }, + [ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW] = { .type = NLA_U32 }, + [ANDR_WIFI_ATTRIBUTE_VOIP_MODE] = { .type = NLA_U32, .len = sizeof(uint32) }, + [ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER] = { .type = NLA_U32, .len = sizeof(uint32) }, +}; + +const struct nla_policy dump_buf_policy[DUMP_BUF_ATTR_MAX] = { + [DUMP_BUF_ATTR_MEMDUMP] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_SSSR_C0_D11_BEFORE] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_SSSR_C0_D11_AFTER] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_SSSR_C1_D11_BEFORE] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_SSSR_C1_D11_AFTER] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_SSSR_C2_D11_BEFORE] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_SSSR_C2_D11_AFTER] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_SSSR_DIG_BEFORE] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_SSSR_DIG_AFTER] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_TIMESTAMP] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_GENERAL_LOG] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_ECNTRS] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_SPECIAL_LOG] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_DHD_DUMP] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_EXT_TRAP] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_HEALTH_CHK] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_PRESERVE_LOG] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_COOKIE] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_FLOWRING_DUMP] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_PKTLOG] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_PKTLOG_DEBUG] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_STATUS_LOG] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_AXI_ERROR] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_RTT_LOG] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_SDTC_ETB_DUMP] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_PKTID_MAP_LOG] = { .type = NLA_BINARY }, + [DUMP_BUF_ATTR_PKTID_UNMAP_LOG] = { .type = NLA_BINARY }, +}; + +const struct nla_policy brcm_drv_attr_policy[BRCM_ATTR_DRIVER_MAX] = { + [BRCM_ATTR_DRIVER_CMD] = { .type = NLA_NUL_STRING }, + [BRCM_ATTR_DRIVER_KEY_PMK] = { .type = NLA_BINARY, .len = WSEC_MAX_PASSPHRASE_LEN }, + [BRCM_ATTR_DRIVER_FEATURE_FLAGS] = { .type = NLA_BINARY, .len = + ((BRCM_WLAN_VENDOR_FEATURES_MAX / 8) + 1) }, + [BRCM_ATTR_DRIVER_RAND_MAC] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN }, + [BRCM_ATTR_SAE_PWE] = { .type = NLA_U32 }, +}; + +#ifdef RTT_SUPPORT +const struct nla_policy rtt_attr_policy[RTT_ATTRIBUTE_MAX] = { + [RTT_ATTRIBUTE_TARGET_CNT] = { .type = NLA_U8 }, + [RTT_ATTRIBUTE_TARGET_INFO] = { .type = NLA_NESTED }, + [RTT_ATTRIBUTE_TARGET_MAC] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN }, + [RTT_ATTRIBUTE_TARGET_TYPE] = { .type = NLA_U8 }, + [RTT_ATTRIBUTE_TARGET_PEER] = { .type = NLA_U8 }, + [RTT_ATTRIBUTE_TARGET_CHAN] = { .type = NLA_BINARY }, + [RTT_ATTRIBUTE_TARGET_PERIOD] = { .type = NLA_U32 }, + [RTT_ATTRIBUTE_TARGET_NUM_BURST] = { .type = NLA_U32 }, + [RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST] = { .type = NLA_U32 }, + [RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM] = { .type = NLA_U32 }, + [RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR] = { .type = NLA_U32 }, + [RTT_ATTRIBUTE_TARGET_LCI] = { .type = NLA_U8 }, + [RTT_ATTRIBUTE_TARGET_LCR] = { .type = NLA_U8 }, + [RTT_ATTRIBUTE_TARGET_BURST_DURATION] = { .type = NLA_U32 }, + [RTT_ATTRIBUTE_TARGET_PREAMBLE] = { .type = NLA_U8 }, + [RTT_ATTRIBUTE_TARGET_BW] = { .type = NLA_U8 }, + [RTT_ATTRIBUTE_RESULTS_COMPLETE] = { .type = NLA_U32 }, + [RTT_ATTRIBUTE_RESULTS_PER_TARGET] = { .type = NLA_NESTED }, + [RTT_ATTRIBUTE_RESULT_CNT] = { .type = NLA_U32 }, + [RTT_ATTRIBUTE_RESULT] = { .type = NLA_BINARY, .len = sizeof(rtt_result_t) }, + [RTT_ATTRIBUTE_RESULT_DETAIL] = { .type = NLA_BINARY, + .len = sizeof(struct rtt_result_detail) }, +}; +#endif /* RTT_SUPPORT */ + +#ifdef KEEP_ALIVE +const struct nla_policy mkeep_alive_attr_policy[MKEEP_ALIVE_ATTRIBUTE_MAX] = { + [MKEEP_ALIVE_ATTRIBUTE_ID] = { .type = NLA_U8 }, + [MKEEP_ALIVE_ATTRIBUTE_IP_PKT] = { .type = NLA_BINARY, .len = MKEEP_ALIVE_IP_PKT_MAX }, + [MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN] = { .type = NLA_U16 }, + [MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN }, + [MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN }, + [MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC] = { .type = NLA_U32 }, + [MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE] = { .type = NLA_U16 } +}; +#endif /* KEEP_ALIVE */ +#ifdef WL_NAN +const struct nla_policy nan_attr_policy[NAN_ATTRIBUTE_MAX] = { + [NAN_ATTRIBUTE_2G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_5G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_CLUSTER_LOW] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_CLUSTER_HIGH] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_SID_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SUB_SID_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SDF_2G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SDF_5G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_HOP_COUNT_LIMIT] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RANDOM_TIME] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_MASTER_PREF] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_OUI] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_WARMUP_TIME] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_24G_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_5G_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_CONF_CLUSTER_VAL] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_DWELL_TIME] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SCAN_PERIOD] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_DWELL_TIME_5G] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SCAN_PERIOD_5G] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_AVAIL_BIT_MAP] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_ENTRY_CONTROL] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RSSI_CLOSE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RSSI_MIDDLE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RSSI_PROXIMITY] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RSSI_CLOSE_5G] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RSSI_MIDDLE_5G] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RSSI_PROXIMITY_5G] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RSSI_WINDOW_SIZE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_CIPHER_SUITE_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SCID_LEN] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_SCID] = { .type = NLA_BINARY, .len = MAX_SCID_LEN }, + [NAN_ATTRIBUTE_2G_AWAKE_DW] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_5G_AWAKE_DW] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_DISC_IND_CFG] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN }, + [NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_CMD_USE_NDPE] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_ENABLE_MERGE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_NSS] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_ENABLE_RANGING] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_DW_EARLY_TERM] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_TRANSAC_ID] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_PUBLISH_ID] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO] = { .type = NLA_BINARY, .len = + NAN_MAX_SERVICE_SPECIFIC_INFO_LEN }, + [NAN_ATTRIBUTE_SUBSCRIBE_ID] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_SUBSCRIBE_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_PUBLISH_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_PUBLISH_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_PERIOD] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_TTL] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_SERVICE_NAME_LEN] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_SERVICE_NAME] = { .type = NLA_BINARY, .len = WL_NAN_SVC_HASH_LEN }, + [NAN_ATTRIBUTE_PEER_ID] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_INST_ID] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_SUBSCRIBE_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SUBSCRIBE_MATCH] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_PUBLISH_MATCH] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SERVICERESPONSEFILTER] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_USESERVICERESPONSEFILTER] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_RX_MATCH_FILTER] = { .type = NLA_BINARY, .len = MAX_MATCH_FILTER_LEN }, + [NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_TX_MATCH_FILTER] = { .type = NLA_BINARY, .len = MAX_MATCH_FILTER_LEN }, + [NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES] = { .type = NLA_U16, .len = sizeof(uint16) }, + [NAN_ATTRIBUTE_MAC_ADDR_LIST] = { .type = NLA_BINARY, .len = + (NAN_SRF_MAX_MAC*ETHER_ADDR_LEN) }, + [NAN_ATTRIBUTE_TX_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SDE_CONTROL_SECURITY] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RECV_IND_CFG] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_KEY_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_KEY_LEN] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_KEY_DATA] = { .type = NLA_BINARY, .len = NAN_MAX_PMK_LEN }, + [NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN] = { .type = NLA_U16, .len = + sizeof(uint16) }, + [NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO] = { .type = NLA_BINARY, .len = + MAX_SDEA_SVC_INFO_LEN }, + [NAN_ATTRIBUTE_SECURITY] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RANGING_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_RANGING_INDICATION] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_SVC_RESPONDER_POLICY] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_NDP_ID] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_IFACE] = { .type = NLA_BINARY, .len = IFNAMSIZ+1 }, + [NAN_ATTRIBUTE_QOS] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_RSP_CODE] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_INST_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN }, + [NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN }, + [NAN_ATTRIBUTE_IF_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN }, + [NAN_ATTRIBUTE_NO_CONFIG_AVAIL] = { .type = NLA_U8, .len = sizeof(uint8) }, + [NAN_ATTRIBUTE_CHANNEL_INFO] = { .type = NLA_BINARY, .len = + sizeof(nan_channel_info_t) * NAN_MAX_CHANNEL_INFO_SUPPORTED }, + [NAN_ATTRIBUTE_NUM_CHANNELS] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_INSTANT_MODE_ENABLE] = { .type = NLA_U32, .len = sizeof(uint32) }, + [NAN_ATTRIBUTE_INSTANT_COMM_CHAN] = { .type = NLA_U32, .len = sizeof(uint32) }, +}; +#endif /* WL_NAN */ + +const struct nla_policy gscan_attr_policy[GSCAN_ATTRIBUTE_MAX] = { + [GSCAN_ATTRIBUTE_BAND] = { .type = NLA_U32 }, + [GSCAN_ATTRIBUTE_NUM_CHANNELS] = { .type = NLA_U32 }, + [GSCAN_ATTRIBUTE_CHANNEL_LIST] = { .type = NLA_BINARY }, + [GSCAN_ATTRIBUTE_WHITELIST_SSID] = { .type = NLA_BINARY, .len = IEEE80211_MAX_SSID_LEN }, + [GSCAN_ATTRIBUTE_NUM_WL_SSID] = { .type = NLA_U32 }, + [GSCAN_ATTRIBUTE_WL_SSID_LEN] = { .type = NLA_U32 }, + [GSCAN_ATTRIBUTE_WL_SSID_FLUSH] = { .type = NLA_U32 }, + [GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM] = { .type = NLA_NESTED }, + /* length is sizeof(wl_ssid_whitelist_t) * MAX_SSID_WHITELIST_NUM */ + [GSCAN_ATTRIBUTE_NUM_BSSID] = { .type = NLA_U32 }, + [GSCAN_ATTRIBUTE_BSSID_PREF_LIST] = { .type = NLA_NESTED }, + /* length is sizeof(wl_bssid_pref_list_t) * MAX_BSSID_PREF_LIST_NUM */ + [GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH] = { .type = NLA_U32 }, + [GSCAN_ATTRIBUTE_BSSID_PREF] = { .type = NLA_BINARY, .len = ETH_ALEN }, + [GSCAN_ATTRIBUTE_RSSI_MODIFIER] = { .type = NLA_U32 }, + [GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH] = { .type = NLA_U32 }, + [GSCAN_ATTRIBUTE_BLACKLIST_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, + [GSCAN_ATTRIBUTE_ROAM_STATE_SET] = { .type = NLA_U32 }, +}; + +#ifdef DHD_WAKE_STATUS +const struct nla_policy wake_stat_attr_policy[WAKE_STAT_ATTRIBUTE_MAX] = { + [WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT] = { .type = NLA_U32 }, +#ifdef CUSTOM_WAKE_REASON_STATS + [WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE] = { .type = NLA_BINARY, + .len = (MAX_WAKE_REASON_STATS * sizeof(int))}, +#else + [WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE] = { .type = NLA_BINARY, + .len = (WLC_E_LAST * sizeof(uint))}, +#endif /* CUSTOM_WAKE_REASON_STATS */ + [WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT_USED] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 }, + [WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 }, +}; +#endif /* DHD_WAKE_STATUS */ + +#ifdef RSSI_MONITOR_SUPPORT +const struct nla_policy rssi_monitor_attr_policy[RSSI_MONITOR_ATTRIBUTE_MAX] = { + [RSSI_MONITOR_ATTRIBUTE_MAX_RSSI] = { .type = NLA_U32 }, + [RSSI_MONITOR_ATTRIBUTE_MIN_RSSI] = { .type = NLA_U32 }, + [RSSI_MONITOR_ATTRIBUTE_START] = { .type = NLA_U32 } +}; +#endif /* RSSI_MONITOR_SUPPORT */ + + +const struct nla_policy hal_start_attr_policy[SET_HAL_START_ATTRIBUTE_MAX] = { + [0] = { .strict_start_type = 0 }, + [SET_HAL_START_ATTRIBUTE_DEINIT] = { .type = NLA_UNSPEC }, + [SET_HAL_START_ATTRIBUTE_PRE_INIT] = { .type = NLA_NUL_STRING }, + [SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID] = { .type = NLA_U32 }, +}; + +const struct nla_policy andr_dbg_policy[DEBUG_ATTRIBUTE_MAX] = { + [DEBUG_ATTRIBUTE_GET_DRIVER] = { .type = NLA_BINARY }, + [DEBUG_ATTRIBUTE_GET_FW] = { .type = NLA_BINARY }, + [DEBUG_ATTRIBUTE_RING_ID] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_RING_NAME] = { .type = NLA_NUL_STRING }, + [DEBUG_ATTRIBUTE_RING_FLAGS] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_LOG_LEVEL] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_LOG_TIME_INTVAL] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_FW_DUMP_LEN] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_FW_DUMP_DATA] = { .type = NLA_U64 }, + [DEBUG_ATTRIBUTE_FW_ERR_CODE] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_RING_DATA] = { .type = NLA_BINARY }, + [DEBUG_ATTRIBUTE_RING_STATUS] = { .type = NLA_BINARY }, + [DEBUG_ATTRIBUTE_RING_NUM] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_DRIVER_DUMP_LEN] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_DRIVER_DUMP_DATA] = { .type = NLA_BINARY }, + [DEBUG_ATTRIBUTE_PKT_FATE_NUM] = { .type = NLA_U32 }, + [DEBUG_ATTRIBUTE_PKT_FATE_DATA] = { .type = NLA_U64 }, + [DEBUG_ATTRIBUTE_HANG_REASON] = { .type = NLA_BINARY }, +}; + +#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF) +const struct nla_policy andr_twt_attr_policy[ANDR_TWT_ATTR_MAX] = { + [ANDR_TWT_ATTR_NONE] = { .strict_start_type = 0 }, + [ANDR_TWT_ATTR_CONFIG_ID] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_NEGOTIATION_TYPE] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_TRIGGER_TYPE] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_WAKE_DURATION] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKE_INTERVAL] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKE_INTERVAL_MIN] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKE_INTERVAL_MAX] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKE_DURATION_MIN] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKE_DURATION_MAX] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_PKT_SIZE] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_PKT_NUM] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_WAKETIME_OFFSET] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_ALL_TWT] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_RESUME_TIME] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_EOSP_DUR] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_EOSP_CNT] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_NUM_SP] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_DEVICE_CAP] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_PEER_CAP] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_STATUS] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_REASON_CODE] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_TWT_RESUMED] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_TWT_NOTIFICATION] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_SUB_EVENT] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_NUM_PEER_STATS] = { .type = NLA_U8 }, + [ANDR_TWT_ATTR_AVG_PKT_NUM_TX] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_PKT_SIZE_TX] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_PKT_NUM_RX] = { .type = NLA_U32 }, + [ANDR_TWT_ATTR_AVG_PKT_SIZE_RX] = { .type = NLA_U32 }, +}; +#endif /* !WL_TWT && WL_TWT_HAL_IF */ + +#endif /* LINUX_VERSION >= 5.3 */ + +static struct wiphy_vendor_command wl_vendor_cmds [] = { + { + { + .vendor_id = OUI_BRCM, + .subcmd = BRCM_VENDOR_SCMD_PRIV_STR + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_priv_string_handler, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = brcm_drv_attr_policy, + .maxattr = BRCM_ATTR_DRIVER_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#ifdef BCM_PRIV_CMD_SUPPORT + { + { + .vendor_id = OUI_BRCM, + .subcmd = BRCM_VENDOR_SCMD_BCM_STR + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_priv_bcm_handler, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = brcm_drv_attr_policy, + .maxattr = BRCM_ATTR_DRIVER_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* BCM_PRIV_CMD_SUPPORT */ +#if defined(WL_SAE) || defined(WL_CLIENT_SAE) + { + { + .vendor_id = OUI_BRCM, + .subcmd = BRCM_VENDOR_SCMD_BCM_PSK + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_sae_password + }, +#endif /* WL_SAE || WL_CLIENT_SAE */ + { + { + .vendor_id = OUI_BRCM, + .subcmd = BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_connect_params_handler, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = brcm_drv_attr_policy, + .maxattr = BRCM_ATTR_DRIVER_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_BRCM, + .subcmd = BRCM_VENDOR_SCMD_SET_START_AP_PARAMS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_start_ap_params_handler, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = brcm_drv_attr_policy, + .maxattr = BRCM_ATTR_DRIVER_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#ifdef GSCAN_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_gscan_get_capabilities + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_scan_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_batch_scan_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_initiate_gscan + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_enable_full_scan_result + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_HOTLIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_hotlist_cfg + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_gscan_get_batch_results + }, +#endif /* GSCAN_SUPPORT */ +#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_gscan_get_channel_list, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = gscan_attr_policy, + .maxattr = GSCAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ +#ifdef RTT_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_SET_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_set_config, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = rtt_attr_policy, + .maxattr = RTT_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_CANCEL_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_cancel_config, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = rtt_attr_policy, + .maxattr = RTT_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_GETCAPABILITY + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_get_capability, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = rtt_attr_policy, + .maxattr = RTT_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_GETAVAILCHANNEL + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_get_responder_info, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = rtt_attr_policy, + .maxattr = RTT_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_SET_RESPONDER + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_set_responder, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = rtt_attr_policy, + .maxattr = RTT_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = RTT_SUBCMD_CANCEL_RESPONDER + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_rtt_cancel_responder, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = rtt_attr_policy, + .maxattr = RTT_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* RTT_SUPPORT */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_get_feature_set, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_get_feature_set_matrix, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_RANDOM_MAC_OUI + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_rand_mac_oui, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#ifdef CUSTOM_FORCE_NODFS_FLAG + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_NODFS_CHANNELS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_nodfs_flag, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* CUSTOM_FORCE_NODFS_FLAG */ + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_WIFI_SET_COUNTRY + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_country, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#ifdef LINKSTAT_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = LSTATS_SUBCMD_GET_INFO + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_lstats_get_info + }, +#endif /* LINKSTAT_SUPPORT */ + +#ifdef GSCAN_SUPPORT + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_epno_cfg + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_set_lazy_roam_cfg + + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, .doit = wl_cfgvendor_enable_lazy_roam }, @@ -9294,7 +10465,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_ssid_whitelist + .doit = wl_cfgvendor_set_ssid_whitelist, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = gscan_attr_policy, + .maxattr = GSCAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { @@ -9303,7 +10478,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_bssid_blacklist + .doit = wl_cfgvendor_set_bssid_blacklist, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = gscan_attr_policy, + .maxattr = GSCAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* GSCAN_SUPPORT || ROAMEXP_SUPPORT */ #ifdef ROAMEXP_SUPPORT @@ -9313,7 +10492,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = WIFI_SUBCMD_FW_ROAM_POLICY }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_fw_roaming_state + .doit = wl_cfgvendor_set_fw_roaming_state, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = gscan_attr_policy, + .maxattr = GSCAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9330,7 +10513,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_GET_VER }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_dbg_get_version + .doit = wl_cfgvendor_dbg_get_version, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_dbg_policy, + .maxattr = DEBUG_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #ifdef DHD_LOG_DUMP { @@ -9339,7 +10526,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_GET_FILE_DUMP_BUF }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_dbg_file_dump + .doit = wl_cfgvendor_dbg_file_dump, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = dump_buf_policy, + .maxattr = DUMP_BUF_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* DHD_LOG_DUMP */ @@ -9358,7 +10549,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_GET_MEM_DUMP }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_dbg_get_mem_dump + .doit = wl_cfgvendor_dbg_get_mem_dump, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_dbg_policy, + .maxattr = DEBUG_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9366,7 +10561,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_START_LOGGING }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_dbg_start_logging + .doit = wl_cfgvendor_dbg_start_logging, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_dbg_policy, + .maxattr = DEBUG_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9382,7 +10581,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_GET_RING_STATUS }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_dbg_get_ring_status + .doit = wl_cfgvendor_dbg_get_ring_status, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_dbg_policy, + .maxattr = DEBUG_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9390,7 +10593,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_GET_RING_DATA }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_dbg_get_ring_data + .doit = wl_cfgvendor_dbg_get_ring_data, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_dbg_policy, + .maxattr = DEBUG_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* DEBUGABILITY */ { @@ -9416,7 +10623,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_GET_TX_PKT_FATES }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_dbg_get_tx_pkt_fates + .doit = wl_cfgvendor_dbg_get_tx_pkt_fates, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_dbg_policy, + .maxattr = DEBUG_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9424,7 +10635,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_GET_RX_PKT_FATES }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_dbg_get_rx_pkt_fates + .doit = wl_cfgvendor_dbg_get_rx_pkt_fates, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_dbg_policy, + .maxattr = DEBUG_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* DBG_PKT_MON */ #ifdef KEEP_ALIVE @@ -9434,7 +10649,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_start_mkeep_alive + .doit = wl_cfgvendor_start_mkeep_alive, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = mkeep_alive_attr_policy, + .maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9442,7 +10661,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_stop_mkeep_alive + .doit = wl_cfgvendor_stop_mkeep_alive, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = mkeep_alive_attr_policy, + .maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* KEEP_ALIVE */ #ifdef WL_NAN @@ -9452,7 +10675,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_ENABLE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_start_handler + .doit = wl_cfgvendor_nan_start_handler, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9460,7 +10687,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_DISABLE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_stop_handler + .doit = wl_cfgvendor_nan_stop_handler, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9468,7 +10699,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_CONFIG }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_config_handler + .doit = wl_cfgvendor_nan_config_handler, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9476,7 +10711,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_REQUEST_PUBLISH }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_req_publish + .doit = wl_cfgvendor_nan_req_publish, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9484,7 +10723,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_REQUEST_SUBSCRIBE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_req_subscribe + .doit = wl_cfgvendor_nan_req_subscribe, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9492,7 +10735,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_CANCEL_PUBLISH }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_cancel_publish + .doit = wl_cfgvendor_nan_cancel_publish, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9500,7 +10747,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_CANCEL_SUBSCRIBE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_cancel_subscribe + .doit = wl_cfgvendor_nan_cancel_subscribe, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9508,7 +10759,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_TRANSMIT }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_transmit + .doit = wl_cfgvendor_nan_transmit, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9525,7 +10780,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_data_path_iface_create + .doit = wl_cfgvendor_nan_data_path_iface_create, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9533,7 +10792,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_data_path_iface_delete + .doit = wl_cfgvendor_nan_data_path_iface_delete, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9541,7 +10804,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_REQUEST }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_data_path_request + .doit = wl_cfgvendor_nan_data_path_request, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9549,7 +10816,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_RESPONSE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_data_path_response + .doit = wl_cfgvendor_nan_data_path_response, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9557,7 +10828,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_END }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_data_path_end + .doit = wl_cfgvendor_nan_data_path_end, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #ifdef WL_NAN_DISC_CACHE { @@ -9566,7 +10841,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_SEC_INFO }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_data_path_sec_info + .doit = wl_cfgvendor_nan_data_path_sec_info, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* WL_NAN_DISC_CACHE */ { @@ -9583,7 +10862,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = NAN_WIFI_SUBCMD_ENABLE_MERGE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_nan_enable_merge + .doit = wl_cfgvendor_nan_enable_merge, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = nan_attr_policy, + .maxattr = NAN_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* WL_NAN */ #if defined(PKT_FILTER_SUPPORT) && defined(APF) @@ -9593,7 +10876,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = APF_SUBCMD_GET_CAPABILITIES }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_apf_get_capabilities + .doit = wl_cfgvendor_apf_get_capabilities, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = apf_atrribute_policy, + .maxattr = APF_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { @@ -9602,7 +10889,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = APF_SUBCMD_SET_FILTER }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_apf_set_filter + .doit = wl_cfgvendor_apf_set_filter, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = apf_atrribute_policy, + .maxattr = APF_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* PKT_FILTER_SUPPORT && APF */ #ifdef NDO_CONFIG_SUPPORT @@ -9612,7 +10903,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = WIFI_SUBCMD_CONFIG_ND_OFFLOAD }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_configure_nd_offload + .doit = wl_cfgvendor_configure_nd_offload, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* NDO_CONFIG_SUPPORT */ #ifdef RSSI_MONITOR_SUPPORT @@ -9622,7 +10917,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_rssi_monitor + .doit = wl_cfgvendor_set_rssi_monitor, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = rssi_monitor_attr_policy, + .maxattr = RSSI_MONITOR_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* RSSI_MONITOR_SUPPORT */ #ifdef DHD_WAKE_STATUS @@ -9632,7 +10931,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_GET_WAKE_REASON_STATS }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_get_wake_reason_stats + .doit = wl_cfgvendor_get_wake_reason_stats, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = wake_stat_attr_policy, + .maxattr = WAKE_STAT_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* DHD_WAKE_STATUS */ #ifdef DHDTCPACK_SUPPRESS @@ -9642,7 +10945,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = WIFI_SUBCMD_CONFIG_TCPACK_SUP }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_tcpack_sup_mode + .doit = wl_cfgvendor_set_tcpack_sup_mode, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* DHDTCPACK_SUPPRESS */ #if !defined(BCMSUP_4WAY_HANDSHAKE) || (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) @@ -9652,7 +10959,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = BRCM_VENDOR_SCMD_SET_PMK }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_pmk + .doit = wl_cfgvendor_set_pmk, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = brcm_drv_attr_policy, + .maxattr = BRCM_ATTR_DRIVER_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* !BCMSUP_4WAY_HANDSHAKE || LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */ { @@ -9661,7 +10972,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = BRCM_VENDOR_SCMD_GET_FEATURES }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_get_driver_feature + .doit = wl_cfgvendor_get_driver_feature, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = brcm_drv_attr_policy, + .maxattr = BRCM_ATTR_DRIVER_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT) { @@ -9680,7 +10995,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_SET_HAL_START }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_hal_started + .doit = wl_cfgvendor_set_hal_started, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = hal_start_attr_policy, + .maxattr = SET_HAL_START_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, { { @@ -9696,7 +11015,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = DEBUG_SET_HAL_PID }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_hal_pid + .doit = wl_cfgvendor_set_hal_pid, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = hal_start_attr_policy, + .maxattr = SET_HAL_START_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* WL_CFG80211 */ #ifdef WL_LATENCY_MODE @@ -9706,7 +11029,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = WIFI_SUBCMD_SET_LATENCY_MODE }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wl_cfgvendor_set_latency_mode + .doit = wl_cfgvendor_set_latency_mode, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* WL_LATENCY_MODE */ #ifdef WL_P2P_RAND @@ -9716,7 +11043,11 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = BRCM_VENDOR_SCMD_SET_MAC }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV, - .doit = wl_cfgvendor_set_p2p_rand_mac + .doit = wl_cfgvendor_set_p2p_rand_mac, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = brcm_drv_attr_policy, + .maxattr = BRCM_ATTR_DRIVER_MAX +#endif /* LINUX_VERSION >= 5.3 */ }, #endif /* WL_P2P_RAND */ #ifdef WL_SAR_TX_POWER @@ -9726,9 +11057,87 @@ static struct wiphy_vendor_command wl_vendor_cmds [] = { .subcmd = WIFI_SUBCMD_TX_POWER_SCENARIO }, .flags = WIPHY_VENDOR_CMD_NEED_WDEV, - .doit = wl_cfgvendor_tx_power_scenario + .doit = wl_cfgvendor_tx_power_scenario, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_wifi_attr_policy, + .maxattr = ANDR_WIFI_ATTRIBUTE_MAX +#endif /* LINUX_VERSION >= 5.3 */ } #endif /* WL_SAR_TX_POWER */ +#if !defined(WL_TWT) && defined(WL_TWT_HAL_IF) + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_SETUP + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_setup, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_TEARDOWN + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_teardown, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_INFO_FRAME + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_info_frame, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_GET_CAP + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_cap, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_GET_STATS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_get_stats, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, + { + { + .vendor_id = OUI_GOOGLE, + .subcmd = ANDR_TWT_SUBCMD_CLR_STATS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wl_cfgvendor_twt_clear_stats, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) + .policy = andr_twt_attr_policy, + .maxattr = ANDR_TWT_ATTR_MAX +#endif /* LINUX_VERSION >= 5.3 */ + }, +#endif /* !WL_TWT && WL_TWT_HAL_IF */ }; @@ -9774,7 +11183,8 @@ static const struct nl80211_vendor_cmd_info wl_vendor_events [] = { { OUI_BRCM, BRCM_VENDOR_EVENT_CU}, { OUI_BRCM, BRCM_VENDOR_EVENT_WIPS}, { OUI_GOOGLE, NAN_ASYNC_RESPONSE_DISABLED}, - { OUI_BRCM, BRCM_VENDOR_EVENT_RCC_INFO} + { OUI_BRCM, BRCM_VENDOR_EVENT_RCC_INFO}, + {OUI_BRCM, BRCM_VENDOR_EVENT_TWT} }; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) @@ -9786,7 +11196,9 @@ wl_cfgvendor_apply_cmd_policy(struct wiphy *wiphy) WL_INFORM(("Apply CMD_RAW_DATA policy\n")); for (i = 0; i < n_cmds; i++) { - wl_vendor_cmds[i].policy = VENDOR_CMD_RAW_DATA; + if (wl_vendor_cmds[i].policy == NULL) { + wl_vendor_cmds[i].policy = VENDOR_CMD_RAW_DATA; + } } } #endif /* LINUX VER >= 5.3 */ diff --git a/bcmdhd.101.10.361.x/wl_cfgvendor.h b/bcmdhd.101.10.361.x/wl_cfgvendor.h index 581ab11..8826e6d 100755 --- a/bcmdhd.101.10.361.x/wl_cfgvendor.h +++ b/bcmdhd.101.10.361.x/wl_cfgvendor.h @@ -157,6 +157,10 @@ typedef enum { ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START = 0x1900, ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_END = 0x19FF, + /* define all TWT related commands between 0x2140 and 0x214F */ + ANDROID_NL80211_SUBCMD_TWT_START = 0x2140, + ANDROID_NL80211_SUBCMD_TWT_END = 0x214F, + /* This is reserved for future usage */ } ANDROID_VENDOR_SUB_COMMAND; @@ -245,6 +249,13 @@ enum andr_vendor_subcmd { APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START, APF_SUBCMD_SET_FILTER, WIFI_SUBCMD_TX_POWER_SCENARIO = ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START, + + ANDR_TWT_SUBCMD_GET_CAP = ANDROID_NL80211_SUBCMD_TWT_START, + ANDR_TWT_SUBCMD_SETUP, + ANDR_TWT_SUBCMD_TEARDOWN, + ANDR_TWT_SUBCMD_INFO_FRAME, + ANDR_TWT_SUBCMD_GET_STATS, + ANDR_TWT_SUBCMD_CLR_STATS, /* Add more sub commands here */ VENDOR_SUBCMD_MAX }; @@ -406,11 +417,13 @@ enum rtt_attributes { RTT_ATTRIBUTE_TARGET_BURST_DURATION, RTT_ATTRIBUTE_TARGET_PREAMBLE, RTT_ATTRIBUTE_TARGET_BW, - RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, + RTT_ATTRIBUTE_RESULTS_COMPLETE, RTT_ATTRIBUTE_RESULTS_PER_TARGET, RTT_ATTRIBUTE_RESULT_CNT, RTT_ATTRIBUTE_RESULT, - RTT_ATTRIBUTE_RESULT_DETAIL + RTT_ATTRIBUTE_RESULT_DETAIL, + /* Add any new RTT_ATTRIBUTE prior to RTT_ATTRIBUTE_MAX */ + RTT_ATTRIBUTE_MAX }; enum wifi_rssi_monitor_attr { @@ -419,7 +432,8 @@ enum wifi_rssi_monitor_attr { #endif RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, - RSSI_MONITOR_ATTRIBUTE_START + RSSI_MONITOR_ATTRIBUTE_START, + RSSI_MONITOR_ATTRIBUTE_MAX }; enum wifi_sae_key_attr { @@ -450,7 +464,9 @@ enum debug_attributes { DEBUG_ATTRIBUTE_DRIVER_DUMP_DATA, DEBUG_ATTRIBUTE_PKT_FATE_NUM, DEBUG_ATTRIBUTE_PKT_FATE_DATA, - DEBUG_ATTRIBUTE_HANG_REASON + DEBUG_ATTRIBUTE_HANG_REASON, + /* Please add new attributes from here to sync up old HAL */ + DEBUG_ATTRIBUTE_MAX }; typedef enum { @@ -521,8 +537,12 @@ typedef enum { DUMP_BUF_ATTR_PKTLOG_DEBUG = 21, DUMP_BUF_ATTR_STATUS_LOG = 22, DUMP_BUF_ATTR_AXI_ERROR = 23, - DUMP_BUF_ATTR_RTT_LOG = 24 + DUMP_BUF_ATTR_RTT_LOG = 24, + DUMP_BUF_ATTR_SDTC_ETB_DUMP = 25, + DUMP_BUF_ATTR_PKTID_MAP_LOG = 26, + DUMP_BUF_ATTR_PKTID_UNMAP_LOG = 27, /* Please add new attributes from here to sync up old HAL */ + DUMP_BUF_ATTR_MAX } EWP_DUMP_CMD_ATTRIBUTE; enum mkeep_alive_attributes { @@ -535,7 +555,8 @@ enum mkeep_alive_attributes { MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, - MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE + MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE, + MKEEP_ALIVE_ATTRIBUTE_MAX }; typedef enum wl_vendor_event { @@ -586,7 +607,9 @@ typedef enum wl_vendor_event { BRCM_VENDOR_EVENT_CU = 38, BRCM_VENDOR_EVENT_WIPS = 39, NAN_ASYNC_RESPONSE_DISABLED = 40, - BRCM_VENDOR_EVENT_RCC_INFO = 41 + BRCM_VENDOR_EVENT_RCC_INFO = 41, + BRCM_VENDOR_EVENT_TWT = 43, + WL_VENDOR_EVENT_LAST } wl_vendor_event_t; enum andr_wifi_attr { @@ -602,13 +625,20 @@ enum andr_wifi_attr { ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE, ANDR_WIFI_ATTRIBUTE_LATENCY_MODE, ANDR_WIFI_ATTRIBUTE_RANDOM_MAC, - ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO + ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO, + ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION, + ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW, + ANDR_WIFI_ATTRIBUTE_VOIP_MODE, + ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER, + /* Any new ANDR_WIFI attribute add prior to the ANDR_WIFI_ATTRIBUTE_MAX */ + ANDR_WIFI_ATTRIBUTE_MAX }; enum apf_attributes { APF_ATTRIBUTE_VERSION, APF_ATTRIBUTE_MAX_LEN, APF_ATTRIBUTE_PROGRAM, - APF_ATTRIBUTE_PROGRAM_LEN + APF_ATTRIBUTE_PROGRAM_LEN, + APF_ATTRIBUTE_MAX }; typedef enum wl_vendor_gscan_attribute { @@ -664,7 +694,10 @@ enum wake_stat_attributes { WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS, WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT, WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT, - WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT + WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT, + WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO, + /* Please add new attributes from here to sync up old HAL */ + WAKE_STAT_ATTRIBUTE_MAX }; typedef struct rx_data_cnt_details_t { @@ -731,9 +764,91 @@ typedef struct wifi_roaming_capabilities { typedef enum { SET_HAL_START_ATTRIBUTE_DEINIT = 0x0001, SET_HAL_START_ATTRIBUTE_PRE_INIT = 0x0002, - SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID = 0x0003 + SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID = 0x0003, + /* Add any new HAL_START attribute prior to SET_HAL_START_ATTRIBUTE_MAX */ + SET_HAL_START_ATTRIBUTE_MAX } SET_HAL_START_ATTRIBUTE; +#ifdef WL_TWT +typedef enum { + WIFI_TWT_EVENT_SETUP = 1, + WIFI_TWT_EVENT_TEARDOWN = 2, + WIFI_TWT_EVENT_INFO_FRM = 3, + WIFI_TWT_EVENT_NOTIFY = 4 +} wifi_twt_sub_event; + +typedef enum { + WIFI_TWT_ATTR_NONE = 0, + WIFI_TWT_ATTR_SUB_EVENT = 1, + WIFI_TWT_ATTR_REASON_CODE = 2, + WIFI_TWT_ATTR_STATUS = 3, + WIFI_TWT_ATTR_SETUP_CMD = 4, + WIFI_TWT_ATTR_FLOW_FLAGS = 5, + WIFI_TWT_ATTR_FLOW_ID = 6, + WIFI_TWT_ATTR_CHANNEL = 7, + WIFI_TWT_ATTR_NEGOTIATION_TYPE = 8, + WIFI_TWT_ATTR_WAKETIME_H = 9, + WIFI_TWT_ATTR_WAKETIME_L = 10, + WIFI_TWT_ATTR_WAKE_DURATION = 11, + WIFI_TWT_ATTR_WAKE_INTERVAL = 12, + WIFI_TWT_ATTR_BID = 13, + WIFI_TWT_ATTR_ALLTWT = 14, + WIFI_TWT_ATTR_NEXT_TWT_H = 15, + WIFI_TWT_ATTR_NEXT_TWT_L = 16, + WIFI_TWT_ATTR_CONFIG_ID = 17, + WIFI_TWT_ATTR_NOTIFICATION = 18, + WIFI_TWT_ATTR_FLOW_TYPE = 19, + WIFI_TWT_ATTR_TRIGGER_TYPE = 20, + + WIFI_TWT_ATTR_MAX +} wifi_twt_attribute; +#endif /* WL_TWT */ + +#ifdef WL_TWT_HAL_IF +#define BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN 500 + +typedef enum { + ANDR_TWT_ATTR_NONE = 0, + ANDR_TWT_ATTR_CONFIG_ID = 1, + ANDR_TWT_ATTR_NEGOTIATION_TYPE = 2, + ANDR_TWT_ATTR_TRIGGER_TYPE = 3, + ANDR_TWT_ATTR_WAKE_DURATION = 4, + ANDR_TWT_ATTR_WAKE_INTERVAL = 5, + ANDR_TWT_ATTR_WAKE_INTERVAL_MIN = 6, + ANDR_TWT_ATTR_WAKE_INTERVAL_MAX = 7, + ANDR_TWT_ATTR_WAKE_DURATION_MIN = 8, + ANDR_TWT_ATTR_WAKE_DURATION_MAX = 9, + ANDR_TWT_ATTR_AVG_PKT_SIZE = 10, + ANDR_TWT_ATTR_AVG_PKT_NUM = 11, + ANDR_TWT_ATTR_WAKETIME_OFFSET = 12, + ANDR_TWT_ATTR_ALL_TWT = 13, + ANDR_TWT_ATTR_RESUME_TIME = 14, + ANDR_TWT_ATTR_AVG_EOSP_DUR = 15, + ANDR_TWT_ATTR_EOSP_CNT = 16, + ANDR_TWT_ATTR_NUM_SP = 17, + ANDR_TWT_ATTR_DEVICE_CAP = 18, + ANDR_TWT_ATTR_PEER_CAP = 19, + ANDR_TWT_ATTR_STATUS = 20, + ANDR_TWT_ATTR_REASON_CODE = 21, + ANDR_TWT_ATTR_TWT_RESUMED = 22, + ANDR_TWT_ATTR_TWT_NOTIFICATION = 23, + ANDR_TWT_ATTR_SUB_EVENT = 24, + ANDR_TWT_ATTR_NUM_PEER_STATS = 25, + ANDR_TWT_ATTR_AVG_PKT_NUM_TX = 26, + ANDR_TWT_ATTR_AVG_PKT_SIZE_TX = 27, + ANDR_TWT_ATTR_AVG_PKT_NUM_RX = 28, + ANDR_TWT_ATTR_AVG_PKT_SIZE_RX = 29, + ANDR_TWT_ATTR_MAX +} andr_twt_attribute; + +typedef enum { + ANDR_TWT_EVENT_SETUP = 1, + ANDR_TWT_EVENT_TEARDOWN = 2, + ANDR_TWT_EVENT_INFO_FRM = 3, + ANDR_TWT_EVENT_NOTIFY = 4 +} andr_twt_sub_event; +#endif /* WL_TWT_HAL_IF */ + /* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */ #define BRCM_VENDOR_SCMD_CAPA "cap" #define MEMDUMP_PATH_LEN 128 diff --git a/bcmdhd.101.10.361.x/wl_cfgvif.c b/bcmdhd.101.10.361.x/wl_cfgvif.c index e9a1d76..f5d6910 100755 --- a/bcmdhd.101.10.361.x/wl_cfgvif.c +++ b/bcmdhd.101.10.361.x/wl_cfgvif.c @@ -1548,37 +1548,32 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, #if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL) dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); #endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */ -#ifdef WL_EXT_IAPSTA - enum nl80211_band band; - s32 _chan; -#endif /* WL_EXT_IAPSTA */ u16 center_freq = chan->center_freq; dev = ndev_to_wlc_ndev(dev, cfg); #ifdef WL_EXT_IAPSTA - _chan = ieee80211_frequency_to_channel(chan->center_freq); if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP || dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) { u16 wl_iftype = 0; u16 wl_mode = 0; + + chspec = wl_freq_to_chanspec(chan->center_freq); if (cfg80211_to_wl_iftype(dev->ieee80211_ptr->iftype, &wl_iftype, &wl_mode) < 0) { WL_ERR(("Unknown interface type:0x%x\n", dev->ieee80211_ptr->iftype)); return -EINVAL; } wl_ext_iapsta_update_iftype(dev, wl_iftype); - _chan = wl_ext_iapsta_update_channel(dev, _chan); - } - if (CHANNEL_IS_5G(_chan)) - band = NL80211_BAND_5GHZ; - else - band = NL80211_BAND_2GHZ; - center_freq = ieee80211_channel_to_frequency(_chan, band); + chspec = wl_ext_iapsta_update_channel(dev, chspec); + center_freq = wl_channel_to_frequency(wf_chspec_primary20_chan(chspec), + CHSPEC_BAND(chspec)); + } else #endif chspec = wl_freq_to_chanspec(center_freq); - WL_MSG(dev->name, "netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", - dev->ifindex, channel_type, CHSPEC_CHANNEL(chspec)); + WL_MSG(dev->name, "netdev_ifidx(%d) chan_type(%d) target channel(%s-%d %sMHz)\n", + dev->ifindex, channel_type, CHSPEC2BANDSTR(chspec), + CHSPEC_CHANNEL(chspec), wf_chspec_to_bw_str(chspec)); #ifdef WL_P2P_6G if (!(cfg->p2p_6g_enabled)) { @@ -2775,7 +2770,7 @@ wl_cfg80211_set_ap_role( dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); #endif /* WLEASYMESH */ - new_chip = wl_new_chip_check(dev); + new_chip = dhd_conf_new_chip_check(cfg->pub); if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr)); @@ -2806,7 +2801,7 @@ wl_cfg80211_set_ap_role( } #ifdef WLEASYMESH else if (dhd->conf->fw_type == FW_TYPE_EZMESH) { - WL_MSG(dev->name, "Getting AP mode ok, set map and dwds"); + WL_MSG(dev->name, "Getting AP mode ok, set map and dwds\n"); err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32)); if (err < 0) { WL_ERR(("WLC_DOWN error %d\n", err)); @@ -2823,7 +2818,7 @@ wl_cfg80211_set_ap_role( WL_ERR(("wl dwds 1 error %d\n", err)); return err; } - WL_MSG(dev->name, "Get AP %d", (int)ap); + WL_MSG(dev->name, "Get AP %d\n", (int)ap); } #endif /* WLEASYMESH*/ @@ -2841,10 +2836,10 @@ wl_cfg80211_set_ap_role( if (wl_get_drv_status_all(cfg, CONNECTED) > 0) { #ifdef WLEASYMESH if (dhd->conf->fw_type == FW_TYPE_EZMESH) { - WL_MSG(dev->name, "do wl down"); + WL_MSG(dev->name, "do wl down\n"); } else { #endif /* WLEASYMESH */ - WL_ERR(("Concurrent i/f operational. can't do wl down")); + WL_ERR(("Concurrent i/f operational. can't do wl down\n")); return BCME_ERROR; #ifdef WLEASYMESH } @@ -2874,7 +2869,7 @@ wl_cfg80211_set_ap_role( #ifdef WLEASYMESH //For FrontHaulAP if (dhd->conf->fw_type == FW_TYPE_EZMESH) { - WL_MSG(dev->name, "wl map 2"); + WL_MSG(dev->name, "wl map 2\n"); err = wldev_iovar_setint(dev, "map", 2); if (err < 0) { WL_ERR(("wl map 2 error %d\n", err)); @@ -3092,6 +3087,14 @@ wl_cfg80211_bcn_bringup_ap( } #endif /* SOFTAP_UAPSD_OFF */ +#ifdef WLDWDS + err = wldev_iovar_setint(dev, "dwds", 1); + if (err < 0) { + WL_ERR(("set dwds error %d\n", err)); + goto exit; + } +#endif /* WLDWDS */ + err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32)); if (unlikely(err)) { WL_ERR(("WLC_UP error (%d)\n", err)); @@ -3133,12 +3136,23 @@ wl_cfg80211_bcn_bringup_ap( } if (dhd->conf->chip == BCM43430_CHIP_ID && bssidx > 0 && (wsec & (TKIP_ENABLED|AES_ENABLED))) { + struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg); + struct ether_addr bssid; + int ret = 0; wsec |= WSEC_SWFLAG; // terence 20180628: fix me, this is a workaround err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); if (err < 0) { WL_ERR(("wsec error %d\n", err)); goto exit; } + bzero(&bssid, sizeof(bssid)); + ret = wldev_ioctl_get(primary_ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN); + if (ret != BCME_NOTASSOCIATED && memcmp(ðer_null, &bssid, ETHER_ADDR_LEN)) { + scb_val_t scbval; + bzero(&scbval, sizeof(scb_val_t)); + scbval.val = WLAN_REASON_DEAUTH_LEAVING; + wldev_ioctl_set(primary_ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); + } } if ((wsec == WEP_ENABLED) && cfg->wep_key.len) { WL_DBG(("Applying buffered WEP KEY \n")); @@ -3665,14 +3679,23 @@ wl_cfg80211_start_ap( * hardcoded values in 'wl_cfg80211_set_channel()'. */ #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS)) - if (!dev->ieee80211_ptr->preset_chandef.chan) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + if (!dev->ieee80211_ptr->u.ap.preset_chandef.chan) +#else + if (!dev->ieee80211_ptr->preset_chandef.chan) +#endif + { WL_ERR(("chan is NULL\n")); err = -EINVAL; goto fail; } if ((err = wl_cfg80211_set_channel(wiphy, dev, - dev->ieee80211_ptr->preset_chandef.chan, - NL80211_CHAN_HT20) < 0)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + dev->ieee80211_ptr->u.ap.preset_chandef.chan, +#else + dev->ieee80211_ptr->preset_chandef.chan, +#endif + NL80211_CHAN_HT20) < 0)) { WL_ERR(("Set channel failed \n")); goto fail; } @@ -3759,11 +3782,18 @@ wl_cfg80211_start_ap( } } #endif /* SUPPORT_AP_RADIO_PWRSAVE */ +#ifdef WL_EXT_IAPSTA + wl_ext_in4way_sync(dev, 0, WL_EXT_STATUS_AP_ENABLING, NULL); +#endif fail: if (err) { WL_ERR(("ADD/SET beacon failed\n")); wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + wl_cfg80211_stop_ap(wiphy, dev, 0); +#else wl_cfg80211_stop_ap(wiphy, dev); +#endif if (dev_role == NL80211_IFTYPE_AP) { #ifdef WL_EXT_IAPSTA if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) { @@ -3804,7 +3834,11 @@ fail: s32 wl_cfg80211_stop_ap( struct wiphy *wiphy, - struct net_device *dev) + struct net_device *dev +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + , unsigned int link_id +#endif + ) { int err = 0; u32 dev_role = 0; @@ -3854,6 +3888,9 @@ wl_cfg80211_stop_ap( err = -EINVAL; goto exit; } +#ifdef WL_EXT_IAPSTA + wl_ext_in4way_sync(dev, 0, WL_EXT_STATUS_AP_DISABLING, NULL); +#endif /* Free up resources */ wl_cfg80211_cleanup_if(dev); @@ -4485,8 +4522,10 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, (reason == WLC_E_REASON_INITIAL_ASSOC) && (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) { if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) { + char chan_str[64]; /* AP/GO brought up successfull in firmware */ - WL_MSG(ndev->name, "AP/GO Link up\n"); + wl_ext_get_chan_str(ndev, chan_str, sizeof(chan_str)); + WL_MSG(ndev->name, "AP/GO Link up (%s)\n", chan_str); wl_set_drv_status(cfg, AP_CREATED, ndev); if (delayed_work_pending(&cfg->ap_work)) { cancel_delayed_work_sync(&cfg->ap_work); @@ -4544,6 +4583,11 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT, WL_EXT_STATUS_STA_CONNECTED, (void *)&e->addr); #endif +#ifdef STA_MGMT + if (!wl_ext_add_sta_info(ndev, (u8 *)&e->addr)) { + return -EINVAL; + } +#endif /* STA_MGMT */ cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC); #ifdef WL_WPS_SYNC wl_wps_session_update(ndev, WPS_STATE_LINKUP, e->addr.octet); @@ -4566,6 +4610,11 @@ wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev, wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT, WL_EXT_STATUS_STA_DISCONNECTED, (void *)&e->addr); #endif +#ifdef STA_MGMT + if (!wl_ext_del_sta_info(ndev, (u8 *)&e->addr)) { + return -EINVAL; + } +#endif /* STA_MGMT */ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); #ifdef WL_WPS_SYNC wl_wps_session_update(ndev, WPS_STATE_LINKDOWN, e->addr.octet); @@ -5056,44 +5105,42 @@ wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev, } #endif /* WL_CFG80211_ACL */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) int wl_chspec_chandef(chanspec_t chanspec, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) - struct cfg80211_chan_def *chandef, -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0))) - struct chan_info *chaninfo, -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */ - struct wiphy *wiphy) + struct cfg80211_chan_def *chandef, struct wiphy *wiphy) { uint16 freq = 0; - int chan_type = 0; - int channel = 0; struct ieee80211_channel *chan; if (!chandef) { return -1; + } else { + memset(chandef, 0, sizeof(*chandef)); } - channel = CHSPEC_CHANNEL(chanspec); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) + chandef->center_freq1 = wl_channel_to_frequency(CHSPEC_CHANNEL(chanspec), CHSPEC_BAND(chanspec)); + freq = wl_channel_to_frequency(wf_chspec_primary20_chan(chanspec), CHSPEC_BAND(chanspec)); + chandef->chan = ieee80211_get_channel(wiphy, freq); + chandef->center_freq2 = 0; switch (CHSPEC_BW(chanspec)) { case WL_CHANSPEC_BW_20: - chan_type = NL80211_CHAN_HT20; + chandef->width = NL80211_CHAN_WIDTH_20; break; + case WL_CHANSPEC_BW_40: - { - if (CHSPEC_SB_UPPER(chanspec)) { - channel += CH_10MHZ_APART; - } else { - channel -= CH_10MHZ_APART; - } - } - chan_type = NL80211_CHAN_HT40PLUS; + chandef->width = NL80211_CHAN_WIDTH_40; break; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) case WL_CHANSPEC_BW_80: + chandef->width = NL80211_CHAN_WIDTH_80; + break; + case WL_CHANSPEC_BW_8080: { + /* XXX Left as is but need proper calculation for center_freq2 is used */ + int chan_type = 0; + int channel = 0; uint16 sb = CHSPEC_CTL_SB(chanspec); if (sb == WL_CHANSPEC_CTL_SB_LL) { @@ -5111,19 +5158,45 @@ int wl_chspec_chandef(chanspec_t chanspec, chan_type = NL80211_CHAN_HT40MINUS; else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU) chan_type = NL80211_CHAN_HT40PLUS; - } + freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chanspec)); + chan = ieee80211_get_channel(wiphy, freq); + cfg80211_chandef_create(chandef, chan, chan_type); + return 0; break; + } + case WL_CHANSPEC_BW_160: - channel = wf_chspec_primary20_chan(chanspec); - /* Using base chan_type as kernel does not define chan_type for 160 MHz */ - chan_type = NL80211_CHAN_HT20; + chandef->width = NL80211_CHAN_WIDTH_160; break; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ default: + chandef->width = NL80211_CHAN_WIDTH_20; + break; + } + +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && \ + (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 7, 0))) + + int chan_type = 0; + int channel = 0; + channel = CHSPEC_CHANNEL(chanspec); + switch (CHSPEC_BW(chanspec)) { + case WL_CHANSPEC_BW_20: chan_type = NL80211_CHAN_HT20; break; + case WL_CHANSPEC_BW_40: + if (CHSPEC_SB_UPPER(chanspec)) { + channel += CH_10MHZ_APART; + } else { + channel -= CH_10MHZ_APART; + } + chan_type = NL80211_CHAN_HT40PLUS; + break; + default: + chan_type = NL80211_CHAN_HT20; + break; } + freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chanspec)); chan = ieee80211_get_channel(wiphy, freq); WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n", @@ -5135,24 +5208,19 @@ int wl_chspec_chandef(chanspec_t chanspec, return -EINVAL; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) - cfg80211_chandef_create(chandef, chan, chan_type); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0))) - chaninfo->freq = freq; - chaninfo->chan_type = chan_type; + chandef->freq = freq; + chandef->chan_type = chan_type; #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ + return 0; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) void wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy) { u32 freq; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) struct cfg80211_chan_def chandef; -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0))) - struct chan_info chaninfo; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ if (!wiphy) { WL_ERR(("wiphy is null\n")); @@ -5167,21 +5235,21 @@ wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wip } #endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) - if (wl_chspec_chandef(chanspec, &chandef, wiphy)) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0))) - if (wl_chspec_chandef(chanspec, &chaninfo, wiphy)) -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ - { + if (wl_chspec_chandef(chanspec, &chandef, wiphy)) { WL_ERR(("chspec_chandef failed\n")); return; } + #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) + cfg80211_ch_switch_notify(dev, &chandef, 0); +#else cfg80211_ch_switch_notify(dev, &chandef); +#endif #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0))) - freq = chan_info.freq; - cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type); + freq = chandef.freq; + cfg80211_ch_switch_notify(dev, freq, chandef.chan_type); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */ WL_MSG(dev->name, "Channel switch notification for freq: %d chanspec: 0x%x\n", diff --git a/bcmdhd.101.10.361.x/wl_cfgvif.h b/bcmdhd.101.10.361.x/wl_cfgvif.h index 09f63fb..e7daeec 100755 --- a/bcmdhd.101.10.361.x/wl_cfgvif.h +++ b/bcmdhd.101.10.361.x/wl_cfgvif.h @@ -195,7 +195,12 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, defined(WL_COMPAT_WIRELESS) extern s32 wl_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *info); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2) || defined(CFG80211_BKPORT_MLO) +extern s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id); +#else extern s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev); +#endif extern s32 wl_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *info); #else @@ -248,4 +253,7 @@ extern bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len); #ifdef SUPPORT_AP_BWCTRL extern void wl_restore_ap_bw(struct bcm_cfg80211 *cfg); #endif /* SUPPORT_AP_BWCTRL */ + +extern int wl_chspec_chandef(chanspec_t chanspec, + struct cfg80211_chan_def *chandef, struct wiphy *wiphy); #endif /* _wl_cfgvif_h_ */ diff --git a/bcmdhd.101.10.361.x/wl_escan.c b/bcmdhd.101.10.361.x/wl_escan.c index 666a5b2..11e6bdc 100755 --- a/bcmdhd.101.10.361.x/wl_escan.c +++ b/bcmdhd.101.10.361.x/wl_escan.c @@ -41,11 +41,11 @@ #define dtohchanspec(i) (i) #define WL_EXTRA_BUF_MAX 2048 -#define wl_escan_get_buf(a) ((wl_scan_results_t *) (a)->escan_buf) +#define wl_escan_get_buf(a) ((wl_scan_results_v109_t *) (a)->escan_buf) #if defined(WL_WIRELESS_EXT) extern int wl_iw_handle_scanresults_ies(char **event_p, char *end, - struct iw_request_info *info, wl_bss_info_t *bi); + struct iw_request_info *info, wl_bss_info_v109_t *bi); #define for_each_bss_wext(list, bss, __i) \ for (__i = 0; __i < list->count && __i < IW_MAX_AP; __i++, bss = next_bss(list, bss)) #endif @@ -205,7 +205,7 @@ wl_ch_host_to_driver(int ioctl_ver, u16 channel) return wl_chspec_host_to_driver(ioctl_ver, chanspec); } -static inline struct wl_bss_info *next_bss(wl_scan_results_t *list, +static inline struct wl_bss_info *next_bss(wl_scan_results_v109_t *list, struct wl_bss_info *bss) { return bss = bss ? @@ -216,7 +216,7 @@ static inline struct wl_bss_info *next_bss(wl_scan_results_t *list, #ifndef BSSCACHE static void wl_escan_dump_bss(struct net_device *dev, struct wl_escan_info *escan, - wl_bss_info_t *bi) + wl_bss_info_v109_t *bi) { int16 rssi; int channel; @@ -244,9 +244,9 @@ wl_escan_dump_bss(struct net_device *dev, struct wl_escan_info *escan, static s32 wl_escan_inform_bss(struct net_device *dev, struct wl_escan_info *escan) { - wl_scan_results_t *bss_list; + wl_scan_results_v109_t *bss_list; #ifndef BSSCACHE - wl_bss_info_t *bi = NULL; /* must be initialized */ + wl_bss_info_v109_t *bi = NULL; /* must be initialized */ s32 i; #endif s32 err = 0; @@ -283,34 +283,34 @@ wl_escan_inform_bss(struct net_device *dev, struct wl_escan_info *escan) wl_reset_bss_cache(&escan->g_bss_cache_ctrl); if (escan->autochannel) wl_ext_get_best_channel(dev, &escan->g_bss_cache_ctrl, - escan->ioctl_ver, &escan->best_2g_ch, &escan->best_5g_ch); + &escan->best_2g_ch, &escan->best_5g_ch, &escan->best_6g_ch); #else bi = next_bss(bss_list, bi); for_each_bss(bss_list, bi, i) { wl_escan_dump_bss(dev, escan, bi); } if (escan->autochannel) - wl_ext_get_best_channel(dev, bss_list, escan->ioctl_ver, - &escan->best_2g_ch, &escan->best_5g_ch); + wl_ext_get_best_channel(dev, bss_list, + &escan->best_2g_ch, &escan->best_5g_ch, &escan->best_6g_ch); #endif return err; } #endif /* ESCAN_RESULT_PATCH */ -static wl_scan_params_t * +static wl_scan_params_v1_t * wl_escan_alloc_params(struct net_device *dev, struct wl_escan_info *escan, int channel, int nprobes, int *out_params_size) { - wl_scan_params_t *params; + wl_scan_params_v1_t *params; int params_size; int num_chans; *out_params_size = 0; /* Our scan params only need space for 1 channel and 0 ssids */ - params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); - params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); + params_size = WL_SCAN_PARAMS_V1_FIXED_SIZE + 1 * sizeof(uint16); + params = (wl_scan_params_v1_t*) kzalloc(params_size, GFP_KERNEL); if (params == NULL) { ESCAN_ERROR(dev->name, "mem alloc failed (%d bytes)\n", params_size); return params; @@ -343,7 +343,7 @@ wl_escan_alloc_params(struct net_device *dev, struct wl_escan_info *escan, static void wl_escan_abort(struct net_device *dev, struct wl_escan_info *escan) { - wl_scan_params_t *params = NULL; + wl_scan_params_v1_t *params = NULL; s32 params_size = 0; s32 err = BCME_OK; if (!in_atomic()) { @@ -416,7 +416,7 @@ wl_escan_notify_complete(struct net_device *dev, #ifdef ESCAN_BUF_OVERFLOW_MGMT static void wl_escan_find_removal_candidate(struct wl_escan_info *escan, - wl_bss_info_t *bss, removal_element_t *candidate) + wl_bss_info_v109_t *bss, removal_element_t *candidate) { int idx; for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) { @@ -435,17 +435,17 @@ wl_escan_find_removal_candidate(struct wl_escan_info *escan, static void wl_escan_remove_lowRSSI_info(struct net_device *dev, struct wl_escan_info *escan, - wl_scan_results_t *list, removal_element_t *candidate, wl_bss_info_t *bi) + wl_scan_results_v109_t *list, removal_element_t *candidate, wl_bss_info_v109_t *bi) { int idx1, idx2; int total_delete_len = 0; for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) { - int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; - wl_bss_info_t *bss = NULL; + int cur_len = WL_SCAN_RESULTS_V109_FIXED_SIZE; + wl_bss_info_v109_t *bss = NULL; if (candidate[idx1].RSSI >= bi->RSSI) continue; for (idx2 = 0; idx2 < list->count; idx2++) { - bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) : + bss = bss ? (wl_bss_info_v109_t *)((uintptr)bss + dtoh32(bss->length)) : list->bss_info; if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) && candidate[idx1].RSSI == bss->RSSI && @@ -478,16 +478,16 @@ wl_escan_ext_handler(struct net_device *dev, void *argu, { struct wl_escan_info *escan = (struct wl_escan_info *)argu; s32 status = ntoh32(e->status); - wl_bss_info_t *bi; - wl_escan_result_t *escan_result; - wl_bss_info_t *bss = NULL; - wl_scan_results_t *list; + wl_bss_info_v109_t *bi; + wl_escan_result_v109_t *escan_result; + wl_bss_info_v109_t *bss = NULL; + wl_scan_results_v109_t *list; u32 bi_length; u32 i; u16 channel; mutex_lock(&escan->usr_sync); - escan_result = (wl_escan_result_t *)data; + escan_result = (wl_escan_result_v109_t *)data; if (escan->escan_state != ESCAN_STATE_SCANING) { ESCAN_DBG(dev->name, "Not my scan\n"); @@ -514,7 +514,7 @@ wl_escan_ext_handler(struct net_device *dev, void *argu, goto exit; } bi_length = dtoh32(bi->length); - if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { + if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_V109_FIXED_SIZE)) { ESCAN_ERROR(dev->name, "Invalid bss_info length %d: ignoring\n", bi_length); goto exit; @@ -529,7 +529,7 @@ wl_escan_ext_handler(struct net_device *dev, void *argu, /* ----- terence 20130524: skip invalid bss */ { - int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; + int cur_len = WL_SCAN_RESULTS_V109_FIXED_SIZE; #ifdef ESCAN_BUF_OVERFLOW_MGMT removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT]; int remove_lower_rssi = FALSE; @@ -546,7 +546,7 @@ wl_escan_ext_handler(struct net_device *dev, void *argu, ESCAN_DBG(dev->name, "%s(%pM) RSSI %d flags 0x%x length %d\n", bi->SSID, &bi->BSSID, bi->RSSI, bi->flags, bi->length); for (i = 0; i < list->count; i++) { - bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) + bss = bss ? (wl_bss_info_v109_t *)((uintptr)bss + dtoh32(bss->length)) : list->bss_info; #ifdef ESCAN_BUF_OVERFLOW_MGMT ESCAN_DBG(dev->name, @@ -690,17 +690,15 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan, wl_uint32_list_t *list, void *scan_params, wl_scan_info_t *scan_info) { int err = 0; - wl_scan_results_t *results; + wl_scan_results_v109_t *results; char *ptr; int i = 0, j = 0; wlc_ssid_t ssid_tmp; u32 n_channels = 0; - uint channel; chanspec_t chanspec; u32 n_ssids = 0; - wl_scan_params_t *params = NULL; + wl_scan_params_v1_t *params = NULL; wl_scan_params_v2_t *params_v2 = NULL; - u32 scan_param_size = 0; u32 channel_offset = 0; u32 cur_offset; uint16 *chan_list = NULL; @@ -708,7 +706,7 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan, results = wl_escan_get_buf(escan); results->version = 0; results->count = 0; - results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; + results->buflen = WL_SCAN_RESULTS_V109_FIXED_SIZE; escan->escan_state = ESCAN_STATE_SCANING; /* Arm scan timeout timer */ @@ -716,12 +714,10 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan, if (escan->scan_params_v2) { params_v2 = (wl_scan_params_v2_t *)scan_params; - scan_param_size = sizeof(wl_scan_params_v2_t); channel_offset = offsetof(wl_scan_params_v2_t, channel_list); } else { - params = (wl_scan_params_t *)scan_params; - scan_param_size = sizeof(wl_scan_params_t); - channel_offset = offsetof(wl_scan_params_t, channel_list); + params = (wl_scan_params_v1_t *)scan_params; + channel_offset = offsetof(wl_scan_params_v1_t, channel_list); } if (params_v2) { @@ -748,7 +744,7 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan, params->scan_type = DOT11_SCANTYPE_ACTIVE; params->nprobes = htod32(-1); if (scan_info->scan_time) - params_v2->active_time = htod32(scan_info->scan_time); + params->active_time = htod32(scan_info->scan_time); else params->active_time = htod32(-1); params->passive_time = htod32(-1); @@ -760,29 +756,19 @@ wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan, cur_offset = channel_offset; - n_channels = dtoh32(list->count); + n_channels = list->count; /* Copy channel array if applicable */ ESCAN_SCAN(dev->name, "### List of channelspecs to scan ###\n"); if (n_channels > 0) { for (i = 0; i < n_channels; i++) { - channel = dtoh32(list->element[i]); - if (!dhd_conf_match_channel(escan->pub, channel)) - continue; - chanspec = WL_CHANSPEC_BW_20; + chanspec = list->element[i]; if (chanspec == INVCHANSPEC) { ESCAN_ERROR(dev->name, "Invalid chanspec! Skipping channel\n"); continue; } - if (channel <= CH_MAX_2G_CHANNEL) { - chanspec |= WL_CHANSPEC_BAND_2G; - } else { - chanspec |= WL_CHANSPEC_BAND_5G; - } - chan_list[j] = channel; - chan_list[j] &= WL_CHANSPEC_CHAN_MASK; - chan_list[j] |= chanspec; + chan_list[j] = chanspec; ESCAN_SCAN(dev->name, "Chan : %d, Channel spec: %x\n", - channel, chan_list[j]); + CHSPEC_CHANNEL(chanspec), chanspec); chan_list[j] = wl_chspec_host_to_driver(escan->ioctl_ver, chan_list[j]); j++; @@ -854,7 +840,7 @@ wl_escan_timeout(unsigned long data) { wl_event_msg_t msg; struct wl_escan_info *escan = (struct wl_escan_info *)data; - wl_scan_results_t *bss_list; + wl_scan_results_v109_t *bss_list; struct wl_bss_info *bi = NULL; s32 i; u32 channel; @@ -894,14 +880,13 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) struct dhd_pub *dhdp = dhd_get_pub(dev); struct wl_escan_info *escan = dhdp->escan; s32 err = BCME_OK; - wl_escan_params_t *eparams = NULL; + wl_escan_params_v1_t *eparams = NULL; wl_escan_params_v2_t *eparams_v2 = NULL; - u8 *scan_params = NULL; + u8 *scan_params = NULL, *params = NULL; s32 params_size; - wl_escan_params_t *params = NULL; u32 n_channels = 0; wl_uint32_list_t *list; - u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; + u8 valid_chan_list[sizeof(u32)*(MAX_CTRL_CHANSPECS + 1)]; mutex_lock(&escan->usr_sync); if (escan->escan_state == ESCAN_STATE_DOWN) { @@ -923,14 +908,14 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) goto exit2; } - ESCAN_TRACE(dev->name, "Enter \n"); + ESCAN_TRACE(dev->name, "Enter\n"); if (escan->scan_params_v2) { params_size = (WL_SCAN_PARAMS_V2_FIXED_SIZE + OFFSETOF(wl_escan_params_v2_t, params)); } else { - params_size = (WL_SCAN_PARAMS_FIXED_SIZE + - OFFSETOF(wl_escan_params_t, params)); + params_size = (WL_SCAN_PARAMS_V1_FIXED_SIZE + + OFFSETOF(wl_escan_params_v1_t, params)); } /* if scan request is not empty parse scan request paramters */ @@ -940,18 +925,16 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) if (scan_info->channels.count) { memcpy(list, &scan_info->channels, sizeof(wl_channel_list_t)); } else { - list->count = htod32(WL_NUMCHANNELS); - err = wldev_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list, - sizeof(valid_chan_list), false); + err = wl_construct_ctl_chanspec_list(dev, list); if (err != 0) { ESCAN_ERROR(dev->name, "get channels failed with %d\n", err); goto exit; } } - n_channels = dtoh32(list->count); - /* Allocate space for populating ssids in wl_escan_params_t struct */ - if (dtoh32(list->count) % 2) + n_channels = list->count; + /* Allocate space for populating ssids in wl_escan_params_v1_t struct */ + if (list->count % 2) /* If n_channels is odd, add a padd of u16 */ params_size += sizeof(u16) * (n_channels + 1); else @@ -960,7 +943,7 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) params_size += sizeof(struct wlc_ssid) * 2; } - params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); + params = kzalloc(params_size, GFP_KERNEL); if (params == NULL) { ESCAN_ERROR(dev->name, "kzalloc failed\n"); err = -ENOMEM; @@ -972,13 +955,14 @@ wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info) scan_params = (u8 *)&eparams_v2->params; eparams_v2->version = htod32(ESCAN_REQ_VERSION_V2); eparams_v2->action = htod16(WL_SCAN_ACTION_START); + wl_escan_set_sync_id(eparams_v2->sync_id); } else { - eparams = (wl_escan_params_t *)params; + eparams = (wl_escan_params_v1_t *)params; scan_params = (u8 *)&eparams->params; - eparams->version = htod32(ESCAN_REQ_VERSION); + eparams->version = htod32(ESCAN_REQ_VERSION_V1); eparams->action = htod16(WL_SCAN_ACTION_START); + wl_escan_set_sync_id(eparams->sync_id); } - wl_escan_set_sync_id(params->sync_id); wl_escan_prep(dev, escan, list, scan_params, scan_info); @@ -1027,7 +1011,7 @@ rssi_to_qual(int rssi) static int wl_escan_merge_scan_results(struct net_device *dev, struct wl_escan_info *escan, - struct iw_request_info *info, char *extra, wl_bss_info_t *bi, int *len, int max_size) + struct iw_request_info *info, char *extra, wl_bss_info_v109_t *bi, int *len, int max_size) { s32 err = BCME_OK; struct iw_event iwe; @@ -1150,8 +1134,8 @@ wl_escan_merge_scan_list(struct net_device *dev, u8 *cur_bssid, s32 err = BCME_OK; int i = 0, cnt = 0; int len_prep = 0; - wl_bss_info_t *bi = NULL; - wl_scan_results_t *bss_list; + wl_bss_info_v109_t *bi = NULL; + wl_scan_results_v109_t *bss_list; __u16 buflen_from_user = dwrq->length; bss_list = escan->bss_list; @@ -1187,8 +1171,8 @@ wl_escan_merge_cache_list(struct net_device *dev, u8 *cur_bssid, s32 err = BCME_OK; int i = 0, cnt = 0; int len_prep = 0; - wl_bss_info_t *bi = NULL; - wl_scan_results_t *bss_list; + wl_bss_info_v109_t *bi = NULL; + wl_scan_results_v109_t *bss_list; __u16 buflen_from_user = dwrq->length; wl_bss_cache_t *node; @@ -1232,7 +1216,7 @@ wl_escan_get_scan(struct net_device *dev, int cache_cnt = 0; #endif int len_prep = 0, len_ret = 0; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; __u16 buflen_from_user = dwrq->length; char *buf = NULL; struct ether_addr cur_bssid; @@ -1389,8 +1373,8 @@ wl_escan_mesh_info(struct net_device *dev, struct wl_escan_info *escan, struct ether_addr *peer_bssid, struct wl_mesh_params *mesh_info) { int i = 0; - wl_bss_info_t *bi = NULL; - wl_scan_results_t *bss_list; + wl_bss_info_v109_t *bi = NULL; + wl_scan_results_v109_t *bss_list; int16 bi_rssi, bi_chan; wlc_ssid_t bi_meshid; bool is_mesh_peer = FALSE, found = FALSE; @@ -1461,8 +1445,8 @@ wl_escan_mesh_peer(struct net_device *dev, struct wl_escan_info *escan, struct wl_mesh_params *mesh_info) { int i = 0; - wl_bss_info_t *bi = NULL; - wl_scan_results_t *bss_list; + wl_bss_info_v109_t *bi = NULL; + wl_scan_results_v109_t *bss_list; int16 bi_rssi, bi_chan, max_rssi = -100; uint min_hop_cnt = 255; wlc_ssid_t bi_meshid; diff --git a/bcmdhd.101.10.361.x/wl_escan.h b/bcmdhd.101.10.361.x/wl_escan.h index fcd19d9..9e652ea 100755 --- a/bcmdhd.101.10.361.x/wl_escan.h +++ b/bcmdhd.101.10.361.x/wl_escan.h @@ -5,8 +5,8 @@ #if defined(WL_WIRELESS_EXT) #include #endif /* WL_WIRELESS_EXT */ -#include #include +#include #include #define ESCAN_BUF_SIZE (64 * 1024) @@ -35,12 +35,13 @@ typedef struct wl_escan_info { int escan_state; int ioctl_ver; u8 escan_buf[ESCAN_BUF_SIZE]; - wl_scan_results_t *bss_list; + wl_scan_results_v109_t *bss_list; u8 *escan_ioctl_buf; struct mutex usr_sync; /* maily for up/down synchronization */ int autochannel; int best_2g_ch; int best_5g_ch; + int best_6g_ch; #if defined(RSSIAVG) wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl; @@ -64,7 +65,7 @@ typedef struct wl_mesh_params { uint16 master_channel; uint hop_cnt; struct ether_addr peer_bssid[MAX_HOP_LIST]; - uint16 scan_channel; + uint32 scan_channel; } wl_mesh_params_t; bool wl_escan_mesh_info(struct net_device *dev, struct wl_escan_info *escan, struct ether_addr *peer_bssid, diff --git a/bcmdhd.101.10.361.x/wl_event.c b/bcmdhd.101.10.361.x/wl_event.c index a111b3f..2d2a999 100755 --- a/bcmdhd.101.10.361.x/wl_event.c +++ b/bcmdhd.101.10.361.x/wl_event.c @@ -312,7 +312,8 @@ wl_ext_event_create_handler(struct wl_event_params *event_params) #else /* Allocate workqueue for event */ if (!event_params->event_workq) { - event_params->event_workq = alloc_workqueue("ext_eventd", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + event_params->event_workq = alloc_workqueue("ext_eventd", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0); } if (!event_params->event_workq) { @@ -386,6 +387,7 @@ wl_ext_event_register(struct net_device *dev, dhd_pub_t *dhd, uint32 event, mutex_unlock(&event_params->event_sync); return -ENOMEM; } + memset(leaf, 0, sizeof(event_handler_list_t)); leaf->next = NULL; leaf->dev = dev; leaf->etype = event; diff --git a/bcmdhd.101.10.361.x/wl_iapsta.c b/bcmdhd.101.10.361.x/wl_iapsta.c index aeaef14..1113cda 100755 --- a/bcmdhd.101.10.361.x/wl_iapsta.c +++ b/bcmdhd.101.10.361.x/wl_iapsta.c @@ -3,15 +3,27 @@ #include #include #include +#include #include #include #ifdef WL_CFG80211 #include +#include #endif /* WL_CFG80211 */ #ifdef WL_ESCAN #include #endif /* WL_ESCAN */ +#ifdef BTC_WAR +/* btc_war: + * -1(don't apply btc) + * 0(disable btc war): btc_mode=1; txchain=3; rxchain=3 + * 1(enable btc war): txchain=2; rxchain=2; btc_mode=5 + */ +int btc_war = -1; +module_param(btc_war, int, 0644); +#endif /* BTC_WAR */ + #define IAPSTA_ERROR(name, arg1, args...) \ do { \ if (android_msg_level & ANDROID_ERROR_LEVEL) { \ @@ -56,14 +68,35 @@ extern int disable_proptx; #define CSA_FW_BIT (1<<0) #define CSA_DRV_BIT (1<<1) +#define WL_DUMP_BUF_LEN (127 * 1024) + #define MAX_AP_LINK_WAIT_TIME 3000 #define MAX_STA_LINK_WAIT_TIME 15000 #define STA_LINKDOWN_TIMEOUT 10000 #define STA_CONNECT_TIMEOUT 10500 +#define STA_CONNECT_FULL_CHAN_TIMEOUT 3000 #define STA_CONNECT_RETRY_TIMEOUT 600 #define STA_RECONNECT_RETRY_TIMEOUT 300 +#define STA_DISCONNECT_RECONNECT_TIMEOUT 30000 +#define STA_DISCONNECT_RECONNECT_MAX 3 +#define STA_4WAY_TIMEOUT 1000 +#ifdef EAPOL_RESEND_M4 +#define STA_KEY_INSTALL_INTERVAL 50 +#define STA_KEY_INSTALL_MAX (STA_4WAY_TIMEOUT/STA_KEY_INSTALL_INTERVAL) +#else +#define STA_KEY_INSTALL_INTERVAL 50 +#define STA_KEY_INSTALL_MAX 3 +#endif #define STA_EAPOL_TIMEOUT 100 #define STA_EMPTY_SCAN_MAX 6 +#define AP_RESTART_TIMEOUT 1000 +#define AP_TXBCNFRM_TIMEOUT 10000 +#ifdef RXF0OVFL_REINIT_WAR +#define RXF0OVFL_POLLING_TIMEOUT 1000 +#define RXF0OVFL_THRESHOLD 100 +#endif /* RXF0OVFL_REINIT_WAR */ + +#define MAX_DWDS_IF_NUM 4 enum wl_if_list { IF_PIF, @@ -120,6 +153,37 @@ typedef enum ENCMODE { ENC_TKIPAES } encmode_t; +#ifdef STA_MGMT +typedef struct wl_sta_info { + int ifidx; + struct ether_addr bssid; + struct list_head list; +} wl_sta_info_t; +#endif /* STA_MGMT */ + +#ifdef TPUT_MONITOR +typedef struct wl_tput_info { + unsigned long last_tx; + unsigned long last_rx; + struct osl_timespec tput_ts; + int32 tput_tx; + int32 tput_rx; + int32 tput_tx_kb; + int32 tput_rx_kb; +} wl_tput_info_t; +#endif /* TPUT_MONITOR */ + +#ifdef WLDWDS +typedef struct wl_dwds_info { + struct net_device *dev; + int ifidx; + uint8 bssidx; +#ifdef TPUT_MONITOR + struct wl_tput_info tput_info; +#endif /* TPUT_MONITOR */ +} wl_dwds_info_t; +#endif /* WLDWDS */ + typedef struct wl_if_info { struct net_device *dev; ifmode_t ifmode; @@ -134,7 +198,7 @@ typedef struct wl_if_info { bgnmode_t bgnmode; int hidden; int maxassoc; - uint16 channel; + struct wl_chan_info chan_info; authmode_t amode; encmode_t emode; bool vsdb; @@ -158,14 +222,14 @@ typedef struct wl_if_info { uint conn_state; uint16 prev_channel; uint16 post_channel; + struct osl_timespec sta_disc_ts; + struct osl_timespec sta_conn_ts; + bool ap_recon_sta; + wait_queue_head_t ap_recon_sta_event; + struct ether_addr ap_disc_sta_bssid; + struct osl_timespec ap_disc_sta_ts; #ifdef TPUT_MONITOR - unsigned long last_tx; - unsigned long last_rx; - struct osl_timespec tput_ts; - int32 tput_tx; - int32 tput_rx; - int32 tput_tx_kb; - int32 tput_rx_kb; + struct wl_tput_info tput_info; #endif /* TPUT_MONITOR */ timer_list_compat_t connect_timer; #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) @@ -185,13 +249,32 @@ typedef struct wl_if_info { int eapol_resend_intvl; #endif /* EAPOL_DYNAMATIC_RESEND */ #endif /* EAPOL_RESEND */ +#ifdef KEY_INSTALL_CHECK + timer_list_compat_t key_install_timer; + int key_install_cnt; +#endif /* KEY_INSTALL_CHECK */ int empty_scan; +#ifdef RESTART_AP_WAR + timer_list_compat_t restart_ap_timer; +#endif /* RESTART_AP_WAR */ +#ifdef RESET_AP_WAR + timer_list_compat_t reset_ap_timer; + uint32 txbcnfrm; +#endif /* RESET_AP_WAR */ +#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) +#ifdef WL_EXT_DISCONNECT_RECONNECT + struct osl_timespec sta_disc_conn_ts; + int sta_disc_recon_cnt; +#endif /* WL_EXT_DISCONNECT_RECONNECT */ +#endif /* WL_EXT_RECONNECT && WL_CFG80211 */ } wl_if_info_t; typedef struct wl_apsta_params { struct wl_if_info if_info[MAX_IF_NUM]; - struct dhd_pub *dhd; - int ioctl_ver; +#ifdef WLDWDS + struct wl_dwds_info dwds_info[MAX_DWDS_IF_NUM]; +#endif /* WLDWDS */ + u8 *ioctl_buf; bool init; int rsdb; bool vsdb; @@ -210,12 +293,6 @@ typedef struct wl_apsta_params { #endif /* WLMESH && WL_ESCAN */ struct mutex in4way_sync; int sta_btc_mode; - struct osl_timespec sta_disc_ts; - struct osl_timespec sta_conn_ts; - bool ap_recon_sta; - wait_queue_head_t ap_recon_sta_event; - struct ether_addr ap_disc_sta_bssid; - struct osl_timespec ap_disc_sta_ts; #ifdef TPUT_MONITOR timer_list_compat_t monitor_timer; int32 tput_sum; @@ -229,6 +306,15 @@ typedef struct wl_apsta_params { #ifdef EAPOL_RESEND spinlock_t eapol_lock; #endif /* EAPOL_RESEND */ +#ifdef STA_MGMT + struct list_head sta_list; +#endif /* STA_MGMT */ +#ifdef RXF0OVFL_REINIT_WAR + timer_list_compat_t rxf0ovfl_timer; + uint32 rxbeaconmbss; + uint32 rxf0ovfl; + int war_reason; +#endif /* RXF0OVFL_REINIT_WAR */ } wl_apsta_params_t; enum wifi_isam_status { @@ -244,7 +330,11 @@ enum wifi_isam_reason { ISAM_RC_MESH_ACS = 1, ISAM_RC_TPUT_MONITOR = 2, ISAM_RC_AP_ACS = 3, - ISAM_RC_EAPOL_RESEND = 4 + ISAM_RC_AP_RESTART = 4, + ISAM_RC_AP_RESET = 5, + ISAM_RC_EAPOL_RESEND = 6, + ISAM_RC_KEY_INSTALL = 7, + ISAM_RC_RXF0OVFL_REINIT = 8 }; #define wl_get_isam_status(cur_if, stat) \ @@ -259,9 +349,6 @@ enum wifi_isam_reason { static int wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock); static int wl_ext_disable_iface(struct net_device *dev, char *ifname); -#if defined(WLMESH) && defined(WL_ESCAN) -static int wl_mesh_escan_attach(dhd_pub_t *dhd, struct wl_if_info *cur_if); -#endif /* WLMESH && WL_ESCAN */ static struct wl_if_info * wl_get_cur_if(struct net_device *dev) @@ -548,17 +635,17 @@ wl_ext_set_amode(struct wl_if_info *cur_if) } static int -wl_ext_set_emode(struct wl_apsta_params *apsta_params, - struct wl_if_info *cur_if) +wl_ext_set_emode(struct wl_if_info *cur_if) { struct net_device *dev = cur_if->dev; - int wsec=0; + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct wl_wsec_key wsec_key; wsec_pmk_t psk; authmode_t amode = cur_if->amode; encmode_t emode = cur_if->emode; + int wsec=0; char *key = cur_if->key; - struct dhd_pub *dhd = apsta_params->dhd; memset(&wsec_key, 0, sizeof(wsec_key)); memset(&psk, 0, sizeof(psk)); @@ -632,18 +719,40 @@ wl_ext_set_emode(struct wl_apsta_params *apsta_params, return 0; } -static u32 -wl_ext_get_chanspec(struct wl_apsta_params *apsta_params, - struct net_device *dev) +static void +wl_ext_set_chan_info(struct wl_if_info *cur_if, uint band, uint16 chan) +{ + cur_if->chan_info.band = band; + cur_if->chan_info.chan = chan; +} + +static bool +wl_ext_associated(struct net_device *dev) { - int ret = 0; struct ether_addr bssid; - u32 chanspec = 0; + int ret = 0; ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0); if (ret != BCME_NOTASSOCIATED && memcmp(ðer_null, &bssid, ETHER_ADDR_LEN)) { + return TRUE; + } + + return FALSE; +} + +static u32 +wl_ext_get_chanspec(struct net_device *dev, struct wl_chan_info *chan_info) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + u32 chanspec = 0; + + if (wl_ext_associated(dev)) { if (wl_ext_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) { - chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec); + chanspec = wl_ext_chspec_driver_to_host(dhd, chanspec); + if (chan_info) { + chan_info->band = CHSPEC2WLC_BAND(chanspec); + chan_info->chan = wf_chspec_ctlchan(chanspec); + } return chanspec; } } @@ -652,77 +761,82 @@ wl_ext_get_chanspec(struct wl_apsta_params *apsta_params, } static uint16 -wl_ext_get_chan(struct wl_apsta_params *apsta_params, struct net_device *dev) +wl_ext_get_chan(struct net_device *dev, struct wl_chan_info *chan_info) { - int ret = 0; uint16 chan = 0, ctl_chan; - struct ether_addr bssid; u32 chanspec = 0; - - ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0); - if (ret != BCME_NOTASSOCIATED && memcmp(ðer_null, &bssid, ETHER_ADDR_LEN)) { - if (wl_ext_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) { - chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec); - ctl_chan = wf_chspec_ctlchan(chanspec); - chan = (u16)(ctl_chan & 0x00FF); - return chan; - } + + chanspec = wl_ext_get_chanspec(dev, chan_info); + if (chanspec) { + ctl_chan = wf_chspec_ctlchan(chanspec); + chan = (u16)(ctl_chan & 0x00FF); } - return 0; + return chan; +} + +void +wl_ext_get_chan_str(struct net_device *dev, char *chan_str, int total_len) +{ + struct wl_chan_info chan_info; + int bytes_written=0; + u32 chanspec = 0; + + memset(chan_str, 0, total_len); + chanspec = wl_ext_get_chanspec(dev, &chan_info); + if (chanspec) { + bytes_written += snprintf(chan_str+bytes_written, total_len, "%s-%d %sMHz", + WLCBAND2STR(chan_info.band), chan_info.chan, + wf_chspec_to_bw_str(chanspec)); + } } static chanspec_t -wl_ext_chan_to_chanspec(struct wl_apsta_params *apsta_params, - struct net_device *dev, uint16 channel) +wl_ext_chan_to_chanspec(struct net_device *dev, struct wl_chan_info *chan_info) { - s32 _chan = channel; - chanspec_t chspec = 0; - chanspec_t fw_chspec = 0; + struct dhd_pub *dhd = dhd_get_pub(dev); + chanspec_band_t chanspec_band; + chanspec_t chspec = 0, fw_chspec = 0; u32 bw = WL_CHANSPEC_BW_20; - s32 err = BCME_OK; - s32 bw_cap = 0; + s32 err = BCME_OK, bw_cap = 0; s8 iovar_buf[WLC_IOCTL_SMLEN]; struct { u32 band; u32 bw_cap; } param = {0, 0}; - uint band; - if (_chan <= CH_MAX_2G_CHANNEL) - band = IEEE80211_BAND_2GHZ; - else - band = IEEE80211_BAND_5GHZ; + if ((chan_info->band != WLC_BAND_2G) && (chan_info->band != WLC_BAND_5G) && + (chan_info->band != WLC_BAND_6G)) { + IAPSTA_ERROR(dev->name, "bad band %d\n", chan_info->band); + return BCME_BADBAND; + } - if (band == IEEE80211_BAND_5GHZ) { - param.band = WLC_BAND_5G; - err = wl_ext_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), - iovar_buf, WLC_IOCTL_SMLEN, NULL); - if (err) { - if (err != BCME_UNSUPPORTED) { - IAPSTA_ERROR(dev->name, "bw_cap failed, %d\n", err); - return err; - } else { - err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap); - if (bw_cap != WLC_N_BW_20ALL) - bw = WL_CHANSPEC_BW_40; - } + param.band = chan_info->band; + err = wl_ext_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), + iovar_buf, WLC_IOCTL_SMLEN, NULL); + if (err) { + if (err != BCME_UNSUPPORTED) { + IAPSTA_ERROR(dev->name, "bw_cap failed, %d\n", err); + return err; } else { - if (WL_BW_CAP_80MHZ(iovar_buf[0])) - bw = WL_CHANSPEC_BW_80; - else if (WL_BW_CAP_40MHZ(iovar_buf[0])) + err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap); + if (bw_cap != WLC_N_BW_20ALL) bw = WL_CHANSPEC_BW_40; - else - bw = WL_CHANSPEC_BW_20; } + } else { + if (WL_BW_CAP_80MHZ(iovar_buf[0])) + bw = WL_CHANSPEC_BW_80; + else if (WL_BW_CAP_40MHZ(iovar_buf[0])) + bw = WL_CHANSPEC_BW_40; + else + bw = WL_CHANSPEC_BW_20; } - else if (band == IEEE80211_BAND_2GHZ) - bw = WL_CHANSPEC_BW_20; set_channel: - chspec = wf_channel2chspec(_chan, bw); + chanspec_band = wl_ext_wlcband_to_chanspec_band(chan_info->band); + chspec = wf_create_chspec_from_primary(chan_info->chan, bw, chanspec_band); if (wf_chspec_valid(chspec)) { - fw_chspec = wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver, chspec); + fw_chspec = wl_ext_chspec_host_to_driver(dhd, chspec); if (fw_chspec == INVCHANSPEC) { IAPSTA_ERROR(dev->name, "failed to convert host chanspec to fw chanspec\n"); fw_chspec = 0; @@ -769,60 +883,98 @@ wl_ext_assoclist(struct net_device *dev, char *data, char *command, assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST); ret = wl_ext_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), 0); if (ret) - return -1; + return 0; maxassoc = dtoh32(assoc_maclist->count); - bytes_written += snprintf(command+bytes_written, total_len, - "%2s: %12s", - "no", "------addr------"); for (i=0; iea[i]); + "\n#%02d: %pM", i, &assoc_maclist->ea[i]); } return bytes_written; } -static void -wl_ext_mod_timer(timer_list_compat_t *timer, uint sec, uint msec) -{ - uint timeout = sec * 1000 + msec; - - IAPSTA_TRACE("wlan", "timeout=%d\n", timeout); - - if (timer_pending(timer)) - del_timer_sync(timer); - - if (timeout) - mod_timer(timer, jiffies + msecs_to_jiffies(timeout)); -} - -static void -wl_ext_send_event_msg(struct net_device *dev, int event, int status) +void +wl_ext_send_event_msg(struct net_device *dev, int event, int status, + int reason) { struct dhd_pub *dhd = dhd_get_pub(dev); struct wl_if_info *cur_if; wl_event_msg_t msg; - cur_if = wl_get_cur_if(dev); - if (!cur_if) - return; - - bzero(&msg, sizeof(wl_event_msg_t)); - - msg.ifidx = hton32(dhd_net2idx(dhd->info, dev)); - msg.event_type = hton32(event); - msg.status = hton32(status); - memcpy(&msg.addr, &cur_if->bssid, ETHER_ADDR_LEN); - + if (dhd && dhd->up) { + cur_if = wl_get_cur_if(dev); + if (!cur_if) + return; + bzero(&msg, sizeof(wl_event_msg_t)); + msg.ifidx = dhd_net2idx(dhd->info, dev); + msg.event_type = hton32(event); + msg.status = hton32(status); + msg.reason = hton32(reason); + memcpy(&msg.addr, &cur_if->bssid, ETHER_ADDR_LEN); #ifdef WL_EVENT - wl_ext_event_send(dhd->event_params, &msg, NULL); -#endif + wl_ext_event_send(dhd->event_params, &msg, NULL); +#endif /* WL_EVENT */ #ifdef WL_CFG80211 - if (dhd->up) { wl_cfg80211_event(dev, &msg, NULL); +#endif /* WL_CFG80211 */ + } +} + +#ifdef BTC_WAR +bool +wl_ext_iapsta_if_2g_enabled(struct net_device *net) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_if_info *tmp_if; + struct wl_chan_info chan_info; + bool enabled = FALSE; + uint16 cur_chan; + int i; + + for (i=0; iif_info[i]; + if (tmp_if && wl_get_isam_status(tmp_if, IF_READY)) { + cur_chan = wl_ext_get_chan(tmp_if->dev, &chan_info); + if (cur_chan && chan_info.band == WLC_BAND_2G) { + enabled = TRUE; + break; + } + } + } + + return enabled; +} + +void +wl_ext_btc_config(struct net_device *dev, bool enable) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + bool enab = FALSE; + + if (dhd->conf->chip == BCM4354_CHIP_ID || dhd->conf->chip == BCM4356_CHIP_ID || + dhd->conf->chip == BCM43752_CHIP_ID) { + IAPSTA_INFO(dev->name, "btc_war=%d, enable=%d\n", btc_war, enable); + if (btc_war >= 0) { + if (enable && btc_war > 0) { + if (wl_ext_iapsta_if_2g_enabled(dev)) + enab = TRUE; + } + if (enab) { + IAPSTA_INFO(dev->name, "enable\n"); + wl_ext_iovar_setint(dev, "txchain", 2); + wl_ext_iovar_setint(dev, "rxchain", 2); + wl_ext_iovar_setint(dev, "btc_mode", 5); + } else { + IAPSTA_INFO(dev->name, "disable\n"); + wl_ext_iovar_setint(dev, "btc_mode", 1); + wl_ext_iovar_setint(dev, "txchain", 3); + wl_ext_iovar_setint(dev, "rxchain", 3); + } + } } -#endif /* defined(WL_CFG80211) */ } +#endif /* BTC_WAR */ static void wl_ext_connect_timeout(unsigned long data) @@ -843,7 +995,7 @@ wl_ext_connect_timeout(unsigned long data) cur_if->assoc_info.reassoc = 0; #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ IAPSTA_ERROR(dev->name, "timer expired\n"); - wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS); + wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WLC_E_STATUS_SUCCESS); } #if defined(WL_CFG80211) || (defined(WLMESH) && defined(WL_ESCAN)) @@ -857,7 +1009,7 @@ wl_ext_if_enabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode) tmp_if = &apsta_params->if_info[i]; if (tmp_if && tmp_if->ifmode == ifmode && wl_get_isam_status(tmp_if, IF_READY)) { - if (wl_ext_get_chan(apsta_params, tmp_if->dev)) { + if (wl_ext_associated(tmp_if->dev)) { target_if = tmp_if; break; } @@ -971,7 +1123,7 @@ wl_ext_mesh_peer_status(struct net_device *dev, char *data, char *command, } #ifdef WL_ESCAN -#define WL_MESH_DELAY_SCAN_TMO 3 +#define WL_MESH_DELAY_SCAN_TMO 3000 static void wl_mesh_timer(unsigned long data) { @@ -989,7 +1141,7 @@ wl_mesh_timer(unsigned long data) bzero(&msg, sizeof(wl_event_msg_t)); IAPSTA_TRACE(dev->name, "timer expired\n"); - msg.ifidx = hton32(dhd_net2idx(dhd->info, dev)); + msg.ifidx = dhd_net2idx(dhd->info, dev); msg.event_type = hton32(WLC_E_RESERVED); msg.reason = hton32(ISAM_RC_MESH_ACS); wl_ext_event_send(dhd->event_params, &msg, NULL); @@ -1063,9 +1215,10 @@ exit: } static int -wl_mesh_clear_mesh_info(struct wl_apsta_params *apsta_params, - struct wl_if_info *mesh_if, bool scan) +wl_mesh_clear_mesh_info(struct wl_if_info *mesh_if, bool scan) { + struct dhd_pub *dhd = dhd_get_pub(mesh_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct wl_mesh_params *mesh_info = &apsta_params->mesh_info; uchar mesh_oui[]={0x00, 0x22, 0xf4}; int ret; @@ -1075,8 +1228,9 @@ wl_mesh_clear_mesh_info(struct wl_apsta_params *apsta_params, ret = wl_mesh_clear_vndr_ie(mesh_if->dev, mesh_oui); memset(mesh_info, 0, sizeof(struct wl_mesh_params)); if (scan) { - mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev); - wl_ext_mod_timer(&mesh_if->delay_scan, 0, 100); + mesh_info->scan_channel = wl_ext_get_chan(mesh_if->dev, + &mesh_if->chan_info); + wl_timer_mod(dhd, &mesh_if->delay_scan, 100); } return ret; @@ -1155,7 +1309,7 @@ wl_mesh_update_master_info(struct wl_apsta_params *apsta_params, if (sta_if) { wldev_ioctl(mesh_if->dev, WLC_GET_BSSID, &mesh_info->master_bssid, ETHER_ADDR_LEN, 0); - mesh_info->master_channel = wl_ext_get_chan(apsta_params, mesh_if->dev); + mesh_info->master_channel = wl_ext_get_chan(mesh_if->dev, &mesh_if->chan_info); mesh_info->hop_cnt = 0; memset(mesh_info->peer_bssid, 0, MAX_HOP_LIST*ETHER_ADDR_LEN); if (!wl_mesh_update_vndr_ie(apsta_params, mesh_if)) @@ -1231,7 +1385,7 @@ wl_mesh_update_mesh_info(struct wl_apsta_params *apsta_params, wl_ext_get_sec(mesh_if->dev, mesh_if->ifmode, sec, sizeof(sec), FALSE); if (strnicmp(sec, "sae/sae", strlen("sae/sae")) == 0) sae = TRUE; - cur_chan = wl_ext_get_chan(apsta_params, mesh_if->dev); + cur_chan = wl_ext_get_chan(mesh_if->dev, &mesh_if->chan_info); bss_found = wl_escan_mesh_peer(mesh_if->dev, mesh_if->escan, &cur_ssid, cur_chan, sae, &peer_mesh_info); @@ -1252,63 +1406,105 @@ exit: } static void -wl_mesh_event_handler(struct wl_apsta_params *apsta_params, - struct wl_if_info *mesh_if, const wl_event_msg_t *e, void *data) +wl_mesh_event_handler(struct wl_if_info *cur_if, + const wl_event_msg_t *e, void *data) { + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct wl_mesh_params *mesh_info = &apsta_params->mesh_info; uint32 event_type = ntoh32(e->event_type); uint32 status = ntoh32(e->status); uint32 reason = ntoh32(e->reason); - int ret; + uint16 flags = ntoh16(e->flags); + struct wl_if_info *mesh_if = NULL, *tmp_if = NULL; + int ret, i; - if (wl_get_isam_status(mesh_if, AP_CREATED) && - ((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) || - (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && - reason == WLC_E_REASON_INITIAL_ASSOC))) { - if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { - mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev); - wl_ext_mod_timer(&mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO, 0); - } - } - else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || - (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && - reason == WLC_E_REASON_DEAUTH)) { - wl_mesh_clear_mesh_info(apsta_params, mesh_if, FALSE); - } - else if (wl_get_isam_status(mesh_if, AP_CREATED) && - (event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) && - reason == DOT11_SC_SUCCESS) { - mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev); - wl_ext_mod_timer(&mesh_if->delay_scan, 0, 100); - } - else if (event_type == WLC_E_DISASSOC_IND || event_type == WLC_E_DEAUTH_IND || - (event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) { - if (!memcmp(&mesh_info->peer_bssid, &e->addr, ETHER_ADDR_LEN)) - wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE); - } - else if (wl_get_isam_status(mesh_if, AP_CREATED) && - event_type == WLC_E_RESERVED && reason == ISAM_RC_MESH_ACS) { - if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { - wl_scan_info_t scan_info; - memset(&scan_info, 0, sizeof(wl_scan_info_t)); - wl_ext_ioctl(mesh_if->dev, WLC_GET_SSID, &scan_info.ssid, sizeof(wlc_ssid_t), 0); - scan_info.channels.count = 1; - scan_info.channels.channel[0] = mesh_info->scan_channel; - ret = wl_escan_set_scan(mesh_if->dev, &scan_info); - if (ret) - wl_ext_mod_timer(&mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO, 0); + if (cur_if->ifmode == IMESH_MODE) + mesh_if = cur_if; + else { + for (i=0; iif_info[i]; + if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE) { + mesh_if = tmp_if; + break; + } + } + } + + if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) { + if (event_type == WLC_E_LINK) { + if (!(flags & WLC_EVENT_MSG_LINK)) { + if (mesh_if && apsta_params->macs) + wl_mesh_clear_mesh_info(mesh_if, TRUE); + } else { + if (mesh_if && apsta_params->macs) + wl_mesh_update_master_info(apsta_params, mesh_if); + } + } + else if (event_type == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) { + if (mesh_if && apsta_params->macs) + wl_mesh_clear_mesh_info(mesh_if, TRUE); + } + else if (event_type == WLC_E_DEAUTH || event_type == WLC_E_DEAUTH_IND || + event_type == WLC_E_DISASSOC || event_type == WLC_E_DISASSOC_IND) { + if (mesh_if && apsta_params->macs) + wl_mesh_clear_mesh_info(mesh_if, TRUE); } } - else if (wl_get_isam_status(mesh_if, AP_CREATED) && - ((event_type == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) || - (event_type == WLC_E_ESCAN_RESULT && - (status == WLC_E_STATUS_ABORT || status == WLC_E_STATUS_NEWSCAN || - status == WLC_E_STATUS_11HQUIET || status == WLC_E_STATUS_CS_ABORT || - status == WLC_E_STATUS_NEWASSOC || status == WLC_E_STATUS_TIMEOUT)))) { - if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { - if (!wl_mesh_update_mesh_info(apsta_params, mesh_if)) { - mesh_info->scan_channel = 0; - wl_ext_mod_timer(&mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO, 0); + else if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) { + if (wl_get_isam_status(mesh_if, AP_CREATED) && + ((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) || + (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && + reason == WLC_E_REASON_INITIAL_ASSOC))) { + if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { + mesh_info->scan_channel = wl_ext_get_chan(&mesh_if->dev, + mesh_if->chan_info); + wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO); + } + } + else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || + (event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && + reason == WLC_E_REASON_DEAUTH)) { + wl_mesh_clear_mesh_info(mesh_if, FALSE); + } + else if (wl_get_isam_status(mesh_if, AP_CREATED) && + (event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) && + reason == DOT11_SC_SUCCESS) { + mesh_info->scan_channel = wl_ext_get_chan(mesh_if->dev, + &mesh_if->chan_info); + wl_timer_mod(dhd, &mesh_if->delay_scan, 100); + } + else if (event_type == WLC_E_DISASSOC_IND || event_type == WLC_E_DEAUTH_IND || + (event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) { + if (!memcmp(&mesh_info->peer_bssid, &e->addr, ETHER_ADDR_LEN)) + wl_mesh_clear_mesh_info(mesh_if, TRUE); + } + else if (wl_get_isam_status(mesh_if, AP_CREATED) && + event_type == WLC_E_RESERVED && reason == ISAM_RC_MESH_ACS) { + if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { + wl_scan_info_t scan_info; + memset(&scan_info, 0, sizeof(wl_scan_info_t)); + wl_ext_ioctl(mesh_if->dev, WLC_GET_SSID, &scan_info.ssid, sizeof(wlc_ssid_t), 0); + if (mesh_info->scan_channel) { + scan_info.channels.count = 1; + scan_info.channels.channel[0] = mesh_info->scan_channel; + } + ret = wl_escan_set_scan(mesh_if->dev, &scan_info); + if (ret) + wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO); + } + } + else if (wl_get_isam_status(mesh_if, AP_CREATED) && + ((event_type == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) || + (event_type == WLC_E_ESCAN_RESULT && + (status == WLC_E_STATUS_ABORT || status == WLC_E_STATUS_NEWSCAN || + status == WLC_E_STATUS_11HQUIET || status == WLC_E_STATUS_CS_ABORT || + status == WLC_E_STATUS_NEWASSOC || status == WLC_E_STATUS_TIMEOUT)))) { + if (!wl_mesh_update_master_info(apsta_params, mesh_if)) { + if (!wl_mesh_update_mesh_info(apsta_params, mesh_if)) { + mesh_info->scan_channel = 0; + wl_timer_mod(dhd, &mesh_if->delay_scan, WL_MESH_DELAY_SCAN_TMO); + } } } } @@ -1318,9 +1514,7 @@ static void wl_mesh_escan_detach(dhd_pub_t *dhd, struct wl_if_info *mesh_if) { IAPSTA_TRACE(mesh_if->dev->name, "Enter\n"); - - del_timer_sync(&mesh_if->delay_scan); - + wl_timer_deregister(mesh_if->dev, &mesh_if->delay_scan); if (mesh_if->escan) { mesh_if->escan = NULL; } @@ -1332,7 +1526,7 @@ wl_mesh_escan_attach(dhd_pub_t *dhd, struct wl_if_info *mesh_if) IAPSTA_TRACE(mesh_if->dev->name, "Enter\n"); mesh_if->escan = dhd->escan; - init_timer_compat(&mesh_if->delay_scan, wl_mesh_timer, mesh_if->dev); + wl_timer_register(mesh_if->dev, &mesh_if->delay_scan, wl_mesh_timer); return 0; } @@ -1397,7 +1591,6 @@ wl_ext_isam_peer_path(struct net_device *dev, char *command, int total_len) struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct wl_mesh_params *mesh_info = &apsta_params->mesh_info; struct wl_if_info *tmp_if; - uint16 chan = 0; char *dump_buf = NULL; int dump_len = WLC_IOCTL_MEDLEN; int dump_written = 0; @@ -1418,8 +1611,7 @@ wl_ext_isam_peer_path(struct net_device *dev, char *command, int total_len) for (i=0; iif_info[i]; if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE && apsta_params->macs) { - chan = wl_ext_get_chan(apsta_params, tmp_if->dev); - if (chan) { + if (wl_ext_associated(tmp_if->dev)) { dump_written += snprintf(dump_buf+dump_written, dump_len, DHD_LOG_PREFIXS "[%s-%c] mbssid=%pM, mchan=%d, hop=%d, pbssid=%pM", tmp_if->ifname, tmp_if->prefix, &mesh_info->master_bssid, @@ -1488,6 +1680,7 @@ static int wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if, bool force_enable, int wait_up) { + struct wl_chan_info *chan_info = &cur_if->chan_info; s8 iovar_buf[WLC_IOCTL_SMLEN]; struct { s32 cfg; @@ -1497,26 +1690,29 @@ wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if, chanspec_t fw_chspec; u32 timeout; wlc_ssid_t ssid = { 0, {0} }; - uint16 chan = 0; + uint32 chanspec = 0; - if (cur_if->ifmode != IAP_MODE) { + if (cur_if->ifmode != IAP_MODE && cur_if->ifmode != IGO_MODE) { IAPSTA_ERROR(cur_if->ifname, "Wrong ifmode\n"); return 0; } - if (wl_ext_dfs_chan(cur_if->channel) && !apsta_params->radar && !force_enable) { + if (wl_ext_dfs_chan(chan_info) && !apsta_params->radar && !force_enable) { WL_MSG(cur_if->ifname, "[%c] skip DFS channel %d\n", - cur_if->prefix, cur_if->channel); + cur_if->prefix, chan_info->chan); return 0; - } else if (!cur_if->channel) { + } else if (wl_ext_passive_chan(cur_if->dev, chan_info)) { + WL_MSG(cur_if->ifname, "[%c] skip PASSIVE channel %d\n", + cur_if->prefix, chan_info->chan); + return 0; + } else if (!chan_info->chan) { WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix); return 0; } WL_MSG(cur_if->ifname, "[%c] Turning on...\n", cur_if->prefix); - wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver, cur_if->channel, - &fw_chspec); + wl_ext_set_chanspec(cur_if->dev, chan_info, &fw_chspec); wl_clr_isam_status(cur_if, AP_CREATED); wl_set_isam_status(cur_if, AP_CREATING); @@ -1543,9 +1739,10 @@ wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if, } wl_ext_ioctl(cur_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0); - chan = wl_ext_get_chan(apsta_params, cur_if->dev); - WL_MSG(cur_if->ifname, "[%c] enabled with SSID: \"%s\" on channel %d\n", - cur_if->prefix, ssid.SSID, chan); + chanspec = wl_ext_get_chanspec(cur_if->dev, chan_info); + WL_MSG(cur_if->ifname, "[%c] enabled with SSID: \"%s\" on channel %s-%d(0x%x)\n", + cur_if->prefix, ssid.SSID, CHSPEC2BANDSTR(chanspec), + chan_info->chan, chanspec); wl_clr_isam_status(cur_if, AP_CREATING); @@ -1555,22 +1752,34 @@ wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if, } static bool -wl_ext_diff_band(uint16 chan1, uint16 chan2) +wl_ext_same_chan(struct wl_chan_info *chan_info_1, + struct wl_chan_info *chan_info_2) +{ + if (chan_info_1->band == chan_info_2->band && + chan_info_1->chan == chan_info_2->chan) { + return TRUE; + } + return FALSE; +} + +static bool +wl_ext_rsdb_band(uint band_1, uint band_2) { - if ((chan1 <= CH_MAX_2G_CHANNEL && chan2 > CH_MAX_2G_CHANNEL) || - (chan1 > CH_MAX_2G_CHANNEL && chan2 <= CH_MAX_2G_CHANNEL)) { + if ((band_1 == WLC_BAND_2G && band_2 != WLC_BAND_2G) || + (band_2 == WLC_BAND_2G && band_1 != WLC_BAND_2G)) { return TRUE; } return FALSE; } static uint16 -wl_ext_same_band(struct wl_apsta_params *apsta_params, +wl_ext_get_same_band_chan(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if, bool nodfs) { struct wl_if_info *tmp_if; - uint16 tmp_chan, target_chan = 0; + struct wl_chan_info chan_info; wl_prio_t max_prio; + uint16 chan = 0; int i; // find the max prio @@ -1579,33 +1788,41 @@ wl_ext_same_band(struct wl_apsta_params *apsta_params, tmp_if = &apsta_params->if_info[i]; if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) && tmp_if->prio > max_prio) { - tmp_chan = wl_ext_get_chan(apsta_params, tmp_if->dev); - if (wl_ext_dfs_chan(tmp_chan) && nodfs) + memset(&chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(tmp_if->dev, &chan_info); + if (wl_ext_dfs_chan(&chan_info) && nodfs) continue; - if (tmp_chan && !wl_ext_diff_band(cur_if->channel, tmp_chan)) { - target_chan = tmp_chan; + if (chan_info.chan && (cur_if->chan_info.band == chan_info.band)) { + chan = chan_info.chan; max_prio = tmp_if->prio; } } } - return target_chan; + return chan; } static uint16 wl_ext_get_vsdb_chan(struct wl_apsta_params *apsta_params, - struct wl_if_info *cur_if, struct wl_if_info *target_if) + const struct wl_if_info *cur_if, const struct wl_if_info *target_if) { - uint16 target_chan = 0, cur_chan = cur_if->channel; + struct wl_chan_info chan_info; + uint cur_band = cur_if->chan_info.band; + uint16 cur_chan = cur_if->chan_info.chan; + uint target_band; + uint16 target_chan; if (cur_if->vsdb && target_if->vsdb) return 0; - target_chan = wl_ext_get_chan(apsta_params, target_if->dev); + memset(&chan_info, 0, sizeof(struct wl_chan_info)); + target_chan = wl_ext_get_chan(target_if->dev, &chan_info); if (target_chan) { - IAPSTA_INFO(cur_if->ifname, "cur_chan=%d, target_chan=%d\n", - cur_chan, target_chan); - if (wl_ext_diff_band(cur_chan, target_chan)) { + target_band = chan_info.band; + IAPSTA_INFO(cur_if->ifname, "cur_chan=%s-%d, target_chan=%s-%d\n", + WLCBAND2STR(cur_band), cur_chan, + WLCBAND2STR(target_band), target_chan); + if (wl_ext_rsdb_band(cur_band, target_band)) { if (!apsta_params->rsdb) return target_chan; } else { @@ -1622,23 +1839,25 @@ wl_ext_rsdb_core_conflict(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) { struct wl_if_info *tmp_if; - uint16 cur_chan, tmp_chan; + struct wl_chan_info cur_chan_info, tmp_chan_info; int i; if (apsta_params->rsdb) { - cur_chan = wl_ext_get_chan(apsta_params, cur_if->dev); + memset(&cur_chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(cur_if->dev, &cur_chan_info); for (i=0; iif_info[i]; if (tmp_if != cur_if && wl_get_isam_status(tmp_if, IF_READY) && tmp_if->prio > cur_if->prio) { - tmp_chan = wl_ext_get_chan(apsta_params, tmp_if->dev); - if (!tmp_chan) + memset(&tmp_chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(tmp_if->dev, &tmp_chan_info); + if (!tmp_chan_info.chan) continue; - if (wl_ext_diff_band(cur_chan, tmp_chan) && - wl_ext_diff_band(cur_chan, cur_if->channel)) + if (wl_ext_rsdb_band(cur_chan_info.band, tmp_chan_info.band) && + wl_ext_rsdb_band(cur_chan_info.band, cur_if->chan_info.chan)) return TRUE; - else if (!wl_ext_diff_band(cur_chan, tmp_chan) && - wl_ext_diff_band(cur_chan, cur_if->channel)) + else if (!wl_ext_rsdb_band(cur_chan_info.band, tmp_chan_info.band) && + wl_ext_rsdb_band(cur_chan_info.band, cur_if->chan_info.chan)) return TRUE; } } @@ -1653,26 +1872,25 @@ wl_ext_trigger_csa(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_ bool core_conflict = FALSE; if (wl_ext_master_if(cur_if) && (apsta_params->csa & CSA_DRV_BIT)) { - if (!cur_if->channel) { + if (!cur_if->chan_info.chan) { WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix); - } else if (wl_ext_dfs_chan(cur_if->channel) && !apsta_params->radar) { + } else if (wl_ext_dfs_chan(&cur_if->chan_info) && !apsta_params->radar) { WL_MSG(cur_if->ifname, "[%c] skip DFS channel %d\n", - cur_if->prefix, cur_if->channel); + cur_if->prefix, cur_if->chan_info.chan); wl_ext_if_down(apsta_params, cur_if); } else { wl_chan_switch_t csa_arg; memset(&csa_arg, 0, sizeof(csa_arg)); csa_arg.mode = 1; csa_arg.count = 3; - csa_arg.chspec = wl_ext_chan_to_chanspec(apsta_params, cur_if->dev, - cur_if->channel); + csa_arg.chspec = wl_ext_chan_to_chanspec(cur_if->dev, &cur_if->chan_info); core_conflict = wl_ext_rsdb_core_conflict(apsta_params, cur_if); if (core_conflict) { WL_MSG(cur_if->ifname, "[%c] Skip CSA due to rsdb core conflict\n", cur_if->prefix); } else if (csa_arg.chspec) { WL_MSG(cur_if->ifname, "[%c] Trigger CSA to channel %d(0x%x)\n", - cur_if->prefix, cur_if->channel, csa_arg.chspec); + cur_if->prefix, cur_if->chan_info.chan, csa_arg.chspec); wl_set_isam_status(cur_if, AP_CREATING); wl_ext_iovar_setbuf(cur_if->dev, "csa", &csa_arg, sizeof(csa_arg), iovar_buf, sizeof(iovar_buf), NULL); @@ -1692,128 +1910,125 @@ static void wl_ext_move_cur_dfs_channel(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) { - uint16 other_chan = 0, cur_chan = cur_if->channel; + struct wl_chan_info *cur_chan_info = &cur_if->chan_info; + uint cur_band = cur_chan_info->band; + uint16 cur_chan = cur_chan_info->chan, auto_chan = 0; uint16 chan_2g = 0, chan_5g = 0; - uint32 auto_band = WLC_BAND_2G; - - if (wl_ext_master_if(cur_if) && wl_ext_dfs_chan(cur_if->channel) && - !apsta_params->radar) { + if (!apsta_params->radar && wl_ext_master_if(cur_if) && + wl_ext_dfs_chan(cur_chan_info)) { wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE); if (!chan_2g && !chan_5g) { - cur_if->channel = 0; + cur_chan_info->chan = 0; WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix); return; } - if (apsta_params->vsdb) { - if (chan_5g) { - cur_if->channel = chan_5g; - auto_band = WLC_BAND_5G; - other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE); - } else { - cur_if->channel = chan_2g; - auto_band = WLC_BAND_2G; - other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE); - } - if (!other_chan) { - other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, - auto_band); + if (chan_5g) + wl_ext_set_chan_info(cur_if, WLC_BAND_5G, chan_5g); + else + wl_ext_set_chan_info(cur_if, WLC_BAND_2G, chan_2g); + auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, TRUE); + if (!auto_chan) { + auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, + cur_chan_info->band); } - if (other_chan) - cur_if->channel = other_chan; - } else if (apsta_params->rsdb) { + if (auto_chan) + cur_chan_info->chan = auto_chan; + } + else if (apsta_params->rsdb) { if (chan_5g) { - cur_if->channel = chan_5g; - auto_band = WLC_BAND_5G; - other_chan = wl_ext_same_band(apsta_params, cur_if, FALSE); - if (wl_ext_dfs_chan(other_chan) && chan_2g) { - cur_if->channel = chan_2g; - auto_band = WLC_BAND_2G; - other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE); + wl_ext_set_chan_info(cur_if, WLC_BAND_5G, chan_5g); + auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, FALSE); + if (auto_chan) { + if (wl_ext_dfs_chan(cur_chan_info) && chan_2g) { + wl_ext_set_chan_info(cur_if, WLC_BAND_2G, chan_2g); + auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, TRUE); + } } } else { - cur_if->channel = chan_2g; - auto_band = WLC_BAND_2G; - other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE); + wl_ext_set_chan_info(cur_if, WLC_BAND_2G, chan_2g); + auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, TRUE); } - if (!other_chan) { - other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, - auto_band); + if (!auto_chan) { + auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, + cur_chan_info->band); } - if (other_chan) - cur_if->channel = other_chan; - } else { - cur_if->channel = chan_5g; - other_chan = wl_ext_same_band(apsta_params, cur_if, FALSE); - if (other_chan) { - cur_if->channel = other_chan; + if (auto_chan) { + cur_chan_info->chan = auto_chan; + } + } + else { + wl_ext_set_chan_info(cur_if, WLC_BAND_5G, chan_5g); + auto_chan = wl_ext_get_same_band_chan(apsta_params, cur_if, FALSE); + if (auto_chan) { + cur_chan_info->chan = auto_chan; } else { - auto_band = WLC_BAND_5G; - other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, - auto_band); - if (other_chan) - cur_if->channel = other_chan; + auto_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, + cur_chan_info->band); + if (auto_chan) { + cur_chan_info->chan = auto_chan; + } } } - WL_MSG(cur_if->ifname, "[%c] move channel %d => %d\n", - cur_if->prefix, cur_chan, cur_if->channel); + WL_MSG(cur_if->ifname, "[%c] move channel %s-%d => %s-%d\n", + cur_if->prefix, WLCBAND2STR(cur_band), cur_chan, + WLCBAND2STR(cur_chan_info->band), cur_chan_info->chan); } } static void wl_ext_move_other_dfs_channel(struct wl_apsta_params *apsta_params, - struct wl_if_info *cur_if) + struct wl_if_info *tgt_if) { - uint16 other_chan = 0, cur_chan = cur_if->channel; + struct wl_chan_info *tgt_chan_info = &tgt_if->chan_info; + uint cur_band = tgt_chan_info->band; + uint16 cur_chan = tgt_chan_info->chan, auto_chan = 0; uint16 chan_2g = 0, chan_5g = 0; - uint32 auto_band = WLC_BAND_2G; - if (wl_ext_master_if(cur_if) && wl_ext_dfs_chan(cur_if->channel) && - !apsta_params->radar) { - - wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE); + if (!apsta_params->radar && wl_ext_master_if(tgt_if) && + wl_ext_dfs_chan(tgt_chan_info)) { + wl_ext_get_default_chan(tgt_if->dev, &chan_2g, &chan_5g, TRUE); if (!chan_2g && !chan_5g) { - cur_if->channel = 0; - WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix); + tgt_chan_info->chan = 0; + WL_MSG(tgt_if->ifname, "[%c] no valid channel\n", tgt_if->prefix); return; } if (apsta_params->vsdb) { - if (chan_5g) { - cur_if->channel = chan_5g; - auto_band = WLC_BAND_5G; - other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE); - } else { - cur_if->channel = chan_2g; - auto_band = WLC_BAND_2G; - other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE); + if (chan_5g) + wl_ext_set_chan_info(tgt_if, WLC_BAND_5G, chan_5g); + else + wl_ext_set_chan_info(tgt_if, WLC_BAND_2G, chan_2g); + auto_chan = wl_ext_get_same_band_chan(apsta_params, tgt_if, TRUE); + if (!auto_chan) { + auto_chan = wl_ext_autochannel(tgt_if->dev, ACS_FW_BIT|ACS_DRV_BIT, + tgt_chan_info->band); } - if (!other_chan) { - other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, - auto_band); + if (auto_chan) { + tgt_chan_info->chan = auto_chan; } - if (other_chan) - cur_if->channel = other_chan; - } else if (apsta_params->rsdb) { + } + else if (apsta_params->rsdb) { if (chan_2g) { - cur_if->channel = chan_2g; - auto_band = WLC_BAND_2G; - other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE); - if (!other_chan) { - other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT, - auto_band); + wl_ext_set_chan_info(tgt_if, WLC_BAND_2G, chan_2g); + auto_chan = wl_ext_get_same_band_chan(apsta_params, tgt_if, TRUE); + if (!auto_chan) { + auto_chan = wl_ext_autochannel(tgt_if->dev, ACS_FW_BIT|ACS_DRV_BIT, + tgt_chan_info->band); } } else { - cur_if->channel = 0; + tgt_chan_info->chan = 0; + } + if (auto_chan) { + tgt_chan_info->chan = auto_chan; } - if (other_chan) - cur_if->channel = other_chan; } else { - cur_if->channel = 0; + tgt_chan_info->chan = 0; } - WL_MSG(cur_if->ifname, "[%c] move channel %d => %d\n", - cur_if->prefix, cur_chan, cur_if->channel); + WL_MSG(tgt_if->ifname, "[%c] move channel %s-%d => %s-%d\n", + tgt_if->prefix, WLCBAND2STR(cur_band), cur_chan, + WLCBAND2STR(tgt_chan_info->band), tgt_chan_info->chan); } } @@ -1822,12 +2037,12 @@ wl_ext_move_cur_channel(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) { struct wl_if_info *tmp_if, *target_if = NULL; - uint16 tmp_chan, target_chan = 0; + struct wl_chan_info cur_chan_info, tgt_chan_info; + uint16 tmp_chan; wl_prio_t max_prio; int i; if (apsta_params->vsdb) { - target_chan = cur_if->channel; goto exit; } @@ -1840,31 +2055,35 @@ wl_ext_move_cur_channel(struct wl_apsta_params *apsta_params, tmp_chan = wl_ext_get_vsdb_chan(apsta_params, cur_if, tmp_if); if (tmp_chan) { target_if = tmp_if; - target_chan = tmp_chan; max_prio = tmp_if->prio; } } } - if (target_chan) { - tmp_chan = wl_ext_get_chan(apsta_params, cur_if->dev); - if (apsta_params->rsdb && tmp_chan && - wl_ext_diff_band(tmp_chan, target_chan)) { - WL_MSG(cur_if->ifname, "[%c] keep on current channel %d\n", - cur_if->prefix, tmp_chan); - cur_if->channel = 0; + if (target_if) { + memset(&cur_chan_info, 0, sizeof(struct wl_chan_info)); + memset(&tgt_chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(cur_if->dev, &cur_chan_info); + wl_ext_get_chan(target_if->dev, &tgt_chan_info); + if (apsta_params->rsdb && cur_chan_info.chan && + wl_ext_rsdb_band(cur_chan_info.band, tgt_chan_info.band)) { + WL_MSG(cur_if->ifname, "[%c] keep on current channel %s-%d\n", + cur_if->prefix, WLCBAND2STR(cur_chan_info.band), cur_chan_info.chan); + cur_if->chan_info.chan = 0; } else { - WL_MSG(cur_if->ifname, "[%c] channel=%d => %s[%c] channel=%d\n", - cur_if->prefix, cur_if->channel, - target_if->ifname, target_if->prefix, target_chan); - cur_if->channel = target_chan; + WL_MSG(cur_if->ifname, "[%c] channel=%s-%d => %s[%c] channel=%s-%d\n", + cur_if->prefix, + WLCBAND2STR(cur_if->chan_info.band), cur_if->chan_info.chan, + target_if->ifname, target_if->prefix, + WLCBAND2STR(tgt_chan_info.band), tgt_chan_info.chan); + wl_ext_set_chan_info(cur_if, tgt_chan_info.band, tgt_chan_info.chan); } } exit: wl_ext_move_cur_dfs_channel(apsta_params, cur_if); - return cur_if->channel; + return cur_if->chan_info.chan; } static struct wl_if_info * @@ -1876,7 +2095,7 @@ wl_ext_move_other_channel(struct wl_apsta_params *apsta_params, wl_prio_t max_prio = 0, cur_prio; int i; - if (apsta_params->vsdb || !cur_if->channel) { + if (apsta_params->vsdb || !cur_if->chan_info.chan) { return NULL; } @@ -1896,9 +2115,10 @@ wl_ext_move_other_channel(struct wl_apsta_params *apsta_params, } if (target_if) { - WL_MSG(target_if->ifname, "channel=%d => %s channel=%d\n", - target_chan, cur_if->ifname, cur_if->channel); - target_if->channel = cur_if->channel; + WL_MSG(target_if->ifname, "channel=%s-%d => %s channel=%s-%d\n", + WLCBAND2STR(target_if->chan_info.band), target_chan, + cur_if->ifname, WLCBAND2STR(cur_if->chan_info.band), cur_if->chan_info.chan); + wl_ext_set_chan_info(target_if, cur_if->chan_info.band, cur_if->chan_info.chan); wl_ext_move_other_dfs_channel(apsta_params, target_if); if (apsta_params->csa == 0) { wl_ext_if_down(apsta_params, target_if); @@ -1973,7 +2193,7 @@ wl_ext_iapsta_other_if_enabled(struct net_device *net) for (i=0; iif_info[i]; if (tmp_if && wl_get_isam_status(tmp_if, IF_READY)) { - if (wl_ext_get_chan(apsta_params, tmp_if->dev)) { + if (wl_ext_associated(tmp_if->dev)) { enabled = TRUE; break; } @@ -2006,14 +2226,58 @@ wl_ext_sta_connecting(struct net_device *dev) return connecting; } -#ifdef PROPTX_MAXCOUNT -int -wl_ext_get_wlfc_maxcount(struct dhd_pub *dhd, int ifidx) +bool +wl_ext_sta_handshaking(struct net_device *dev) { - struct wl_apsta_params *apsta_params = dhd->iapsta_params; - struct wl_if_info *tmp_if, *cur_if = NULL; - int i, maxcount = WL_TXSTATUS_FREERUNCTR_MASK; - + struct wl_if_info *cur_if = NULL; + bool connecting = FALSE; + int state; + + cur_if = wl_get_cur_if(dev); + if (!cur_if) + return FALSE; + + if (cur_if->ifmode != ISTA_MODE && cur_if->ifmode != IGC_MODE) + return FALSE; + + state = cur_if->conn_state; + if (state >= CONN_STATE_4WAY_M1 && state < CONN_STATE_CONNECTED) { + connecting = TRUE; + IAPSTA_TRACE(dev->name, "conn_state %d\n", state); + } + + return connecting; +} + +#ifdef DHD_LOSSLESS_ROAMING +int +wl_ext_any_sta_handshaking(struct dhd_pub *dhd) +{ + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_if_info *cur_if; + int state = 0, i; + + for (i=0; iif_info[i]; + if (cur_if->dev && cur_if->ifmode == ISTA_MODE) { + state = cur_if->conn_state; + if (state >= CONN_STATE_4WAY_M1 && state < CONN_STATE_CONNECTED) { + return state; + } + } + } + return 0; +} +#endif /* DHD_LOSSLESS_ROAMING */ + +#ifdef PROPTX_MAXCOUNT +int +wl_ext_get_wlfc_maxcount(struct dhd_pub *dhd, int ifidx) +{ + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_if_info *tmp_if, *cur_if = NULL; + int i, maxcount = WL_TXSTATUS_FREERUNCTR_MASK; + if (!apsta_params->rsdb) return maxcount; @@ -2037,8 +2301,8 @@ wl_ext_update_wlfc_maxcount(struct dhd_pub *dhd) { struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct wl_if_info *tmp_if; + struct wl_chan_info chan_info; bool band_5g = FALSE; - uint16 chan = 0; int i, ret; if (!apsta_params->rsdb) @@ -2047,8 +2311,9 @@ wl_ext_update_wlfc_maxcount(struct dhd_pub *dhd) for (i=0; iif_info[i]; if (tmp_if->dev) { - chan = wl_ext_get_chan(apsta_params, tmp_if->dev); - if (chan > CH_MAX_2G_CHANNEL) { + memset(&chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(tmp_if->dev, &chan_info); + if (chan_info.band == WLC_BAND_5G || chan_info.band == WLC_BAND_6G) { tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_5g; ret = dhd_wlfc_update_maxcount(dhd, tmp_if->ifidx, tmp_if->transit_maxcount); @@ -2063,9 +2328,9 @@ wl_ext_update_wlfc_maxcount(struct dhd_pub *dhd) for (i=0; iif_info[i]; if (tmp_if->dev) { - chan = wl_ext_get_chan(apsta_params, tmp_if->dev); - if ((chan == 0) || (chan <= CH_MAX_2G_CHANNEL && chan >= CH_MIN_2G_CHANNEL)) { - if (chan == 0) { + wl_ext_get_chan(tmp_if->dev, &chan_info); + if ((chan_info.chan == 0) || (chan_info.band == WLC_BAND_2G)) { + if (chan_info.chan == 0) { tmp_if->transit_maxcount = WL_TXSTATUS_FREERUNCTR_MASK; } else if (band_5g) { tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_2g; @@ -2088,15 +2353,16 @@ static struct wl_if_info * wl_ext_get_dfs_master_if(struct wl_apsta_params *apsta_params) { struct wl_if_info *cur_if = NULL; - uint16 chan = 0; + struct wl_chan_info chan_info; int i; for (i=0; iif_info[i]; if (!cur_if->dev || !wl_ext_master_if(cur_if)) continue; - chan = wl_ext_get_chan(apsta_params, cur_if->dev); - if (wl_ext_dfs_chan(chan)) { + memset(&chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(cur_if->dev, &chan_info); + if (chan_info.chan && wl_ext_dfs_chan(&chan_info)) { return cur_if; } } @@ -2108,7 +2374,7 @@ wl_ext_save_master_channel(struct wl_apsta_params *apsta_params, uint16 post_channel) { struct wl_if_info *cur_if = NULL; - uint16 chan = 0; + struct wl_chan_info chan_info; int i; if (apsta_params->vsdb) @@ -2118,14 +2384,68 @@ wl_ext_save_master_channel(struct wl_apsta_params *apsta_params, cur_if = &apsta_params->if_info[i]; if (!cur_if->dev || !wl_ext_master_if(cur_if)) continue; - chan = wl_ext_get_chan(apsta_params, cur_if->dev); - if (chan) { - cur_if->prev_channel = chan; + memset(&chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(cur_if->dev, &chan_info); + if (chan_info.chan) { + cur_if->prev_channel = chan_info.chan; cur_if->post_channel = post_channel; } } } +void +wl_ext_iapsta_enable_master_if(struct net_device *dev, bool post) +{ + dhd_pub_t *dhd = dhd_get_pub(dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_if_info *cur_if = NULL; + int i; + + for (i=0; iif_info[i]; + if (cur_if && cur_if->post_channel) { + if (post) + cur_if->chan_info.chan = cur_if->post_channel; + else + cur_if->chan_info.chan = cur_if->prev_channel; + if (wl_ext_associated(cur_if->dev)) + wl_ext_if_down(apsta_params, cur_if); + wl_ext_if_up(apsta_params, cur_if, TRUE, 0); + cur_if->prev_channel = 0; + cur_if->post_channel = 0; + } + } +} + +void +wl_ext_iapsta_restart_master(struct net_device *dev) +{ + dhd_pub_t *dhd = dhd_get_pub(dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_if_info *ap_if = NULL; + + if (apsta_params->radar) + return; + + ap_if = wl_ext_get_dfs_master_if(apsta_params); + if (ap_if) { + uint16 chan_2g, chan_5g; + wl_ext_if_down(apsta_params, ap_if); + wl_ext_iapsta_restart_master(dev); + wl_ext_get_default_chan(ap_if->dev, &chan_2g, &chan_5g, TRUE); + if (chan_5g) + wl_ext_set_chan_info(ap_if, WLC_BAND_5G, chan_5g); + else if (chan_2g) + wl_ext_set_chan_info(ap_if, WLC_BAND_2G, chan_2g); + else + ap_if->chan_info.chan = 0; + if (ap_if->chan_info.chan) { + wl_ext_move_cur_channel(apsta_params, ap_if); + wl_ext_if_up(apsta_params, ap_if, FALSE, 0); + } + } +} + static void wl_ext_if_reenabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode, u32 channel) { @@ -2136,7 +2456,7 @@ wl_ext_if_reenabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode, u32 c tmp_if = &apsta_params->if_info[i]; if (tmp_if && tmp_if->ifmode == ifmode && wl_get_isam_status(tmp_if, IF_READY)) { - if (wl_ext_get_chan(apsta_params, tmp_if->dev) == channel) { + if (wl_ext_get_chan(tmp_if->dev, &tmp_if->chan_info) == channel) { WL_MSG(tmp_if->ifname, "re-enable channel %d\n", channel); if (ifmode == IAP_MODE) { wl_ext_if_down(apsta_params, tmp_if); @@ -2150,7 +2470,7 @@ wl_ext_if_reenabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode, u32 c } u32 -wl_ext_iapsta_update_channel(struct net_device *dev, u32 channel) +wl_ext_iapsta_update_channel(struct net_device *dev, u32 chanspec) { struct dhd_pub *dhd = dhd_get_pub(dev); struct wl_apsta_params *apsta_params = dhd->iapsta_params; @@ -2159,18 +2479,19 @@ wl_ext_iapsta_update_channel(struct net_device *dev, u32 channel) cur_if = wl_get_cur_if(dev); if (cur_if) { + struct wl_chan_info *chan_info = &cur_if->chan_info; mutex_lock(&apsta_params->usr_sync); wl_ext_isam_status(cur_if->dev, NULL, 0); - cur_if->channel = channel; + wl_ext_set_chan_info(cur_if, CHSPEC2WLC_BAND(chanspec), + wf_chspec_ctlchan(chanspec)); if (wl_ext_master_if(cur_if) && apsta_params->acs) { - uint auto_band = WL_GET_BAND(channel); - cur_if->channel = wl_ext_autochannel(cur_if->dev, apsta_params->acs, - auto_band); - } - channel = wl_ext_move_cur_channel(apsta_params, cur_if); - if (channel) { - if (cur_if->ifmode == ISTA_MODE && wl_ext_dfs_chan(channel)) - wl_ext_save_master_channel(apsta_params, channel); + chan_info->chan = wl_ext_autochannel(cur_if->dev, apsta_params->acs, + chan_info->band); + } + chan_info->chan = wl_ext_move_cur_channel(apsta_params, cur_if); + if (chan_info->chan) { + if (cur_if->ifmode == ISTA_MODE && wl_ext_dfs_chan(chan_info)) + wl_ext_save_master_channel(apsta_params, chan_info->chan); target_if = wl_ext_move_other_channel(apsta_params, cur_if); if (dhd->conf->chip == BCM4359_CHIP_ID && cur_if->ifmode == ISTA_MODE && !target_if) { @@ -2179,22 +2500,23 @@ wl_ext_iapsta_update_channel(struct net_device *dev, u32 channel) * step2: enable wlan2 on channel 36 * step3: enable wlan0 to connect channel 1 AP, then it will fw trap */ - wl_ext_if_reenabled(apsta_params, IAP_MODE, channel); + wl_ext_if_reenabled(apsta_params, IAP_MODE, chan_info->chan); } } if (cur_if->ifmode == ISTA_MODE) { - if (conf->war & SET_CHAN_INCONN) { + if (conf->war & SET_CHAN_INCONN && chan_info->chan) { chanspec_t fw_chspec; - IAPSTA_INFO(dev->name, "set channel %d\n", channel); - wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver, channel, - &fw_chspec); + IAPSTA_INFO(dev->name, "set channel %d\n", chan_info->chan); + wl_ext_set_chanspec(cur_if->dev, chan_info, &fw_chspec); } wl_set_isam_status(cur_if, STA_CONNECTING); } + chanspec = wf_create_chspec_from_primary(chan_info->chan, + CHSPEC_BW(chanspec), wl_ext_wlcband_to_chanspec_band(chan_info->band)); mutex_unlock(&apsta_params->usr_sync); } - return channel; + return chanspec; } static int @@ -2240,6 +2562,9 @@ wl_ext_iapsta_update_iftype(struct net_device *net, int wl_iftype) cur_if->prio = PRIO_STA; cur_if->vsdb = TRUE; cur_if->prefix = 'S'; +#ifdef WL_STATIC_IF + dhd_conf_preinit_ioctls_sta(dhd, ifidx); +#endif /* WL_STATIC_IF */ } else if (wl_iftype == WL_IF_TYPE_AP && cur_if->ifmode != IMESH_MODE) { cur_if->ifmode = IAP_MODE; cur_if->prio = PRIO_AP; @@ -2295,57 +2620,6 @@ wl_ext_iapsta_iftype_enabled(struct net_device *net, int wl_iftype) return FALSE; } -void -wl_ext_iapsta_enable_master_if(struct net_device *dev, bool post) -{ - dhd_pub_t *dhd = dhd_get_pub(dev); - struct wl_apsta_params *apsta_params = dhd->iapsta_params; - struct wl_if_info *cur_if = NULL; - int i; - - for (i=0; iif_info[i]; - if (cur_if && cur_if->post_channel) { - if (post) - cur_if->channel = cur_if->post_channel; - else - cur_if->channel = cur_if->prev_channel; - wl_ext_if_up(apsta_params, cur_if, TRUE, 0); - cur_if->prev_channel = 0; - cur_if->post_channel = 0; - } - } -} - -void -wl_ext_iapsta_restart_master(struct net_device *dev) -{ - dhd_pub_t *dhd = dhd_get_pub(dev); - struct wl_apsta_params *apsta_params = dhd->iapsta_params; - struct wl_if_info *ap_if = NULL; - - if (apsta_params->radar) - return; - - ap_if = wl_ext_get_dfs_master_if(apsta_params); - if (ap_if) { - uint16 chan_2g, chan_5g; - wl_ext_if_down(apsta_params, ap_if); - wl_ext_iapsta_restart_master(dev); - wl_ext_get_default_chan(ap_if->dev, &chan_2g, &chan_5g, TRUE); - if (chan_5g) - ap_if->channel = chan_5g; - else if (chan_2g) - ap_if->channel = chan_2g; - else - ap_if->channel = 0; - if (ap_if->channel) { - wl_ext_move_cur_channel(apsta_params, ap_if); - wl_ext_if_up(apsta_params, ap_if, FALSE, 0); - } - } -} - bool wl_ext_iapsta_mesh_creating(struct net_device *net) { @@ -2395,7 +2669,84 @@ wl_ext_reconnect_timeout(unsigned long data) return; } IAPSTA_ERROR(dev->name, "timer expired\n"); - wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS); + wl_ext_send_event_msg(dev, WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WLC_E_STATUS_SUCCESS); +} + +#ifdef WL_EXT_DISCONNECT_RECONNECT +static bool +wl_ext_disc_recon_retry(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) +{ + int sta_disc_recon_cnt = cur_if->sta_disc_recon_cnt; + struct osl_timespec *sta_disc_conn_ts = &cur_if->sta_disc_conn_ts; + struct osl_timespec cur_ts; + uint32 diff_ms = 0; + bool retry = FALSE; + + if (sta_disc_recon_cnt == 0) + osl_do_gettimeofday(sta_disc_conn_ts); + + osl_do_gettimeofday(&cur_ts); + diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_conn_ts)/1000; + + IAPSTA_INFO(cur_if->ifname, "sta_disc_recon_cnt=%d, diff_ms = %dms\n", + sta_disc_recon_cnt, diff_ms); + if (sta_disc_recon_cnt >= STA_DISCONNECT_RECONNECT_MAX) { + if (diff_ms >= STA_DISCONNECT_RECONNECT_TIMEOUT) { + osl_do_gettimeofday(sta_disc_conn_ts); + cur_if->sta_disc_recon_cnt = 0; + retry = TRUE; + } else { + retry = FALSE; + } + } else { + retry = TRUE; + } + + if (retry) + cur_if->sta_disc_recon_cnt++; + + return retry; +} +#endif /* WL_EXT_DISCONNECT_RECONNECT */ + +static void +wl_ext_update_assoc_info(struct net_device *dev, bool reassoc) +{ +#ifndef WL_REASSOC_BCAST + dhd_pub_t *dhd = dhd_get_pub(dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_chan_info chan_info; +#endif + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + wlcfg_assoc_info_t *assoc_info; + struct wl_if_info *cur_if; + + cur_if = wl_get_cur_if(dev); + if (cur_if) { + assoc_info = &cur_if->assoc_info; + assoc_info->reassoc = reassoc; + assoc_info->bssid_hint = false; +#ifdef WL_REASSOC_BCAST + assoc_info->chan_cnt = 0; + assoc_info->chanspecs[0] = 0; + memcpy(&assoc_info->bssid, ðer_bcast, ETHER_ADDR_LEN); +#else + assoc_info->chanspecs[0] = wl_ext_get_chanspec(dev, &chan_info); + if (assoc_info->chanspecs[0] && reassoc) { + assoc_info->chan_cnt = 1; + wldev_ioctl(dev, WLC_GET_BSSID, &cur_if->bssid, ETHER_ADDR_LEN, 0); + memcpy(&assoc_info->bssid, &cur_if->bssid, ETHER_ADDR_LEN); + } else { + assoc_info->chan_cnt = 0; + memcpy(&assoc_info->bssid, ðer_bcast, ETHER_ADDR_LEN); + } +#endif /* WL_REASSOC_BCAST */ + if (!ETHER_ISBCAST(assoc_info->bssid)) + assoc_info->targeted_join = true; + else + assoc_info->targeted_join = false; + wl_get_assoc_channels(cfg, dev, assoc_info); + } } static int @@ -2405,45 +2756,122 @@ wl_ext_connect_retry(struct net_device *dev, wl_event_msg_t *e) struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct wl_if_info *cur_if; struct bcm_cfg80211 *cfg = wl_get_cfg(dev); - struct osl_timespec cur_ts, *sta_conn_ts = &apsta_params->sta_conn_ts; + struct osl_timespec cur_ts, *sta_conn_ts; + wlcfg_assoc_info_t *assoc_info; uint32 diff_ms = 0; int max_wait_time = 0, ret = 0; - bool connecting = FALSE; + bool connecting, handshaking, associated; + uint32 etype = ntoh32(e->event_type); + uint32 status = ntoh32(e->status); + + if (wl_get_drv_status(cfg, DISCONNECTING, dev)) { + WL_MSG(dev->name, "skip connect retry due to disconnecting\n"); + return BCME_BADADDR; + } cur_if = wl_get_cur_if(dev); if (!cur_if) return ret; + sta_conn_ts = &cur_if->sta_conn_ts; + connecting = wl_ext_sta_connecting(dev); + handshaking = wl_ext_sta_handshaking(dev); mutex_unlock(&apsta_params->in4way_sync); mutex_lock(&cfg->connect_sync); - connecting = wl_ext_sta_connecting(dev); osl_do_gettimeofday(&cur_ts); diff_ms = osl_do_gettimediff(&cur_ts, sta_conn_ts)/1000; + associated = wl_ext_associated(dev); + assoc_info = &cur_if->assoc_info; if (connecting && diff_ms < STA_CONNECT_TIMEOUT && !wl_get_drv_status(cfg, DISCONNECTING, dev)) { - uint32 etype = ntoh32(e->event_type); - uint32 status = ntoh32(e->status); if (etype == WLC_E_SET_SSID && (status == WLC_E_STATUS_NO_NETWORKS || status == WLC_E_STATUS_NO_ACK)) { - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); - if (cur_if->assoc_info.reassoc) { + wl_timer_mod(dhd, &cur_if->reconnect_timer, 0); + if (assoc_info->reassoc && associated && !handshaking) { + /* There are two cases will come in to retry reassoc: + * 1) reconnect from wpa_supplicant + * 2) fw roam + */ + if (associated) + bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN); WL_MSG(dev->name, "retry reassoc\n"); - wl_handle_reassoc(cfg, dev, &cur_if->assoc_info); - max_wait_time = STA_RECONNECT_RETRY_TIMEOUT; - } else { - if (!wl_ext_get_chan(apsta_params, dev)) { - WL_MSG(dev->name, "retry join\n"); - wl_cfg80211_disassoc(dev, WLAN_REASON_DEAUTH_LEAVING); - wl_handle_join(cfg, dev, &cur_if->assoc_info); - max_wait_time = STA_CONNECT_RETRY_TIMEOUT; + if (wl_handle_reassoc(cfg, dev, assoc_info)) + goto exit; + if (assoc_info->chan_cnt == 0) + max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT; + else + max_wait_time = STA_RECONNECT_RETRY_TIMEOUT + + (WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt); + max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT); + } + else { + /* There is one case will come in to retry join: + * 1) connect from wpa_supplicant + */ + WL_MSG(dev->name, "retry join\n"); + if (associated) { + bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN); + wl_cfg80211_disassoc(dev, WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT); + } + if (wl_handle_join(cfg, dev, assoc_info)) + goto exit; + if (assoc_info->chan_cnt == 0) + max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT; + else + max_wait_time = STA_CONNECT_RETRY_TIMEOUT + + (WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt); + max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT); + } + IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time); + wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time); + } + ret = BCME_ERROR; + } +#ifdef WL_EXT_DISCONNECT_RECONNECT + else if (cur_if->conn_state >= CONN_STATE_CONNECTED && + !wl_get_drv_status(cfg, DISCONNECTING, dev) && + wl_get_drv_status(cfg, CONNECTED, dev)) { + if (etype == WLC_E_DISASSOC_IND || etype == WLC_E_DEAUTH_IND) { + /* There is one case will come in to retry join: + * 1) receive disconnect from AP after connected + */ + if (wl_ext_disc_recon_retry(apsta_params, cur_if)) { + int wpa_auth = 0; + WL_MSG(dev->name, "retry join cnt %d\n", cur_if->sta_disc_recon_cnt); + bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN); + wl_ext_update_assoc_info(dev, FALSE); +#ifdef DHD_LOSSLESS_ROAMING + wl_ext_send_event_msg(dev, WLC_E_ROAM_PREP, WLC_E_STATUS_SUCCESS, WLC_E_REASON_DEAUTH); +#endif + if (wl_handle_join(cfg, dev, assoc_info)) + goto exit; + wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT); + osl_do_gettimeofday(sta_conn_ts); + wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING); + wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth); + if (!(wpa_auth & (WPA3_AUTH_SAE_PSK|0x20))) { + if (assoc_info->chan_cnt == 0) + max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT; + else + max_wait_time = STA_CONNECT_RETRY_TIMEOUT + + (WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS * assoc_info->chan_cnt); + max_wait_time = min(max_wait_time, STA_CONNECT_FULL_CHAN_TIMEOUT); + IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time); + wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time); } + ret = BCME_ERROR; + } + else { + WL_MSG(dev->name, "out of retry cnt %d within %dms\n", + cur_if->sta_disc_recon_cnt, STA_DISCONNECT_RECONNECT_TIMEOUT); } - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, max_wait_time); } - ret = -EAGAIN; } +#endif /* WL_EXT_DISCONNECT_RECONNECT */ + +exit: mutex_unlock(&cfg->connect_sync); mutex_lock(&apsta_params->in4way_sync); @@ -2453,6 +2881,7 @@ wl_ext_connect_retry(struct net_device *dev, wl_event_msg_t *e) static void wl_ext_set_connect_retry(struct net_device *dev, void *context) { + struct dhd_pub *dhd = dhd_get_pub(dev); wlcfg_assoc_info_t *assoc_info = (wlcfg_assoc_info_t *)context; struct wl_if_info *cur_if; int max_wait_time; @@ -2462,21 +2891,90 @@ wl_ext_set_connect_retry(struct net_device *dev, void *context) if (!cur_if) return; - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->reconnect_timer, 0); memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t)); wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth); if (!(wpa_auth & (WPA3_AUTH_SAE_PSK|0x20) && assoc_info)) { memcpy(&cur_if->bssid, assoc_info->bssid, ETHER_ADDR_LEN); memcpy(&cur_if->assoc_info, assoc_info, sizeof(wlcfg_assoc_info_t)); - if (assoc_info->reassoc) + if (assoc_info->chan_cnt == 0) + max_wait_time = STA_CONNECT_FULL_CHAN_TIMEOUT; + else if (assoc_info->reassoc) max_wait_time = STA_RECONNECT_RETRY_TIMEOUT; else max_wait_time = STA_CONNECT_RETRY_TIMEOUT; IAPSTA_INFO(dev->name, "reconnect %dms later\n", max_wait_time); - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, max_wait_time); + wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time); } } #endif /* WL_EXT_RECONNECT */ + +#ifdef STA_MGMT +static void +wl_ext_flush_sta_list(struct net_device *net, int ifidx) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + wl_sta_info_t *node, *next; + + list_for_each_entry_safe(node, next, &apsta_params->sta_list, list) { + if (node->ifidx == ifidx || ifidx == 0xFF) { + IAPSTA_INFO(net->name, "Del BSSID %pM\n", &node->bssid); + list_del(&node->list); + kfree(node); + } + } +} + +bool +wl_ext_del_sta_info(struct net_device *net, u8 *bssid) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + int ifidx = dhd_net2idx(dhd->info, net); + wl_sta_info_t *node, *next; + bool in_list = FALSE; + + list_for_each_entry_safe(node, next, &apsta_params->sta_list, list) { + if (node->ifidx == ifidx && !memcmp(&node->bssid, bssid, ETHER_ADDR_LEN)) { + IAPSTA_INFO(net->name, "Del BSSID %pM\n", &node->bssid); + in_list = TRUE; + list_del(&node->list); + kfree(node); + } + } + return in_list; +} + +bool +wl_ext_add_sta_info(struct net_device *net, u8 *bssid) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + int ifidx = dhd_net2idx(dhd->info, net); + wl_sta_info_t *node, *next, *leaf; + + list_for_each_entry_safe(node, next, &apsta_params->sta_list, list) { + if (node->ifidx == ifidx && !memcmp(&node->bssid, bssid, ETHER_ADDR_LEN)) { + IAPSTA_INFO(net->name, "BSSID %pM already in list\n", bssid); + return FALSE; + } + } + + leaf = kmalloc(sizeof(wl_sta_info_t), GFP_KERNEL); + if (!leaf) { + IAPSTA_ERROR(net->name, "Memory alloc failure %d\n", + (int)sizeof(wl_sta_info_t)); + return FALSE; + } + IAPSTA_INFO(net->name, "Add BSSID %pM in the leaf\n", bssid); + leaf->ifidx = ifidx; + memcpy(&leaf->bssid, bssid, ETHER_ADDR_LEN); + list_add_tail(&leaf->list, &apsta_params->sta_list); + + return TRUE; +} +#endif /* STA_MGMT */ #endif /* WL_CFG80211 */ #ifndef WL_STATIC_IF @@ -2729,7 +3227,7 @@ wl_ext_update_conn_state(dhd_pub_t *dhd, int ifidx, uint conn_state) conn_state >= CONN_STATE_CONNECTED || conn_state <= CONN_STATE_CONNECTING) apsta_params->if_info[ifidx].conn_state = conn_state; - else + else IAPSTA_INFO(cur_if->dev->name, "skip update %d\n", conn_state); } else { apsta_params->if_info[ifidx].conn_state = conn_state; @@ -2784,7 +3282,7 @@ wl_ext_free_eapol_txpkt(struct wl_if_info *cur_if, bool rx) #ifdef BCMDBUS if (!rx) #endif /* BCMDBUS */ - wl_ext_mod_timer(&cur_if->eapol_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->eapol_timer, 0); if (cur_if->pend_eapol_pkt) { PKTCFREE(dhd->osh, cur_if->pend_eapol_pkt, TRUE); @@ -2843,7 +3341,7 @@ wl_ext_backup_eapol_txpkt(dhd_pub_t *dhd, int ifidx, void *pkt) #else interval = STA_EAPOL_TIMEOUT; #endif /* EAPOL_DYNAMATIC_RESEND */ - wl_ext_mod_timer(&cur_if->eapol_timer, 0, interval); + wl_timer_mod(dhd, &cur_if->eapol_timer, interval); IAPSTA_TRACE(cur_if->dev->name, "backup eapol pkt\n"); } spin_unlock_irqrestore(&apsta_params->eapol_lock, flags); @@ -2877,7 +3375,7 @@ wl_resend_eapol_handler(struct wl_if_info *cur_if, cur_if->eapol_max_intvl, STA_EAPOL_TIMEOUT, cur_if->eapol_cnt); #else - IAPSTA_INFO(dev->name, "resend eapol pkt %d\n", STA_EAPOL_TIMEOUT); + IAPSTA_INFO(dev->name, "resend eapol pkt %dms\n", STA_EAPOL_TIMEOUT); #endif /* EAPOL_DYNAMATIC_RESEND */ pending = TRUE; } @@ -2906,89 +3404,186 @@ wl_eapol_timer(unsigned long data) bzero(&msg, sizeof(wl_event_msg_t)); IAPSTA_TRACE(dev->name, "timer expired\n"); - msg.ifidx = hton32(dhd_net2idx(dhd->info, dev)); + msg.ifidx = dhd_net2idx(dhd->info, dev); msg.event_type = hton32(WLC_E_RESERVED); msg.reason = hton32(ISAM_RC_EAPOL_RESEND); wl_ext_event_send(dhd->event_params, &msg, NULL); } #endif /* EAPOL_RESEND */ -#if defined(WL_CFG80211) && defined(SCAN_SUPPRESS) +#ifdef KEY_INSTALL_CHECK static void -wl_ext_light_scan_prep(struct net_device *dev, void *scan_params, bool scan_v2) +wl_ext_key_install_timeout(unsigned long data) { - wl_scan_params_t *params = NULL; - wl_scan_params_v2_t *params_v2 = NULL; + struct net_device *dev = (struct net_device *)data; + struct dhd_pub *dhd; + wl_event_msg_t msg; - if (!scan_params) { - IAPSTA_ERROR(dev->name, "NULL scan_params\n"); + if (!dev) { + IAPSTA_ERROR("wlan", "dev is not ready\n"); return; } - IAPSTA_INFO(dev->name, "Enter\n"); - if (scan_v2) { - params_v2 = (wl_scan_params_v2_t *)scan_params; - } else { - params = (wl_scan_params_t *)scan_params; - } + dhd = dhd_get_pub(dev); - if (params_v2) { - /* scan params ver2 */ - params_v2->nprobes = 1; - params_v2->active_time = 20; - params_v2->home_time = 150; - } else { - /* scan params ver 1 */ - if (!params) { - ASSERT(0); - return; - } - params->nprobes = 1; - params->active_time = 20; - params->home_time = 150; + bzero(&msg, sizeof(wl_event_msg_t)); + IAPSTA_TRACE(dev->name, "timer expired\n"); + + msg.ifidx = dhd_net2idx(dhd->info, dev); + msg.event_type = hton32(WLC_E_RESERVED); + msg.reason = hton32(ISAM_RC_KEY_INSTALL); + wl_ext_event_send(dhd->event_params, &msg, NULL); +} + +static void +wl_ext_key_install_handler(struct wl_if_info *cur_if, + const wl_event_msg_t *e, void *data) +{ + struct net_device *dev = cur_if->dev; + struct dhd_pub *dhd = dhd_get_pub(dev); + struct bcm_cfg80211 *cfg = wl_get_cfg(dev); + uint32 etype = ntoh32(e->event_type); + uint32 reason = ntoh32(e->reason); + int err, key_installed = 0; + + if (etype == WLC_E_RESERVED && reason == ISAM_RC_KEY_INSTALL) { + if (cur_if->conn_state >= CONN_STATE_4WAY_M4 && + !wl_get_drv_status(cfg, DISCONNECTING, dev) && + wl_get_drv_status(cfg, CONNECTED, dev)) { + err = wldev_iovar_getint(dev, "buf_key_b4_m4_installed", &key_installed); + if (!err && !key_installed) { + cur_if->key_install_cnt++; + if (cur_if->key_install_cnt > STA_KEY_INSTALL_MAX) { + IAPSTA_ERROR(dev->name, "key not installed, send disconnect\n"); +#ifdef EAPOL_RESEND + wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); +#endif /* EAPOL_RESEND */ + wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED); + wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1); + wl_timer_mod(dhd, &cur_if->key_install_timer, 0); + cur_if->key_install_cnt = 0; + } else { + IAPSTA_INFO(dev->name, "check key installed %dms later, cnt=%d\n", + STA_KEY_INSTALL_INTERVAL, cur_if->key_install_cnt); + wl_timer_mod(dhd, &cur_if->key_install_timer, STA_KEY_INSTALL_INTERVAL); + } + } else { +#ifdef EAPOL_RESEND + wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); +#endif /* EAPOL_RESEND */ + IAPSTA_INFO(dev->name, "key installed\n"); + wl_timer_mod(dhd, &cur_if->connect_timer, 0); + wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED); + cur_if->key_install_cnt = 0; + } + } + } + return; +} + +static int +wl_key_installed(struct wl_if_info *cur_if) +{ + struct net_device *dev = cur_if->dev; + dhd_pub_t *dhd = dhd_get_pub(dev); + int err, key_installed = 0; + + err = wldev_iovar_getint(dev, "buf_key_b4_m4_installed", &key_installed); + if (err) { + IAPSTA_INFO(dev->name, "not supported %d\n", err); + key_installed = 1; + } else if (key_installed) + IAPSTA_INFO(dev->name, "key installed\n"); + + if (key_installed) + wl_timer_mod(dhd, &cur_if->key_install_timer, 0); + else { + IAPSTA_INFO(dev->name, "check key installed %dms later\n", STA_KEY_INSTALL_INTERVAL); + wl_timer_mod(dhd, &cur_if->key_install_timer, STA_KEY_INSTALL_INTERVAL); + } + + return key_installed; +} +#endif /* KEY_INSTALL_CHECK */ + +#if defined(WL_CFG80211) && defined(SCAN_SUPPRESS) +static void +wl_ext_light_scan_prep(struct net_device *dev, void *scan_params, bool scan_v2) +{ + wl_scan_params_v1_t *params = NULL; + wl_scan_params_v2_t *params_v2 = NULL; + + if (!scan_params) { + IAPSTA_ERROR(dev->name, "NULL scan_params\n"); + return; + } + IAPSTA_INFO(dev->name, "Enter\n"); + + if (scan_v2) { + params_v2 = (wl_scan_params_v2_t *)scan_params; + } else { + params = (wl_scan_params_v1_t *)scan_params; + } + + if (params_v2) { + /* scan params ver2 */ + params_v2->nprobes = 1; + params_v2->active_time = 20; + params_v2->home_time = 150; + } else { + /* scan params ver 1 */ + if (!params) { + ASSERT(0); + return; + } + params->nprobes = 1; + params->active_time = 20; + params->home_time = 150; } return; } static uint16 -wl_ext_max_tput_chan(struct wl_apsta_params *apsta_params) +wl_ext_max_tput_chan(struct wl_apsta_params *apsta_params, + struct wl_chan_info *chan_info) { struct wl_if_info *tmp_if, *max_tput_if = NULL; - uint16 chan = 0, max_tput_chan = 0; int32 tput_sum = 0; int i; for (i=0; iif_info[i]; - if (tmp_if->dev && (tmp_if->tput_tx + tmp_if->tput_rx) > tput_sum) { - chan = wl_ext_get_chan(apsta_params, tmp_if->dev); - if (chan) { + if (tmp_if->dev && (tmp_if->tput_info.tput_tx + tmp_if->tput_info.tput_rx) > tput_sum) { + memset(chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(tmp_if->dev, chan_info); + if (chan_info->chan) { max_tput_if = tmp_if; - tput_sum = tmp_if->tput_tx + tmp_if->tput_rx; - max_tput_chan = chan; + tput_sum = tmp_if->tput_info.tput_tx + tmp_if->tput_info.tput_rx; break; } } } - if (max_tput_chan) - IAPSTA_INFO(max_tput_if->dev->name, "chan=%d\n", max_tput_chan); + if (max_tput_if) + IAPSTA_INFO(max_tput_if->dev->name, "chan=%s-%d\n", + WLCBAND2STR(chan_info->band), chan_info->chan); - return max_tput_chan; + return chan_info->chan; } uint16 -wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2) +wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2, + struct wl_chan_info *chan_info) { struct dhd_pub *dhd = dhd_get_pub(dev); struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct dhd_conf *conf = dhd->conf; - uint16 chan = 0; if (!(conf->scan_intput & (SCAN_CURCHAN_INTPUT|SCAN_LIGHT_INTPUT))) return 0; + memset(chan_info, 0, sizeof(struct wl_chan_info)); if (apsta_params->tput_sum >= conf->scan_tput_thresh) { IAPSTA_INFO(dev->name, "tput %dMbps >= %dMbps (busy cnt/thresh %d/%d)\n", apsta_params->tput_sum, conf->scan_tput_thresh, @@ -2996,9 +3591,9 @@ wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2) if (apsta_params->scan_busy_cnt >= conf->scan_busy_thresh) { apsta_params->scan_busy_cnt = 0; } else if (conf->scan_intput & SCAN_CURCHAN_INTPUT) { - chan = wl_ext_max_tput_chan(apsta_params); + wl_ext_max_tput_chan(apsta_params, chan_info); } - if ((conf->scan_intput & SCAN_LIGHT_INTPUT) && !chan) + if ((conf->scan_intput & SCAN_LIGHT_INTPUT) && !chan_info->chan) wl_ext_light_scan_prep(dev, scan_params, scan_v2); apsta_params->scan_busy_cnt++; } @@ -3006,7 +3601,7 @@ wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2) apsta_params->scan_busy_cnt = 0; } - return chan; + return chan_info->chan; } static int @@ -3100,7 +3695,6 @@ wl_set_btc_in4way(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_i } } } - } static void @@ -3108,7 +3702,7 @@ wl_wait_disconnect(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_ enum wl_ext_status status) { struct net_device *dev = cur_if->dev; - struct osl_timespec cur_ts, *sta_disc_ts = &apsta_params->sta_disc_ts; + struct osl_timespec cur_ts, *sta_disc_ts = &cur_if->sta_disc_ts; int max_wait_time = 200, max_wait_cnt = 20; int cur_conn_state = cur_if->conn_state; uint32 diff_ms = 0; @@ -3158,13 +3752,13 @@ wl_iapsta_suspend_resume_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (suspend) { if (insuspend & AP_DOWN_IN_SUSPEND) { - cur_if->channel = wl_ext_get_chan(apsta_params, cur_if->dev); - if (cur_if->channel) + cur_if->chan_info.chan = wl_ext_get_chan(cur_if->dev, &cur_if->chan_info); + if (cur_if->chan_info.chan) wl_ext_if_down(apsta_params, cur_if); } } else { if (insuspend & AP_DOWN_IN_SUSPEND) { - if (cur_if->channel) + if (cur_if->chan_info.chan) wl_ext_if_up(apsta_params, cur_if, FALSE, 0); } } @@ -3181,7 +3775,7 @@ wl_iapsta_suspend_resume(dhd_pub_t *dhd, int suspend) #ifdef TPUT_MONITOR if (suspend) - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0); + wl_timer_mod(dhd, &apsta_params->monitor_timer, 0); #endif /* TPUT_MONITOR */ for (i=0; imonitor_timer, 0, dhd->conf->tput_monitor_ms); + wl_timer_mod(dhd, &apsta_params->monitor_timer, dhd->conf->tput_monitor_ms); #endif /* TPUT_MONITOR */ return 0; @@ -3213,11 +3807,11 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct dhd_conf *conf = dhd->conf; struct net_device *dev = cur_if->dev; - struct osl_timespec cur_ts, *sta_disc_ts = &apsta_params->sta_disc_ts; - struct osl_timespec *sta_conn_ts = &apsta_params->sta_conn_ts; + struct osl_timespec cur_ts, *sta_disc_ts = &cur_if->sta_disc_ts; + struct osl_timespec *sta_conn_ts = &cur_if->sta_conn_ts; uint32 diff_ms = 0; - int ret = 0, cur_conn_state; - int suppressed = 0, wpa_auth = 0; + int ret = 0, suppressed = 0, wpa_auth = 0, max_wait_time = 0, key_installed = 1; + uint cur_conn_state, conn_state; bool connecting = FALSE; wl_event_msg_t *e = (wl_event_msg_t *)context; #ifdef WL_CFG80211 @@ -3268,7 +3862,8 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, osl_do_gettimeofday(&cur_ts); diff_ms = osl_do_gettimediff(&cur_ts, sta_conn_ts)/1000; if (connecting && diff_ms <= STA_CONNECT_TIMEOUT) { - IAPSTA_ERROR(dev->name, "connecting... %d\n", cur_conn_state); + IAPSTA_ERROR(dev->name, "scan during connecting... %d\n", + cur_conn_state); ret = -EBUSY; break; } @@ -3282,34 +3877,25 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (wl_get_drv_status(cfg, CONNECTING, dev) || (connecting && diff_ms <= STA_CONNECT_TIMEOUT) || (cur_if->empty_scan >= STA_EMPTY_SCAN_MAX)) { - unsigned long flags = 0; cur_if->empty_scan = 0; - spin_lock_irqsave(&dhd->up_lock, flags); - if (dhd->up) { - wl_event_msg_t msg; - bzero(&msg, sizeof(wl_event_msg_t)); - msg.event_type = hton32(WLC_E_ESCAN_RESULT); - msg.status = hton32(WLC_E_STATUS_SUCCESS); - WL_MSG(dev->name, "FAKE SCAN\n"); - wl_cfg80211_event(dev, &msg, NULL); - ret = -EBUSY; - } - spin_unlock_irqrestore(&dhd->up_lock, flags); + WL_MSG(dev->name, "FAKE SCAN\n"); + ret = -EBUSY; } } break; case WL_EXT_STATUS_SCAN_COMPLETE: - if ((conf->war & FW_REINIT_EMPTY_SCAN) && cfg->bss_list->count == 0) { - uint16 channel; + if ((conf->war & FW_REINIT_EMPTY_SCAN) && + cfg->bss_list->count == 0 && !p2p_scan(cfg)) { + bool assoc; osl_do_gettimeofday(&cur_ts); diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_ts)/1000; - channel = wl_ext_get_chan(apsta_params, dev); + assoc = wl_ext_associated(dev); cur_if->empty_scan++; - if ((channel && cur_if->empty_scan >= STA_EMPTY_SCAN_MAX) || + if ((assoc && cur_if->empty_scan >= STA_EMPTY_SCAN_MAX) || (diff_ms < STA_LINKDOWN_TIMEOUT && apsta_params->linkdown_reason == WLC_E_LINK_BCN_LOSS)) { if (conf->chip == BCM43569_CHIP_ID) { - if (channel) { + if (assoc) { IAPSTA_INFO(dev->name, "wl disassoc for empty scan\n"); wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1); } @@ -3324,18 +3910,26 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, } break; #endif /* WL_CFG80211 */ - case WL_EXT_STATUS_DISCONNECTING: + case WL_EXT_STATUS_PRE_DISCONNECTING: #ifdef EAPOL_RESEND wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); #endif /* EAPOL_RESEND */ - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); +#ifdef KEY_INSTALL_CHECK + wl_timer_mod(dhd, &cur_if->key_install_timer, 0); +#endif /* KEY_INSTALL_CHECK */ + wl_timer_mod(dhd, &cur_if->connect_timer, 0); #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->reconnect_timer, 0); memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t)); +#ifdef WL_EXT_DISCONNECT_RECONNECT + cur_if->sta_disc_recon_cnt = 0; +#endif /* WL_EXT_DISCONNECT_RECONNECT */ #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ #ifdef SCAN_SUPPRESS apsta_params->scan_busy_cnt = 0; #endif /* SCAN_SUPPRESS */ + break; + case WL_EXT_STATUS_DISCONNECTING: if (connecting) { IAPSTA_ERROR(dev->name, "connect failed at %d\n", cur_conn_state); wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_IDLE); @@ -3343,6 +3937,9 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (action & STA_NO_BTC_IN4WAY) { wl_set_btc_in4way(apsta_params, cur_if, status, FALSE); } +#ifdef BTC_WAR + wl_ext_btc_config(cur_if->dev, FALSE); +#endif /* BTC_WAR */ if (action & STA_WAIT_DISCONNECTED) { wl_wait_disconnect(apsta_params, cur_if, status); wake_up_interruptible(&conf->event_complete); @@ -3353,8 +3950,11 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (action & STA_REASSOC_RETRY) { wl_ext_set_connect_retry(dev, context); } +#ifdef WL_EXT_DISCONNECT_RECONNECT + cur_if->sta_disc_recon_cnt = 0; +#endif /* WL_EXT_DISCONNECT_RECONNECT */ #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ - wl_ext_mod_timer(&cur_if->connect_timer, 0, STA_CONNECT_TIMEOUT); + wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT); osl_do_gettimeofday(sta_conn_ts); wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING); if (action & STA_NO_BTC_IN4WAY) { @@ -3364,12 +3964,18 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, case WL_EXT_STATUS_CONNECTED: wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth); if ((wpa_auth < WPA_AUTH_UNSPECIFIED) || (wpa_auth & WPA2_AUTH_FT)) { - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->connect_timer, 0); wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED); +#ifdef BTC_WAR + wl_ext_btc_config(cur_if->dev, TRUE); +#endif /* BTC_WAR */ + max_wait_time = 0; + } else { + max_wait_time = STA_4WAY_TIMEOUT; } #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); - memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t)); + wl_ext_update_assoc_info(dev, TRUE); + wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time); #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ if (cur_if->ifmode == ISTA_MODE) { dhd_conf_set_wme(dhd, cur_if->ifidx, 0); @@ -3379,6 +3985,31 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, dhd_conf_set_mchan_bw(dhd, WL_P2P_IF_CLIENT, -1); } break; + case WL_EXT_STATUS_ROAMED: + wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth); + if ((wpa_auth >= WPA_AUTH_UNSPECIFIED) && !(wpa_auth & WPA2_AUTH_FT)) { + wl_timer_mod(dhd, &cur_if->connect_timer, STA_CONNECT_TIMEOUT); + osl_do_gettimeofday(sta_conn_ts); + wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTING); +#ifdef BTC_WAR + wl_ext_btc_config(cur_if->dev, TRUE); +#endif /* BTC_WAR */ + max_wait_time = STA_4WAY_TIMEOUT; + } else { + max_wait_time = 0; + } +#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) + wl_ext_update_assoc_info(dev, TRUE); + wl_timer_mod(dhd, &cur_if->reconnect_timer, max_wait_time); +#endif /* WL_EXT_RECONNECT && WL_CFG80211 */ +#ifdef KEY_INSTALL_CHECK + wl_timer_mod(dhd, &cur_if->key_install_timer, 0); +#endif /* KEY_INSTALL_CHECK */ + if (cur_if->ifmode == ISTA_MODE) { + dhd_conf_set_wme(dhd, cur_if->ifidx, 0); + wake_up_interruptible(&conf->event_complete); + } + break; case WL_EXT_STATUS_RECONNECT: #ifdef EAPOL_RESEND wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); @@ -3393,9 +4024,15 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, #ifdef EAPOL_RESEND wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); #endif /* EAPOL_RESEND */ +#ifdef KEY_INSTALL_CHECK + wl_timer_mod(dhd, &cur_if->key_install_timer, 0); +#endif /* KEY_INSTALL_CHECK */ #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->reconnect_timer, 0); memset(&cur_if->assoc_info, 0, sizeof(wlcfg_assoc_info_t)); +#ifdef WL_EXT_DISCONNECT_RECONNECT + cur_if->sta_disc_recon_cnt = 0; +#endif /* WL_EXT_DISCONNECT_RECONNECT */ #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ #ifdef SCAN_SUPPRESS apsta_params->scan_busy_cnt = 0; @@ -3404,7 +4041,7 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, !(ntoh16(e->flags) & WLC_EVENT_MSG_LINK)) { apsta_params->linkdown_reason = ntoh32(e->reason); } - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->connect_timer, 0); if (connecting) { IAPSTA_ERROR(dev->name, "connect failed at %d\n", cur_conn_state); } @@ -3412,23 +4049,37 @@ wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (action & STA_NO_BTC_IN4WAY) { wl_set_btc_in4way(apsta_params, cur_if, status, FALSE); } +#ifdef BTC_WAR + wl_ext_btc_config(cur_if->dev, FALSE); +#endif /* BTC_WAR */ osl_do_gettimeofday(sta_disc_ts); wake_up_interruptible(&conf->event_complete); break; case WL_EXT_STATUS_ADD_KEY: - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); - wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_CONNECTED); -#ifdef EAPOL_RESEND - wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); -#endif /* EAPOL_RESEND */ + conn_state = CONN_STATE_ADD_KEY; + wl_timer_mod(dhd, &cur_if->connect_timer, 0); #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->reconnect_timer, 0); #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ +#ifdef KEY_INSTALL_CHECK + key_installed = wl_key_installed(cur_if); +#endif /* KEY_INSTALL_CHECK */ + if (key_installed) + conn_state = CONN_STATE_CONNECTED; + wl_ext_update_conn_state(dhd, cur_if->ifidx, conn_state); + IAPSTA_INFO(dev->name, "WPA 4-WAY complete %d => %d\n", + cur_conn_state, conn_state); +#ifdef EAPOL_RESEND + if (key_installed) + wl_ext_release_eapol_txpkt(dhd, cur_if->ifidx, FALSE); +#endif /* EAPOL_RESEND */ if (action & STA_NO_BTC_IN4WAY) { wl_set_btc_in4way(apsta_params, cur_if, status, FALSE); } +#ifdef BTC_WAR + wl_ext_btc_config(cur_if->dev, TRUE); +#endif /* BTC_WAR */ wake_up_interruptible(&conf->event_complete); - IAPSTA_INFO(dev->name, "WPA 4-WAY complete %d\n", cur_conn_state); break; default: IAPSTA_INFO(dev->name, "Unknown action=0x%x, status=%d\n", action, status); @@ -3444,8 +4095,8 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, { struct wl_apsta_params *apsta_params = dhd->iapsta_params; struct net_device *dev = cur_if->dev; - struct osl_timespec cur_ts, *ap_disc_sta_ts = &apsta_params->ap_disc_sta_ts; - u8 *ap_disc_sta_bssid = (u8*)&apsta_params->ap_disc_sta_bssid; + struct osl_timespec cur_ts, *ap_disc_sta_ts = &cur_if->ap_disc_sta_ts; + u8 *ap_disc_sta_bssid = (u8*)&cur_if->ap_disc_sta_bssid; uint32 diff_ms = 0, timeout, max_wait_time = 300; int ret = 0, suppressed = 0; u8* mac_addr = context; @@ -3464,12 +4115,25 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, break; } break; + case WL_EXT_STATUS_AP_ENABLING: +#ifdef RESTART_AP_WAR + wl_timer_mod(dhd, &cur_if->restart_ap_timer, AP_RESTART_TIMEOUT); +#endif /* RESTART_AP_WAR */ + break; case WL_EXT_STATUS_AP_ENABLED: +#ifdef RESTART_AP_WAR + wl_timer_mod(dhd, &cur_if->restart_ap_timer, 0); +#endif /* RESTART_AP_WAR */ if (cur_if->ifmode == IAP_MODE) dhd_conf_set_wme(dhd, cur_if->ifidx, 1); else if (cur_if->ifmode == IGO_MODE) dhd_conf_set_mchan_bw(dhd, WL_P2P_IF_GO, -1); break; + case WL_EXT_STATUS_AP_DISABLING: +#ifdef RESTART_AP_WAR + wl_timer_mod(dhd, &cur_if->restart_ap_timer, 0); +#endif /* RESTART_AP_WAR */ + break; case WL_EXT_STATUS_DELETE_STA: if (action & AP_WAIT_STA_RECONNECT) { osl_do_gettimeofday(&cur_ts); @@ -3485,13 +4149,13 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, } if (wait) { IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d, waiting %dms ...\n", - status, apsta_params->ap_recon_sta, max_wait_time); + status, cur_if->ap_recon_sta, max_wait_time); mutex_unlock(&apsta_params->in4way_sync); - timeout = wait_event_interruptible_timeout(apsta_params->ap_recon_sta_event, - apsta_params->ap_recon_sta, msecs_to_jiffies(max_wait_time)); + timeout = wait_event_interruptible_timeout(cur_if->ap_recon_sta_event, + cur_if->ap_recon_sta, msecs_to_jiffies(max_wait_time)); mutex_lock(&apsta_params->in4way_sync); IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d, timeout=%d\n", - status, apsta_params->ap_recon_sta, timeout); + status, cur_if->ap_recon_sta, timeout); if (timeout > 0) { IAPSTA_INFO(dev->name, "skip delete STA %pM\n", mac_addr); ret = -1; @@ -3499,8 +4163,8 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, } } else { IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d => 0\n", - status, apsta_params->ap_recon_sta); - apsta_params->ap_recon_sta = FALSE; + status, cur_if->ap_recon_sta); + cur_if->ap_recon_sta = FALSE; if (cur_if->ifmode == IGO_MODE) wl_ext_update_conn_state(dhd, cur_if->ifidx, CONN_STATE_IDLE); } @@ -3509,10 +4173,10 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, case WL_EXT_STATUS_STA_DISCONNECTED: if (action & AP_WAIT_STA_RECONNECT) { IAPSTA_INFO(dev->name, "latest disc STA %pM ap_recon_sta=%d\n", - ap_disc_sta_bssid, apsta_params->ap_recon_sta); + ap_disc_sta_bssid, cur_if->ap_recon_sta); osl_do_gettimeofday(ap_disc_sta_ts); memcpy(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN); - apsta_params->ap_recon_sta = FALSE; + cur_if->ap_recon_sta = FALSE; } break; case WL_EXT_STATUS_STA_CONNECTED: @@ -3522,11 +4186,11 @@ wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if, if (diff_ms < max_wait_time && !memcmp(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN)) { IAPSTA_INFO(dev->name, "status=%d, ap_recon_sta=%d => 1\n", - status, apsta_params->ap_recon_sta); - apsta_params->ap_recon_sta = TRUE; - wake_up_interruptible(&apsta_params->ap_recon_sta_event); + status, cur_if->ap_recon_sta); + cur_if->ap_recon_sta = TRUE; + wake_up_interruptible(&cur_if->ap_recon_sta_event); } else { - apsta_params->ap_recon_sta = FALSE; + cur_if->ap_recon_sta = FALSE; } } break; @@ -3664,6 +4328,29 @@ wl_ext_in4way_sync_wext(struct net_device *dev, uint action, #endif /* WL_WIRELESS_EXT */ #ifdef TPUT_MONITOR +static void +wl_tput_monitor_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct dhd_pub *dhd; + wl_event_msg_t msg; + + if (!dev) { + IAPSTA_ERROR("wlan", "dev is not ready\n"); + return; + } + + dhd = dhd_get_pub(dev); + + bzero(&msg, sizeof(wl_event_msg_t)); + IAPSTA_TRACE(dev->name, "timer expired\n"); + + msg.ifidx = 0; + msg.event_type = hton32(WLC_E_RESERVED); + msg.reason = hton32(ISAM_RC_TPUT_MONITOR); + wl_ext_event_send(dhd->event_params, &msg, NULL); +} + static int wl_ext_assoclist_num(struct net_device *dev) { @@ -3681,194 +4368,402 @@ wl_ext_assoclist_num(struct net_device *dev) return maxassoc; } +static int +dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + dhd_ioctl_t ioc; + int8 index; + int ret; + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + + index = dhd_net2idx(dhd->info, dev); + if (index == DHD_BAD_IF) { + IAPSTA_ERROR(dev->name, "Bad ifidx from dev\n"); + return -ENODEV; + } + ret = dhd_ioctl_process(dhd, index, &ioc, arg); + + return ret; +} + static void -wl_tput_monitor_timer(unsigned long data) +wl_ampdu_dump(struct net_device *dev) { - struct net_device *dev = (struct net_device *)data; - struct dhd_pub *dhd; - wl_event_msg_t msg; + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + char *ioctl_buf = apsta_params->ioctl_buf, *buf = NULL; + char *tx_pch_start, *tx_pch_end, *rx_pch_start, *rx_pch_end; + int ret = 0, max_len, tx_len, rx_len; - if (!dev) { - IAPSTA_ERROR("wlan", "dev is not ready\n"); + if (!(android_msg_level & ANDROID_AMPDU_LEVEL)) + return; + + if (!ioctl_buf) return; + + memset(ioctl_buf, 0, WL_DUMP_BUF_LEN); + ret = bcm_mkiovar("dump", "ampdu", strlen("ampdu"), ioctl_buf, WL_DUMP_BUF_LEN); + if (ret == 0) { + goto exit; + } + ret = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctl_buf, WL_DUMP_BUF_LEN); + if (ret) { + goto exit; } - dhd = dhd_get_pub(dev); + buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); + if (buf == NULL) { + IAPSTA_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_MEDLEN); + goto exit; + } + memset(buf, 0, WLC_IOCTL_MEDLEN); + ret = bcm_mkiovar("dump_clear", "ampdu", strlen("ampdu"), buf, WLC_IOCTL_MEDLEN); + if (ret == 0) { + goto exit; + } + ret = dev_wlc_ioctl(dev, WLC_SET_VAR, (void *)buf, WLC_IOCTL_MEDLEN); + if (ret) { + goto exit; + } - bzero(&msg, sizeof(wl_event_msg_t)); - IAPSTA_TRACE(dev->name, "timer expired\n"); + tx_pch_start = strstr(ioctl_buf, "TX MCS"); + tx_pch_end = strstr(ioctl_buf, "HEMU"); + rx_pch_start = strstr(ioctl_buf, "RX MCS"); + rx_pch_end = strstr(ioctl_buf, "RX MCS SGI"); + max_len = (tx_pch_end-tx_pch_start) + (rx_pch_end-rx_pch_start); + if (max_len > (WLC_IOCTL_MEDLEN-1)) + goto exit; - msg.ifidx = 0; - msg.event_type = hton32(WLC_E_RESERVED); - msg.reason = hton32(ISAM_RC_TPUT_MONITOR); - wl_ext_event_send(dhd->event_params, &msg, NULL); + tx_len = tx_pch_end - tx_pch_start; + rx_len = rx_pch_end - rx_pch_start; + + memset(buf, 0, WLC_IOCTL_MEDLEN); + memcpy(buf, tx_pch_start, tx_len); + memcpy(buf+tx_len, rx_pch_start, rx_len); + WL_MSG(dev->name,"\n%s\n", buf); + +exit: + if (buf) + kfree(buf); } static void -wl_tput_dump(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) +wl_btc_dump(struct net_device *dev) { - struct dhd_pub *dhd = apsta_params->dhd; - void *buf = NULL; - sta_info_v4_t *sta = NULL; - struct ether_addr bssid; - wl_rssi_ant_t *rssi_ant_p; - char rssi_buf[16]; - scb_val_t scb_val; - int ret, bytes_written = 0, i; - s32 rate = 0; - dhd_if_t *ifp = NULL; + struct dhd_pub *dhd = dhd_get_pub(dev); + int ret, val; - if (!(android_msg_level & ANDROID_TPUT_LEVEL)) + if (!(android_msg_level & ANDROID_BTC_LEVEL)) return; - ifp = dhd_get_ifp(dhd, cur_if->ifidx); + ret = dhd_conf_reg2args(dhd, "btc_params", FALSE, 15, &val); + if (!ret) + WL_MSG(dev->name,"btc_params15=%d\n", val); +} - buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); - if (buf == NULL) { - IAPSTA_ERROR(cur_if->dev->name, "MALLOC failed\n"); +static void +wl_tvpm_dump(struct net_device *dev) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + wl_tvpm_req_t* tvpm_req = NULL; + size_t reqlen = sizeof(wl_tvpm_req_t) + sizeof(wl_tvpm_status_t); + uint8 *outbuf = apsta_params->ioctl_buf; + size_t outlen = WLC_IOCTL_MEDLEN; + wl_tvpm_status_t* status; + int ret, phy_temp = 0; + bool tvpm = FALSE, sense = FALSE; + + if (!(android_msg_level & ANDROID_TVPM_LEVEL)) + return; + + tvpm_req = kmalloc(reqlen, GFP_KERNEL); + if (tvpm_req == NULL) { + IAPSTA_ERROR(dev->name, "MALLOC failed\n"); goto exit; } + memset(tvpm_req, 0, reqlen); - wldev_ioctl_get(cur_if->dev, WLC_GET_RATE, &rate, sizeof(rate)); - rate = dtoh32(rate); - memset(rssi_buf, 0, sizeof(rssi_buf)); - if (cur_if->ifmode == ISTA_MODE) { - ret = wldev_iovar_getbuf(cur_if->dev, "phy_rssi_ant", NULL, 0, - buf, WLC_IOCTL_MEDLEN, NULL); - rssi_ant_p = (wl_rssi_ant_t *)buf; - rssi_ant_p->version = dtoh32(rssi_ant_p->version); - rssi_ant_p->count = dtoh32(rssi_ant_p->count); - if (ret < 0 || rssi_ant_p->count == 0) { - wldev_ioctl(cur_if->dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0); + tvpm_req->version = TVPM_REQ_VERSION_1; + tvpm_req->length = reqlen; + tvpm_req->req_type = WL_TVPM_REQ_STATUS; + ret = wldev_iovar_getbuf(dev, "tvpm", tvpm_req, reqlen, outbuf, outlen, NULL); + status = (wl_tvpm_status_t*)outbuf; + if (!ret && status->enable) { + tvpm = TRUE; + } else { + ret = wldev_iovar_getbuf(dev, "phy_tempsense", &phy_temp, sizeof(phy_temp), + outbuf, outlen, NULL); + if (!ret) { + phy_temp = dtoh32(*(int*)outbuf); + sense = TRUE; + } + } + + if (tvpm) { + WL_MSG(dev->name,"temp=%3d, duty=%3d, pwrbko=%d, chains=%d\n", + status->temp, status->tx_dutycycle, status->tx_power_backoff, + status->num_active_chains); + } + else if (sense) { + WL_MSG(dev->name,"phy_temp=%3d\n", phy_temp); + } + +exit: + if (tvpm_req) + kfree(tvpm_req); +} + +static void +wl_phy_rssi_ant(struct net_device *dev, struct ether_addr *mac, + char *rssi_buf, int len) +{ + struct wl_if_info *cur_if = NULL; + char buf[WLC_IOCTL_SMLEN]; + wl_rssi_ant_t *rssi_ant_p; + int ret, bytes_written = 0, i; + scb_val_t scb_val; + + cur_if = wl_get_cur_if(dev); + if (!cur_if) + return; + + memset(buf, 0, sizeof(buf)); + ret = wldev_iovar_getbuf(dev, "phy_rssi_ant", + mac, mac ? ETHER_ADDR_LEN : 0, buf, sizeof(buf), NULL); + rssi_ant_p = (wl_rssi_ant_t *)buf; + rssi_ant_p->version = dtoh32(rssi_ant_p->version); + rssi_ant_p->count = dtoh32(rssi_ant_p->count); + if (ret < 0 || rssi_ant_p->count == 0) { + if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) { + wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0); rssi_ant_p->count = 1; rssi_ant_p->rssi_ant[0] = dtoh32(scb_val.val); } - for (i=0; icount && rssi_ant_p->rssi_ant[i]; i++) { - bytes_written += snprintf(rssi_buf+bytes_written, sizeof(rssi_buf), - "[%2d]", rssi_ant_p->rssi_ant[i]); + } + for (i=0; icount && rssi_ant_p->rssi_ant[i]; i++) { + bytes_written += snprintf(rssi_buf+bytes_written, len, + "[%2d]", rssi_ant_p->rssi_ant[i]); + } +} + +static void +wl_tput_dump(struct wl_apsta_params *apsta_params, + struct net_device *dev, wl_tput_info_t *tput_info) +{ + WL_MSG(dev->name, + "tx=%3d.%d%d%d Mbps, rx=%3d.%d%d%d Mbps, tput_sum=%3d.%d%d%d Mbps\n", + tput_info->tput_tx, (tput_info->tput_tx_kb/100)%10, + (tput_info->tput_tx_kb/10)%10, (tput_info->tput_tx_kb)%10, + tput_info->tput_rx, (tput_info->tput_rx_kb/100)%10, + (tput_info->tput_rx_kb/10)%10, (tput_info->tput_rx_kb)%10, + apsta_params->tput_sum, (apsta_params->tput_sum_kb/100)%10, + (apsta_params->tput_sum_kb/10)%10, (apsta_params->tput_sum_kb)%10); +} + +static void +wl_sta_info_dump(struct net_device *dev, struct ether_addr *mac) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + void *buf = apsta_params->ioctl_buf; + sta_info_v4_t *sta = NULL; + char rssi_buf[16]; + int ret; + s32 rate = 0; + + memset(rssi_buf, 0, sizeof(rssi_buf)); + wl_phy_rssi_ant(dev, mac, rssi_buf, sizeof(rssi_buf)); + ret = wldev_iovar_getbuf(dev, "sta_info", (const void*)mac, + ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL); + if (ret == 0) { + sta = (sta_info_v4_t *)buf; + } + if (sta == NULL || (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5 && + sta->ver != WL_STA_VER_6)) { + wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate)); + rate = dtoh32(rate); + WL_MSG(dev->name, + "mac=%pM, rssi=%s, tx_rate:%4d%2s\n", + mac, rssi_buf, rate/2, (rate & 1) ? ".5" : ""); + } else { + if (dtoh32(sta->rx_rate) != -1) { + WL_MSG(dev->name, + "mac=%pM, rssi=%s, tx_rate:%4d.%d, rx_rate:%4d.%d\n", + mac, rssi_buf, + dtoh32(sta->tx_rate)/1000, ((dtoh32(sta->tx_rate)/100)%10), + dtoh32(sta->rx_rate)/1000, ((dtoh32(sta->rx_rate)/100)%10)); + } else { + WL_MSG(dev->name, + "mac=%pM, rssi=%s, tx_rate:%4d.%d, rx_rate:%4d\n", + mac, rssi_buf, + dtoh32(sta->tx_rate)/1000, ((dtoh32(sta->tx_rate)/100)%10), + dtoh32(sta->rx_rate)); } + } +} + +static void +wl_cur_if_tput_dump(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) +{ +#ifdef WLDWDS + struct wl_dwds_info *dwds_if; + int i; +#endif /* WLDWDS */ + struct ether_addr bssid; + int ret = 0; + + if (!(android_msg_level & ANDROID_TPUT_LEVEL)) + return; + + wl_tput_dump(apsta_params, cur_if->dev, &cur_if->tput_info); + + if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) { wldev_ioctl(cur_if->dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0); - ret = wldev_iovar_getbuf(cur_if->dev, "sta_info", (const void*)&bssid, - ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL); - if (ret == 0) { - sta = (sta_info_v4_t *)buf; + if (ret != BCME_NOTASSOCIATED && memcmp(ðer_null, &bssid, ETHER_ADDR_LEN)) { + wl_sta_info_dump(cur_if->dev, &bssid); } } - else { - bytes_written += snprintf(rssi_buf+bytes_written, sizeof(rssi_buf), - "[ ][ ]"); - } - - if (sta == NULL || (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5)) { - WL_MSG(cur_if->dev->name, - "rssi=%s, tx=%3d.%d%d%d Mbps(rate:%4d%2s), rx=%3d.%d%d%d Mbps(rate: ), "\ - "tput_sum=%3d.%d%d%d Mbps\n", - rssi_buf, cur_if->tput_tx, (cur_if->tput_tx_kb/100)%10, - (cur_if->tput_tx_kb/10)%10, (cur_if->tput_tx_kb)%10, - rate/2, (rate & 1) ? ".5" : "", - cur_if->tput_rx, (cur_if->tput_rx_kb/100)%10, - (cur_if->tput_rx_kb/10)%10, (cur_if->tput_rx_kb)%10, - apsta_params->tput_sum, (apsta_params->tput_sum_kb/100)%10, - (apsta_params->tput_sum_kb/10)%10, (apsta_params->tput_sum_kb)%10); - } else { - WL_MSG(cur_if->dev->name, - "rssi=%s, tx=%3d.%d%d%d Mbps(rate:%4d%2s), rx=%3d.%d%d%d Mbps(rate:%4d.%d), "\ - "tput_sum=%3d.%d%d%d Mbps\n", - rssi_buf, cur_if->tput_tx, (cur_if->tput_tx_kb/100)%10, - (cur_if->tput_tx_kb/10)%10, (cur_if->tput_tx_kb)%10, - rate/2, (rate & 1) ? ".5" : "", - cur_if->tput_rx, (cur_if->tput_rx_kb/100)%10, - (cur_if->tput_rx_kb/10)%10, (cur_if->tput_rx_kb)%10, - dtoh32(sta->rx_rate)/1000, ((dtoh32(sta->rx_rate)/100)%10), - apsta_params->tput_sum, (apsta_params->tput_sum_kb/100)%10, - (apsta_params->tput_sum_kb/10)%10, (apsta_params->tput_sum_kb)%10); + else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE) { + int i, maxassoc = 0; + char mac_buf[MAX_NUM_OF_ASSOCLIST * + sizeof(struct ether_addr) + sizeof(uint)] = {0}; + struct maclist *assoc_maclist = (struct maclist *)mac_buf; + + assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST); + ret = wl_ext_ioctl(cur_if->dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), 0); + if (ret) + goto exit; + maxassoc = dtoh32(assoc_maclist->count); + for (i=0; idev, &assoc_maclist->ea[i]); + } +#ifdef WLDWDS + for (i=0; idwds_info[i]; + if (dwds_if->dev && cur_if->bssidx == dwds_if->bssidx) { + wl_tput_dump(apsta_params, dwds_if->dev, &dwds_if->tput_info); + } + } +#endif /* WLDWDS */ } exit: - if (buf) { - kfree(buf); - } + return; } static void -wl_tput_monitor(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) +wl_tput_monitor(struct dhd_pub *dhd, int ifidx, struct wl_tput_info *tput_info) { - struct dhd_pub *dhd = apsta_params->dhd; dhd_if_t *ifp = NULL; - ifp = dhd_get_ifp(dhd, cur_if->ifidx); + ifp = dhd_get_ifp(dhd, ifidx); + if (!ifp) + return; - if (cur_if->tput_ts.tv_sec == 0 && cur_if->tput_ts.tv_nsec == 0) { - osl_do_gettimeofday(&cur_if->tput_ts); - cur_if->last_tx = ifp->stats.tx_bytes; - cur_if->last_rx = ifp->stats.rx_bytes; + if (tput_info->tput_ts.tv_sec == 0 && tput_info->tput_ts.tv_nsec == 0) { + osl_do_gettimeofday(&tput_info->tput_ts); + tput_info->last_tx = ifp->stats.tx_bytes; + tput_info->last_rx = ifp->stats.rx_bytes; } else { struct osl_timespec cur_ts; uint32 diff_ms; osl_do_gettimeofday(&cur_ts); - diff_ms = osl_do_gettimediff(&cur_ts, &cur_if->tput_ts)/1000; - memcpy(&cur_if->tput_ts, &cur_ts, sizeof(struct osl_timespec)); - cur_if->tput_tx = (int32)(((ifp->stats.tx_bytes-cur_if->last_tx)/1024/1024)*8)*1000/diff_ms; - if (cur_if->tput_tx == 0) { - cur_if->tput_tx = (int32)((ifp->stats.tx_bytes-cur_if->last_tx)*8*1000/1024/1024)/diff_ms; - cur_if->tput_tx_kb = (int32)((ifp->stats.tx_bytes-cur_if->last_tx)*8*1000/1024)/diff_ms; - cur_if->tput_tx_kb = cur_if->tput_tx_kb % 1000; + diff_ms = osl_do_gettimediff(&cur_ts, &tput_info->tput_ts)/1000; + memcpy(&tput_info->tput_ts, &cur_ts, sizeof(struct osl_timespec)); + tput_info->tput_tx = (int32)(((ifp->stats.tx_bytes-tput_info->last_tx)/1024/1024)*8)*1000/diff_ms; + if (tput_info->tput_tx == 0) { + tput_info->tput_tx = (int32)((ifp->stats.tx_bytes-tput_info->last_tx)*8*1000/1024/1024)/diff_ms; + tput_info->tput_tx_kb = (int32)((ifp->stats.tx_bytes-tput_info->last_tx)*8*1000/1024)/diff_ms; + tput_info->tput_tx_kb = tput_info->tput_tx_kb % 1000; } else - cur_if->tput_tx_kb = 0; - cur_if->tput_rx = (int32)(((ifp->stats.rx_bytes-cur_if->last_rx)/1024/1024)*8)*1000/diff_ms; - if (cur_if->tput_rx == 0) { - cur_if->tput_rx = (int32)((ifp->stats.rx_bytes-cur_if->last_rx)*8*1000/1024/1024)/diff_ms; - cur_if->tput_rx_kb = (int32)((ifp->stats.rx_bytes-cur_if->last_rx)*8*1000/1024)/diff_ms; - cur_if->tput_rx_kb = cur_if->tput_rx_kb % 1000; + tput_info->tput_tx_kb = 0; + tput_info->tput_rx = (int32)(((ifp->stats.rx_bytes-tput_info->last_rx)/1024/1024)*8)*1000/diff_ms; + if (tput_info->tput_rx == 0) { + tput_info->tput_rx = (int32)((ifp->stats.rx_bytes-tput_info->last_rx)*8*1000/1024/1024)/diff_ms; + tput_info->tput_rx_kb = (int32)((ifp->stats.rx_bytes-tput_info->last_rx)*8*1000/1024)/diff_ms; + tput_info->tput_rx_kb = tput_info->tput_rx_kb % 1000; } else - cur_if->tput_rx_kb = 0; - cur_if->last_tx = ifp->stats.tx_bytes; - cur_if->last_rx = ifp->stats.rx_bytes; + tput_info->tput_rx_kb = 0; + tput_info->last_tx = ifp->stats.tx_bytes; + tput_info->last_rx = ifp->stats.rx_bytes; } } static void -wl_tput_monitor_handler(struct wl_apsta_params *apsta_params, - struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data) +wl_tput_monitor_handler(struct wl_if_info *cur_if, + const wl_event_msg_t *e, void *data) { - struct dhd_pub *dhd = apsta_params->dhd; + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + wl_tput_info_t *tput_info; struct wl_if_info *tmp_if; +#ifdef WLDWDS + struct wl_dwds_info *dwds_if; +#endif /* WLDWDS */ uint32 etype = ntoh32(e->event_type); uint32 status = ntoh32(e->status); uint32 reason = ntoh32(e->reason); uint16 flags = ntoh16(e->flags); uint timeout = dhd->conf->tput_monitor_ms; int32 tput_sum = 0, tput_sum_kb = 0; - bool monitor_if[MAX_IF_NUM] = {FALSE}; + bool monitor_if[MAX_IF_NUM] = {FALSE}, monitor = FALSE; int i; if (etype == WLC_E_RESERVED && reason == ISAM_RC_TPUT_MONITOR) { tput_sum = 0; for (i=0; iif_info[i]; - if (tmp_if->dev && tmp_if->ifmode == ISTA_MODE && - wl_ext_get_chan(apsta_params, tmp_if->dev)) { - wl_tput_monitor(apsta_params, tmp_if); + if (tmp_if->dev && + (tmp_if->ifmode == ISTA_MODE || tmp_if->ifmode == IGC_MODE) && + wl_ext_associated(tmp_if->dev)) { + wl_tput_monitor(dhd, tmp_if->ifidx, &tmp_if->tput_info); monitor_if[i] = TRUE; } - else if (tmp_if->dev && tmp_if->ifmode == IAP_MODE && + else if (tmp_if->dev && + (tmp_if->ifmode == IAP_MODE || tmp_if->ifmode == IGO_MODE) && wl_ext_assoclist_num(tmp_if->dev)) { - wl_tput_monitor(apsta_params, tmp_if); + wl_tput_monitor(dhd, tmp_if->ifidx, &tmp_if->tput_info); monitor_if[i] = TRUE; } - tput_sum += (tmp_if->tput_tx + tmp_if->tput_rx); - tput_sum_kb += (tmp_if->tput_tx_kb + tmp_if->tput_rx_kb); + if (monitor_if[i] == TRUE) { + tput_info = &tmp_if->tput_info; + tput_sum += (tput_info->tput_tx + tput_info->tput_rx); + tput_sum_kb += (tput_info->tput_tx_kb + tput_info->tput_rx_kb); + } + } +#ifdef WLDWDS + for (i=0; idwds_info[i]; + if (dwds_if->dev) { + wl_tput_monitor(dhd, dwds_if->ifidx, &dwds_if->tput_info); + tput_info = &dwds_if->tput_info; + tput_sum += (tput_info->tput_tx + tput_info->tput_rx); + tput_sum_kb += (tput_info->tput_tx_kb + tput_info->tput_rx_kb); + } } +#endif /* WLDWDS */ apsta_params->tput_sum = tput_sum + (tput_sum_kb/1000); apsta_params->tput_sum_kb = tput_sum_kb % 1000; for (i=0; iif_info[i]; - wl_tput_dump(apsta_params, tmp_if); - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout); + wl_cur_if_tput_dump(apsta_params, tmp_if); + monitor = TRUE; } } + if (monitor) { + wl_btc_dump(cur_if->dev); + wl_tvpm_dump(cur_if->dev); + wl_ampdu_dump(cur_if->dev); + wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout); + } #ifdef BCMSDIO if (apsta_params->tput_sum >= dhd->conf->doflow_tput_thresh && dhd_doflow) { dhd_doflow = FALSE; @@ -3881,57 +4776,44 @@ wl_tput_monitor_handler(struct wl_apsta_params *apsta_params, } #endif } - else if (cur_if->ifmode == ISTA_MODE) { + else if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) { if (etype == WLC_E_LINK) { if (flags & WLC_EVENT_MSG_LINK) { - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout); + wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout); } else if (!wl_ext_iapsta_other_if_enabled(cur_if->dev)) { - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0); + wl_timer_mod(dhd, &apsta_params->monitor_timer, 0); } } } - else if (cur_if->ifmode == IAP_MODE) { + else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE) { if ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) || (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && reason == WLC_E_REASON_INITIAL_ASSOC)) { - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout); + wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout); } else if ((etype == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && reason == WLC_E_REASON_DEAUTH)) { if (!wl_ext_iapsta_other_if_enabled(cur_if->dev)) { - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0); + wl_timer_mod(dhd, &apsta_params->monitor_timer, 0); } } else if ((etype == WLC_E_ASSOC_IND || etype == WLC_E_REASSOC_IND) && reason == DOT11_SC_SUCCESS) { - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, timeout); + wl_timer_mod(dhd, &apsta_params->monitor_timer, timeout); } } } #endif /* TPUT_MONITOR */ #ifdef ACS_MONITOR -static void -wl_ext_mod_timer_pending(timer_list_compat_t *timer, uint sec, uint msec) -{ - uint timeout = sec * 1000 + msec; - - if (timeout && !timer_pending(timer)) { - IAPSTA_TRACE("wlan", "timeout=%d\n", timeout); - mod_timer(timer, jiffies + msecs_to_jiffies(timeout)); - } -} - static bool wl_ext_max_prio_if(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) { struct wl_if_info *tmp_if; wl_prio_t max_prio; - uint16 target_chan; int i; if (apsta_params->vsdb) { - target_chan = cur_if->channel; goto exit; } @@ -3941,8 +4823,7 @@ wl_ext_max_prio_if(struct wl_apsta_params *apsta_params, tmp_if = &apsta_params->if_info[i]; if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) && tmp_if->prio > max_prio) { - target_chan = wl_ext_get_chan(apsta_params, tmp_if->dev); - if (target_chan) { + if (wl_ext_associated(tmp_if->dev)) { return TRUE; } } @@ -3955,7 +4836,7 @@ static void wl_ext_acs_scan(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) { if (apsta_params->acs & ACS_DRV_BIT) { - if (wl_ext_get_chan(apsta_params, cur_if->dev)) { + if (wl_ext_associated(cur_if->dev)) { int ret, cur_scan_time; cur_if->escan->autochannel = 1; cur_scan_time = wl_ext_set_scan_time(cur_if->dev, 80, @@ -3973,22 +4854,22 @@ wl_ext_acs_scan(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) static void wl_ext_acs(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if) { - uint cur_band; - uint16 cur_chan, acs_chan; + struct wl_chan_info chan_info; if (apsta_params->acs & ACS_DRV_BIT) { mutex_lock(&apsta_params->usr_sync); - cur_chan = wl_ext_get_chan(apsta_params, cur_if->dev); - if (cur_chan) { - cur_band = WL_GET_BAND(cur_chan); - if (cur_band == WLC_BAND_5G) - cur_if->channel = cur_if->escan->best_5g_ch; + memset(&chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(cur_if->dev, &chan_info); + if (chan_info.chan) { + if (chan_info.band == WLC_BAND_5G) + cur_if->chan_info.chan = cur_if->escan->best_5g_ch; else - cur_if->channel = cur_if->escan->best_2g_ch; - acs_chan = wl_ext_move_cur_channel(apsta_params, cur_if); - if (acs_chan != cur_chan) { - WL_MSG(cur_if->dev->name, "move channel %d => %d\n", - cur_chan, acs_chan); + cur_if->chan_info.chan = cur_if->escan->best_2g_ch; + wl_ext_move_cur_channel(apsta_params, cur_if); + if (!wl_ext_same_chan(&cur_if->chan_info, &chan_info)) { + WL_MSG(cur_if->dev->name, "move channel %s-%d => %s-%d\n", + WLCBAND2STR(chan_info.band), chan_info.chan, + WLCBAND2STR(cur_if->chan_info.band), cur_if->chan_info.chan); wl_ext_if_down(apsta_params, cur_if); wl_ext_move_other_channel(apsta_params, cur_if); wl_ext_if_up(apsta_params, cur_if, FALSE, 500); @@ -4015,7 +4896,7 @@ wl_acs_timer(unsigned long data) bzero(&msg, sizeof(wl_event_msg_t)); IAPSTA_TRACE(dev->name, "timer expired\n"); - msg.ifidx = hton32(dhd_net2idx(dhd->info, dev)); + msg.ifidx = dhd_net2idx(dhd->info, dev); msg.event_type = hton32(WLC_E_RESERVED); msg.reason = hton32(ISAM_RC_AP_ACS); wl_ext_event_send(dhd->event_params, &msg, NULL); @@ -4036,34 +4917,34 @@ wl_acs_handler(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data) (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && reason == WLC_E_REASON_INITIAL_ASSOC)) { // Link up - wl_ext_mod_timer_pending(&cur_if->acs_timer, acs_tmo, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000); } else if ((etype == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && reason == WLC_E_REASON_DEAUTH)) { // Link down - wl_ext_mod_timer(&cur_if->acs_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, 0); cur_if->escan->autochannel = 0; } else if ((etype == WLC_E_ASSOC_IND || etype == WLC_E_REASSOC_IND) && reason == DOT11_SC_SUCCESS) { // external STA connected - wl_ext_mod_timer(&cur_if->acs_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, 0); } else if (etype == WLC_E_DISASSOC_IND || etype == WLC_E_DEAUTH_IND || (etype == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) { // external STA disconnected - wl_ext_mod_timer_pending(&cur_if->acs_timer, acs_tmo, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000); } else if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_ACS) { // acs_tmo expired if (!wl_ext_assoclist_num(cur_if->dev) && !wl_ext_max_prio_if(apsta_params, cur_if)) { wl_ext_acs_scan(apsta_params, cur_if); - wl_ext_mod_timer(&cur_if->acs_timer, acs_tmo, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, acs_tmo*1000); } else { - wl_ext_mod_timer(&cur_if->acs_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, 0); } } else if (((etype == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) || @@ -4077,63 +4958,370 @@ wl_acs_handler(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data) !wl_ext_max_prio_if(apsta_params, cur_if)) { wl_ext_acs(apsta_params, cur_if); } else { - wl_ext_mod_timer(&cur_if->acs_timer, 0, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, 0); + } + } + } +} + +static void +wl_acs_detach(struct wl_if_info *cur_if) +{ + IAPSTA_TRACE(cur_if->dev->name, "Enter\n"); + wl_timer_deregister(cur_if->dev, &cur_if->acs_timer); + if (cur_if->escan) { + cur_if->escan = NULL; + } +} + +static void +wl_acs_attach(dhd_pub_t *dhd, struct wl_if_info *cur_if) +{ + IAPSTA_TRACE(cur_if->dev->name, "Enter\n"); + cur_if->escan = dhd->escan; + wl_timer_register(cur_if->dev, &cur_if->acs_timer, wl_acs_timer); +} +#endif /* ACS_MONITOR */ + +#ifdef RESTART_AP_WAR +static void +wl_ext_restart_ap_timeout(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct dhd_pub *dhd; + wl_event_msg_t msg; + + if (!dev) { + IAPSTA_ERROR("wlan", "dev is not ready\n"); + return; + } + + dhd = dhd_get_pub(dev); + + bzero(&msg, sizeof(wl_event_msg_t)); + IAPSTA_TRACE(dev->name, "timer expired\n"); + + msg.ifidx = dhd_net2idx(dhd->info, dev); + msg.event_type = hton32(WLC_E_RESERVED); + msg.reason = hton32(ISAM_RC_AP_RESTART); + wl_ext_event_send(dhd->event_params, &msg, NULL); +} + +static void +wl_ext_restart_ap_handler(struct wl_if_info *cur_if, + const wl_event_msg_t *e, void *data) +{ + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + uint32 etype = ntoh32(e->event_type); + uint32 reason = ntoh32(e->reason); + + if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_RESTART) { + if (!wl_get_isam_status(cur_if, AP_CREATED)) { + if (!wl_ext_associated(cur_if->dev)) { + WL_MSG(cur_if->ifname, "restart AP\n"); + wl_ext_if_down(apsta_params, cur_if); + wl_ext_if_up(apsta_params, cur_if, FALSE, 1); + wl_timer_mod(dhd, &cur_if->restart_ap_timer, AP_RESTART_TIMEOUT); + } else { + WL_MSG(cur_if->ifname, "skip restart AP\n"); } } } + return; +} +#endif /* RESTART_AP_WAR */ + +#if defined(RESET_AP_WAR) || defined(RXF0OVFL_REINIT_WAR) +static int +wl_ext_counters_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len) +{ + struct wl_if_info *cur_if = ctx; + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + int res = BCME_OK; + + switch (type) { + case WL_CNT_XTLV_CNTV_LE10_UCODE: { + wl_cnt_v_le10_mcst_t *cnt = (wl_cnt_v_le10_mcst_t *)data; + if (len != sizeof(wl_cnt_v_le10_mcst_t)) { + printf("type %d: cnt struct length mismatch! %d != %d\n", + type, len, (int)sizeof(wl_cnt_v_le10_mcst_t)); + } +#ifdef RESET_AP_WAR + if (apsta_params->war_reason == ISAM_RC_AP_RESET) + cur_if->txbcnfrm = dtoh32(cnt->txbcnfrm); +#endif /* RESET_AP_WAR */ +#ifdef RXF0OVFL_REINIT_WAR + if (apsta_params->war_reason == ISAM_RC_RXF0OVFL_REINIT) { + apsta_params->rxbeaconmbss = dtoh32(cnt->rxbeaconmbss); + apsta_params->rxf0ovfl = dtoh32(cnt->rxf0ovfl); + } +#endif /* RXF0OVFL_REINIT_WAR */ + break; + } + case WL_CNT_XTLV_GE40_UCODE_V1: + { + wl_cnt_ge40mcst_v1_t *cnt = (wl_cnt_ge40mcst_v1_t *)data; + if (len != sizeof(wl_cnt_ge40mcst_v1_t)) { + IAPSTA_ERROR(cur_if->ifname, + "type 0x%x, cnt struct length mismatch! %d != %d\n", + type, len, (int)sizeof(wl_cnt_ge40mcst_v1_t)); + } +#ifdef RESET_AP_WAR + if (apsta_params->war_reason == ISAM_RC_AP_RESET) + cur_if->txbcnfrm = dtoh32(cnt->txbcnfrm); +#endif /* RESET_AP_WAR */ +#ifdef RXF0OVFL_REINIT_WAR + if (apsta_params->war_reason == ISAM_RC_RXF0OVFL_REINIT) { + apsta_params->rxbeaconmbss = dtoh32(cnt->rxbeaconmbss); + apsta_params->rxf0ovfl = dtoh32(cnt->rxf0ovfl); + } +#endif /* RXF0OVFL_REINIT_WAR */ + break; + } + case WL_CNT_XTLV_GE80_UCODE_V1: + { + wl_cnt_ge80mcst_v1_t *cnt = (wl_cnt_ge80mcst_v1_t *)data; + if (len != sizeof(wl_cnt_ge80mcst_v1_t)) { + IAPSTA_ERROR(cur_if->ifname, + "type 0x%x, cnt struct length mismatch! %d != %d\n", + type, len, (int)sizeof(wl_cnt_ge80mcst_v1_t)); + } +#ifdef RESET_AP_WAR + if (apsta_params->war_reason == ISAM_RC_AP_RESET) + cur_if->txbcnfrm = dtoh32(cnt->txbcnfrm); +#endif /* RESET_AP_WAR */ +#ifdef RXF0OVFL_REINIT_WAR + if (apsta_params->war_reason == ISAM_RC_RXF0OVFL_REINIT) { + apsta_params->rxbeaconmbss = dtoh32(cnt->rxbeaconmbss); + apsta_params->rxf0ovfl = dtoh32(cnt->rxf0ovfl); + } +#endif /* RXF0OVFL_REINIT_WAR */ + break; + } + default: + break; + } + return res; +} + +static int +wl_ext_counters_update(struct wl_if_info *cur_if, int war_reason) +{ + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + char *iovar_buf = apsta_params->ioctl_buf; + uint32 corerev = 0; + wl_cnt_info_t *cntinfo; + uint16 ver; + int ret = 0; + + ret = wldev_iovar_getbuf(cur_if->dev, "counters", NULL, 0, + iovar_buf, WLC_IOCTL_MEDLEN, NULL); + if (unlikely(ret)) { + IAPSTA_ERROR(cur_if->ifname, + "counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)); + goto exit; + } + cntinfo = (wl_cnt_info_t *)iovar_buf; + cntinfo->version = dtoh16(cntinfo->version); + cntinfo->datalen = dtoh16(cntinfo->datalen); + ver = cntinfo->version; + CHK_CNTBUF_DATALEN(iovar_buf, WLC_IOCTL_MEDLEN); + if (ver > WL_CNT_VERSION_XTLV) { + IAPSTA_ERROR(cur_if->ifname, + "Incorrect version of counters struct: expected %d; got %d\n", + WL_CNT_VERSION_XTLV, ver); + goto exit; + } + + if (ver == WL_CNT_VERSION_11) { + wlc_rev_info_t revinfo; + memset(&revinfo, 0, sizeof(revinfo)); + ret = wl_ext_ioctl(cur_if->dev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), 0); + if (ret) { + IAPSTA_ERROR(cur_if->ifname, "WLC_GET_REVINFO failed %d\n", ret); + goto exit; + } + corerev = dtoh32(revinfo.corerev); + } + ret = wl_cntbuf_to_xtlv_format(NULL, cntinfo, WLC_IOCTL_MEDLEN, corerev); + if (ret) { + IAPSTA_ERROR(cur_if->ifname, "wl_cntbuf_to_xtlv_format failed %d\n", ret); + goto exit; + } + + apsta_params->war_reason = war_reason; + if ((ret = bcm_unpack_xtlv_buf(cur_if, cntinfo->data, cntinfo->datalen, + BCM_XTLV_OPTION_ALIGN32, wl_ext_counters_cbfn))) { + IAPSTA_ERROR(cur_if->ifname, "bcm_unpack_xtlv_buf failed %d\n", ret); + goto exit; + } + +exit: + return ret; +} +#endif /* RESET_AP_WAR | RXF0OVFL_REINIT_WAR */ + +#ifdef RESET_AP_WAR +static void +wl_ext_reset_ap_timeout(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct dhd_pub *dhd; + wl_event_msg_t msg; + + if (!dev) { + IAPSTA_ERROR("wlan", "dev is not ready\n"); + return; + } + + dhd = dhd_get_pub(dev); + + bzero(&msg, sizeof(wl_event_msg_t)); + IAPSTA_TRACE(dev->name, "timer expired\n"); + + msg.ifidx = dhd_net2idx(dhd->info, dev); + msg.event_type = hton32(WLC_E_RESERVED); + msg.reason = hton32(ISAM_RC_AP_RESET); + wl_ext_event_send(dhd->event_params, &msg, NULL); +} + +static void +wl_ext_reset_ap_handler(struct wl_if_info *cur_if, + const wl_event_msg_t *e, void *data) +{ + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + uint32 etype = ntoh32(e->event_type); + uint32 status = ntoh32(e->status); + uint32 reason = ntoh32(e->reason); + uint32 txbcnfrm; + int ret = 0; + + if (wl_get_isam_status(cur_if, AP_CREATED)) { + if ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) || + (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && + reason == WLC_E_REASON_INITIAL_ASSOC)) { + // Link up + wl_ext_counters_update(cur_if, ISAM_RC_AP_RESET); + wl_timer_mod(dhd, &cur_if->reset_ap_timer, AP_TXBCNFRM_TIMEOUT); + } + else if (etype == WLC_E_RESERVED && reason == ISAM_RC_AP_RESET) { + txbcnfrm = cur_if->txbcnfrm; + ret = wl_ext_counters_update(cur_if, ISAM_RC_AP_RESET); + if (ret) + goto done; + if ((cur_if->txbcnfrm != 0) && (txbcnfrm == cur_if->txbcnfrm)) { + WL_MSG(cur_if->ifname, "reset AP mode\n"); + wl_ext_if_down(apsta_params, cur_if); + wl_ext_if_up(apsta_params, cur_if, FALSE, 500); + } +done: + wl_timer_mod(dhd, &cur_if->reset_ap_timer, AP_TXBCNFRM_TIMEOUT); + } + } + return; +} +#endif /* RESET_AP_WAR */ + +#ifdef RXF0OVFL_REINIT_WAR +static void +wl_ext_rxf0ovfl_reinit_timeout(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct dhd_pub *dhd; + wl_event_msg_t msg; + + if (!dev) { + IAPSTA_ERROR("wlan", "dev is not ready\n"); + return; + } + + dhd = dhd_get_pub(dev); + + bzero(&msg, sizeof(wl_event_msg_t)); + IAPSTA_TRACE(dev->name, "timer expired\n"); + + msg.ifidx = dhd_net2idx(dhd->info, dev); + msg.event_type = hton32(WLC_E_RESERVED); + msg.reason = hton32(ISAM_RC_RXF0OVFL_REINIT); + wl_ext_event_send(dhd->event_params, &msg, NULL); } static void -wl_acs_detach(struct wl_if_info *cur_if) +wl_ext_rxf0ovfl_reinit_handler(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data) { - IAPSTA_TRACE(cur_if->dev->name, "Enter\n"); - del_timer_sync(&cur_if->acs_timer); - if (cur_if->escan) { - cur_if->escan = NULL; + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + uint32 etype = ntoh32(e->event_type); + uint32 reason = ntoh32(e->reason); + uint32 status = ntoh32(e->status); + uint16 flags = ntoh16(e->flags); + uint32 rxbeaconmbss, rxbeaconmbss_diff = 0, rxf0ovfl, rxf0ovfl_diff = 0; + int ret = 0; + bool reinit = FALSE; + + if ((cur_if->ifmode == ISTA_MODE) && + (etype == WLC_E_LINK) && (flags & WLC_EVENT_MSG_LINK)) { + // Link up + wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT); + wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT); + } + else if ((cur_if->ifmode == IAP_MODE) && + ((etype == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) || + (etype == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS && + reason == WLC_E_REASON_INITIAL_ASSOC))) { + // Link up + wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT); + wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT); + } + else if ((etype == WLC_E_RESERVED) && (reason == ISAM_RC_RXF0OVFL_REINIT) && + (wl_ext_iapsta_other_if_enabled(cur_if->dev))) { + rxbeaconmbss = apsta_params->rxbeaconmbss; + rxf0ovfl = apsta_params->rxf0ovfl; + wl_ext_counters_update(cur_if, ISAM_RC_RXF0OVFL_REINIT); + if (ret) + goto done; + rxf0ovfl_diff = apsta_params->rxf0ovfl - rxf0ovfl; + rxbeaconmbss_diff = apsta_params->rxbeaconmbss - rxbeaconmbss; + if (rxf0ovfl_diff > 0) { + IAPSTA_INFO(cur_if->ifname, + "rxf0ovfl diff = %d, rxbeaconmbss diff = %d\n", + rxf0ovfl_diff, rxbeaconmbss_diff); + } + if (wl_ext_if_enabled(apsta_params, ISTA_MODE)) { + if (rxbeaconmbss_diff < 5 && rxf0ovfl_diff > RXF0OVFL_THRESHOLD) + reinit = TRUE; + } + else if (wl_ext_if_enabled(apsta_params, IAP_MODE)) { + if (rxf0ovfl_diff > RXF0OVFL_THRESHOLD) + reinit = TRUE; + } + if (reinit) { + WL_MSG(cur_if->ifname, "wl reinit\n"); + wl_ext_ioctl(cur_if->dev, WLC_INIT, NULL, 0, 1); + } +done: + wl_timer_mod(dhd, &apsta_params->rxf0ovfl_timer, RXF0OVFL_POLLING_TIMEOUT); } -} -static void -wl_acs_attach(dhd_pub_t *dhd, struct wl_if_info *cur_if) -{ - IAPSTA_TRACE(cur_if->dev->name, "Enter\n"); - cur_if->escan = dhd->escan; - init_timer_compat(&cur_if->acs_timer, wl_acs_timer, cur_if->dev); + return; } -#endif /* ACS_MONITOR */ +#endif /* RXF0OVFL_REINIT_WAR */ void -wl_ext_iapsta_event(struct net_device *dev, void *argu, +wl_ext_iapsta_link(struct wl_if_info *cur_if, const wl_event_msg_t *e, void *data) { - struct wl_apsta_params *apsta_params = (struct wl_apsta_params *)argu; - struct wl_if_info *cur_if = NULL; -#if defined(WLMESH) && defined(WL_ESCAN) - struct wl_if_info *tmp_if = NULL; - struct wl_if_info *mesh_if = NULL; - int i; -#endif /* WLMESH && WL_ESCAN */ + struct dhd_pub *dhd = dhd_get_pub(cur_if->dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; uint32 event_type = ntoh32(e->event_type); uint32 status = ntoh32(e->status); uint32 reason = ntoh32(e->reason); uint16 flags = ntoh16(e->flags); - cur_if = wl_get_cur_if(dev); - -#if defined(WLMESH) && defined(WL_ESCAN) - for (i=0; iif_info[i]; - if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE) { - mesh_if = tmp_if; - break; - } - } -#endif /* WLMESH && WL_ESCAN */ - if (!cur_if || !cur_if->dev) { - IAPSTA_DBG(dev->name, "ifidx %d is not ready\n", e->ifidx); - return; - } - if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) { if (event_type == WLC_E_LINK) { if (!(flags & WLC_EVENT_MSG_LINK)) { @@ -4145,10 +5333,6 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, wl_ext_net_setcarrier(cur_if, FALSE, FALSE); #endif /* SET_CARRIER */ wl_clr_isam_status(cur_if, STA_CONNECTED); -#if defined(WLMESH) && defined(WL_ESCAN) - if (mesh_if && apsta_params->macs) - wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE); -#endif /* WLMESH && WL_ESCAN */ } else { WL_MSG(cur_if->ifname, "[%c] Link UP with %pM\n", cur_if->prefix, &e->addr); @@ -4156,15 +5340,11 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, wl_ext_net_setcarrier(cur_if, TRUE, FALSE); #endif /* SET_CARRIER */ wl_set_isam_status(cur_if, STA_CONNECTED); -#if defined(WLMESH) && defined(WL_ESCAN) - if (mesh_if && apsta_params->macs) - wl_mesh_update_master_info(apsta_params, mesh_if); -#endif /* WLMESH && WL_ESCAN */ } wl_clr_isam_status(cur_if, STA_CONNECTING); wake_up_interruptible(&apsta_params->netif_change_event); #ifdef PROPTX_MAXCOUNT - wl_ext_update_wlfc_maxcount(apsta_params->dhd); + wl_ext_update_wlfc_maxcount(dhd); #endif /* PROPTX_MAXCOUNT */ } else if (event_type == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) { @@ -4173,12 +5353,8 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, event_type, reason, status); wl_clr_isam_status(cur_if, STA_CONNECTING); wake_up_interruptible(&apsta_params->netif_change_event); -#if defined(WLMESH) && defined(WL_ESCAN) - if (mesh_if && apsta_params->macs) - wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE); -#endif /* WLMESH && WL_ESCAN */ #ifdef PROPTX_MAXCOUNT - wl_ext_update_wlfc_maxcount(apsta_params->dhd); + wl_ext_update_wlfc_maxcount(dhd); #endif /* PROPTX_MAXCOUNT */ } else if (event_type == WLC_E_DEAUTH || event_type == WLC_E_DEAUTH_IND || @@ -4189,10 +5365,6 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, #ifdef SET_CARRIER wl_ext_net_setcarrier(cur_if, FALSE, FALSE); #endif /* SET_CARRIER */ -#if defined(WLMESH) && defined(WL_ESCAN) - if (mesh_if && apsta_params->macs) - wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE); -#endif /* WLMESH && WL_ESCAN */ } } else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE || @@ -4214,7 +5386,7 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, wl_ext_net_setcarrier(cur_if, TRUE, FALSE); #endif /* SET_CARRIER */ #ifdef PROPTX_MAXCOUNT - wl_ext_update_wlfc_maxcount(apsta_params->dhd); + wl_ext_update_wlfc_maxcount(dhd); #endif /* PROPTX_MAXCOUNT */ } else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) || @@ -4227,7 +5399,7 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, wl_ext_net_setcarrier(cur_if, FALSE, FALSE); #endif /* SET_CARRIER */ #ifdef PROPTX_MAXCOUNT - wl_ext_update_wlfc_maxcount(apsta_params->dhd); + wl_ext_update_wlfc_maxcount(dhd); #endif /* PROPTX_MAXCOUNT */ } else if ((event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) && @@ -4245,17 +5417,34 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, event_type, reason); wl_ext_isam_status(cur_if->dev, NULL, 0); } -#if defined(WLMESH) && defined(WL_ESCAN) - if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) - wl_mesh_event_handler(apsta_params, cur_if, e, data); -#endif /* WLMESH && WL_ESCAN */ + } +} + +void +wl_ext_iapsta_event(struct net_device *dev, void *argu, + const wl_event_msg_t *e, void *data) +{ +#ifdef ACS_MONITOR + struct wl_apsta_params *apsta_params = (struct wl_apsta_params *)argu; +#endif /* ACS_MONITOR */ + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_if_info *cur_if = NULL; + + cur_if = wl_get_cur_if(dev); + if (!cur_if || !cur_if->dev) { + IAPSTA_DBG(dev->name, "ifidx %d is not ready\n", e->ifidx); + return; } + wl_ext_iapsta_link(cur_if, e, data); #ifdef TPUT_MONITOR - if (apsta_params->dhd->conf->tput_monitor_ms) - wl_tput_monitor_handler(apsta_params, cur_if, e, data); + if (dhd->conf->tput_monitor_ms) + wl_tput_monitor_handler(cur_if, e, data); #endif /* TPUT_MONITOR */ +#if defined(WLMESH) && defined(WL_ESCAN) + wl_mesh_event_handler(cur_if, e, data); +#endif /* WLMESH && WL_ESCAN */ #ifdef ACS_MONITOR if ((apsta_params->acs & ACS_DRV_BIT) && apsta_params->acs_tmo) wl_acs_handler(cur_if, e, data); @@ -4263,6 +5452,18 @@ wl_ext_iapsta_event(struct net_device *dev, void *argu, #ifdef EAPOL_RESEND wl_resend_eapol_handler(cur_if, e, data); #endif /* EAPOL_RESEND */ +#ifdef KEY_INSTALL_CHECK + wl_ext_key_install_handler(cur_if, e, data); +#endif /* KEY_INSTALL_CHECK */ +#ifdef RESTART_AP_WAR + wl_ext_restart_ap_handler(cur_if, e, data); +#endif /* RESTART_AP_WAR */ +#ifdef RESET_AP_WAR + wl_ext_reset_ap_handler(cur_if, e, data); +#endif /* RESET_AP_WAR */ +#ifdef RXF0OVFL_REINIT_WAR + wl_ext_rxf0ovfl_reinit_handler(cur_if, e, data); +#endif /* RXF0OVFL_REINIT_WAR */ return; } @@ -4288,6 +5489,7 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next) {" bgnmode ", NULL, NULL}, {" hidden ", NULL, NULL}, {" maxassoc ", NULL, NULL}, + {" band ", NULL, NULL}, {" chan ", NULL, NULL}, {" amode ", NULL, NULL}, {" emode ", NULL, NULL}, @@ -4402,8 +5604,23 @@ wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next) } } else if (!strcmp(row->name, " maxassoc ")) { cur_if->maxassoc = (int)simple_strtol(pick_tmp, NULL, 10); + } else if (!strcmp(row->name, " band ")) { + if (!strcmp(pick_tmp, "2g")) + cur_if->amode = WLC_BAND_2G; + else if (!strcmp(pick_tmp, "5g")) + cur_if->amode = WLC_BAND_5G; +#ifdef WL_6G_BAND + else if (!strcmp(pick_tmp, "6g")) + cur_if->amode = WLC_BAND_6G; +#endif /* WL_6G_BAND */ + else { + IAPSTA_ERROR(cur_if->dev->name, "band [2g|5g|6g]\n"); + return -1; + } } else if (!strcmp(row->name, " chan ")) { - cur_if->channel = (int)simple_strtol(pick_tmp, NULL, 10); + cur_if->chan_info.chan = (int)simple_strtol(pick_tmp, NULL, 10); + if (!cur_if->chan_info.band) + cur_if->chan_info.band = WL_GET_BAND(cur_if->chan_info.chan); } else if (!strcmp(row->name, " amode ")) { if (!strcmp(pick_tmp, "open")) cur_if->amode = AUTH_OPEN; @@ -4468,14 +5685,14 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para if (i >= 1 && !strlen(cur_if->ifname)) snprintf(cur_if->ifname, IFNAMSIZ, "wlan%d", i); if (cur_if->ifmode == ISTA_MODE) { - cur_if->channel = 0; + wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 0); cur_if->maxassoc = -1; cur_if->prio = PRIO_STA; cur_if->vsdb = TRUE; cur_if->prefix = 'S'; snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta"); } else if (cur_if->ifmode == IAP_MODE) { - cur_if->channel = 1; + wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1); cur_if->maxassoc = -1; cur_if->prio = PRIO_AP; cur_if->vsdb = FALSE; @@ -4483,16 +5700,12 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap"); #ifdef WLMESH } else if (cur_if->ifmode == IMESH_MODE) { - cur_if->channel = 1; + wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1); cur_if->maxassoc = -1; cur_if->prio = PRIO_MESH; cur_if->vsdb = FALSE; cur_if->prefix = 'M'; snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh"); -#ifdef WL_ESCAN - if (i == 0 && apsta_params->macs) - wl_mesh_escan_attach(dhd, cur_if); -#endif /* WL_ESCAN */ #endif /* WLMESH */ } } @@ -4600,7 +5813,6 @@ wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_para } #endif /* WLMESH */ - wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver); apsta_params->init = TRUE; WL_MSG(dev->name, "apstamode=%d\n", apstamode); @@ -4721,7 +5933,7 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock struct wl_apsta_params *apsta_params = dhd->iapsta_params; apstamode_t apstamode = apsta_params->apstamode; struct wl_if_info *cur_if = NULL, *tmp_if = NULL; - uint16 cur_chan; + struct wl_chan_info chan_info; struct wl_conn_info conn_info; u32 timeout; @@ -4753,13 +5965,11 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock if (wl_ext_master_if(cur_if) && apsta_params->acs) { uint16 chan_2g, chan_5g; - uint auto_band; - auto_band = WL_GET_BAND(cur_if->channel); wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE); - if ((chan_2g && auto_band == WLC_BAND_2G) || - (chan_5g && auto_band == WLC_BAND_5G)) { - cur_if->channel = wl_ext_autochannel(cur_if->dev, apsta_params->acs, - auto_band); + if ((chan_2g && cur_if->chan_info.band == WLC_BAND_2G) || + (chan_5g && cur_if->chan_info.band == WLC_BAND_5G)) { + cur_if->chan_info.chan = wl_ext_autochannel(cur_if->dev, apsta_params->acs, + cur_if->chan_info.band); } else { IAPSTA_ERROR(ifname, "invalid channel\n"); ret = -1; @@ -4769,16 +5979,17 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock wl_ext_move_cur_channel(apsta_params, cur_if); - if (wl_ext_master_if(cur_if) && !cur_if->channel) { + if (wl_ext_master_if(cur_if) && !cur_if->chan_info.chan) { IAPSTA_ERROR(ifname, "skip channel 0\n"); ret = -1; goto exit; } - cur_chan = wl_ext_get_chan(apsta_params, cur_if->dev); - if (cur_chan) { + memset(&chan_info, 0, sizeof(struct wl_chan_info)); + wl_ext_get_chan(cur_if->dev, &chan_info); + if (chan_info.chan) { IAPSTA_INFO(cur_if->ifname, "Associated\n"); - if (cur_chan != cur_if->channel) { + if (!wl_ext_same_chan(&cur_if->chan_info, &chan_info)) { wl_ext_trigger_csa(apsta_params, cur_if); } goto exit; @@ -4811,21 +6022,20 @@ wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up, bool lock if (wl_ext_master_if(cur_if)) { wl_ext_set_bgnmode(cur_if); - if (!cur_if->channel) { - cur_if->channel = 1; + if (!cur_if->chan_info.chan) { + wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1); } - ret = wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver, - cur_if->channel, &fw_chspec); + ret = wl_ext_set_chanspec(cur_if->dev, &cur_if->chan_info, &fw_chspec); if (ret) goto exit; } wl_ext_set_amode(cur_if); - wl_ext_set_emode(apsta_params, cur_if); + wl_ext_set_emode(cur_if); if (cur_if->ifmode == ISTA_MODE) { conn_info.bssidx = cur_if->bssidx; - conn_info.channel = cur_if->channel; + conn_info.channel = cur_if->chan_info.chan; memcpy(conn_info.ssid.SSID, cur_if->ssid, strlen(cur_if->ssid)); conn_info.ssid.SSID_len = strlen(cur_if->ssid); memcpy(&conn_info.bssid, &cur_if->bssid, ETHER_ADDR_LEN); @@ -4949,22 +6159,67 @@ exit: } int -wl_ext_isam_status(struct net_device *dev, char *command, int total_len) +wl_ext_isam_dev_status(struct net_device *dev, ifmode_t ifmode, char prefix, + char *dump_buf, int dump_len) { - struct dhd_pub *dhd = dhd_get_pub(dev); - struct wl_apsta_params *apsta_params = dhd->iapsta_params; - int i; - struct wl_if_info *tmp_if; - uint16 chan = 0; + struct wl_chan_info chan_info; wlc_ssid_t ssid = { 0, {0} }; struct ether_addr bssid; scb_val_t scb_val; char sec[64]; u32 chanspec = 0; - char *dump_buf = NULL; - int dump_len = WLC_IOCTL_MEDLEN; int dump_written = 0; + if (dev) { + memset(&ssid, 0, sizeof(ssid)); + memset(&bssid, 0, sizeof(bssid)); + memset(&scb_val, 0, sizeof(scb_val)); + memset(&chan_info, 0, sizeof(struct wl_chan_info)); + if (wl_ext_associated(dev)) { + wl_ext_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0); + wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0); + wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0); + chanspec = wl_ext_get_chanspec(dev, &chan_info); + wl_ext_get_sec(dev, ifmode, sec, sizeof(sec), FALSE); + dump_written += snprintf(dump_buf+dump_written, dump_len, + "\n" DHD_LOG_PREFIXS "[%s-%c]: bssid=%pM, chan=%s-%-3d(0x%x %sMHz), " + "rssi=%3d, sec=%-20s, SSID=\"%s\"", + dev->name, prefix, &bssid, + WLCBAND2STR(chan_info.band), chan_info.chan, chanspec, + CHSPEC_IS20(chanspec)?"20": + CHSPEC_IS40(chanspec)?"40": + CHSPEC_IS80(chanspec)?"80":"160", + dtoh32(scb_val.val), sec, ssid.SSID); + if (ifmode == IAP_MODE) { + dump_written += wl_ext_assoclist(dev, NULL, + dump_buf+dump_written, dump_len-dump_written); + } +#ifdef WLMESH + else if (ifmode == IMESH_MODE) { + dump_written += snprintf(dump_buf+dump_written, dump_len, "\n"); + dump_written += wl_ext_mesh_peer_status(dev, NULL, + dump_buf+dump_written, dump_len-dump_written); + } +#endif /* WLMESH */ + } else { + dump_written += snprintf(dump_buf+dump_written, dump_len, + "\n" DHD_LOG_PREFIXS "[%s-%c]:", dev->name, prefix); + } + } + + return dump_written; +} + +int +wl_ext_isam_status(struct net_device *dev, char *command, int total_len) +{ + struct dhd_pub *dhd = dhd_get_pub(dev); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_if_info *cur_if = NULL; + char *dump_buf = NULL; + int dump_len = WLC_IOCTL_MEDLEN, dump_written = 0; + int i; + if (command || android_msg_level & ANDROID_INFO_LEVEL) { if (command) { dump_buf = command; @@ -4976,48 +6231,28 @@ wl_ext_isam_status(struct net_device *dev, char *command, int total_len) dump_len); return -1; } + memset(dump_buf, 0, dump_len); } dump_written += snprintf(dump_buf+dump_written, dump_len, "apstamode=%d", apsta_params->apstamode); for (i=0; iif_info[i]; - if (tmp_if->dev) { - chan = wl_ext_get_chan(apsta_params, tmp_if->dev); - if (chan) { - wl_ext_ioctl(tmp_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0); - wldev_ioctl(tmp_if->dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0); - wldev_ioctl(tmp_if->dev, WLC_GET_RSSI, &scb_val, - sizeof(scb_val_t), 0); - chanspec = wl_ext_get_chanspec(apsta_params, tmp_if->dev); - wl_ext_get_sec(tmp_if->dev, tmp_if->ifmode, sec, sizeof(sec), FALSE); - dump_written += snprintf(dump_buf+dump_written, dump_len, - "\n" DHD_LOG_PREFIXS "[%s-%c]: bssid=%pM, chan=%3d(0x%x %sMHz), " - "rssi=%3d, sec=%-15s, SSID=\"%s\"", - tmp_if->ifname, tmp_if->prefix, &bssid, chan, chanspec, - CHSPEC_IS20(chanspec)?"20": - CHSPEC_IS40(chanspec)?"40": - CHSPEC_IS80(chanspec)?"80":"160", - dtoh32(scb_val.val), sec, ssid.SSID); - if (tmp_if->ifmode == IAP_MODE) { - dump_written += snprintf(dump_buf+dump_written, dump_len, "\n"); - dump_written += wl_ext_assoclist(tmp_if->dev, NULL, - dump_buf+dump_written, dump_len-dump_written); - } -#ifdef WLMESH - else if (tmp_if->ifmode == IMESH_MODE) { - dump_written += snprintf(dump_buf+dump_written, dump_len, "\n"); - dump_written += wl_ext_mesh_peer_status(tmp_if->dev, NULL, + cur_if = &apsta_params->if_info[i]; + if (cur_if->dev) { + dump_written += wl_ext_isam_dev_status(cur_if->dev, + cur_if->ifmode, cur_if->prefix, + dump_buf+dump_written, dump_len-dump_written); + } +#ifdef WLDWDS + if (cur_if->ifmode == IAP_MODE) { + for (i=0; idwds_info[i].dev) { + dump_written += wl_ext_isam_dev_status(apsta_params->dwds_info[i].dev, + IAP_MODE, 'W', dump_buf+dump_written, dump_len-dump_written); } -#endif /* WLMESH */ - } else { - dump_written += snprintf(dump_buf+dump_written, dump_len, - "\n" DHD_LOG_PREFIXS "[%s-%c]:", tmp_if->ifname, tmp_if->prefix); } } +#endif /* WLDWDS */ } IAPSTA_INFO(dev->name, "%s\n", dump_buf); } @@ -5065,7 +6300,7 @@ wl_ext_isam_param(struct net_device *dev, char *command, int total_len) if (apsta_params->acs_tmo != acs_tmo) { apsta_params->acs_tmo = acs_tmo; WL_MSG(dev->name, "acs_timer reset to %d\n", acs_tmo); - wl_ext_mod_timer(&cur_if->acs_timer, acs_tmo, 0); + wl_timer_mod(dhd, &cur_if->acs_timer, 0); } ret = 0; } else { @@ -5382,7 +6617,6 @@ wl_ext_iapsta_alive_postinit(struct net_device *dev) } // fix me: how to check it's ISTAAP_MODE or IDUALAP_MODE? - wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver); WL_MSG(dev->name, "apstamode=%d\n", apsta_params->apstamode); for (i=0; iifname)) strcpy(cur_if->ifname, "wlan2"); if (cur_if->ifmode == ISTA_MODE) { - cur_if->channel = 0; + wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 0); cur_if->maxassoc = -1; wl_set_isam_status(cur_if, IF_READY); cur_if->prio = PRIO_STA; @@ -5401,7 +6635,7 @@ wl_ext_iapsta_alive_postinit(struct net_device *dev) snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta"); } else if (cur_if->ifmode == IAP_MODE) { - cur_if->channel = 1; + wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1); cur_if->maxassoc = -1; wl_set_isam_status(cur_if, IF_READY); cur_if->prio = PRIO_AP; @@ -5411,7 +6645,7 @@ wl_ext_iapsta_alive_postinit(struct net_device *dev) } #ifdef WLMESH else if (cur_if->ifmode == IMESH_MODE) { - cur_if->channel = 1; + wl_ext_set_chan_info(cur_if, WLC_BAND_2G, 1); cur_if->maxassoc = -1; wl_set_isam_status(cur_if, IF_READY); cur_if->prio = PRIO_MESH; @@ -5469,6 +6703,10 @@ wl_ext_iapsta_postinit(struct net_device *net, struct wl_if_info *cur_if) if (dhd->conf->fw_type == FW_TYPE_MESH) { apsta_params->csa |= (CSA_FW_BIT | CSA_DRV_BIT); } + cur_if->ifmode = ISTA_MODE; + cur_if->prio = PRIO_STA; + cur_if->vsdb = TRUE; + cur_if->prefix = 'S'; if (dhd->conf->vndr_ie_assocreq && strlen(dhd->conf->vndr_ie_assocreq)) wl_ext_add_del_ie(net, VNDR_IE_ASSOCREQ_FLAG, dhd->conf->vndr_ie_assocreq, "add"); } else { @@ -5557,9 +6795,11 @@ wl_ext_iapsta_update_net_device(struct net_device *net, int ifidx) if (apsta_params->apstamode != IUNKNOWN_MODE && apsta_params->apstamode != ISTAAPAP_MODE && apsta_params->apstamode != ISTASTA_MODE) { - memcpy(net->dev_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN); - net->dev_addr[0] |= 0x02; - wl_ext_iapsta_get_vif_macaddr(dhd, ifidx, net->dev_addr); + u8 mac_addr[ETH_ALEN]; + memcpy(mac_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN); + mac_addr[0] |= 0x02; + wl_ext_iapsta_get_vif_macaddr(dhd, ifidx, mac_addr); + dev_addr_set(net, mac_addr); } #endif /* WL_STATIC_IF */ } @@ -5567,80 +6807,158 @@ wl_ext_iapsta_update_net_device(struct net_device *net, int ifidx) return 0; } +#ifdef WLDWDS +int +wl_ext_iapsta_attach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssidx) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_if_info *cur_if = NULL; + int i; + + for (i=0; iif_info[ifidx]; + if (cur_if->bssidx == bssidx) { + break; + } + } + + if (cur_if) { + IAPSTA_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx); + for (i=0; idwds_info[i].dev == NULL) { + apsta_params->dwds_info[i].dev = net; + apsta_params->dwds_info[i].ifidx = ifidx; + apsta_params->dwds_info[i].bssidx = bssidx; + break; + } + } + } + + return 0; +} + +int +wl_ext_iapsta_dettach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssidx) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + struct wl_if_info *cur_if = NULL; + int i; + + for (i=0; iif_info[ifidx]; + if (cur_if->bssidx == bssidx) { + break; + } + } + + if (cur_if) { + IAPSTA_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx); + for (i=0; idwds_info[i].dev == net) { + memset(&apsta_params->dwds_info[i], 0, sizeof(struct wl_dwds_info)); + } + } + } + + return 0; +} +#endif /* WLDWDS */ + +static void +wl_ext_iapsta_init_priv(struct net_device *net) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + + if (!apsta_params->ioctl_buf) { + apsta_params->ioctl_buf = kmalloc(WL_DUMP_BUF_LEN, GFP_KERNEL); + if (unlikely(!apsta_params->ioctl_buf)) { + IAPSTA_ERROR(net->name, "Can not allocate ioctl_buf\n"); + } + } + init_waitqueue_head(&apsta_params->netif_change_event); + mutex_init(&apsta_params->usr_sync); + mutex_init(&apsta_params->in4way_sync); +#ifdef STA_MGMT + INIT_LIST_HEAD(&apsta_params->sta_list); +#endif /* STA_MGMT */ +#ifdef EAPOL_RESEND + spin_lock_init(&apsta_params->eapol_lock); +#endif /* EAPOL_RESEND */ +} + +static void +wl_ext_iapsta_deinit_priv(struct net_device *net) +{ + struct dhd_pub *dhd = dhd_get_pub(net); + struct wl_apsta_params *apsta_params = dhd->iapsta_params; + + if (apsta_params->ioctl_buf) { + kfree(apsta_params->ioctl_buf); + apsta_params->ioctl_buf = NULL; + } + memset(apsta_params, 0, sizeof(struct wl_apsta_params)); +} + int wl_ext_iapsta_attach_netdev(struct net_device *net, int ifidx, uint8 bssidx) { struct dhd_pub *dhd = dhd_get_pub(net); struct wl_apsta_params *apsta_params = dhd->iapsta_params; - struct wl_if_info *cur_if = NULL, *primary_if; + struct wl_if_info *cur_if = NULL; if (ifidx < MAX_IF_NUM) { IAPSTA_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx); cur_if = &apsta_params->if_info[ifidx]; } + if (ifidx == 0) { - memset(apsta_params, 0, sizeof(struct wl_apsta_params)); - apsta_params->dhd = dhd; - cur_if->dev = net; - cur_if->ifidx = ifidx; - cur_if->bssidx = bssidx; - cur_if->ifmode = ISTA_MODE; - cur_if->prio = PRIO_STA; - cur_if->vsdb = TRUE; - cur_if->prefix = 'S'; - wl_ext_event_register(net, dhd, WLC_E_LAST, wl_ext_iapsta_event, - apsta_params, PRIO_EVENT_IAPSTA); + wl_ext_iapsta_init_priv(net); strcpy(cur_if->ifname, net->name); - init_waitqueue_head(&apsta_params->netif_change_event); - init_waitqueue_head(&apsta_params->ap_recon_sta_event); - mutex_init(&apsta_params->usr_sync); - mutex_init(&apsta_params->in4way_sync); - mutex_init(&cur_if->pm_sync); #ifdef TPUT_MONITOR - init_timer_compat(&apsta_params->monitor_timer, wl_tput_monitor_timer, net); + wl_timer_register(net, &apsta_params->monitor_timer, wl_tput_monitor_timer); #endif /* TPUT_MONITOR */ -#ifdef ACS_MONITOR - wl_acs_attach(dhd, cur_if); -#endif /* ACS_MONITOR */ - INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler); -#ifdef SET_CARRIER - wl_ext_net_setcarrier(cur_if, FALSE, TRUE); -#endif /* SET_CARRIER */ - init_timer_compat(&cur_if->connect_timer, wl_ext_connect_timeout, net); -#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - init_timer_compat(&cur_if->reconnect_timer, wl_ext_reconnect_timeout, net); -#endif /* WL_EXT_RECONNECT && WL_CFG80211 */ -#ifdef EAPOL_RESEND - spin_lock_init(&apsta_params->eapol_lock); - init_timer_compat(&cur_if->eapol_timer, wl_eapol_timer, net); -#endif /* EAPOL_RESEND */ - } else if (cur_if && wl_get_isam_status(cur_if, IF_ADDING)) { - primary_if = &apsta_params->if_info[IF_PIF]; +#ifdef RXF0OVFL_REINIT_WAR + wl_timer_register(net, &apsta_params->rxf0ovfl_timer, wl_ext_rxf0ovfl_reinit_timeout); +#endif /* RXF0OVFL_REINIT_WAR */ + } + + if (ifidx == 0 || (cur_if && wl_get_isam_status(cur_if, IF_ADDING))) { cur_if->dev = net; cur_if->ifidx = ifidx; cur_if->bssidx = bssidx; + mutex_init(&cur_if->pm_sync); + INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler); + init_waitqueue_head(&cur_if->ap_recon_sta_event); wl_ext_event_register(net, dhd, WLC_E_LAST, wl_ext_iapsta_event, apsta_params, PRIO_EVENT_IAPSTA); #if defined(WLMESH) && defined(WL_ESCAN) - if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) { - wl_mesh_escan_attach(dhd, cur_if); - } + wl_mesh_escan_attach(dhd, cur_if); #endif /* WLMESH && WL_ESCAN */ #ifdef ACS_MONITOR wl_acs_attach(dhd, cur_if); #endif /* ACS_MONITOR */ - mutex_init(&cur_if->pm_sync); - INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler); #ifdef SET_CARRIER wl_ext_net_setcarrier(cur_if, FALSE, TRUE); #endif /* SET_CARRIER */ - init_timer_compat(&cur_if->connect_timer, wl_ext_connect_timeout, net); + wl_timer_register(net, &cur_if->connect_timer, wl_ext_connect_timeout); #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - init_timer_compat(&cur_if->reconnect_timer, wl_ext_reconnect_timeout, net); + wl_timer_register(net, &cur_if->reconnect_timer, wl_ext_reconnect_timeout); #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ +#ifdef RESTART_AP_WAR + wl_timer_register(net, &cur_if->restart_ap_timer, wl_ext_restart_ap_timeout); +#endif /* RESTART_AP_WAR */ +#ifdef RESET_AP_WAR + wl_timer_register(net, &cur_if->reset_ap_timer, wl_ext_reset_ap_timeout); +#endif /* RESET_AP_WAR */ #ifdef EAPOL_RESEND - init_timer_compat(&cur_if->eapol_timer, wl_eapol_timer, net); + wl_timer_register(net, &cur_if->eapol_timer, wl_eapol_timer); #endif /* EAPOL_RESEND */ +#ifdef KEY_INSTALL_CHECK + wl_timer_register(net, &cur_if->key_install_timer, wl_ext_key_install_timeout); +#endif /* KEY_INSTALL_CHECK */ } return 0; @@ -5661,41 +6979,24 @@ wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx) cur_if = &apsta_params->if_info[ifidx]; } - if (ifidx == 0) { -#ifdef EAPOL_RESEND - wl_ext_release_eapol_txpkt(dhd, ifidx, FALSE); -#endif /* EAPOL_RESEND */ - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); -#if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); -#endif /* WL_EXT_RECONNECT && WL_CFG80211 */ -#ifdef SET_CARRIER - wl_ext_net_setcarrier(cur_if, FALSE, FALSE); -#endif /* SET_CARRIER */ - wl_ext_add_remove_pm_enable_work(net, FALSE); -#ifdef ACS_MONITOR - wl_acs_detach(cur_if); -#endif /* ACS_MONITOR */ -#ifdef TPUT_MONITOR - wl_ext_mod_timer(&apsta_params->monitor_timer, 0, 0); -#endif /* TPUT_MONITOR */ -#if defined(WLMESH) && defined(WL_ESCAN) - if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) { - wl_mesh_escan_detach(dhd, cur_if); - } -#endif /* WLMESH && WL_ESCAN */ - wl_ext_event_deregister(net, dhd, WLC_E_LAST, wl_ext_iapsta_event); - memset(apsta_params, 0, sizeof(struct wl_apsta_params)); - } - else if (cur_if && (wl_get_isam_status(cur_if, IF_READY) || - wl_get_isam_status(cur_if, IF_ADDING))) { + if (ifidx == 0 || (cur_if && (wl_get_isam_status(cur_if, IF_READY) || + wl_get_isam_status(cur_if, IF_ADDING)))) { #ifdef EAPOL_RESEND wl_ext_release_eapol_txpkt(dhd, ifidx, FALSE); #endif /* EAPOL_RESEND */ - wl_ext_mod_timer(&cur_if->connect_timer, 0, 0); +#ifdef KEY_INSTALL_CHECK + wl_timer_deregister(net, &cur_if->key_install_timer); +#endif /* KEY_INSTALL_CHECK */ + wl_timer_deregister(net, &cur_if->connect_timer); #if defined(WL_EXT_RECONNECT) && defined(WL_CFG80211) - wl_ext_mod_timer(&cur_if->reconnect_timer, 0, 0); + wl_timer_deregister(net, &cur_if->reconnect_timer); #endif /* WL_EXT_RECONNECT && WL_CFG80211 */ +#ifdef RESTART_AP_WAR + wl_timer_deregister(net, &cur_if->restart_ap_timer); +#endif /* RESTART_AP_WAR */ +#ifdef RESET_AP_WAR + wl_timer_deregister(net, &cur_if->reset_ap_timer); +#endif /* RESET_AP_WAR */ #ifdef SET_CARRIER wl_ext_net_setcarrier(cur_if, FALSE, FALSE); #endif /* SET_CARRIER */ @@ -5704,14 +7005,25 @@ wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx) wl_acs_detach(cur_if); #endif /* ACS_MONITOR */ #if defined(WLMESH) && defined(WL_ESCAN) - if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) { - wl_mesh_escan_detach(dhd, cur_if); - } + wl_mesh_escan_detach(dhd, cur_if); #endif /* WLMESH && WL_ESCAN */ wl_ext_event_deregister(net, dhd, WLC_E_LAST, wl_ext_iapsta_event); +#ifdef STA_MGMT + wl_ext_flush_sta_list(net, ifidx); +#endif /* STA_MGMT */ memset(cur_if, 0, sizeof(struct wl_if_info)); } + if (ifidx == 0) { +#ifdef RXF0OVFL_REINIT_WAR + wl_timer_deregister(net, &apsta_params->rxf0ovfl_timer); +#endif /* RXF0OVFL_REINIT_WAR */ +#ifdef TPUT_MONITOR + wl_timer_deregister(net, &apsta_params->monitor_timer); +#endif /* TPUT_MONITOR */ + wl_ext_iapsta_deinit_priv(net); + } + return 0; } @@ -5725,7 +7037,7 @@ wl_ext_iapsta_attach(struct net_device *net) iapsta_params = kzalloc(sizeof(struct wl_apsta_params), GFP_KERNEL); if (unlikely(!iapsta_params)) { - IAPSTA_ERROR("wlan", "Could not allocate apsta_params\n"); + IAPSTA_ERROR(net->name, "Can not allocate apsta_params\n"); return -ENOMEM; } dhd->iapsta_params = (void *)iapsta_params; @@ -5741,6 +7053,7 @@ wl_ext_iapsta_dettach(struct net_device *net) IAPSTA_TRACE(net->name, "Enter\n"); if (dhd->iapsta_params) { + wl_ext_iapsta_deinit_priv(net); kfree(dhd->iapsta_params); dhd->iapsta_params = NULL; } diff --git a/bcmdhd.101.10.361.x/wl_iapsta.h b/bcmdhd.101.10.361.x/wl_iapsta.h index 6e42b16..f88c6e7 100755 --- a/bcmdhd.101.10.361.x/wl_iapsta.h +++ b/bcmdhd.101.10.361.x/wl_iapsta.h @@ -10,7 +10,8 @@ typedef enum IFMODE { } ifmode_t; enum wl_ext_status { - WL_EXT_STATUS_DISCONNECTING = 0, + WL_EXT_STATUS_PRE_DISCONNECTING = 0, + WL_EXT_STATUS_DISCONNECTING, WL_EXT_STATUS_DISCONNECTED, WL_EXT_STATUS_SCAN, WL_EXT_STATUS_SCANNING, @@ -18,11 +19,14 @@ enum wl_ext_status { WL_EXT_STATUS_CONNECTING, WL_EXT_STATUS_RECONNECT, WL_EXT_STATUS_CONNECTED, + WL_EXT_STATUS_ROAMED, WL_EXT_STATUS_ADD_KEY, + WL_EXT_STATUS_AP_ENABLING, WL_EXT_STATUS_AP_ENABLED, WL_EXT_STATUS_DELETE_STA, WL_EXT_STATUS_STA_DISCONNECTED, WL_EXT_STATUS_STA_CONNECTED, + WL_EXT_STATUS_AP_DISABLING, WL_EXT_STATUS_AP_DISABLED }; @@ -33,6 +37,10 @@ void wl_ext_backup_eapol_txpkt(dhd_pub_t *dhd, int ifidx, void *pkt); void wl_ext_release_eapol_txpkt(dhd_pub_t *dhd, int ifidx, bool rx); #endif /* EAPOL_RESEND */ void wl_ext_iapsta_get_vif_macaddr(struct dhd_pub *dhd, int ifidx, u8 *mac_addr); +#ifdef WLDWDS +int wl_ext_iapsta_attach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssidx); +int wl_ext_iapsta_dettach_dwds_netdev(struct net_device *net, int ifidx, uint8 bssidx); +#endif /* WLDWDS */ int wl_ext_iapsta_attach_netdev(struct net_device *net, int ifidx, uint8 bssidx); int wl_ext_iapsta_attach_name(struct net_device *net, int ifidx); int wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx); @@ -50,6 +58,10 @@ int wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len); void wl_ext_add_remove_pm_enable_work(struct net_device *dev, bool add); bool wl_ext_iapsta_other_if_enabled(struct net_device *net); bool wl_ext_sta_connecting(struct net_device *dev); +void wl_ext_get_chan_str(struct net_device *dev, char *chan_str, int total_len); +#ifdef DHD_LOSSLESS_ROAMING +int wl_ext_any_sta_handshaking(struct dhd_pub *dhd); +#endif /* DHD_LOSSLESS_ROAMING */ void wl_iapsta_wait_event_complete(struct dhd_pub *dhd); int wl_iapsta_suspend_resume(dhd_pub_t *dhd, int suspend); #ifdef USE_IW @@ -74,8 +86,18 @@ void wl_ext_iapsta_restart_master(struct net_device *dev); void wl_ext_iapsta_ifadding(struct net_device *net, int ifidx); bool wl_ext_iapsta_mesh_creating(struct net_device *net); void wl_ext_fw_reinit_incsa(struct net_device *dev); +void wl_ext_send_event_msg(struct net_device *dev, int event, int status, + int reason); +#ifdef BTC_WAR +void wl_ext_btc_config(struct net_device *dev, bool enable); +#endif /* BTC_WAR */ +#ifdef STA_MGMT +bool wl_ext_del_sta_info(struct net_device *net, u8 *bssid); +bool wl_ext_add_sta_info(struct net_device *net, u8 *bssid); +#endif /* STA_MGMT */ #ifdef SCAN_SUPPRESS -uint16 wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2); +uint16 wl_ext_scan_suppress(struct net_device *dev, void *scan_params, bool scan_v2, + struct wl_chan_info *chan_info); void wl_ext_reset_scan_busy(dhd_pub_t *dhd); #endif /* SCAN_SUPPRESS */ #endif diff --git a/bcmdhd.101.10.361.x/wl_iw.c b/bcmdhd.101.10.361.x/wl_iw.c index 160148e..10e4f34 100755 --- a/bcmdhd.101.10.361.x/wl_iw.c +++ b/bcmdhd.101.10.361.x/wl_iw.c @@ -216,8 +216,8 @@ static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action); #endif /* !WL_ESCAN */ struct pmk_list { - pmkid_list_t pmkids; - pmkid_t foo[MAXPMKID - 1]; + pmkid_list_v1_t pmkids; + pmkid_v1_t foo[MAXPMKID - 1]; }; typedef struct wl_wext_info { @@ -293,7 +293,7 @@ dev_wlc_ioctl( index = dhd_net2idx(dhd->info, dev); if (index == DHD_BAD_IF) { - WL_ERROR(("Bad ifidx from dev:%p\n", dev)); + WL_ERROR(("Bad ifidx from %s\n", dev->name)); return -ENODEV; } ret = dhd_ioctl_process(dhd, index, &ioc, arg); @@ -456,6 +456,7 @@ typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, #endif /* WIRELESS_EXT < 13 */ #if WIRELESS_EXT > 12 +#ifdef CONFIG_WEXT_PRIV static int wl_iw_set_leddc( struct net_device *dev, @@ -502,6 +503,7 @@ wl_iw_set_pm( error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); return error; } +#endif /* CONFIG_WEXT_PRIV */ #endif /* WIRELESS_EXT > 12 */ int @@ -532,7 +534,7 @@ static int wl_iw_config_commit( struct net_device *dev, struct iw_request_info *info, - void *zwrq, + union iwreq_data *zwrq, char *extra ) { @@ -616,10 +618,11 @@ static int wl_iw_set_freq( struct net_device *dev, struct iw_request_info *info, - struct iw_freq *fwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_freq *fwrq = &wrqu->freq; int error, chan; uint sf = 0; struct dhd_pub *dhd = dhd_get_pub(dev); @@ -668,18 +671,22 @@ static int wl_iw_get_freq( struct net_device *dev, struct iw_request_info *info, - struct iw_freq *fwrq, + union iwreq_data *wrqu, char *extra ) { + struct dhd_pub *dhd = dhd_get_pub(dev); + struct iw_freq *fwrq = &wrqu->freq; int error; - u32 chanspec = 0; + chanspec_t chanspec = 0; int ctl_chan; WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name)); - if ((error = dev_wlc_intvar_get(dev, "chanspec", &chanspec))) + DHD_CHECK(dhd, dev); + if ((error = dev_wlc_intvar_get(dev, "chanspec", (s32 *)&chanspec))) return error; + chanspec = wl_ext_chspec_driver_to_host(dhd, chanspec); ctl_chan = wf_chspec_ctlchan(chanspec); /* Return radio channel in channel form */ @@ -692,7 +699,7 @@ static int wl_iw_set_mode( struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, + union iwreq_data *wrqu, char *extra ) { @@ -709,7 +716,7 @@ wl_iw_set_mode( wext_info->conn_info.channel = 0; } - switch (*uwrq) { + switch (wrqu->mode) { case IW_MODE_MASTER: infra = ap = 1; break; @@ -737,7 +744,7 @@ static int wl_iw_get_mode( struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, + union iwreq_data *wrqu, char *extra ) { @@ -751,7 +758,7 @@ wl_iw_get_mode( infra = dtoh32(infra); ap = dtoh32(ap); - *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC; + wrqu->mode = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC; return 0; } @@ -760,10 +767,11 @@ static int wl_iw_get_range( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; struct iw_range *range = (struct iw_range *) extra; static int channels[MAXCHANNEL+1]; wl_uint32_list_t *list = (wl_uint32_list_t *) channels; @@ -992,10 +1000,11 @@ static int wl_iw_set_spy( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_iw_t *iw = IW_DEV_IF(dev); struct sockaddr *addr = (struct sockaddr *) extra; int i; @@ -1017,10 +1026,11 @@ static int wl_iw_get_spy( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_iw_t *iw = IW_DEV_IF(dev); struct sockaddr *addr = (struct sockaddr *) extra; struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num]; @@ -1046,7 +1056,7 @@ static int wl_iw_set_wap( struct net_device *dev, struct iw_request_info *info, - struct sockaddr *awrq, + union iwreq_data *wrqu, char *extra ) { @@ -1057,13 +1067,13 @@ wl_iw_set_wap( WL_TRACE(("%s: SIOCSIWAP\n", dev->name)); DHD_CHECK(dhd, dev); wext_info = dhd->wext_info; - if (awrq->sa_family != ARPHRD_ETHER) { + if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) { WL_ERROR(("Invalid Header...sa_family\n")); return -EINVAL; } /* Ignore "auto" or "off" */ - if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { + if (ETHER_ISBCAST(wrqu->ap_addr.sa_data) || ETHER_ISNULLADDR(wrqu->ap_addr.sa_data)) { scb_val_t scbval; bzero(&scbval, sizeof(scb_val_t)); WL_MSG(dev->name, "WLC_DISASSOC\n"); @@ -1076,21 +1086,21 @@ wl_iw_set_wap( #endif return 0; } - /* WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(awrq->sa_data), + /* WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(wrqu->ap_addr.sa_data), * eabuf))); */ /* Reassociate to the specified AP */ if (wext_info) - memcpy(&wext_info->conn_info.bssid, awrq->sa_data, ETHER_ADDR_LEN); + memcpy(&wext_info->conn_info.bssid, wrqu->ap_addr.sa_data, ETHER_ADDR_LEN); if (wext_info && wext_info->conn_info.ssid.SSID_len) { if ((error = wl_ext_connect(dev, &wext_info->conn_info))) return error; } else { - if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) { + if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, wrqu->ap_addr.sa_data, ETHER_ADDR_LEN))) { WL_ERROR(("WLC_REASSOC failed (%d).\n", error)); return error; } - WL_MSG(dev->name, "join BSSID="MACSTR"\n", MAC2STR((u8 *)awrq->sa_data)); + WL_MSG(dev->name, "join BSSID="MACSTR"\n", MAC2STR((u8 *)wrqu->ap_addr.sa_data)); } #ifdef WL_EXT_IAPSTA wl_ext_in4way_sync_wext(dev, STA_NO_BTC_IN4WAY, WL_EXT_STATUS_CONNECTING, NULL); @@ -1103,17 +1113,17 @@ static int wl_iw_get_wap( struct net_device *dev, struct iw_request_info *info, - struct sockaddr *awrq, + union iwreq_data *wrqu, char *extra ) { WL_TRACE(("%s: SIOCGIWAP\n", dev->name)); - awrq->sa_family = ARPHRD_ETHER; - memset(awrq->sa_data, 0, ETHER_ADDR_LEN); + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + memset(wrqu->ap_addr.sa_data, 0, ETHER_ADDR_LEN); /* Ignore error (may be down or disassociated) */ - (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN); + (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, wrqu->ap_addr.sa_data, ETHER_ADDR_LEN); return 0; } @@ -1123,7 +1133,7 @@ static int wl_iw_mlme( struct net_device *dev, struct iw_request_info *info, - struct sockaddr *awrq, + union iwreq_data *wrqu, char *extra ) { @@ -1171,14 +1181,15 @@ static int wl_iw_get_aplist( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { - wl_scan_results_t *list; + struct iw_point *dwrq = (struct iw_point *)wrqu; + wl_scan_results_v109_t *list; struct sockaddr *addr = (struct sockaddr *) extra; struct iw_quality qual[IW_MAX_AP]; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int error, i; uint buflen = dwrq->length; int16 rssi; @@ -1205,7 +1216,7 @@ wl_iw_get_aplist( ASSERT(list->version == WL_BSS_INFO_VERSION); for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + buflen)); @@ -1247,17 +1258,18 @@ static int wl_iw_iscan_get_aplist( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { - wl_scan_results_t *list; + struct iw_point *dwrq = (struct iw_point *)wrqu; + wl_scan_results_v109_t *list; iscan_buf_t * buf; iscan_info_t *iscan; struct sockaddr *addr = (struct sockaddr *) extra; struct iw_quality qual[IW_MAX_AP]; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int i; int16 rssi; struct dhd_pub *dhd = dhd_get_pub(dev); @@ -1283,7 +1295,7 @@ wl_iw_iscan_get_aplist( bi = NULL; for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + WLC_IW_ISCAN_MAXLEN)); @@ -1365,11 +1377,11 @@ wl_iw_iscan_set_scan( ) { struct dhd_pub *dhd = dhd_get_pub(dev); - wl_wext_info_t *wext_info = NULL; wlc_ssid_t ssid; #ifdef WL_ESCAN wl_scan_info_t scan_info; #else + wl_wext_info_t *wext_info = NULL; iscan_info_t *iscan; #ifdef WL_EXT_IAPSTA int err; @@ -1377,7 +1389,6 @@ wl_iw_iscan_set_scan( #endif DHD_CHECK(dhd, dev); - wext_info = dhd->wext_info; #ifdef WL_ESCAN /* default Broadcast scan */ memset(&ssid, 0, sizeof(ssid)); @@ -1398,6 +1409,7 @@ wl_iw_iscan_set_scan( scan_info.ssid.SSID_len = ssid.SSID_len; return wl_escan_set_scan(dev, &scan_info); #else + wext_info = dhd->wext_info; iscan = &wext_info->iscan; WL_TRACE(("%s: SIOCSIWSCAN iscan=%p\n", dev->name, iscan)); #ifdef WL_EXT_IAPSTA @@ -1532,7 +1544,7 @@ static #endif int wl_iw_handle_scanresults_ies(char **event_p, char *end, - struct iw_request_info *info, wl_bss_info_t *bi) + struct iw_request_info *info, wl_bss_info_v109_t *bi) { #if WIRELESS_EXT > 17 struct iw_event iwe; @@ -1596,7 +1608,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, } #ifdef BCMWAPI_WPI - ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); + ptr = ((uint8 *)bi) + sizeof(wl_bss_info_v109_t); ptr_len = bi->ie_length; while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WAPI_ID))) { @@ -1639,14 +1651,15 @@ static int wl_iw_get_scan( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; channel_info_t ci; - wl_scan_results_t *list; + wl_scan_results_v109_t *list; struct iw_event iwe; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int error, i, j; char *event = extra, *end = extra + dwrq->length, *value; uint buflen = dwrq->length; @@ -1682,7 +1695,7 @@ wl_iw_get_scan( ASSERT(list->version == WL_BSS_INFO_VERSION); for (i = 0; i < list->count && i < IW_MAX_AP; i++) { - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + buflen)); @@ -1769,16 +1782,17 @@ static int wl_iw_iscan_get_scan( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; struct dhd_pub *dhd = dhd_get_pub(dev); - wl_wext_info_t *wext_info = NULL; #ifndef WL_ESCAN - wl_scan_results_t *list; + wl_wext_info_t *wext_info = NULL; + wl_scan_results_v109_t *list; struct iw_event iwe; - wl_bss_info_t *bi = NULL; + wl_bss_info_v109_t *bi = NULL; int ii, j; int apcnt; char *event = extra, *end = extra + dwrq->length, *value; @@ -1789,7 +1803,6 @@ wl_iw_iscan_get_scan( #endif DHD_CHECK(dhd, dev); - wext_info = dhd->wext_info; #ifdef WL_ESCAN return wl_escan_get_scan(dev, info, dwrq, extra); #else @@ -1798,6 +1811,7 @@ wl_iw_iscan_get_scan( if (!extra) return -EINVAL; + wext_info = dhd->wext_info; /* use backup if our thread is not successful */ iscan = &wext_info->iscan; if ((!iscan) || (iscan->sysioc_pid < 0)) { @@ -1822,7 +1836,7 @@ wl_iw_iscan_get_scan( bi = NULL; for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) { - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; + bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + WLC_IW_ISCAN_MAXLEN)); @@ -1919,10 +1933,11 @@ static int wl_iw_set_essid( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wlc_ssid_t ssid; int error; struct dhd_pub *dhd = dhd_get_pub(dev); @@ -1982,10 +1997,11 @@ static int wl_iw_get_essid( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wlc_ssid_t ssid; int error; @@ -2004,14 +2020,15 @@ wl_iw_get_essid( /* Max SSID length check */ if (ssid.SSID_len > IW_ESSID_MAX_SIZE) { ssid.SSID_len = IW_ESSID_MAX_SIZE; + /* Get the current SSID */ + memcpy(extra, ssid.SSID, ssid.SSID_len); + /* NULL terminating as length of extra buffer is IW_ESSID_MAX_SIZE ie 32 */ + extra[IW_ESSID_MAX_SIZE-1] = '\0'; + } else { + /* Get the current SSID */ + memcpy(extra, ssid.SSID, ssid.SSID_len); } - /* Get the current SSID */ - memcpy(extra, ssid.SSID, ssid.SSID_len); - - /* NULL terminating as length of extra buffer is IW_ESSID_MAX_SIZE ie 32 */ - extra[IW_ESSID_MAX_SIZE] = '\0'; - dwrq->length = ssid.SSID_len; dwrq->flags = 1; /* active */ @@ -2023,10 +2040,11 @@ static int wl_iw_set_nick( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_iw_t *iw = IW_DEV_IF(dev); WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name)); @@ -2047,10 +2065,11 @@ static int wl_iw_get_nick( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_iw_t *iw = IW_DEV_IF(dev); WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name)); @@ -2066,10 +2085,11 @@ wl_iw_get_nick( static int wl_iw_set_rate( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->bitrate; wl_rateset_t rateset; int error, rate, i, error_bg, error_a; @@ -2132,10 +2152,11 @@ static int wl_iw_set_rate( static int wl_iw_get_rate( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->bitrate; int error, rate; WL_TRACE(("%s: SIOCGIWRATE\n", dev->name)); @@ -2153,10 +2174,11 @@ static int wl_iw_set_rts( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->rts; int error, rts; WL_TRACE(("%s: SIOCSIWRTS\n", dev->name)); @@ -2178,10 +2200,11 @@ static int wl_iw_get_rts( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->rts; int error, rts; WL_TRACE(("%s: SIOCGIWRTS\n", dev->name)); @@ -2200,10 +2223,11 @@ static int wl_iw_set_frag( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->frag; int error, frag; WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name)); @@ -2225,10 +2249,11 @@ static int wl_iw_get_frag( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->frag; int error, fragthreshold; WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name)); @@ -2247,10 +2272,11 @@ static int wl_iw_set_txpow( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->txpower; int error, disable; uint16 txpwrmw; WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name)); @@ -2287,10 +2313,11 @@ static int wl_iw_get_txpow( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->txpower; int error, disable, txpwrdbm; uint8 result; @@ -2315,10 +2342,11 @@ static int wl_iw_set_retry( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->retry; int error, lrl, srl; WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name)); @@ -2362,10 +2390,11 @@ static int wl_iw_get_retry( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->retry; int error, lrl, srl; WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name)); @@ -2403,10 +2432,11 @@ static int wl_iw_set_encode( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_wsec_key_t key; int error, val, wsec; @@ -2492,10 +2522,11 @@ static int wl_iw_get_encode( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_wsec_key_t key; int error, val, wsec, auth; @@ -2555,10 +2586,11 @@ static int wl_iw_set_power( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->power; int error, pm; WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name)); @@ -2576,10 +2608,11 @@ static int wl_iw_get_power( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->power; int error, pm; WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name)); @@ -2599,10 +2632,11 @@ static int wl_iw_set_wpaie( struct net_device *dev, struct iw_request_info *info, - struct iw_point *iwp, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *iwp = (struct iw_point *)wrqu; #if defined(BCMWAPI_WPI) uchar buf[WLC_IOCTL_SMLEN] = {0}; uchar *p = buf; @@ -2627,10 +2661,11 @@ static int wl_iw_get_wpaie( struct net_device *dev, struct iw_request_info *info, - struct iw_point *iwp, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *iwp = (struct iw_point *)wrqu; WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name)); iwp->length = 64; dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length); @@ -2641,10 +2676,11 @@ static int wl_iw_set_encodeext( struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_point *dwrq = (struct iw_point *)wrqu; wl_wsec_key_t key; int error; struct iw_encode_ext *iwe; @@ -2793,7 +2829,7 @@ static int wl_iw_set_pmksa( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { @@ -2801,7 +2837,7 @@ wl_iw_set_pmksa( struct iw_pmksa *iwpmksa; uint i; char eabuf[ETHER_ADDR_STR_LEN]; - pmkid_t *pmkid_array = NULL; + pmkid_v1_t *pmkid_array = NULL; struct dhd_pub *dhd = dhd_get_pub(dev); wl_wext_info_t *wext_info = NULL; @@ -2818,7 +2854,7 @@ wl_iw_set_pmksa( bzero((char *)pmk_list, sizeof(struct pmk_list)); } if (iwpmksa->cmd == IW_PMKSA_REMOVE) { - pmkid_list_t pmkid, *pmkidptr; + pmkid_list_v1_t pmkid, *pmkidptr; pmkidptr = &pmkid; bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN); bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); @@ -2883,7 +2919,7 @@ static int wl_iw_get_encodeext( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { @@ -2895,10 +2931,11 @@ static int wl_iw_set_wpaauth( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->param; int error = 0; int paramid; int paramval; @@ -2935,7 +2972,7 @@ wl_iw_set_wpaauth( case IW_AUTH_CIPHER_PAIRWISE: case IW_AUTH_CIPHER_GROUP: { - int fbt_cap = 0; +// int fbt_cap = 0; if (paramid == IW_AUTH_CIPHER_PAIRWISE) { iw->pwsec = paramval; @@ -2984,6 +3021,7 @@ wl_iw_set_wpaauth( return error; } +#if 0 /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way * handshake. */ @@ -3004,6 +3042,7 @@ wl_iw_set_wpaauth( } } } +#endif break; } @@ -3151,10 +3190,11 @@ static int wl_iw_get_wpaauth( struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + union iwreq_data *wrqu, char *extra ) { + struct iw_param *vwrq = &wrqu->param; int error; int paramid; int paramval = 0; @@ -3321,6 +3361,7 @@ static const iw_handler wl_iw_handler[] = }; #if WIRELESS_EXT > 12 +#ifdef CONFIG_WEXT_PRIV enum { WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV, WL_IW_SET_VLANMODE, @@ -3356,15 +3397,18 @@ static struct iw_priv_args wl_iw_priv_args[] = { }, { 0, 0, 0, { 0 } } }; +#endif /* CONFIG_WEXT_PRIV */ const struct iw_handler_def wl_iw_handler_def = { .num_standard = ARRAYSIZE(wl_iw_handler), + .standard = (const iw_handler *) wl_iw_handler, +#ifdef CONFIG_WEXT_PRIV .num_private = ARRAY_SIZE(wl_iw_priv_handler), .num_private_args = ARRAY_SIZE(wl_iw_priv_args), - .standard = (const iw_handler *) wl_iw_handler, .private = wl_iw_priv_handler, .private_args = wl_iw_priv_args, +#endif /* CONFIG_WEXT_PRIV */ #if WIRELESS_EXT >= 19 get_wireless_stats: dhd_get_wireless_stats, #endif /* WIRELESS_EXT >= 19 */ @@ -3849,10 +3893,12 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat int rssi; scb_val_t scb_val; #if WIRELESS_EXT > 11 +#ifdef WL_NAN char *cntbuf = NULL; wl_cnt_info_t *cntinfo; uint16 ver; uint32 corerev = 0; +#endif #endif /* WIRELESS_EXT > 11 */ phy_noise = 0; @@ -3896,6 +3942,7 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat #endif /* WIRELESS_EXT > 18 */ #if WIRELESS_EXT > 11 +#ifdef WL_NAN WL_TRACE(("wl_iw_get_wireless_stats counters\n *****")); cntbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL); @@ -3916,12 +3963,10 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat cntinfo->version = dtoh16(cntinfo->version); cntinfo->datalen = dtoh16(cntinfo->datalen); ver = cntinfo->version; -#ifdef WL_NAN CHK_CNTBUF_DATALEN(cntbuf, MAX_WLIW_IOCTL_LEN); -#endif - if (ver > WL_CNT_T_VERSION) { + if (ver > WL_CNT_VERSION_XTLV) { WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n", - WL_CNT_T_VERSION, ver)); + WL_CNT_VERSION_XTLV, ver)); res = BCME_VERSION; goto done; } @@ -3937,7 +3982,6 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat corerev = dtoh32(revinfo.corerev); } -#ifdef WL_NAN res = wl_cntbuf_to_xtlv_format(NULL, cntinfo, MAX_WLIW_IOCTL_LEN, corerev); if (res) { WL_ERROR(("wl_cntbuf_to_xtlv_format failed %d\n", res)); @@ -3953,9 +3997,11 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat done: #if WIRELESS_EXT > 11 +#ifdef WL_NAN if (cntbuf) { kfree(cntbuf); } +#endif #endif /* WIRELESS_EXT > 11 */ return res; } @@ -3987,7 +4033,7 @@ wl_iw_set_event_mask(struct net_device *dev) } static int -wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) +wl_iw_iscan_prep(wl_scan_params_v1_t *params, wlc_ssid_t *ssid) { int err = 0; @@ -4013,14 +4059,14 @@ wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) { - int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)); - wl_iscan_params_t *params; + int params_size = (WL_SCAN_PARAMS_V1_FIXED_SIZE + OFFSETOF(wl_iscan_params_v1_t, params)); + wl_iscan_params_v1_t *params; int err = 0; if (ssid && ssid->SSID_len) { params_size += sizeof(wlc_ssid_t); } - params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); + params = (wl_iscan_params_v1_t*)kmalloc(params_size, GFP_KERNEL); if (params == NULL) { return -ENOMEM; } @@ -4034,7 +4080,7 @@ wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) params->action = htod16(action); params->scan_duration = htod16(0); - /* params_size += OFFSETOF(wl_iscan_params_t, params); */ + /* params_size += OFFSETOF(wl_iscan_params_v1_t, params); */ (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size, iscan->ioctlbuf, WLC_IOCTL_SMLEN); } @@ -4050,7 +4096,7 @@ wl_iw_iscan_get(iscan_info_t *iscan) iscan_buf_t * ptr; wl_iscan_results_t * list_buf; wl_iscan_results_t list; - wl_scan_results_t *results; + wl_scan_results_v109_t *results; uint32 status; /* buffers are allocated on demand */ @@ -4275,14 +4321,12 @@ s32 wl_iw_autochannel(struct net_device *dev, char* command, int total_len) { struct dhd_pub *dhd = dhd_get_pub(dev); - wl_wext_info_t *wext_info = NULL; int ret = 0; #ifdef WL_ESCAN int bytes_written = -1; #endif DHD_CHECK(dhd, dev); - wext_info = dhd->wext_info; #ifdef WL_ESCAN sscanf(command, "%*s %d", &dhd->escan->autochannel); if (dhd->escan->autochannel == 0) { diff --git a/bcmdhd.101.10.361.x/wl_roam.c b/bcmdhd.101.10.361.x/wl_roam.c index c6254da..52ee4d3 100755 --- a/bcmdhd.101.10.361.x/wl_roam.c +++ b/bcmdhd.101.10.361.x/wl_roam.c @@ -226,7 +226,7 @@ int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan, n++; } - WL_DBG((" %s: 0x%04X\n", __FUNCTION__, channels[0])); + WL_SCAN(("0x%04X\n", channels[0])); #ifdef WES_SUPPORT if (cfg->roamscan_mode == ROAMSCAN_MODE_WES) { @@ -242,7 +242,7 @@ int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan, ch = wf_chspec_ctlchan(ch) | CHSPEC_BAND(ch) | band_bw; if (band_match && !is_duplicated_channel(channels, n, ch)) { - WL_DBG(("%s: Chanspec = %s\n", __FUNCTION__, + WL_SCAN(("Chanspec = %s\n", wf_chspec_ntoa_ex(ch, chanbuf))); channels[n++] = ch; if (n >= n_channels) { @@ -270,7 +270,7 @@ int get_roam_channel_list(struct bcm_cfg80211 *cfg, chanspec_t target_chan, band_match && !is_duplicated_channel(channels, n, ch) && (memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) { /* match found, add it */ - WL_DBG(("%s: Chanspec = %s\n", __FUNCTION__, + WL_SCAN(("Chanspec = %s\n", wf_chspec_ntoa_ex(ch, chanbuf))); channels[n++] = ch; if (n >= n_channels) { diff --git a/bcmdhd.101.10.361.x/wl_timer.c b/bcmdhd.101.10.361.x/wl_timer.c new file mode 100755 index 0000000..e9ea4d8 --- /dev/null +++ b/bcmdhd.101.10.361.x/wl_timer.c @@ -0,0 +1,611 @@ +#include +#ifdef WL_TIMER + +#define TIMER_ERROR(name, arg1, args...) \ + do { \ + if (android_msg_level & ANDROID_ERROR_LEVEL) { \ + printf("[%s] TIMER-ERROR) %s : " arg1, name, __func__, ## args); \ + } \ + } while (0) +#define TIMER_TRACE(name, arg1, args...) \ + do { \ + if (android_msg_level & ANDROID_TRACE_LEVEL) { \ + printf("[%s] TIMER-TRACE) %s : " arg1, name, __func__, ## args); \ + } \ + } while (0) + +#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ + 4 && __GNUC_MINOR__ >= 6)) +#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \ +(entry) = list_first_entry((ptr), type, member); \ +_Pragma("GCC diagnostic pop") \ + +#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \ +entry = container_of((ptr), type, member); \ +_Pragma("GCC diagnostic pop") \ + +#else +#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \ +(entry) = list_first_entry((ptr), type, member); \ + +#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \ +entry = container_of((ptr), type, member); \ + +#endif /* STRICT_GCC_WARNINGS */ + +typedef void(*FUNC_HANDLER) (void *cb_argu); + +struct wl_func_q { + struct list_head eq_list; + FUNC_HANDLER cb_func; + void *cb_argu; +}; + +typedef void(*TIMER_HANDLER) (void *cb_argu); + +typedef struct timer_handler_list { + struct list_head list; + struct net_device *net; + timer_list_compat_t *timer; + TIMER_HANDLER cb_func; + void *cb_argu; + uint tmo_ms; + ulong tmo_jiffies; +} timer_handler_list_t; + +typedef struct wl_timer_params { + dhd_pub_t *pub; + struct list_head timer_list; + struct list_head eq_list; + timer_list_compat_t timer; + spinlock_t eq_lock; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + struct workqueue_struct *timer_workq; + struct work_struct timer_work; + struct workqueue_struct *func_workq; + struct work_struct func_work; +#else + tsk_ctl_t thr_timer_ctl; + tsk_ctl_t thr_func_ctl; +#endif +} wl_timer_params_t; + +static unsigned long +wl_func_lock_eq(struct wl_timer_params *timer_params) +{ + unsigned long flags; + + spin_lock_irqsave(&timer_params->eq_lock, flags); + return flags; +} + +static void +wl_func_unlock_eq(struct wl_timer_params *timer_params, unsigned long flags) +{ + spin_unlock_irqrestore(&timer_params->eq_lock, flags); +} + +static void +wl_func_init_eq_lock(struct wl_timer_params *timer_params) +{ + spin_lock_init(&timer_params->eq_lock); +} + +static void +wl_func_init_eq(struct wl_timer_params *timer_params) +{ + wl_func_init_eq_lock(timer_params); + INIT_LIST_HEAD(&timer_params->eq_list); +} + +static void +wl_func_flush_eq(struct wl_timer_params *timer_params) +{ + struct wl_func_q *e; + unsigned long flags; + + flags = wl_func_lock_eq(timer_params); + while (!list_empty_careful(&timer_params->eq_list)) { + BCM_SET_LIST_FIRST_ENTRY(e, &timer_params->eq_list, struct wl_func_q, eq_list); + list_del(&e->eq_list); + kfree(e); + } + wl_func_unlock_eq(timer_params, flags); +} + +static struct wl_func_q * +wl_func_deq(struct wl_timer_params *timer_params) +{ + struct wl_func_q *e = NULL; + unsigned long flags; + + flags = wl_func_lock_eq(timer_params); + if (likely(!list_empty(&timer_params->eq_list))) { + BCM_SET_LIST_FIRST_ENTRY(e, &timer_params->eq_list, struct wl_func_q, eq_list); + list_del(&e->eq_list); + } + wl_func_unlock_eq(timer_params, flags); + + return e; +} + +static s32 +wl_func_enq(struct wl_timer_params *timer_params, + void *cb_func, void *cb_argu) +{ + struct wl_func_q *e; + s32 err = 0; + uint32 funcq_size; + unsigned long flags; + gfp_t aflags; + + funcq_size = sizeof(struct wl_func_q); + aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; + e = kzalloc(funcq_size, aflags); + if (unlikely(!e)) { + TIMER_ERROR("wlan", "funcq_size alloc failed %d\n", funcq_size); + return -ENOMEM; + } + e->cb_func = cb_func; + e->cb_argu = cb_argu; + flags = wl_func_lock_eq(timer_params); + list_add_tail(&e->eq_list, &timer_params->eq_list); + wl_func_unlock_eq(timer_params, flags); + + return err; +} + +static void +wl_func_put(struct wl_func_q *e) +{ + kfree(e); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) +static void wl_func_handler(struct work_struct *data); +#define WL_FUNC_HANDLER() static void wl_func_handler(struct work_struct *data) +#else +static int wl_func_handler(void *data); +#define WL_FUNC_HANDLER() static int wl_func_handler(void *data) +#endif + +WL_FUNC_HANDLER() +{ + struct wl_timer_params *timer_params = NULL; + struct wl_func_q *e; + struct net_device *net = NULL; + dhd_pub_t *dhd; + unsigned long flags = 0; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + timer_params = (struct wl_timer_params *)tsk->parent; +#else + BCM_SET_CONTAINER_OF(timer_params, data, struct wl_timer_params, func_work); +#endif + + dhd = timer_params->pub; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + while (1) { + if (down_interruptible(&tsk->sema) == 0) { + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } +#endif + DHD_EVENT_WAKE_LOCK(dhd); + while ((e = wl_func_deq(timer_params))) { + DHD_GENERAL_LOCK(dhd, flags); + if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd)) { + TIMER_ERROR(net->name, "BUS is DOWN.\n"); + DHD_GENERAL_UNLOCK(dhd, flags); + goto fail; + } + DHD_GENERAL_UNLOCK(dhd, flags); + e->cb_func(e->cb_argu); +fail: + wl_func_put(e); + } + DHD_EVENT_WAKE_UNLOCK(dhd); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + } else { + break; + } + } + complete_and_exit(&tsk->completed, 0); +#endif +} + +void +wl_func_send(void *params, void *cb_func, void *cb_argu) +{ + struct wl_timer_params *timer_params = params; + + if (timer_params == NULL) { + TIMER_ERROR("wlan", "Stale ignored\n"); + return; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (timer_params->func_workq == NULL) { + TIMER_ERROR("wlan", "Event handler is not created\n"); + return; + } +#endif + + if (likely(!wl_func_enq(timer_params, cb_func, cb_argu))) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + queue_work(timer_params->func_workq, &timer_params->func_work); +#else + if (timer_params->thr_func_ctl.thr_pid >= 0) { + up(&timer_params->thr_func_ctl.sema); + } +#endif + } +} + +static s32 +wl_func_create_handler(struct wl_timer_params *timer_params) +{ + int ret = 0; + TIMER_TRACE("wlan", "Enter\n"); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (!timer_params->func_workq) { + timer_params->func_workq = alloc_workqueue("timer_funcd", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0); + } + if (!timer_params->func_workq) { + TIMER_ERROR("wlan", "func_workq alloc_workqueue failed\n"); + ret = -ENOMEM; + } else { + INIT_WORK(&timer_params->func_work, wl_func_handler); + } +#else + PROC_START(wl_func_handler, timer_params, &timer_params->thr_func_ctl, 0, "timer_funcd"); + if (timer_params->thr_func_ctl.thr_pid < 0) { + ret = -ENOMEM; + } +#endif + + return ret; +} + +static void +wl_func_destroy_handler(struct wl_timer_params *timer_params) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (timer_params && timer_params->func_workq) { + cancel_work_sync(&timer_params->func_work); + destroy_workqueue(timer_params->func_workq); + timer_params->func_workq = NULL; + } +#else + if (timer_params->thr_func_ctl.thr_pid >= 0) { + PROC_STOP(&timer_params->thr_func_ctl); + } +#endif +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) +static void wl_timer_handler(struct work_struct *data); +#define WL_TIMER_HANDLER() static void wl_timer_handler(struct work_struct *data) +#else +static int wl_timer_handler(void *data); +#define WL_TIMER_HANDLER() static int wl_timer_handler(void *data) +#endif + +WL_TIMER_HANDLER() +{ + struct wl_timer_params *timer_params = NULL; + struct timer_handler_list *node, *next; + dhd_pub_t *dhd; + unsigned long flags = 0; + unsigned long cur_jiffies, diff_jiffies, min_jiffies = 0; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + timer_params = (struct wl_timer_params *)tsk->parent; +#else + BCM_SET_CONTAINER_OF(timer_params, data, struct wl_timer_params, timer_work); +#endif + + dhd = timer_params->pub; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + while (1) { + if (down_interruptible(&tsk->sema) == 0) { + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } +#endif + DHD_EVENT_WAKE_LOCK(dhd); + DHD_GENERAL_LOCK(dhd, flags); + if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd)) { + TIMER_ERROR("wlan", "BUS is DOWN.\n"); + DHD_GENERAL_UNLOCK(dhd, flags); + goto exit; + } + DHD_GENERAL_UNLOCK(dhd, flags); + cur_jiffies = jiffies; + list_for_each_entry_safe(node, next, &timer_params->timer_list, list) { + if (node->tmo_ms) { + if (time_after(cur_jiffies, node->tmo_jiffies)) { + wl_func_send(timer_params, node->cb_func, node->cb_argu); + node->tmo_ms = 0; + } else { + diff_jiffies = node->tmo_jiffies - cur_jiffies; + if (min_jiffies == 0) + min_jiffies = diff_jiffies; + else if (diff_jiffies < min_jiffies) + min_jiffies = diff_jiffies; + } + } + } + if (min_jiffies) + mod_timer(&timer_params->timer, jiffies + min_jiffies); +exit: + DHD_EVENT_WAKE_UNLOCK(dhd); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)) + } else { + break; + } + } + complete_and_exit(&tsk->completed, 0); +#endif +} + +void +wl_timer_kick_handler(wl_timer_params_t *timer_params) +{ + if (timer_params == NULL) { + TIMER_ERROR("wlan", "timer_params not ready\n"); + return; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (timer_params->timer_workq == NULL) { + TIMER_ERROR("wlan", "timer handler is not created\n"); + return; + } + queue_work(timer_params->timer_workq, &timer_params->timer_work); +#else + if (timer_params->thr_timer_ctl.thr_pid >= 0) { + up(&timer_params->thr_timer_ctl.sema); + } +#endif +} + +static void +wl_timer_timeout(unsigned long data) +{ + struct wl_timer_params *timer_params = (struct wl_timer_params *)data; + + if (!timer_params) { + TIMER_ERROR("wlan", "timer_params is not ready\n"); + return; + } + + TIMER_TRACE("wlan", "timer expired\n"); + wl_timer_kick_handler(timer_params); +} + +static s32 +wl_timer_create_handler(struct wl_timer_params *timer_params) +{ + int ret = 0; + + TIMER_TRACE("wlan", "Enter\n"); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (!timer_params->timer_workq) { + timer_params->timer_workq = alloc_workqueue("timerd", + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0); + } + if (!timer_params->timer_workq) { + TIMER_ERROR("wlan", "timer_workq alloc_workqueue failed\n"); + ret = -ENOMEM; + } else { + INIT_WORK(&timer_params->timer_work, wl_timer_handler); + } +#else + PROC_START(wl_timer_handler, timer_params, &timer_params->thr_timer_ctl, 0, "timerd"); + if (timer_params->thr_timer_ctl.thr_pid < 0) { + ret = -ENOMEM; + } +#endif + + return ret; +} + +static void +wl_timer_destroy_handler(struct wl_timer_params *timer_params) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) + if (timer_params && timer_params->timer_workq) { + cancel_work_sync(&timer_params->timer_work); + destroy_workqueue(timer_params->timer_workq); + timer_params->timer_workq = NULL; + } +#else + if (timer_params->thr_timer_ctl.thr_pid >= 0) { + PROC_STOP(&timer_params->thr_timer_ctl); + } +#endif +} + +static void +wl_timer_free(struct wl_timer_params *timer_params) +{ + timer_handler_list_t *node, *next; + + list_for_each_entry_safe(node, next, &timer_params->timer_list, list) { + TIMER_TRACE(node->net->name, "Free timer\n"); + list_del(&node->list); + kfree(node); + } +} + +void +wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms) +{ + wl_timer_params_t *timer_params = dhd->timer_params; + timer_handler_list_t *node, *next; + bool found = FALSE; + + list_for_each_entry_safe(node, next, &timer_params->timer_list, list) { + if (node->timer == timer) { + node->tmo_ms = tmo_ms; + if (tmo_ms) { + TIMER_TRACE(node->net->name, "update timer %dms\n", tmo_ms); + node->tmo_jiffies = jiffies + msecs_to_jiffies(tmo_ms); + wl_timer_kick_handler(timer_params); + } + found = TRUE; + break; + } + } + if (!found) + TIMER_ERROR("wlan", "timer not found\n"); +} + +void +wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func) +{ + dhd_pub_t *dhd = dhd_get_pub(net); + wl_timer_params_t *timer_params = dhd->timer_params; + timer_handler_list_t *node, *next, *leaf; + + list_for_each_entry_safe(node, next, &timer_params->timer_list, list) { + if (node->timer == timer) { + TIMER_TRACE(net->name, "timer already registered\n"); + return; + } + } + + leaf = kmalloc(sizeof(timer_handler_list_t), GFP_KERNEL); + if (!leaf) { + TIMER_ERROR(net->name, "Memory alloc failure %d\n", + (int)sizeof(timer_handler_list_t)); + return; + } + memset(leaf, 0, sizeof(timer_handler_list_t)); + leaf->net = net; + leaf->timer = timer; + leaf->cb_func = cb_func; + leaf->cb_argu = net; + TIMER_ERROR(net->name, "timer registered tmo=%d\n", leaf->tmo_ms); + list_add_tail(&leaf->list, &timer_params->timer_list); + + return; +} + +void +wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer) +{ + dhd_pub_t *dhd = dhd_get_pub(net); + wl_timer_params_t *timer_params = dhd->timer_params; + timer_handler_list_t *node, *next; + + list_for_each_entry_safe(node, next, &timer_params->timer_list, list) { + if (node->timer == timer) { + TIMER_TRACE(net->name, "timer deregistered\n"); + list_del(&node->list); + kfree(node); + } + } + return; +} + +static s32 +wl_timer_init_priv(struct wl_timer_params *timer_params) +{ + s32 err = 0; + + INIT_LIST_HEAD(&timer_params->timer_list); + if (wl_timer_create_handler(timer_params)) + return -ENOMEM; + wl_func_init_eq(timer_params); + if (wl_func_create_handler(timer_params)) + return -ENOMEM; + + return err; +} + +static void +wl_timer_deinit_priv(struct wl_timer_params *timer_params) +{ + wl_timer_free(timer_params); + wl_func_destroy_handler(timer_params); + wl_func_flush_eq(timer_params); + wl_timer_destroy_handler(timer_params); +} + +void +wl_timer_dettach(dhd_pub_t *dhdp) +{ + struct wl_timer_params *timer_params = dhdp->timer_params; + + if (timer_params) { + if (timer_pending(&timer_params->timer)) + del_timer_sync(&timer_params->timer); + wl_timer_deinit_priv(timer_params); + kfree(timer_params); + dhdp->timer_params = NULL; + } +} + +s32 +wl_timer_attach(struct net_device *net) +{ + struct dhd_pub *dhdp = dhd_get_pub(net); + struct wl_timer_params *timer_params = NULL; + s32 err = 0; + + timer_params = kmalloc(sizeof(wl_timer_params_t), GFP_KERNEL); + if (!timer_params) { + TIMER_ERROR(net->name, "Failed to allocate memory (%zu)\n", + sizeof(wl_timer_params_t)); + return -ENOMEM; + } + dhdp->timer_params = timer_params; + memset(timer_params, 0, sizeof(wl_timer_params_t)); + timer_params->pub = dhdp; + + err = wl_timer_init_priv(timer_params); + if (err) { + TIMER_ERROR(net->name, "Failed to wl_timer_init_priv (%d)\n", err); + goto exit; + } + init_timer_compat(&timer_params->timer, wl_timer_timeout, timer_params); + +exit: + if (err) + wl_timer_dettach(dhdp); + return err; +} +#else +void +wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms) +{ + if (timer_pending(timer)) + del_timer_sync(timer); + if (tmo_ms) + mod_timer(timer, jiffies + msecs_to_jiffies(tmo_ms)); +} + +void +wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func) +{ + init_timer_compat(timer, cb_func, net); +} + +void +wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer) +{ + if (timer_pending(timer)) + del_timer_sync(timer); +} +#endif diff --git a/bcmdhd.101.10.361.x/wl_timer.h b/bcmdhd.101.10.361.x/wl_timer.h new file mode 100755 index 0000000..97997f4 --- /dev/null +++ b/bcmdhd.101.10.361.x/wl_timer.h @@ -0,0 +1,8 @@ +#ifndef _wl_timer_ +#define _wl_timer_ +s32 wl_timer_attach(struct net_device *net); +void wl_timer_dettach(dhd_pub_t *dhdp); +void wl_timer_register(struct net_device *net, timer_list_compat_t *timer, void *cb_func); +void wl_timer_deregister(struct net_device *net, timer_list_compat_t *timer); +void wl_timer_mod(dhd_pub_t *dhd, timer_list_compat_t *timer, uint32 tmo_ms); +#endif diff --git a/bcmdhd.101.10.361.x/wldev_common.c b/bcmdhd.101.10.361.x/wldev_common.c index 9cf13d2..801d332 100755 --- a/bcmdhd.101.10.361.x/wldev_common.c +++ b/bcmdhd.101.10.361.x/wldev_common.c @@ -508,30 +508,16 @@ int wldev_get_mode( int wldev_set_country( struct net_device *dev, char *country_code, bool notify, int revinfo) { + int error = 0; #if defined(BCMDONGLEHOST) - int error = -1; - wl_country_t cspec = {{0}, 0, {0}}; + struct dhd_pub *dhd = dhd_get_pub(dev); if (!country_code) - return error; - - cspec.rev = revinfo; - strlcpy(cspec.country_abbrev, country_code, WL_CCODE_LEN + 1); - strlcpy(cspec.ccode, country_code, WL_CCODE_LEN + 1); - error = dhd_conf_map_country_list(dhd_get_pub(dev), &cspec); - if (error) - dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec); - error = dhd_conf_set_country(dhd_get_pub(dev), &cspec); - if (error < 0) { - WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev)); - return error; - } - dhd_conf_fix_country(dhd_get_pub(dev)); - dhd_conf_get_country(dhd_get_pub(dev), &cspec); - dhd_bus_country_set(dev, &cspec, notify); + return -1; + error = dhd_conf_country(dhd, "country", country_code); + dhd_bus_country_set(dev, &dhd->dhd_cspec, notify); printf("%s: set country for %s as %s rev %d\n", - __FUNCTION__, country_code, cspec.ccode, cspec.rev); + __FUNCTION__, country_code, dhd->dhd_cspec.ccode, dhd->dhd_cspec.rev); #endif /* defined(BCMDONGLEHOST) */ - return 0; + return error; } -- 2.20.1